# HG changeset patch # User jfranck # Date 1410174688 -7200 # Node ID aa84b660622983fc2486e81ffc3ff811d52c3648 # Parent c32c9586ea94d2368dd1ac56257479f9d6fb186e 8056021: checkin for JDK-8027262 breaks Checker Framework Reviewed-by: jjg, mcimadamore diff -r c32c9586ea94 -r aa84b6606229 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Attribute.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Attribute.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Attribute.java Mon Sep 08 13:11:28 2014 +0200 @@ -151,7 +151,7 @@ * access this attribute. */ public final List> values; - public final TypeAnnotationPosition position; + public TypeAnnotationPosition position; private boolean synthesized = false; @@ -179,9 +179,53 @@ @Override public TypeAnnotationPosition getPosition() { + if (hasUnknownPosition()) { + if (values.size() != 0) { + Name valueName = values.head.fst.name.table.names.value; + Pair res = getElemPair(valueName); + position = res == null ? null : res.snd.getPosition(); + } + } return position; } + public boolean isContainerTypeCompound() { + if (isSynthesized() && values.size() == 1) + return getFirstEmbeddedTC() != null; + return false; + } + + private Compound getFirstEmbeddedTC() { + if (values.size() == 1) { + Pair val = values.get(0); + if (val.fst.getSimpleName().contentEquals("value") + && val.snd instanceof Array) { + Array arr = (Array) val.snd; + if (arr.values.length != 0 + && arr.values[0] instanceof Attribute.TypeCompound) + return (Attribute.TypeCompound) arr.values[0]; + } + } + return null; + } + + public boolean tryFixPosition() { + if (!isContainerTypeCompound()) + return false; + + Compound from = getFirstEmbeddedTC(); + if (from != null && from.position != null && + from.position.type != TargetType.UNKNOWN) { + position = from.position; + return true; + } + return false; + } + + public boolean hasUnknownPosition() { + return position.type == TargetType.UNKNOWN; + } + public void accept(Visitor v) { v.visitCompound(this); } /** @@ -250,12 +294,6 @@ valmap.put(value.fst, value.snd); return valmap; } - - public TypeCompound toTypeCompound() { - // It is safe to alias the position. - return new TypeCompound(this, this.position); - } - } public static class TypeCompound extends Compound { diff -r c32c9586ea94 -r aa84b6606229 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TargetType.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TargetType.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TargetType.java Mon Sep 08 13:11:28 2014 +0200 @@ -107,7 +107,10 @@ CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT(0x4A, true), /** For annotations on a type argument of a method reference. */ - METHOD_REFERENCE_TYPE_ARGUMENT(0x4B, true); + METHOD_REFERENCE_TYPE_ARGUMENT(0x4B, true), + + /** For annotations with an unknown target. */ + UNKNOWN(0xFF); private static final int MAXIMUM_TARGET_TYPE_VALUE = 0x4B; @@ -147,15 +150,26 @@ targets = new TargetType[MAXIMUM_TARGET_TYPE_VALUE + 1]; TargetType[] alltargets = values(); for (TargetType target : alltargets) { + if (target.targetTypeValue != UNKNOWN.targetTypeValue) targets[target.targetTypeValue] = target; } + for (int i = 0; i <= MAXIMUM_TARGET_TYPE_VALUE; ++i) { + if (targets[i] == null) + targets[i] = UNKNOWN; + } } public static boolean isValidTargetTypeValue(int tag) { + if (tag == UNKNOWN.targetTypeValue) + return true; + return (tag >= 0 && tag < targets.length); } public static TargetType fromTargetTypeValue(int tag) { + if (tag == UNKNOWN.targetTypeValue) + return UNKNOWN; + if (tag < 0 || tag >= targets.length) Assert.error("Unknown TargetType: " + tag); return targets[tag]; diff -r c32c9586ea94 -r aa84b6606229 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java Mon Sep 08 13:11:28 2014 +0200 @@ -256,6 +256,9 @@ case METHOD_RETURN: case FIELD: break; + case UNKNOWN: + sb.append(", position UNKNOWN!"); + break; default: Assert.error("Unknown target type: " + type); } @@ -658,11 +661,10 @@ public static TypeAnnotationPosition exceptionParameter(final List location, final JCLambda onLambda, - final int type_index, final int pos) { return new TypeAnnotationPosition(TargetType.EXCEPTION_PARAMETER, pos, Integer.MIN_VALUE, onLambda, - type_index, Integer.MIN_VALUE, + Integer.MIN_VALUE, Integer.MIN_VALUE, location); } @@ -675,7 +677,7 @@ public static TypeAnnotationPosition exceptionParameter(final JCLambda onLambda, final int pos) { - return exceptionParameter(emptyPath, onLambda, Integer.MIN_VALUE, pos); + return exceptionParameter(emptyPath, onLambda, pos); } /** @@ -685,7 +687,7 @@ */ public static TypeAnnotationPosition exceptionParameter(final List location) { - return exceptionParameter(location, null, Integer.MIN_VALUE, -1); + return exceptionParameter(location, null, -1); } @@ -1199,4 +1201,12 @@ return methodTypeParameterBound(location, null, parameter_index, bound_index, -1); } + + // Consider this deprecated on arrival. We eventually want to get + // rid of this value altogether. Do not use it for anything new. + public static final TypeAnnotationPosition unknown = + new TypeAnnotationPosition(TargetType.UNKNOWN, -1, + Integer.MIN_VALUE, null, + Integer.MIN_VALUE, Integer.MIN_VALUE, + emptyPath); } diff -r c32c9586ea94 -r aa84b6606229 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Mon Sep 08 13:11:28 2014 +0200 @@ -0,0 +1,1397 @@ +/* + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.javac.code; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.type.TypeKind; + +import javax.tools.JavaFileObject; + +import com.sun.tools.javac.code.Attribute.TypeCompound; +import com.sun.tools.javac.code.Type.ArrayType; +import com.sun.tools.javac.code.Type.CapturedType; +import com.sun.tools.javac.code.Type.ClassType; +import com.sun.tools.javac.code.Type.ErrorType; +import com.sun.tools.javac.code.Type.ForAll; +import com.sun.tools.javac.code.Type.MethodType; +import com.sun.tools.javac.code.Type.PackageType; +import com.sun.tools.javac.code.Type.TypeVar; +import com.sun.tools.javac.code.Type.UndetVar; +import com.sun.tools.javac.code.Type.Visitor; +import com.sun.tools.javac.code.Type.WildcardType; +import com.sun.tools.javac.code.TypeAnnotationPosition.TypePathEntry; +import com.sun.tools.javac.code.TypeAnnotationPosition.TypePathEntryKind; +import com.sun.tools.javac.code.Symbol.VarSymbol; +import com.sun.tools.javac.code.Symbol.MethodSymbol; +import com.sun.tools.javac.comp.Annotate; +import com.sun.tools.javac.comp.Annotate.Worker; +import com.sun.tools.javac.comp.Attr; +import com.sun.tools.javac.comp.AttrContext; +import com.sun.tools.javac.comp.Env; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.TreeInfo; +import com.sun.tools.javac.tree.JCTree.JCBlock; +import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCLambda; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; +import com.sun.tools.javac.tree.JCTree.JCNewClass; +import com.sun.tools.javac.tree.JCTree.JCTypeApply; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.tree.TreeScanner; +import com.sun.tools.javac.tree.JCTree.*; +import com.sun.tools.javac.util.Assert; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.util.Names; +import com.sun.tools.javac.util.Options; + +/** + * Contains operations specific to processing type annotations. + * This class has two functions: + * separate declaration from type annotations and insert the type + * annotations to their types; + * and determine the TypeAnnotationPositions for all type annotations. + */ +public class TypeAnnotations { + protected static final Context.Key typeAnnosKey = new Context.Key<>(); + + public static TypeAnnotations instance(Context context) { + TypeAnnotations instance = context.get(typeAnnosKey); + if (instance == null) + instance = new TypeAnnotations(context); + return instance; + } + + final Log log; + final Names names; + final Symtab syms; + final Annotate annotate; + final Attr attr; + + protected TypeAnnotations(Context context) { + context.put(typeAnnosKey, this); + names = Names.instance(context); + log = Log.instance(context); + syms = Symtab.instance(context); + annotate = Annotate.instance(context); + attr = Attr.instance(context); + Options options = Options.instance(context); + } + + /** + * Separate type annotations from declaration annotations and + * determine the correct positions for type annotations. + * This version only visits types in signatures and should be + * called from MemberEnter. + * The method takes the Annotate object as parameter and + * adds an Annotate.Worker to the correct Annotate queue for + * later processing. + */ + public void organizeTypeAnnotationsSignatures(final Env env, final JCClassDecl tree) { + annotate.afterRepeated( new Worker() { + @Override + public void run() { + JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile); + + try { + new TypeAnnotationPositions(true).scan(tree); + } finally { + log.useSource(oldSource); + } + } + } ); + } + + public void validateTypeAnnotationsSignatures(final Env env, final JCClassDecl tree) { + annotate.validate(new Worker() { //validate annotations + @Override + public void run() { + JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile); + + try { + attr.validateTypeAnnotations(tree, true); + } finally { + log.useSource(oldSource); + } + } + } ); + } + + /** + * This version only visits types in bodies, that is, field initializers, + * top-level blocks, and method bodies, and should be called from Attr. + */ + public void organizeTypeAnnotationsBodies(JCClassDecl tree) { + new TypeAnnotationPositions(false).scan(tree); + } + + public enum AnnotationType { DECLARATION, TYPE, BOTH } + + /** + * Determine whether an annotation is a declaration annotation, + * a type annotation, or both. + */ + public AnnotationType annotationType(Attribute.Compound a, Symbol s) { + Attribute.Compound atTarget = + a.type.tsym.attribute(syms.annotationTargetType.tsym); + if (atTarget == null) { + return inferTargetMetaInfo(a, s); + } + Attribute atValue = atTarget.member(names.value); + if (!(atValue instanceof Attribute.Array)) { + Assert.error("annotationType(): bad @Target argument " + atValue + + " (" + atValue.getClass() + ")"); + return AnnotationType.DECLARATION; // error recovery + } + Attribute.Array arr = (Attribute.Array) atValue; + boolean isDecl = false, isType = false; + for (Attribute app : arr.values) { + if (!(app instanceof Attribute.Enum)) { + Assert.error("annotationType(): unrecognized Attribute kind " + app + + " (" + app.getClass() + ")"); + isDecl = true; + continue; + } + Attribute.Enum e = (Attribute.Enum) app; + if (e.value.name == names.TYPE) { + if (s.kind == Kinds.TYP) + isDecl = true; + } else if (e.value.name == names.FIELD) { + if (s.kind == Kinds.VAR && + s.owner.kind != Kinds.MTH) + isDecl = true; + } else if (e.value.name == names.METHOD) { + if (s.kind == Kinds.MTH && + !s.isConstructor()) + isDecl = true; + } else if (e.value.name == names.PARAMETER) { + if (s.kind == Kinds.VAR && + s.owner.kind == Kinds.MTH && + (s.flags() & Flags.PARAMETER) != 0) + isDecl = true; + } else if (e.value.name == names.CONSTRUCTOR) { + if (s.kind == Kinds.MTH && + s.isConstructor()) + isDecl = true; + } else if (e.value.name == names.LOCAL_VARIABLE) { + if (s.kind == Kinds.VAR && + s.owner.kind == Kinds.MTH && + (s.flags() & Flags.PARAMETER) == 0) + isDecl = true; + } else if (e.value.name == names.ANNOTATION_TYPE) { + if (s.kind == Kinds.TYP && + (s.flags() & Flags.ANNOTATION) != 0) + isDecl = true; + } else if (e.value.name == names.PACKAGE) { + if (s.kind == Kinds.PCK) + isDecl = true; + } else if (e.value.name == names.TYPE_USE) { + if (s.kind == Kinds.TYP || + s.kind == Kinds.VAR || + (s.kind == Kinds.MTH && !s.isConstructor() && + !s.type.getReturnType().hasTag(TypeTag.VOID)) || + (s.kind == Kinds.MTH && s.isConstructor())) + isType = true; + } else if (e.value.name == names.TYPE_PARAMETER) { + /* Irrelevant in this case */ + // TYPE_PARAMETER doesn't aid in distinguishing between + // Type annotations and declaration annotations on an + // Element + } else { + Assert.error("annotationType(): unrecognized Attribute name " + e.value.name + + " (" + e.value.name.getClass() + ")"); + isDecl = true; + } + } + if (isDecl && isType) { + return AnnotationType.BOTH; + } else if (isType) { + return AnnotationType.TYPE; + } else { + return AnnotationType.DECLARATION; + } + } + + /** Infer the target annotation kind, if none is give. + * We only infer declaration annotations. + */ + private static AnnotationType inferTargetMetaInfo(Attribute.Compound a, Symbol s) { + return AnnotationType.DECLARATION; + } + + + private class TypeAnnotationPositions extends TreeScanner { + + private final boolean sigOnly; + + TypeAnnotationPositions(boolean sigOnly) { + this.sigOnly = sigOnly; + } + + /* + * When traversing the AST we keep the "frames" of visited + * trees in order to determine the position of annotations. + */ + private ListBuffer frames = new ListBuffer<>(); + + protected void push(JCTree t) { frames = frames.prepend(t); } + protected JCTree pop() { return frames.next(); } + // could this be frames.elems.tail.head? + private JCTree peek2() { return frames.toList().tail.head; } + + @Override + public void scan(JCTree tree) { + push(tree); + super.scan(tree); + pop(); + } + + /** + * Separates type annotations from declaration annotations. + * This step is needed because in certain locations (where declaration + * and type annotations can be mixed, e.g. the type of a field) + * we never build an JCAnnotatedType. This step finds these + * annotations and marks them as if they were part of the type. + */ + private void separateAnnotationsKinds(JCTree typetree, Type type, Symbol sym, + TypeAnnotationPosition pos) { + List annotations = sym.getRawAttributes(); + ListBuffer declAnnos = new ListBuffer<>(); + ListBuffer typeAnnos = new ListBuffer<>(); + ListBuffer onlyTypeAnnos = new ListBuffer<>(); + + for (Attribute.Compound a : annotations) { + switch (annotationType(a, sym)) { + case DECLARATION: + declAnnos.append(a); + break; + case BOTH: { + declAnnos.append(a); + Attribute.TypeCompound ta = toTypeCompound(a, pos); + typeAnnos.append(ta); + break; + } + case TYPE: { + Attribute.TypeCompound ta = toTypeCompound(a, pos); + typeAnnos.append(ta); + // Also keep track which annotations are only type annotations + onlyTypeAnnos.append(ta); + break; + } + } + } + + sym.resetAnnotations(); + sym.setDeclarationAttributes(declAnnos.toList()); + + if (typeAnnos.isEmpty()) { + return; + } + + List typeAnnotations = typeAnnos.toList(); + + if (type == null) { + // When type is null, put the type annotations to the symbol. + // This is used for constructor return annotations, for which + // we use the type of the enclosing class. + type = sym.getEnclosingElement().asType(); + + // Declaration annotations are always allowed on constructor returns. + // Therefore, use typeAnnotations instead of onlyTypeAnnos. + type = typeWithAnnotations(typetree, type, typeAnnotations, typeAnnotations); + // Note that we don't use the result, the call to + // typeWithAnnotations side-effects the type annotation positions. + // This is important for constructors of nested classes. + sym.appendUniqueTypeAttributes(typeAnnotations); + return; + } + + // type is non-null and annotations are added to that type + type = typeWithAnnotations(typetree, type, typeAnnotations, onlyTypeAnnos.toList()); + + if (sym.getKind() == ElementKind.METHOD) { + sym.type.asMethodType().restype = type; + } else if (sym.getKind() == ElementKind.PARAMETER) { + sym.type = type; + if (sym.getQualifiedName().equals(names._this)) { + sym.owner.type.asMethodType().recvtype = type; + // note that the typeAnnotations will also be added to the owner below. + } else { + MethodType methType = sym.owner.type.asMethodType(); + List params = ((MethodSymbol)sym.owner).params; + List oldArgs = methType.argtypes; + ListBuffer newArgs = new ListBuffer<>(); + while (params.nonEmpty()) { + if (params.head == sym) { + newArgs.add(type); + } else { + newArgs.add(oldArgs.head); + } + oldArgs = oldArgs.tail; + params = params.tail; + } + methType.argtypes = newArgs.toList(); + } + } else { + sym.type = type; + } + + sym.appendUniqueTypeAttributes(typeAnnotations); + + if (sym.getKind() == ElementKind.PARAMETER || + sym.getKind() == ElementKind.LOCAL_VARIABLE || + sym.getKind() == ElementKind.RESOURCE_VARIABLE || + sym.getKind() == ElementKind.EXCEPTION_PARAMETER) { + // Make sure all type annotations from the symbol are also + // on the owner. + sym.owner.appendUniqueTypeAttributes(sym.getRawTypeAttributes()); + } + } + + // This method has a similar purpose as + // {@link com.sun.tools.javac.parser.JavacParser.insertAnnotationsToMostInner(JCExpression, List, boolean)} + // We found a type annotation in a declaration annotation position, + // for example, on the return type. + // Such an annotation is _not_ part of an JCAnnotatedType tree and we therefore + // need to set its position explicitly. + // The method returns a copy of type that contains these annotations. + // + // As a side effect the method sets the type annotation position of "annotations". + // Note that it is assumed that all annotations share the same position. + private Type typeWithAnnotations(final JCTree typetree, final Type type, + final List annotations, + final List onlyTypeAnnotations) { + //System.err.printf("typeWithAnnotations(typetree: %s, type: %s, annotations: %s, onlyTypeAnnotations: %s)%n", + // typetree, type, annotations, onlyTypeAnnotations); + if (annotations.isEmpty()) { + return type; + } + if (type.hasTag(TypeTag.ARRAY)) { + Type.ArrayType arType = (Type.ArrayType) type; + Type.ArrayType tomodify = new Type.ArrayType(null, arType.tsym, + Type.noAnnotations); + Type toreturn; + if (type.isAnnotated()) { + toreturn = tomodify.annotatedType(type.getAnnotationMirrors()); + } else { + toreturn = tomodify; + } + + JCArrayTypeTree arTree = arrayTypeTree(typetree); + + ListBuffer depth = new ListBuffer<>(); + depth = depth.append(TypePathEntry.ARRAY); + while (arType.elemtype.hasTag(TypeTag.ARRAY)) { + if (arType.elemtype.isAnnotated()) { + Type aelemtype = arType.elemtype; + arType = (Type.ArrayType) aelemtype; + ArrayType prevToMod = tomodify; + tomodify = new Type.ArrayType(null, arType.tsym, + Type.noAnnotations); + prevToMod.elemtype = tomodify.annotatedType(arType.elemtype.getAnnotationMirrors()); + } else { + arType = (Type.ArrayType) arType.elemtype; + tomodify.elemtype = new Type.ArrayType(null, arType.tsym, + Type.noAnnotations); + tomodify = (Type.ArrayType) tomodify.elemtype; + } + arTree = arrayTypeTree(arTree.elemtype); + depth = depth.append(TypePathEntry.ARRAY); + } + Type arelemType = typeWithAnnotations(arTree.elemtype, arType.elemtype, annotations, onlyTypeAnnotations); + tomodify.elemtype = arelemType; + { + // All annotations share the same position; modify the first one. + Attribute.TypeCompound a = annotations.get(0); + TypeAnnotationPosition p = a.position; + p.location = p.location.prependList(depth.toList()); + } + typetree.type = toreturn; + return toreturn; + } else if (type.hasTag(TypeTag.TYPEVAR)) { + // Nothing to do for type variables. + return type; + } else if (type.getKind() == TypeKind.UNION) { + // There is a TypeKind, but no TypeTag. + JCTypeUnion tutree = (JCTypeUnion) typetree; + JCExpression fst = tutree.alternatives.get(0); + Type res = typeWithAnnotations(fst, fst.type, annotations, onlyTypeAnnotations); + fst.type = res; + // TODO: do we want to set res as first element in uct.alternatives? + // UnionClassType uct = (com.sun.tools.javac.code.Type.UnionClassType)type; + // Return the un-annotated union-type. + return type; + } else { + Type enclTy = type; + Element enclEl = type.asElement(); + JCTree enclTr = typetree; + + while (enclEl != null && + enclEl.getKind() != ElementKind.PACKAGE && + enclTy != null && + enclTy.getKind() != TypeKind.NONE && + enclTy.getKind() != TypeKind.ERROR && + (enclTr.getKind() == JCTree.Kind.MEMBER_SELECT || + enclTr.getKind() == JCTree.Kind.PARAMETERIZED_TYPE || + enclTr.getKind() == JCTree.Kind.ANNOTATED_TYPE)) { + // Iterate also over the type tree, not just the type: the type is already + // completely resolved and we cannot distinguish where the annotation + // belongs for a nested type. + if (enclTr.getKind() == JCTree.Kind.MEMBER_SELECT) { + // only change encl in this case. + enclTy = enclTy.getEnclosingType(); + enclEl = enclEl.getEnclosingElement(); + enclTr = ((JCFieldAccess)enclTr).getExpression(); + } else if (enclTr.getKind() == JCTree.Kind.PARAMETERIZED_TYPE) { + enclTr = ((JCTypeApply)enclTr).getType(); + } else { + // only other option because of while condition + enclTr = ((JCAnnotatedType)enclTr).getUnderlyingType(); + } + } + + /** We are trying to annotate some enclosing type, + * but nothing more exists. + */ + if (enclTy != null && + enclTy.hasTag(TypeTag.NONE)) { + switch (onlyTypeAnnotations.size()) { + case 0: + // Don't issue an error if all type annotations are + // also declaration annotations. + // If the annotations are also declaration annotations, they are + // illegal as type annotations but might be legal as declaration annotations. + // The normal declaration annotation checks make sure that the use is valid. + break; + case 1: + log.error(typetree.pos(), "cant.type.annotate.scoping.1", + onlyTypeAnnotations); + break; + default: + log.error(typetree.pos(), "cant.type.annotate.scoping", + onlyTypeAnnotations); + } + return type; + } + + // At this point we have visited the part of the nested + // type that is written in the source code. + // Now count from here to the actual top-level class to determine + // the correct nesting. + + // The genericLocation for the annotation. + ListBuffer depth = new ListBuffer<>(); + + Type topTy = enclTy; + while (enclEl != null && + enclEl.getKind() != ElementKind.PACKAGE && + topTy != null && + topTy.getKind() != TypeKind.NONE && + topTy.getKind() != TypeKind.ERROR) { + topTy = topTy.getEnclosingType(); + enclEl = enclEl.getEnclosingElement(); + + if (topTy != null && topTy.getKind() != TypeKind.NONE) { + // Only count enclosing types. + depth = depth.append(TypePathEntry.INNER_TYPE); + } + } + + if (depth.nonEmpty()) { + // Only need to change the annotation positions + // if they are on an enclosed type. + // All annotations share the same position; modify the first one. + Attribute.TypeCompound a = annotations.get(0); + TypeAnnotationPosition p = a.position; + p.location = p.location.appendList(depth.toList()); + } + + Type ret = typeWithAnnotations(type, enclTy, annotations); + typetree.type = ret; + return ret; + } + } + + private JCArrayTypeTree arrayTypeTree(JCTree typetree) { + if (typetree.getKind() == JCTree.Kind.ARRAY_TYPE) { + return (JCArrayTypeTree) typetree; + } else if (typetree.getKind() == JCTree.Kind.ANNOTATED_TYPE) { + return (JCArrayTypeTree) ((JCAnnotatedType)typetree).underlyingType; + } else { + Assert.error("Could not determine array type from type tree: " + typetree); + return null; + } + } + + /** Return a copy of the first type that only differs by + * inserting the annotations to the left-most/inner-most type + * or the type given by stopAt. + * + * We need the stopAt parameter to know where on a type to + * put the annotations. + * If we have nested classes Outer > Middle > Inner, and we + * have the source type "@A Middle.Inner", we will invoke + * this method with type = Outer.Middle.Inner, + * stopAt = Middle.Inner, and annotations = @A. + * + * @param type The type to copy. + * @param stopAt The type to stop at. + * @param annotations The annotations to insert. + * @return A copy of type that contains the annotations. + */ + private Type typeWithAnnotations(final Type type, + final Type stopAt, + final List annotations) { + //System.err.println("typeWithAnnotations " + type + " " + annotations + " stopAt " + stopAt); + Visitor> visitor = + new Type.Visitor>() { + @Override + public Type visitClassType(ClassType t, List s) { + // assert that t.constValue() == null? + if (t == stopAt || + t.getEnclosingType() == Type.noType) { + return t.annotatedType(s); + } else { + ClassType ret = new ClassType(t.getEnclosingType().accept(this, s), + t.typarams_field, t.tsym, + t.getAnnotationMirrors()); + ret.all_interfaces_field = t.all_interfaces_field; + ret.allparams_field = t.allparams_field; + ret.interfaces_field = t.interfaces_field; + ret.rank_field = t.rank_field; + ret.supertype_field = t.supertype_field; + return ret; + } + } + + @Override + public Type visitWildcardType(WildcardType t, List s) { + return t.annotatedType(s); + } + + @Override + public Type visitArrayType(ArrayType t, List s) { + ArrayType ret = new ArrayType(t.elemtype.accept(this, s), t.tsym, + t.getAnnotationMirrors()); + return ret; + } + + @Override + public Type visitMethodType(MethodType t, List s) { + // Impossible? + return t; + } + + @Override + public Type visitPackageType(PackageType t, List s) { + // Impossible? + return t; + } + + @Override + public Type visitTypeVar(TypeVar t, List s) { + return t.annotatedType(s); + } + + @Override + public Type visitCapturedType(CapturedType t, List s) { + return t.annotatedType(s); + } + + @Override + public Type visitForAll(ForAll t, List s) { + // Impossible? + return t; + } + + @Override + public Type visitUndetVar(UndetVar t, List s) { + // Impossible? + return t; + } + + @Override + public Type visitErrorType(ErrorType t, List s) { + return t.annotatedType(s); + } + + @Override + public Type visitType(Type t, List s) { + return t.annotatedType(s); + } + }; + + return type.accept(visitor, annotations); + } + + private Attribute.TypeCompound toTypeCompound(Attribute.Compound a, TypeAnnotationPosition p) { + // It is safe to alias the position. + return new Attribute.TypeCompound(a, p); + } + + + /* This is the beginning of the second part of organizing + * type annotations: determine the type annotation positions. + */ + + // This method is considered deprecated, and will be removed + // in the near future. Don't use it for anything new. + private TypeAnnotationPosition + resolveFrame(JCTree tree, + JCTree frame, + List path, + JCLambda currentLambda, + int outer_type_index, + ListBuffer location) { + /* + System.out.println("Resolving tree: " + tree + " kind: " + tree.getKind()); + System.out.println(" Framing tree: " + frame + " kind: " + frame.getKind()); + */ + + // Note that p.offset is set in + // com.sun.tools.javac.jvm.Gen.setTypeAnnotationPositions(int) + + switch (frame.getKind()) { + case TYPE_CAST: + return TypeAnnotationPosition.typeCast(location.toList(), + currentLambda, + outer_type_index, + frame.pos); + + case INSTANCE_OF: + return TypeAnnotationPosition.instanceOf(location.toList(), + currentLambda, + frame.pos); + + case NEW_CLASS: + final JCNewClass frameNewClass = (JCNewClass) frame; + if (frameNewClass.def != null) { + // Special handling for anonymous class instantiations + final JCClassDecl frameClassDecl = frameNewClass.def; + if (frameClassDecl.extending == tree) { + return TypeAnnotationPosition + .classExtends(location.toList(), currentLambda, + frame.pos); + } else if (frameClassDecl.implementing.contains(tree)) { + final int type_index = + frameClassDecl.implementing.indexOf(tree); + return TypeAnnotationPosition + .classExtends(location.toList(), currentLambda, + type_index, frame.pos); + } else { + // In contrast to CLASS below, typarams cannot occur here. + throw new AssertionError("Could not determine position of tree " + tree + + " within frame " + frame); + } + } else if (frameNewClass.typeargs.contains(tree)) { + final int type_index = + frameNewClass.typeargs.indexOf(tree); + return TypeAnnotationPosition + .constructorInvocationTypeArg(location.toList(), + currentLambda, + type_index, + frame.pos); + } else { + return TypeAnnotationPosition + .newObj(location.toList(), currentLambda, + frame.pos); + } + + case NEW_ARRAY: + return TypeAnnotationPosition + .newObj(location.toList(), currentLambda, frame.pos); + + case ANNOTATION_TYPE: + case CLASS: + case ENUM: + case INTERFACE: + if (((JCClassDecl)frame).extending == tree) { + return TypeAnnotationPosition + .classExtends(location.toList(), currentLambda, + frame.pos); + } else if (((JCClassDecl)frame).implementing.contains(tree)) { + final int type_index = + ((JCClassDecl)frame).implementing.indexOf(tree); + return TypeAnnotationPosition + .classExtends(location.toList(), currentLambda, + type_index, frame.pos); + } else if (((JCClassDecl)frame).typarams.contains(tree)) { + final int parameter_index = + ((JCClassDecl)frame).typarams.indexOf(tree); + return TypeAnnotationPosition + .typeParameter(location.toList(), currentLambda, + parameter_index, frame.pos); + } else { + throw new AssertionError("Could not determine position of tree " + + tree + " within frame " + frame); + } + + case METHOD: { + final JCMethodDecl frameMethod = (JCMethodDecl) frame; + if (frameMethod.thrown.contains(tree)) { + final int type_index = frameMethod.thrown.indexOf(tree); + return TypeAnnotationPosition + .methodThrows(location.toList(), currentLambda, + type_index, frame.pos); + } else if (frameMethod.restype == tree) { + return TypeAnnotationPosition + .methodReturn(location.toList(), currentLambda, + frame.pos); + } else if (frameMethod.typarams.contains(tree)) { + final int parameter_index = + frameMethod.typarams.indexOf(tree); + return TypeAnnotationPosition + .methodTypeParameter(location.toList(), + currentLambda, + parameter_index, frame.pos); + } else { + throw new AssertionError("Could not determine position of tree " + tree + + " within frame " + frame); + } + } + + case PARAMETERIZED_TYPE: { + List newPath = path.tail; + + if (((JCTypeApply)frame).clazz == tree) { + // generic: RAW; noop + } else if (((JCTypeApply)frame).arguments.contains(tree)) { + JCTypeApply taframe = (JCTypeApply) frame; + int arg = taframe.arguments.indexOf(tree); + location = location.prepend( + new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, + arg)); + + Type typeToUse; + if (newPath.tail != null && + newPath.tail.head.hasTag(Tag.NEWCLASS)) { + // If we are within an anonymous class + // instantiation, use its type, because it + // contains a correctly nested type. + typeToUse = newPath.tail.head.type; + } else { + typeToUse = taframe.type; + } + + location = locateNestedTypes(typeToUse, location); + } else { + throw new AssertionError("Could not determine type argument position of tree " + tree + + " within frame " + frame); + } + + return resolveFrame(newPath.head, newPath.tail.head, + newPath, currentLambda, + outer_type_index, location); + } + + case MEMBER_REFERENCE: { + JCMemberReference mrframe = (JCMemberReference) frame; + + if (mrframe.expr == tree) { + switch (mrframe.mode) { + case INVOKE: + return TypeAnnotationPosition + .methodRef(location.toList(), currentLambda, + frame.pos); + case NEW: + return TypeAnnotationPosition + .constructorRef(location.toList(), + currentLambda, + frame.pos); + default: + throw new AssertionError("Unknown method reference mode " + mrframe.mode + + " for tree " + tree + " within frame " + frame); + } + } else if (mrframe.typeargs != null && + mrframe.typeargs.contains(tree)) { + final int type_index = mrframe.typeargs.indexOf(tree); + switch (mrframe.mode) { + case INVOKE: + return TypeAnnotationPosition + .methodRefTypeArg(location.toList(), + currentLambda, + type_index, frame.pos); + case NEW: + return TypeAnnotationPosition + .constructorRefTypeArg(location.toList(), + currentLambda, + type_index, frame.pos); + default: + throw new AssertionError("Unknown method reference mode " + mrframe.mode + + " for tree " + tree + " within frame " + frame); + } + } else { + throw new AssertionError("Could not determine type argument position of tree " + tree + + " within frame " + frame); + } + } + + case ARRAY_TYPE: { + location = location.prepend(TypePathEntry.ARRAY); + List newPath = path.tail; + while (true) { + JCTree npHead = newPath.tail.head; + if (npHead.hasTag(JCTree.Tag.TYPEARRAY)) { + newPath = newPath.tail; + location = location.prepend(TypePathEntry.ARRAY); + } else if (npHead.hasTag(JCTree.Tag.ANNOTATED_TYPE)) { + newPath = newPath.tail; + } else { + break; + } + } + return resolveFrame(newPath.head, newPath.tail.head, + newPath, currentLambda, + outer_type_index, location); + } + + case TYPE_PARAMETER: + if (path.tail.tail.head.hasTag(JCTree.Tag.CLASSDEF)) { + final JCClassDecl clazz = + (JCClassDecl)path.tail.tail.head; + final int parameter_index = + clazz.typarams.indexOf(path.tail.head); + final int bound_index = + ((JCTypeParameter)frame).bounds.get(0) + .type.isInterface() ? + ((JCTypeParameter)frame).bounds.indexOf(tree) + 1: + ((JCTypeParameter)frame).bounds.indexOf(tree); + return TypeAnnotationPosition + .typeParameterBound(location.toList(), + currentLambda, + parameter_index, bound_index, + frame.pos); + } else if (path.tail.tail.head.hasTag(JCTree.Tag.METHODDEF)) { + final JCMethodDecl method = + (JCMethodDecl)path.tail.tail.head; + final int parameter_index = + method.typarams.indexOf(path.tail.head); + final int bound_index = + ((JCTypeParameter)frame).bounds.get(0) + .type.isInterface() ? + ((JCTypeParameter)frame).bounds.indexOf(tree) + 1: + ((JCTypeParameter)frame).bounds.indexOf(tree); + return TypeAnnotationPosition + .methodTypeParameterBound(location.toList(), + currentLambda, + parameter_index, + bound_index, + frame.pos); + } else { + throw new AssertionError("Could not determine position of tree " + tree + + " within frame " + frame); + } + + case VARIABLE: + VarSymbol v = ((JCVariableDecl)frame).sym; + if (v.getKind() != ElementKind.FIELD) { + v.owner.appendUniqueTypeAttributes(v.getRawTypeAttributes()); + } + switch (v.getKind()) { + case LOCAL_VARIABLE: + return TypeAnnotationPosition + .localVariable(location.toList(), currentLambda, + frame.pos); + case FIELD: + return TypeAnnotationPosition.field(location.toList(), + currentLambda, + frame.pos); + case PARAMETER: + if (v.getQualifiedName().equals(names._this)) { + return TypeAnnotationPosition + .methodReceiver(location.toList(), + currentLambda, + frame.pos); + } else { + final int parameter_index = + methodParamIndex(path, frame); + return TypeAnnotationPosition + .methodParameter(location.toList(), + currentLambda, + parameter_index, + frame.pos); + } + case EXCEPTION_PARAMETER: + return TypeAnnotationPosition + .exceptionParameter(location.toList(), + currentLambda, + frame.pos); + case RESOURCE_VARIABLE: + return TypeAnnotationPosition + .resourceVariable(location.toList(), + currentLambda, + frame.pos); + default: + throw new AssertionError("Found unexpected type annotation for variable: " + v + " with kind: " + v.getKind()); + } + + case ANNOTATED_TYPE: { + if (frame == tree) { + // This is only true for the first annotated type we see. + // For any other annotated types along the path, we do + // not care about inner types. + JCAnnotatedType atypetree = (JCAnnotatedType) frame; + final Type utype = atypetree.underlyingType.type; + Assert.checkNonNull(utype); + Symbol tsym = utype.tsym; + if (tsym.getKind().equals(ElementKind.TYPE_PARAMETER) || + utype.getKind().equals(TypeKind.WILDCARD) || + utype.getKind().equals(TypeKind.ARRAY)) { + // Type parameters, wildcards, and arrays have the declaring + // class/method as enclosing elements. + // There is actually nothing to do for them. + } else { + location = locateNestedTypes(utype, location); + } + } + List newPath = path.tail; + return resolveFrame(newPath.head, newPath.tail.head, + newPath, currentLambda, + outer_type_index, location); + } + + case UNION_TYPE: { + List newPath = path.tail; + return resolveFrame(newPath.head, newPath.tail.head, + newPath, currentLambda, + outer_type_index, location); + } + + case INTERSECTION_TYPE: { + JCTypeIntersection isect = (JCTypeIntersection)frame; + final List newPath = path.tail; + return resolveFrame(newPath.head, newPath.tail.head, + newPath, currentLambda, + isect.bounds.indexOf(tree), location); + } + + case METHOD_INVOCATION: { + JCMethodInvocation invocation = (JCMethodInvocation)frame; + if (!invocation.typeargs.contains(tree)) { + throw new AssertionError("{" + tree + "} is not an argument in the invocation: " + invocation); + } + MethodSymbol exsym = (MethodSymbol) TreeInfo.symbol(invocation.getMethodSelect()); + final int type_index = invocation.typeargs.indexOf(tree); + if (exsym == null) { + throw new AssertionError("could not determine symbol for {" + invocation + "}"); + } else if (exsym.isConstructor()) { + return TypeAnnotationPosition + .constructorInvocationTypeArg(location.toList(), + currentLambda, + type_index, + invocation.pos); + } else { + return TypeAnnotationPosition + .methodInvocationTypeArg(location.toList(), + currentLambda, + type_index, + invocation.pos); + } + } + + case EXTENDS_WILDCARD: + case SUPER_WILDCARD: { + // Annotations in wildcard bounds + final List newPath = path.tail; + return resolveFrame(newPath.head, newPath.tail.head, + newPath, currentLambda, + outer_type_index, + location.prepend(TypePathEntry.WILDCARD)); + } + + case MEMBER_SELECT: { + final List newPath = path.tail; + return resolveFrame(newPath.head, newPath.tail.head, + newPath, currentLambda, + outer_type_index, location); + } + + default: + throw new AssertionError("Unresolved frame: " + frame + + " of kind: " + frame.getKind() + + "\n Looking for tree: " + tree); + } + } + + private ListBuffer + locateNestedTypes(Type type, + ListBuffer depth) { + Type encl = type.getEnclosingType(); + while (encl != null && + encl.getKind() != TypeKind.NONE && + encl.getKind() != TypeKind.ERROR) { + depth = depth.prepend(TypePathEntry.INNER_TYPE); + encl = encl.getEnclosingType(); + } + return depth; + } + + private int methodParamIndex(List path, JCTree param) { + List curr = path; + while (curr.head.getTag() != Tag.METHODDEF && + curr.head.getTag() != Tag.LAMBDA) { + curr = curr.tail; + } + if (curr.head.getTag() == Tag.METHODDEF) { + JCMethodDecl method = (JCMethodDecl)curr.head; + return method.params.indexOf(param); + } else if (curr.head.getTag() == Tag.LAMBDA) { + JCLambda lambda = (JCLambda)curr.head; + return lambda.params.indexOf(param); + } else { + Assert.error("methodParamIndex expected to find method or lambda for param: " + param); + return -1; + } + } + + // Each class (including enclosed inner classes) is visited separately. + // This flag is used to prevent from visiting inner classes. + private boolean isInClass = false; + + @Override + public void visitClassDef(JCClassDecl tree) { + if (isInClass) + return; + isInClass = true; + + if (sigOnly) { + scan(tree.mods); + scan(tree.typarams); + scan(tree.extending); + scan(tree.implementing); + } + scan(tree.defs); + } + + /** + * Resolve declaration vs. type annotations in methods and + * then determine the positions. + */ + @Override + public void visitMethodDef(final JCMethodDecl tree) { + if (tree.sym == null) { + Assert.error("Visiting tree node before memberEnter"); + } + if (sigOnly) { + if (!tree.mods.annotations.isEmpty()) { + if (tree.sym.isConstructor()) { + final TypeAnnotationPosition pos = + TypeAnnotationPosition.methodReturn(tree.pos); + // Use null to mark that the annotations go + // with the symbol. + separateAnnotationsKinds(tree, null, tree.sym, pos); + } else { + final TypeAnnotationPosition pos = + TypeAnnotationPosition.methodReturn(tree.restype.pos); + separateAnnotationsKinds(tree.restype, + tree.sym.type.getReturnType(), + tree.sym, pos); + } + } + if (tree.recvparam != null && tree.recvparam.sym != null && + !tree.recvparam.mods.annotations.isEmpty()) { + // Nothing to do for separateAnnotationsKinds if + // there are no annotations of either kind. + // TODO: make sure there are no declaration annotations. + final TypeAnnotationPosition pos = + TypeAnnotationPosition.methodReceiver(tree.recvparam.vartype.pos); + separateAnnotationsKinds(tree.recvparam.vartype, + tree.recvparam.sym.type, + tree.recvparam.sym, pos); + } + int i = 0; + for (JCVariableDecl param : tree.params) { + if (!param.mods.annotations.isEmpty()) { + // Nothing to do for separateAnnotationsKinds if + // there are no annotations of either kind. + final TypeAnnotationPosition pos = + TypeAnnotationPosition.methodParameter(i, param.vartype.pos); + separateAnnotationsKinds(param.vartype, + param.sym.type, + param.sym, pos); + } + ++i; + } + } + + push(tree); + // super.visitMethodDef(tree); + if (sigOnly) { + scan(tree.mods); + scan(tree.restype); + scan(tree.typarams); + scan(tree.recvparam); + scan(tree.params); + scan(tree.thrown); + } else { + scan(tree.defaultValue); + scan(tree.body); + } + pop(); + } + + /* Store a reference to the current lambda expression, to + * be used by all type annotations within this expression. + */ + private JCLambda currentLambda = null; + + public void visitLambda(JCLambda tree) { + JCLambda prevLambda = currentLambda; + try { + currentLambda = tree; + + int i = 0; + for (JCVariableDecl param : tree.params) { + if (!param.mods.annotations.isEmpty()) { + // Nothing to do for separateAnnotationsKinds if + // there are no annotations of either kind. + final TypeAnnotationPosition pos = + TypeAnnotationPosition.methodParameter(tree, i, + param.vartype.pos); + separateAnnotationsKinds(param.vartype, param.sym.type, param.sym, pos); + } + ++i; + } + + push(tree); + scan(tree.body); + scan(tree.params); + pop(); + } finally { + currentLambda = prevLambda; + } + } + + /** + * Resolve declaration vs. type annotations in variable declarations and + * then determine the positions. + */ + @Override + public void visitVarDef(final JCVariableDecl tree) { + if (tree.mods.annotations.isEmpty()) { + // Nothing to do for separateAnnotationsKinds if + // there are no annotations of either kind. + } else if (tree.sym == null) { + Assert.error("Visiting tree node before memberEnter"); + } else if (tree.sym.getKind() == ElementKind.PARAMETER) { + // Parameters are handled in visitMethodDef or visitLambda. + } else if (tree.sym.getKind() == ElementKind.FIELD) { + if (sigOnly) { + TypeAnnotationPosition pos = + TypeAnnotationPosition.field(tree.pos); + separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos); + } + } else if (tree.sym.getKind() == ElementKind.LOCAL_VARIABLE) { + final TypeAnnotationPosition pos = + TypeAnnotationPosition.localVariable(currentLambda, + tree.pos); + separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos); + } else if (tree.sym.getKind() == ElementKind.EXCEPTION_PARAMETER) { + final TypeAnnotationPosition pos = + TypeAnnotationPosition.exceptionParameter(currentLambda, + tree.pos); + separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos); + } else if (tree.sym.getKind() == ElementKind.RESOURCE_VARIABLE) { + final TypeAnnotationPosition pos = + TypeAnnotationPosition.resourceVariable(currentLambda, + tree.pos); + separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos); + } else if (tree.sym.getKind() == ElementKind.ENUM_CONSTANT) { + // No type annotations can occur here. + } else { + // There is nothing else in a variable declaration that needs separation. + Assert.error("Unhandled variable kind: " + tree + " of kind: " + tree.sym.getKind()); + } + + push(tree); + // super.visitVarDef(tree); + scan(tree.mods); + scan(tree.vartype); + if (!sigOnly) { + scan(tree.init); + } + pop(); + } + + @Override + public void visitBlock(JCBlock tree) { + // Do not descend into top-level blocks when only interested + // in the signature. + if (!sigOnly) { + scan(tree.stats); + } + } + + @Override + public void visitAnnotatedType(JCAnnotatedType tree) { + push(tree); + findPosition(tree, tree, tree.annotations); + pop(); + super.visitAnnotatedType(tree); + } + + @Override + public void visitTypeParameter(JCTypeParameter tree) { + findPosition(tree, peek2(), tree.annotations); + super.visitTypeParameter(tree); + } + + private void copyNewClassAnnotationsToOwner(JCNewClass tree) { + Symbol sym = tree.def.sym; + final TypeAnnotationPosition pos = + TypeAnnotationPosition.newObj(tree.pos); + ListBuffer newattrs = new ListBuffer<>(); + + for (Attribute.TypeCompound old : sym.getRawTypeAttributes()) { + newattrs.append(new Attribute.TypeCompound(old.type, old.values, + pos)); + } + + sym.owner.appendUniqueTypeAttributes(newattrs.toList()); + } + + @Override + public void visitNewClass(JCNewClass tree) { + if (tree.def != null && + !tree.def.mods.annotations.isEmpty()) { + JCClassDecl classdecl = tree.def; + TypeAnnotationPosition pos; + + if (classdecl.extending == tree.clazz) { + pos = TypeAnnotationPosition.classExtends(tree.pos); + } else if (classdecl.implementing.contains(tree.clazz)) { + final int index = classdecl.implementing.indexOf(tree.clazz); + pos = TypeAnnotationPosition.classExtends(index, tree.pos); + } else { + // In contrast to CLASS elsewhere, typarams cannot occur here. + throw new AssertionError("Could not determine position of tree " + tree); + } + Type before = classdecl.sym.type; + separateAnnotationsKinds(classdecl, tree.clazz.type, classdecl.sym, pos); + copyNewClassAnnotationsToOwner(tree); + // classdecl.sym.type now contains an annotated type, which + // is not what we want there. + // TODO: should we put this type somewhere in the superclass/interface? + classdecl.sym.type = before; + } + + scan(tree.encl); + scan(tree.typeargs); + scan(tree.clazz); + scan(tree.args); + + // The class body will already be scanned. + // scan(tree.def); + } + + @Override + public void visitNewArray(JCNewArray tree) { + findPosition(tree, tree, tree.annotations); + int dimAnnosCount = tree.dimAnnotations.size(); + ListBuffer depth = new ListBuffer<>(); + + // handle annotations associated with dimensions + for (int i = 0; i < dimAnnosCount; ++i) { + ListBuffer location = + new ListBuffer(); + if (i != 0) { + depth = depth.append(TypePathEntry.ARRAY); + location = location.appendList(depth.toList()); + } + final TypeAnnotationPosition p = + TypeAnnotationPosition.newObj(location.toList(), + currentLambda, + tree.pos); + + setTypeAnnotationPos(tree.dimAnnotations.get(i), p); + } + + // handle "free" annotations + // int i = dimAnnosCount == 0 ? 0 : dimAnnosCount - 1; + // TODO: is depth.size == i here? + JCExpression elemType = tree.elemtype; + depth = depth.append(TypePathEntry.ARRAY); + while (elemType != null) { + if (elemType.hasTag(JCTree.Tag.ANNOTATED_TYPE)) { + JCAnnotatedType at = (JCAnnotatedType)elemType; + final ListBuffer locationbuf = + locateNestedTypes(elemType.type, + new ListBuffer()); + final List location = + locationbuf.toList().prependList(depth.toList()); + final TypeAnnotationPosition p = + TypeAnnotationPosition.newObj(location, currentLambda, + tree.pos); + setTypeAnnotationPos(at.annotations, p); + elemType = at.underlyingType; + } else if (elemType.hasTag(JCTree.Tag.TYPEARRAY)) { + depth = depth.append(TypePathEntry.ARRAY); + elemType = ((JCArrayTypeTree)elemType).elemtype; + } else if (elemType.hasTag(JCTree.Tag.SELECT)) { + elemType = ((JCFieldAccess)elemType).selected; + } else { + break; + } + } + scan(tree.elems); + } + + private void findPosition(JCTree tree, JCTree frame, List annotations) { + if (!annotations.isEmpty()) { + /* + System.err.println("Finding pos for: " + annotations); + System.err.println(" tree: " + tree + " kind: " + tree.getKind()); + System.err.println(" frame: " + frame + " kind: " + frame.getKind()); + */ + final TypeAnnotationPosition p = + resolveFrame(tree, frame, frames.toList(), currentLambda, 0, + new ListBuffer()); + setTypeAnnotationPos(annotations, p); + } + } + + private void setTypeAnnotationPos(List annotations, + TypeAnnotationPosition position) { + for (JCAnnotation anno : annotations) { + // attribute might be null during DeferredAttr; + // we will be back later. + if (anno.attribute != null) { + ((Attribute.TypeCompound) anno.attribute).position = position; + } + } + } + + @Override + public String toString() { + return super.toString() + ": sigOnly: " + sigOnly; + } + } +} diff -r c32c9586ea94 -r aa84b6606229 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java Mon Sep 08 13:11:28 2014 +0200 @@ -29,8 +29,6 @@ import java.util.LinkedHashMap; import java.util.Map; -import javax.lang.model.element.ElementKind; -import javax.lang.model.type.TypeKind; import javax.tools.JavaFileObject; import com.sun.tools.javac.util.*; @@ -38,7 +36,6 @@ import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Symbol.*; -import com.sun.tools.javac.code.TypeAnnotationPosition.*; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.tree.JCTree.*; @@ -263,78 +260,36 @@ * Compute an attribute from its annotation. *********************************************************************/ - /** - * Enter (and attribute) a single regular annotation, returning - * its Attribute. We give these annotations a position in case we - * end up creating a type annotation from using toTypeCompound. - * - * In some cases, namely on annotations that can never be type - * annotations (like package annotations), the position can be - * null; however, if this annotation is in a place where it might - * possibly denote a type annotation, it will have a non-null - * position. - * - * @param a Annotation to attribute. - * @param expected Expected annotation type. - * @param env The environment. - * @param position The type annotation position this will have if - * it's converted to a type annotation. - * @return The Attribute.Compound representing this annotation. + /** Process a single compound annotation, returning its + * Attribute. Used from MemberEnter for attaching the attributes + * to the annotated symbol. */ Attribute.Compound enterAnnotation(JCAnnotation a, Type expected, - Env env, - TypeAnnotationPosition position) { - List> buf = - enterAttributeValues(a, expected, env, position); - Attribute.Compound ac = - new Attribute.Compound(a.type, buf, position); + Env env) { + List> elems = + enterAttributeValues(a, expected, env); + Attribute.Compound ac = new Attribute.Compound(a.type, elems); a.attribute = ac; return ac; } - /** - * Enter (and attribute) a single type annotation, returning its - * Attribute. - * - * Things are a bit complicated, though, because a single source - * annotation (JCAnnotation) might give rise to several bytecode - * annotations (Attribute.TypeCompound), but we can only associate - * a source annotation with one bytecode annotation. Thus, we - * have to distinguish between the "primary" (which will be stored - * to the JCAnnotation) and "secondary" (which won't) annotations. - * The primary place this gets used is for anonymous classes. - * - * The annotations we generate for the new instruction are the - * primary, and the ones we generate for the class are the - * secondaries. (Note: this choice is arbitrary, and it does not - * appear to cause any problems if these roles are reversed) - * - * @param a The annotation to attribute. - * @param expected The expected annotation type. - * @param env The environment. - * @param position The type annotation position to give the type - * annotation. - * @param secondaryAttr Whether or not this is a secondary (ie - * will ignore the .attribute field on a). - * @return The Attribute.TypeCompound representing the annotation. - */ Attribute.TypeCompound enterTypeAnnotation(JCAnnotation a, Type expected, - Env env, - TypeAnnotationPosition position, - boolean secondaryAttr) { - List> buf = - enterAttributeValues(a, expected, env, position); + Env env) { + List> elems = + enterAttributeValues(a, expected, env); + + if (a.attribute == null || !(a.attribute instanceof Attribute.TypeCompound)) { + // Create a new TypeCompound - // Secondary attr means we do not set the .attribute field of - // the JCAnnotation, nor do we pay attention to it. - if (!secondaryAttr || a.attribute == null || - !(a.attribute instanceof Attribute.TypeCompound)) { - // Create a new TypeCompound Attribute.TypeCompound tc = - new Attribute.TypeCompound(a.type, buf, position); + new Attribute.TypeCompound(a.type, elems, + // TODO: Eventually, we will get rid of this use of + // unknown, because we'll get a position from + // MemberEnter (task 8027262). + TypeAnnotationPosition.unknown); a.attribute = tc; return tc; } else { @@ -343,12 +298,10 @@ } } - // Attribute all the annotation's values. private List> enterAttributeValues(JCAnnotation a, Type expected, - Env env, - TypeAnnotationPosition position) { + Env env) { // The annotation might have had its type attributed (but not // checked) by attr.attribAnnotationTypes during MemberEnter, // in which case we do not need to do it again. @@ -373,13 +326,13 @@ JCExpression t = tl.head; if (!t.hasTag(ASSIGN)) { log.error(t.pos(), "annotation.value.must.be.name.value"); - enterAttributeValue(t.type = syms.errType, t, env, position); + enterAttributeValue(t.type = syms.errType, t, env); continue; } JCAssign assign = (JCAssign)t; if (!assign.lhs.hasTag(IDENT)) { log.error(t.pos(), "annotation.value.must.be.name.value"); - enterAttributeValue(t.type = syms.errType, t, env, position); + enterAttributeValue(t.type = syms.errType, t, env); continue; } JCIdent left = (JCIdent)assign.lhs; @@ -394,7 +347,7 @@ if (method.owner != a.type.tsym && !isError) log.error(left.pos(), "no.annotation.member", left.name, a.type); Type result = method.type.getReturnType(); - Attribute value = enterAttributeValue(result, assign.rhs, env, position); + Attribute value = enterAttributeValue(result, assign.rhs, env); if (!method.type.isErroneous()) buf.append(new Pair<>((MethodSymbol)method, value)); t.type = result; @@ -405,13 +358,6 @@ Attribute enterAttributeValue(Type expected, JCExpression tree, Env env) { - return enterAttributeValue(expected, tree, env, null); - } - - Attribute enterAttributeValue(Type expected, - JCExpression tree, - Env env, - TypeAnnotationPosition position) { //first, try completing the attribution value sym - if a completion //error is thrown, we should recover gracefully, and display an //ordinary resolution diagnostic. @@ -433,7 +379,8 @@ ListBuffer buf = new ListBuffer<>(); for (List l = na.elems; l.nonEmpty(); l=l.tail) { buf.append(enterAttributeValue(types.elemtype(expected), - l.head, env, position)); + l.head, + env)); } na.type = expected; return new Attribute. @@ -447,13 +394,15 @@ log.error(na.elemtype.pos(), "new.not.allowed.in.annotation"); } for (List l = na.elems; l.nonEmpty(); l=l.tail) { - enterAttributeValue(syms.errType, l.head, env, position); + enterAttributeValue(syms.errType, + l.head, + env); } return new Attribute.Error(syms.errType); } if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) { if (tree.hasTag(ANNOTATION)) { - return enterAnnotation((JCAnnotation)tree, expected, env, position); + return enterAnnotation((JCAnnotation)tree, expected, env); } else { log.error(tree.pos(), "annotation.value.must.be.annotation"); expected = syms.errType; @@ -462,7 +411,7 @@ if (tree.hasTag(ANNOTATION)) { //error recovery if (!expected.isErroneous()) log.error(tree.pos(), "annotation.not.valid.for.type", expected); - enterAnnotation((JCAnnotation)tree, syms.errType, env, position); + enterAnnotation((JCAnnotation)tree, syms.errType, env); return new Attribute.Error(((JCAnnotation)tree).annotationType.type); } if (expected.isPrimitive() || @@ -529,11 +478,9 @@ * synthesized container annotation or null IFF all repeating * annotation are invalid. This method reports errors/warnings. */ - private T processRepeatedAnnotations( - List annotations, + private T processRepeatedAnnotations(List annotations, AnnotationContext ctx, - Symbol on, - TypeAnnotationPosition position) { + Symbol on) { T firstOccurrence = annotations.head; List repeated = List.nil(); Type origAnnoType = null; @@ -545,8 +492,12 @@ !annotations.tail.isEmpty()); // i.e. size() > 1 int count = 0; - for (List al = annotations; !al.isEmpty(); al = al.tail) { + for (List al = annotations; + !al.isEmpty(); + al = al.tail) + { count++; + // There must be more than a single anno in the annotation list Assert.check(count > 1 || !al.tail.isEmpty()); @@ -586,16 +537,26 @@ new Pair(containerValueSymbol, new Attribute.Array(arrayOfOrigAnnoType, repeated)); if (ctx.isTypeCompound) { - Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p), position); + /* TODO: the following code would be cleaner: + Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p), + ((Attribute.TypeCompound)annotations.head).position); + JCTypeAnnotation annoTree = m.TypeAnnotation(at); + at = enterTypeAnnotation(annoTree, targetContainerType, ctx.env); + */ + // However, we directly construct the TypeCompound to keep the + // direct relation to the contained TypeCompounds. + Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p), + ((Attribute.TypeCompound)annotations.head).position); + + // TODO: annotation applicability checks from below? + at.setSynthesized(true); @SuppressWarnings("unchecked") T x = (T) at; return x; } else { - Attribute.Compound c = new Attribute.Compound(targetContainerType, - List.of(p), - position); + Attribute.Compound c = new Attribute.Compound(targetContainerType, List.of(p)); JCAnnotation annoTree = m.Annotation(c); if (!chk.annotationApplicable(annoTree, on)) @@ -604,7 +565,7 @@ if (!chk.validateAnnotationDeferErrors(annoTree)) log.error(annoTree.pos(), "duplicate.annotation.invalid.repeated", origAnnoType); - c = enterAnnotation(annoTree, targetContainerType, ctx.env, position); + c = enterAnnotation(annoTree, targetContainerType, ctx.env); c.setSynthesized(true); @SuppressWarnings("unchecked") @@ -616,7 +577,6 @@ } } - /** Fetches the actual Type that should be the containing annotation. */ private Type getContainingType(Attribute.Compound currentAnno, DiagnosticPosition pos, @@ -746,53 +706,31 @@ return fatalError ? null : containerValueSymbol; } - /** - * First step of repeating annotations handling: go through a list - * of annotations, and gather up all the repeated ones into a map, - * which we use to build an AnnotationContext. - * - * Because we do this, we need to get all the annotations for a - * given AST node at once (ie. if we have "@A @B @A int foo;", we - * have to get "@A @B @A" at the same time). - * - * @param annotations The annotations being attached. - * @param env The environment. - * @param sym The symbol to which the annotations will be attached. - * @param creator The attribute creator used to enter the annotations. - * @param position The position for any type annotations. - * @return The AnnotaionContext for use in the next phase. - */ private AnnotationContext prepareEnterAnnotations(List annotations, Env env, Symbol sym, AttributeCreator creator, - TypeAnnotationPosition position) { + boolean isTypeCompound) { Map> annotated = new LinkedHashMap<>(); Map pos = new HashMap<>(); - // Go through the annotation list, build up a map from - // annotation types to lists of annotations. for (List al = annotations; !al.isEmpty(); al = al.tail) { JCAnnotation a = al.head; - T c = creator.create(a, syms.annotationType, env, position); + T c = creator.create(a, syms.annotationType, env); Assert.checkNonNull(c, "Failed to create annotation"); if (annotated.containsKey(a.type.tsym)) { - // Make sure we even allow repeating annotations. if (!allowRepeatedAnnos) { log.error(a.pos(), "repeatable.annotations.not.supported.in.source"); allowRepeatedAnnos = true; } - // Append the annotation to the list for this kind of - // annotation. ListBuffer l = annotated.get(a.type.tsym); l = l.append(c); annotated.put(a.type.tsym, l); pos.put(c, a.pos()); } else { - // We are seeing the first annotation of this kind. annotated.put(a.type.tsym, ListBuffer.of(c)); pos.put(c, a.pos()); } @@ -806,54 +744,25 @@ } return new AnnotationContext<>(env, annotated, pos, - creator.createsTypeCompound()); + isTypeCompound); } - /** - * Entry-point for repeating annotations handling. At this point, - * we should know the type annotation position, and we should have - * all the annotations for a given source location. - * - * We first gather up all the repeated annotations and build an - * AnnotationContext. Then create Placeholder's for any repeated - * annotations and send them further down the pipeline. - * - * Something to keep in mind here is that even if we are handling - * "declaration" annotations, it is still possible that those - * might turn into type annotations (consider "@A @B int foo;", - * for example). - * - * The pipeline uses a sort of continuation-passing like style, - * with creator and attacher. This allows two things. First, it - * allows for a single pipeline for repeating annotations, - * regardless of what eventually happens to the annotations. - * Second, it allows us to avoid some unsafe casts we would - * otherwise have to make. - * - * @param annotations The annotations to handle. - * @param env The environment. - * @param sym The symbol to which to attach annotations. - * @param position The position for type annotations. - * @param creator The creator to use to enter annotations. - * @param attacher The attacher to use to attach annotations. - */ + // Gather up annotations into a map from type symbols to lists of + // Compound attributes, then continue on with repeating + // annotations processing private void attachAttributesLater(final List annotations, final Env env, final Symbol sym, - final TypeAnnotationPosition position, + final boolean isTypeCompound, final AttributeCreator creator, final AttributeAttacher attacher) { - // First, gather up all the repeated annotations. final AnnotationContext ctx = - prepareEnterAnnotations(annotations, env, sym, creator, position); + prepareEnterAnnotations(annotations, env, sym, creator, isTypeCompound); final Map> annotated = ctx.annotated; boolean hasRepeated = false; - // Now run through all the annotation types in the - // AnnotationContext. If there are any that have more than - // one entry, then we set up a Placeholder for them. List buf = List.nil(); for (ListBuffer lb : annotated.values()) { if (lb.size() == 1) { @@ -868,62 +777,14 @@ final List attrs = buf.reverse(); - if (!creator.createsTypeCompound()) { + if (!isTypeCompound) { // Attach declaration attributes early, so // that @Repeatable and other annotations get attached. // Since the attacher uses setDeclarationAttributes, this // will be overwritten later. - // - // The root cause of this is that annotations are - // themselves defined using annotations. However, it is - // never the case that a type annotation affects the - // definition of an annotation, so we don't have to do - // this. - // - // We really should find a better way to do this. - @SuppressWarnings("unchecked") - List tempattrs = (List) attrs; - sym.setDeclarationAttributes(tempattrs); + attacher.attach(sym, attrs); } - if (hasRepeated) { - // If we have repeated annotations, then we go to the next - // pipeline step, which replaces all the placeholders. - replacePlaceholdersAndAttach(attrs, ctx, env, sym, attacher); - } else { - // If we don't have repeated annotations, then we still - // have to run the annotations through the rest of the - // pipeline. - // - // For type annotations, we might have error-reporting to - // do, and the attacher might end up attaching the - // annotation to the symbol's owner as well. - // - // For regular annotations, we might have a - // classifyingAttacher, in which case we have to pull the - // annotations off the symbol, classify them, and then put - // them in the right place. - attachAttributesAfterRepeated(attrs, env, attacher); - } - } - - /** - * Next pipeline step for repeated annotations: replate all the - * placeholders, and then send the result further down the pipe. - * - * @param attrs The Attributes representing the annotations. - * @param ctx The AnnotationContext being used. - * @param env The environment. - * @param sym The symbol to which to attach annotations. - * @param attacher The attacher to use to attach annotations. - */ - private - void replacePlaceholdersAndAttach(final List attrs, - final AnnotationContext ctx, - final Env env, - final Symbol sym, - final AttributeAttacher attacher) { - // Set up a Worker. repeated(new Annotate.Worker() { @Override public String toString() { @@ -935,493 +796,38 @@ JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile); try { - // Replace placeholders - final List replaced = - replacePlaceholders(attrs, ctx, sym); - // Then send the result to the final pipeline stage. - attachAttributesAfterRepeated(replaced, env, attacher); + attacher.attach(sym, replacePlaceholders(attrs, ctx, sym)); } finally { log.useSource(oldSource); } } }); - } - - /** - * Final pipeline stage. Simply use the attacher to deal with the - * annotations however we want to deal with them. Note that - * attachers may do a number of things, like attach annotations to - * other symbols (as is the case with some type annotations, which - * get attached to their symbol's owner as well), report errors, - * or even create copies (as is the case with classifyingAttacher) - * - * At this point, we have to be able to guarantee that we don't - * see any Placeholders. - * - * @param attrs The Attributes representing the annotations. - * @param env The environment. - * @param attacher The attacher we use to finish handling the - * annotations. - */ - private - void attachAttributesAfterRepeated(final List attrs, - final Env env, - final AttributeAttacher attacher) { - // Set up a Worker that just calls the attacher. - afterRepeated(new Worker() { - @Override - public String toString() { - return "attach pass for: " + attrs; - } - - @Override - public void run() { - JavaFileObject oldSource = - log.useSource(env.toplevel.sourcefile); - try { - attacher.attach(attrs); - } finally { - log.useSource(oldSource); - } - } - }); - } - - /** - * AttributeAttachers are similar to continuations. That contains - * the behavior of the final stage of the annotation pipeline, - * when we've creted Attributes (which have a type annotation - * position), and we've dealt with repeating annotations. Once we - * have done all that, we simply hand off the list of attributes - * to the attacher and let it do its work. - * - * If we didn't have the multiple deferred steps, we could - * implement this by returning a list of Attributes from a - * top-level method representing the entire repeating annotations - * pipeline. Since we have to handle annotations in multiple - * steps, we can't do that. Therefore, in this light, we can - * think of an attacher as being essentially a return - * continuation. - * - * We also have ways to "build" more complex attachers out of - * simple ones, such as classifyingAttacher. This allows us - * considerable flexibility in how we deal with annotations at the - * end of the pipeline (which is necessary, because there are a - * lot of cases). - */ - public interface AttributeAttacher { - public void attach(List attrs); - } - - /** - * An interface for describing error reporting behaviors for - * type-only annotations. Sometimes, we need to report errors if - * any annotations wind up being type-only annotations (the best - * example being for illegal scoping). But at the point where we - * know this, we don't always know if a given annotation will be a - * type-only annotation, a regular annotation, or both. So we - * have to defer the error-reporting until we do know. - */ - public interface Reporter { - public void report(List attrs); - } - - public enum AnnotationKind { DECLARATION, TYPE, BOTH } - - public Attribute[] getTargetTypes(Attribute.Compound a) { - Attribute.Compound atTarget = - a.type.tsym.attribute(syms.annotationTargetType.tsym); - if (atTarget == null) { - return null; - } - Attribute atValue = atTarget.member(names.value); - Assert.check(atValue instanceof Attribute.Array); - return ((Attribute.Array) atValue).values; - } - - public boolean hasTypeUseTarget(Attribute.Compound a, - boolean isTypeParameter) { - Attribute[] targets = getTargetTypes(a); - if (targets != null) { - for (Attribute app : targets) { - Assert.check(app instanceof Attribute.Enum); - Attribute.Enum e = (Attribute.Enum) app; - if (e.value.name == names.TYPE_USE || - (isTypeParameter && e.value.name == names.TYPE_PARAMETER)) { - return true; - } - } - } - return false; - } - - /** - * Determine whether an annotation is a declaration annotation, - * a type annotation, or both. - */ - public AnnotationKind annotationKind(Attribute.Compound a, Symbol s) { - Attribute[] targets = getTargetTypes(a); - if (targets == null) { - return AnnotationKind.DECLARATION; - } - boolean isDecl = false, isType = false; - for (Attribute app : targets) { - Assert.check(app instanceof Attribute.Enum); - Attribute.Enum e = (Attribute.Enum) app; - if (e.value.name == names.TYPE) { - if (s.kind == Kinds.TYP) { - ElementKind skind = s.getKind(); - // The only symbols we should see here correspond - // to definitions. - Assert.check(skind == ElementKind.ANNOTATION_TYPE || - skind == ElementKind.INTERFACE || - skind == ElementKind.ENUM || - skind == ElementKind.CLASS); - isDecl = true; - } - } else if (e.value.name == names.FIELD) { - if (s.kind == Kinds.VAR && - s.owner.kind != Kinds.MTH) - isDecl = true; - } else if (e.value.name == names.METHOD) { - if (s.kind == Kinds.MTH && - !s.isConstructor()) - isDecl = true; - } else if (e.value.name == names.PARAMETER) { - if (s.kind == Kinds.VAR && - s.owner.kind == Kinds.MTH && - (s.flags() & Flags.PARAMETER) != 0) - isDecl = true; - } else if (e.value.name == names.CONSTRUCTOR) { - if (s.kind == Kinds.MTH && - s.isConstructor()) - isDecl = true; - } else if (e.value.name == names.LOCAL_VARIABLE) { - if (s.kind == Kinds.VAR && - s.owner.kind == Kinds.MTH && - (s.flags() & Flags.PARAMETER) == 0) - isDecl = true; - } else if (e.value.name == names.ANNOTATION_TYPE) { - if (s.kind == Kinds.TYP && - (s.flags() & Flags.ANNOTATION) != 0) - isDecl = true; - } else if (e.value.name == names.PACKAGE) { - if (s.kind == Kinds.PCK) - isDecl = true; - } else if (e.value.name == names.TYPE_USE) { - if (s.kind == Kinds.TYP || - s.kind == Kinds.VAR || - (s.kind == Kinds.MTH && !s.isConstructor() && - !s.type.getReturnType().hasTag(TypeTag.VOID)) || - (s.kind == Kinds.MTH && s.isConstructor())) - isType = true; - } else if (e.value.name == names.TYPE_PARAMETER) { - /* Irrelevant in this case: we will never see symbols - * that are type parameters, as we never attach - * declaration annotations to them. */ - Assert.check(s.getKind() != ElementKind.TYPE_PARAMETER); - } else { - Assert.error("annotationKind(): unrecognized Attribute name " + e.value.name + - " (" + e.value.name.getClass() + ")"); - } - } - if (isDecl && isType) { - return AnnotationKind.BOTH; - } else if (isType) { - return AnnotationKind.TYPE; } else { - return AnnotationKind.DECLARATION; + attacher.attach(sym, attrs); } } - /** - * An attacher that just attaches annotations as declaration - * annotations. This is used in places where we know for a fact - * that type annotations cannot occur. - */ - private AttributeAttacher - declAnnotationsAttacher(final Symbol sym) { - return new AttributeAttacher() { + private interface AttributeAttacher { + public void attach(Symbol sym, List attrs); + } + + private final AttributeAttacher declAnnotationsAttacher = + new AttributeAttacher() { @Override - public String toString() { - return "Attacher for strictly declaration annotations, for " + - sym; - } - - @Override - public void attach(List attrs) { + public void attach(Symbol sym, List attrs) { sym.resetAnnotations(); sym.setDeclarationAttributes(attrs); } }; - } - /** - * An attacher that just attaches annotations as type annotations. - * We use this in places where only type annotations can occur. - * The most common use for this is any annotation where we have to - * "parse" a type (arrays, inner classes, type arguments, bounds, - * etc.). We also use this for base types for non-declarations - * (ie. casts, instanceofs, etc). A more subtle case is for - * anonymous classes and receiver parameters, both of which cannot - * have regular annotations. - */ - private AttributeAttacher - typeAnnotationsAttacher(final Symbol sym) { - return new AttributeAttacher() { - @Override - public String toString() { - return "Attacher for strictly type annotations, for " + sym; - } - - @Override - public void attach(List attrs) { - if (!attrs.isEmpty()) { - attachTypeAnnotations(sym, attrs); - } - } - }; - } - - /** - * Attach type-only annotations using an attacher, and run a - * reporter. Either the reporter or the attacher may be null, in - * which case we skip that step. - */ - private AttributeAttacher - reportingTypeAnnotationsAttacher(final AttributeAttacher attacher, - final Reporter reporter) { - return new AttributeAttacher() { - @Override - public String toString() { - return "Error-reporting type annotation, attacher is: " + attacher + - "\n reporter is: " + reporter; - } - + private final AttributeAttacher typeAnnotationsAttacher = + new AttributeAttacher() { @Override - public void attach(List attrs) { - if (attacher != null) - attacher.attach(attrs); - - if (reporter != null) - reporter.report(attrs); - } - }; - } - - /** - * Attach type-only annotations to a symbol and also update the - * .type field on a tree (unless it is a package type). This is - * used to put annotations on to a type as well as a symbol. - */ - private AttributeAttacher - typeUpdatingTypeAnnotationsAttacher(final AttributeAttacher attacher, - final JCTree tree) { - return new AttributeAttacher() { - @Override - public String toString() { - return "Type-updating type annotation attacher, attacher is: " + attacher + - "\n tree is: " + tree; - } - - @Override - public void attach(List attrs) { - if (null != attacher) - attacher.attach(attrs); - - if (!attrs.isEmpty() && !tree.type.hasTag(TypeTag.PACKAGE)) { - tree.type = tree.type.annotatedType(attrs); - } - } - }; - } - - /** - * A Reporter for illegal scoping. We set one of these up in - * TypeAnnotate whenever we are in a place that corresponds to a - * package or static class that cannot be annotated. - */ - private void reportIllegalScoping(List attrs, - int pos) { - switch (attrs.size()) { - case 0: - // Don't issue an error if all type annotations are - // also declaration annotations. - // If the annotations are also declaration annotations, they are - // illegal as type annotations but might be legal as declaration annotations. - // The normal declaration annotation checks make sure that the use is valid. - break; - case 1: - log.error(pos, "cant.type.annotate.scoping.1", attrs); - break; - default: - log.error(pos, "cant.type.annotate.scoping", attrs); - } - } - - private Reporter - illegalScopingReporter(final int pos) { - return new Reporter() { - @Override - public String toString() { - return "Illegal scoping reporter at position " + pos; - } - - @Override - public void report(List attrs) { - reportIllegalScoping(attrs, pos); + public void attach(Symbol sym, List attrs) { + sym.appendUniqueTypeAttributes(attrs); } }; - } - // Create the "simple case": just attach type and regular - // annotations, no reporting. - private AttributeAttacher - classifyingAttacher(final Symbol sym) { - return classifyingAttacher(sym, declAnnotationsAttacher(sym), - typeAnnotationsAttacher(sym), - null); - } - - - /** - * Build an attacher for handling the case where we have - * annotations, but we don't know for sure whether they are - * declaration annotations, type annotations, or both. - * - * We do this by taking an attacher for declaration annotations, - * another one for type annotations, and (possibly) a reporter for - * type-only annotations. We then use the logic from - * annotationKind to figure out what kind each annotation is and - * deal with it accordingly. - * - * Any of the declAttacher, the typeAttacher, or the Reporter can - * be null, in which case we skip it. - * - * We have to have the reporter *separate* from the type - * annotation attacher, because we might be attaching type - * annotations that are also declaration annotations. But the - * semantics of reporters are that they get called for type-only - * annotations. For an example of where this matters, consider - * "@A java.lang.Object foo;", where @A can annotate packages and - * type uses. We would create the classifyingAttacher with null - * for the type attacher and an illegal scoping reporter. Both - * attachers would end up getting called on @A (which, we'd skip - * the type attacher, because it's null), the result being that @A - * goes on foo as a declaration annotation. The reporter would - * not get called, because there are no type-only annotations. - * However, if @A can only annotate type uses, then it's a - * type-only annotation, and we report an illegal scoping error. - * - * Note: there is a case where we want both attachers to be null: - * speculative attribution. - * - * @param sym The symbol to which to attach annotations. - * @param declAttacher The attacher to use for declaration (and - * both) annotations, or null. - * @param typeAttacher The attacher to use for type (and both) - * annotations, or null. - * @param reporter The reporter to use for type-only annotations, or null. - * @return The created attacher. - */ - private AttributeAttacher - classifyingAttacher(final Symbol sym, - final AttributeAttacher declAttacher, - final AttributeAttacher typeAttacher, - final Reporter reporter) { - return new AttributeAttacher() { - @Override - public String toString() { - return "Classifying attacher, attaching to " + sym + - "\n declaration annotation attacher is: " + declAttacher + - "\n type annotation attacher is: " + typeAttacher + - "\n reporter for strictly type annotations is: " + reporter; - } - - @Override - public void attach(List attrs) { - // We sort annotations into "buckets" based on what - // kind they are. - ListBuffer declAnnos = new ListBuffer<>(); - ListBuffer typeAnnos = new ListBuffer<>(); - // We also need to keep track of the type-only - // annotations, in case we have a reporting action. - ListBuffer onlyTypeAnnos = new ListBuffer<>(); - - for (Attribute.Compound a : attrs) { - Assert.check(!(a instanceof Placeholder), - "Placeholders found in annotations being attached!"); - switch (annotationKind(a, sym)) { - case DECLARATION: - declAnnos.append(a); - break; - case BOTH: { - declAnnos.append(a); - Attribute.TypeCompound ta = a.toTypeCompound(); - Assert.checkNonNull(ta.position); - typeAnnos.append(ta); - break; - } - case TYPE: { - Attribute.TypeCompound ta = a.toTypeCompound(); - Assert.checkNonNull(ta.position); - typeAnnos.append(ta); - // Also keep track which annotations are only type annotations - onlyTypeAnnos.append(ta); - break; - } - default: - throw new AssertionError("Unknown annotation type"); - } - } - - if (declAttacher != null) - declAttacher.attach(declAnnos.toList()); - - if (typeAttacher != null) - typeAttacher.attach(typeAnnos.toList()); - - if (reporter != null) - reporter.report(onlyTypeAnnos.toList()); - } - }; - } - - /** - * Actually attach a list of type annotations to a symbol. For - * variables defined in methods, we need to attach to both the - * variable symbol, as well as the method symbol. This takes care - * of that. - * - * @param sym The symbol to which to attach. - * @param attrs The annotations to attach. - */ - public void attachTypeAnnotations(Symbol sym, List attrs) { - sym.appendUniqueTypeAttributes(attrs); - - // For type annotations on variables in methods, make - // sure they are attached to the owner too. - switch(sym.getKind()) { - case PARAMETER: - case LOCAL_VARIABLE: - case RESOURCE_VARIABLE: - case EXCEPTION_PARAMETER: - // Make sure all type annotations from the symbol are also - // on the owner. - sym.owner.appendUniqueTypeAttributes(attrs); - break; - } - } - - /** - * Final task for repeating annotations: go through a list of - * Attributes and replace all the placeholders with containers. - * - * @param buf The list of Attributes. - * @param ctx The AnnotationContext. - * @param sym The symbol to which we are attaching. - * @return The list of attributes with all placeholders replaced. - */ private List replacePlaceholders(List buf, Annotate.AnnotationContext ctx, @@ -1443,16 +849,13 @@ return result.reverse(); } - /** - * Replace one placeholder with a container. - */ private T replaceOne(Placeholder placeholder, Annotate.AnnotationContext ctx, Symbol sym) { // Process repeated annotations T validRepeated = processRepeatedAnnotations(placeholder.getPlaceholderFor(), - ctx, sym, placeholder.position); + ctx, sym); if (validRepeated != null) { // Check that the container isn't manually @@ -1473,65 +876,16 @@ * Annotation processing *********************************************************************/ - /** - * Run a list of annotations through the repeating annotations - * pipeline, and attach them. We don't have any diagnostic - * position. - */ - void annotateLater(final List annotations, - final Env localEnv, - final Symbol s) { - annotateLater(annotations, localEnv, s, null); - } - - /** - * Run a list of annotations through the repeating annotations - * pipeline and attach them. This is for when we have annotations - * that cannot possibly be type annotations (thus, we have no type - * annotation position). - */ + /** Queue annotations for later processing. */ void annotateLater(final List annotations, final Env localEnv, final Symbol s, final DiagnosticPosition deferPos) { - // Only attach declaration annotations. - doAnnotateLater(annotations, localEnv, s, deferPos, null, - declAnnotationsAttacher(s)); - } - - /** - * Run a list of annotations through the repeating annotation - * pipeline, and then classify and attach them. This is used - * whenever we have annotations that might be regular annotations, - * type annotations, or both. - */ - void annotateWithClassifyLater(final List annotations, - final Env localEnv, - final Symbol s, - final DiagnosticPosition deferPos, - final TypeAnnotationPosition tapos) { - // Set up just the basic classifying attacher. - doAnnotateLater(annotations, localEnv, s, deferPos, tapos, - classifyingAttacher(s)); - } - - /** - * Set up a worker for handling annotations without parsing a type tree. - */ - private void doAnnotateLater(final List annotations, - final Env localEnv, - final Symbol s, - final DiagnosticPosition deferPos, - final TypeAnnotationPosition tapos, - final AttributeAttacher attacher) { if (annotations.isEmpty()) { return; } - // Mark annotations as incomplete for now. - // - // This should probably get redesigned at some point. if (s.kind != PCK) { - s.resetAnnotations(); + s.resetAnnotations(); // mark Annotations as incomplete for now } normal(new Annotate.Worker() { @Override @@ -1541,44 +895,12 @@ @Override public void run() { - annotateNow(annotations, localEnv, s, deferPos, - tapos, attacher); - } - }); - - validate(annotationValidator(annotations, localEnv, s)); - } - - /** - * Run a list of declaration (meaning they are in a declaration - * position) annotations through the repeating annotations - * pipeline. - * - * Note that in some cases, these annotations might end up being - * type annotations, or both declaration and type annotations. - * - * @param annotations The annotations to handle. - * @param localEnv the environment. - * @param s The symbol to which to attach. - * @param deferPos The diagnostic position to use. - * @param position The type annotation position to use if some of - * the annotations end up being type annotations. - * @param attacher The attacher to use. - */ - private void annotateNow(final List annotations, - final Env localEnv, - final Symbol s, - final DiagnosticPosition deferPos, - final TypeAnnotationPosition position, - final AttributeAttacher attacher) { - if (annotations.isEmpty()) { - return; - } Assert.check(s.kind == PCK || s.annotationsPendingCompletion()); JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); - DiagnosticPosition prevLintPos = deferPos != null ? - deferredLintHandler.setPos(deferPos) : - deferredLintHandler.immediate(); + DiagnosticPosition prevLintPos = + deferPos != null + ? deferredLintHandler.setPos(deferPos) + : deferredLintHandler.immediate(); Lint prevLint = deferPos != null ? null : chk.setLint(lint); try { if (s.hasAnnotations() && @@ -1586,7 +908,7 @@ log.error(annotations.head.pos, "already.annotated", kindName(s), s); - actualEnterAnnotations(annotations, localEnv, s, position, attacher); + actualEnterAnnotations(annotations, localEnv, s); } finally { if (prevLint != null) chk.setLint(prevLint); @@ -1594,12 +916,9 @@ log.useSource(prev); } } + }); - // Set up a validator to enforce some rules on regular annotations. - private Annotate.Worker annotationValidator(final List annotations, - final Env localEnv, - final Symbol s) { - return new Annotate.Worker() { //validate annotations + validate(new Annotate.Worker() { //validate annotations @Override public void run() { JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); @@ -1609,140 +928,52 @@ log.useSource(prev); } } - }; - } - - private void checkForDeclarationAnnotations(List annotations, - boolean isTypeParameter) { - // Ensure that no declaration annotations are present. - // Note that a tree type might be an AnnotatedType with - // empty annotations, if only declaration annotations were given. - // This method will raise an error for such a type. - for (JCAnnotation ai : annotations) { - Assert.checkNonNull(ai.type); - Assert.checkNonNull(ai.attribute); - - if (!ai.type.isErroneous() && - !hasTypeUseTarget(ai.attribute, isTypeParameter)) { - log.error(ai.pos(), "annotation.type.not.applicable"); - } - } + }); } - // Set up a validator to enforce some rules on type annotations. - // In addition to those enforced by Check.validateTypeAnnotations, - // this enforces that declaration annotations cannot occur on type - // parameters. - private Annotate.Worker typeAnnotationValidator(final List annotations, - final Env localEnv, - final boolean isTypeParameter) { - return new Annotate.Worker() { //validate annotations - @Override - public void run() { - JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); - try { - checkForDeclarationAnnotations(annotations, isTypeParameter); - chk.validateTypeAnnotations(annotations, isTypeParameter); - } finally { - log.useSource(prev); - } - } - }; + private interface AttributeCreator { + public T create(JCAnnotation a, Type expected, Env env); } - /** - * This is an interface that wraps up the functionality of - * enterAnnotations and enterTypeAnnotations. This allows some - * code duplication to be removed from the original repeating - * annotations pipeline. It also allows for some unsafe casts to - * be eliminated. - * - * Note: when Lambdas can be used in the compiler, we can just use - * method refs for enterAnnotations and enterTypeAnnotations. - */ - private interface AttributeCreator { - public T create(JCAnnotation a, - Type expected, - Env env, - TypeAnnotationPosition position); - public abstract boolean createsTypeCompound(); - } - - // Note: try to avoid doing anything that makes these any more - // than just the equivalent of method refs in a pre-lambda - // setting. That way, they can go away when we are allowed to use - // lambda. + // TODO: When SE8 features can be used, these can go away and be + // replaced by method refs. private final AttributeCreator enterAnnotationsCreator = new AttributeCreator() { @Override - public String toString() { - return "Attribute creator for regular declaration annotations"; - } - - @Override public Attribute.Compound create(JCAnnotation a, Type expected, - Env env, - TypeAnnotationPosition position) { - return enterAnnotation(a, syms.annotationType, env, position); + Env env) { + return enterAnnotation(a, syms.annotationType, env); } - - @Override - public boolean createsTypeCompound() { return false; } }; - - private AttributeCreator - enterTypeAnnotationsCreator(final boolean secondaryAttr) { - return new AttributeCreator() { - @Override - public String toString() { - if (!secondaryAttr) { - return "Attribute creator for regular type annotations"; - } else { - return "Attribute creator for regular type annotations, ignores cached attributes"; - } - } - + private final AttributeCreator enterTypeAnnotationsCreator = + new AttributeCreator() { @Override public Attribute.TypeCompound create(JCAnnotation a, Type expected, - Env env, - TypeAnnotationPosition position) { - return enterTypeAnnotation(a, syms.annotationType, - env, position, secondaryAttr); + Env env) { + return enterTypeAnnotation(a, syms.annotationType, env); } + }; - @Override - public boolean createsTypeCompound() { return true; } - }; + /** Enter a set of annotations. */ + private void actualEnterAnnotations(List annotations, + Env env, + Symbol s) { + Assert.checkNonNull(s, "Symbol argument to actualEnterAnnotations is null"); + attachAttributesLater(annotations, env, s, false, + enterAnnotationsCreator, + declAnnotationsAttacher); } - /** - * Send a list of annotations (which occurred in a declaration - * position) into the repeating annotations pipeline. - */ - private void actualEnterAnnotations(List annotations, - Env env, - Symbol s, - TypeAnnotationPosition position, - AttributeAttacher attacher) { - Assert.checkNonNull(s); - attachAttributesLater(annotations, env, s, position, - enterAnnotationsCreator, attacher); - } - - /** - * Send a list of annotations (which occurred in a type-use - * position) into the repeating annotations pipeline. + /* + * If the symbol is non-null, attach the type annotation to it. */ private void actualEnterTypeAnnotations(final List annotations, final Env env, final Symbol s, - final DiagnosticPosition deferPos, - final boolean secondaryAttr, - final TypeAnnotationPosition position, - final AttributeAttacher attacher) { - Assert.checkNonNull(s); + final DiagnosticPosition deferPos) { + Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is nul/"); JavaFileObject prev = log.useSource(env.toplevel.sourcefile); DiagnosticPosition prevLintPos = null; @@ -1750,9 +981,9 @@ prevLintPos = deferredLintHandler.setPos(deferPos); } try { - attachAttributesLater(annotations, env, s, position, - enterTypeAnnotationsCreator(secondaryAttr), - attacher); + attachAttributesLater(annotations, env, s, true, + enterTypeAnnotationsCreator, + typeAnnotationsAttacher); } finally { if (prevLintPos != null) deferredLintHandler.setPos(prevLintPos); @@ -1760,114 +991,11 @@ } } - /** - * Given a type tree, walk down it and handle any annotations we - * find. - * - * @param tree The type tree to scan. - * @param env The environment. - * @param sym The symbol to which to attach any annotations we - * might find. - * @param deferPos The diagnostic position to use. - * @param creator The creator to use for making positions. - */ public void annotateTypeLater(final JCTree tree, final Env env, final Symbol sym, - final DiagnosticPosition deferPos, - final PositionCreator creator) { - doAnnotateTypeLater(tree, List.nil(), env, - sym, deferPos, creator, false, false); - } - - /** - * Given a type tree, walk down it and handle any annotations we - * find. We also have a set of base-type annotations (which - * occurred in a declaration position in source), which may either - * be declaration annotations or annotations on the base type. - * For an example, in "@A int @B []", we would have the type tree - * "int @B []" with base-type annotations "@A". - * - * @param tree The type tree to scan. - * @param baseTypeAnnos The base-type annotations. - * @param env The environment. - * @param sym The symbol to which to attach any annotations we - * might find. - * @param deferPos The diagnostic position to use. - * @param creator The creator to use for making positions. - */ - public void annotateTypeLater(final JCTree tree, - final List baseTypeAnnos, - final Env env, - final Symbol sym, - final DiagnosticPosition deferPos, - final PositionCreator creator) { - doAnnotateTypeLater(tree, baseTypeAnnos, env, sym, deferPos, - creator, false, false); - } - - /** - * Given a type tree, walk down it and handle any annotations we - * find. We also have a set of base-type annotations (which - * occurred in a declaration position in source), which must be - * type annotations on the base type. - * - * @param tree The type tree to scan. - * @param baseTypeAnnos The base-type annotations. - * @param env The environment. - * @param sym The symbol to which to attach any annotations we - * might find. - * @param deferPos The diagnostic position to use. - * @param creator The creator to use for making positions. - */ - public void annotateStrictTypeLater(final JCTree tree, - final List baseTypeAnnos, - final Env env, - final Symbol sym, - final DiagnosticPosition deferPos, - final PositionCreator creator) { - doAnnotateTypeLater(tree, baseTypeAnnos, env, sym, deferPos, - creator, true, false); - } - - /** - * Given a type tree representing an anonymous class' supertype, - * walk down it and handle any annotations we find. We also have - * a set of base-type annotations (which occurred in a declaration - * position in source), which must be type annotations on the base - * type. - * - * @param tree The type tree to scan. - * @param baseTypeAnnos The base-type annotations. - * @param env The environment. - * @param sym The symbol to which to attach any annotations we - * might find. - * @param deferPos The diagnostic position to use. - * @param creator The creator to use for making positions. - */ - public void annotateAnonClassDefLater(final JCTree tree, - final List baseTypeAnnos, - final Env env, - final Symbol sym, - final DiagnosticPosition deferPos, - final PositionCreator creator) { - doAnnotateTypeLater(tree, baseTypeAnnos, env, sym, deferPos, - creator, true, true); - } - - // The combined worker function for the annotateTypeLater family. - public void doAnnotateTypeLater(final JCTree tree, - final List baseTypeAnnos, - final Env env, - final Symbol sym, - final DiagnosticPosition deferPos, - final PositionCreator creator, - final boolean onlyTypeAnnos, - final boolean secondaryAttr) { + final DiagnosticPosition deferPos) { Assert.checkNonNull(sym); - Assert.checkNonNull(baseTypeAnnos); - Assert.checkNonNull(creator); - normal(new Annotate.Worker() { @Override public String toString() { @@ -1875,912 +1003,93 @@ } @Override public void run() { - if (!baseTypeAnnos.isEmpty()) { - sym.resetAnnotations(); // mark Annotations as incomplete for now - } - - tree.accept(typeAnnotator(baseTypeAnnos, sym, env, deferPos, - creator, onlyTypeAnnos, - secondaryAttr)); + tree.accept(new TypeAnnotate(env, sym, deferPos)); } }); } /** - * A client passed into various visitors that takes a type path as - * an argument and performs an action (typically creating a - * TypeAnnotationPosition and then creating a {@code Worker} and - * adding it to a queue. + * We need to use a TreeScanner, because it is not enough to visit the top-level + * annotations. We also need to visit type arguments, etc. */ - public abstract class PositionCreator { - public abstract TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex); - } + private class TypeAnnotate extends TreeScanner { + private final Env env; + private final Symbol sym; + private DiagnosticPosition deferPos; - // For when we don't have a creator. Throws an exception. - public final PositionCreator noCreator = - new PositionCreator() { - @Override - public String toString() { - return "Sentinel null position creator"; - } + public TypeAnnotate(final Env env, + final Symbol sym, + final DiagnosticPosition deferPos) { - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - throw new AssertionError("No annotation position creator registered"); - } - }; - - // For when we are creating annotations that will inevitably - // trigger errors. Creates null. - public final PositionCreator errorCreator = - new PositionCreator() { - @Override - public String toString() { - return "Position creator for annotations that represent errors"; + this.env = env; + this.sym = sym; + this.deferPos = deferPos; } @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return null; - } - }; - - // Create class extension positions - public final PositionCreator extendsCreator = - new PositionCreator() { - @Override - public String toString() { - return "Position creator for extends"; + public void visitAnnotatedType(final JCAnnotatedType tree) { + actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos); + super.visitAnnotatedType(tree); } @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.classExtends(path, lambda, -1); - } - }; - - // Create interface implementation positions - public PositionCreator implementsCreator(final int idx) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for implements, index " + idx; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.classExtends(path, lambda, idx, -1); - } - }; - } - - // Create method parameter positions - public final PositionCreator paramCreator(final int idx) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for parameter " + idx; + public void visitTypeParameter(final JCTypeParameter tree) { + actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos); + super.visitTypeParameter(tree); } @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.methodParameter(path, lambda, idx, -1); - } - }; - } - - // Create class type parameter positions - public PositionCreator typeParamCreator(final int idx) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for class type parameter " + idx; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.typeParameter(path, lambda, idx, -1); - } - }; - } - - public PositionCreator typeParamBoundCreator(final JCTypeParameter typaram, - final int param_idx, - final int bound_idx) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for class type parameter " + param_idx + - ", bound " + bound_idx; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - final int real_bound_idx = - typaram.bounds.head.type.isInterface() ? bound_idx + 1 : bound_idx; - return TypeAnnotationPosition - .typeParameterBound(path, lambda, param_idx, real_bound_idx, -1); - } - }; - } - - // Create field positions - public final PositionCreator fieldCreator = - new PositionCreator() { - @Override - public String toString() { - return "Position creator for field declaration"; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.field(path, lambda, -1); - } - }; - - // Create local variable positions - public PositionCreator localVarCreator(final int pos) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for local variable declaration at " + - pos; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.localVariable(path, lambda, pos); - } - }; - } - - // Create resource variable positions. - public PositionCreator resourceVarCreator(final int pos) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for resource variable declaration at " + - pos; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.resourceVariable(path, lambda, pos); - } - }; - } - - // Create exception parameter positions. - public PositionCreator exceptionParamCreator(final int pos) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for exception param declaration at " + - pos; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.exceptionParameter(path, lambda, - typeIndex, pos); - } - }; - } - - // Create constructor reference type argument positions. - public PositionCreator constructorRefTypeArgCreator(final int idx, - final int pos) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for constructor reference type argument " + idx + - " at " + pos; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition - .constructorRefTypeArg(path, lambda, idx, pos); - } - }; - } - - public PositionCreator methodInvokeTypeArgCreator(final int idx, - final int pos) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for method invoke type argument " + idx + - " at " + pos; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.methodInvocationTypeArg(path, lambda, idx, pos); - } - }; - } - - public PositionCreator methodTypeParamCreator(final int idx) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for method type parameter " + idx; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.methodTypeParameter(path, lambda, idx, -1); - } - }; - } - - public PositionCreator methodTypeParamBoundCreator(final JCTypeParameter typaram, - final int param_idx, - final int bound_idx) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for method type parameter " + param_idx + - " bound " + bound_idx; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - final int real_bound_idx = - typaram.bounds.head.type.isInterface() ? bound_idx + 1 : bound_idx; - return TypeAnnotationPosition - .methodTypeParameterBound(path, lambda, param_idx, real_bound_idx, -1); - } - }; - } - - public PositionCreator throwCreator(final int idx) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for throw, type index " + idx; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.methodThrows(path, lambda, idx, -1); - } - }; - } - - public final PositionCreator returnCreator = - new PositionCreator() { - @Override - public String toString() { - return "Position creator for method return type"; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.methodReturn(path, lambda, -1); - } - }; - - public PositionCreator receiverCreator = - new PositionCreator() { - @Override - public String toString() { - return "Position creator for method receiver parameter type"; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.methodReceiver(path, lambda, -1); - } - }; - - public PositionCreator methodRefCreator(final int pos) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for method reference at " + pos; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.methodRef(path, lambda, pos); - } - }; - } - - public PositionCreator methodRefTypeArgCreator(final int idx, - final int pos) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for method reference type argument " + idx + - " at " + pos; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.methodRefTypeArg(path, lambda, idx, pos); - } - }; - } - - public PositionCreator constructorRefCreator(final int pos) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for constructor reference at " + pos; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.constructorRef(path, lambda, pos); - } - }; - } - - public PositionCreator constructorInvokeTypeArgCreator(final int idx, - final int pos) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for constructor invoke type argument " + idx + - " at " + pos; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.constructorInvocationTypeArg(path, lambda, idx, pos); - } - }; - } - - public PositionCreator instanceOfCreator(final int pos) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for instanceof at " + pos; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.instanceOf(path, lambda, pos); - } - }; - } - - public PositionCreator newObjCreator(final int pos) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for new at " + pos; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.newObj(path, lambda, pos); - } - }; - } - - public PositionCreator castCreator(final int pos) { - return new PositionCreator() { - @Override - public String toString() { - return "Position creator for cast at " + pos; - } - - @Override - public TypeAnnotationPosition create(List path, - JCLambda lambda, - int typeIndex) { - return TypeAnnotationPosition.typeCast(path, lambda, typeIndex, pos); - } - }; - } - - public static List makeInners(Type type) { - return addInners(type, List.nil()); - } - - private static List addInners(Type type, - List typepath) { - Type encl = type.getEnclosingType(); - while (encl != null && encl.getKind() != TypeKind.NONE && - encl.getKind() != TypeKind.ERROR) { - typepath = typepath.append(TypePathEntry.INNER_TYPE); - encl = encl.getEnclosingType(); - } - return typepath; - } - - /** - * Set up the visitor to scan the type tree and handle any - * annotations we find. If we are in speculative attribution, we - * will not actually attach anything, we will just enter the - * annotations and run them through the pipeline to pick up any - * errors that might occur. - * - * @param baseTypeAnnos Annotations on the base type, which need - * to be classified if onlyTypeAnnos is false. - * @param sym The symbol to which to attach. - * @param env The environment. - * @param creator The position creator to use. - * @param onlyTypeAnnos Whether or not baseTypeAnnos can represent - * declaration annotations. - * @param secondaryAttr Whether or not we are creating secondary - * attributes (see enterTypeAnnotations). - */ - public TypeAnnotate typeAnnotator(final List baseTypeAnnos, - final Symbol sym, - final Env env, - final DiagnosticPosition deferPos, - final PositionCreator creator, - final boolean onlyTypeAnnos, - final boolean secondaryAttr) { - if (!env.info.isSpeculative) { - return new TypeAnnotate(baseTypeAnnos, sym, env, deferPos, creator, - declAnnotationsAttacher(sym), - typeAnnotationsAttacher(sym), - onlyTypeAnnos, secondaryAttr); - } else { - return new TypeAnnotate(baseTypeAnnos, sym, env, deferPos, creator, - null, null, onlyTypeAnnos, secondaryAttr); - } - } - - /** - * A visitor that scans a type tree and handles an annotations it finds. - * - */ - private class TypeAnnotate extends TreeScanner { - // The creator we use to create positions. - protected PositionCreator creator; - // The current type path - private List typepath = List.nil(); - // The current innermost lambda - private JCLambda currentLambda; - // The current type index, if we are looking at an - // intersection type. - private int type_index = 0; - // Whether or not we are looking at the innermost type. This - // gets used to figure out where to attach base type - // annotations. - private boolean innermost; - // The attachers and reporter we use. - private AttributeAttacher declAttacher; - private AttributeAttacher typeAttacher; - private Reporter reporter; - // The symbol to which we are attaching. - private final Symbol sym; - // The diagnostic position we use. - private final DiagnosticPosition deferPos; - // The environment - private final Env env; - private final List baseTypeAnnos; - // Whether or not baseTypeAnnos can be declaration - // annotations, or just strictly type annotations. - private final boolean onlyTypeAnnos; - // Whether or not we are creating secondary attributes (see - // enterTypeAnnotations). - private final boolean secondaryAttr; - - public TypeAnnotate(final List baseTypeAnnos, - final Symbol sym, - final Env env, - final DiagnosticPosition deferPos, - final PositionCreator creator, - final AttributeAttacher declAttacher, - final AttributeAttacher typeAttacher, - final boolean onlyTypeAnnos, - final boolean secondaryAttr) { - this.baseTypeAnnos = baseTypeAnnos; - this.sym = sym; - this.env = env; - this.deferPos = deferPos; - this.currentLambda = env.getLambda(); - this.creator = creator; - this.innermost = true; - this.declAttacher = declAttacher; - this.typeAttacher = typeAttacher; - this.reporter = null; - this.onlyTypeAnnos = onlyTypeAnnos; - this.secondaryAttr = secondaryAttr; + public void visitNewArray(final JCNewArray tree) { + actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos); + for (List dimAnnos : tree.dimAnnotations) + actualEnterTypeAnnotations(dimAnnos, env, sym, deferPos); + super.visitNewArray(tree); } - // Deal with the base-type annotations. This should only get - // called when we are at the inner-most type. - private void doBaseTypeAnnos() { - if (onlyTypeAnnos) { - // If the base type annotations can only be type - // annotations, then handle them as such. - doTypeAnnos(baseTypeAnnos, false); - } else if (!baseTypeAnnos.isEmpty()) { - // Otherwise, send them into the repeating annotations - // pipeline with a classifying attacher we build based - // on the current state. - final TypeAnnotationPosition tapos = - creator.create(typepath, currentLambda, type_index); - annotateNow(baseTypeAnnos, env, sym, deferPos, tapos, - classifyingAttacher(sym, declAttacher, - typeAttacher, reporter)); - // Also set up a validator. - validate(annotationValidator(baseTypeAnnos, env, sym)); - } + @Override + public void visitMethodDef(final JCMethodDecl tree) { + scan(tree.mods); + scan(tree.restype); + scan(tree.typarams); + scan(tree.recvparam); + scan(tree.params); + scan(tree.thrown); + scan(tree.defaultValue); + // Do not annotate the body, just the signature. + // scan(tree.body); } - // Deal with type annotations we found while scanning the tree. - private void doTypeAnnos(List annos, - boolean isTypeParameter) { - if (!annos.isEmpty()) { - // Grab the reporter and the type attacher (which, - // it's ok for either to be null), and combine them - // into a reporting attacher. - final AttributeAttacher attacher = - reportingTypeAnnotationsAttacher(typeAttacher, reporter); - // Create the position using the current type path and - // type index. - final TypeAnnotationPosition tapos = - creator.create(typepath, currentLambda, type_index); - // Send the annotations into the repeating annotations - // pipeline, and set up a validator. - actualEnterTypeAnnotations(annos, env, sym, deferPos, secondaryAttr, - tapos, attacher); - validate(typeAnnotationValidator(annos, env, isTypeParameter)); + @Override + public void visitVarDef(final JCVariableDecl tree) { + DiagnosticPosition prevPos = deferPos; + deferPos = tree.pos(); + try { + if (sym != null && sym.kind == Kinds.VAR) { + // Don't visit a parameter once when the sym is the method + // and once when the sym is the parameter. + scan(tree.mods); + scan(tree.vartype); + } + scan(tree.init); + } finally { + deferPos = prevPos; } } @Override - public void visitTypeIdent(final JCPrimitiveTypeTree tree) { - // This is one place that can represent the base type. - // But we need to make sure we're actually in the - // innermost type (ie not a type argument or something). - if (innermost) { - final AttributeAttacher oldTypeAttacher = typeAttacher; - // We want to update the Type to have annotations. - typeAttacher = typeUpdatingTypeAnnotationsAttacher(oldTypeAttacher, - tree); - // We can't possibly have any INNER_TYPE type path - // elements, because these are all primitives. - doBaseTypeAnnos(); - typeAttacher = oldTypeAttacher; - } - } - - @Override - public void visitIdent(final JCIdent tree) { - // This is one place that can represent the base type. - // But we need to make sure we're actually in the - // innermost type (ie not a type argument or something). - if (innermost) { - final AttributeAttacher oldTypeAttacher = typeAttacher; - // Set up an attacher that updates the Type, so we get - // the annotations. - typeAttacher = typeUpdatingTypeAnnotationsAttacher(oldTypeAttacher, - tree); - // Add any INNER_TYPE type path elements we might need. - if (tree.type != null) { - final List oldpath = typepath; - typepath = addInners(tree.type, typepath); - doBaseTypeAnnos(); - typepath = oldpath; - } else { - doBaseTypeAnnos(); - } - typeAttacher = oldTypeAttacher; - } - } - - @Override - public void visitAnnotatedType(JCAnnotatedType tree) { - // This is one place where we run into pure type - // annotations. - Assert.checkNonNull(tree.getUnderlyingType().type); - final boolean oldinnermost = innermost; - // Make sure we don't consider ourselves "innermost" when - // scanning the annotations. - innermost = false; - scan(tree.annotations); - innermost = oldinnermost; - scan(tree.underlyingType); - final List oldpath = typepath; - typepath = addInners(tree.getUnderlyingType().type, typepath); - doTypeAnnos(tree.annotations, false); - typepath = oldpath; - } - - @Override - public void visitTypeArray(JCArrayTypeTree tree) { - // This case is simple: just add an ARRAY to the type path. - final List oldpath = typepath; - typepath = typepath.append(TypePathEntry.ARRAY); - super.visitTypeArray(tree); - typepath = oldpath; - } - - @Override - public void visitTypeApply(JCTypeApply tree) { - // Handle type arguments - Assert.checkNonNull(tree.getType().type); - final List oldpath = typepath; - // First, look at the base type. - scan(tree.clazz); - - // Add any INNER_TYPE path elements we need first - if (tree.getType() != null && tree.getType().type != null) { - typepath = addInners(tree.getType().type, typepath); - } - // Make sure we're not considering ourselves innermost - // when looking at type arguments. - final boolean oldinnermost = innermost; - innermost = false; - // For each type argument, add a TYPE_ARGUMENT path - // element for the right index. - int i = 0; - for (List l = tree.arguments; l.nonEmpty(); - l = l.tail, i++) { - final JCExpression arg = l.head; - final List noargpath = typepath; - typepath = typepath.append(new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, i)); - scan(arg); - typepath = noargpath; - } - typepath = oldpath; - innermost = oldinnermost; - } - - @Override - public void visitNewArray(JCNewArray tree) { - // We can also run into type annotations here, on dimAnnos. - final List oldpath = typepath; - final PositionCreator oldcreator = creator; - creator = newObjCreator(tree.pos); - doTypeAnnos(tree.annotations, false); - - // Go through the dimensions, set up the type path, and - // handle any annetations we find. - for (int i = 0; i < tree.dimAnnotations.size(); i++) { - final List dimAnnos = tree.dimAnnotations.get(i); - doTypeAnnos(dimAnnos, false); - // This is right. As per the type annotations spec, - // the first array dimension has no arrays in the type - // path, the second has one, and so on, and the - // element type has n for n dimensions. - typepath = typepath.append(TypePathEntry.ARRAY); - } - - // The element type is sometimes null, in the case of - // array literals. - scan(tree.elemtype); - typepath = oldpath; - creator = oldcreator; - } - - @Override - public void visitWildcard(JCWildcard tree) { - // Simple: add a WILDCARD type path element and continue. - final List oldpath = typepath; - typepath = typepath.append(TypePathEntry.WILDCARD); - super.visitWildcard(tree); - typepath = oldpath; - } - - @Override - public void visitTypeParameter(JCTypeParameter tree) { - // This is another place where we can run into pure type - // annotations. - scan(tree.annotations); - Assert.checkNonNull(tree.type); - doTypeAnnos(tree.annotations, true); - } - - @Override - public void visitLambda(JCLambda tree) { - // If we run into a lambda, set the current lambda to it. - final JCLambda oldLambda = currentLambda; - currentLambda = tree; - scan(tree.body); - scan(tree.params); - currentLambda = oldLambda; - } - - @Override - public void visitTypeIntersection(JCTypeIntersection tree) { - final boolean oldinnermost = innermost; - // Run through the options, and update the type_index - // accordingly. - for (List l = tree.bounds; l.nonEmpty(); - l = l.tail, type_index++) { - scan(l.head); - // Set innermost to false after the first element - innermost = false; - } - innermost = oldinnermost; - } - - @Override - public void visitTypeUnion(JCTypeUnion tree) { - final boolean oldinnermost = innermost; - // Run through the options, and update the type_index - // accordingly. - for (List l = tree.alternatives; l.nonEmpty(); - l = l.tail, type_index++) { - scan(l.head); - // Set innermost to false after the first element - innermost = false; - } - innermost = oldinnermost; - } - - @Override - public void visitSelect(JCFieldAccess tree) { - // In this case, we need to possibly set up an - // illegalScopingReporter, if the selected type cannot be - // annotated. - Symbol sym = tree.sym; - final AttributeAttacher oldTypeAttacher = typeAttacher; - final Reporter oldReporter = reporter; - // If we're selecting from an interface or a static class, - // set up attachers that will only attach declaration - // annotations and will report type annotations as errors. - Type selectedTy = tree.selected.type; - if ((sym != null && (sym.isStatic() || sym.isInterface() || - selectedTy.hasTag(TypeTag.PACKAGE))) || - tree.name == names._class) { - typeAttacher = null; - reporter = illegalScopingReporter(tree.pos); - } - super.visitSelect(tree); - typeAttacher = oldTypeAttacher; - reporter = oldReporter; - } - - // These methods stop the visitor from continuing on when it - // sees a definition. - @Override - public void visitVarDef(final JCVariableDecl tree) { - } - - @Override public void visitClassDef(JCClassDecl tree) { + // We can only hit a classdef if it is declared within + // a method. Ignore it - the class will be visited + // separately later. } @Override public void visitNewClass(JCNewClass tree) { - + if (tree.def == null) { + // For an anonymous class instantiation the class + // will be visited separately. + super.visitNewClass(tree); } } - - // A derived TypeAnnotate visitor that also scans expressions - // within Deferred attribution. - private class TypeAnnotateExpr extends TypeAnnotate { - // This constructor creates an instance suitable for deferred - // attribution. - public TypeAnnotateExpr(final Symbol sym, - final Env env, - final DiagnosticPosition deferPos, - final PositionCreator creator) { - super(List.nil(), sym, env, deferPos, - creator, null, null, false, false); - } - - @Override - public void visitTypeCast(final JCTypeCast tree) { - final PositionCreator oldcreator = creator; - creator = castCreator(tree.pos); - super.visitTypeCast(tree); - creator = oldcreator; - } - - @Override - public void visitTypeTest(JCInstanceOf tree) { - final PositionCreator oldcreator = creator; - creator = instanceOfCreator(tree.pos); - super.visitTypeTest(tree); - creator = oldcreator; - } - - @Override - public void visitReference(JCMemberReference that) { - final boolean isConstructor = that.getName() == names.init; - final PositionCreator oldcreator = creator; - creator = isConstructor ? constructorRefCreator(that.pos) : - methodRefCreator(that.pos); - scan(that.expr); - - if (null != that.typeargs) { - int i = 0; - for (List l = that.typeargs; - l.nonEmpty(); l = l.tail, i++) { - final Annotate.PositionCreator typeArgCreator = - isConstructor ? constructorRefTypeArgCreator(i, that.pos) : - methodRefTypeArgCreator(i, that.pos); - final JCExpression arg = l.head; - scan(that.expr); - } - } - - creator = oldcreator; - } - - @Override - public void visitNewClass(JCNewClass tree) { - // This will be visited by Attr later, so don't do - // anything. - } - } - - /** - * Set up a visitor to scan an expression and handle any type - * annotations it finds, within a deferred attribution context. - */ - public void typeAnnotateExprLater(final JCTree tree, - final Env env, - final Symbol sym, - final DiagnosticPosition deferPos, - final PositionCreator creator) { - Assert.checkNonNull(sym); - Assert.checkNonNull(creator); - - normal(new Annotate.Worker() { - @Override - public String toString() { - return "type annotate " + tree + " onto " + sym + " in " + sym.owner; - } - @Override - public void run() { - tree.accept(new TypeAnnotateExpr(sym, env, deferPos, creator)); - } - }); } } diff -r c32c9586ea94 -r aa84b6606229 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Mon Sep 08 13:11:28 2014 +0200 @@ -94,6 +94,7 @@ final Types types; final JCDiagnostic.Factory diags; final Annotate annotate; + final TypeAnnotations typeAnnotations; final DeferredLintHandler deferredLintHandler; final TypeEnvs typeEnvs; final Dependencies dependencies; @@ -124,6 +125,7 @@ types = Types.instance(context); diags = JCDiagnostic.Factory.instance(context); annotate = Annotate.instance(context); + typeAnnotations = TypeAnnotations.instance(context); deferredLintHandler = DeferredLintHandler.instance(context); typeEnvs = TypeEnvs.instance(context); dependencies = Dependencies.instance(context); @@ -372,7 +374,8 @@ public Type attribImportQualifier(JCImport tree, Env env) { // Attribute qualifying package or class. JCFieldAccess s = (JCFieldAccess)tree.qualid; - return attribTree(s.selected, env, + return attribTree(s.selected, + env, new ResultInfo(tree.staticImport ? TYP : (TYP | PCK), Type.noType)); } @@ -572,8 +575,7 @@ /** Derived visitor method: attribute an expression tree. */ public Type attribExpr(JCTree tree, Env env, Type pt) { - return attribTree(tree, env, - new ResultInfo(VAL, !pt.hasTag(ERROR) ? pt : Type.noType)); + return attribTree(tree, env, new ResultInfo(VAL, !pt.hasTag(ERROR) ? pt : Type.noType)); } /** Derived visitor method: attribute an expression tree with @@ -585,7 +587,6 @@ /** Derived visitor method: attribute a type tree. */ - public Type attribType(JCTree tree, Env env) { Type result = attribType(tree, env, Type.noType); return result; @@ -600,7 +601,6 @@ /** Derived visitor method: attribute a statement or definition tree. */ - public Type attribStat(JCTree tree, Env env) { return attribTree(tree, env, statInfo); } @@ -669,8 +669,7 @@ a.tsym.flags_field |= UNATTRIBUTED; a.bound = Type.noType; if (!tvar.bounds.isEmpty()) { - List bounds = - List.of(attribType(tvar.bounds.head, env)); + List bounds = List.of(attribType(tvar.bounds.head, env)); for (JCExpression bound : tvar.bounds.tail) bounds = bounds.prepend(attribType(bound, env)); types.setBounds(a, bounds.reverse()); @@ -705,7 +704,7 @@ * @param type The expected type, or null * @see VarSymbol#setLazyConstValue */ - public Object attribLazyConstantValue(final Env env, + public Object attribLazyConstantValue(Env env, JCVariableDecl variable, Type type) { @@ -824,7 +823,6 @@ c.flags_field |= NOOUTERTHIS; } attribClass(tree.pos(), c); - result = tree.type = c.type; } } @@ -867,9 +865,9 @@ ClassSymbol owner = env.enclClass.sym; if ((owner.flags() & ANNOTATION) != 0 && - tree.params.nonEmpty()) + tree.params.nonEmpty()) log.error(tree.params.head.pos(), - "intf.annotation.members.cant.have.params"); + "intf.annotation.members.cant.have.params"); // Attribute all value parameters. for (List l = tree.params; l.nonEmpty(); l = l.tail) { @@ -943,91 +941,56 @@ if (tree.name == names.init && owner.type != syms.objectType) { JCBlock body = tree.body; if (body.stats.isEmpty() || - !TreeInfo.isSelfCall(body.stats.head)) { + !TreeInfo.isSelfCall(body.stats.head)) { body.stats = body.stats. - prepend(memberEnter.SuperCall(make.at(body.pos), - List.nil(), - List.nil(), - false)); + prepend(memberEnter.SuperCall(make.at(body.pos), + List.nil(), + List.nil(), + false)); } else if ((env.enclClass.sym.flags() & ENUM) != 0 && - (tree.mods.flags & GENERATEDCONSTR) == 0 && - TreeInfo.isSuperCall(body.stats.head)) { + (tree.mods.flags & GENERATEDCONSTR) == 0 && + TreeInfo.isSuperCall(body.stats.head)) { // enum constructors are not allowed to call super // directly, so make sure there aren't any super calls // in enum constructors, except in the compiler // generated one. log.error(tree.body.stats.head.pos(), - "call.to.super.not.allowed.in.enum.ctor", - env.enclClass.sym); + "call.to.super.not.allowed.in.enum.ctor", + env.enclClass.sym); } } + // Attribute all type annotations in the body + annotate.annotateTypeLater(tree.body, localEnv, m, null); + annotate.flush(); + // Attribute method body. attribStat(tree.body, localEnv); } localEnv.info.scope.leave(); result = tree.type = m.type; - } - finally { + } finally { chk.setLint(prevLint); chk.setMethod(prevMethod); } } - public Annotate.PositionCreator getVarCreator(final JCVariableDecl tree) { - // Form the enclosing tree node, figure out what kind - // of definition we are looking at. - switch(env.tree.getTag()) { - case TRY: - // If it's a try, then we have a resource variable - return annotate.resourceVarCreator(tree.pos); - case CATCH: - // If it's a catch, then we have an exception parameter - return annotate.exceptionParamCreator(tree.pos); - case LAMBDA: { - // If it's a lambda, then we could have a local - // variable or a parameter. - final JCLambda lambda = (JCLambda) env.tree; - // We have to figure out what the index of the - // parameter is, and unfortunately, the visitor - // and tree APIs don't help us much here. If we - // don't find the declaration in the parameter - // list, then it must be a local variable. - // - // This could easily be replaced by an index - // parameter, which is -1 for non-indexed - // definitions. - int index = -1; - int i = 0; - for (List l = lambda.params; - l.nonEmpty(); l = l.tail, i++) { - if (l.head == tree) { - index = i; - break; - } - } - if (index == -1) { - return annotate.localVarCreator(tree.pos); - } else { - return annotate.paramCreator(index); - } - } - default: - // The default case is to treat any declaration as a local - // variable. - return annotate.localVarCreator(tree.pos); - } - } - - public void visitVarDef(final JCVariableDecl tree) { + public void visitVarDef(JCVariableDecl tree) { // Local variables have not been entered yet, so we need to do it now: if (env.info.scope.owner.kind == MTH) { if (tree.sym != null) { // parameters have already been entered env.info.scope.enter(tree.sym); } else { - memberEnter.memberEnter(tree, env, getVarCreator(tree)); + memberEnter.memberEnter(tree, env); + annotate.flush(); + } + } else { + if (tree.init != null) { + // Field initializer expression need to be entered. + annotate.annotateTypeLater(tree.init, env, tree.sym, tree.pos()); + annotate.flush(); } } @@ -1086,6 +1049,9 @@ env.dup(tree, env.info.dup(env.info.scope.dupUnshared(fakeOwner))); if ((tree.flags & STATIC) != 0) localEnv.info.staticLevel++; + // Attribute all type annotations in the block + annotate.annotateTypeLater(tree, localEnv, localEnv.info.scope.owner, null); + annotate.flush(); attribStats(tree.stats, localEnv); { @@ -1449,21 +1415,17 @@ isBooleanOrNumeric(env, condTree.falsepart); case APPLY: JCMethodInvocation speculativeMethodTree = - (JCMethodInvocation)deferredAttr.attribSpeculative(tree, env, unknownExprInfo, - annotate.noCreator); + (JCMethodInvocation)deferredAttr.attribSpeculative(tree, env, unknownExprInfo); Type owntype = TreeInfo.symbol(speculativeMethodTree.meth).type.getReturnType(); return types.unboxedTypeOrType(owntype).isPrimitive(); case NEWCLASS: JCExpression className = removeClassParams.translate(((JCNewClass)tree).clazz); JCExpression speculativeNewClassTree = - (JCExpression)deferredAttr.attribSpeculative(className, - env, - unknownTypeInfo, - annotate.newObjCreator(tree.pos)); + (JCExpression)deferredAttr.attribSpeculative(className, env, unknownTypeInfo); return types.unboxedTypeOrType(speculativeNewClassTree.type).isPrimitive(); default: - Type speculativeType = deferredAttr.attribSpeculative(tree, env, unknownExprInfo, annotate.noCreator).type; + Type speculativeType = deferredAttr.attribSpeculative(tree, env, unknownExprInfo).type; speculativeType = types.unboxedTypeOrType(speculativeType); return speculativeType.isPrimitive(); } @@ -1724,28 +1686,7 @@ // Attribute arguments, yielding list of argument types. attribArgs(tree.args, localEnv, argtypesBuf); argtypes = argtypesBuf.toList(); - - // Attribute and annotate the type arguments - ListBuffer typeargtypesbuf = new ListBuffer<>(); - int i = 0; - - for (List l = tree.typeargs; - l.nonEmpty(); l = l.tail, i++) { - final JCExpression arg = l.head; - try { - annotate.enterStart(); - typeargtypesbuf.append(attribType(arg, localEnv)); - annotate.annotateTypeLater(arg, localEnv, - localEnv.info.scope.owner, - tree.pos(), - annotate.constructorInvokeTypeArgCreator(i, tree.pos)); - } finally { - annotate.enterDone(); - } - } - - typeargtypes = - chk.checkRefTypes(tree.typeargs, typeargtypesbuf.toList()); + typeargtypes = attribTypes(tree.typeargs, localEnv); // Variable `site' points to the class in which the called // constructor is defined. @@ -1818,27 +1759,7 @@ // Attribute the arguments, yielding list of argument types, ... int kind = attribArgs(tree.args, localEnv, argtypesBuf); argtypes = argtypesBuf.toList(); - - // Attribute and annotate the type arguments - ListBuffer typeargtypesbuf = new ListBuffer<>(); - int i = 0; - - for (List l = tree.typeargs; - l.nonEmpty(); l = l.tail, i++) { - final JCExpression arg = l.head; - try { - annotate.enterStart(); - typeargtypesbuf.append(attribType(arg, localEnv)); - annotate.annotateTypeLater(arg, localEnv, - localEnv.info.scope.owner, - tree.pos(), - annotate.methodInvokeTypeArgCreator(i, tree.pos)); - } finally { - annotate.enterDone(); - } - } - - typeargtypes = typeargtypesbuf.toList(); + typeargtypes = attribAnyTypes(tree.typeargs, localEnv); // ... and attribute the method using as a prototype a methodtype // whose formal argument types is exactly the list of actual @@ -1863,7 +1784,6 @@ // current context. Also, capture the return type result = check(tree, capture(restype), VAL, resultInfo); } - chk.validate(tree.typeargs, localEnv); } //where @@ -1935,12 +1855,14 @@ annoclazzid = (JCAnnotatedType) clazzid; clazzid = annoclazzid.underlyingType; } - } else if (clazz.hasTag(ANNOTATED_TYPE)) { + } else { + if (clazz.hasTag(ANNOTATED_TYPE)) { annoclazzid = (JCAnnotatedType) clazz; clazzid = annoclazzid.underlyingType; } else { clazzid = clazz; } + } JCExpression clazzid1 = clazzid; // The same in fully qualified form @@ -1962,12 +1884,11 @@ EndPosTable endPosTable = this.env.toplevel.endPositions; endPosTable.storeEnd(clazzid1, tree.getEndPosition(endPosTable)); - if (annoclazzid != null) { - JCAnnotatedType annoType = annoclazzid; - List annos = annoclazzid.annotations; - - if (clazz.hasTag(TYPEAPPLY)) { - + if (clazz.hasTag(ANNOTATED_TYPE)) { + JCAnnotatedType annoType = (JCAnnotatedType) clazz; + List annos = annoType.annotations; + + if (annoType.underlyingType.hasTag(TYPEAPPLY)) { clazzid1 = make.at(tree.pos). TypeApply(clazzid1, ((JCTypeApply) clazz).arguments); @@ -1984,32 +1905,12 @@ clazz = clazzid1; } - Type clazztype; - - try { - annotate.enterStart(); // Attribute clazz expression and store // symbol + type back into the attributed tree. - clazztype = TreeInfo.isEnumInit(env.tree) ? + Type clazztype = TreeInfo.isEnumInit(env.tree) ? attribIdentAsEnumType(env, (JCIdent)clazz) : attribType(clazz, env); - if (cdef != null) { - // If we are looking at an anonymous class creation, then - // we are not allowed to have declaration annotations on - // the base type. - annotate.annotateStrictTypeLater(clazz, cdef.mods.annotations, localEnv, - env.info.scope.owner, tree.pos(), - annotate.newObjCreator(tree.pos)); - } else { - // Otherwise, we are. - annotate.annotateTypeLater(clazz, localEnv, env.info.scope.owner, - tree.pos(), annotate.newObjCreator(tree.pos)); - } - } finally { - annotate.enterDone(); - } - clazztype = chk.checkDiamond(tree, clazztype); chk.validate(clazz, localEnv); if (tree.encl != null) { @@ -2038,29 +1939,7 @@ ListBuffer argtypesBuf = new ListBuffer<>(); int pkind = attribArgs(tree.args, localEnv, argtypesBuf); List argtypes = argtypesBuf.toList(); - List typeargtypes; - - // Attribute and annotate the type arguments - ListBuffer typeargtypesbuf = new ListBuffer<>(); - int i = 0; - - for (List l = tree.typeargs; - l.nonEmpty(); l = l.tail, i++) { - final JCExpression arg = l.head; - try { - annotate.enterStart(); - typeargtypesbuf.append(attribType(arg, localEnv)); - annotate.annotateTypeLater(arg, localEnv, - localEnv.info.scope.owner, - tree.pos(), - annotate.constructorInvokeTypeArgCreator(i, tree.pos)); - } finally { - annotate.enterDone(); - } - } - - typeargtypes = - chk.checkRefTypes(tree.typeargs, typeargtypesbuf.toList()); + List typeargtypes = attribTypes(tree.typeargs, localEnv); // If we have made no mistakes in the class type... if (clazztype.hasTag(CLASS)) { @@ -2242,9 +2121,7 @@ ta.arguments = List.nil(); ResultInfo findDiamondResult = new ResultInfo(VAL, resultInfo.checkContext.inferenceContext().free(resultInfo.pt) ? Type.noType : pt()); - Type inferred = deferredAttr.attribSpeculative(tree, env, - findDiamondResult, - annotate.newObjCreator(tree.pos)).type; + Type inferred = deferredAttr.attribSpeculative(tree, env, findDiamondResult).type; Type polyPt = allowPoly ? syms.objectType : clazztype; @@ -2306,20 +2183,8 @@ Type owntype = types.createErrorType(tree.type); Env localEnv = env.dup(tree); Type elemtype; - - for(List dim : tree.dimAnnotations) { - this.attribAnnotationTypes(dim, localEnv); - } - if (tree.elemtype != null) { - try { - annotate.enterStart(); elemtype = attribType(tree.elemtype, localEnv); - annotate.annotateTypeLater(tree, env, env.info.scope.owner, tree.pos(), - annotate.newObjCreator(tree.pos)); - } finally { - annotate.enterDone(); - } chk.validate(tree.elemtype, localEnv); owntype = elemtype; for (List l = tree.dims; l.nonEmpty(); l = l.tail) { @@ -2340,7 +2205,6 @@ elemtype = types.createErrorType(pt()); } } - if (tree.elems != null) { attribExprs(tree.elems, localEnv, elemtype); owntype = new ArrayType(elemtype, syms.arrayClass, @@ -2737,8 +2601,6 @@ @Override public void visitReference(final JCMemberReference that) { - final boolean isConstructor = that.getName() == names.init; - if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) { if (pt().hasTag(NONE)) { //method reference only allowed in assignment or method invocation/cast context @@ -2749,20 +2611,9 @@ } final Env localEnv = env.dup(that); try { - Type exprType; - try { - annotate.enterStart(); //attribute member reference qualifier - if this is a constructor //reference, the expected kind must be a type - exprType = attribTree(that.expr, env, memberReferenceQualifierResult(that)); - final Annotate.PositionCreator creator = - isConstructor ? annotate.constructorRefCreator(that.pos) : - annotate.methodRefCreator(that.pos); - annotate.annotateTypeLater(that.expr, localEnv, env.info.scope.owner, - that.pos(), creator); - } finally { - annotate.enterDone(); - } + Type exprType = attribTree(that.expr, env, memberReferenceQualifierResult(that)); if (that.getMode() == JCMemberReference.ReferenceMode.NEW) { exprType = chk.checkConstructorRefType(that.expr, exprType); @@ -2792,24 +2643,7 @@ //attrib type-arguments List typeargtypes = List.nil(); if (that.typeargs != null) { - try { - annotate.enterStart(); typeargtypes = attribTypes(that.typeargs, localEnv); - - // Annotate type arguments - int i = 0; - for (List l = that.typeargs; - l.nonEmpty(); l = l.tail, i++) { - final Annotate.PositionCreator typeArgCreator = - isConstructor ? annotate.constructorRefTypeArgCreator(i, that.pos) : - annotate.methodRefTypeArgCreator(i, that.pos); - final JCExpression arg = l.head; - annotate.annotateTypeLater(arg, env, env.info.scope.owner, - that.pos(), typeArgCreator); - } - } finally { - annotate.enterDone(); - } } Type desc; @@ -3192,15 +3026,7 @@ } public void visitTypeCast(final JCTypeCast tree) { - Type clazztype; - try { - annotate.enterStart(); - clazztype = attribType(tree.clazz, env); - annotate.annotateTypeLater(tree.clazz, env, env.info.scope.owner, - tree.pos(), annotate.castCreator(tree.pos)); - } finally { - annotate.enterDone(); - } + Type clazztype = attribType(tree.clazz, env); chk.validate(tree.clazz, env, false); //a fresh environment is required for 292 inference to work properly --- //see Infer.instantiatePolymorphicSignatureInstance() @@ -3233,16 +3059,7 @@ public void visitTypeTest(JCInstanceOf tree) { Type exprtype = chk.checkNullOrRefType( tree.expr.pos(), attribExpr(tree.expr, env)); - Type clazztype; - try { - annotate.enterStart(); - clazztype = attribType(tree.clazz, env); - annotate.annotateTypeLater(tree.clazz, env, env.info.scope.owner, tree.pos(), - annotate.instanceOfCreator(tree.pos)); - } finally { - annotate.enterDone(); - } - + Type clazztype = attribType(tree.clazz, env); if (!clazztype.hasTag(TYPEVAR)) { clazztype = chk.checkClassOrArrayType(tree.clazz.pos(), clazztype); } @@ -3371,12 +3188,9 @@ if ((pkind() & (PCK | TYP)) == 0) site = capture(site); // Capture field access + // don't allow T.class T[].class, etc if (skind == TYP) { - // If the qualifier is a type, annotate it - annotate.annotateTypeLater(tree, env, env.info.scope.owner, - tree.pos(), annotate.errorCreator); Type elt = site; - // don't allow T.class T[].class, etc while (elt.hasTag(ARRAY)) elt = ((ArrayType)elt).elemtype; if (elt.hasTag(TYPEVAR)) { @@ -4224,13 +4038,8 @@ Assert.error("should be handled in Annotate"); } - /* This needs to be removed or otherwise changed, as it implicitly - * relies on the annotated types having previously been visited by - * Annotate.TypeAnnotate. - */ public void visitAnnotatedType(JCAnnotatedType tree) { - Type underlyingType = attribTree(tree.getUnderlyingType(), env, - resultInfo); + Type underlyingType = attribType(tree.getUnderlyingType(), env); this.attribAnnotationTypes(tree.annotations, env); annotateType(tree, tree.annotations); result = tree.type = underlyingType; @@ -4249,10 +4058,8 @@ public void run() { List compounds = fromAnnotations(annotations); Assert.check(annotations.size() == compounds.size()); - if (!tree.type.hasTag(TypeTag.PACKAGE)) { tree.type = tree.type.annotatedType(compounds); } - } }); } @@ -4503,6 +4310,13 @@ checkForSerial(c)) { checkSerialVersionUID(tree, c); } + if (allowTypeAnnos) { + // Correctly organize the postions of the type annotations + typeAnnotations.organizeTypeAnnotationsBodies(tree); + + // Check type annotations applicability rules + validateTypeAnnotations(tree, false); + } } // where boolean checkForSerial(ClassSymbol c) { @@ -4581,6 +4395,233 @@ return types.capture(type); } + public void validateTypeAnnotations(JCTree tree, boolean sigOnly) { + tree.accept(new TypeAnnotationsValidator(sigOnly)); + } + //where + private final class TypeAnnotationsValidator extends TreeScanner { + + private final boolean sigOnly; + public TypeAnnotationsValidator(boolean sigOnly) { + this.sigOnly = sigOnly; + } + + public void visitAnnotation(JCAnnotation tree) { + chk.validateTypeAnnotation(tree, false); + super.visitAnnotation(tree); + } + public void visitAnnotatedType(JCAnnotatedType tree) { + if (!tree.underlyingType.type.isErroneous()) { + super.visitAnnotatedType(tree); + } + } + public void visitTypeParameter(JCTypeParameter tree) { + chk.validateTypeAnnotations(tree.annotations, true); + scan(tree.bounds); + // Don't call super. + // This is needed because above we call validateTypeAnnotation with + // false, which would forbid annotations on type parameters. + // super.visitTypeParameter(tree); + } + public void visitMethodDef(JCMethodDecl tree) { + if (tree.recvparam != null && + !tree.recvparam.vartype.type.isErroneous()) { + checkForDeclarationAnnotations(tree.recvparam.mods.annotations, + tree.recvparam.vartype.type.tsym); + } + if (tree.restype != null && tree.restype.type != null) { + validateAnnotatedType(tree.restype, tree.restype.type); + } + if (sigOnly) { + scan(tree.mods); + scan(tree.restype); + scan(tree.typarams); + scan(tree.recvparam); + scan(tree.params); + scan(tree.thrown); + } else { + scan(tree.defaultValue); + scan(tree.body); + } + } + public void visitVarDef(final JCVariableDecl tree) { + //System.err.println("validateTypeAnnotations.visitVarDef " + tree); + if (tree.sym != null && tree.sym.type != null) + validateAnnotatedType(tree.vartype, tree.sym.type); + scan(tree.mods); + scan(tree.vartype); + if (!sigOnly) { + scan(tree.init); + } + } + public void visitTypeCast(JCTypeCast tree) { + if (tree.clazz != null && tree.clazz.type != null) + validateAnnotatedType(tree.clazz, tree.clazz.type); + super.visitTypeCast(tree); + } + public void visitTypeTest(JCInstanceOf tree) { + if (tree.clazz != null && tree.clazz.type != null) + validateAnnotatedType(tree.clazz, tree.clazz.type); + super.visitTypeTest(tree); + } + public void visitNewClass(JCNewClass tree) { + if (tree.clazz.hasTag(ANNOTATED_TYPE)) { + checkForDeclarationAnnotations(((JCAnnotatedType) tree.clazz).annotations, + tree.clazz.type.tsym); + } + if (tree.def != null) { + checkForDeclarationAnnotations(tree.def.mods.annotations, tree.clazz.type.tsym); + } + if (tree.clazz.type != null) { + validateAnnotatedType(tree.clazz, tree.clazz.type); + } + super.visitNewClass(tree); + } + public void visitNewArray(JCNewArray tree) { + if (tree.elemtype != null && tree.elemtype.type != null) { + if (tree.elemtype.hasTag(ANNOTATED_TYPE)) { + checkForDeclarationAnnotations(((JCAnnotatedType) tree.elemtype).annotations, + tree.elemtype.type.tsym); + } + validateAnnotatedType(tree.elemtype, tree.elemtype.type); + } + super.visitNewArray(tree); + } + public void visitClassDef(JCClassDecl tree) { + //System.err.println("validateTypeAnnotations.visitClassDef " + tree); + if (sigOnly) { + scan(tree.mods); + scan(tree.typarams); + scan(tree.extending); + scan(tree.implementing); + } + for (JCTree member : tree.defs) { + if (member.hasTag(Tag.CLASSDEF)) { + continue; + } + scan(member); + } + } + public void visitBlock(JCBlock tree) { + if (!sigOnly) { + scan(tree.stats); + } + } + + /* I would want to model this after + * com.sun.tools.javac.comp.Check.Validator.visitSelectInternal(JCFieldAccess) + * and override visitSelect and visitTypeApply. + * However, we only set the annotated type in the top-level type + * of the symbol. + * Therefore, we need to override each individual location where a type + * can occur. + */ + private void validateAnnotatedType(final JCTree errtree, final Type type) { + //System.err.println("Attr.validateAnnotatedType: " + errtree + " type: " + type); + + if (type.isPrimitiveOrVoid()) { + return; + } + + JCTree enclTr = errtree; + Type enclTy = type; + + boolean repeat = true; + while (repeat) { + if (enclTr.hasTag(TYPEAPPLY)) { + List tyargs = enclTy.getTypeArguments(); + List trargs = ((JCTypeApply)enclTr).getTypeArguments(); + if (trargs.length() > 0) { + // Nothing to do for diamonds + if (tyargs.length() == trargs.length()) { + for (int i = 0; i < tyargs.length(); ++i) { + validateAnnotatedType(trargs.get(i), tyargs.get(i)); + } + } + // If the lengths don't match, it's either a diamond + // or some nested type that redundantly provides + // type arguments in the tree. + } + + // Look at the clazz part of a generic type + enclTr = ((JCTree.JCTypeApply)enclTr).clazz; + } + + if (enclTr.hasTag(SELECT)) { + enclTr = ((JCTree.JCFieldAccess)enclTr).getExpression(); + if (enclTy != null && + !enclTy.hasTag(NONE)) { + enclTy = enclTy.getEnclosingType(); + } + } else if (enclTr.hasTag(ANNOTATED_TYPE)) { + JCAnnotatedType at = (JCTree.JCAnnotatedType) enclTr; + if (enclTy == null || enclTy.hasTag(NONE)) { + if (at.getAnnotations().size() == 1) { + log.error(at.underlyingType.pos(), "cant.type.annotate.scoping.1", at.getAnnotations().head.attribute); + } else { + ListBuffer comps = new ListBuffer<>(); + for (JCAnnotation an : at.getAnnotations()) { + comps.add(an.attribute); + } + log.error(at.underlyingType.pos(), "cant.type.annotate.scoping", comps.toList()); + } + repeat = false; + } + enclTr = at.underlyingType; + // enclTy doesn't need to be changed + } else if (enclTr.hasTag(IDENT)) { + repeat = false; + } else if (enclTr.hasTag(JCTree.Tag.WILDCARD)) { + JCWildcard wc = (JCWildcard) enclTr; + if (wc.getKind() == JCTree.Kind.EXTENDS_WILDCARD) { + validateAnnotatedType(wc.getBound(), ((WildcardType)enclTy).getExtendsBound()); + } else if (wc.getKind() == JCTree.Kind.SUPER_WILDCARD) { + validateAnnotatedType(wc.getBound(), ((WildcardType)enclTy).getSuperBound()); + } else { + // Nothing to do for UNBOUND + } + repeat = false; + } else if (enclTr.hasTag(TYPEARRAY)) { + JCArrayTypeTree art = (JCArrayTypeTree) enclTr; + validateAnnotatedType(art.getType(), ((ArrayType)enclTy).getComponentType()); + repeat = false; + } else if (enclTr.hasTag(TYPEUNION)) { + JCTypeUnion ut = (JCTypeUnion) enclTr; + for (JCTree t : ut.getTypeAlternatives()) { + validateAnnotatedType(t, t.type); + } + repeat = false; + } else if (enclTr.hasTag(TYPEINTERSECTION)) { + JCTypeIntersection it = (JCTypeIntersection) enclTr; + for (JCTree t : it.getBounds()) { + validateAnnotatedType(t, t.type); + } + repeat = false; + } else if (enclTr.getKind() == JCTree.Kind.PRIMITIVE_TYPE || + enclTr.getKind() == JCTree.Kind.ERRONEOUS) { + repeat = false; + } else { + Assert.error("Unexpected tree: " + enclTr + " with kind: " + enclTr.getKind() + + " within: "+ errtree + " with kind: " + errtree.getKind()); + } + } + } + + private void checkForDeclarationAnnotations(List annotations, + Symbol sym) { + // Ensure that no declaration annotations are present. + // Note that a tree type might be an AnnotatedType with + // empty annotations, if only declaration annotations were given. + // This method will raise an error for such a type. + for (JCAnnotation ai : annotations) { + if (!ai.type.isErroneous() && + typeAnnotations.annotationType(ai.attribute, sym) == TypeAnnotations.AnnotationType.DECLARATION) { + log.error(ai.pos(), "annotation.type.not.applicable"); + } + } + } + } + // /** diff -r c32c9586ea94 -r aa84b6606229 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java Mon Sep 08 13:11:28 2014 +0200 @@ -59,11 +59,6 @@ */ boolean isSerializable = false; - /** - * Are we doing speculative attribution? - */ - boolean isSpeculative = false; - /** Are arguments to current function applications boxed into an array for varargs? */ Resolve.MethodResolutionPhase pendingResolutionPhase = null; @@ -100,7 +95,6 @@ info.returnResult = returnResult; info.defaultSuperCallSite = defaultSuperCallSite; info.isSerializable = isSerializable; - info.isSpeculative = isSpeculative; return info; } diff -r c32c9586ea94 -r aa84b6606229 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Mon Sep 08 13:11:28 2014 +0200 @@ -25,7 +25,6 @@ package com.sun.tools.javac.comp; -import com.sun.source.tree.*; import com.sun.source.tree.LambdaExpressionTree.BodyKind; import com.sun.tools.javac.code.*; import com.sun.tools.javac.tree.*; @@ -78,7 +77,6 @@ final Types types; final Flow flow; final Names names; - final Annotate annotate; final TypeEnvs typeEnvs; public static DeferredAttr instance(Context context) { @@ -103,7 +101,6 @@ flow = Flow.instance(context); names = Names.instance(context); stuckTree = make.Ident(names.empty).setType(Type.stuckType); - annotate = Annotate.instance(context); typeEnvs = TypeEnvs.instance(context); emptyDeferredAttrContext = new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) { @@ -139,8 +136,7 @@ AttrMode mode; SpeculativeCache speculativeCache; - DeferredType(JCExpression tree, - Env env) { + DeferredType(JCExpression tree, Env env) { super(null, noAnnotations); this.tree = tree; this.env = attr.copyEnv(env); @@ -284,18 +280,12 @@ //Note: if a symbol is imported twice we might do two identical //speculative rounds... Assert.check(dt.mode == null || dt.mode == AttrMode.SPECULATIVE); - JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, - resultInfo, - annotate.noCreator); + JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo); dt.speculativeCache.put(speculativeTree, resultInfo); return speculativeTree.type; case CHECK: Assert.check(dt.mode != null); - final boolean oldSpeculative = dt.env.info.isSpeculative; - dt.env.info.isSpeculative = false; - Type out = attr.attribTree(dt.tree, dt.env, resultInfo); - dt.env.info.isSpeculative = oldSpeculative; - return out; + return attr.attribTree(dt.tree, dt.env, resultInfo); } Assert.error(); return null; @@ -372,13 +362,9 @@ * restored after type-checking. All diagnostics (but critical ones) are * disabled during speculative type-checking. */ - JCTree attribSpeculative(JCTree tree, - Env env, - ResultInfo resultInfo, - Annotate.PositionCreator creator) { + JCTree attribSpeculative(JCTree tree, Env env, ResultInfo resultInfo) { final JCTree newTree = new TreeCopier<>(make).copy(tree); Env speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner))); - speculativeEnv.info.isSpeculative = true; Log.DeferredDiagnosticHandler deferredDiagnosticHandler = new Log.DeferredDiagnosticHandler(log, new Filter() { public boolean accepts(final JCDiagnostic d) { @@ -401,9 +387,6 @@ }); try { attr.attribTree(newTree, speculativeEnv, resultInfo); - annotate.typeAnnotateExprLater(newTree, speculativeEnv, - speculativeEnv.info.scope.owner, - newTree.pos(), creator); unenterScanner.scan(newTree); return newTree; } finally { @@ -771,11 +754,8 @@ checkContext.report(null, ex.getDiagnostic()); } Env localEnv = env.dup(tree); - JCExpression exprTree = - (JCExpression)attribSpeculative(tree.getQualifierExpression(), - localEnv, - attr.memberReferenceQualifierResult(tree), - annotate.methodRefCreator(tree.pos)); + JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv, + attr.memberReferenceQualifierResult(tree)); ListBuffer argtypes = new ListBuffer<>(); for (Type t : types.findDescriptorType(pt).getParameterTypes()) { argtypes.append(Type.noType); @@ -1197,11 +1177,8 @@ public void visitReference(JCMemberReference tree) { //perform arity-based check Env localEnv = env.dup(tree); - JCExpression exprTree = - (JCExpression)attribSpeculative(tree.getQualifierExpression(), - localEnv, - attr.memberReferenceQualifierResult(tree), - annotate.methodRefCreator(tree.pos)); + JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv, + attr.memberReferenceQualifierResult(tree)); JCMemberReference mref2 = new TreeCopier(make).copy(tree); mref2.expr = exprTree; Symbol res = @@ -1345,7 +1322,7 @@ return null; site = resolvedReturnType.type; } else { - site = attribSpeculative(rec, env, attr.unknownTypeExprInfo, annotate.noCreator).type; + site = attribSpeculative(rec, env, attr.unknownTypeExprInfo).type; } } else { site = env.enclClass.sym.type; diff -r c32c9586ea94 -r aa84b6606229 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Env.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Env.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Env.java Mon Sep 08 13:11:28 2014 +0200 @@ -26,7 +26,6 @@ package com.sun.tools.javac.comp; import com.sun.tools.javac.tree.*; -import com.sun.tools.javac.tree.JCTree.JCLambda; import java.util.Iterator; import java.util.NoSuchElementException; @@ -157,10 +156,4 @@ } }; } - - public JCLambda getLambda() { - Env out = enclosing(JCTree.Tag.LAMBDA); - - return out != null ? (JCLambda) out.tree : null; - } } diff -r c32c9586ea94 -r aa84b6606229 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java Mon Sep 08 13:11:28 2014 +0200 @@ -44,7 +44,6 @@ import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Type.*; -import com.sun.tools.javac.code.TypeAnnotationPosition.*; import com.sun.tools.javac.tree.JCTree.*; import static com.sun.tools.javac.code.Flags.*; @@ -85,6 +84,7 @@ private final TreeMaker make; private final Todo todo; private final Annotate annotate; + private final TypeAnnotations typeAnnotations; private final Types types; private final JCDiagnostic.Factory diags; private final Source source; @@ -112,6 +112,7 @@ make = TreeMaker.instance(context); todo = Todo.instance(context); annotate = Annotate.instance(context); + typeAnnotations = TypeAnnotations.instance(context); types = Types.instance(context); diags = JCDiagnostic.Factory.instance(context); source = Source.instance(context); @@ -143,13 +144,6 @@ */ boolean completionEnabled = true; - /** The creator that will be used for any varDef's we visit. This - * is used to create the position for any type annotations (or - * annotations that potentially are type annotations) that we - * encounter. - */ - Annotate.PositionCreator creator; - /* ---------- Processing import clauses ---------------- */ @@ -278,7 +272,6 @@ } /** Construct method type from method signature. - * @param msym The MethodSymbol for the method. * @param typarams The method's type parameters. * @param params The method's value parameters. * @param res The method's result type, @@ -287,89 +280,33 @@ * null if none given; TODO: or already set here? * @param thrown The method's thrown exceptions. * @param env The method's (local) environment. - * @param declAnnos The annotations on the method declaration, - * some of which may be type annotations on - * the return type. - * @param deferPos The deferred diagnostic position for error - * reporting. */ - Type signature(final MethodSymbol msym, - final List typarams, - final List params, - final JCTree res, - final JCVariableDecl recvparam, - final List thrown, - final Env env, - final List declAnnos, - final DiagnosticPosition deferPos) { - int i; + Type signature(MethodSymbol msym, + List typarams, + List params, + JCTree res, + JCVariableDecl recvparam, + List thrown, + Env env) { // Enter and attribute type parameters. List tvars = enter.classEnter(typarams, env); attr.attribTypeVariables(typarams, env); - // Handle type annotations on type parameters. - i = 0; - for (List l = typarams; l.nonEmpty(); - l = l.tail, i++) { - final JCTypeParameter param = l.head; - annotate.annotateTypeLater(param, env, msym, deferPos, - annotate.methodTypeParamCreator(i)); - // ...and bounds on type parameters. - int j = 0; - for (List bounds = param.bounds; - bounds.nonEmpty(); bounds = bounds.tail, j++) { - annotate.annotateTypeLater(bounds.head, env, msym, deferPos, - annotate.methodTypeParamBoundCreator(param, i, j)); - } - } - - // Enter and attribute value parameters. Type annotations get - // METHOD_FORMAL_PARAMETER positions. + // Enter and attribute value parameters. ListBuffer argbuf = new ListBuffer<>(); - i = 0; - for (List l = params; l.nonEmpty(); l = l.tail, i++) { - // The types will get annotated by visitVarDef - memberEnter(l.head, env, annotate.paramCreator(i)); + for (List l = params; l.nonEmpty(); l = l.tail) { + memberEnter(l.head, env); argbuf.append(l.head.vartype.type); } // Attribute result type, if one is given. - Type restype; - - if (res != null) { - // If we have any declaration annotations, they might - // be/also be type annotations on the return type. We - // pass them in, so they get classified and then attached - // to the method, or the return type, or both. - restype = attr.attribType(res, env); - annotate.annotateTypeLater(res, declAnnos, env, msym, deferPos, - annotate.returnCreator); - } else { - // For constructors, we don't actually have a type, so we - // can't have a type path (except for INNER_TYPE), and we - // don't have annotations on arrays, type arguments, and - // the like. - - // The only type path we have is if we are in an inner type. - List typepath = Annotate.makeInners(msym.owner.type); - TypeAnnotationPosition tapos = - TypeAnnotationPosition.methodReturn(typepath, env.getLambda(), -1); - - // We don't have to walk down a type. We just have to do - // repeating annotation handling, then classify and attach - // the annotations. - annotate.annotateWithClassifyLater(declAnnos, env, msym, - deferPos, tapos); - restype = syms.voidType; - } - + Type restype = res == null ? syms.voidType : attr.attribType(res, env); // Attribute receiver type, if one is given. Type recvtype; if (recvparam!=null) { - // The type will get annotated by visitVarDef - memberEnter(recvparam, env, annotate.receiverCreator); + memberEnter(recvparam, env); recvtype = recvparam.vartype.type; } else { recvtype = null; @@ -377,12 +314,8 @@ // Attribute thrown exceptions. ListBuffer thrownbuf = new ListBuffer<>(); - i = 0; - for (List l = thrown; l.nonEmpty(); l = l.tail, i++) { + for (List l = thrown; l.nonEmpty(); l = l.tail) { Type exc = attr.attribType(l.head, env); - // Annotate each exception type. - annotate.annotateTypeLater(l.head, env, msym, deferPos, - annotate.throwCreator(i)); if (!exc.hasTag(TYPEVAR)) { exc = chk.checkClassType(l.head.pos(), exc); } else if (exc.tsym.owner == msym) { @@ -437,49 +370,33 @@ /** Enter field and method definitions and process import * clauses, catching any completion failure exceptions. */ - protected void memberEnter(JCTree tree, Env env, - Annotate.PositionCreator creator) { + protected void memberEnter(JCTree tree, Env env) { Env prevEnv = this.env; - Annotate.PositionCreator prevCreator = this.creator; try { this.env = env; - this.creator = creator; tree.accept(this); } catch (CompletionFailure ex) { chk.completionError(tree.pos(), ex); } finally { - this.creator = prevCreator; this.env = prevEnv; } } - - protected void memberEnter(JCTree tree, Env env) { - memberEnter(tree, env, annotate.noCreator); - } - /** Enter members from a list of trees. */ - void memberEnter(List trees, - Env env, - Annotate.PositionCreator creator) { + void memberEnter(List trees, Env env) { for (List l = trees; l.nonEmpty(); l = l.tail) - memberEnter(l.head, env, creator); - } - - void memberEnter(List trees, - Env env) { - memberEnter(trees, env, annotate.noCreator); + memberEnter(l.head, env); } /** Enter members for a class. */ - void finishClass(final JCClassDecl tree, final Env env) { + void finishClass(JCClassDecl tree, Env env) { if ((tree.mods.flags & Flags.ENUM) != 0 && (types.supertype(tree.sym.type).tsym.flags() & Flags.ENUM) == 0) { addEnumMembers(tree, env); } - memberEnter(tree.defs, env, annotate.fieldCreator); + memberEnter(tree.defs, env); } /** Add the implicit members for an enum type @@ -554,7 +471,7 @@ } } // process package annotations - annotate.annotateLater(tree.annotations, env, env.toplevel.packge); + annotate.annotateLater(tree.annotations, env, env.toplevel.packge, null); } // process the non-static imports and the static imports of types. @@ -602,13 +519,15 @@ Env localEnv = methodEnv(tree, env); + annotate.enterStart(); + try { DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos()); try { // Compute the method type m.type = signature(m, tree.typarams, tree.params, tree.restype, tree.recvparam, - tree.thrown, localEnv, - tree.mods.annotations, tree.pos()); + tree.thrown, + localEnv); } finally { deferredLintHandler.setPos(prevLintPos); } @@ -635,9 +554,16 @@ enclScope.enter(m); } + annotate.annotateLater(tree.mods.annotations, localEnv, m, tree.pos()); + // Visit the signature of the method. Note that + // TypeAnnotate doesn't descend into the body. + annotate.annotateTypeLater(tree, localEnv, m, tree.pos()); + if (tree.defaultValue != null) - annotateDefaultValueLater(tree.defaultValue, localEnv, - m, annotate.noCreator); + annotateDefaultValueLater(tree.defaultValue, localEnv, m); + } finally { + annotate.enterDone(); + } } /** Create a fresh environment for method bodies. @@ -706,18 +632,10 @@ chk.checkTransparentVar(tree.pos(), v, enclScope); enclScope.enter(v); } - if (TreeInfo.isReceiverParam(tree)) { - // If we are dealing with a receiver parameter, then - // we only allow base type annotations to be type - // annotations. Receivers are not allowed to have - // declaration annotations. - annotate.annotateStrictTypeLater(tree.vartype, tree.mods.annotations, - localEnv, v, tree.pos(), creator); - } else { - // Otherwise, we annotate the type. - annotate.annotateTypeLater(tree.vartype, tree.mods.annotations, - localEnv, v, tree.pos(), creator); - } + + annotate.annotateLater(tree.mods.annotations, localEnv, v, tree.pos()); + annotate.annotateTypeLater(tree.vartype, localEnv, v, tree.pos()); + v.pos = tree.pos; } finally { annotate.enterDone(); @@ -889,8 +807,7 @@ /** Queue processing of an attribute default value. */ void annotateDefaultValueLater(final JCExpression defaultValue, final Env localEnv, - final MethodSymbol m, - final Annotate.PositionCreator creator) { + final MethodSymbol m) { annotate.normal(new Annotate.Worker() { @Override public String toString() { @@ -979,38 +896,19 @@ // create an environment for evaluating the base clauses Env baseEnv = baseEnv(tree, env); - // Annotations. - // In general, we cannot fully process annotations yet, but we - // can attribute the annotation types and then check to see if the - // @Deprecated annotation is present. - attr.attribAnnotationTypes(tree.mods.annotations, baseEnv); - if (hasDeprecatedAnnotation(tree.mods.annotations)) - c.flags_field |= DEPRECATED; - - // Don't attach declaration annotations to anonymous - // classes, they get handled specially below. - if (!sym.isAnonymous()) { - annotate.annotateLater(tree.mods.annotations, baseEnv, - c, tree.pos()); - } + if (tree.extending != null) + annotate.annotateTypeLater(tree.extending, baseEnv, sym, tree.pos()); + for (JCExpression impl : tree.implementing) + annotate.annotateTypeLater(impl, baseEnv, sym, tree.pos()); + annotate.flush(); // Determine supertype. Type supertype; - if (tree.extending != null) { dependencies.push(AttributionKind.EXTENDS, tree.extending); try { supertype = attr.attribBase(tree.extending, baseEnv, true, false, true); - if (sym.isAnonymous()) { - annotate.annotateAnonClassDefLater(tree.extending, - tree.mods.annotations, - baseEnv, sym, tree.pos(), - annotate.extendsCreator); - } else { - annotate.annotateTypeLater(tree.extending, baseEnv, sym, - tree.pos(), annotate.extendsCreator); - } } finally { dependencies.pop(); } @@ -1029,7 +927,6 @@ ListBuffer all_interfaces = null; // lazy init Set interfaceSet = new HashSet<>(); List interfaceTrees = tree.implementing; - int i = 0; for (JCExpression iface : interfaceTrees) { dependencies.push(AttributionKind.IMPLEMENTS, iface); try { @@ -1042,19 +939,6 @@ if (all_interfaces == null) all_interfaces = new ListBuffer().appendList(interfaces); all_interfaces.append(modelMissingTypes(it, iface, true)); - - } - if (sym.isAnonymous()) { - // Note: if an anonymous class ever has more than - // one supertype for some reason, this will - // incorrectly attach tree.mods.annotations to ALL - // supertypes, not just the first. - annotate.annotateAnonClassDefLater(iface, tree.mods.annotations, - baseEnv, sym, tree.pos(), - annotate.implementsCreator(i++)); - } else { - annotate.annotateTypeLater(iface, baseEnv, sym, tree.pos(), - annotate.implementsCreator(i++)); } } finally { dependencies.pop(); @@ -1083,28 +967,22 @@ } } - // class type parameters use baseEnv but everything uses env + // Annotations. + // In general, we cannot fully process annotations yet, but we + // can attribute the annotation types and then check to see if the + // @Deprecated annotation is present. + attr.attribAnnotationTypes(tree.mods.annotations, baseEnv); + if (hasDeprecatedAnnotation(tree.mods.annotations)) + c.flags_field |= DEPRECATED; + annotate.annotateLater(tree.mods.annotations, baseEnv, + c, tree.pos()); chk.checkNonCyclicDecl(tree); + // class type parameters use baseEnv but everything uses env attr.attribTypeVariables(tree.typarams, baseEnv); - // Do this here, where we have the symbol. - int j = 0; - for (List l = tree.typarams; l.nonEmpty(); - l = l.tail, j++) { - final JCTypeParameter typaram = l.head; - annotate.annotateTypeLater(typaram, baseEnv, sym, tree.pos(), - annotate.typeParamCreator(j)); - - int k = 0; - for(List b = typaram.bounds; b.nonEmpty(); - b = b.tail, k++) { - final JCExpression bound = b.head; - annotate.annotateTypeLater(bound, baseEnv, sym, tree.pos(), - annotate.typeParamBoundCreator(typaram, j, k)); - } - - } + for (JCTypeParameter tp : tree.typarams) + annotate.annotateTypeLater(tp, baseEnv, sym, tree.pos()); // Add default constructor if needed. if ((c.flags() & INTERFACE) == 0 && @@ -1187,6 +1065,10 @@ Env toFinish = halfcompleted.next(); topLevels.add(toFinish.toplevel); finish(toFinish); + if (allowTypeAnnos) { + typeAnnotations.organizeTypeAnnotationsSignatures(toFinish, (JCClassDecl)toFinish.tree); + typeAnnotations.validateTypeAnnotationsSignatures(toFinish, (JCClassDecl)toFinish.tree); + } } } finally { isFirst = true; diff -r c32c9586ea94 -r aa84b6606229 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java Mon Sep 08 13:11:28 2014 +0200 @@ -1588,6 +1588,8 @@ return TypeAnnotationPosition.methodReturn(readTypePath()); case FIELD: return TypeAnnotationPosition.field(readTypePath()); + case UNKNOWN: + throw new AssertionError("jvm.ClassReader: UNKNOWN target type should never occur!"); default: throw new AssertionError("jvm.ClassReader: Unknown target type for position: " + type); } diff -r c32c9586ea94 -r aa84b6606229 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Mon Sep 08 13:11:28 2014 +0200 @@ -740,13 +740,25 @@ ListBuffer invisibles = new ListBuffer<>(); for (Attribute.TypeCompound tc : typeAnnos) { - Assert.checkNonNull(tc.position); - if (tc.position.type.isLocal() != inCode) { + if (tc.hasUnknownPosition()) { + boolean fixed = tc.tryFixPosition(); + + // Could we fix it? + if (!fixed) { + // This happens for nested types like @A Outer. @B Inner. + // For method parameters we get the annotation twice! Once with + // a valid position, once unknown. + // TODO: find a cleaner solution. + PrintWriter pw = log.getWriter(Log.WriterKind.ERROR); + pw.println("ClassWriter: Position UNKNOWN in type annotation: " + tc); continue; } - if (!tc.position.emitToClassfile()) { + } + + if (tc.position.type.isLocal() != inCode) continue; - } + if (!tc.position.emitToClassfile()) + continue; switch (types.getRetention(tc)) { case SOURCE: break; case CLASS: invisibles.append(tc); break; @@ -927,6 +939,8 @@ case METHOD_RETURN: case FIELD: break; + case UNKNOWN: + throw new AssertionError("jvm.ClassWriter: UNKNOWN target type should never occur!"); default: throw new AssertionError("jvm.ClassWriter: Unknown target type for position: " + p); } diff -r c32c9586ea94 -r aa84b6606229 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java Mon Sep 08 13:11:28 2014 +0200 @@ -519,6 +519,7 @@ ListBuffer fieldTAs = new ListBuffer<>(); ListBuffer nonfieldTAs = new ListBuffer<>(); for (TypeCompound ta : tas) { + Assert.check(ta.getPosition().type != TargetType.UNKNOWN); if (ta.getPosition().type == TargetType.FIELD) { fieldTAs.add(ta); } else { @@ -1818,7 +1819,10 @@ || code.meth.getKind() == javax.lang.model.element.ElementKind.STATIC_INIT; for (Attribute.TypeCompound ta : meth.getRawTypeAttributes()) { - if (ta.position != null && ta.position.matchesPos(treePos)) + if (ta.hasUnknownPosition()) + ta.tryFixPosition(); + + if (ta.position.matchesPos(treePos)) ta.position.updatePosOffset(code.cp); } @@ -1826,7 +1830,10 @@ return; for (Attribute.TypeCompound ta : meth.owner.getRawTypeAttributes()) { - if (ta.position != null && ta.position.matchesPos(treePos)) + if (ta.hasUnknownPosition()) + ta.tryFixPosition(); + + if (ta.position.matchesPos(treePos)) ta.position.updatePosOffset(code.cp); } @@ -1836,7 +1843,10 @@ continue; for (Attribute.TypeCompound ta : s.getRawTypeAttributes()) { - if (ta.position != null && ta.position.matchesPos(treePos)) + if (ta.hasUnknownPosition()) + ta.tryFixPosition(); + + if (ta.position.matchesPos(treePos)) ta.position.updatePosOffset(code.cp); } } @@ -2208,8 +2218,8 @@ } public void visitTypeTest(JCInstanceOf tree) { + setTypeAnnotationPositions(tree.pos); genExpr(tree.expr, tree.expr.type).load(); - setTypeAnnotationPositions(tree.pos); code.emitop2(instanceof_, makeRef(tree.pos(), tree.clazz.type)); result = items.makeStackItem(syms.booleanType); } diff -r c32c9586ea94 -r aa84b6606229 langtools/test/com/sun/javadoc/testTypeAnnotations/TestTypeAnnotations.java --- a/langtools/test/com/sun/javadoc/testTypeAnnotations/TestTypeAnnotations.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/test/com/sun/javadoc/testTypeAnnotations/TestTypeAnnotations.java Mon Sep 08 13:11:28 2014 +0200 @@ -27,7 +27,7 @@ * @summary Make sure that type annotations are displayed correctly * @author Bhavesh Patel * @library ../lib - * @ignore + * @ignore 8006735 output type annotations in javadoc * @build JavadocTester * @run main TestTypeAnnotations */ diff -r c32c9586ea94 -r aa84b6606229 langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.java --- a/langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.java Mon Sep 08 13:11:28 2014 +0200 @@ -3,6 +3,7 @@ * @bug 8026564 * @summary The parts of a fully-qualified type can't be annotated. * @author Werner Dietl + * @ignore 8057679 clarify error messages trying to annotate scoping * @compile/fail/ref=CantAnnotatePackages.out -XDrawDiagnostics CantAnnotatePackages.java */ diff -r c32c9586ea94 -r aa84b6606229 langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.java --- a/langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.java Mon Sep 08 13:11:28 2014 +0200 @@ -3,6 +3,7 @@ * @bug 8006733 8006775 * @summary Ensure behavior for nested types is correct. * @author Werner Dietl + * @ignore 8057679 clarify error messages trying to annotate scoping * @compile/fail/ref=CantAnnotateScoping.out -XDrawDiagnostics CantAnnotateScoping.java */ diff -r c32c9586ea94 -r aa84b6606229 langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotateStaticClass2.java --- a/langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotateStaticClass2.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotateStaticClass2.java Mon Sep 08 13:11:28 2014 +0200 @@ -3,6 +3,8 @@ * @bug 8006733 8006775 * @summary Ensure behavior for nested types is correct. * @author Werner Dietl + * @ignore 8057679 clarify error messages trying to annotate scoping + * @ignore 8057683 improve ordering of errors with type annotations * @compile/fail/ref=CantAnnotateStaticClass2.out -XDrawDiagnostics CantAnnotateStaticClass2.java */ diff -r c32c9586ea94 -r aa84b6606229 langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotateStaticClass3.java --- a/langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotateStaticClass3.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/test/tools/javac/annotations/typeAnnotations/failures/CantAnnotateStaticClass3.java Mon Sep 08 13:11:28 2014 +0200 @@ -3,6 +3,8 @@ * @bug 8006733 8006775 8027262 * @summary Ensure behavior for nested types is correct. * @author Werner Dietl + * @ignore 8057679 clarify error messages trying to annotate scoping + * @ignore 8057683 improve order of errors with type annotations * @compile/fail/ref=CantAnnotateStaticClass3.out -XDrawDiagnostics CantAnnotateStaticClass3.java */ diff -r c32c9586ea94 -r aa84b6606229 langtools/test/tools/javac/annotations/typeAnnotations/failures/common/arrays/DeclarationAnnotation.out --- a/langtools/test/tools/javac/annotations/typeAnnotations/failures/common/arrays/DeclarationAnnotation.out Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/test/tools/javac/annotations/typeAnnotations/failures/common/arrays/DeclarationAnnotation.out Mon Sep 08 13:11:28 2014 +0200 @@ -1,5 +1,5 @@ +DeclarationAnnotation.java:13:21: compiler.err.annotation.type.not.applicable DeclarationAnnotation.java:10:21: compiler.err.annotation.type.not.applicable DeclarationAnnotation.java:11:21: compiler.err.annotation.type.not.applicable DeclarationAnnotation.java:12:21: compiler.err.annotation.type.not.applicable -DeclarationAnnotation.java:13:21: compiler.err.annotation.type.not.applicable 4 errors diff -r c32c9586ea94 -r aa84b6606229 langtools/test/tools/javac/annotations/typeAnnotations/newlocations/AllLocations.java --- a/langtools/test/tools/javac/annotations/typeAnnotations/newlocations/AllLocations.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/test/tools/javac/annotations/typeAnnotations/newlocations/AllLocations.java Mon Sep 08 13:11:28 2014 +0200 @@ -25,6 +25,7 @@ * @test * @bug 8027262 * @summary Stress test for type annotatons + * @ignore 8057685 javac should not crash compiling type annotations * @compile AllLocations.java */ diff -r c32c9586ea94 -r aa84b6606229 langtools/test/tools/javac/annotations/typeAnnotations/newlocations/RepeatingTypeAnnotations.java --- a/langtools/test/tools/javac/annotations/typeAnnotations/newlocations/RepeatingTypeAnnotations.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/test/tools/javac/annotations/typeAnnotations/newlocations/RepeatingTypeAnnotations.java Mon Sep 08 13:11:28 2014 +0200 @@ -28,6 +28,7 @@ * @bug 8006775 * @summary repeating type annotations are possible * @author Werner Dietl + * @ignore 8057683 improve ordering of errors with type annotations * @compile/fail/ref=RepeatingTypeAnnotations.out -XDrawDiagnostics RepeatingTypeAnnotations.java */ diff -r c32c9586ea94 -r aa84b6606229 langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Lambda.java --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Lambda.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Lambda.java Mon Sep 08 13:11:28 2014 +0200 @@ -25,7 +25,8 @@ * @test * @bug 8008077 8029721 8042451 8043974 * @summary Test population of reference info for lambda expressions - * javac crash for annotated parameter type of lambda in a field + * javac crash for annotated parameter type of lambda in a field + * @ignore 8057687 emit correct byte code an attributes for type annotations * @compile -g Driver.java ReferenceInfoUtil.java Lambda.java * @run main Driver Lambda * @author Werner Dietl diff -r c32c9586ea94 -r aa84b6606229 langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/NestedTypes.java --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/NestedTypes.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/NestedTypes.java Mon Sep 08 13:11:28 2014 +0200 @@ -27,6 +27,7 @@ * @test * @bug 8042451 8044009 8044010 * @summary Test population of reference info for nested types + * @ignore 8057687 emit correct byte code an attributes for type annotations * @compile -g Driver.java ReferenceInfoUtil.java NestedTypes.java * @run main Driver NestedTypes */ diff -r c32c9586ea94 -r aa84b6606229 langtools/test/tools/javac/processing/model/type/BasicAnnoTests.java --- a/langtools/test/tools/javac/processing/model/type/BasicAnnoTests.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/test/tools/javac/processing/model/type/BasicAnnoTests.java Mon Sep 08 13:11:28 2014 +0200 @@ -26,7 +26,8 @@ * @bug 8013852 * @summary Annotations on types * @library /tools/javac/lib - * @ignore + * @ignore 8057688 type annotations in type argument position are lost + * @ignore 8031744 Annotations on many Language Model elements are not returned * @build JavacTestingAbstractProcessor DPrinter BasicAnnoTests * @compile/process -processor BasicAnnoTests -proc:only BasicAnnoTests.java */ diff -r c32c9586ea94 -r aa84b6606229 langtools/test/tools/javac/warnings/6747671/T6747671.java --- a/langtools/test/tools/javac/warnings/6747671/T6747671.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/test/tools/javac/warnings/6747671/T6747671.java Mon Sep 08 13:11:28 2014 +0200 @@ -34,6 +34,7 @@ } @TA B @TA[] arr = new @TA B @TA [0];//JDK-8022567: raw warning (2) + //todo: 8057688 type annotations in type argument position are lost Class classes1;//no warning Class[] classes2;//no warning diff -r c32c9586ea94 -r aa84b6606229 langtools/test/tools/javac/warnings/6747671/T6747671.out --- a/langtools/test/tools/javac/warnings/6747671/T6747671.out Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/test/tools/javac/warnings/6747671/T6747671.out Mon Sep 08 13:11:28 2014 +0200 @@ -8,5 +8,5 @@ T6747671.java:32:20: compiler.warn.raw.class.use: T6747671.A, T6747671.A T6747671.java:33:16: compiler.warn.raw.class.use: T6747671.A.Z, T6747671.A.Z T6747671.java:36:9: compiler.warn.raw.class.use: @T6747671.TA T6747671.B, T6747671.B -T6747671.java:36:27: compiler.warn.raw.class.use: @T6747671.TA T6747671.B, T6747671.B +T6747671.java:36:27: compiler.warn.raw.class.use: T6747671.B, T6747671.B 11 warnings diff -r c32c9586ea94 -r aa84b6606229 langtools/test/tools/javac/warnings/suppress/T6480588.java --- a/langtools/test/tools/javac/warnings/suppress/T6480588.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/test/tools/javac/warnings/suppress/T6480588.java Mon Sep 08 13:11:28 2014 +0200 @@ -7,7 +7,7 @@ * @compile/ref=T6480588.out -XDrawDiagnostics -Xlint:unchecked,deprecation,cast T6480588.java * @run main VerifySuppressWarnings T6480588.java */ - +// TODO: 8057683 improve ordering of errors with type annotations @DeprecatedAnnotation class T6480588 extends DeprecatedClass implements DeprecatedInterface { @DeprecatedAnnotation diff -r c32c9586ea94 -r aa84b6606229 langtools/test/tools/javac/warnings/suppress/T6480588.out --- a/langtools/test/tools/javac/warnings/suppress/T6480588.out Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/test/tools/javac/warnings/suppress/T6480588.out Mon Sep 08 13:11:28 2014 +0200 @@ -1,6 +1,6 @@ -T6480588.java:11:2: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package T6480588.java:12:24: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6480588.java:12:51: compiler.warn.has.been.deprecated: DeprecatedInterface, compiler.misc.unnamed.package +T6480588.java:11:2: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package T6480588.java:14:12: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6480588.java:14:65: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6480588.java:13:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package @@ -12,7 +12,7 @@ T6480588.java:26:5: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6480588.java:25:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package T6480588.java:26:33: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package -T6480588.java:28:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package T6480588.java:29:25: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6480588.java:29:52: compiler.warn.has.been.deprecated: DeprecatedInterface, compiler.misc.unnamed.package +T6480588.java:28:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package 17 warnings diff -r c32c9586ea94 -r aa84b6606229 langtools/test/tools/javac/warnings/suppress/TypeAnnotations.java --- a/langtools/test/tools/javac/warnings/suppress/TypeAnnotations.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/test/tools/javac/warnings/suppress/TypeAnnotations.java Mon Sep 08 13:11:28 2014 +0200 @@ -2,6 +2,7 @@ * @test /nodynamiccopyright/ * @bug 8021112 * @summary Verify that \\@SuppressWarnings("unchecked") works for type annotations + * @ignore 8057683 improve ordering of errors with type annotations * @build VerifySuppressWarnings * @compile/ref=TypeAnnotations.out -XDrawDiagnostics -Xlint:unchecked,deprecation,cast TypeAnnotations.java * @run main VerifySuppressWarnings TypeAnnotations.java diff -r c32c9586ea94 -r aa84b6606229 langtools/test/tools/javap/output/RepeatingTypeAnnotations.java --- a/langtools/test/tools/javap/output/RepeatingTypeAnnotations.java Mon Sep 08 10:50:59 2014 +0200 +++ b/langtools/test/tools/javap/output/RepeatingTypeAnnotations.java Mon Sep 08 13:11:28 2014 +0200 @@ -25,6 +25,7 @@ * @test * @bug 8005220 * @summary javap must display repeating annotations + * @ignore 8057687 emit correct byte code an attributes for type annotations */ import java.io.*; import java.util.*;