# HG changeset patch # User lana # Date 1403111344 25200 # Node ID 26e23230009ae601abd2010e97d0f3e909513a9d # Parent f0f30d0016f402818dd48e742e831a474adc942f# Parent bd3cf6f243bea7a01e9b0b39c5a6717e401cb162 Merge diff -r f0f30d0016f4 -r 26e23230009a langtools/src/share/classes/com/sun/source/util/TaskEvent.java --- a/langtools/src/share/classes/com/sun/source/util/TaskEvent.java Fri Jun 13 11:21:39 2014 -0700 +++ b/langtools/src/share/classes/com/sun/source/util/TaskEvent.java Wed Jun 18 10:09:04 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, 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 @@ -68,7 +68,15 @@ /** * For events relating to an individual annotation processing round. **/ - ANNOTATION_PROCESSING_ROUND + ANNOTATION_PROCESSING_ROUND, + /** + * Sent before parsing first source file, and after writing the last output file. + * This event is not sent when using {@link JavacTask#parse()}, + * {@link JavacTask#analyze()} or {@link JavacTask#generate()}. + * + * @since 1.9 + */ + COMPILATION, } public TaskEvent(Kind kind) { diff -r f0f30d0016f4 -r 26e23230009a langtools/src/share/classes/com/sun/tools/javac/api/ClientCodeWrapper.java --- a/langtools/src/share/classes/com/sun/tools/javac/api/ClientCodeWrapper.java Fri Jun 13 11:21:39 2014 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/api/ClientCodeWrapper.java Wed Jun 18 10:09:04 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2014, 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 @@ -202,9 +202,6 @@ // - // FIXME: all these classes should be converted to use multi-catch when - // that is available in the bootstrap compiler. - protected class WrappedJavaFileManager implements JavaFileManager { protected JavaFileManager clientJavaFileManager; WrappedJavaFileManager(JavaFileManager clientJavaFileManager) { diff -r f0f30d0016f4 -r 26e23230009a langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java --- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Fri Jun 13 11:21:39 2014 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Wed Jun 18 10:09:04 2014 -0700 @@ -161,6 +161,15 @@ compilerMain.log = Log.instance(context); compilerMain.setOptions(Options.instance(context)); compilerMain.filenames = new LinkedHashSet<>(); + compilerMain.deferredFileManagerOptions = new LinkedHashMap<>(); + // The following line is conceptually wrong. It should not refer to args + // which may include inappropriate file manager options. + // (Ideally, args should not even be passed into JavacTaskImpl at all.) + // The "no filenames in args" check should have been handled by the use of + // the GrumpyHelper in JavacTool.getTask, but processArgs also has some + // additional checking, which should be factored out and called separately. + // If we fix this, then filenames and deferredFileManagerOptions in Main + // can revert to being protected or private, not public. Collection filenames = compilerMain.processArgs(CommandLine.parse(args), classNames); if (filenames != null && !filenames.isEmpty()) throw new IllegalArgumentException("Malformed arguments " + toString(filenames, " ")); diff -r f0f30d0016f4 -r 26e23230009a langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java --- a/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java Fri Jun 13 11:21:39 2014 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java Wed Jun 18 10:09:04 2014 -0700 @@ -142,7 +142,7 @@ * access this attribute. */ public final List> values; - public TypeAnnotationPosition position; + public final TypeAnnotationPosition position; private boolean synthesized = false; @@ -170,53 +170,9 @@ @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); } /** @@ -280,6 +236,12 @@ 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 f0f30d0016f4 -r 26e23230009a langtools/src/share/classes/com/sun/tools/javac/code/Flags.java --- a/langtools/src/share/classes/com/sun/tools/javac/code/Flags.java Fri Jun 13 11:21:39 2014 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Flags.java Wed Jun 18 10:09:04 2014 -0700 @@ -296,7 +296,8 @@ ModifierFlags = ((long)StandardFlags & ~INTERFACE) | DEFAULT, InterfaceMethodMask = ABSTRACT | STATIC | PUBLIC | STRICTFP | DEFAULT, AnnotationTypeElementMask = ABSTRACT | PUBLIC, - LocalVarFlags = FINAL | PARAMETER; + LocalVarFlags = FINAL | PARAMETER, + ReceiverParamFlags = PARAMETER; public static Set asModifierSet(long flags) { diff -r f0f30d0016f4 -r 26e23230009a langtools/src/share/classes/com/sun/tools/javac/code/TargetType.java --- a/langtools/src/share/classes/com/sun/tools/javac/code/TargetType.java Fri Jun 13 11:21:39 2014 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/TargetType.java Wed Jun 18 10:09:04 2014 -0700 @@ -107,10 +107,7 @@ CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT(0x4A, true), /** For annotations on a type argument of a method reference. */ - METHOD_REFERENCE_TYPE_ARGUMENT(0x4B, true), - - /** For annotations with an unknown target. */ - UNKNOWN(0xFF); + METHOD_REFERENCE_TYPE_ARGUMENT(0x4B, true); private static final int MAXIMUM_TARGET_TYPE_VALUE = 0x4B; @@ -150,26 +147,15 @@ 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 f0f30d0016f4 -r 26e23230009a langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java --- a/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java Fri Jun 13 11:21:39 2014 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java Wed Jun 18 10:09:04 2014 -0700 @@ -259,9 +259,6 @@ case METHOD_RETURN: case FIELD: break; - case UNKNOWN: - sb.append(", position UNKNOWN!"); - break; default: Assert.error("Unknown target type: " + type); } @@ -428,7 +425,7 @@ } /** - * Create a {@code TypeAnnotationPosition} for a method receiver. + * Create a {@code TypeAnnotationPosition} for a method receiver parameter. * * @param location The type path. * @param onLambda The lambda for this parameter. @@ -445,7 +442,7 @@ } /** - * Create a {@code TypeAnnotationPosition} for a method receiver. + * Create a {@code TypeAnnotationPosition} for a method receiver parameter. * * @param location The type path. */ @@ -455,7 +452,7 @@ } /** - * Create a {@code TypeAnnotationPosition} for a method receiver. + * Create a {@code TypeAnnotationPosition} for a method receiver parameter. * * @param pos The position from the associated tree node. */ @@ -664,10 +661,11 @@ 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, - Integer.MIN_VALUE, Integer.MIN_VALUE, + type_index, Integer.MIN_VALUE, location); } @@ -680,7 +678,7 @@ public static TypeAnnotationPosition exceptionParameter(final JCLambda onLambda, final int pos) { - return exceptionParameter(emptyPath, onLambda, pos); + return exceptionParameter(emptyPath, onLambda, Integer.MIN_VALUE, pos); } /** @@ -690,7 +688,7 @@ */ public static TypeAnnotationPosition exceptionParameter(final List location) { - return exceptionParameter(location, null, -1); + return exceptionParameter(location, null, Integer.MIN_VALUE, -1); } @@ -1204,12 +1202,4 @@ 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 f0f30d0016f4 -r 26e23230009a langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java --- a/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Fri Jun 13 11:21:39 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1397 +0,0 @@ -/* - * 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 f0f30d0016f4 -r 26e23230009a langtools/src/share/classes/com/sun/tools/javac/code/Types.java --- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Fri Jun 13 11:21:39 2014 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Wed Jun 18 10:09:04 2014 -0700 @@ -1212,17 +1212,38 @@ TypeRelation isSameTypeLoose = new LooseSameTypeVisitor(); private class LooseSameTypeVisitor extends SameTypeVisitor { + + /** cache of the type-variable pairs being (recursively) tested. */ + private Set cache = new HashSet<>(); + @Override boolean sameTypeVars(TypeVar tv1, TypeVar tv2) { - return tv1.tsym == tv2.tsym && visit(tv1.getUpperBound(), tv2.getUpperBound()); + return tv1.tsym == tv2.tsym && checkSameBounds(tv1, tv2); } @Override protected boolean containsTypes(List ts1, List ts2) { return containsTypeEquivalent(ts1, ts2); } - } - - /** + + /** + * Since type-variable bounds can be recursive, we need to protect against + * infinite loops - where the same bounds are checked over and over recursively. + */ + private boolean checkSameBounds(TypeVar tv1, TypeVar tv2) { + TypePair p = new TypePair(tv1, tv2, true); + if (cache.add(p)) { + try { + return visit(tv1.getUpperBound(), tv2.getUpperBound()); + } finally { + cache.remove(p); + } + } else { + return false; + } + } + }; + + /** * Strict type-equality relation - type variables are considered * equals if they share the same object identity. */ @@ -3396,9 +3417,16 @@ class TypePair { final Type t1; final Type t2; + boolean strict; + TypePair(Type t1, Type t2) { + this(t1, t2, false); + } + + TypePair(Type t1, Type t2, boolean strict) { this.t1 = t1; this.t2 = t2; + this.strict = strict; } @Override public int hashCode() { @@ -3409,8 +3437,8 @@ if (!(obj instanceof TypePair)) return false; TypePair typePair = (TypePair)obj; - return isSameType(t1, typePair.t1) - && isSameType(t2, typePair.t2); + return isSameType(t1, typePair.t1, strict) + && isSameType(t2, typePair.t2, strict); } } Set mergeCache = new HashSet<>(); diff -r f0f30d0016f4 -r 26e23230009a langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java Fri Jun 13 11:21:39 2014 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java Wed Jun 18 10:09:04 2014 -0700 @@ -29,12 +29,15 @@ 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.*; 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.*; @@ -259,36 +262,78 @@ * Compute an attribute from its annotation. *********************************************************************/ - /** Process a single compound annotation, returning its - * Attribute. Used from MemberEnter for attaching the attributes - * to the annotated symbol. + /** + * 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. */ Attribute.Compound enterAnnotation(JCAnnotation a, Type expected, - Env env) { - List> elems = - enterAttributeValues(a, expected, env); - Attribute.Compound ac = new Attribute.Compound(a.type, elems); + Env env, + TypeAnnotationPosition position) { + List> buf = + enterAttributeValues(a, expected, env, position); + Attribute.Compound ac = + new Attribute.Compound(a.type, buf, position); 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) { - List> elems = - enterAttributeValues(a, expected, env); - - if (a.attribute == null || !(a.attribute instanceof Attribute.TypeCompound)) { - // Create a new TypeCompound + Env env, + TypeAnnotationPosition position, + boolean secondaryAttr) { + List> buf = + enterAttributeValues(a, expected, env, position); + // 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, elems, - // TODO: Eventually, we will get rid of this use of - // unknown, because we'll get a position from - // MemberEnter (task 8027262). - TypeAnnotationPosition.unknown); + new Attribute.TypeCompound(a.type, buf, position); a.attribute = tc; return tc; } else { @@ -297,10 +342,12 @@ } } + // Attribute all the annotation's values. private List> enterAttributeValues(JCAnnotation a, Type expected, - Env env) { + Env env, + TypeAnnotationPosition position) { // 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. @@ -325,13 +372,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); + enterAttributeValue(t.type = syms.errType, t, env, position); 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); + enterAttributeValue(t.type = syms.errType, t, env, position); continue; } JCIdent left = (JCIdent)assign.lhs; @@ -346,7 +393,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); + Attribute value = enterAttributeValue(result, assign.rhs, env, position); if (!method.type.isErroneous()) buf.append(new Pair<>((MethodSymbol)method, value)); t.type = result; @@ -357,6 +404,13 @@ 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. @@ -378,8 +432,7 @@ ListBuffer buf = new ListBuffer<>(); for (List l = na.elems; l.nonEmpty(); l=l.tail) { buf.append(enterAttributeValue(types.elemtype(expected), - l.head, - env)); + l.head, env, position)); } na.type = expected; return new Attribute. @@ -393,15 +446,13 @@ 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); + enterAttributeValue(syms.errType, l.head, env, position); } return new Attribute.Error(syms.errType); } if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) { if (tree.hasTag(ANNOTATION)) { - return enterAnnotation((JCAnnotation)tree, expected, env); + return enterAnnotation((JCAnnotation)tree, expected, env, position); } else { log.error(tree.pos(), "annotation.value.must.be.annotation"); expected = syms.errType; @@ -410,7 +461,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); + enterAnnotation((JCAnnotation)tree, syms.errType, env, position); return new Attribute.Error(((JCAnnotation)tree).annotationType.type); } if (expected.isPrimitive() || @@ -477,9 +528,11 @@ * 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) { + Symbol on, + TypeAnnotationPosition position) { T firstOccurrence = annotations.head; List repeated = List.nil(); Type origAnnoType = null; @@ -491,12 +544,8 @@ !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()); @@ -536,26 +585,16 @@ new Pair(containerValueSymbol, new Attribute.Array(arrayOfOrigAnnoType, repeated)); if (ctx.isTypeCompound) { - /* 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? - + Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p), position); at.setSynthesized(true); @SuppressWarnings("unchecked") T x = (T) at; return x; } else { - Attribute.Compound c = new Attribute.Compound(targetContainerType, List.of(p)); + Attribute.Compound c = new Attribute.Compound(targetContainerType, + List.of(p), + position); JCAnnotation annoTree = m.Annotation(c); if (!chk.annotationApplicable(annoTree, on)) @@ -564,7 +603,7 @@ if (!chk.validateAnnotationDeferErrors(annoTree)) log.error(annoTree.pos(), "duplicate.annotation.invalid.repeated", origAnnoType); - c = enterAnnotation(annoTree, targetContainerType, ctx.env); + c = enterAnnotation(annoTree, targetContainerType, ctx.env, position); c.setSynthesized(true); @SuppressWarnings("unchecked") @@ -576,6 +615,7 @@ } } + /** Fetches the actual Type that should be the containing annotation. */ private Type getContainingType(Attribute.Compound currentAnno, DiagnosticPosition pos, @@ -705,31 +745,53 @@ 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, - boolean isTypeCompound) { + TypeAnnotationPosition position) { 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); + T c = creator.create(a, syms.annotationType, env, position); 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()); } @@ -743,25 +805,54 @@ } return new AnnotationContext<>(env, annotated, pos, - isTypeCompound); + creator.createsTypeCompound()); } - // Gather up annotations into a map from type symbols to lists of - // Compound attributes, then continue on with repeating - // annotations processing + /** + * 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. + */ private void attachAttributesLater(final List annotations, final Env env, final Symbol sym, - final boolean isTypeCompound, + final TypeAnnotationPosition position, final AttributeCreator creator, final AttributeAttacher attacher) { + // First, gather up all the repeated annotations. final AnnotationContext ctx = - prepareEnterAnnotations(annotations, env, sym, creator, isTypeCompound); + prepareEnterAnnotations(annotations, env, sym, creator, position); 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) { @@ -776,14 +867,62 @@ final List attrs = buf.reverse(); - if (!isTypeCompound) { + if (!creator.createsTypeCompound()) { // Attach declaration attributes early, so // that @Repeatable and other annotations get attached. // Since the attacher uses setDeclarationAttributes, this // will be overwritten later. - attacher.attach(sym, attrs); + // + // 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); } + 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() { @@ -795,38 +934,493 @@ JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile); try { - attacher.attach(sym, replacePlaceholders(attrs, ctx, sym)); + // Replace placeholders + final List replaced = + replacePlaceholders(attrs, ctx, sym); + // Then send the result to the final pipeline stage. + attachAttributesAfterRepeated(replaced, env, attacher); } 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 { - attacher.attach(sym, attrs); + return AnnotationKind.DECLARATION; } } - private interface AttributeAttacher { - public void attach(Symbol sym, List 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() { + @Override + public String toString() { + return "Attacher for strictly declaration annotations, for " + + sym; + } - private final AttributeAttacher declAnnotationsAttacher = - new AttributeAttacher() { @Override - public void attach(Symbol sym, List attrs) { + public void attach(List attrs) { sym.resetAnnotations(); sym.setDeclarationAttributes(attrs); } }; + } - private final AttributeAttacher typeAnnotationsAttacher = - new AttributeAttacher() { + /** + * 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; + } + @Override - public void attach(Symbol sym, List attrs) { - sym.appendUniqueTypeAttributes(attrs); + 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); } }; + } + // 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, @@ -848,13 +1442,16 @@ 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); + ctx, sym, placeholder.position); if (validRepeated != null) { // Check that the container isn't manually @@ -875,16 +1472,65 @@ * Annotation processing *********************************************************************/ - /** Queue annotations for later 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). + */ 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(); // mark Annotations as incomplete for now + s.resetAnnotations(); } normal(new Annotate.Worker() { @Override @@ -894,12 +1540,44 @@ @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() && @@ -907,7 +1585,7 @@ log.error(annotations.head.pos, "already.annotated", kindName(s), s); - actualEnterAnnotations(annotations, localEnv, s); + actualEnterAnnotations(annotations, localEnv, s, position, attacher); } finally { if (prevLint != null) chk.setLint(prevLint); @@ -915,9 +1593,12 @@ log.useSource(prev); } } - }); - validate(new Annotate.Worker() { //validate annotations + // 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 @Override public void run() { JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); @@ -927,52 +1608,140 @@ 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"); + } + } } - private interface AttributeCreator { - public T create(JCAnnotation a, Type expected, Env env); + // 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); + } + } + }; } - // TODO: When SE8 features can be used, these can go away and be - // replaced by method refs. + /** + * 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. 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) { - return enterAnnotation(a, syms.annotationType, env); + Env env, + TypeAnnotationPosition position) { + return enterAnnotation(a, syms.annotationType, env, position); } + + @Override + public boolean createsTypeCompound() { return false; } }; - private final AttributeCreator enterTypeAnnotationsCreator = - new AttributeCreator() { + + 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"; + } + } + @Override public Attribute.TypeCompound create(JCAnnotation a, Type expected, - Env env) { - return enterTypeAnnotation(a, syms.annotationType, env); + Env env, + TypeAnnotationPosition position) { + return enterTypeAnnotation(a, syms.annotationType, + env, position, secondaryAttr); } - }; - /** Enter a set of annotations. */ + @Override + public boolean createsTypeCompound() { return true; } + }; + } + + /** + * 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) { - Assert.checkNonNull(s, "Symbol argument to actualEnterAnnotations is null"); - attachAttributesLater(annotations, env, s, false, - enterAnnotationsCreator, - declAnnotationsAttacher); + Symbol s, + TypeAnnotationPosition position, + AttributeAttacher attacher) { + Assert.checkNonNull(s); + attachAttributesLater(annotations, env, s, position, + enterAnnotationsCreator, attacher); } - /* - * If the symbol is non-null, attach the type annotation to it. + /** + * Send a list of annotations (which occurred in a type-use + * position) into the repeating annotations pipeline. */ private void actualEnterTypeAnnotations(final List annotations, final Env env, final Symbol s, - final DiagnosticPosition deferPos) { - Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is nul/"); + final DiagnosticPosition deferPos, + final boolean secondaryAttr, + final TypeAnnotationPosition position, + final AttributeAttacher attacher) { + Assert.checkNonNull(s); JavaFileObject prev = log.useSource(env.toplevel.sourcefile); DiagnosticPosition prevLintPos = null; @@ -980,9 +1749,9 @@ prevLintPos = deferredLintHandler.setPos(deferPos); } try { - attachAttributesLater(annotations, env, s, true, - enterTypeAnnotationsCreator, - typeAnnotationsAttacher); + attachAttributesLater(annotations, env, s, position, + enterTypeAnnotationsCreator(secondaryAttr), + attacher); } finally { if (prevLintPos != null) deferredLintHandler.setPos(prevLintPos); @@ -990,11 +1759,114 @@ } } + /** + * 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 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) { Assert.checkNonNull(sym); + Assert.checkNonNull(baseTypeAnnos); + Assert.checkNonNull(creator); + normal(new Annotate.Worker() { @Override public String toString() { @@ -1002,93 +1874,912 @@ } @Override public void run() { - tree.accept(new TypeAnnotate(env, sym, deferPos)); + if (!baseTypeAnnos.isEmpty()) { + sym.resetAnnotations(); // mark Annotations as incomplete for now + } + + tree.accept(typeAnnotator(baseTypeAnnos, sym, env, deferPos, + creator, onlyTypeAnnos, + secondaryAttr)); } }); } /** - * 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. + * 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. */ - private class TypeAnnotate extends TreeScanner { - private final Env env; - private final Symbol sym; - private DiagnosticPosition deferPos; + public abstract class PositionCreator { + public abstract TypeAnnotationPosition create(List path, + JCLambda lambda, + int typeIndex); + } - public TypeAnnotate(final Env env, - final Symbol sym, - final 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"; + } - this.env = env; - this.sym = sym; - this.deferPos = 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"; } @Override - public void visitAnnotatedType(final JCAnnotatedType tree) { - actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos); - super.visitAnnotatedType(tree); + 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"; } @Override - public void visitTypeParameter(final JCTypeParameter tree) { - actualEnterTypeAnnotations(tree.annotations, env, sym, deferPos); - super.visitTypeParameter(tree); + 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; } @Override - 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); + 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; } - @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 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 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; + // 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 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 f0f30d0016f4 -r 26e23230009a langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri Jun 13 11:21:39 2014 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Wed Jun 18 10:09:04 2014 -0700 @@ -91,7 +91,6 @@ final Types types; final JCDiagnostic.Factory diags; final Annotate annotate; - final TypeAnnotations typeAnnotations; final DeferredLintHandler deferredLintHandler; public static Attr instance(Context context) { @@ -120,7 +119,6 @@ types = Types.instance(context); diags = JCDiagnostic.Factory.instance(context); annotate = Annotate.instance(context); - typeAnnotations = TypeAnnotations.instance(context); deferredLintHandler = DeferredLintHandler.instance(context); Options options = Options.instance(context); @@ -137,6 +135,7 @@ allowTypeAnnos = source.allowTypeAnnotations(); allowLambda = source.allowLambda(); allowDefaultMethods = source.allowDefaultMethods(); + allowStaticInterfaceMethods = source.allowStaticInterfaceMethods(); sourceName = source.name; relax = (options.isSet("-retrofit") || options.isSet("-relax")); @@ -194,6 +193,10 @@ */ boolean allowDefaultMethods; + /** Switch: static interface methods enabled? + */ + boolean allowStaticInterfaceMethods; + /** Switch: allow references to surrounding object from anonymous * objects during constructor call? */ @@ -434,8 +437,7 @@ 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)); } @@ -638,7 +640,8 @@ /** 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 @@ -650,6 +653,7 @@ /** Derived visitor method: attribute a type tree. */ + public Type attribType(JCTree tree, Env env) { Type result = attribType(tree, env, Type.noType); return result; @@ -664,6 +668,7 @@ /** Derived visitor method: attribute a statement or definition tree. */ + public Type attribStat(JCTree tree, Env env) { return attribTree(tree, env, statInfo); } @@ -731,7 +736,8 @@ 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()); @@ -765,7 +771,7 @@ * @param type The expected type, or null * @see VarSymbol#setLazyConstValue */ - public Object attribLazyConstantValue(Env env, + public Object attribLazyConstantValue(final Env env, JCVariableDecl variable, Type type) { @@ -884,6 +890,7 @@ c.flags_field |= NOOUTERTHIS; } attribClass(tree.pos(), c); + result = tree.type = c.type; } } @@ -1021,10 +1028,6 @@ } } - // Attribute all type annotations in the body - annotate.annotateTypeLater(tree.body, localEnv, m, null); - annotate.flush(); - // Attribute method body. attribStat(tree.body, localEnv); } @@ -1038,21 +1041,59 @@ } } - public void visitVarDef(JCVariableDecl tree) { + 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) { // 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); - 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(); + memberEnter.memberEnter(tree, env, getVarCreator(tree)); } } @@ -1103,17 +1144,15 @@ // Block is a static or instance initializer; // let the owner of the environment be a freshly // created BLOCK-method. - Env localEnv = + final Env localEnv = env.dup(tree, env.info.dup(env.info.scope.dupUnshared())); localEnv.info.scope.owner = new MethodSymbol(tree.flags | BLOCK | env.info.scope.owner.flags() & STRICTFP, names.empty, null, env.info.scope.owner); + 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); { // Store init and clinit type annotations with the ClassSymbol @@ -1126,8 +1165,6 @@ cs.appendInitTypeAttributes(tas); } } - - attribStats(tree.stats, localEnv); } else { // Create a new local environment with a local scope. Env localEnv = @@ -1481,17 +1518,21 @@ isBooleanOrNumeric(env, condTree.falsepart); case APPLY: JCMethodInvocation speculativeMethodTree = - (JCMethodInvocation)deferredAttr.attribSpeculative(tree, env, unknownExprInfo); + (JCMethodInvocation)deferredAttr.attribSpeculative(tree, env, unknownExprInfo, + annotate.noCreator); 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); + (JCExpression)deferredAttr.attribSpeculative(className, + env, + unknownTypeInfo, + annotate.newObjCreator(tree.pos)); return types.unboxedTypeOrType(speculativeNewClassTree.type).isPrimitive(); default: - Type speculativeType = deferredAttr.attribSpeculative(tree, env, unknownExprInfo).type; + Type speculativeType = deferredAttr.attribSpeculative(tree, env, unknownExprInfo, annotate.noCreator).type; speculativeType = types.unboxedTypeOrType(speculativeType); return speculativeType.isPrimitive(); } @@ -1754,7 +1795,28 @@ // Attribute arguments, yielding list of argument types. attribArgs(tree.args, localEnv, argtypesBuf); argtypes = argtypesBuf.toList(); - typeargtypes = attribTypes(tree.typeargs, localEnv); + + // 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()); // Variable `site' points to the class in which the called // constructor is defined. @@ -1827,7 +1889,27 @@ // Attribute the arguments, yielding list of argument types, ... int kind = attribArgs(tree.args, localEnv, argtypesBuf); argtypes = argtypesBuf.toList(); - typeargtypes = attribAnyTypes(tree.typeargs, localEnv); + + // 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(); // ... and attribute the method using as a prototype a methodtype // whose formal argument types is exactly the list of actual @@ -1852,6 +1934,7 @@ // current context. Also, capture the return type result = check(tree, capture(restype), VAL, resultInfo); } + chk.validate(tree.typeargs, localEnv); } //where @@ -1927,14 +2010,12 @@ 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 @@ -1956,11 +2037,12 @@ EndPosTable endPosTable = this.env.toplevel.endPositions; endPosTable.storeEnd(clazzid1, tree.getEndPosition(endPosTable)); - if (clazz.hasTag(ANNOTATED_TYPE)) { - JCAnnotatedType annoType = (JCAnnotatedType) clazz; - List annos = annoType.annotations; - - if (annoType.underlyingType.hasTag(TYPEAPPLY)) { + if (annoclazzid != null) { + JCAnnotatedType annoType = annoclazzid; + List annos = annoclazzid.annotations; + + if (clazz.hasTag(TYPEAPPLY)) { + clazzid1 = make.at(tree.pos). TypeApply(clazzid1, ((JCTypeApply) clazz).arguments); @@ -1977,12 +2059,32 @@ clazz = clazzid1; } + Type clazztype; + + try { + annotate.enterStart(); // Attribute clazz expression and store // symbol + type back into the attributed tree. - Type clazztype = TreeInfo.isEnumInit(env.tree) ? + 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) { @@ -2011,7 +2113,29 @@ ListBuffer argtypesBuf = new ListBuffer<>(); int pkind = attribArgs(tree.args, localEnv, argtypesBuf); List argtypes = argtypesBuf.toList(); - List typeargtypes = attribTypes(tree.typeargs, localEnv); + 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()); // If we have made no mistakes in the class type... if (clazztype.hasTag(CLASS)) { @@ -2194,7 +2318,9 @@ 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).type; + Type inferred = deferredAttr.attribSpeculative(tree, env, + findDiamondResult, + annotate.newObjCreator(tree.pos)).type; Type polyPt = allowPoly ? syms.objectType : clazztype; @@ -2256,8 +2382,20 @@ 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) { @@ -2278,6 +2416,7 @@ elemtype = types.createErrorType(pt()); } } + if (tree.elems != null) { attribExprs(tree.elems, localEnv, elemtype); owntype = new ArrayType(elemtype, syms.arrayClass, @@ -2672,6 +2811,8 @@ @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 @@ -2682,9 +2823,20 @@ } 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 - Type exprType = attribTree(that.expr, env, memberReferenceQualifierResult(that)); + 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(); + } if (that.getMode() == JCMemberReference.ReferenceMode.NEW) { exprType = chk.checkConstructorRefType(that.expr, exprType); @@ -2714,7 +2866,24 @@ //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; @@ -3088,7 +3257,15 @@ } public void visitTypeCast(final JCTypeCast tree) { - Type clazztype = attribType(tree.clazz, env); + 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(); + } chk.validate(tree.clazz, env, false); //a fresh environment is required for 292 inference to work properly --- //see Infer.instantiatePolymorphicSignatureInstance() @@ -3121,7 +3298,16 @@ public void visitTypeTest(JCInstanceOf tree) { Type exprtype = chk.checkNullOrRefType( tree.expr.pos(), attribExpr(tree.expr, env)); - Type clazztype = attribType(tree.clazz, 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(); + } + if (!clazztype.hasTag(TYPEVAR)) { clazztype = chk.checkClassOrArrayType(tree.clazz.pos(), clazztype); } @@ -3250,9 +3436,12 @@ if ((pkind() & (PCK | TYP)) == 0) site = capture(site); // Capture field access + 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 - if (skind == TYP) { - Type elt = site; while (elt.hasTag(ARRAY)) elt = ((ArrayType)elt).elemtype; if (elt.hasTag(TYPEVAR)) { @@ -3334,6 +3523,10 @@ tree.pos(), site, sym.name, true); } } + if (!allowStaticInterfaceMethods && sitesym.isInterface() && + sym.isStatic() && sym.kind == MTH) { + log.error(tree.pos(), "static.intf.method.invoke.not.supported.in.source", sourceName); + } } else if (sym.kind != ERR && (sym.flags() & STATIC) != 0 && sym.name != names._class) { // If the qualified item is not a type and the selected item is static, report // a warning. Make allowance for the class of an array type e.g. Object[].class) @@ -4081,8 +4274,13 @@ 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 = attribType(tree.getUnderlyingType(), env); + Type underlyingType = attribTree(tree.getUnderlyingType(), env, + resultInfo); this.attribAnnotationTypes(tree.annotations, env); annotateType(tree, tree.annotations); result = tree.type = underlyingType; @@ -4101,8 +4299,10 @@ 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); } + } }); } @@ -4353,13 +4553,6 @@ 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) { @@ -4433,233 +4626,6 @@ 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 f0f30d0016f4 -r 26e23230009a langtools/src/share/classes/com/sun/tools/javac/comp/AttrContext.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/AttrContext.java Fri Jun 13 11:21:39 2014 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/AttrContext.java Wed Jun 18 10:09:04 2014 -0700 @@ -58,6 +58,11 @@ */ 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; @@ -94,6 +99,7 @@ info.returnResult = returnResult; info.defaultSuperCallSite = defaultSuperCallSite; info.isSerializable = isSerializable; + info.isSpeculative = isSpeculative; return info; } diff -r f0f30d0016f4 -r 26e23230009a langtools/src/share/classes/com/sun/tools/javac/comp/Check.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Fri Jun 13 11:21:39 2014 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Wed Jun 18 10:09:04 2014 -0700 @@ -1041,7 +1041,9 @@ switch (sym.kind) { case VAR: - if (sym.owner.kind != TYP) + if (TreeInfo.isReceiverParam(tree)) + mask = ReceiverParamFlags; + else if (sym.owner.kind != TYP) mask = LocalVarFlags; else if ((sym.owner.flags_field & INTERFACE) != 0) mask = implicit = InterfaceVarFlags; @@ -1818,6 +1820,11 @@ Type t1, Type t2, Type site) { + if ((site.tsym.flags() & COMPOUND) != 0) { + // special case for intersections: need to eliminate wildcards in supertypes + t1 = types.capture(t1); + t2 = types.capture(t2); + } return firstIncompatibility(pos, t1, t2, site) == null; } diff -r f0f30d0016f4 -r 26e23230009a langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Fri Jun 13 11:21:39 2014 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Wed Jun 18 10:09:04 2014 -0700 @@ -25,6 +25,7 @@ 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.*; @@ -76,6 +77,7 @@ final Types types; final Flow flow; final Names names; + final Annotate annotate; public static DeferredAttr instance(Context context) { DeferredAttr instance = context.get(deferredAttrKey); @@ -99,6 +101,7 @@ flow = Flow.instance(context); names = Names.instance(context); stuckTree = make.Ident(names.empty).setType(Type.stuckType); + annotate = Annotate.instance(context); emptyDeferredAttrContext = new DeferredAttrContext(AttrMode.CHECK, null, MethodResolutionPhase.BOX, infer.emptyContext, null, null) { @Override @@ -133,7 +136,8 @@ 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); @@ -277,12 +281,18 @@ //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); + JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, + resultInfo, + annotate.noCreator); dt.speculativeCache.put(speculativeTree, resultInfo); return speculativeTree.type; case CHECK: Assert.check(dt.mode != null); - return attr.attribTree(dt.tree, dt.env, resultInfo); + 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; } Assert.error(); return null; @@ -359,9 +369,13 @@ * restored after type-checking. All diagnostics (but critical ones) are * disabled during speculative type-checking. */ - JCTree attribSpeculative(JCTree tree, Env env, ResultInfo resultInfo) { + JCTree attribSpeculative(JCTree tree, + Env env, + ResultInfo resultInfo, + Annotate.PositionCreator creator) { final JCTree newTree = new TreeCopier<>(make).copy(tree); Env speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared())); + speculativeEnv.info.isSpeculative = true; speculativeEnv.info.scope.owner = env.info.scope.owner; Log.DeferredDiagnosticHandler deferredDiagnosticHandler = new Log.DeferredDiagnosticHandler(log, new Filter() { @@ -385,6 +399,9 @@ }); try { attr.attribTree(newTree, speculativeEnv, resultInfo); + annotate.typeAnnotateExprLater(newTree, speculativeEnv, + speculativeEnv.info.scope.owner, + newTree.pos(), creator); unenterScanner.scan(newTree); return newTree; } finally { @@ -741,8 +758,11 @@ checkContext.report(null, ex.getDiagnostic()); } Env localEnv = env.dup(tree); - JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv, - attr.memberReferenceQualifierResult(tree)); + JCExpression exprTree = + (JCExpression)attribSpeculative(tree.getQualifierExpression(), + localEnv, + attr.memberReferenceQualifierResult(tree), + annotate.methodRefCreator(tree.pos)); ListBuffer argtypes = new ListBuffer<>(); for (Type t : types.findDescriptorType(pt).getParameterTypes()) { argtypes.append(Type.noType); @@ -1164,8 +1184,11 @@ public void visitReference(JCMemberReference tree) { //perform arity-based check Env localEnv = env.dup(tree); - JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv, - attr.memberReferenceQualifierResult(tree)); + JCExpression exprTree = + (JCExpression)attribSpeculative(tree.getQualifierExpression(), + localEnv, + attr.memberReferenceQualifierResult(tree), + annotate.methodRefCreator(tree.pos)); JCMemberReference mref2 = new TreeCopier(make).copy(tree); mref2.expr = exprTree; Symbol res = @@ -1309,7 +1332,7 @@ return null; site = resolvedReturnType.type; } else { - site = attribSpeculative(rec, env, attr.unknownTypeExprInfo).type; + site = attribSpeculative(rec, env, attr.unknownTypeExprInfo, annotate.noCreator).type; } } else { site = env.enclClass.sym.type; diff -r f0f30d0016f4 -r 26e23230009a langtools/src/share/classes/com/sun/tools/javac/comp/Env.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Env.java Fri Jun 13 11:21:39 2014 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Env.java Wed Jun 18 10:09:04 2014 -0700 @@ -26,6 +26,7 @@ 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; @@ -156,4 +157,10 @@ } }; } + + public JCLambda getLambda() { + Env out = enclosing(JCTree.Tag.LAMBDA); + + return out != null ? (JCLambda) out.tree : null; + } } diff -r f0f30d0016f4 -r 26e23230009a langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java Fri Jun 13 11:21:39 2014 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java Wed Jun 18 10:09:04 2014 -0700 @@ -35,8 +35,9 @@ import com.sun.tools.javac.tree.*; import com.sun.tools.javac.util.*; +import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Type.*; -import com.sun.tools.javac.code.Symbol.*; +import com.sun.tools.javac.code.TypeAnnotationPosition.*; import com.sun.tools.javac.tree.JCTree.*; import static com.sun.tools.javac.code.Flags.*; @@ -75,7 +76,6 @@ 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; @@ -101,7 +101,6 @@ 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); @@ -131,6 +130,13 @@ */ 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 ---------------- */ @@ -348,6 +354,7 @@ } /** 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, @@ -356,33 +363,89 @@ * 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(MethodSymbol msym, - List typarams, - List params, - JCTree res, - JCVariableDecl recvparam, - List thrown, - Env env) { + 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; // Enter and attribute type parameters. List tvars = enter.classEnter(typarams, env); attr.attribTypeVariables(typarams, env); - // Enter and attribute value parameters. + // 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. ListBuffer argbuf = new ListBuffer<>(); - for (List l = params; l.nonEmpty(); l = l.tail) { - memberEnter(l.head, env); + 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)); argbuf.append(l.head.vartype.type); } // Attribute result type, if one is given. - Type restype = res == null ? syms.voidType : attr.attribType(res, env); + 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; + } + // Attribute receiver type, if one is given. Type recvtype; if (recvparam!=null) { - memberEnter(recvparam, env); + // The type will get annotated by visitVarDef + memberEnter(recvparam, env, annotate.receiverCreator); recvtype = recvparam.vartype.type; } else { recvtype = null; @@ -390,8 +453,12 @@ // Attribute thrown exceptions. ListBuffer thrownbuf = new ListBuffer<>(); - for (List l = thrown; l.nonEmpty(); l = l.tail) { + i = 0; + for (List l = thrown; l.nonEmpty(); l = l.tail, i++) { 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) { @@ -420,33 +487,49 @@ /** Enter field and method definitions and process import * clauses, catching any completion failure exceptions. */ - protected void memberEnter(JCTree tree, Env env) { + protected void memberEnter(JCTree tree, Env env, + Annotate.PositionCreator creator) { 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) { + void memberEnter(List trees, + Env env, + Annotate.PositionCreator creator) { for (List l = trees; l.nonEmpty(); l = l.tail) - memberEnter(l.head, env); + memberEnter(l.head, env, creator); + } + + void memberEnter(List trees, + Env env) { + memberEnter(trees, env, annotate.noCreator); } /** Enter members for a class. */ - void finishClass(JCClassDecl tree, Env env) { + void finishClass(final JCClassDecl tree, final 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); + memberEnter(tree.defs, env, annotate.fieldCreator); } /** Add the implicit members for an enum type @@ -521,7 +604,7 @@ } } // process package annotations - annotate.annotateLater(tree.annotations, env, env.toplevel.packge, null); + annotate.annotateLater(tree.annotations, env, env.toplevel.packge); } // process the non-static imports and the static imports of types. @@ -567,15 +650,13 @@ 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.thrown, localEnv, + tree.mods.annotations, tree.pos()); } finally { deferredLintHandler.setPos(prevLintPos); } @@ -602,16 +683,9 @@ 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); - } finally { - annotate.enterDone(); - } + annotateDefaultValueLater(tree.defaultValue, localEnv, + m, annotate.noCreator); } /** Create a fresh environment for method bodies. @@ -646,22 +720,8 @@ attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype); } else { attr.attribType(tree.vartype, localEnv); - if (tree.nameexpr != null) { - attr.attribExpr(tree.nameexpr, localEnv); - MethodSymbol m = localEnv.enclMethod.sym; - if (m.isConstructor()) { - Type outertype = m.owner.owner.type; - if (outertype.hasTag(TypeTag.CLASS)) { - checkType(tree.vartype, outertype, "incorrect.constructor.receiver.type"); - checkType(tree.nameexpr, outertype, "incorrect.constructor.receiver.name"); - } else { - log.error(tree, "receiver.parameter.not.applicable.constructor.toplevel.class"); - } - } else { - checkType(tree.vartype, m.owner.type, "incorrect.receiver.type"); - checkType(tree.nameexpr, m.owner.type, "incorrect.receiver.name"); - } - } + if (TreeInfo.isReceiverParam(tree)) + checkReceiver(tree, localEnv); } } finally { deferredLintHandler.setPos(prevLintPos); @@ -695,8 +755,18 @@ chk.checkTransparentVar(tree.pos(), v, enclScope); enclScope.enter(v); } - annotate.annotateLater(tree.mods.annotations, localEnv, v, tree.pos()); - annotate.annotateTypeLater(tree.vartype, env, v, tree.pos()); + 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); + } v.pos = tree.pos; } finally { annotate.enterDone(); @@ -708,6 +778,26 @@ log.error(tree, diag, type, tree.type); } } + void checkReceiver(JCVariableDecl tree, Env localEnv) { + attr.attribExpr(tree.nameexpr, localEnv); + MethodSymbol m = localEnv.enclMethod.sym; + if (m.isConstructor()) { + Type outertype = m.owner.owner.type; + if (outertype.hasTag(TypeTag.METHOD)) { + // we have a local inner class + outertype = m.owner.owner.owner.type; + } + if (outertype.hasTag(TypeTag.CLASS)) { + checkType(tree.vartype, outertype, "incorrect.constructor.receiver.type"); + checkType(tree.nameexpr, outertype, "incorrect.constructor.receiver.name"); + } else { + log.error(tree, "receiver.parameter.not.applicable.constructor.toplevel.class"); + } + } else { + checkType(tree.vartype, m.owner.type, "incorrect.receiver.type"); + checkType(tree.nameexpr, m.owner.type, "incorrect.receiver.name"); + } + } public boolean needsLazyConstValue(JCTree tree) { InitTreeVisitor initTreeVisitor = new InitTreeVisitor(); @@ -849,7 +939,8 @@ /** Queue processing of an attribute default value. */ void annotateDefaultValueLater(final JCExpression defaultValue, final Env localEnv, - final MethodSymbol m) { + final MethodSymbol m, + final Annotate.PositionCreator creator) { annotate.normal(new Annotate.Worker() { @Override public String toString() { @@ -936,22 +1027,44 @@ // create an environment for evaluating the base clauses Env baseEnv = baseEnv(tree, env); - 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(); + // 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()); + } // Determine supertype. - Type supertype = - (tree.extending != null) - ? attr.attribBase(tree.extending, baseEnv, true, false, true) - : ((tree.mods.flags & Flags.ENUM) != 0) + Type supertype; + + if (tree.extending != null) { + 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); + } + } else { + supertype = ((tree.mods.flags & Flags.ENUM) != 0) ? attr.attribBase(enumBase(tree.pos, c), baseEnv, true, false, false) : (c.fullname == names.java_lang_Object) ? Type.noType : syms.objectType; + } ct.supertype_field = modelMissingTypes(supertype, tree.extending, false); // Determine interfaces. @@ -959,18 +1072,33 @@ ListBuffer all_interfaces = null; // lazy init Set interfaceSet = new HashSet<>(); List interfaceTrees = tree.implementing; + int i = 0; for (JCExpression iface : interfaceTrees) { - Type i = attr.attribBase(iface, baseEnv, false, true, true); - if (i.hasTag(CLASS)) { - interfaces.append(i); - if (all_interfaces != null) all_interfaces.append(i); - chk.checkNotRepeated(iface.pos(), types.erasure(i), interfaceSet); + Type it = attr.attribBase(iface, baseEnv, false, true, true); + if (it.hasTag(CLASS)) { + interfaces.append(it); + if (all_interfaces != null) all_interfaces.append(it); + chk.checkNotRepeated(iface.pos(), types.erasure(it), interfaceSet); } else { if (all_interfaces == null) all_interfaces = new ListBuffer().appendList(interfaces); - all_interfaces.append(modelMissingTypes(i, iface, true)); + 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++)); } + } + if ((c.flags_field & ANNOTATION) != 0) { ct.interfaces_field = List.of(syms.annotationType); ct.all_interfaces_field = ct.interfaces_field; @@ -993,22 +1121,28 @@ } } - // 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()); // class type parameters use baseEnv but everything uses env chk.checkNonCyclicDecl(tree); attr.attribTypeVariables(tree.typarams, baseEnv); // Do this here, where we have the symbol. - for (JCTypeParameter tp : tree.typarams) - annotate.annotateTypeLater(tp, baseEnv, sym, tree.pos()); + 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)); + } + + } // Add default constructor if needed. if ((c.flags() & INTERFACE) == 0 && @@ -1088,10 +1222,6 @@ while (halfcompleted.nonEmpty()) { Env toFinish = halfcompleted.next(); finish(toFinish); - if (allowTypeAnnos) { - typeAnnotations.organizeTypeAnnotationsSignatures(toFinish, (JCClassDecl)toFinish.tree); - typeAnnotations.validateTypeAnnotationsSignatures(toFinish, (JCClassDecl)toFinish.tree); - } } } finally { isFirst = true; diff -r f0f30d0016f4 -r 26e23230009a langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java --- a/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java Fri Jun 13 11:21:39 2014 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java Wed Jun 18 10:09:04 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, 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 @@ -158,11 +158,6 @@ symbolFileEnabled = b; } - @Override - public boolean isDefaultBootClassPath() { - return locations.isDefaultBootClassPath(); - } - public JavaFileObject getFileForInput(String name) { return getRegularFile(new File(name)); } @@ -579,15 +574,6 @@ } } - private String defaultEncodingName; - private String getDefaultEncodingName() { - if (defaultEncodingName == null) { - defaultEncodingName = - new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding(); - } - return defaultEncodingName; - } - public ClassLoader getClassLoader(Location location) { nullCheck(location); Iterable path = getLocation(location); diff -r f0f30d0016f4 -r 26e23230009a langtools/src/share/classes/com/sun/tools/javac/file/Locations.java --- a/langtools/src/share/classes/com/sun/tools/javac/file/Locations.java Fri Jun 13 11:21:39 2014 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/file/Locations.java Wed Jun 18 10:09:04 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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 @@ -22,12 +22,10 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package com.sun.tools.javac.file; +import java.io.File; import java.io.FileNotFoundException; -import java.util.Iterator; -import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; @@ -38,64 +36,72 @@ import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.zip.ZipFile; + +import javax.tools.JavaFileManager; import javax.tools.JavaFileManager.Location; +import javax.tools.StandardJavaFileManager; import javax.tools.StandardLocation; import com.sun.tools.javac.code.Lint; import com.sun.tools.javac.main.Option; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Log; -import com.sun.tools.javac.util.Options; import com.sun.tools.javac.util.StringUtils; -import javax.tools.JavaFileManager; -import javax.tools.StandardJavaFileManager; -import static javax.tools.StandardLocation.*; -import static com.sun.tools.javac.main.Option.*; +import static javax.tools.StandardLocation.CLASS_PATH; +import static javax.tools.StandardLocation.PLATFORM_CLASS_PATH; +import static javax.tools.StandardLocation.SOURCE_PATH; -/** This class converts command line arguments, environment variables - * and system properties (in File.pathSeparator-separated String form) - * into a boot class path, user class path, and source path (in - * {@code Collection} form). +import static com.sun.tools.javac.main.Option.BOOTCLASSPATH; +import static com.sun.tools.javac.main.Option.DJAVA_ENDORSED_DIRS; +import static com.sun.tools.javac.main.Option.DJAVA_EXT_DIRS; +import static com.sun.tools.javac.main.Option.ENDORSEDDIRS; +import static com.sun.tools.javac.main.Option.EXTDIRS; +import static com.sun.tools.javac.main.Option.XBOOTCLASSPATH; +import static com.sun.tools.javac.main.Option.XBOOTCLASSPATH_APPEND; +import static com.sun.tools.javac.main.Option.XBOOTCLASSPATH_PREPEND; + +/** + * This class converts command line arguments, environment variables and system properties (in + * File.pathSeparator-separated String form) into a boot class path, user class path, and source + * path (in {@code Collection} form). * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. + *

