/*
* Copyright 2016-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.sun.source.tree.AnnotationTree;
import com.sun.source.tree.ModifiersTree;
import com.sun.source.util.TreePath;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import javax.lang.model.type.TypeMirror;
/**
* An implementation of {@link Element} that uses only the information available from a {@link
* com.sun.source.tree.Tree}. This results in an incomplete implementation; see documentation for
* individual methods and {@link com.facebook.buck.jvm.java.abi.source} for more information.
*/
abstract class TreeBackedElement implements Element {
private final Element underlyingElement;
@Nullable private final TreeBackedElement enclosingElement;
private final List<Element> enclosedElements = new ArrayList<>();
private final TreeBackedElementResolver resolver;
@Nullable private final TreePath path;
@Nullable private List<TreeBackedAnnotationMirror> annotationMirrors;
public TreeBackedElement(
Element underlyingElement,
@Nullable TreeBackedElement enclosingElement,
@Nullable TreePath path,
TreeBackedElementResolver resolver) {
this.underlyingElement = underlyingElement;
this.enclosingElement = enclosingElement;
// Some element types don't appear as members of enclosingElement.getEnclosedElements, so
// it's up to each subtype's constructor to decide whether to add itself or not.
this.path = path;
this.resolver = resolver;
}
/* package */ Element getUnderlyingElement() {
return underlyingElement;
}
protected final TreeBackedElementResolver getResolver() {
return resolver;
}
@Nullable
/* package */ TreePath getTreePath() {
return path;
}
@Override
public ElementKind getKind() {
return underlyingElement.getKind();
}
@Override
public Set<Modifier> getModifiers() {
return underlyingElement.getModifiers();
}
@Override
public Name getSimpleName() {
return underlyingElement.getSimpleName();
}
@Override
@Nullable
public TreeBackedElement getEnclosingElement() {
return enclosingElement;
}
@Override
public List<? extends Element> getEnclosedElements() {
return Collections.unmodifiableList(enclosedElements);
}
protected void addEnclosedElement(Element element) {
enclosedElements.add(element);
}
@Override
public abstract TypeMirror asType();
@Override
public List<? extends AnnotationMirror> getAnnotationMirrors() {
if (annotationMirrors == null) {
List<? extends AnnotationMirror> underlyingAnnotations =
underlyingElement.getAnnotationMirrors();
if (underlyingAnnotations.isEmpty()) {
return underlyingAnnotations;
}
List<? extends AnnotationTree> annotationTrees = getAnnotationTrees();
List<TreeBackedAnnotationMirror> result = new ArrayList<>();
for (int i = 0; i < underlyingAnnotations.size(); i++) {
result.add(
new TreeBackedAnnotationMirror(
underlyingAnnotations.get(i),
new TreePath(path, annotationTrees.get(i)),
resolver));
}
annotationMirrors = Collections.unmodifiableList(result);
}
return annotationMirrors;
}
private List<? extends AnnotationTree> getAnnotationTrees() {
ModifiersTree modifiersTree = getModifiersTree();
if (modifiersTree == null) {
return Collections.emptyList();
}
return modifiersTree.getAnnotations();
}
@Nullable
protected abstract ModifiersTree getModifiersTree();
@Override
@Nullable
public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
throw new UnsupportedOperationException();
}
@Override
public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
throw new UnsupportedOperationException();
}
@Override
public String toString() {
return underlyingElement.toString();
}
}