| /* |
| * 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 com.google.common.collect.Iterables.getLast; |
| import static java.util.Objects.requireNonNull; |
| |
| import com.google.common.base.Ascii; |
| import com.google.common.base.Joiner; |
| import com.google.common.base.Supplier; |
| import com.google.common.collect.ImmutableList; |
| import com.google.turbine.binder.bound.TypeBoundClass; |
| import com.google.turbine.binder.bound.TypeBoundClass.TyVarInfo; |
| import com.google.turbine.binder.sym.PackageSymbol; |
| import com.google.turbine.binder.sym.TyVarSymbol; |
| import com.google.turbine.model.TurbineConstantTypeKind; |
| import com.google.turbine.model.TurbineFlag; |
| import com.google.turbine.model.TurbineTyKind; |
| import com.google.turbine.type.AnnoInfo; |
| import com.google.turbine.type.Type; |
| import com.google.turbine.type.Type.ArrayTy; |
| import com.google.turbine.type.Type.ClassTy; |
| import com.google.turbine.type.Type.ErrorTy; |
| import com.google.turbine.type.Type.IntersectionTy; |
| import com.google.turbine.type.Type.MethodTy; |
| import com.google.turbine.type.Type.PrimTy; |
| import com.google.turbine.type.Type.TyVar; |
| import com.google.turbine.type.Type.WildTy; |
| import com.google.turbine.type.Type.WildTy.BoundKind; |
| import java.lang.annotation.Annotation; |
| import java.util.List; |
| import javax.lang.model.element.AnnotationMirror; |
| import javax.lang.model.element.Element; |
| import javax.lang.model.type.ArrayType; |
| import javax.lang.model.type.DeclaredType; |
| import javax.lang.model.type.ErrorType; |
| import javax.lang.model.type.ExecutableType; |
| import javax.lang.model.type.IntersectionType; |
| import javax.lang.model.type.NoType; |
| import javax.lang.model.type.NullType; |
| import javax.lang.model.type.PrimitiveType; |
| import javax.lang.model.type.TypeKind; |
| import javax.lang.model.type.TypeMirror; |
| import javax.lang.model.type.TypeVariable; |
| import javax.lang.model.type.TypeVisitor; |
| import javax.lang.model.type.WildcardType; |
| import org.checkerframework.checker.nullness.qual.Nullable; |
| |
| /** A {@link TypeMirror} implementation backed by a {@link Type}. */ |
| public abstract class TurbineTypeMirror implements TypeMirror { |
| |
| protected final ModelFactory factory; |
| |
| protected TurbineTypeMirror(ModelFactory factory) { |
| this.factory = requireNonNull(factory); |
| } |
| |
| protected abstract ImmutableList<AnnoInfo> annos(); |
| |
| @Override |
| public final List<? extends AnnotationMirror> getAnnotationMirrors() { |
| ImmutableList.Builder<AnnotationMirror> result = ImmutableList.builder(); |
| for (AnnoInfo anno : annos()) { |
| result.add(TurbineAnnotationMirror.create(factory, anno)); |
| } |
| return result.build(); |
| } |
| |
| @Override |
| public final <A extends Annotation> A getAnnotation(Class<A> annotationType) { |
| throw new AssertionError(); |
| } |
| |
| @Override |
| public final <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) { |
| throw new AssertionError(); |
| } |
| |
| public abstract Type asTurbineType(); |
| |
| @Override |
| public String toString() { |
| return asTurbineType().toString(); |
| } |
| |
| /** A {@link PrimitiveType} implementation backed by a {@link PrimTy}. */ |
| static class TurbinePrimitiveType extends TurbineTypeMirror implements PrimitiveType { |
| |
| @Override |
| public String toString() { |
| return Ascii.toLowerCase(type.primkind().toString()); |
| } |
| |
| @Override |
| public Type asTurbineType() { |
| return type; |
| } |
| |
| public final PrimTy type; |
| |
| TurbinePrimitiveType(ModelFactory factory, PrimTy type) { |
| super(factory); |
| if (type.primkind() == TurbineConstantTypeKind.STRING) { |
| throw new AssertionError(type); |
| } |
| this.type = type; |
| } |
| |
| @Override |
| public TypeKind getKind() { |
| switch (type.primkind()) { |
| case CHAR: |
| return TypeKind.CHAR; |
| case SHORT: |
| return TypeKind.SHORT; |
| case INT: |
| return TypeKind.INT; |
| case LONG: |
| return TypeKind.LONG; |
| case FLOAT: |
| return TypeKind.FLOAT; |
| case DOUBLE: |
| return TypeKind.DOUBLE; |
| case BOOLEAN: |
| return TypeKind.BOOLEAN; |
| case BYTE: |
| return TypeKind.BYTE; |
| case NULL: |
| return TypeKind.NULL; |
| case STRING: |
| } |
| throw new AssertionError(type.primkind()); |
| } |
| |
| @Override |
| public <R, P> R accept(TypeVisitor<R, P> v, P p) { |
| return v.visitPrimitive(this, p); |
| } |
| |
| @Override |
| protected ImmutableList<AnnoInfo> annos() { |
| return type.annos(); |
| } |
| } |
| |
| /** A {@link DeclaredType} implementation backed by a {@link ClassTy}. */ |
| static class TurbineDeclaredType extends TurbineTypeMirror implements DeclaredType { |
| |
| @Override |
| public int hashCode() { |
| return type.sym().hashCode(); |
| } |
| |
| @Override |
| public boolean equals(@Nullable Object obj) { |
| return obj instanceof TurbineDeclaredType && type.equals(((TurbineDeclaredType) obj).type); |
| } |
| |
| @Override |
| public ClassTy asTurbineType() { |
| return type; |
| } |
| |
| private final ClassTy type; |
| |
| TurbineDeclaredType(ModelFactory factory, ClassTy type) { |
| super(factory); |
| this.type = type; |
| } |
| |
| @Override |
| public String toString() { |
| return type.toString(); |
| } |
| |
| final Supplier<Element> element = |
| factory.memoize( |
| new Supplier<Element>() { |
| @Override |
| public Element get() { |
| return factory.typeElement(type.sym()); |
| } |
| }); |
| |
| @Override |
| public Element asElement() { |
| return element.get(); |
| } |
| |
| final Supplier<TypeMirror> enclosing = |
| factory.memoize( |
| new Supplier<TypeMirror>() { |
| @Override |
| public TypeMirror get() { |
| TypeBoundClass info = factory.getSymbol(type.sym()); |
| if (info != null |
| && info.owner() != null |
| && ((info.access() & TurbineFlag.ACC_STATIC) == 0) |
| && info.kind() == TurbineTyKind.CLASS) { |
| if (type.classes().size() > 1) { |
| return factory.asTypeMirror( |
| ClassTy.create(type.classes().subList(0, type.classes().size() - 1))); |
| } |
| return factory.asTypeMirror(ClassTy.asNonParametricClassTy(info.owner())); |
| } |
| return factory.noType(); |
| } |
| }); |
| |
| @Override |
| public TypeMirror getEnclosingType() { |
| return enclosing.get(); |
| } |
| |
| final Supplier<ImmutableList<TypeMirror>> typeArguments = |
| factory.memoize( |
| new Supplier<ImmutableList<TypeMirror>>() { |
| @Override |
| public ImmutableList<TypeMirror> get() { |
| return factory.asTypeMirrors(getLast(type.classes()).targs()); |
| } |
| }); |
| |
| @Override |
| public List<? extends TypeMirror> getTypeArguments() { |
| return typeArguments.get(); |
| } |
| |
| @Override |
| public TypeKind getKind() { |
| return TypeKind.DECLARED; |
| } |
| |
| @Override |
| public <R, P> R accept(TypeVisitor<R, P> v, P p) { |
| return v.visitDeclared(this, p); |
| } |
| |
| public ClassTy type() { |
| return type; |
| } |
| |
| @Override |
| protected ImmutableList<AnnoInfo> annos() { |
| return getLast(type.classes()).annos(); |
| } |
| } |
| |
| /** An {@link ArrayType} implementation backed by a {@link ArrayTy}. */ |
| static class TurbineArrayType extends TurbineTypeMirror implements ArrayType { |
| |
| @Override |
| public Type asTurbineType() { |
| return type; |
| } |
| |
| private final ArrayTy type; |
| |
| TurbineArrayType(ModelFactory factory, ArrayTy type) { |
| super(factory); |
| this.type = type; |
| } |
| |
| @Override |
| public TypeMirror getComponentType() { |
| return factory.asTypeMirror(type.elementType()); |
| } |
| |
| @Override |
| public TypeKind getKind() { |
| return TypeKind.ARRAY; |
| } |
| |
| @Override |
| public <R, P> R accept(TypeVisitor<R, P> v, P p) { |
| return v.visitArray(this, p); |
| } |
| |
| @Override |
| protected ImmutableList<AnnoInfo> annos() { |
| return type.annos(); |
| } |
| } |
| |
| /** An {@link ErrorType} implementation backed by a {@link ErrorTy}. */ |
| static class TurbineErrorType extends TurbineTypeMirror implements ErrorType { |
| |
| private final ErrorTy type; |
| |
| public TurbineErrorType(ModelFactory factory, ErrorTy type) { |
| super(factory); |
| this.type = type; |
| } |
| |
| @Override |
| public TypeKind getKind() { |
| return TypeKind.ERROR; |
| } |
| |
| @Override |
| public <R, P> R accept(TypeVisitor<R, P> v, P p) { |
| return v.visitError(this, p); |
| } |
| |
| @Override |
| protected ImmutableList<AnnoInfo> annos() { |
| return ImmutableList.of(); |
| } |
| |
| @Override |
| public Type asTurbineType() { |
| return type; |
| } |
| |
| @Override |
| public Element asElement() { |
| return factory.noElement(type.name()); |
| } |
| |
| @Override |
| public TypeMirror getEnclosingType() { |
| return factory.noType(); |
| } |
| |
| @Override |
| public List<? extends TypeMirror> getTypeArguments() { |
| return ImmutableList.of(); |
| } |
| |
| @Override |
| public String toString() { |
| return type.toString(); |
| } |
| } |
| |
| /** A 'package type' implementation backed by a {@link PackageSymbol}. */ |
| static class TurbinePackageType extends TurbineTypeMirror implements NoType { |
| |
| @Override |
| public Type asTurbineType() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| final PackageSymbol symbol; |
| |
| TurbinePackageType(ModelFactory factory, PackageSymbol symbol) { |
| super(factory); |
| this.symbol = symbol; |
| } |
| |
| @Override |
| public TypeKind getKind() { |
| return TypeKind.PACKAGE; |
| } |
| |
| @Override |
| public <R, P> R accept(TypeVisitor<R, P> v, P p) { |
| return v.visitNoType(this, p); |
| } |
| |
| @Override |
| public String toString() { |
| return symbol.toString(); |
| } |
| |
| @Override |
| public boolean equals(@Nullable Object other) { |
| return other instanceof TurbinePackageType |
| && symbol.equals(((TurbinePackageType) other).symbol); |
| } |
| |
| @Override |
| public int hashCode() { |
| return symbol.hashCode(); |
| } |
| |
| @Override |
| protected ImmutableList<AnnoInfo> annos() { |
| return ImmutableList.of(); |
| } |
| } |
| |
| /** The absence of a type, {@see javax.lang.model.util.Types#getNoType}. */ |
| static class TurbineNoType extends TurbineTypeMirror implements NoType { |
| |
| @Override |
| public Type asTurbineType() { |
| return Type.NONE; |
| } |
| |
| TurbineNoType(ModelFactory factory) { |
| super(factory); |
| } |
| |
| @Override |
| public TypeKind getKind() { |
| return TypeKind.NONE; |
| } |
| |
| @Override |
| public <R, P> R accept(TypeVisitor<R, P> v, P p) { |
| return v.visitNoType(this, p); |
| } |
| |
| @Override |
| public String toString() { |
| return "none"; |
| } |
| |
| @Override |
| public boolean equals(@Nullable Object other) { |
| return other instanceof TurbineNoType; |
| } |
| |
| @Override |
| public int hashCode() { |
| return getKind().hashCode(); |
| } |
| |
| @Override |
| protected ImmutableList<AnnoInfo> annos() { |
| return ImmutableList.of(); |
| } |
| } |
| |
| /** A void type, {@see javax.lang.model.util.Types#getNoType}. */ |
| static class TurbineVoidType extends TurbineTypeMirror implements NoType { |
| |
| @Override |
| public Type asTurbineType() { |
| return Type.VOID; |
| } |
| |
| TurbineVoidType(ModelFactory factory) { |
| super(factory); |
| } |
| |
| @Override |
| public TypeKind getKind() { |
| return TypeKind.VOID; |
| } |
| |
| @Override |
| public <R, P> R accept(TypeVisitor<R, P> v, P p) { |
| return v.visitNoType(this, p); |
| } |
| |
| @Override |
| protected ImmutableList<AnnoInfo> annos() { |
| return ImmutableList.of(); |
| } |
| } |
| |
| /** A {@link TypeVariable} implementation backed by a {@link TyVar}. */ |
| static class TurbineTypeVariable extends TurbineTypeMirror implements TypeVariable { |
| |
| @Override |
| public int hashCode() { |
| return type.hashCode(); |
| } |
| |
| @Override |
| public boolean equals(@Nullable Object obj) { |
| return obj instanceof TurbineTypeVariable && type.equals(((TurbineTypeVariable) obj).type); |
| } |
| |
| @Override |
| public Type asTurbineType() { |
| return type; |
| } |
| |
| private final TyVar type; |
| |
| private final Supplier<TyVarInfo> info = |
| factory.memoize( |
| new Supplier<TyVarInfo>() { |
| @Override |
| public TyVarInfo get() { |
| return factory.getTyVarInfo(type.sym()); |
| } |
| }); |
| |
| private TyVarInfo info() { |
| return info.get(); |
| } |
| |
| TurbineTypeVariable(ModelFactory factory, Type.TyVar type) { |
| super(factory); |
| this.type = type; |
| } |
| |
| @Override |
| public TypeKind getKind() { |
| return TypeKind.TYPEVAR; |
| } |
| |
| @Override |
| public <R, P> R accept(TypeVisitor<R, P> v, P p) { |
| return v.visitTypeVariable(this, p); |
| } |
| |
| @Override |
| public Element asElement() { |
| return factory.typeParameterElement(type.sym()); |
| } |
| |
| @Override |
| public TypeMirror getUpperBound() { |
| return factory.asTypeMirror(info().upperBound()); |
| } |
| |
| @Override |
| public TypeMirror getLowerBound() { |
| return info().lowerBound() != null |
| ? factory.asTypeMirror(info().lowerBound()) |
| : factory.noType(); |
| } |
| |
| @Override |
| public String toString() { |
| return type.toString(); |
| } |
| |
| @Override |
| protected ImmutableList<AnnoInfo> annos() { |
| return type.annos(); |
| } |
| } |
| |
| /** A {@link WildcardType} implementation backed by a {@link WildTy}. */ |
| static class TurbineWildcardType extends TurbineTypeMirror implements WildcardType { |
| |
| @Override |
| public Type asTurbineType() { |
| return type; |
| } |
| |
| private final WildTy type; |
| |
| public TurbineWildcardType(ModelFactory factory, WildTy type) { |
| super(factory); |
| this.type = type; |
| } |
| |
| @Override |
| public TypeKind getKind() { |
| return TypeKind.WILDCARD; |
| } |
| |
| @Override |
| public <R, P> R accept(TypeVisitor<R, P> v, P p) { |
| return v.visitWildcard(this, p); |
| } |
| |
| @Override |
| public boolean equals(@Nullable Object obj) { |
| return obj instanceof TurbineWildcardType && type.equals(((TurbineWildcardType) obj).type); |
| } |
| |
| @Override |
| public int hashCode() { |
| return type.hashCode(); |
| } |
| |
| @Override |
| public TypeMirror getExtendsBound() { |
| return type.boundKind() == BoundKind.UPPER ? factory.asTypeMirror(type.bound()) : null; |
| } |
| |
| @Override |
| public TypeMirror getSuperBound() { |
| return type.boundKind() == BoundKind.LOWER ? factory.asTypeMirror(type.bound()) : null; |
| } |
| |
| @Override |
| protected ImmutableList<AnnoInfo> annos() { |
| return type.annotations(); |
| } |
| } |
| |
| /** A {@link IntersectionType} implementation backed by a {@link IntersectionTy}. */ |
| static class TurbineIntersectionType extends TurbineTypeMirror implements IntersectionType { |
| |
| @Override |
| public Type asTurbineType() { |
| return type; |
| } |
| |
| private final IntersectionTy type; |
| |
| TurbineIntersectionType(ModelFactory factory, IntersectionTy type) { |
| super(factory); |
| this.type = type; |
| } |
| |
| @Override |
| public boolean equals(@Nullable Object obj) { |
| return obj instanceof TurbineIntersectionType |
| && type.equals(((TurbineIntersectionType) obj).type); |
| } |
| |
| @Override |
| public int hashCode() { |
| return type.hashCode(); |
| } |
| |
| @Override |
| public TypeKind getKind() { |
| return TypeKind.INTERSECTION; |
| } |
| |
| @Override |
| public <R, P> R accept(TypeVisitor<R, P> v, P p) { |
| return v.visitIntersection(this, p); |
| } |
| |
| final Supplier<ImmutableList<TypeMirror>> bounds = |
| factory.memoize( |
| new Supplier<ImmutableList<TypeMirror>>() { |
| @Override |
| public ImmutableList<TypeMirror> get() { |
| return factory.asTypeMirrors(TurbineTypes.getBounds(factory, type)); |
| } |
| }); |
| |
| @Override |
| public List<? extends TypeMirror> getBounds() { |
| return bounds.get(); |
| } |
| |
| @Override |
| public String toString() { |
| return Joiner.on('&').join(getBounds()); |
| } |
| |
| @Override |
| protected ImmutableList<AnnoInfo> annos() { |
| return ImmutableList.of(); |
| } |
| } |
| |
| /** A {@link NullType} implementation. */ |
| public static class TurbineNullType extends TurbineTypeMirror implements NullType { |
| |
| @Override |
| public Type asTurbineType() { |
| return Type.PrimTy.create(TurbineConstantTypeKind.NULL, ImmutableList.of()); |
| } |
| |
| public TurbineNullType(ModelFactory factory) { |
| super(factory); |
| } |
| |
| @Override |
| protected ImmutableList<AnnoInfo> annos() { |
| return ImmutableList.of(); |
| } |
| |
| @Override |
| public boolean equals(@Nullable Object obj) { |
| return obj instanceof NullType; |
| } |
| |
| @Override |
| public int hashCode() { |
| return super.hashCode(); |
| } |
| |
| @Override |
| public TypeKind getKind() { |
| return TypeKind.NULL; |
| } |
| |
| @Override |
| public <R, P> R accept(TypeVisitor<R, P> v, P p) { |
| return v.visitNull(this, p); |
| } |
| } |
| |
| /** An {@link ExecutableType} implementation backed by a {@link MethodTy}. */ |
| public static class TurbineExecutableType extends TurbineTypeMirror implements ExecutableType { |
| |
| @Override |
| public String toString() { |
| return type.toString(); |
| } |
| |
| @Override |
| public MethodTy asTurbineType() { |
| return type; |
| } |
| |
| public final MethodTy type; |
| |
| TurbineExecutableType(ModelFactory factory, MethodTy type) { |
| super(factory); |
| this.type = type; |
| } |
| |
| @Override |
| public boolean equals(@Nullable Object obj) { |
| return obj instanceof TurbineExecutableType |
| && type.equals(((TurbineExecutableType) obj).type); |
| } |
| |
| @Override |
| public int hashCode() { |
| return type.hashCode(); |
| } |
| |
| @Override |
| public List<? extends TypeVariable> getTypeVariables() { |
| ImmutableList.Builder<TypeVariable> result = ImmutableList.builder(); |
| for (TyVarSymbol tyVar : type.tyParams()) { |
| result.add((TypeVariable) factory.asTypeMirror(TyVar.create(tyVar, ImmutableList.of()))); |
| } |
| return result.build(); |
| } |
| |
| @Override |
| public TypeMirror getReturnType() { |
| return factory.asTypeMirror(type.returnType()); |
| } |
| |
| @Override |
| public List<? extends TypeMirror> getParameterTypes() { |
| return factory.asTypeMirrors(type.parameters()); |
| } |
| |
| @Override |
| public TypeMirror getReceiverType() { |
| return type.receiverType() != null |
| ? factory.asTypeMirror(type.receiverType()) |
| : factory.noType(); |
| } |
| |
| @Override |
| public List<? extends TypeMirror> getThrownTypes() { |
| return factory.asTypeMirrors(type.thrown()); |
| } |
| |
| @Override |
| public TypeKind getKind() { |
| return TypeKind.EXECUTABLE; |
| } |
| |
| @Override |
| public <R, P> R accept(TypeVisitor<R, P> v, P p) { |
| return v.visitExecutable(this, p); |
| } |
| |
| @Override |
| protected ImmutableList<AnnoInfo> annos() { |
| return ImmutableList.of(); |
| } |
| } |
| } |