blob: ab4148293f7ce4bdf2a50bf1e7b6fb253dc7730c [file] [log] [blame]
/*
* Copyright 2019 Google Inc. All Rights Reserved.
*
* 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.google.turbine.processing;
import static java.util.Objects.requireNonNull;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.turbine.binder.bound.AnnotationMetadata;
import com.google.turbine.binder.bound.SourceTypeBoundClass;
import com.google.turbine.binder.bound.TurbineAnnotationValue;
import com.google.turbine.binder.bound.TypeBoundClass;
import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo;
import com.google.turbine.binder.bound.TypeBoundClass.MethodInfo;
import com.google.turbine.binder.bound.TypeBoundClass.ParamInfo;
import com.google.turbine.binder.bound.TypeBoundClass.TyVarInfo;
import com.google.turbine.binder.lookup.PackageScope;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.binder.sym.FieldSymbol;
import com.google.turbine.binder.sym.MethodSymbol;
import com.google.turbine.binder.sym.PackageSymbol;
import com.google.turbine.binder.sym.ParamSymbol;
import com.google.turbine.binder.sym.Symbol;
import com.google.turbine.binder.sym.TyVarSymbol;
import com.google.turbine.diag.TurbineError;
import com.google.turbine.diag.TurbineError.ErrorKind;
import com.google.turbine.model.Const;
import com.google.turbine.model.Const.ArrayInitValue;
import com.google.turbine.model.TurbineFlag;
import com.google.turbine.tree.Tree;
import com.google.turbine.tree.Tree.MethDecl;
import com.google.turbine.tree.Tree.TyDecl;
import com.google.turbine.tree.Tree.VarDecl;
import com.google.turbine.type.AnnoInfo;
import com.google.turbine.type.Type;
import com.google.turbine.type.Type.ClassTy;
import com.google.turbine.type.Type.ClassTy.SimpleClassTy;
import com.google.turbine.type.Type.ErrorTy;
import java.lang.annotation.Annotation;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.EnumSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ElementVisitor;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import javax.lang.model.element.NestingKind;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import org.checkerframework.checker.nullness.qual.Nullable;
/** An {@link Element} implementation backed by a {@link Symbol}. */
public abstract class TurbineElement implements Element {
public abstract Symbol sym();
public abstract String javadoc();
@Override
public abstract int hashCode();
@Override
public abstract boolean equals(@Nullable Object obj);
protected final ModelFactory factory;
private final Supplier<ImmutableList<AnnotationMirror>> annotationMirrors;
protected <T> Supplier<T> memoize(Supplier<T> supplier) {
return factory.memoize(supplier);
}
protected TurbineElement(ModelFactory factory) {
this.factory = requireNonNull(factory);
this.annotationMirrors =
factory.memoize(
new Supplier<ImmutableList<AnnotationMirror>>() {
@Override
public ImmutableList<AnnotationMirror> get() {
ImmutableList.Builder<AnnotationMirror> result = ImmutableList.builder();
for (AnnoInfo anno : annos()) {
result.add(TurbineAnnotationMirror.create(factory, anno));
}
return result.build();
}
});
}
static AnnoInfo getAnnotation(Iterable<AnnoInfo> annos, ClassSymbol sym) {
for (AnnoInfo anno : annos) {
if (Objects.equals(anno.sym(), sym)) {
return anno;
}
}
return null;
}
@Override
public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
ClassSymbol sym = new ClassSymbol(annotationType.getName().replace('.', '/'));
TypeBoundClass info = factory.getSymbol(sym);
if (info == null) {
return null;
}
AnnoInfo anno = getAnnotation(annos(), sym);
if (anno == null) {
return null;
}
return TurbineAnnotationProxy.create(factory, annotationType, anno);
}
@Override
public final <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
ClassSymbol sym = new ClassSymbol(annotationType.getName().replace('.', '/'));
TypeBoundClass info = factory.getSymbol(sym);
if (info == null) {
return null;
}
AnnotationMetadata metadata = info.annotationMetadata();
if (metadata == null) {
return null;
}
List<A> result = new ArrayList<>();
for (AnnoInfo anno : annos()) {
if (anno.sym().equals(sym)) {
result.add(TurbineAnnotationProxy.create(factory, annotationType, anno));
continue;
}
if (anno.sym().equals(metadata.repeatable())) {
// requireNonNull is safe because java.lang.annotation.Repeatable declares `value`.
ArrayInitValue arrayValue = (ArrayInitValue) requireNonNull(anno.values().get("value"));
for (Const element : arrayValue.elements()) {
result.add(
TurbineAnnotationProxy.create(
factory, annotationType, ((TurbineAnnotationValue) element).info()));
}
}
}
return Iterables.toArray(result, annotationType);
}
@Override
public final List<? extends AnnotationMirror> getAnnotationMirrors() {
return annotationMirrors.get();
}
List<? extends AnnotationMirror> getAllAnnotationMirrors() {
return getAnnotationMirrors();
}
protected abstract ImmutableList<AnnoInfo> annos();
/** A {@link TypeElement} implementation backed by a {@link ClassSymbol}. */
static class TurbineTypeElement extends TurbineElement implements TypeElement {
@Override
public int hashCode() {
return sym.hashCode();
}
private final ClassSymbol sym;
private final Supplier<TypeBoundClass> info;
TurbineTypeElement(ModelFactory factory, ClassSymbol sym) {
super(factory);
this.sym = requireNonNull(sym);
this.info =
memoize(
new Supplier<TypeBoundClass>() {
@Override
public TypeBoundClass get() {
return factory.getSymbol(sym);
}
});
}
@Nullable
TypeBoundClass info() {
return info.get();
}
TypeBoundClass infoNonNull() {
TypeBoundClass info = info();
if (info == null) {
throw TurbineError.format(/* source= */ null, ErrorKind.SYMBOL_NOT_FOUND, sym);
}
return info;
}
@Override
public NestingKind getNestingKind() {
TypeBoundClass info = info();
return (info != null && info.owner() != null) ? NestingKind.MEMBER : NestingKind.TOP_LEVEL;
}
private final Supplier<TurbineName> qualifiedName =
memoize(
new Supplier<TurbineName>() {
@Override
public TurbineName get() {
TypeBoundClass info = info();
if (info == null || info.owner() == null) {
return new TurbineName(sym.toString());
}
ClassSymbol sym = sym();
Deque<String> flat = new ArrayDeque<>();
while (info.owner() != null) {
flat.addFirst(sym.binaryName().substring(info.owner().binaryName().length() + 1));
sym = info.owner();
info = factory.getSymbol(sym);
}
flat.addFirst(sym.toString());
return new TurbineName(Joiner.on('.').join(flat));
}
});
@Override
public Name getQualifiedName() {
return qualifiedName.get();
}
private final Supplier<TypeMirror> superclass =
memoize(
new Supplier<TypeMirror>() {
@Override
public TypeMirror get() {
TypeBoundClass info = infoNonNull();
switch (info.kind()) {
case CLASS:
case ENUM:
if (info.superclass() != null) {
return factory.asTypeMirror(info.superClassType());
}
if (info instanceof SourceTypeBoundClass) {
// support simple names for stuff that doesn't exist
TyDecl decl = ((SourceTypeBoundClass) info).decl();
if (decl.xtnds().isPresent()) {
ArrayDeque<Tree.Ident> flat = new ArrayDeque<>();
for (Tree.ClassTy curr = decl.xtnds().get();
curr != null;
curr = curr.base().orElse(null)) {
flat.addFirst(curr.name());
}
return factory.asTypeMirror(ErrorTy.create(flat));
}
}
return factory.noType();
case INTERFACE:
case ANNOTATION:
return factory.noType();
}
throw new AssertionError(info.kind());
}
});
@Override
public TypeMirror getSuperclass() {
return superclass.get();
}
@Override
public String toString() {
return getQualifiedName().toString();
}
private final Supplier<List<TypeMirror>> interfaces =
memoize(
new Supplier<List<TypeMirror>>() {
@Override
public List<TypeMirror> get() {
return factory.asTypeMirrors(infoNonNull().interfaceTypes());
}
});
@Override
public List<? extends TypeMirror> getInterfaces() {
return interfaces.get();
}
private final Supplier<ImmutableList<TypeParameterElement>> typeParameters =
memoize(
new Supplier<ImmutableList<TypeParameterElement>>() {
@Override
public ImmutableList<TypeParameterElement> get() {
ImmutableList.Builder<TypeParameterElement> result = ImmutableList.builder();
for (TyVarSymbol p : infoNonNull().typeParameters().values()) {
result.add(factory.typeParameterElement(p));
}
return result.build();
}
});
@Override
public List<? extends TypeParameterElement> getTypeParameters() {
return typeParameters.get();
}
private final Supplier<TypeMirror> type =
memoize(
new Supplier<TypeMirror>() {
@Override
public TypeMirror get() {
return factory.asTypeMirror(asGenericType(sym));
}
ClassTy asGenericType(ClassSymbol symbol) {
TypeBoundClass info = info();
if (info == null) {
return ClassTy.asNonParametricClassTy(symbol);
}
Deque<Type.ClassTy.SimpleClassTy> simples = new ArrayDeque<>();
simples.addFirst(simple(symbol, info));
while (info.owner() != null && (info.access() & TurbineFlag.ACC_STATIC) == 0) {
symbol = info.owner();
info = factory.getSymbol(symbol);
simples.addFirst(simple(symbol, info));
}
return ClassTy.create(ImmutableList.copyOf(simples));
}
private SimpleClassTy simple(ClassSymbol sym, TypeBoundClass info) {
ImmutableList.Builder<Type> args = ImmutableList.builder();
for (TyVarSymbol t : info.typeParameters().values()) {
args.add(Type.TyVar.create(t, ImmutableList.of()));
}
return SimpleClassTy.create(sym, args.build(), ImmutableList.of());
}
});
@Override
public TypeMirror asType() {
return type.get();
}
@Override
public ElementKind getKind() {
TypeBoundClass info = infoNonNull();
switch (info.kind()) {
case CLASS:
return ElementKind.CLASS;
case INTERFACE:
return ElementKind.INTERFACE;
case ENUM:
return ElementKind.ENUM;
case ANNOTATION:
return ElementKind.ANNOTATION_TYPE;
}
throw new AssertionError(info.kind());
}
@Override
public Set<Modifier> getModifiers() {
return asModifierSet(ModifierOwner.TYPE, infoNonNull().access() & ~TurbineFlag.ACC_SUPER);
}
private final Supplier<TurbineName> simpleName =
memoize(
new Supplier<TurbineName>() {
@Override
public TurbineName get() {
TypeBoundClass info = info();
if (info == null || info.owner() == null) {
return new TurbineName(sym.simpleName());
}
return new TurbineName(
sym.binaryName().substring(info.owner().binaryName().length() + 1));
}
});
@Override
public Name getSimpleName() {
return simpleName.get();
}
private final Supplier<Element> enclosing =
memoize(
new Supplier<Element>() {
@Override
public Element get() {
return getNestingKind().equals(NestingKind.TOP_LEVEL)
? factory.packageElement(sym.owner())
: factory.typeElement(info().owner());
}
});
@Override
public Element getEnclosingElement() {
return enclosing.get();
}
private final Supplier<ImmutableList<Element>> enclosed =
memoize(
new Supplier<ImmutableList<Element>>() {
@Override
public ImmutableList<Element> get() {
TypeBoundClass info = infoNonNull();
ImmutableList.Builder<Element> result = ImmutableList.builder();
for (FieldInfo field : info.fields()) {
result.add(factory.fieldElement(field.sym()));
}
for (MethodInfo method : info.methods()) {
result.add(factory.executableElement(method.sym()));
}
for (ClassSymbol child : info.children().values()) {
result.add(factory.typeElement(child));
}
return result.build();
}
});
@Override
public List<? extends Element> getEnclosedElements() {
return enclosed.get();
}
@Override
public <R, P> R accept(ElementVisitor<R, P> v, P p) {
return v.visitType(this, p);
}
@Override
public ClassSymbol sym() {
return sym;
}
@Override
public String javadoc() {
TypeBoundClass info = info();
if (!(info instanceof SourceTypeBoundClass)) {
return null;
}
return ((SourceTypeBoundClass) info).decl().javadoc();
}
@Override
public boolean equals(@Nullable Object obj) {
return obj instanceof TurbineTypeElement && sym.equals(((TurbineTypeElement) obj).sym);
}
@Override
protected ImmutableList<AnnoInfo> annos() {
return infoNonNull().annotations();
}
@Override
public final <A extends Annotation> A getAnnotation(Class<A> annotationType) {
ClassSymbol sym = new ClassSymbol(annotationType.getName().replace('.', '/'));
AnnoInfo anno = getAnnotation(annos(), sym);
if (anno != null) {
return TurbineAnnotationProxy.create(factory, annotationType, anno);
}
if (!isAnnotationInherited(sym)) {
return null;
}
ClassSymbol superclass = infoNonNull().superclass();
while (superclass != null) {
TypeBoundClass info = factory.getSymbol(superclass);
if (info == null) {
break;
}
anno = getAnnotation(info.annotations(), sym);
if (anno != null) {
return TurbineAnnotationProxy.create(factory, annotationType, anno);
}
superclass = info.superclass();
}
return null;
}
@Override
List<? extends AnnotationMirror> getAllAnnotationMirrors() {
Map<ClassSymbol, AnnotationMirror> result = new LinkedHashMap<>();
for (AnnoInfo anno : annos()) {
result.put(anno.sym(), TurbineAnnotationMirror.create(factory, anno));
}
ClassSymbol superclass = infoNonNull().superclass();
while (superclass != null) {
TypeBoundClass i = factory.getSymbol(superclass);
if (i == null) {
break;
}
for (AnnoInfo anno : i.annotations()) {
addAnnotationFromSuper(result, anno);
}
superclass = i.superclass();
}
return ImmutableList.copyOf(result.values());
}
private void addAnnotationFromSuper(Map<ClassSymbol, AnnotationMirror> result, AnnoInfo anno) {
if (!isAnnotationInherited(anno.sym())) {
return;
}
if (result.containsKey(anno.sym())) {
// if the same inherited annotation is present on multiple supertypes, only return one
return;
}
result.put(anno.sym(), TurbineAnnotationMirror.create(factory, anno));
}
private boolean isAnnotationInherited(ClassSymbol sym) {
TypeBoundClass annoInfo = factory.getSymbol(sym);
if (annoInfo == null) {
return false;
}
for (AnnoInfo anno : annoInfo.annotations()) {
if (anno.sym().equals(ClassSymbol.INHERITED)) {
return true;
}
}
return false;
}
}
/** A {@link TypeParameterElement} implementation backed by a {@link TyVarSymbol}. */
static class TurbineTypeParameterElement extends TurbineElement implements TypeParameterElement {
@Override
public int hashCode() {
return sym.hashCode();
}
@Override
public boolean equals(@Nullable Object obj) {
return obj instanceof TurbineTypeParameterElement
&& sym.equals(((TurbineTypeParameterElement) obj).sym);
}
private final TyVarSymbol sym;
public TurbineTypeParameterElement(ModelFactory factory, TyVarSymbol sym) {
super(factory);
this.sym = sym;
}
private final Supplier<TyVarInfo> info =
memoize(
new Supplier<TyVarInfo>() {
@Override
public TyVarInfo get() {
return factory.getTyVarInfo(sym);
}
});
@Nullable
private TyVarInfo info() {
return info.get();
}
@Override
public String toString() {
return sym.name();
}
@Override
public Element getGenericElement() {
return factory.element(sym.owner());
}
@Override
public List<? extends TypeMirror> getBounds() {
ImmutableList<Type> bounds = info().upperBound().bounds();
return factory.asTypeMirrors(bounds.isEmpty() ? ImmutableList.of(ClassTy.OBJECT) : bounds);
}
@Override
public TypeMirror asType() {
return factory.asTypeMirror(Type.TyVar.create(sym, info().annotations()));
}
@Override
public ElementKind getKind() {
return ElementKind.TYPE_PARAMETER;
}
@Override
public Set<Modifier> getModifiers() {
return ImmutableSet.of();
}
@Override
public Name getSimpleName() {
return new TurbineName(sym.name());
}
@Override
public Element getEnclosingElement() {
return getGenericElement();
}
@Override
public List<? extends Element> getEnclosedElements() {
return ImmutableList.of();
}
@Override
public <R, P> R accept(ElementVisitor<R, P> v, P p) {
return v.visitTypeParameter(this, p);
}
@Override
public TyVarSymbol sym() {
return sym;
}
@Override
public String javadoc() {
return null;
}
@Override
protected ImmutableList<AnnoInfo> annos() {
return info().annotations();
}
}
/** An {@link ExecutableElement} implementation backed by a {@link MethodSymbol}. */
static class TurbineExecutableElement extends TurbineElement implements ExecutableElement {
private final MethodSymbol sym;
private final Supplier<MethodInfo> info =
memoize(
new Supplier<MethodInfo>() {
@Override
public MethodInfo get() {
return factory.getMethodInfo(sym);
}
});
@Nullable
MethodInfo info() {
return info.get();
}
TurbineExecutableElement(ModelFactory factory, MethodSymbol sym) {
super(factory);
this.sym = sym;
}
@Override
public MethodSymbol sym() {
return sym;
}
@Override
public String javadoc() {
MethDecl decl = info().decl();
return decl != null ? decl.javadoc() : null;
}
@Override
public int hashCode() {
return sym.hashCode();
}
@Override
public boolean equals(@Nullable Object obj) {
return obj instanceof TurbineExecutableElement
&& sym.equals(((TurbineExecutableElement) obj).sym);
}
@Override
public List<? extends TypeParameterElement> getTypeParameters() {
ImmutableList.Builder<TurbineTypeParameterElement> result = ImmutableList.builder();
for (Map.Entry<TyVarSymbol, TyVarInfo> p : info().tyParams().entrySet()) {
result.add(factory.typeParameterElement(p.getKey()));
}
return result.build();
}
@Override
public TypeMirror getReturnType() {
return factory.asTypeMirror(info().returnType());
}
private final Supplier<ImmutableList<VariableElement>> parameters =
memoize(
new Supplier<ImmutableList<VariableElement>>() {
@Override
public ImmutableList<VariableElement> get() {
ImmutableList.Builder<VariableElement> result = ImmutableList.builder();
for (ParamInfo param : info().parameters()) {
if (param.synthetic()) {
// ExecutableElement#getParameters doesn't expect synthetic or mandated
// parameters
continue;
}
result.add(factory.parameterElement(param.sym()));
}
return result.build();
}
});
@Override
public List<? extends VariableElement> getParameters() {
return parameters.get();
}
@Override
public String toString() {
MethodInfo info = info();
StringBuilder sb = new StringBuilder();
if (!info.tyParams().isEmpty()) {
sb.append('<');
Joiner.on(',').appendTo(sb, info.tyParams().keySet());
sb.append('>');
}
if (getKind() == ElementKind.CONSTRUCTOR) {
sb.append(info.sym().owner().simpleName());
} else {
sb.append(info.sym().name());
}
sb.append('(');
boolean first = true;
for (ParamInfo p : info.parameters()) {
if (!first) {
sb.append(',');
}
sb.append(p.type());
first = false;
}
sb.append(')');
return sb.toString();
}
@Override
public TypeMirror getReceiverType() {
return info().receiver() != null
? factory.asTypeMirror(info().receiver().type())
: factory.noType();
}
@Override
public boolean isVarArgs() {
return (info().access() & TurbineFlag.ACC_VARARGS) == TurbineFlag.ACC_VARARGS;
}
@Override
public boolean isDefault() {
return (info().access() & TurbineFlag.ACC_DEFAULT) == TurbineFlag.ACC_DEFAULT;
}
@Override
public List<? extends TypeMirror> getThrownTypes() {
return factory.asTypeMirrors(info().exceptions());
}
@Override
public AnnotationValue getDefaultValue() {
return info().defaultValue() != null
? TurbineAnnotationMirror.annotationValue(factory, info().defaultValue())
: null;
}
@Override
public TypeMirror asType() {
return factory.asTypeMirror(info().asType());
}
@Override
public ElementKind getKind() {
return sym.name().equals("<init>") ? ElementKind.CONSTRUCTOR : ElementKind.METHOD;
}
@Override
public Set<Modifier> getModifiers() {
return asModifierSet(ModifierOwner.METHOD, info().access());
}
@Override
public Name getSimpleName() {
return new TurbineName(info().sym().name());
}
@Override
public Element getEnclosingElement() {
return factory.typeElement(info().sym().owner());
}
@Override
public List<? extends Element> getEnclosedElements() {
return ImmutableList.of();
}
@Override
public <R, P> R accept(ElementVisitor<R, P> v, P p) {
return v.visitExecutable(this, p);
}
@Override
protected ImmutableList<AnnoInfo> annos() {
return info().annotations();
}
}
/** An {@link VariableElement} implementation backed by a {@link FieldSymbol}. */
static class TurbineFieldElement extends TurbineElement implements VariableElement {
@Override
public String toString() {
return sym.name();
}
@Override
public boolean equals(@Nullable Object obj) {
return obj instanceof TurbineFieldElement && sym.equals(((TurbineFieldElement) obj).sym);
}
@Override
public int hashCode() {
return sym.hashCode();
}
private final FieldSymbol sym;
@Override
public FieldSymbol sym() {
return sym;
}
@Override
public String javadoc() {
VarDecl decl = info().decl();
return decl != null ? decl.javadoc() : null;
}
private final Supplier<FieldInfo> info =
memoize(
new Supplier<FieldInfo>() {
@Override
public FieldInfo get() {
return factory.getFieldInfo(sym);
}
});
@Nullable
FieldInfo info() {
return info.get();
}
TurbineFieldElement(ModelFactory factory, FieldSymbol sym) {
super(factory);
this.sym = sym;
}
@Override
public Object getConstantValue() {
if (info().value() == null) {
return null;
}
return info().value().getValue();
}
@Override
public TypeMirror asType() {
return factory.asTypeMirror(info().type());
}
@Override
public ElementKind getKind() {
return ((info().access() & TurbineFlag.ACC_ENUM) == TurbineFlag.ACC_ENUM)
? ElementKind.ENUM_CONSTANT
: ElementKind.FIELD;
}
@Override
public Set<Modifier> getModifiers() {
return asModifierSet(ModifierOwner.FIELD, info().access());
}
@Override
public Name getSimpleName() {
return new TurbineName(sym.name());
}
@Override
public Element getEnclosingElement() {
return factory.typeElement(sym.owner());
}
@Override
public List<? extends Element> getEnclosedElements() {
return ImmutableList.of();
}
@Override
public <R, P> R accept(ElementVisitor<R, P> v, P p) {
return v.visitVariable(this, p);
}
@Override
protected ImmutableList<AnnoInfo> annos() {
return info().annotations();
}
}
private enum ModifierOwner {
TYPE,
PARAMETER,
FIELD,
METHOD
}
private static ImmutableSet<Modifier> asModifierSet(ModifierOwner modifierOwner, int access) {
EnumSet<Modifier> modifiers = EnumSet.noneOf(Modifier.class);
if ((access & TurbineFlag.ACC_PUBLIC) == TurbineFlag.ACC_PUBLIC) {
modifiers.add(Modifier.PUBLIC);
}
if ((access & TurbineFlag.ACC_PROTECTED) == TurbineFlag.ACC_PROTECTED) {
modifiers.add(Modifier.PROTECTED);
}
if ((access & TurbineFlag.ACC_PRIVATE) == TurbineFlag.ACC_PRIVATE) {
modifiers.add(Modifier.PRIVATE);
}
if ((access & TurbineFlag.ACC_ABSTRACT) == TurbineFlag.ACC_ABSTRACT) {
modifiers.add(Modifier.ABSTRACT);
}
if ((access & TurbineFlag.ACC_FINAL) == TurbineFlag.ACC_FINAL) {
modifiers.add(Modifier.FINAL);
}
if ((access & TurbineFlag.ACC_DEFAULT) == TurbineFlag.ACC_DEFAULT) {
modifiers.add(Modifier.DEFAULT);
}
if ((access & TurbineFlag.ACC_STATIC) == TurbineFlag.ACC_STATIC) {
modifiers.add(Modifier.STATIC);
}
if ((access & TurbineFlag.ACC_TRANSIENT) == TurbineFlag.ACC_TRANSIENT) {
switch (modifierOwner) {
case METHOD:
case PARAMETER:
// varargs and transient use the same bits
break;
default:
modifiers.add(Modifier.TRANSIENT);
}
}
if ((access & TurbineFlag.ACC_VOLATILE) == TurbineFlag.ACC_VOLATILE) {
modifiers.add(Modifier.VOLATILE);
}
if ((access & TurbineFlag.ACC_SYNCHRONIZED) == TurbineFlag.ACC_SYNCHRONIZED) {
modifiers.add(Modifier.SYNCHRONIZED);
}
if ((access & TurbineFlag.ACC_NATIVE) == TurbineFlag.ACC_NATIVE) {
modifiers.add(Modifier.NATIVE);
}
if ((access & TurbineFlag.ACC_STRICT) == TurbineFlag.ACC_STRICT) {
modifiers.add(Modifier.STRICTFP);
}
return Sets.immutableEnumSet(modifiers);
}
/** A {@link PackageElement} implementation backed by a {@link PackageSymbol}. */
static class TurbinePackageElement extends TurbineElement implements PackageElement {
private final PackageSymbol sym;
public TurbinePackageElement(ModelFactory factory, PackageSymbol sym) {
super(factory);
this.sym = sym;
}
@Override
public Name getQualifiedName() {
return new TurbineName(sym.toString());
}
@Override
public boolean isUnnamed() {
return sym.binaryName().isEmpty();
}
@Override
public TypeMirror asType() {
return factory.packageType(sym);
}
@Override
public ElementKind getKind() {
return ElementKind.PACKAGE;
}
@Override
public Set<Modifier> getModifiers() {
return ImmutableSet.of();
}
@Override
public Name getSimpleName() {
return new TurbineName(sym.binaryName().substring(sym.binaryName().lastIndexOf('/') + 1));
}
@Override
public Element getEnclosingElement() {
// a package is not enclosed by another element
return null;
}
@Override
public List<TurbineTypeElement> getEnclosedElements() {
ImmutableSet.Builder<TurbineTypeElement> result = ImmutableSet.builder();
PackageScope scope = factory.tli().lookupPackage(Splitter.on('/').split(sym.binaryName()));
requireNonNull(scope); // the current package exists
for (ClassSymbol key : scope.classes()) {
if (key.binaryName().contains("$") && factory.getSymbol(key).owner() != null) {
// Skip member classes: only top-level classes are enclosed by the package.
// The initial check for '$' is an optimization.
continue;
}
if (key.simpleName().equals("package-info")) {
continue;
}
result.add(factory.typeElement(key));
}
return result.build().asList();
}
@Override
public <R, P> R accept(ElementVisitor<R, P> v, P p) {
return v.visitPackage(this, p);
}
@Override
public PackageSymbol sym() {
return sym;
}
@Override
public String javadoc() {
return null;
}
@Override
public int hashCode() {
return sym.hashCode();
}
@Override
public boolean equals(@Nullable Object obj) {
return obj instanceof TurbinePackageElement && sym.equals(((TurbinePackageElement) obj).sym);
}
private final Supplier<ImmutableList<AnnoInfo>> annos =
memoize(
new Supplier<ImmutableList<AnnoInfo>>() {
@Override
public ImmutableList<AnnoInfo> get() {
TypeBoundClass info =
factory.getSymbol(new ClassSymbol(sym.binaryName() + "/package-info"));
return info != null ? info.annotations() : ImmutableList.of();
}
});
@Override
protected ImmutableList<AnnoInfo> annos() {
return annos.get();
}
@Override
public String toString() {
return sym.toString();
}
}
/** A {@link VariableElement} implementation backed by a {@link ParamSymbol}. */
static class TurbineParameterElement extends TurbineElement implements VariableElement {
@Override
public ParamSymbol sym() {
return sym;
}
@Override
public String javadoc() {
return null;
}
@Override
public int hashCode() {
return sym.hashCode();
}
@Override
public boolean equals(@Nullable Object obj) {
return obj instanceof TurbineParameterElement
&& sym.equals(((TurbineParameterElement) obj).sym);
}
private final ParamSymbol sym;
private final Supplier<ParamInfo> info =
memoize(
new Supplier<ParamInfo>() {
@Override
public ParamInfo get() {
return factory.getParamInfo(sym);
}
});
@Nullable
ParamInfo info() {
return info.get();
}
public TurbineParameterElement(ModelFactory factory, ParamSymbol sym) {
super(factory);
this.sym = sym;
}
@Override
public Object getConstantValue() {
return null;
}
private final Supplier<TypeMirror> type =
memoize(
new Supplier<TypeMirror>() {
@Override
public TypeMirror get() {
return factory.asTypeMirror(info().type());
}
});
@Override
public TypeMirror asType() {
return type.get();
}
@Override
public ElementKind getKind() {
return ElementKind.PARAMETER;
}
@Override
public Set<Modifier> getModifiers() {
return asModifierSet(ModifierOwner.PARAMETER, info().access());
}
@Override
public Name getSimpleName() {
return new TurbineName(sym.name());
}
@Override
public Element getEnclosingElement() {
return factory.executableElement(sym.owner());
}
@Override
public List<? extends Element> getEnclosedElements() {
return ImmutableList.of();
}
@Override
public <R, P> R accept(ElementVisitor<R, P> v, P p) {
return v.visitVariable(this, p);
}
@Override
public String toString() {
return String.valueOf(sym.name());
}
@Override
protected ImmutableList<AnnoInfo> annos() {
return info().annotations();
}
}
static class TurbineNoTypeElement implements TypeElement {
private final ModelFactory factory;
private final String name;
public TurbineNoTypeElement(ModelFactory factory, String name) {
this.factory = factory;
this.name = requireNonNull(name);
}
@Override
public TypeMirror asType() {
return factory.noType();
}
@Override
public ElementKind getKind() {
return ElementKind.CLASS;
}
@Override
public Set<Modifier> getModifiers() {
return ImmutableSet.of();
}
@Override
public Name getSimpleName() {
return new TurbineName(name.substring(name.lastIndexOf('.') + 1));
}
@Override
public TypeMirror getSuperclass() {
return factory.noType();
}
@Override
public List<? extends TypeMirror> getInterfaces() {
return ImmutableList.of();
}
@Override
public List<? extends TypeParameterElement> getTypeParameters() {
return ImmutableList.of();
}
@Override
public Element getEnclosingElement() {
int idx = name.lastIndexOf('.');
String packageName;
if (idx == -1) {
packageName = "";
} else {
packageName = name.substring(0, idx).replace('.', '/');
}
return factory.packageElement(new PackageSymbol(packageName));
}
@Override
public List<? extends Element> getEnclosedElements() {
return ImmutableList.of();
}
@Override
public NestingKind getNestingKind() {
return NestingKind.TOP_LEVEL;
}
@Override
public Name getQualifiedName() {
return new TurbineName(name);
}
@Override
public List<? extends AnnotationMirror> getAnnotationMirrors() {
return ImmutableList.of();
}
@Override
public <A extends Annotation> A getAnnotation(Class<A> aClass) {
return null;
}
@Override
public <A extends Annotation> A[] getAnnotationsByType(Class<A> aClass) {
return null;
}
@Override
public <R, P> R accept(ElementVisitor<R, P> elementVisitor, P p) {
return elementVisitor.visitType(this, p);
}
@Override
public String toString() {
return getSimpleName().toString();
}
}
}