/*
* Copyright 2017-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.facebook.buck.jvm.java.abi.source;
import com.facebook.buck.util.liteinfersupport.Nullable;
import com.facebook.buck.util.liteinfersupport.Preconditions;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.AssignmentTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.Tree;
import com.sun.source.util.TreePath;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.type.DeclaredType;
class TreeBackedAnnotationMirror implements AnnotationMirror {
private final AnnotationMirror underlyingAnnotationMirror;
private final TreePath path;
private final AnnotationTree tree;
private final TreeBackedElementResolver resolver;
@Nullable private DeclaredType type;
@Nullable private Map<ExecutableElement, TreeBackedAnnotationValue> elementValues;
TreeBackedAnnotationMirror(
AnnotationMirror underlyingAnnotationMirror,
TreePath path,
TreeBackedElementResolver resolver) {
this.underlyingAnnotationMirror = underlyingAnnotationMirror;
this.path = path;
this.resolver = resolver;
tree = (AnnotationTree) path.getLeaf();
}
@Override
public DeclaredType getAnnotationType() {
if (type == null) {
type =
(DeclaredType) resolver.getCanonicalType(underlyingAnnotationMirror.getAnnotationType());
}
return type;
}
@Override
public Map<ExecutableElement, TreeBackedAnnotationValue> getElementValues() {
if (elementValues == null) {
Map<ExecutableElement, TreeBackedAnnotationValue> result = new LinkedHashMap<>();
Map<String, TreePath> treePaths = new HashMap<>();
List<? extends ExpressionTree> arguments = tree.getArguments();
for (ExpressionTree argument : arguments) {
TreePath valuePath = new TreePath(path, argument);
if (argument.getKind() != Tree.Kind.ASSIGNMENT) {
treePaths.put("value", valuePath);
} else {
AssignmentTree assignment = (AssignmentTree) argument;
IdentifierTree nameTree = (IdentifierTree) assignment.getVariable();
treePaths.put(nameTree.getName().toString(), valuePath);
}
}
for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry :
underlyingAnnotationMirror.getElementValues().entrySet()) {
ExecutableElement underlyingKeyElement = entry.getKey();
TreePath valuePath =
Preconditions.checkNotNull(treePaths.get(entry.getKey().getSimpleName().toString()));
result.put(
resolver.getCanonicalElement(underlyingKeyElement),
new TreeBackedAnnotationValue(entry.getValue(), valuePath, resolver));
}
elementValues = Collections.unmodifiableMap(result);
}
return elementValues;
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append("@");
result.append(getAnnotationType().toString());
Map<ExecutableElement, TreeBackedAnnotationValue> elementValues = getElementValues();
if (!elementValues.isEmpty()) {
result.append("(");
result.append(
elementValues
.entrySet()
.stream()
.map(
entry -> {
Name key = entry.getKey().getSimpleName();
TreeBackedAnnotationValue value = entry.getValue();
if (elementValues.size() == 1 && key.contentEquals("value")) {
return value.toString();
} else {
return String.format("%s=%s", key, value);
}
})
.collect(Collectors.joining(", ")));
result.append(")");
}
return result.toString();
}
}