+ * This is NOT part of any supported API. If you write code that depends on this, you do so at + * your own risk. This code and its internal interfaces are subject to change or deletion without + * notice. */ public class Locations { - /** The log to use for warning output */ + /** + * The log to use for warning output + */ private Log log; - /** Collection of command-line options */ - private Options options; - - /** Handler for -Xlint options */ - private Lint lint; - - /** Access to (possibly cached) file info */ + /** + * Access to (possibly cached) file info + */ private FSInfo fsInfo; - /** Whether to warn about non-existent path elements */ + /** + * Whether to warn about non-existent path elements + */ private boolean warn; - // TODO: remove need for this - private boolean inited = false; // TODO? caching bad? - public Locations() { initHandlers(); } - public void update(Log log, Options options, Lint lint, FSInfo fsInfo) { + // could replace Lint by "boolean warn" + public void update(Log log, Lint lint, FSInfo fsInfo) { this.log = log; - this.options = options; - this.lint = lint; + warn = lint.isEnabled(Lint.LintCategory.PATH); this.fsInfo = fsInfo; } @@ -104,14 +110,14 @@ } public boolean isDefaultBootClassPath() { - BootClassPathLocationHandler h = - (BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH); + BootClassPathLocationHandler h + = (BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH); return h.isDefault(); } boolean isDefaultBootClassPathRtJar(File file) { - BootClassPathLocationHandler h = - (BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH); + BootClassPathLocationHandler h + = (BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH); return h.isDefaultRtJar(file); } @@ -127,6 +133,7 @@ /** * Split a path into its elements. Empty path elements will be ignored. + * * @param path The path to be split * @return The elements of the path */ @@ -135,12 +142,13 @@ } /** - * Split a path into its elements. If emptyPathDefault is not null, all - * empty elements in the path, including empty elements at either end of - * the path, will be replaced with the value of emptyPathDefault. + * Split a path into its elements. If emptyPathDefault is not null, all empty elements in the + * path, including empty elements at either end of the path, will be replaced with the value of + * emptyPathDefault. + * * @param path The path to be split - * @param emptyPathDefault The value to substitute for empty path elements, - * or null, to ignore empty path elements + * @param emptyPathDefault The value to substitute for empty path elements, or null, to ignore + * empty path elements * @return The elements of the path */ private static Iterable getPathEntries(String path, File emptyPathDefault) { @@ -148,33 +156,38 @@ int start = 0; while (start <= path.length()) { int sep = path.indexOf(File.pathSeparatorChar, start); - if (sep == -1) + if (sep == -1) { sep = path.length(); - if (start < sep) + } + if (start < sep) { entries.add(new File(path.substring(start, sep))); - else if (emptyPathDefault != null) + } else if (emptyPathDefault != null) { entries.add(emptyPathDefault); + } start = sep + 1; } return entries; } /** - * Utility class to help evaluate a path option. - * Duplicate entries are ignored, jar class paths can be expanded. + * Utility class to help evaluate a path option. Duplicate entries are ignored, jar class paths + * can be expanded. */ private class Path extends LinkedHashSet { + private static final long serialVersionUID = 0; private boolean expandJarClassPaths = false; - private Set canonicalValues = new HashSet<>(); + private final Set canonicalValues = new HashSet<>(); public Path expandJarClassPaths(boolean x) { expandJarClassPaths = x; return this; } - /** What to use when path element is the empty string */ + /** + * What to use when path element is the empty string + */ private File emptyPathDefault = null; public Path emptyPathDefault(File x) { @@ -182,15 +195,15 @@ return this; } - public Path() { super(); } - public Path addDirectories(String dirs, boolean warn) { boolean prev = expandJarClassPaths; expandJarClassPaths = true; try { - if (dirs != null) - for (File dir : getPathEntries(dirs)) + if (dirs != null) { + for (File dir : getPathEntries(dirs)) { addDirectory(dir, warn); + } + } return this; } finally { expandJarClassPaths = prev; @@ -203,19 +216,22 @@ private void addDirectory(File dir, boolean warn) { if (!dir.isDirectory()) { - if (warn) + if (warn) { log.warning(Lint.LintCategory.PATH, "dir.path.element.not.found", dir); + } return; } File[] files = dir.listFiles(); - if (files == null) + if (files == null) { return; + } for (File direntry : files) { - if (isArchive(direntry)) + if (isArchive(direntry)) { addFile(direntry, warn); + } } } @@ -232,8 +248,9 @@ public Path addFiles(Iterable files, boolean warn) { if (files != null) { - for (File file: files) + for (File file : files) { addFile(file, warn); + } } return this; } @@ -248,7 +265,7 @@ return; } - if (! fsInfo.exists(file)) { + if (!fsInfo.exists(file)) { /* No such file or directory exists */ if (warn) { log.warning(Lint.LintCategory.PATH, @@ -288,12 +305,13 @@ } /* Now what we have left is either a directory or a file name - conforming to archive naming convention */ + conforming to archive naming convention */ super.add(file); canonicalValues.add(canonFile); - if (expandJarClassPaths && fsInfo.isFile(file)) + if (expandJarClassPaths && fsInfo.isFile(file)) { addJarClassPath(file, warn); + } } // Adds referenced classpath elements from a jar's Class-Path @@ -302,7 +320,7 @@ // filenames, but if we do, we should redo all path-related code. private void addJarClassPath(File jarFile, boolean warn) { try { - for (File f: fsInfo.getJarClassPath(jarFile)) { + for (File f : fsInfo.getJarClassPath(jarFile)) { addFile(f, warn); } } catch (IOException e) { @@ -312,53 +330,56 @@ } /** - * Base class for handling support for the representation of Locations. - * Implementations are responsible for handling the interactions between - * the command line options for a location, and API access via setLocation. + * Base class for handling support for the representation of Locations. Implementations are + * responsible for handling the interactions between the command line options for a location, + * and API access via setLocation. + * * @see #initHandlers * @see #getHandler */ protected abstract class LocationHandler { + final Location location; final Set