jjg@1521: /* jjg@1521: * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. jjg@1521: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jjg@1521: * jjg@1521: * This code is free software; you can redistribute it and/or modify it jjg@1521: * under the terms of the GNU General Public License version 2 only, as jjg@1521: * published by the Free Software Foundation. Oracle designates this jjg@1521: * particular file as subject to the "Classpath" exception as provided jjg@1521: * by Oracle in the LICENSE file that accompanied this code. jjg@1521: * jjg@1521: * This code is distributed in the hope that it will be useful, but WITHOUT jjg@1521: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jjg@1521: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jjg@1521: * version 2 for more details (a copy is included in the LICENSE file that jjg@1521: * accompanied this code). jjg@1521: * jjg@1521: * You should have received a copy of the GNU General Public License version jjg@1521: * 2 along with this work; if not, write to the Free Software Foundation, jjg@1521: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jjg@1521: * jjg@1521: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jjg@1521: * or visit www.oracle.com if you need additional information or have any jjg@1521: * questions. jjg@1521: */ jjg@1521: jjg@1521: package com.sun.tools.javac.code; jjg@1521: jjg@1521: import javax.lang.model.element.Element; jjg@1521: import javax.lang.model.element.ElementKind; jjg@1521: import javax.lang.model.type.TypeKind; jjg@1521: jjg@1969: import javax.tools.JavaFileObject; jjg@1969: jjg@1521: import com.sun.tools.javac.code.Attribute.TypeCompound; jjg@1521: import com.sun.tools.javac.code.Type.AnnotatedType; jjg@1521: import com.sun.tools.javac.code.Type.ArrayType; jjg@1521: import com.sun.tools.javac.code.Type.CapturedType; jjg@1521: import com.sun.tools.javac.code.Type.ClassType; jjg@1521: import com.sun.tools.javac.code.Type.ErrorType; jjg@1521: import com.sun.tools.javac.code.Type.ForAll; jjg@1521: import com.sun.tools.javac.code.Type.MethodType; jjg@1521: import com.sun.tools.javac.code.Type.PackageType; jjg@1521: import com.sun.tools.javac.code.Type.TypeVar; jjg@1521: import com.sun.tools.javac.code.Type.UndetVar; jjg@1521: import com.sun.tools.javac.code.Type.Visitor; jjg@1521: import com.sun.tools.javac.code.Type.WildcardType; jjg@1521: import com.sun.tools.javac.code.TypeAnnotationPosition.TypePathEntry; jjg@1521: import com.sun.tools.javac.code.TypeAnnotationPosition.TypePathEntryKind; jjg@1521: import com.sun.tools.javac.code.Symbol.VarSymbol; jjg@1755: import com.sun.tools.javac.code.Symbol.MethodSymbol; jjg@1755: import com.sun.tools.javac.comp.Annotate; jjg@1521: import com.sun.tools.javac.comp.Annotate.Annotator; jlahoda@2111: import com.sun.tools.javac.comp.Attr; jjg@1969: import com.sun.tools.javac.comp.AttrContext; jjg@1969: import com.sun.tools.javac.comp.Env; jjg@1521: import com.sun.tools.javac.tree.JCTree; jjg@1969: import com.sun.tools.javac.tree.TreeInfo; jjg@1521: import com.sun.tools.javac.tree.JCTree.JCBlock; jjg@1521: import com.sun.tools.javac.tree.JCTree.JCClassDecl; jjg@1521: import com.sun.tools.javac.tree.JCTree.JCExpression; jjg@1755: import com.sun.tools.javac.tree.JCTree.JCLambda; jjg@1521: import com.sun.tools.javac.tree.JCTree.JCMethodDecl; jjg@1969: import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; jjg@1755: import com.sun.tools.javac.tree.JCTree.JCNewClass; jjg@1521: import com.sun.tools.javac.tree.JCTree.JCTypeApply; jjg@1521: import com.sun.tools.javac.tree.JCTree.JCVariableDecl; jjg@1521: import com.sun.tools.javac.tree.TreeScanner; jjg@1521: import com.sun.tools.javac.tree.JCTree.*; jjg@1521: import com.sun.tools.javac.util.Assert; jjg@2056: import com.sun.tools.javac.util.Context; jjg@1521: import com.sun.tools.javac.util.List; jjg@1521: import com.sun.tools.javac.util.ListBuffer; jjg@1521: import com.sun.tools.javac.util.Log; jjg@1521: import com.sun.tools.javac.util.Names; emc@2103: import com.sun.tools.javac.util.Options; jjg@1521: jjg@1521: /** jjg@1521: * Contains operations specific to processing type annotations. jjg@1521: * This class has two functions: jjg@1521: * separate declaration from type annotations and insert the type jjg@1521: * annotations to their types; jjg@1521: * and determine the TypeAnnotationPositions for all type annotations. jjg@1521: */ jjg@1521: public class TypeAnnotations { jjg@2056: protected static final Context.Key typeAnnosKey = jjg@2056: new Context.Key(); jjg@2056: jjg@2056: public static TypeAnnotations instance(Context context) { jjg@2056: TypeAnnotations instance = context.get(typeAnnosKey); jjg@2056: if (instance == null) jjg@2056: instance = new TypeAnnotations(context); jjg@2056: return instance; jjg@2056: } jjg@2056: jjg@2056: final Log log; jjg@2056: final Names names; jjg@2056: final Symtab syms; jjg@2056: final Annotate annotate; jlahoda@2111: final Attr attr; emc@2103: private final boolean typeAnnoAsserts; jjg@2056: jjg@2056: protected TypeAnnotations(Context context) { jjg@2056: context.put(typeAnnosKey, this); jjg@2056: names = Names.instance(context); jjg@2056: log = Log.instance(context); jjg@2056: syms = Symtab.instance(context); jjg@2056: annotate = Annotate.instance(context); jlahoda@2111: attr = Attr.instance(context); emc@2103: Options options = Options.instance(context); emc@2103: typeAnnoAsserts = options.isSet("TypeAnnotationAsserts"); jjg@2056: } jjg@1521: jjg@1521: /** jjg@1521: * Separate type annotations from declaration annotations and jjg@1521: * determine the correct positions for type annotations. jjg@1521: * This version only visits types in signatures and should be jjg@1521: * called from MemberEnter. jjg@1755: * The method takes the Annotate object as parameter and jjg@1755: * adds an Annotator to the correct Annotate queue for jjg@1755: * later processing. jjg@1521: */ jjg@2056: public void organizeTypeAnnotationsSignatures(final Env env, final JCClassDecl tree) { jjg@1755: annotate.afterRepeated( new Annotator() { jjg@1521: @Override jjg@1521: public void enterAnnotation() { jjg@1969: JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile); jjg@1969: jjg@1969: try { jjg@2056: new TypeAnnotationPositions(true).scan(tree); jjg@1969: } finally { jjg@1969: log.useSource(oldSource); jjg@1969: } jjg@1521: } jjg@1755: } ); jjg@1521: } jjg@1521: jlahoda@2111: public void validateTypeAnnotationsSignatures(final Env env, final JCClassDecl tree) { jlahoda@2111: annotate.validate(new Annotator() { //validate annotations jlahoda@2111: @Override jlahoda@2111: public void enterAnnotation() { jlahoda@2111: JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile); jlahoda@2111: jlahoda@2111: try { jlahoda@2111: attr.validateTypeAnnotations(tree, true); jlahoda@2111: } finally { jlahoda@2111: log.useSource(oldSource); jlahoda@2111: } jlahoda@2111: } jlahoda@2111: } ); jlahoda@2111: } jlahoda@2111: jjg@1521: /** jjg@1521: * This version only visits types in bodies, that is, field initializers, jjg@1521: * top-level blocks, and method bodies, and should be called from Attr. jjg@1521: */ jjg@2056: public void organizeTypeAnnotationsBodies(JCClassDecl tree) { jjg@2056: new TypeAnnotationPositions(false).scan(tree); jjg@1521: } jjg@1521: jjg@1755: public enum AnnotationType { DECLARATION, TYPE, BOTH }; jjg@1755: jjg@1755: /** jjg@1755: * Determine whether an annotation is a declaration annotation, jjg@1755: * a type annotation, or both. jjg@1755: */ jjg@2056: public AnnotationType annotationType(Attribute.Compound a, Symbol s) { jjg@1755: Attribute.Compound atTarget = jjg@1755: a.type.tsym.attribute(syms.annotationTargetType.tsym); jjg@1755: if (atTarget == null) { jjg@1755: return inferTargetMetaInfo(a, s); jjg@1755: } jjg@1755: Attribute atValue = atTarget.member(names.value); jjg@1755: if (!(atValue instanceof Attribute.Array)) { jjg@1755: Assert.error("annotationType(): bad @Target argument " + atValue + jjg@1755: " (" + atValue.getClass() + ")"); jjg@1755: return AnnotationType.DECLARATION; // error recovery jjg@1755: } jjg@1755: Attribute.Array arr = (Attribute.Array) atValue; jjg@1755: boolean isDecl = false, isType = false; jjg@1755: for (Attribute app : arr.values) { jjg@1755: if (!(app instanceof Attribute.Enum)) { jjg@1755: Assert.error("annotationType(): unrecognized Attribute kind " + app + jjg@1755: " (" + app.getClass() + ")"); jjg@1755: isDecl = true; jjg@1755: continue; jjg@1755: } jjg@1755: Attribute.Enum e = (Attribute.Enum) app; jjg@1755: if (e.value.name == names.TYPE) { jjg@1755: if (s.kind == Kinds.TYP) jjg@1755: isDecl = true; jjg@1755: } else if (e.value.name == names.FIELD) { jjg@1755: if (s.kind == Kinds.VAR && jjg@1755: s.owner.kind != Kinds.MTH) jjg@1755: isDecl = true; jjg@1755: } else if (e.value.name == names.METHOD) { jjg@1755: if (s.kind == Kinds.MTH && jjg@1755: !s.isConstructor()) jjg@1755: isDecl = true; jjg@1755: } else if (e.value.name == names.PARAMETER) { jjg@1755: if (s.kind == Kinds.VAR && jjg@1755: s.owner.kind == Kinds.MTH && jjg@1755: (s.flags() & Flags.PARAMETER) != 0) jjg@1755: isDecl = true; jjg@1755: } else if (e.value.name == names.CONSTRUCTOR) { jjg@1755: if (s.kind == Kinds.MTH && jjg@1755: s.isConstructor()) jjg@1755: isDecl = true; jjg@1755: } else if (e.value.name == names.LOCAL_VARIABLE) { jjg@1755: if (s.kind == Kinds.VAR && jjg@1755: s.owner.kind == Kinds.MTH && jjg@1755: (s.flags() & Flags.PARAMETER) == 0) jjg@1755: isDecl = true; jjg@1755: } else if (e.value.name == names.ANNOTATION_TYPE) { jjg@1755: if (s.kind == Kinds.TYP && jjg@1755: (s.flags() & Flags.ANNOTATION) != 0) jjg@1755: isDecl = true; jjg@1755: } else if (e.value.name == names.PACKAGE) { jjg@1755: if (s.kind == Kinds.PCK) jjg@1755: isDecl = true; jjg@1755: } else if (e.value.name == names.TYPE_USE) { jjg@1755: if (s.kind == Kinds.TYP || jjg@1755: s.kind == Kinds.VAR || jjg@1755: (s.kind == Kinds.MTH && !s.isConstructor() && jjg@1755: !s.type.getReturnType().hasTag(TypeTag.VOID)) || jjg@1755: (s.kind == Kinds.MTH && s.isConstructor())) jjg@1755: isType = true; jjg@1755: } else if (e.value.name == names.TYPE_PARAMETER) { jjg@1755: /* Irrelevant in this case */ jjg@1755: // TYPE_PARAMETER doesn't aid in distinguishing between jjg@1755: // Type annotations and declaration annotations on an jjg@1755: // Element jjg@1755: } else { jjg@1755: Assert.error("annotationType(): unrecognized Attribute name " + e.value.name + jjg@1755: " (" + e.value.name.getClass() + ")"); jjg@1755: isDecl = true; jjg@1755: } jjg@1755: } jjg@1755: if (isDecl && isType) { jjg@1755: return AnnotationType.BOTH; jjg@1755: } else if (isType) { jjg@1755: return AnnotationType.TYPE; jjg@1755: } else { jjg@1755: return AnnotationType.DECLARATION; jjg@1755: } jjg@1755: } jjg@1755: jjg@1755: /** Infer the target annotation kind, if none is give. jjg@1755: * We only infer declaration annotations. jjg@1755: */ jjg@1755: private static AnnotationType inferTargetMetaInfo(Attribute.Compound a, Symbol s) { jjg@1755: return AnnotationType.DECLARATION; jjg@1755: } jjg@1755: jjg@1755: jjg@2056: private class TypeAnnotationPositions extends TreeScanner { jjg@1521: jjg@1521: private final boolean sigOnly; jjg@1521: jjg@2056: TypeAnnotationPositions(boolean sigOnly) { jjg@1521: this.sigOnly = sigOnly; jjg@1521: } jjg@1521: jjg@1521: /* jjg@1521: * When traversing the AST we keep the "frames" of visited jjg@1521: * trees in order to determine the position of annotations. jjg@1521: */ alundblad@2047: private ListBuffer frames = new ListBuffer<>(); jjg@1521: jjg@1521: protected void push(JCTree t) { frames = frames.prepend(t); } jjg@1521: protected JCTree pop() { return frames.next(); } jjg@1521: // could this be frames.elems.tail.head? jjg@1521: private JCTree peek2() { return frames.toList().tail.head; } jjg@1521: jjg@1521: @Override jjg@1521: public void scan(JCTree tree) { jjg@1521: push(tree); jjg@1521: super.scan(tree); jjg@1521: pop(); jjg@1521: } jjg@1521: jjg@1521: /** jjg@1521: * Separates type annotations from declaration annotations. jjg@1521: * This step is needed because in certain locations (where declaration jjg@1521: * and type annotations can be mixed, e.g. the type of a field) jjg@1521: * we never build an JCAnnotatedType. This step finds these jjg@1521: * annotations and marks them as if they were part of the type. jjg@1521: */ jjg@1521: private void separateAnnotationsKinds(JCTree typetree, Type type, Symbol sym, jjg@1521: TypeAnnotationPosition pos) { jjg@1521: List annotations = sym.getRawAttributes(); jjg@1521: ListBuffer declAnnos = new ListBuffer(); jjg@1521: ListBuffer typeAnnos = new ListBuffer(); jjg@1521: jjg@1521: for (Attribute.Compound a : annotations) { jjg@2056: switch (annotationType(a, sym)) { jjg@1521: case DECLARATION: jjg@1521: declAnnos.append(a); jjg@1521: break; jjg@1521: case BOTH: { jjg@1521: declAnnos.append(a); jjg@1521: Attribute.TypeCompound ta = toTypeCompound(a, pos); jjg@1521: typeAnnos.append(ta); jjg@1521: break; jjg@1521: } jjg@1521: case TYPE: { jjg@1521: Attribute.TypeCompound ta = toTypeCompound(a, pos); jjg@1521: typeAnnos.append(ta); jjg@1521: break; jjg@1521: } jjg@1521: } jjg@1521: } jjg@1521: jjg@1802: sym.resetAnnotations(); jjg@1802: sym.setDeclarationAttributes(declAnnos.toList()); jjg@1521: jjg@1755: if (typeAnnos.isEmpty()) { jjg@1755: return; jjg@1755: } jjg@1755: jjg@1521: List typeAnnotations = typeAnnos.toList(); jjg@1521: jjg@1521: if (type == null) { jjg@1521: // When type is null, put the type annotations to the symbol. jjg@1521: // This is used for constructor return annotations, for which jjg@1521: // no appropriate type exists. jjg@1802: sym.appendUniqueTypeAttributes(typeAnnotations); jjg@1521: return; jjg@1521: } jjg@1521: jjg@1521: // type is non-null and annotations are added to that type jjg@2056: type = typeWithAnnotations(typetree, type, typeAnnotations); jjg@1521: jjg@1521: if (sym.getKind() == ElementKind.METHOD) { jjg@1521: sym.type.asMethodType().restype = type; jjg@1755: } else if (sym.getKind() == ElementKind.PARAMETER) { jjg@1755: sym.type = type; jjg@1755: if (sym.getQualifiedName().equals(names._this)) { jjg@1755: sym.owner.type.asMethodType().recvtype = type; jjg@1755: // note that the typeAnnotations will also be added to the owner below. jjg@1755: } else { jjg@1755: MethodType methType = sym.owner.type.asMethodType(); jjg@1755: List params = ((MethodSymbol)sym.owner).params; jjg@1755: List oldArgs = methType.argtypes; jjg@1755: ListBuffer newArgs = new ListBuffer(); jjg@1755: while (params.nonEmpty()) { jjg@1755: if (params.head == sym) { jjg@1755: newArgs.add(type); jjg@1755: } else { jjg@1755: newArgs.add(oldArgs.head); jjg@1755: } jjg@1755: oldArgs = oldArgs.tail; jjg@1755: params = params.tail; jjg@1755: } jjg@1755: methType.argtypes = newArgs.toList(); jjg@1755: } jjg@1521: } else { jjg@1521: sym.type = type; jjg@1521: } jjg@1521: jjg@1802: sym.appendUniqueTypeAttributes(typeAnnotations); jjg@1755: jjg@1521: if (sym.getKind() == ElementKind.PARAMETER || jjg@1521: sym.getKind() == ElementKind.LOCAL_VARIABLE || jjg@1521: sym.getKind() == ElementKind.RESOURCE_VARIABLE || jjg@1521: sym.getKind() == ElementKind.EXCEPTION_PARAMETER) { jjg@1521: // Make sure all type annotations from the symbol are also jjg@1521: // on the owner. jjg@1802: sym.owner.appendUniqueTypeAttributes(sym.getRawTypeAttributes()); jjg@1521: } jjg@1521: } jjg@1521: jjg@1521: // This method has a similar purpose as jjg@1521: // {@link com.sun.tools.javac.parser.JavacParser.insertAnnotationsToMostInner(JCExpression, List, boolean)} jjg@1521: // We found a type annotation in a declaration annotation position, jjg@1521: // for example, on the return type. jjg@1521: // Such an annotation is _not_ part of an JCAnnotatedType tree and we therefore jjg@1521: // need to set its position explicitly. jjg@1521: // The method returns a copy of type that contains these annotations. jjg@1563: // jjg@1563: // As a side effect the method sets the type annotation position of "annotations". jjg@1563: // Note that it is assumed that all annotations share the same position. jjg@2056: private Type typeWithAnnotations(final JCTree typetree, final Type type, jjg@2056: final List annotations) { jjg@1521: // System.out.printf("typeWithAnnotations(typetree: %s, type: %s, annotations: %s)%n", jjg@1521: // typetree, type, annotations); jjg@1521: if (annotations.isEmpty()) { jjg@1521: return type; jjg@1521: } jjg@1521: if (type.hasTag(TypeTag.ARRAY)) { jjg@1521: Type toreturn; jjg@1521: Type.ArrayType tomodify; jjg@1521: Type.ArrayType arType; jjg@1521: { jjg@1521: Type touse = type; jjg@1644: if (type.isAnnotated()) { jjg@1521: Type.AnnotatedType atype = (Type.AnnotatedType)type; jjg@1521: toreturn = new Type.AnnotatedType(atype.underlyingType); jjg@1521: ((Type.AnnotatedType)toreturn).typeAnnotations = atype.typeAnnotations; jjg@1521: touse = atype.underlyingType; jjg@1521: arType = (Type.ArrayType) touse; jjg@1521: tomodify = new Type.ArrayType(null, arType.tsym); jjg@1521: ((Type.AnnotatedType)toreturn).underlyingType = tomodify; jjg@1521: } else { jjg@1521: arType = (Type.ArrayType) touse; jjg@1521: tomodify = new Type.ArrayType(null, arType.tsym); jjg@1521: toreturn = tomodify; jjg@1521: } jjg@1521: } jjg@1521: JCArrayTypeTree arTree = arrayTypeTree(typetree); jjg@1521: alundblad@2047: ListBuffer depth = new ListBuffer<>(); jjg@1521: depth = depth.append(TypePathEntry.ARRAY); jjg@1521: while (arType.elemtype.hasTag(TypeTag.ARRAY)) { jjg@1644: if (arType.elemtype.isAnnotated()) { jjg@1521: Type.AnnotatedType aelemtype = (Type.AnnotatedType) arType.elemtype; jjg@1521: Type.AnnotatedType newAT = new Type.AnnotatedType(aelemtype.underlyingType); jjg@1521: tomodify.elemtype = newAT; jjg@1521: newAT.typeAnnotations = aelemtype.typeAnnotations; jjg@1521: arType = (Type.ArrayType) aelemtype.underlyingType; jjg@1521: tomodify = new Type.ArrayType(null, arType.tsym); jjg@1521: newAT.underlyingType = tomodify; jjg@1521: } else { jjg@1521: arType = (Type.ArrayType) arType.elemtype; jjg@1521: tomodify.elemtype = new Type.ArrayType(null, arType.tsym); jjg@1521: tomodify = (Type.ArrayType) tomodify.elemtype; jjg@1521: } jjg@1521: arTree = arrayTypeTree(arTree.elemtype); jjg@1521: depth = depth.append(TypePathEntry.ARRAY); jjg@1521: } jjg@2056: Type arelemType = typeWithAnnotations(arTree.elemtype, arType.elemtype, annotations); jjg@1521: tomodify.elemtype = arelemType; jjg@1563: { jjg@1563: // All annotations share the same position; modify the first one. jjg@1563: Attribute.TypeCompound a = annotations.get(0); jjg@1521: TypeAnnotationPosition p = a.position; jjg@1521: p.location = p.location.prependList(depth.toList()); jjg@1521: } jjg@1755: typetree.type = toreturn; jjg@1521: return toreturn; jjg@1521: } else if (type.hasTag(TypeTag.TYPEVAR)) { jjg@1521: // Nothing to do for type variables. jjg@1521: return type; jjg@1755: } else if (type.getKind() == TypeKind.UNION) { jjg@1755: // There is a TypeKind, but no TypeTag. jjg@1755: JCTypeUnion tutree = (JCTypeUnion) typetree; jjg@1755: JCExpression fst = tutree.alternatives.get(0); jjg@2056: Type res = typeWithAnnotations(fst, fst.type, annotations); jjg@1755: fst.type = res; jjg@1755: // TODO: do we want to set res as first element in uct.alternatives? jjg@1755: // UnionClassType uct = (com.sun.tools.javac.code.Type.UnionClassType)type; jjg@1755: // Return the un-annotated union-type. jjg@1755: return type; jjg@1521: } else { jjg@1521: Type enclTy = type; jjg@1521: Element enclEl = type.asElement(); jjg@1521: JCTree enclTr = typetree; jjg@1521: jjg@1521: while (enclEl != null && jjg@1521: enclEl.getKind() != ElementKind.PACKAGE && jjg@1521: enclTy != null && jjg@1521: enclTy.getKind() != TypeKind.NONE && jjg@1521: enclTy.getKind() != TypeKind.ERROR && jjg@1521: (enclTr.getKind() == JCTree.Kind.MEMBER_SELECT || jjg@1521: enclTr.getKind() == JCTree.Kind.PARAMETERIZED_TYPE || jjg@1521: enclTr.getKind() == JCTree.Kind.ANNOTATED_TYPE)) { jjg@1521: // Iterate also over the type tree, not just the type: the type is already jjg@1521: // completely resolved and we cannot distinguish where the annotation jjg@1521: // belongs for a nested type. jjg@1521: if (enclTr.getKind() == JCTree.Kind.MEMBER_SELECT) { jjg@1521: // only change encl in this case. jjg@1521: enclTy = enclTy.getEnclosingType(); jjg@1521: enclEl = enclEl.getEnclosingElement(); jjg@1521: enclTr = ((JCFieldAccess)enclTr).getExpression(); jjg@1521: } else if (enclTr.getKind() == JCTree.Kind.PARAMETERIZED_TYPE) { jjg@1521: enclTr = ((JCTypeApply)enclTr).getType(); jjg@1521: } else { jjg@1521: // only other option because of while condition jjg@1521: enclTr = ((JCAnnotatedType)enclTr).getUnderlyingType(); jjg@1521: } jjg@1521: } jjg@1521: jjg@1521: /** We are trying to annotate some enclosing type, jjg@1521: * but nothing more exists. jjg@1521: */ jjg@1521: if (enclTy != null && jjg@1521: enclTy.getKind() == TypeKind.NONE && jjg@1521: (enclTr.getKind() == JCTree.Kind.IDENTIFIER || jjg@1521: enclTr.getKind() == JCTree.Kind.MEMBER_SELECT || jjg@1521: enclTr.getKind() == JCTree.Kind.PARAMETERIZED_TYPE || jjg@1521: enclTr.getKind() == JCTree.Kind.ANNOTATED_TYPE)) { jjg@1521: // TODO: also if it's "java. @A lang.Object", that is, jjg@1521: // if it's on a package? jjg@1521: log.error(enclTr.pos(), "cant.annotate.nested.type", enclTr.toString()); jjg@1521: return type; jjg@1521: } jjg@1521: jjg@1521: // At this point we have visited the part of the nested jjg@1521: // type that is written in the source code. jjg@1521: // Now count from here to the actual top-level class to determine jjg@1521: // the correct nesting. jjg@1521: jjg@1521: // The genericLocation for the annotation. alundblad@2047: ListBuffer depth = new ListBuffer<>(); jjg@1521: jjg@1521: Type topTy = enclTy; jjg@1521: while (enclEl != null && jjg@1521: enclEl.getKind() != ElementKind.PACKAGE && jjg@1521: topTy != null && jjg@1521: topTy.getKind() != TypeKind.NONE && jjg@1521: topTy.getKind() != TypeKind.ERROR) { jjg@1521: topTy = topTy.getEnclosingType(); jjg@1521: enclEl = enclEl.getEnclosingElement(); jjg@1521: jjg@1521: if (topTy != null && topTy.getKind() != TypeKind.NONE) { jjg@1521: // Only count enclosing types. jjg@1521: depth = depth.append(TypePathEntry.INNER_TYPE); jjg@1521: } jjg@1521: } jjg@1521: jjg@1521: if (depth.nonEmpty()) { jjg@1521: // Only need to change the annotation positions jjg@1521: // if they are on an enclosed type. jjg@1563: // All annotations share the same position; modify the first one. jjg@1563: Attribute.TypeCompound a = annotations.get(0); jjg@1563: TypeAnnotationPosition p = a.position; jjg@1563: p.location = p.location.appendList(depth.toList()); jjg@1521: } jjg@1521: jjg@1521: Type ret = typeWithAnnotations(type, enclTy, annotations); jjg@1755: typetree.type = ret; jjg@1521: return ret; jjg@1521: } jjg@1521: } jjg@1521: jjg@2056: private JCArrayTypeTree arrayTypeTree(JCTree typetree) { jjg@1521: if (typetree.getKind() == JCTree.Kind.ARRAY_TYPE) { jjg@1521: return (JCArrayTypeTree) typetree; jjg@1521: } else if (typetree.getKind() == JCTree.Kind.ANNOTATED_TYPE) { jjg@1521: return (JCArrayTypeTree) ((JCAnnotatedType)typetree).underlyingType; jjg@1521: } else { jjg@1521: Assert.error("Could not determine array type from type tree: " + typetree); jjg@1521: return null; jjg@1521: } jjg@1521: } jjg@1521: jjg@1521: /** Return a copy of the first type that only differs by jjg@1521: * inserting the annotations to the left-most/inner-most type jjg@1521: * or the type given by stopAt. jjg@1521: * jjg@1521: * We need the stopAt parameter to know where on a type to jjg@1521: * put the annotations. jjg@1521: * If we have nested classes Outer > Middle > Inner, and we jjg@1521: * have the source type "@A Middle.Inner", we will invoke jjg@1521: * this method with type = Outer.Middle.Inner, jjg@1521: * stopAt = Middle.Inner, and annotations = @A. jjg@1521: * jjg@1521: * @param type The type to copy. jjg@1521: * @param stopAt The type to stop at. jjg@1521: * @param annotations The annotations to insert. jjg@1521: * @return A copy of type that contains the annotations. jjg@1521: */ jjg@2056: private Type typeWithAnnotations(final Type type, jjg@1521: final Type stopAt, jjg@1521: final List annotations) { jjg@1521: Visitor> visitor = jjg@1521: new Type.Visitor>() { jjg@1521: @Override jjg@1521: public Type visitClassType(ClassType t, List s) { jjg@1521: // assert that t.constValue() == null? jjg@1521: if (t == stopAt || jjg@1521: t.getEnclosingType() == Type.noType) { jjg@1521: return new AnnotatedType(s, t); jjg@1521: } else { jjg@1521: ClassType ret = new ClassType(t.getEnclosingType().accept(this, s), jjg@1521: t.typarams_field, t.tsym); jjg@1521: ret.all_interfaces_field = t.all_interfaces_field; jjg@1521: ret.allparams_field = t.allparams_field; jjg@1521: ret.interfaces_field = t.interfaces_field; jjg@1521: ret.rank_field = t.rank_field; jjg@1521: ret.supertype_field = t.supertype_field; jjg@1521: return ret; jjg@1521: } jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public Type visitAnnotatedType(AnnotatedType t, List s) { jjg@1521: return new AnnotatedType(t.typeAnnotations, t.underlyingType.accept(this, s)); jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public Type visitWildcardType(WildcardType t, List s) { jjg@1521: return new AnnotatedType(s, t); jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public Type visitArrayType(ArrayType t, List s) { jjg@1521: ArrayType ret = new ArrayType(t.elemtype.accept(this, s), t.tsym); jjg@1521: return ret; jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public Type visitMethodType(MethodType t, List s) { jjg@1521: // Impossible? jjg@1521: return t; jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public Type visitPackageType(PackageType t, List s) { jjg@1521: // Impossible? jjg@1521: return t; jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public Type visitTypeVar(TypeVar t, List s) { jjg@1521: return new AnnotatedType(s, t); jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public Type visitCapturedType(CapturedType t, List s) { jjg@1521: return new AnnotatedType(s, t); jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public Type visitForAll(ForAll t, List s) { jjg@1521: // Impossible? jjg@1521: return t; jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public Type visitUndetVar(UndetVar t, List s) { jjg@1521: // Impossible? jjg@1521: return t; jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public Type visitErrorType(ErrorType t, List s) { jjg@1521: return new AnnotatedType(s, t); jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public Type visitType(Type t, List s) { jjg@1563: return new AnnotatedType(s, t); jjg@1521: } jjg@1521: }; jjg@1521: jjg@1521: return type.accept(visitor, annotations); jjg@1521: } jjg@1521: jjg@2056: private Attribute.TypeCompound toTypeCompound(Attribute.Compound a, TypeAnnotationPosition p) { jjg@1521: // It is safe to alias the position. jjg@1521: return new Attribute.TypeCompound(a, p); jjg@1521: } jjg@1521: jjg@1521: jjg@1521: /* This is the beginning of the second part of organizing jjg@1521: * type annotations: determine the type annotation positions. jjg@1521: */ jjg@1521: jjg@1521: private void resolveFrame(JCTree tree, JCTree frame, jjg@1521: List path, TypeAnnotationPosition p) { jjg@1521: /* jjg@1521: System.out.println("Resolving tree: " + tree + " kind: " + tree.getKind()); jjg@1521: System.out.println(" Framing tree: " + frame + " kind: " + frame.getKind()); jjg@1521: */ jjg@1563: jjg@1563: // Note that p.offset is set in jjg@1563: // com.sun.tools.javac.jvm.Gen.setTypeAnnotationPositions(int) jjg@1563: jjg@1521: switch (frame.getKind()) { jjg@1521: case TYPE_CAST: jjg@1755: JCTypeCast frameTC = (JCTypeCast) frame; jjg@1521: p.type = TargetType.CAST; jjg@1755: if (frameTC.clazz.hasTag(Tag.TYPEINTERSECTION)) { jjg@1755: // This case was already handled by INTERSECTION_TYPE jjg@1755: } else { jjg@1755: p.type_index = 0; jjg@1755: } jjg@1521: p.pos = frame.pos; jjg@1521: return; jjg@1521: jjg@1521: case INSTANCE_OF: jjg@1521: p.type = TargetType.INSTANCEOF; jjg@1521: p.pos = frame.pos; jjg@1521: return; jjg@1521: jjg@1521: case NEW_CLASS: jjg@1755: JCNewClass frameNewClass = (JCNewClass) frame; jjg@1755: if (frameNewClass.def != null) { jjg@1755: // Special handling for anonymous class instantiations jjg@1755: JCClassDecl frameClassDecl = frameNewClass.def; jjg@1755: if (frameClassDecl.extending == tree) { jjg@1755: p.type = TargetType.CLASS_EXTENDS; jjg@1755: p.type_index = -1; jjg@1755: } else if (frameClassDecl.implementing.contains(tree)) { jjg@1755: p.type = TargetType.CLASS_EXTENDS; jjg@1755: p.type_index = frameClassDecl.implementing.indexOf(tree); jjg@1755: } else { jjg@1755: // In contrast to CLASS below, typarams cannot occur here. jjg@1755: Assert.error("Could not determine position of tree " + tree + jjg@1755: " within frame " + frame); jjg@1755: } jjg@1755: } else if (frameNewClass.typeargs.contains(tree)) { jjg@1521: p.type = TargetType.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT; jjg@1521: p.type_index = frameNewClass.typeargs.indexOf(tree); jjg@1521: } else { jjg@1521: p.type = TargetType.NEW; jjg@1521: } jjg@1521: p.pos = frame.pos; jjg@1521: return; jjg@1521: jjg@1521: case NEW_ARRAY: jjg@1521: p.type = TargetType.NEW; jjg@1521: p.pos = frame.pos; jjg@1521: return; jjg@1521: jjg@1521: case ANNOTATION_TYPE: jjg@1521: case CLASS: jjg@1521: case ENUM: jjg@1521: case INTERFACE: jjg@1521: p.pos = frame.pos; jjg@1521: if (((JCClassDecl)frame).extending == tree) { jjg@1521: p.type = TargetType.CLASS_EXTENDS; jjg@1521: p.type_index = -1; jjg@1521: } else if (((JCClassDecl)frame).implementing.contains(tree)) { jjg@1521: p.type = TargetType.CLASS_EXTENDS; jjg@1521: p.type_index = ((JCClassDecl)frame).implementing.indexOf(tree); jjg@1521: } else if (((JCClassDecl)frame).typarams.contains(tree)) { jjg@1521: p.type = TargetType.CLASS_TYPE_PARAMETER; jjg@1521: p.parameter_index = ((JCClassDecl)frame).typarams.indexOf(tree); jjg@1521: } else { jjg@1521: Assert.error("Could not determine position of tree " + tree + jjg@1521: " within frame " + frame); jjg@1521: } jjg@1521: return; jjg@1521: jjg@1521: case METHOD: { jjg@1521: JCMethodDecl frameMethod = (JCMethodDecl) frame; jjg@1521: p.pos = frame.pos; jjg@1521: if (frameMethod.thrown.contains(tree)) { jjg@1521: p.type = TargetType.THROWS; jjg@1521: p.type_index = frameMethod.thrown.indexOf(tree); jjg@1521: } else if (frameMethod.restype == tree) { jjg@1521: p.type = TargetType.METHOD_RETURN; jjg@1521: } else if (frameMethod.typarams.contains(tree)) { jjg@1521: p.type = TargetType.METHOD_TYPE_PARAMETER; jjg@1521: p.parameter_index = frameMethod.typarams.indexOf(tree); jjg@1521: } else { jjg@1521: Assert.error("Could not determine position of tree " + tree + jjg@1521: " within frame " + frame); jjg@1521: } jjg@1521: return; jjg@1521: } jjg@1521: jjg@1521: case PARAMETERIZED_TYPE: { jjg@1755: List newPath = path.tail; jjg@1755: jjg@1521: if (((JCTypeApply)frame).clazz == tree) { jjg@1521: // generic: RAW; noop jjg@1521: } else if (((JCTypeApply)frame).arguments.contains(tree)) { jjg@1521: JCTypeApply taframe = (JCTypeApply) frame; jjg@1521: int arg = taframe.arguments.indexOf(tree); jjg@1521: p.location = p.location.prepend(new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, arg)); jjg@1521: jjg@1755: Type typeToUse; jjg@1755: if (newPath.tail != null && newPath.tail.head.hasTag(Tag.NEWCLASS)) { jjg@1755: // If we are within an anonymous class instantiation, use its type, jjg@1755: // because it contains a correctly nested type. jjg@1755: typeToUse = newPath.tail.head.type; jjg@1755: } else { jjg@1755: typeToUse = taframe.type; jjg@1755: } jjg@1755: jjg@1755: locateNestedTypes(typeToUse, p); jjg@1521: } else { jjg@1521: Assert.error("Could not determine type argument position of tree " + tree + jjg@1521: " within frame " + frame); jjg@1521: } jjg@1521: jjg@1521: resolveFrame(newPath.head, newPath.tail.head, newPath, p); jjg@1521: return; jjg@1521: } jjg@1521: jjg@1563: case MEMBER_REFERENCE: { jjg@1563: JCMemberReference mrframe = (JCMemberReference) frame; jjg@1563: jjg@1563: if (mrframe.expr == tree) { jjg@1563: switch (mrframe.mode) { jjg@1563: case INVOKE: jjg@1563: p.type = TargetType.METHOD_REFERENCE; jjg@1563: break; jjg@1563: case NEW: jjg@1563: p.type = TargetType.CONSTRUCTOR_REFERENCE; jjg@1563: break; jjg@1563: default: jjg@1563: Assert.error("Unknown method reference mode " + mrframe.mode + jjg@1563: " for tree " + tree + " within frame " + frame); jjg@1563: } jjg@1563: p.pos = frame.pos; jjg@1563: } else if (mrframe.typeargs != null && jjg@1563: mrframe.typeargs.contains(tree)) { jjg@1563: int arg = mrframe.typeargs.indexOf(tree); jjg@1563: p.type_index = arg; jjg@1563: switch (mrframe.mode) { jjg@1563: case INVOKE: jjg@1563: p.type = TargetType.METHOD_REFERENCE_TYPE_ARGUMENT; jjg@1563: break; jjg@1563: case NEW: jjg@1563: p.type = TargetType.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT; jjg@1563: break; jjg@1563: default: jjg@1563: Assert.error("Unknown method reference mode " + mrframe.mode + jjg@1563: " for tree " + tree + " within frame " + frame); jjg@1563: } jjg@1563: p.pos = frame.pos; jjg@1563: } else { jjg@1563: Assert.error("Could not determine type argument position of tree " + tree + jjg@1563: " within frame " + frame); jjg@1563: } jjg@1563: return; jjg@1563: } jjg@1563: jjg@1521: case ARRAY_TYPE: { alundblad@2047: ListBuffer index = new ListBuffer<>(); jjg@1521: index = index.append(TypePathEntry.ARRAY); jjg@1521: List newPath = path.tail; jjg@1521: while (true) { jjg@1521: JCTree npHead = newPath.tail.head; jjg@1521: if (npHead.hasTag(JCTree.Tag.TYPEARRAY)) { jjg@1521: newPath = newPath.tail; jjg@1521: index = index.append(TypePathEntry.ARRAY); jjg@1521: } else if (npHead.hasTag(JCTree.Tag.ANNOTATED_TYPE)) { jjg@1521: newPath = newPath.tail; jjg@1521: } else { jjg@1521: break; jjg@1521: } jjg@1521: } jjg@1521: p.location = p.location.prependList(index.toList()); jjg@1521: resolveFrame(newPath.head, newPath.tail.head, newPath, p); jjg@1521: return; jjg@1521: } jjg@1521: jjg@1521: case TYPE_PARAMETER: jjg@1521: if (path.tail.tail.head.hasTag(JCTree.Tag.CLASSDEF)) { jjg@1521: JCClassDecl clazz = (JCClassDecl)path.tail.tail.head; jjg@1521: p.type = TargetType.CLASS_TYPE_PARAMETER_BOUND; jjg@1521: p.parameter_index = clazz.typarams.indexOf(path.tail.head); jjg@1521: p.bound_index = ((JCTypeParameter)frame).bounds.indexOf(tree); jjg@1521: if (((JCTypeParameter)frame).bounds.get(0).type.isInterface()) { jjg@1521: // Account for an implicit Object as bound 0 jjg@1521: p.bound_index += 1; jjg@1521: } jjg@1521: } else if (path.tail.tail.head.hasTag(JCTree.Tag.METHODDEF)) { jjg@1521: JCMethodDecl method = (JCMethodDecl)path.tail.tail.head; jjg@1521: p.type = TargetType.METHOD_TYPE_PARAMETER_BOUND; jjg@1521: p.parameter_index = method.typarams.indexOf(path.tail.head); jjg@1521: p.bound_index = ((JCTypeParameter)frame).bounds.indexOf(tree); jjg@1521: if (((JCTypeParameter)frame).bounds.get(0).type.isInterface()) { jjg@1521: // Account for an implicit Object as bound 0 jjg@1521: p.bound_index += 1; jjg@1521: } jjg@1521: } else { jjg@1521: Assert.error("Could not determine position of tree " + tree + jjg@1521: " within frame " + frame); jjg@1521: } jjg@1521: p.pos = frame.pos; jjg@1521: return; jjg@1521: jjg@1521: case VARIABLE: jjg@1521: VarSymbol v = ((JCVariableDecl)frame).sym; jjg@1521: p.pos = frame.pos; jjg@1521: switch (v.getKind()) { jjg@1521: case LOCAL_VARIABLE: jjg@1521: p.type = TargetType.LOCAL_VARIABLE; jjg@1521: break; jjg@1521: case FIELD: jjg@1521: p.type = TargetType.FIELD; jjg@1521: break; jjg@1521: case PARAMETER: jjg@1521: if (v.getQualifiedName().equals(names._this)) { jjg@1521: // TODO: Intro a separate ElementKind? jjg@1521: p.type = TargetType.METHOD_RECEIVER; jjg@1521: } else { jjg@1521: p.type = TargetType.METHOD_FORMAL_PARAMETER; jjg@1521: p.parameter_index = methodParamIndex(path, frame); jjg@1521: } jjg@1521: break; jjg@1521: case EXCEPTION_PARAMETER: jjg@1521: p.type = TargetType.EXCEPTION_PARAMETER; jjg@1521: break; jjg@1521: case RESOURCE_VARIABLE: jjg@1521: p.type = TargetType.RESOURCE_VARIABLE; jjg@1521: break; jjg@1521: default: jjg@1521: Assert.error("Found unexpected type annotation for variable: " + v + " with kind: " + v.getKind()); jjg@1521: } jjg@1755: if (v.getKind() != ElementKind.FIELD) { jjg@1802: v.owner.appendUniqueTypeAttributes(v.getRawTypeAttributes()); jjg@1755: } jjg@1521: return; jjg@1521: jjg@1521: case ANNOTATED_TYPE: { jjg@1521: if (frame == tree) { jjg@1521: // This is only true for the first annotated type we see. jjg@1521: // For any other annotated types along the path, we do jjg@1521: // not care about inner types. jjg@1521: JCAnnotatedType atypetree = (JCAnnotatedType) frame; jjg@1521: final Type utype = atypetree.underlyingType.type; jjg@1755: if (utype == null) { jjg@1755: // This might happen during DeferredAttr; jjg@1755: // we will be back later. jjg@1755: return; jjg@1755: } jjg@1521: Symbol tsym = utype.tsym; jjg@1521: if (tsym.getKind().equals(ElementKind.TYPE_PARAMETER) || jjg@1521: utype.getKind().equals(TypeKind.WILDCARD) || jjg@1521: utype.getKind().equals(TypeKind.ARRAY)) { jjg@1521: // Type parameters, wildcards, and arrays have the declaring jjg@1521: // class/method as enclosing elements. jjg@1521: // There is actually nothing to do for them. jjg@1521: } else { jjg@1521: locateNestedTypes(utype, p); jjg@1521: } jjg@1521: } jjg@1521: List newPath = path.tail; jjg@1521: resolveFrame(newPath.head, newPath.tail.head, newPath, p); jjg@1521: return; jjg@1521: } jjg@1521: jjg@1521: case UNION_TYPE: { jjg@1521: List newPath = path.tail; jjg@1521: resolveFrame(newPath.head, newPath.tail.head, newPath, p); jjg@1521: return; jjg@1521: } jjg@1521: jjg@1563: case INTERSECTION_TYPE: { jjg@1563: JCTypeIntersection isect = (JCTypeIntersection)frame; jjg@1563: p.type_index = isect.bounds.indexOf(tree); jjg@1563: List newPath = path.tail; jjg@1563: resolveFrame(newPath.head, newPath.tail.head, newPath, p); jjg@1563: return; jjg@1563: } jjg@1563: jjg@1521: case METHOD_INVOCATION: { jjg@1521: JCMethodInvocation invocation = (JCMethodInvocation)frame; jjg@1521: if (!invocation.typeargs.contains(tree)) { jjg@1521: Assert.error("{" + tree + "} is not an argument in the invocation: " + invocation); jjg@1521: } jjg@1969: MethodSymbol exsym = (MethodSymbol) TreeInfo.symbol(invocation.getMethodSelect()); jjg@1969: if (exsym == null) { jjg@1969: Assert.error("could not determine symbol for {" + invocation + "}"); jjg@1969: } else if (exsym.isConstructor()) { jjg@1969: p.type = TargetType.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT; jjg@1969: } else { jjg@1969: p.type = TargetType.METHOD_INVOCATION_TYPE_ARGUMENT; jjg@1969: } jjg@1521: p.pos = invocation.pos; jjg@1521: p.type_index = invocation.typeargs.indexOf(tree); jjg@1521: return; jjg@1521: } jjg@1521: jjg@1521: case EXTENDS_WILDCARD: jjg@1521: case SUPER_WILDCARD: { jjg@1521: // Annotations in wildcard bounds jjg@1521: p.location = p.location.prepend(TypePathEntry.WILDCARD); jjg@1521: List newPath = path.tail; jjg@1521: resolveFrame(newPath.head, newPath.tail.head, newPath, p); jjg@1521: return; jjg@1521: } jjg@1521: jjg@1521: case MEMBER_SELECT: { jjg@1521: List newPath = path.tail; jjg@1521: resolveFrame(newPath.head, newPath.tail.head, newPath, p); jjg@1521: return; jjg@1521: } jjg@1521: jjg@1521: default: jjg@1521: Assert.error("Unresolved frame: " + frame + " of kind: " + frame.getKind() + jjg@1521: "\n Looking for tree: " + tree); jjg@1521: return; jjg@1521: } jjg@1521: } jjg@1521: jjg@2056: private void locateNestedTypes(Type type, TypeAnnotationPosition p) { jjg@1521: // The number of "steps" to get from the full type to the jjg@1521: // left-most outer type. alundblad@2047: ListBuffer depth = new ListBuffer<>(); jjg@1521: jjg@1521: Type encl = type.getEnclosingType(); jjg@1521: while (encl != null && jjg@1521: encl.getKind() != TypeKind.NONE && jjg@1521: encl.getKind() != TypeKind.ERROR) { jjg@1521: depth = depth.append(TypePathEntry.INNER_TYPE); jjg@1521: encl = encl.getEnclosingType(); jjg@1521: } jjg@1521: if (depth.nonEmpty()) { jjg@1521: p.location = p.location.prependList(depth.toList()); jjg@1521: } jjg@1521: } jjg@1521: jjg@2056: private int methodParamIndex(List path, JCTree param) { jjg@1521: List curr = path; jjg@1755: while (curr.head.getTag() != Tag.METHODDEF && jjg@1755: curr.head.getTag() != Tag.LAMBDA) { jjg@1521: curr = curr.tail; jjg@1521: } jjg@1755: if (curr.head.getTag() == Tag.METHODDEF) { jjg@1755: JCMethodDecl method = (JCMethodDecl)curr.head; jjg@1755: return method.params.indexOf(param); jjg@1755: } else if (curr.head.getTag() == Tag.LAMBDA) { jjg@1755: JCLambda lambda = (JCLambda)curr.head; jjg@1755: return lambda.params.indexOf(param); jjg@1755: } else { jjg@1755: Assert.error("methodParamIndex expected to find method or lambda for param: " + param); jjg@1755: return -1; jjg@1755: } jjg@1521: } jjg@1521: jjg@1521: // Each class (including enclosed inner classes) is visited separately. jjg@1521: // This flag is used to prevent from visiting inner classes. jjg@1521: private boolean isInClass = false; jjg@1521: jjg@1521: @Override jjg@1521: public void visitClassDef(JCClassDecl tree) { jjg@1521: if (isInClass) jjg@1521: return; jjg@1521: isInClass = true; jjg@1755: jjg@1521: if (sigOnly) { jjg@1521: scan(tree.mods); jjg@1521: scan(tree.typarams); jjg@1521: scan(tree.extending); jjg@1521: scan(tree.implementing); jjg@1521: } jjg@1521: scan(tree.defs); jjg@1521: } jjg@1521: jjg@1521: /** jjg@1521: * Resolve declaration vs. type annotations in methods and jjg@1521: * then determine the positions. jjg@1521: */ jjg@1521: @Override jjg@1521: public void visitMethodDef(final JCMethodDecl tree) { jjg@1521: if (tree.sym == null) { emc@2103: if (typeAnnoAsserts) { emc@2103: Assert.error("Visiting tree node before memberEnter"); emc@2103: } else { jjg@1521: return; jjg@1521: } emc@2103: } jjg@1521: if (sigOnly) { jjg@1755: if (!tree.mods.annotations.isEmpty()) { jjg@1755: // Nothing to do for separateAnnotationsKinds if jjg@1755: // there are no annotations of either kind. jjg@1521: TypeAnnotationPosition pos = new TypeAnnotationPosition(); jjg@1521: pos.type = TargetType.METHOD_RETURN; jjg@1521: if (tree.sym.isConstructor()) { jjg@1521: pos.pos = tree.pos; jjg@1521: // Use null to mark that the annotations go with the symbol. jjg@1521: separateAnnotationsKinds(tree, null, tree.sym, pos); jjg@1521: } else { jjg@1521: pos.pos = tree.restype.pos; jjg@1521: separateAnnotationsKinds(tree.restype, tree.sym.type.getReturnType(), jjg@1521: tree.sym, pos); jjg@1521: } jjg@1521: } jjg@1755: if (tree.recvparam != null && tree.recvparam.sym != null && jjg@1755: !tree.recvparam.mods.annotations.isEmpty()) { jjg@1755: // Nothing to do for separateAnnotationsKinds if jjg@1755: // there are no annotations of either kind. jjg@1521: // TODO: make sure there are no declaration annotations. jjg@1521: TypeAnnotationPosition pos = new TypeAnnotationPosition(); jjg@1521: pos.type = TargetType.METHOD_RECEIVER; jjg@1521: pos.pos = tree.recvparam.vartype.pos; jjg@1521: separateAnnotationsKinds(tree.recvparam.vartype, tree.recvparam.sym.type, jjg@1521: tree.recvparam.sym, pos); jjg@1521: } jjg@1521: int i = 0; jjg@1521: for (JCVariableDecl param : tree.params) { jjg@1755: if (!param.mods.annotations.isEmpty()) { jjg@1755: // Nothing to do for separateAnnotationsKinds if jjg@1755: // there are no annotations of either kind. jjg@1755: TypeAnnotationPosition pos = new TypeAnnotationPosition(); jjg@1755: pos.type = TargetType.METHOD_FORMAL_PARAMETER; jjg@1755: pos.parameter_index = i; jjg@1755: pos.pos = param.vartype.pos; jjg@1755: separateAnnotationsKinds(param.vartype, param.sym.type, param.sym, pos); jjg@1755: } jjg@1521: ++i; jjg@1521: } jjg@1521: } jjg@1521: jjg@1521: push(tree); jjg@1521: // super.visitMethodDef(tree); jjg@1521: if (sigOnly) { jjg@1521: scan(tree.mods); jjg@1521: scan(tree.restype); jjg@1521: scan(tree.typarams); jjg@1521: scan(tree.recvparam); jjg@1521: scan(tree.params); jjg@1521: scan(tree.thrown); jjg@1521: } else { jjg@1521: scan(tree.defaultValue); jjg@1521: scan(tree.body); jjg@1521: } jjg@1521: pop(); jjg@1521: } jjg@1521: jjg@1755: /* Store a reference to the current lambda expression, to jjg@1755: * be used by all type annotations within this expression. jjg@1755: */ jjg@1755: private JCLambda currentLambda = null; jjg@1755: jjg@1755: public void visitLambda(JCLambda tree) { jjg@1755: JCLambda prevLambda = currentLambda; jjg@1755: try { jjg@1755: currentLambda = tree; jjg@1755: jjg@1755: int i = 0; jjg@1755: for (JCVariableDecl param : tree.params) { jjg@1755: if (!param.mods.annotations.isEmpty()) { jjg@1755: // Nothing to do for separateAnnotationsKinds if jjg@1755: // there are no annotations of either kind. jjg@1755: TypeAnnotationPosition pos = new TypeAnnotationPosition(); jjg@1755: pos.type = TargetType.METHOD_FORMAL_PARAMETER; jjg@1755: pos.parameter_index = i; jjg@1755: pos.pos = param.vartype.pos; jjg@1755: pos.onLambda = tree; jjg@1755: separateAnnotationsKinds(param.vartype, param.sym.type, param.sym, pos); jjg@1755: } jjg@1755: ++i; jjg@1755: } jjg@1755: jjg@1755: push(tree); jjg@1755: scan(tree.body); jjg@1755: scan(tree.params); jjg@1755: pop(); jjg@1755: } finally { jjg@1755: currentLambda = prevLambda; jjg@1755: } jjg@1755: } jjg@1755: jjg@1521: /** jjg@1521: * Resolve declaration vs. type annotations in variable declarations and jjg@1521: * then determine the positions. jjg@1521: */ jjg@1521: @Override jjg@1521: public void visitVarDef(final JCVariableDecl tree) { jjg@1755: if (tree.mods.annotations.isEmpty()) { jjg@1755: // Nothing to do for separateAnnotationsKinds if jjg@1755: // there are no annotations of either kind. jjg@1755: } else if (tree.sym == null) { emc@2103: if (typeAnnoAsserts) { emc@2103: Assert.error("Visiting tree node before memberEnter"); emc@2103: } jjg@1521: // Something is wrong already. Quietly ignore. jjg@1563: } else if (tree.sym.getKind() == ElementKind.PARAMETER) { jjg@1755: // Parameters are handled in visitMethodDef or visitLambda. jjg@1521: } else if (tree.sym.getKind() == ElementKind.FIELD) { jjg@1521: if (sigOnly) { jjg@1521: TypeAnnotationPosition pos = new TypeAnnotationPosition(); jjg@1521: pos.type = TargetType.FIELD; jjg@1521: pos.pos = tree.pos; jjg@1521: separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos); jjg@1521: } jjg@1521: } else if (tree.sym.getKind() == ElementKind.LOCAL_VARIABLE) { jjg@1521: TypeAnnotationPosition pos = new TypeAnnotationPosition(); jjg@1521: pos.type = TargetType.LOCAL_VARIABLE; jjg@1521: pos.pos = tree.pos; jjg@1755: pos.onLambda = currentLambda; jjg@1521: separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos); jjg@1521: } else if (tree.sym.getKind() == ElementKind.EXCEPTION_PARAMETER) { jjg@1521: TypeAnnotationPosition pos = new TypeAnnotationPosition(); jjg@1521: pos.type = TargetType.EXCEPTION_PARAMETER; jjg@1521: pos.pos = tree.pos; jjg@1755: pos.onLambda = currentLambda; jjg@1521: separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos); jjg@1521: } else if (tree.sym.getKind() == ElementKind.RESOURCE_VARIABLE) { jjg@1521: TypeAnnotationPosition pos = new TypeAnnotationPosition(); jjg@1521: pos.type = TargetType.RESOURCE_VARIABLE; jjg@1521: pos.pos = tree.pos; jjg@1755: pos.onLambda = currentLambda; jjg@1521: separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos); jjg@1563: } else if (tree.sym.getKind() == ElementKind.ENUM_CONSTANT) { jjg@1563: // No type annotations can occur here. jjg@1521: } else { jjg@1521: // There is nothing else in a variable declaration that needs separation. jjg@1563: Assert.error("Unhandled variable kind: " + tree + " of kind: " + tree.sym.getKind()); jjg@1521: } jjg@1521: jjg@1521: push(tree); jjg@1521: // super.visitVarDef(tree); jjg@1521: scan(tree.mods); jjg@1521: scan(tree.vartype); jjg@1521: if (!sigOnly) { jjg@1521: scan(tree.init); jjg@1521: } jjg@1521: pop(); jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public void visitBlock(JCBlock tree) { jjg@1521: // Do not descend into top-level blocks when only interested jjg@1521: // in the signature. jjg@1521: if (!sigOnly) { jjg@1521: scan(tree.stats); jjg@1521: } jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public void visitAnnotatedType(JCAnnotatedType tree) { jjg@1521: push(tree); jjg@1521: findPosition(tree, tree, tree.annotations); jjg@1521: pop(); jjg@1521: super.visitAnnotatedType(tree); jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public void visitTypeParameter(JCTypeParameter tree) { jjg@1521: findPosition(tree, peek2(), tree.annotations); jjg@1521: super.visitTypeParameter(tree); jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1755: public void visitNewClass(JCNewClass tree) { jjg@1755: if (tree.def != null && jjg@1755: !tree.def.mods.annotations.isEmpty()) { jjg@1755: JCClassDecl classdecl = tree.def; jjg@1755: TypeAnnotationPosition pos = new TypeAnnotationPosition(); jjg@1755: pos.type = TargetType.CLASS_EXTENDS; jjg@1755: pos.pos = tree.pos; jjg@1755: if (classdecl.extending == tree.clazz) { jjg@1755: pos.type_index = -1; jjg@1755: } else if (classdecl.implementing.contains(tree.clazz)) { jjg@1755: pos.type_index = classdecl.implementing.indexOf(tree.clazz); jjg@1755: } else { jjg@1755: // In contrast to CLASS elsewhere, typarams cannot occur here. jjg@1755: Assert.error("Could not determine position of tree " + tree); jjg@1755: } jjg@1755: Type before = classdecl.sym.type; jjg@1755: separateAnnotationsKinds(classdecl, tree.clazz.type, classdecl.sym, pos); jjg@1755: jjg@1755: // classdecl.sym.type now contains an annotated type, which jjg@1755: // is not what we want there. jjg@1755: // TODO: should we put this type somewhere in the superclass/interface? jjg@1755: classdecl.sym.type = before; jjg@1755: } jjg@1755: jjg@1755: scan(tree.encl); jjg@1755: scan(tree.typeargs); jjg@1755: scan(tree.clazz); jjg@1755: scan(tree.args); jjg@1755: jjg@1755: // The class body will already be scanned. jjg@1755: // scan(tree.def); jjg@1755: } jjg@1755: jjg@1755: @Override jjg@1521: public void visitNewArray(JCNewArray tree) { jjg@1521: findPosition(tree, tree, tree.annotations); jjg@1521: int dimAnnosCount = tree.dimAnnotations.size(); alundblad@2047: ListBuffer depth = new ListBuffer<>(); jjg@1521: jjg@1521: // handle annotations associated with dimensions jjg@1521: for (int i = 0; i < dimAnnosCount; ++i) { jjg@1521: TypeAnnotationPosition p = new TypeAnnotationPosition(); jjg@1521: p.pos = tree.pos; jjg@1755: p.onLambda = currentLambda; jjg@1521: p.type = TargetType.NEW; jjg@1521: if (i != 0) { jjg@1521: depth = depth.append(TypePathEntry.ARRAY); jjg@1521: p.location = p.location.appendList(depth.toList()); jjg@1521: } jjg@1521: jjg@1521: setTypeAnnotationPos(tree.dimAnnotations.get(i), p); jjg@1521: } jjg@1521: jjg@1521: // handle "free" annotations jjg@1521: // int i = dimAnnosCount == 0 ? 0 : dimAnnosCount - 1; jjg@1521: // TODO: is depth.size == i here? jjg@1521: JCExpression elemType = tree.elemtype; jjg@1755: depth = depth.append(TypePathEntry.ARRAY); jjg@1521: while (elemType != null) { jjg@1521: if (elemType.hasTag(JCTree.Tag.ANNOTATED_TYPE)) { jjg@1521: JCAnnotatedType at = (JCAnnotatedType)elemType; jjg@1521: TypeAnnotationPosition p = new TypeAnnotationPosition(); jjg@1521: p.type = TargetType.NEW; jjg@1521: p.pos = tree.pos; jjg@1755: p.onLambda = currentLambda; jjg@1755: locateNestedTypes(elemType.type, p); jjg@1755: p.location = p.location.prependList(depth.toList()); jjg@1521: setTypeAnnotationPos(at.annotations, p); jjg@1521: elemType = at.underlyingType; jjg@1521: } else if (elemType.hasTag(JCTree.Tag.TYPEARRAY)) { jjg@1521: depth = depth.append(TypePathEntry.ARRAY); jjg@1521: elemType = ((JCArrayTypeTree)elemType).elemtype; jjg@1755: } else if (elemType.hasTag(JCTree.Tag.SELECT)) { jjg@1755: elemType = ((JCFieldAccess)elemType).selected; jjg@1521: } else { jjg@1521: break; jjg@1521: } jjg@1521: } jjg@1521: scan(tree.elems); jjg@1521: } jjg@1521: jjg@1521: private void findPosition(JCTree tree, JCTree frame, List annotations) { jjg@1521: if (!annotations.isEmpty()) { jjg@1521: /* emc@2103: System.err.println("Finding pos for: " + annotations); emc@2103: System.err.println(" tree: " + tree + " kind: " + tree.getKind()); emc@2103: System.err.println(" frame: " + frame + " kind: " + frame.getKind()); jjg@1521: */ jjg@1521: TypeAnnotationPosition p = new TypeAnnotationPosition(); jjg@1755: p.onLambda = currentLambda; jjg@1521: resolveFrame(tree, frame, frames.toList(), p); jjg@1521: setTypeAnnotationPos(annotations, p); jjg@1521: } jjg@1521: } jjg@1521: jjg@2056: private void setTypeAnnotationPos(List annotations, jjg@1521: TypeAnnotationPosition position) { jjg@1521: for (JCAnnotation anno : annotations) { jjg@1755: // attribute might be null during DeferredAttr; jjg@1755: // we will be back later. jjg@1755: if (anno.attribute != null) { jjg@1755: ((Attribute.TypeCompound) anno.attribute).position = position; jjg@1755: } jjg@1521: } jjg@1521: } jjg@1755: jjg@1755: @Override jjg@1755: public String toString() { jjg@1755: return super.toString() + ": sigOnly: " + sigOnly; jjg@1755: } jjg@1521: } jjg@1521: }