OpenJDK / zgc / zgc
changeset 15387:dbafd8b0d8a2
Merge
author | lana |
---|---|
date | Sat, 26 Jan 2013 19:24:46 -0800 |
parents | cd29c25696e3 92bc08d96f0c |
children | f68bab9803a7 |
files | langtools/test/tools/javac/annotations/repeatingAnnotations/MissingContainedBy.java langtools/test/tools/javac/annotations/repeatingAnnotations/MissingContainerFor.java langtools/test/tools/javac/annotations/repeatingAnnotations/UseWrongContainedBy.java langtools/test/tools/javac/annotations/repeatingAnnotations/UseWrongContainerFor.java langtools/test/tools/javac/annotations/repeatingAnnotations/WrongContainedBy.java langtools/test/tools/javac/annotations/repeatingAnnotations/WrongContainerFor.java langtools/test/tools/javac/diags/examples/ContainedByDocumentedMismatch.java langtools/test/tools/javac/diags/examples/ContainedByInheritedMismatch.java langtools/test/tools/javac/diags/examples/ContainedByNoValue.java langtools/test/tools/javac/diags/examples/ContainedByNonDefault.java langtools/test/tools/javac/diags/examples/ContainedByRetentionMismatch.java langtools/test/tools/javac/diags/examples/ContainedByTargetMismatch.java langtools/test/tools/javac/diags/examples/ContainedByWrongValueType.java langtools/test/tools/javac/diags/examples/InferredDoNotConformToLower.java langtools/test/tools/javac/diags/examples/NoUniqueMaximalInstance.java langtools/test/tools/javac/diags/examples/WrongContainedBy.java langtools/test/tools/javac/diags/examples/WrongContainerFor.java langtools/test/tools/javac/lambda/MethodReference26.out langtools/test/tools/javac/lambda/TargetType06.out langtools/test/tools/javac/lambda/TargetType11.out langtools/test/tools/javac/lambda/TargetType45.out langtools/test/tools/javac/lambda/VoidCompatibility.out langtools/test/tools/javac/typeAnnotations/newlocations/BasicTest.java langtools/test/tools/javac/typeAnnotations/newlocations/BasicTest.out |
diffstat | 629 files changed, 30453 insertions(+), 2773 deletions(-) [+] |
line wrap: on
line diff
--- a/langtools/make/build.properties Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/make/build.properties Sat Jan 26 19:24:46 2013 -0800 @@ -29,18 +29,18 @@ # Override this path as needed, either on the command line or in # one of the standard user build.properties files (see build.xml) -# boot.java.home = /opt/jdk/1.6.0 +# boot.java.home = /opt/jdk/1.7.0 boot.java = ${boot.java.home}/bin/java boot.javac = ${boot.java.home}/bin/javac -boot.javac.source = 6 -boot.javac.target = 6 +boot.javac.source = 7 +boot.javac.target = 7 # This is the JDK used to run the product version of the tools, # for example, for testing. If you're building a complete JDK, specify that. # Override this path as needed, either on the command line or in # one of the standard user build.properties files (see build.xml) -# target.java.home = /opt/jdk/1.7.0 +# target.java.home = /opt/jdk/1.8.0 target.java = ${target.java.home}/bin/java # Version info -- override as needed @@ -161,6 +161,14 @@ # +sjavac.includes = \ + com/sun/tools/sjavac/ + +sjavac.tests = \ + tools/sjavac + +# + # The following files require the latest JDK to be available. # The API can be provided by using a suitable boot.java.home # or by setting import.jdk
--- a/langtools/make/build.xml Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/make/build.xml Sat Jan 26 19:24:46 2013 -0800 @@ -241,15 +241,15 @@ </target> <target name="build-bootstrap-tools" - depends="build-bootstrap-javac,build-bootstrap-javadoc,build-bootstrap-doclets,build-bootstrap-javah" + depends="build-bootstrap-javac,build-bootstrap-javadoc,build-bootstrap-doclets,build-bootstrap-javah,build-bootstrap-sjavac" /> <target name="build-all-tools" - depends="build-javac,build-javadoc,build-doclets,build-javah,build-javap" + depends="build-javac,build-javadoc,build-doclets,build-javah,build-javap,build-sjavac" /> <target name="build-all-classes" depends="build-bootstrap-javac,-create-import-jdk-stubs"> - <build-classes includes="${javac.includes} ${javadoc.includes} ${doclets.includes} ${javah.includes} ${javap.includes}"/> + <build-classes includes="${javac.includes} ${javadoc.includes} ${doclets.includes} ${javah.includes} ${javap.includes} ${sjavac.includes}"/> </target> <!-- clean --> @@ -656,6 +656,40 @@ <target name="javap" depends="build-javap,jtreg-javap,findbugs-javap"/> + <!-- + **** sjavac targets. + --> + + <target name="build-bootstrap-sjavac" + depends="-def-build-bootstrap-classes,-def-build-bootstrap-jar,-def-build-bootstrap-tool"> + <build-bootstrap-classes includes="${sjavac.includes}"/> + <build-bootstrap-jar name="sjavac" includes="${sjavac.includes}" + jarmainclass="com.sun.tools.sjavac.Main"/> + <build-bootstrap-tool name="sjavac"/> + </target> + + <target name="build-classes-sjavac" depends="build-classes-javac"> + <build-classes includes="${sjavac.includes}"/> + </target> + + <target name="build-sjavac" depends="build-classes-sjavac"> + <build-jar name="sjavac" includes="${sjavac.includes}" + jarmainclass="com.sun.tools.sjavac.Main" + jarclasspath="sjavac.jar"/> + <build-tool name="sjavac"/> + </target> + + <!-- (no javadoc for javap) --> + + <target name="jtreg-sjavac" depends="build-sjavac,-def-jtreg"> + <jtreg-tool name="sjavac" tests="${sjavac.tests}"/> + </target> + + <target name="findbugs-sjavac" depends="build-sjavac,-def-findbugs"> + <findbugs-tool name="sjavac"/> + </target> + + <target name="sjavac" depends="build-sjavac,jtreg-sjavac,findbugs-sjavac"/> <!-- **** Create import JDK stubs.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/com/sun/javadoc/AnnotatedType.java Sat Jan 26 19:24:46 2013 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2003, 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.javadoc; + + +/** + * Represents an annotated type. + * For example: + * <pre> + * {@code @NonNull String} + * {@code @Positive int} + * </pre> + * + * @author Mahmood Ali + * @since 1.8 + */ +public interface AnnotatedType extends Type { + + AnnotationDesc[] annotations(); + + Type underlyingType(); +}
--- a/langtools/src/share/classes/com/sun/javadoc/ExecutableMemberDoc.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/javadoc/ExecutableMemberDoc.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -88,6 +88,15 @@ Parameter[] parameters(); /** + * Get the receiver annotations of this executable element. + * Return an empty array if there are none. + * + * @return the receiver annotations of this executable element. + * @since 1.8 + */ + AnnotationDesc[] receiverAnnotations(); + + /** * Return the throws tags in this method. * * @return an array of ThrowTag containing all <code>@exception</code>
--- a/langtools/src/share/classes/com/sun/javadoc/Type.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/javadoc/Type.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -142,6 +142,16 @@ WildcardType asWildcardType(); /** + * Returns this type as a <code>AnnotatedType</code> if it represents + * an annotated type. + * + * @return a <code>AnnotatedType</code> if the type if an annotated type, + * or null if it is not + * @since 1.8 + */ + AnnotatedType asAnnotatedType(); + + /** * Return this type as an <code>AnnotationTypeDoc</code> if it represents * an annotation type. Array dimensions are ignored. *
--- a/langtools/src/share/classes/com/sun/javadoc/TypeVariable.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/javadoc/TypeVariable.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -55,4 +55,11 @@ * which this type variable is declared. */ ProgramElementDoc owner(); + + /** + * Get the annotations of this program element. + * Return an empty array if there are none. + */ + public AnnotationDesc[] annotations(); + }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/com/sun/source/tree/AnnotatedTypeTree.java Sat Jan 26 19:24:46 2013 -0800 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2008, 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.source.tree; + +import java.util.List; + +/** + * A tree node for an annotated type + * + * For example: + * <pre> + * {@code @}<em>annotationType String</em> + * {@code @}<em>annotationType</em> ( <em>arguments</em> ) <em>Date</em> + * </pre> + * + * @see "JSR 308: Annotations on Java Types" + * + * @author Mahmood Ali + * @since 1.8 + */ +public interface AnnotatedTypeTree extends ExpressionTree { + List<? extends AnnotationTree> getAnnotations(); + ExpressionTree getUnderlyingType(); +}
--- a/langtools/src/share/classes/com/sun/source/tree/MethodTree.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/source/tree/MethodTree.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -52,6 +52,7 @@ Tree getReturnType(); List<? extends TypeParameterTree> getTypeParameters(); List<? extends VariableTree> getParameters(); + VariableTree getReceiverParameter(); List<? extends ExpressionTree> getThrows(); BlockTree getBody(); Tree getDefaultValue(); // for annotation types
--- a/langtools/src/share/classes/com/sun/source/tree/Tree.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/source/tree/Tree.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -46,12 +46,21 @@ */ public enum Kind { + ANNOTATED_TYPE(AnnotatedTypeTree.class), + /** - * Used for instances of {@link AnnotationTree}. + * Used for instances of {@link AnnotationTree} + * representing declaration annotations. */ ANNOTATION(AnnotationTree.class), /** + * Used for instances of {@link AnnotationTree} + * representing type annotations. + */ + TYPE_ANNOTATION(AnnotationTree.class), + + /** * Used for instances of {@link ArrayAccessTree}. */ ARRAY_ACCESS(ArrayAccessTree.class),
--- a/langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -57,6 +57,7 @@ * @since 1.6 */ public interface TreeVisitor<R,P> { + R visitAnnotatedType(AnnotatedTypeTree node, P p); R visitAnnotation(AnnotationTree node, P p); R visitMethodInvocation(MethodInvocationTree node, P p); R visitAssert(AssertTree node, P p);
--- a/langtools/src/share/classes/com/sun/source/tree/TypeParameterTree.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/source/tree/TypeParameterTree.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -47,4 +47,5 @@ public interface TypeParameterTree extends Tree { Name getName(); List<? extends Tree> getBounds(); + List<? extends AnnotationTree> getAnnotations(); }
--- a/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -260,6 +260,10 @@ return defaultAction(node, p); } + public R visitAnnotatedType(AnnotatedTypeTree node, P p) { + return defaultAction(node, p); + } + public R visitErroneous(ErroneousTree node, P p) { return defaultAction(node, p); }
--- a/langtools/src/share/classes/com/sun/source/util/TaskEvent.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/source/util/TaskEvent.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -60,7 +60,7 @@ **/ GENERATE, /** - * For events relating to overall annotaion processing. + * For events relating to overall annotation processing. **/ ANNOTATION_PROCESSING, /**
--- a/langtools/src/share/classes/com/sun/source/util/TreeScanner.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/source/util/TreeScanner.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -138,6 +138,7 @@ r = scanAndReduce(node.getReturnType(), p, r); r = scanAndReduce(node.getTypeParameters(), p, r); r = scanAndReduce(node.getParameters(), p, r); + r = scanAndReduce(node.getReceiverParameter(), p, r); r = scanAndReduce(node.getThrows(), p, r); r = scanAndReduce(node.getBody(), p, r); r = scanAndReduce(node.getDefaultValue(), p, r); @@ -376,7 +377,8 @@ } public R visitTypeParameter(TypeParameterTree node, P p) { - R r = scan(node.getBounds(), p); + R r = scan(node.getAnnotations(), p); + r = scanAndReduce(node.getBounds(), p, r); return r; } @@ -394,6 +396,12 @@ return r; } + public R visitAnnotatedType(AnnotatedTypeTree node, P p) { + R r = scan(node.getAnnotations(), p); + r = scanAndReduce(node.getUnderlyingType(), p, r); + return r; + } + public R visitOther(Tree node, P p) { return null; }
--- a/langtools/src/share/classes/com/sun/tools/classfile/Attribute.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/classfile/Attribute.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -56,6 +56,8 @@ public static final String RuntimeInvisibleAnnotations = "RuntimeInvisibleAnnotations"; public static final String RuntimeVisibleParameterAnnotations = "RuntimeVisibleParameterAnnotations"; public static final String RuntimeInvisibleParameterAnnotations = "RuntimeInvisibleParameterAnnotations"; + public static final String RuntimeVisibleTypeAnnotations = "RuntimeVisibleTypeAnnotations"; + public static final String RuntimeInvisibleTypeAnnotations = "RuntimeInvisibleTypeAnnotations"; public static final String Signature = "Signature"; public static final String SourceDebugExtension = "SourceDebugExtension"; public static final String SourceFile = "SourceFile"; @@ -120,6 +122,8 @@ standardAttributes.put(RuntimeInvisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations_attribute.class); standardAttributes.put(RuntimeVisibleAnnotations, RuntimeVisibleAnnotations_attribute.class); standardAttributes.put(RuntimeVisibleParameterAnnotations, RuntimeVisibleParameterAnnotations_attribute.class); + standardAttributes.put(RuntimeVisibleTypeAnnotations, RuntimeVisibleTypeAnnotations_attribute.class); + standardAttributes.put(RuntimeInvisibleTypeAnnotations, RuntimeInvisibleTypeAnnotations_attribute.class); standardAttributes.put(Signature, Signature_attribute.class); standardAttributes.put(SourceID, SourceID_attribute.class); } @@ -178,6 +182,8 @@ R visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, P p); R visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, P p); R visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, P p); + R visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, P p); + R visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, P p); R visitSignature(Signature_attribute attr, P p); R visitSourceDebugExtension(SourceDebugExtension_attribute attr, P p); R visitSourceFile(SourceFile_attribute attr, P p);
--- a/langtools/src/share/classes/com/sun/tools/classfile/ClassWriter.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/classfile/ClassWriter.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -498,6 +498,16 @@ return null; } + public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, ClassOutputStream out) { + annotationWriter.write(attr.annotations, out); + return null; + } + + public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, ClassOutputStream out) { + annotationWriter.write(attr.annotations, out); + return null; + } + public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, ClassOutputStream out) { out.writeByte(attr.parameter_annotations.length); for (Annotation[] annos: attr.parameter_annotations) @@ -657,6 +667,12 @@ write(anno, out); } + public void write(TypeAnnotation[] annos, ClassOutputStream out) { + out.writeShort(annos.length); + for (TypeAnnotation anno: annos) + write(anno, out); + } + public void write(Annotation anno, ClassOutputStream out) { out.writeShort(anno.type_index); out.writeShort(anno.element_value_pairs.length); @@ -664,6 +680,11 @@ write(p, out); } + public void write(TypeAnnotation anno, ClassOutputStream out) { + write(anno.position, out); + write(anno.annotation, out); + } + public void write(element_value_pair pair, ClassOutputStream out) { out.writeShort(pair.element_name_index); write(pair.value, out); @@ -702,5 +723,89 @@ return null; } + // TODO: Move this to TypeAnnotation to be closer with similar logic? + private void write(TypeAnnotation.Position p, ClassOutputStream out) { + out.writeByte(p.type.targetTypeValue()); + switch (p.type) { + // type cast + case CAST: + // instanceof + case INSTANCEOF: + // new expression + case NEW: + out.writeShort(p.offset); + break; + // local variable + case LOCAL_VARIABLE: + // resource variable + case RESOURCE_VARIABLE: + int table_length = p.lvarOffset.length; + out.writeShort(table_length); + for (int i = 0; i < table_length; ++i) { + out.writeShort(1); // for table length + out.writeShort(p.lvarOffset[i]); + out.writeShort(p.lvarLength[i]); + out.writeShort(p.lvarIndex[i]); + } + break; + // exception parameter + case EXCEPTION_PARAMETER: + out.writeByte(p.exception_index); + break; + // method receiver + case METHOD_RECEIVER: + // Do nothing + break; + // type parameters + case CLASS_TYPE_PARAMETER: + case METHOD_TYPE_PARAMETER: + out.writeByte(p.parameter_index); + break; + // type parameters bounds + case CLASS_TYPE_PARAMETER_BOUND: + case METHOD_TYPE_PARAMETER_BOUND: + out.writeByte(p.parameter_index); + out.writeByte(p.bound_index); + break; + // class extends or implements clause + case CLASS_EXTENDS: + out.writeByte(p.type_index); + break; + // throws + case THROWS: + out.writeByte(p.type_index); + break; + // method parameter + case METHOD_FORMAL_PARAMETER: + out.writeByte(p.parameter_index); + break; + // method/constructor/reference type argument + case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: + case METHOD_INVOCATION_TYPE_ARGUMENT: + case METHOD_REFERENCE_TYPE_ARGUMENT: + out.writeShort(p.offset); + out.writeByte(p.type_index); + break; + // We don't need to worry about these + case METHOD_RETURN: + case FIELD: + break; + // lambda formal parameter + case LAMBDA_FORMAL_PARAMETER: + out.writeByte(p.parameter_index); + break; + case UNKNOWN: + throw new AssertionError("ClassWriter: UNKNOWN target type should never occur!"); + default: + throw new AssertionError("ClassWriter: Unknown target type for position: " + p); + } + + { // Append location data for generics/arrays. + // TODO: check for overrun? + out.writeByte((byte)p.location.size()); + for (int i : TypeAnnotation.Position.getBinaryFromTypePath(p.location)) + out.writeByte((byte)i); + } + } } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/com/sun/tools/classfile/RuntimeInvisibleTypeAnnotations_attribute.java Sat Jan 26 19:24:46 2013 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2007, 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.classfile; + +import java.io.IOException; + +/** + * See JSR 308 specification, Section 3. + * + * <p><b>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.</b> + */ +public class RuntimeInvisibleTypeAnnotations_attribute extends RuntimeTypeAnnotations_attribute { + RuntimeInvisibleTypeAnnotations_attribute(ClassReader cr, int name_index, int length) + throws IOException, Annotation.InvalidAnnotation { + super(cr, name_index, length); + } + + public RuntimeInvisibleTypeAnnotations_attribute(ConstantPool cp, TypeAnnotation[] annotations) + throws ConstantPoolException { + this(cp.getUTF8Index(Attribute.RuntimeInvisibleTypeAnnotations), annotations); + } + + public RuntimeInvisibleTypeAnnotations_attribute(int name_index, TypeAnnotation[] annotations) { + super(name_index, annotations); + } + + public <R, P> R accept(Visitor<R, P> visitor, P p) { + return visitor.visitRuntimeInvisibleTypeAnnotations(this, p); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/com/sun/tools/classfile/RuntimeTypeAnnotations_attribute.java Sat Jan 26 19:24:46 2013 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2007, 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.classfile; + +import java.io.IOException; + +/** + * See JSR 308 specification, Section 3. + * + * <p><b>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.</b> + */ +public abstract class RuntimeTypeAnnotations_attribute extends Attribute { + protected RuntimeTypeAnnotations_attribute(ClassReader cr, int name_index, int length) + throws IOException, Annotation.InvalidAnnotation { + super(name_index, length); + int num_annotations = cr.readUnsignedShort(); + annotations = new TypeAnnotation[num_annotations]; + for (int i = 0; i < annotations.length; i++) + annotations[i] = new TypeAnnotation(cr); + } + + protected RuntimeTypeAnnotations_attribute(int name_index, TypeAnnotation[] annotations) { + super(name_index, length(annotations)); + this.annotations = annotations; + } + + private static int length(TypeAnnotation[] annos) { + int n = 2; + for (TypeAnnotation anno: annos) + n += anno.length(); + return n; + } + + public final TypeAnnotation[] annotations; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/com/sun/tools/classfile/RuntimeVisibleTypeAnnotations_attribute.java Sat Jan 26 19:24:46 2013 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2007, 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.classfile; + +import java.io.IOException; + +/** + * See JSR 308 specification, Section 3. + * + * <p><b>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.</b> + */ +public class RuntimeVisibleTypeAnnotations_attribute extends RuntimeTypeAnnotations_attribute { + RuntimeVisibleTypeAnnotations_attribute(ClassReader cr, int name_index, int length) + throws IOException, Annotation.InvalidAnnotation { + super(cr, name_index, length); + } + + public RuntimeVisibleTypeAnnotations_attribute(ConstantPool cp, TypeAnnotation[] annotations) + throws ConstantPoolException { + this(cp.getUTF8Index(Attribute.RuntimeVisibleTypeAnnotations), annotations); + } + + public RuntimeVisibleTypeAnnotations_attribute(int name_index, TypeAnnotation[] annotations) { + super(name_index, annotations); + } + + public <R, P> R accept(Visitor<R, P> visitor, P p) { + return visitor.visitRuntimeVisibleTypeAnnotations(this, p); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/com/sun/tools/classfile/TypeAnnotation.java Sat Jan 26 19:24:46 2013 -0800 @@ -0,0 +1,656 @@ +/* + * 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.classfile; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import com.sun.tools.classfile.TypeAnnotation.Position.TypePathEntry; + +/** + * See JSR 308 specification, Section 3. + * + * <p><b>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.</b> + */ +public class TypeAnnotation { + TypeAnnotation(ClassReader cr) throws IOException, Annotation.InvalidAnnotation { + constant_pool = cr.getConstantPool(); + position = read_position(cr); + annotation = new Annotation(cr); + } + + public TypeAnnotation(ConstantPool constant_pool, + Annotation annotation, Position position) { + this.constant_pool = constant_pool; + this.position = position; + this.annotation = annotation; + } + + public int length() { + int n = annotation.length(); + n += position_length(position); + return n; + } + + @Override + public String toString() { + try { + return "@" + constant_pool.getUTF8Value(annotation.type_index).toString().substring(1) + + " pos: " + position.toString(); + } catch (Exception e) { + e.printStackTrace(); + return e.toString(); + } + } + + public final ConstantPool constant_pool; + public final Position position; + public final Annotation annotation; + + private static Position read_position(ClassReader cr) throws IOException, Annotation.InvalidAnnotation { + // Copied from ClassReader + int tag = cr.readUnsignedByte(); // TargetType tag is a byte + if (!TargetType.isValidTargetTypeValue(tag)) + throw new Annotation.InvalidAnnotation("TypeAnnotation: Invalid type annotation target type value: " + String.format("0x%02X", tag)); + + TargetType type = TargetType.fromTargetTypeValue(tag); + + Position position = new Position(); + position.type = type; + + switch (type) { + // type cast + case CAST: + // instanceof + case INSTANCEOF: + // new expression + case NEW: + position.offset = cr.readUnsignedShort(); + break; + // local variable + case LOCAL_VARIABLE: + // resource variable + case RESOURCE_VARIABLE: + int table_length = cr.readUnsignedShort(); + position.lvarOffset = new int[table_length]; + position.lvarLength = new int[table_length]; + position.lvarIndex = new int[table_length]; + for (int i = 0; i < table_length; ++i) { + position.lvarOffset[i] = cr.readUnsignedShort(); + position.lvarLength[i] = cr.readUnsignedShort(); + position.lvarIndex[i] = cr.readUnsignedShort(); + } + break; + // exception parameter + case EXCEPTION_PARAMETER: + position.exception_index = cr.readUnsignedByte(); + break; + // method receiver + case METHOD_RECEIVER: + // Do nothing + break; + // type parameter + case CLASS_TYPE_PARAMETER: + case METHOD_TYPE_PARAMETER: + position.parameter_index = cr.readUnsignedByte(); + break; + // type parameter bound + case CLASS_TYPE_PARAMETER_BOUND: + case METHOD_TYPE_PARAMETER_BOUND: + position.parameter_index = cr.readUnsignedByte(); + position.bound_index = cr.readUnsignedByte(); + break; + // class extends or implements clause + case CLASS_EXTENDS: + int in = cr.readUnsignedShort(); + if (in == 0xFFFF) + in = -1; + position.type_index = in; + break; + // throws + case THROWS: + position.type_index = cr.readUnsignedShort(); + break; + // method parameter + case METHOD_FORMAL_PARAMETER: + position.parameter_index = cr.readUnsignedByte(); + break; + // method/constructor/reference type argument + case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: + case METHOD_INVOCATION_TYPE_ARGUMENT: + case METHOD_REFERENCE_TYPE_ARGUMENT: + position.offset = cr.readUnsignedShort(); + position.type_index = cr.readUnsignedByte(); + break; + // We don't need to worry about these + case METHOD_RETURN: + case FIELD: + break; + // lambda formal parameter + case LAMBDA_FORMAL_PARAMETER: + position.parameter_index = cr.readUnsignedByte(); + break; + case UNKNOWN: + throw new AssertionError("TypeAnnotation: UNKNOWN target type should never occur!"); + default: + throw new AssertionError("TypeAnnotation: Unknown target type: " + type); + } + + { // Write type path + int len = cr.readUnsignedByte(); + List<Integer> loc = new ArrayList<Integer>(len); + for (int i = 0; i < len * TypePathEntry.bytesPerEntry; ++i) + loc.add(cr.readUnsignedByte()); + position.location = Position.getTypePathFromBinary(loc); + } + return position; + } + + private static int position_length(Position pos) { + int n = 0; + n += 1; // TargetType tag is a byte + switch (pos.type) { + // type cast + case CAST: + // instanceof + case INSTANCEOF: + // new expression + case NEW: + n += 2; + break; + // local variable + case LOCAL_VARIABLE: + // resource variable + case RESOURCE_VARIABLE: + n += 2; // table_length; + int table_length = pos.lvarOffset.length; + n += 2 * table_length; // offset + n += 2 * table_length; // length; + n += 2 * table_length; // index + break; + // exception parameter + case EXCEPTION_PARAMETER: + n += 1; // exception_index + break; + // method receiver + case METHOD_RECEIVER: + // Do nothing + break; + // type parameter + case CLASS_TYPE_PARAMETER: + case METHOD_TYPE_PARAMETER: + n += 1; // parameter_index; + break; + // type parameter bound + case CLASS_TYPE_PARAMETER_BOUND: + case METHOD_TYPE_PARAMETER_BOUND: + n += 1; // parameter_index + n += 1; // bound_index + break; + // class extends or implements clause + case CLASS_EXTENDS: + n += 2; // type_index + break; + // throws + case THROWS: + n += 2; // type_index + break; + // method parameter + case METHOD_FORMAL_PARAMETER: + n += 1; // parameter_index + break; + // method/constructor/reference type argument + case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: + case METHOD_INVOCATION_TYPE_ARGUMENT: + case METHOD_REFERENCE_TYPE_ARGUMENT: + n += 2; // offset + n += 1; // type index + break; + // We don't need to worry about these + case METHOD_RETURN: + case FIELD: + break; + // lambda formal parameter + case LAMBDA_FORMAL_PARAMETER: + n += 1; // parameter_index + break; + case UNKNOWN: + throw new AssertionError("TypeAnnotation: UNKNOWN target type should never occur!"); + default: + throw new AssertionError("TypeAnnotation: Unknown target type: " + pos.type); + } + + { + n += 1; // length + n += TypePathEntry.bytesPerEntry * pos.location.size(); // bytes for actual array + } + + return n; + } + + // Code duplicated from com.sun.tools.javac.code.TypeAnnotationPosition + public static class Position { + public enum TypePathEntryKind { + ARRAY(0), + INNER_TYPE(1), + WILDCARD(2), + TYPE_ARGUMENT(3); + + public final int tag; + + private TypePathEntryKind(int tag) { + this.tag = tag; + } + } + + public static class TypePathEntry { + /** The fixed number of bytes per TypePathEntry. */ + public static final int bytesPerEntry = 2; + + public final TypePathEntryKind tag; + public final int arg; + + public static final TypePathEntry ARRAY = new TypePathEntry(TypePathEntryKind.ARRAY); + public static final TypePathEntry INNER_TYPE = new TypePathEntry(TypePathEntryKind.INNER_TYPE); + public static final TypePathEntry WILDCARD = new TypePathEntry(TypePathEntryKind.WILDCARD); + + private TypePathEntry(TypePathEntryKind tag) { + if (!(tag == TypePathEntryKind.ARRAY || + tag == TypePathEntryKind.INNER_TYPE || + tag == TypePathEntryKind.WILDCARD)) { + throw new AssertionError("Invalid TypePathEntryKind: " + tag); + } + this.tag = tag; + this.arg = 0; + } + + public TypePathEntry(TypePathEntryKind tag, int arg) { + if (tag != TypePathEntryKind.TYPE_ARGUMENT) { + throw new AssertionError("Invalid TypePathEntryKind: " + tag); + } + this.tag = tag; + this.arg = arg; + } + + public static TypePathEntry fromBinary(int tag, int arg) { + if (arg != 0 && tag != TypePathEntryKind.TYPE_ARGUMENT.tag) { + throw new AssertionError("Invalid TypePathEntry tag/arg: " + tag + "/" + arg); + } + switch (tag) { + case 0: + return ARRAY; + case 1: + return INNER_TYPE; + case 2: + return WILDCARD; + case 3: + return new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, arg); + default: + throw new AssertionError("Invalid TypePathEntryKind tag: " + tag); + } + } + + @Override + public String toString() { + return tag.toString() + + (tag == TypePathEntryKind.TYPE_ARGUMENT ? ("(" + arg + ")") : ""); + } + + @Override + public boolean equals(Object other) { + if (! (other instanceof TypePathEntry)) { + return false; + } + TypePathEntry tpe = (TypePathEntry) other; + return this.tag == tpe.tag && this.arg == tpe.arg; + } + + @Override + public int hashCode() { + return this.tag.hashCode() * 17 + this.arg; + } + } + + public TargetType type = TargetType.UNKNOWN; + + // For generic/array types. + // TODO: or should we use null? Noone will use this object. + public List<TypePathEntry> location = new ArrayList<TypePathEntry>(0); + + // Tree position. + public int pos = -1; + + // For typecasts, type tests, new (and locals, as start_pc). + public boolean isValidOffset = false; + public int offset = -1; + + // For locals. arrays same length + public int[] lvarOffset = null; + public int[] lvarLength = null; + public int[] lvarIndex = null; + + // For type parameter bound + public int bound_index = Integer.MIN_VALUE; + + // For type parameter and method parameter + public int parameter_index = Integer.MIN_VALUE; + + // For class extends, implements, and throws clauses + public int type_index = Integer.MIN_VALUE; + + // For exception parameters, index into exception table + public int exception_index = Integer.MIN_VALUE; + + public Position() {} + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append('['); + sb.append(type); + + switch (type) { + // type cast + case CAST: + // instanceof + case INSTANCEOF: + // new expression + case NEW: + sb.append(", offset = "); + sb.append(offset); + break; + // local variable + case LOCAL_VARIABLE: + // resource variable + case RESOURCE_VARIABLE: + if (lvarOffset == null) { + sb.append(", lvarOffset is null!"); + break; + } + sb.append(", {"); + for (int i = 0; i < lvarOffset.length; ++i) { + if (i != 0) sb.append("; "); + sb.append("start_pc = "); + sb.append(lvarOffset[i]); + sb.append(", length = "); + sb.append(lvarLength[i]); + sb.append(", index = "); + sb.append(lvarIndex[i]); + } + sb.append("}"); + break; + // method receiver + case METHOD_RECEIVER: + // Do nothing + break; + // type parameter + case CLASS_TYPE_PARAMETER: + case METHOD_TYPE_PARAMETER: + sb.append(", param_index = "); + sb.append(parameter_index); + break; + // type parameter bound + case CLASS_TYPE_PARAMETER_BOUND: + case METHOD_TYPE_PARAMETER_BOUND: + sb.append(", param_index = "); + sb.append(parameter_index); + sb.append(", bound_index = "); + sb.append(bound_index); + break; + // class extends or implements clause + case CLASS_EXTENDS: + sb.append(", type_index = "); + sb.append(type_index); + break; + // throws + case THROWS: + sb.append(", type_index = "); + sb.append(type_index); + break; + // exception parameter + case EXCEPTION_PARAMETER: + sb.append(", exception_index = "); + sb.append(exception_index); + break; + // method parameter + case METHOD_FORMAL_PARAMETER: + sb.append(", param_index = "); + sb.append(parameter_index); + break; + // method/constructor/reference type argument + case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: + case METHOD_INVOCATION_TYPE_ARGUMENT: + case METHOD_REFERENCE_TYPE_ARGUMENT: + sb.append(", offset = "); + sb.append(offset); + sb.append(", type_index = "); + sb.append(type_index); + break; + // We don't need to worry about these + case METHOD_RETURN: + case FIELD: + break; + // lambda formal parameter + case LAMBDA_FORMAL_PARAMETER: + // TODO: also needs an offset? + sb.append(", param_index = "); + sb.append(parameter_index); + break; + case UNKNOWN: + sb.append(", position UNKNOWN!"); + break; + default: + throw new AssertionError("Unknown target type: " + type); + } + + // Append location data for generics/arrays. + if (!location.isEmpty()) { + sb.append(", location = ("); + sb.append(location); + sb.append(")"); + } + + sb.append(", pos = "); + sb.append(pos); + + sb.append(']'); + return sb.toString(); + } + + /** + * Indicates whether the target tree of the annotation has been optimized + * away from classfile or not. + * @return true if the target has not been optimized away + */ + public boolean emitToClassfile() { + return !type.isLocal() || isValidOffset; + } + + /** + * Decode the binary representation for a type path and set + * the {@code location} field. + * + * @param list The bytecode representation of the type path. + */ + public static List<TypePathEntry> getTypePathFromBinary(List<Integer> list) { + List<TypePathEntry> loc = new ArrayList<TypePathEntry>(list.size() / TypePathEntry.bytesPerEntry); + int idx = 0; + while (idx < list.size()) { + if (idx + 1 == list.size()) { + throw new AssertionError("Could not decode type path: " + list); + } + loc.add(TypePathEntry.fromBinary(list.get(idx), list.get(idx + 1))); + idx += 2; + } + return loc; + } + + public static List<Integer> getBinaryFromTypePath(List<TypePathEntry> locs) { + List<Integer> loc = new ArrayList<Integer>(locs.size() * TypePathEntry.bytesPerEntry); + for (TypePathEntry tpe : locs) { + loc.add(tpe.tag.tag); + loc.add(tpe.arg); + } + return loc; + } + } + + // Code duplicated from com.sun.tools.javac.code.TargetType + // The IsLocal flag could be removed here. + public enum TargetType { + /** For annotations on a class type parameter declaration. */ + CLASS_TYPE_PARAMETER(0x00), + + /** For annotations on a method type parameter declaration. */ + METHOD_TYPE_PARAMETER(0x01), + + /** For annotations on the type of an "extends" or "implements" clause. */ + CLASS_EXTENDS(0x10), + + /** For annotations on a bound of a type parameter of a class. */ + CLASS_TYPE_PARAMETER_BOUND(0x11), + + /** For annotations on a bound of a type parameter of a method. */ + METHOD_TYPE_PARAMETER_BOUND(0x12), + + /** For annotations on a field. */ + FIELD(0x13), + + /** For annotations on a method return type. */ + METHOD_RETURN(0x14), + + /** For annotations on the method receiver. */ + METHOD_RECEIVER(0x15), + + /** For annotations on a method parameter. */ + METHOD_FORMAL_PARAMETER(0x16), + + /** For annotations on a throws clause in a method declaration. */ + THROWS(0x17), + + /** For annotations on a local variable. */ + LOCAL_VARIABLE(0x40, true), + + /** For annotations on a resource variable. */ + RESOURCE_VARIABLE(0x41, true), + + /** For annotations on an exception parameter. */ + EXCEPTION_PARAMETER(0x42, true), + + /** For annotations on a typecast. */ + CAST(0x43, true), + + /** For annotations on a type test. */ + INSTANCEOF(0x44, true), + + /** For annotations on an object creation expression. */ + NEW(0x45, true), + + /** For annotations on a type argument of an object creation expression. */ + CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(0x46, true), + + /** For annotations on a type argument of a method call. */ + METHOD_INVOCATION_TYPE_ARGUMENT(0x47, true), + + /** For annotations on a lambda parameter type. */ + LAMBDA_FORMAL_PARAMETER(0x48, true), + + /** For annotations on a method reference. */ + METHOD_REFERENCE(0x49, true), + + /** For annotations on a type argument of a method reference. */ + METHOD_REFERENCE_TYPE_ARGUMENT(0x50, true), + + /** For annotations with an unknown target. */ + UNKNOWN(0xFF); + + private static final int MAXIMUM_TARGET_TYPE_VALUE = 0x50; + + private final int targetTypeValue; + private final boolean isLocal; + + private TargetType(int targetTypeValue) { + this(targetTypeValue, false); + } + + private TargetType(int targetTypeValue, boolean isLocal) { + if (targetTypeValue < 0 + || targetTypeValue > 255) + throw new AssertionError("Attribute type value needs to be an unsigned byte: " + String.format("0x%02X", targetTypeValue)); + this.targetTypeValue = targetTypeValue; + this.isLocal = isLocal; + } + + /** + * Returns whether or not this TargetType represents an annotation whose + * target is exclusively a tree in a method body + * + * Note: wildcard bound targets could target a local tree and a class + * member declaration signature tree + */ + public boolean isLocal() { + return isLocal; + } + + public int targetTypeValue() { + return this.targetTypeValue; + } + + private static final TargetType[] targets; + + static { + 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) + throw new AssertionError("Unknown TargetType: " + tag); + return targets[tag]; + } + } +}
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractExecutableMemberWriter.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractExecutableMemberWriter.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -139,6 +139,15 @@ } } + protected void addReceiverAnnotations(ExecutableMemberDoc member, + Content tree) { + if (member.receiverAnnotations().length > 0) { + tree.addContent(writer.getSpace()); + writer.addReceiverAnnotationInfo(member, tree); + } + } + + /** * Add all the parameters for the executable member. *
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConfigurationImpl.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConfigurationImpl.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -33,8 +33,10 @@ import com.sun.javadoc.*; import com.sun.tools.doclets.internal.toolkit.*; import com.sun.tools.doclets.internal.toolkit.util.*; +import com.sun.tools.doclint.DocLint; import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.util.Context; +import com.sun.tools.javadoc.RootDocImpl; /** * Configure the output based on the command line options. @@ -172,6 +174,11 @@ public boolean createoverview = false; /** + * Collected set of doclint options + */ + public Set<String> doclintOpts = new LinkedHashSet<String>(); + + /** * Unique Resource Handler for this package. */ public final MessageRetriever standardmessage; @@ -255,6 +262,10 @@ nooverview = true; } else if (opt.equals("-overview")) { overview = true; + } else if (opt.equals("-xdoclint")) { + doclintOpts.add(null); + } else if (opt.startsWith("-xdoclint:")) { + doclintOpts.add(opt.substring(opt.indexOf(":") + 1)); } } if (root.specifiedClasses().length > 0) { @@ -270,6 +281,10 @@ } setCreateOverview(); setTopFile(root); + + if (root instanceof RootDocImpl) { + ((RootDocImpl) root).initDocLint(doclintOpts); + } } /** @@ -303,7 +318,9 @@ option.equals("-serialwarn") || option.equals("-use") || option.equals("-nonavbar") || - option.equals("-nooverview")) { + option.equals("-nooverview") || + option.equals("-xdoclint") || + option.startsWith("-xdoclint:")) { return 1; } else if (option.equals("-help")) { System.out.println(getText("doclet.usage")); @@ -410,6 +427,16 @@ return false; } noindex = true; + } else if (opt.startsWith("-xdoclint:")) { + if (opt.contains("/")) { + reporter.printError(getText("doclet.Option_doclint_no_qualifiers")); + return false; + } + if (!DocLint.isValidOption( + opt.replace("-xdoclint:", DocLint.XMSGS_CUSTOM_PREFIX))) { + reporter.printError(getText("doclet.Option_doclint_invalid_arg")); + return false; + } } } return true; @@ -506,8 +533,8 @@ */ @Override public Locale getLocale() { - if (root instanceof com.sun.tools.javadoc.RootDocImpl) - return ((com.sun.tools.javadoc.RootDocImpl)root).getLocale(); + if (root instanceof RootDocImpl) + return ((RootDocImpl)root).getLocale(); else return Locale.getDefault(); } @@ -518,8 +545,8 @@ @Override public JavaFileManager getFileManager() { if (fileManager == null) { - if (root instanceof com.sun.tools.javadoc.RootDocImpl) - fileManager = ((com.sun.tools.javadoc.RootDocImpl)root).getFileManager(); + if (root instanceof RootDocImpl) + fileManager = ((RootDocImpl) root).getFileManager(); else fileManager = new JavacFileManager(new Context(), false, null); } @@ -527,4 +554,12 @@ } private JavaFileManager fileManager; + + @Override + public boolean showMessage(SourcePosition pos, String key) { + if (root instanceof RootDocImpl) { + return pos == null || ((RootDocImpl) root).showTagMessages(); + } + return true; + } }
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -137,6 +137,7 @@ addName(constructor.name(), pre); } addParameters(constructor, pre); + writer.addReceiverAnnotationInfo(constructor, pre); addExceptions(constructor, pre); return pre; }
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -1730,6 +1730,17 @@ } /** + * Add the annotation types of the executable receiver. + * + * @param method the executable to write the receiver annotations for. + * @param htmltree the documentation tree to which the annotation info will be + * added + */ + public void addReceiverAnnotationInfo(ExecutableMemberDoc method, Content htmltree) { + addAnnotationInfo(method, method.receiverAnnotations(), htmltree); + } + + /** * Adds the annotatation types for the given doc. * * @param doc the package to write annotations for @@ -1799,6 +1810,26 @@ * documented. */ private List<String> getAnnotations(int indent, AnnotationDesc[] descList, boolean linkBreak) { + return getAnnotations(indent, descList, linkBreak, true); + } + + /** + * Return the string representations of the annotation types for + * the given doc. + * + * A {@code null} {@code elementType} indicates that all the + * annotations should be returned without any filtering. + * + * @param indent the number of extra spaces to indent the annotations. + * @param descList the array of {@link AnnotationDesc}. + * @param linkBreak if true, add new line between each member value. + * @param elementType the type of targeted element (used for filtering + * type annotations from declaration annotations) + * @return an array of strings representing the annotations being + * documented. + */ + public List<String> getAnnotations(int indent, AnnotationDesc[] descList, boolean linkBreak, + boolean isJava5DeclarationLocation) { List<String> results = new ArrayList<String>(); StringBuilder annotation; for (int i = 0; i < descList.length; i++) { @@ -1812,6 +1843,11 @@ (!isAnnotationDocumented && !isContainerDocumented)) { continue; } + /* TODO: check logic here to correctly handle declaration + * and type annotations. + if (Util.isDeclarationAnnotation(annotationDoc, isJava5DeclarationLocation)) { + continue; + }*/ annotation = new StringBuilder(); isAnnotationDocumented = false; LinkInfoImpl linkInfo = new LinkInfoImpl(configuration,
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkFactoryImpl.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkFactoryImpl.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,6 +25,8 @@ package com.sun.tools.doclets.formats.html; +import java.util.List; + import com.sun.javadoc.*; import com.sun.tools.doclets.internal.toolkit.*; import com.sun.tools.doclets.internal.toolkit.util.*; @@ -123,11 +125,50 @@ typeLinkInfo.excludeTypeBounds = linkInfo.excludeTypeBounds; typeLinkInfo.excludeTypeParameterLinks = linkInfo.excludeTypeParameterLinks; typeLinkInfo.linkToSelf = linkInfo.linkToSelf; + typeLinkInfo.isJava5DeclarationLocation = false; LinkOutput output = getLinkOutput(typeLinkInfo); ((LinkInfoImpl) linkInfo).displayLength += typeLinkInfo.displayLength; return output; } + protected LinkOutput getTypeAnnotationLink(LinkInfo linkInfo, + AnnotationDesc annotation) { + throw new RuntimeException("Not implemented yet!"); + } + + public LinkOutput getTypeAnnotationLinks(LinkInfo linkInfo) { + LinkOutput output = getOutputInstance(); + AnnotationDesc[] annotations; + if (linkInfo.type instanceof AnnotatedType) { + annotations = linkInfo.type.asAnnotatedType().annotations(); + } else if (linkInfo.type instanceof TypeVariable) { + annotations = linkInfo.type.asTypeVariable().annotations(); + } else { + return output; + } + + if (annotations.length == 0) + return output; + + List<String> annos = m_writer.getAnnotations(0, annotations, false, linkInfo.isJava5DeclarationLocation); + + boolean isFirst = true; + for (String anno : annos) { + if (!isFirst) { + linkInfo.displayLength += 1; + output.append(" "); + isFirst = false; + } + output.append(anno); + } + if (!annos.isEmpty()) { + linkInfo.displayLength += 1; + output.append(" "); + } + + return output; + } + /** * Given a class, return the appropriate tool tip. *
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkInfoImpl.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkInfoImpl.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -459,6 +459,8 @@ case CONTEXT_RETURN_TYPE: case CONTEXT_SUMMARY_RETURN_TYPE: + excludeTypeBounds = true; + break; case CONTEXT_EXECUTABLE_MEMBER_PARAM: excludeTypeBounds = true; break;
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/MethodWriterImpl.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/MethodWriterImpl.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -130,6 +130,7 @@ addName(method.name(), pre); } addParameters(method, pre); + addReceiverAnnotations(method, pre); addExceptions(method, pre); return pre; }
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -781,4 +781,6 @@ sourcetab = n; tabSpaces = String.format("%" + n + "s", ""); } + + public abstract boolean showMessage(SourcePosition pos, String key); }
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties Sat Jan 26 19:24:46 2013 -0800 @@ -11,6 +11,8 @@ doclet.Class_0_extends_implements_serializable=Class {0} extends {1} implements Serializable doclet.Option_conflict=Option {0} conflicts with {1} doclet.Option_reuse=Option reused: {0} +doclet.Option_doclint_no_qualifiers=Access qualifiers not permitted for -Xdoclint arguments +doclet.Option_doclint_invalid_arg=Invalid argument for -Xdoclint option doclet.exception_encountered= {0} encountered \n\ \twhile attempting to create file: {1} doclet.perform_copy_exception_encountered= {0} encountered while \n\
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/MessageRetriever.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/MessageRetriever.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -60,9 +60,9 @@ private ResourceBundle messageRB; /** - * Initilize the ResourceBundle with the given resource. + * Initialize the ResourceBundle with the given resource. * - * @param rb the esource bundle to read. + * @param rb the resource bundle to read. */ public MessageRetriever(ResourceBundle rb) { this.configuration = null; @@ -71,7 +71,7 @@ } /** - * Initilize the ResourceBundle with the given resource. + * Initialize the ResourceBundle with the given resource. * * @param configuration the configuration * @param resourcelocation Resource. @@ -189,7 +189,8 @@ * @param args arguments to be replaced in the message. */ public void warning(SourcePosition pos, String key, Object... args) { - printWarning(pos, getText(key, args)); + if (configuration.showMessage(pos, key)) + printWarning(pos, getText(key, args)); } /**
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -26,9 +26,11 @@ package com.sun.tools.doclets.internal.toolkit.util; import java.io.*; +import java.lang.annotation.ElementType; import java.util.*; import com.sun.javadoc.*; +import com.sun.javadoc.AnnotationDesc.ElementValuePair; import com.sun.tools.doclets.internal.toolkit.*; import javax.tools.StandardLocation; @@ -304,9 +306,7 @@ //Try walking the tree. addAllInterfaceTypes(results, superType, - superType instanceof ClassDoc ? - ((ClassDoc) superType).interfaceTypes() : - ((ParameterizedType) superType).interfaceTypes(), + interfaceTypesOf(superType), false, configuration); List<Type> resultsList = new ArrayList<Type>(results.values()); if (sort) { @@ -315,6 +315,14 @@ return resultsList; } + private static Type[] interfaceTypesOf(Type type) { + if (type instanceof AnnotatedType) + type = ((AnnotatedType)type).underlyingType(); + return type instanceof ClassDoc ? + ((ClassDoc)type).interfaceTypes() : + ((ParameterizedType)type).interfaceTypes(); + } + public static List<Type> getAllInterfaces(Type type, Configuration configuration) { return getAllInterfaces(type, configuration, true); } @@ -325,9 +333,7 @@ if (superType == null) return; addAllInterfaceTypes(results, superType, - superType instanceof ClassDoc ? - ((ClassDoc) superType).interfaceTypes() : - ((ParameterizedType) superType).interfaceTypes(), + interfaceTypesOf(superType), raw, configuration); } @@ -337,9 +343,7 @@ if (superType == null) return; addAllInterfaceTypes(results, superType, - superType instanceof ClassDoc ? - ((ClassDoc) superType).interfaceTypes() : - ((ParameterizedType) superType).interfaceTypes(), + interfaceTypesOf(superType), false, configuration); } @@ -363,6 +367,9 @@ results.put(superInterface.asClassDoc(), superInterface); } } + if (type instanceof AnnotatedType) + type = ((AnnotatedType)type).underlyingType(); + if (type instanceof ParameterizedType) findAllInterfaceTypes(results, (ParameterizedType) type, configuration); else if (((ClassDoc) type).typeParameters().length == 0) @@ -494,6 +501,57 @@ return false; } + private static boolean isDeclarationTarget(AnnotationDesc targetAnno) { + // The error recovery steps here are analogous to TypeAnnotations + ElementValuePair[] elems = targetAnno.elementValues(); + if (elems == null + || elems.length != 1 + || !"value".equals(elems[0].element().name()) + || !(elems[0].value().value() instanceof AnnotationValue[])) + return true; // error recovery + + AnnotationValue[] values = (AnnotationValue[])elems[0].value().value(); + for (int i = 0; i < values.length; i++) { + Object value = values[i].value(); + if (!(value instanceof FieldDoc)) + return true; // error recovery + + FieldDoc eValue = (FieldDoc)value; + if (Util.isJava5DeclarationElementType(eValue)) { + return true; + } + } + + return false; + } + + /** + * Returns true if the {@code annotationDoc} is to be treated + * as a declaration annotation, when targeting the + * {@code elemType} element type. + * + * @param annotationDoc the annotationDoc to check + * @param elemType the targeted elemType + * @return true if annotationDoc is a declaration annotation + */ + public static boolean isDeclarationAnnotation(AnnotationTypeDoc annotationDoc, + boolean isJava5DeclarationLocation) { + if (!isJava5DeclarationLocation) + return false; + AnnotationDesc[] annotationDescList = annotationDoc.annotations(); + // Annotations with no target are treated as declaration as well + if (annotationDescList.length==0) + return true; + for (int i = 0; i < annotationDescList.length; i++) { + if (annotationDescList[i].annotationType().qualifiedName().equals( + java.lang.annotation.Target.class.getName())) { + if (isDeclarationTarget(annotationDescList[i])) + return true; + } + } + return false; + } + /** * Return true if this class is linkable and false if we can't link to the * desired class. @@ -662,4 +720,25 @@ } return false; } + + /** + * Test whether the given FieldDoc is one of the declaration annotation ElementTypes + * defined in Java 5. + * Instead of testing for one of the new enum constants added in Java 8, test for + * the old constants. This prevents bootstrapping problems. + * + * @param elt The FieldDoc to test + * @return true, iff the given ElementType is one of the constants defined in Java 5 + * @since 1.8 + */ + public static boolean isJava5DeclarationElementType(FieldDoc elt) { + return elt.name().contentEquals(ElementType.ANNOTATION_TYPE.name()) || + elt.name().contentEquals(ElementType.CONSTRUCTOR.name()) || + elt.name().contentEquals(ElementType.FIELD.name()) || + elt.name().contentEquals(ElementType.LOCAL_VARIABLE.name()) || + elt.name().contentEquals(ElementType.METHOD.name()) || + elt.name().contentEquals(ElementType.PACKAGE.name()) || + elt.name().contentEquals(ElementType.PARAMETER.name()) || + elt.name().contentEquals(ElementType.TYPE.name()); + } }
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/links/LinkFactory.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/links/LinkFactory.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -61,6 +61,11 @@ //Just a primitive. linkInfo.displayLength += type.typeName().length(); linkOutput.append(type.typeName()); + } else if (type.asAnnotatedType() != null) { + linkOutput.append(getTypeAnnotationLinks(linkInfo)); + linkInfo.type = type.asAnnotatedType().underlyingType(); + linkOutput.append(getLinkOutput(linkInfo)); + return linkOutput; } else if (type.asWildcardType() != null) { //Wildcard type. linkInfo.isTypeBound = true; @@ -82,6 +87,7 @@ linkOutput.append(getLinkOutput(linkInfo)); } } else if (type.asTypeVariable()!= null) { + linkOutput.append(getTypeAnnotationLinks(linkInfo)); linkInfo.isTypeBound = true; //A type variable. Doc owner = type.asTypeVariable().owner(); @@ -175,6 +181,9 @@ protected abstract LinkOutput getTypeParameterLink(LinkInfo linkInfo, Type typeParam); + protected abstract LinkOutput getTypeAnnotationLink(LinkInfo linkInfo, + AnnotationDesc annotation); + /** * Return the links to the type parameters. * @@ -226,6 +235,24 @@ return output; } + public LinkOutput getTypeAnnotationLinks(LinkInfo linkInfo) { + LinkOutput output = getOutputInstance(); + if (linkInfo.type.asAnnotatedType() == null) + return output; + AnnotationDesc[] annotations = linkInfo.type.asAnnotatedType().annotations(); + for (int i = 0; i < annotations.length; i++) { + if (i > 0) { + linkInfo.displayLength += 1; + output.append(" "); + } + output.append(getTypeAnnotationLink(linkInfo, annotations[i])); + } + + linkInfo.displayLength += 1; + output.append(" "); + return output; + } + /** * Return &lt;, which is used in type parameters. Override this * if your doclet uses something different.
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/links/LinkInfo.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/links/LinkInfo.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -69,6 +69,12 @@ public boolean isTypeBound = false; /** + * Whether the document element is in a Java 5 declaration + * location or not. + */ + public boolean isJava5DeclarationLocation = true; + + /** * The label for the link. */ public String label;
--- a/langtools/src/share/classes/com/sun/tools/doclint/Checker.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclint/Checker.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -25,6 +25,7 @@ package com.sun.tools.doclint; +import com.sun.source.doctree.LiteralTree; import java.util.regex.Matcher; import com.sun.source.doctree.LinkTree; import java.net.URI; @@ -91,10 +92,11 @@ boolean foundInheritDoc = false; boolean foundReturn = false; - enum Flag { + public enum Flag { TABLE_HAS_CAPTION, HAS_ELEMENT, - HAS_TEXT + HAS_TEXT, + REPORTED_BAD_INLINE } static class TagStackItem { @@ -194,7 +196,8 @@ @Override public Void visitText(TextTree tree, Void ignore) { - if (!tree.getBody().trim().isEmpty()) { + if (hasNonWhitespace(tree)) { + checkAllowsText(tree); markEnclosingTag(Flag.HAS_TEXT); } return null; @@ -202,6 +205,7 @@ @Override public Void visitEntity(EntityTree tree, Void ignore) { + checkAllowsText(tree); markEnclosingTag(Flag.HAS_TEXT); String name = tree.getName().toString(); if (name.startsWith("#")) { @@ -217,6 +221,18 @@ return null; } + void checkAllowsText(DocTree tree) { + TagStackItem top = tagStack.peek(); + if (top != null + && top.tree.getKind() == DocTree.Kind.START_ELEMENT + && !top.tag.acceptsText()) { + if (top.flags.add(Flag.REPORTED_BAD_INLINE)) { + env.messages.error(HTML, tree, "dc.text.not.allowed", + ((StartElementTree) top.tree).getName()); + } + } + } + // </editor-fold> // <editor-fold defaultstate="collapsed" desc="HTML elements"> @@ -229,53 +245,22 @@ if (t == null) { env.messages.error(HTML, tree, "dc.tag.unknown", treeName); } else { + for (TagStackItem tsi: tagStack) { + if (tsi.tag.accepts(t)) { + while (tagStack.peek() != tsi) tagStack.pop(); + break; + } else if (tsi.tag.endKind != HtmlTag.EndKind.OPTIONAL) + break; + } + + checkStructure(tree, t); + // tag specific checks switch (t) { // check for out of sequence headers, such as <h1>...</h1> <h3>...</h3> case H1: case H2: case H3: case H4: case H5: case H6: checkHeader(tree, t); break; - // <p> inside <pre> - case P: - TagStackItem top = tagStack.peek(); - if (top != null && top.tag == HtmlTag.PRE) - env.messages.warning(HTML, tree, "dc.tag.p.in.pre"); - break; - } - - // check that only block tags and inline tags are used, - // and that blocks tags are not used within inline tags - switch (t.blockType) { - case INLINE: - break; - case BLOCK: - TagStackItem top = tagStack.peek(); - if (top != null && top.tag != null && top.tag.blockType == HtmlTag.BlockType.INLINE) { - switch (top.tree.getKind()) { - case START_ELEMENT: { - Name name = ((StartElementTree) top.tree).getName(); - env.messages.error(HTML, tree, "dc.tag.not.allowed.inline.element", - treeName, name); - break; - } - case LINK: - case LINK_PLAIN: { - String name = top.tree.getKind().tagName; - env.messages.error(HTML, tree, "dc.tag.not.allowed.inline.tag", - treeName, name); - break; - } - default: - env.messages.error(HTML, tree, "dc.tag.not.allowed.inline.other", - treeName); - } - } - break; - case OTHER: - env.messages.error(HTML, tree, "dc.tag.not.allowed", treeName); - break; - default: - throw new AssertionError(); } if (t.flags.contains(HtmlTag.Flag.NO_NEST)) { @@ -323,6 +308,58 @@ } } + private void checkStructure(StartElementTree tree, HtmlTag t) { + Name treeName = tree.getName(); + TagStackItem top = tagStack.peek(); + switch (t.blockType) { + case BLOCK: + if (top == null || top.tag.accepts(t)) + return; + + switch (top.tree.getKind()) { + case START_ELEMENT: { + if (top.tag.blockType == HtmlTag.BlockType.INLINE) { + Name name = ((StartElementTree) top.tree).getName(); + env.messages.error(HTML, tree, "dc.tag.not.allowed.inline.element", + treeName, name); + return; + } + } + break; + + case LINK: + case LINK_PLAIN: { + String name = top.tree.getKind().tagName; + env.messages.error(HTML, tree, "dc.tag.not.allowed.inline.tag", + treeName, name); + return; + } + } + break; + + case INLINE: + if (top == null || top.tag.accepts(t)) + return; + break; + + case LIST_ITEM: + case TABLE_ITEM: + if (top != null) { + // reset this flag so subsequent bad inline content gets reported + top.flags.remove(Flag.REPORTED_BAD_INLINE); + if (top.tag.accepts(t)) + return; + } + break; + + case OTHER: + env.messages.error(HTML, tree, "dc.tag.not.allowed", treeName); + return; + } + + env.messages.error(HTML, tree, "dc.tag.not.allowed.here", treeName); + } + private void checkHeader(StartElementTree tree, HtmlTag tag) { // verify the new tag if (getHeaderLevel(tag) > getHeaderLevel(currHeaderTag) + 1) { @@ -359,9 +396,8 @@ env.messages.error(HTML, tree, "dc.tag.unknown", treeName); } else if (t.endKind == HtmlTag.EndKind.NONE) { env.messages.error(HTML, tree, "dc.tag.end.not.permitted", treeName); - } else if (tagStack.isEmpty()) { - env.messages.error(HTML, tree, "dc.tag.end.unexpected", treeName); } else { + boolean done = false; while (!tagStack.isEmpty()) { TagStackItem top = tagStack.peek(); if (t == top.tag) { @@ -378,11 +414,8 @@ && !top.flags.contains(Flag.HAS_ELEMENT)) { env.messages.warning(HTML, tree, "dc.tag.empty", treeName); } - if (t.flags.contains(HtmlTag.Flag.NO_TEXT) - && top.flags.contains(Flag.HAS_TEXT)) { - env.messages.error(HTML, tree, "dc.text.not.allowed", treeName); - } tagStack.pop(); + done = true; break; } else if (top.tag == null || top.tag.endKind != HtmlTag.EndKind.REQUIRED) { tagStack.pop(); @@ -400,10 +433,15 @@ tagStack.pop(); } else { env.messages.error(HTML, tree, "dc.tag.end.unexpected", treeName); + done = true; break; } } } + + if (!done && tagStack.isEmpty()) { + env.messages.error(HTML, tree, "dc.tag.end.unexpected", treeName); + } } return super.visitEndElement(tree, ignore); @@ -447,14 +485,18 @@ if (currTag != HtmlTag.A) { break; } - // fallthrough + // fallthrough case ID: String value = getAttrValue(tree); - if (!validName.matcher(value).matches()) { - env.messages.error(HTML, tree, "dc.invalid.anchor", value); - } - if (!foundAnchors.add(value)) { - env.messages.error(HTML, tree, "dc.anchor.already.defined", value); + if (value == null) { + env.messages.error(HTML, tree, "dc.anchor.value.missing"); + } else { + if (!validName.matcher(value).matches()) { + env.messages.error(HTML, tree, "dc.invalid.anchor", value); + } + if (!foundAnchors.add(value)) { + env.messages.error(HTML, tree, "dc.anchor.already.defined", value); + } } break; @@ -542,6 +584,19 @@ } @Override + public Void visitLiteral(LiteralTree tree, Void ignore) { + if (tree.getKind() == DocTree.Kind.CODE) { + for (TagStackItem tsi: tagStack) { + if (tsi.tag == HtmlTag.CODE) { + env.messages.warning(HTML, tree, "dc.tag.code.within.code"); + break; + } + } + } + return super.visitLiteral(tree, ignore); + } + + @Override public Void visitParam(ParamTree tree, Void ignore) { boolean typaram = tree.isTypeParameter(); IdentifierTree nameTree = tree.getName(); @@ -740,7 +795,7 @@ for (DocTree d: list) { switch (d.getKind()) { case TEXT: - if (!((TextTree) d).getBody().trim().isEmpty()) + if (hasNonWhitespace((TextTree) d)) return; break; default: @@ -749,6 +804,16 @@ } env.messages.warning(SYNTAX, tree, "dc.empty", tree.getKind().tagName); } + + boolean hasNonWhitespace(TextTree tree) { + String s = tree.getBody(); + for (int i = 0; i < s.length(); i++) { + if (!Character.isWhitespace(s.charAt(i))) + return true; + } + return false; + } + // </editor-fold> }
--- a/langtools/src/share/classes/com/sun/tools/doclint/DocLint.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclint/DocLint.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -122,7 +122,7 @@ if (javacFiles.isEmpty()) { if (!needHelp) - System.out.println("no files given"); + out.println("no files given"); } JavacTool tool = JavacTool.create(); @@ -179,11 +179,11 @@ } } else if (arg.equals(STATS)) { env.messages.setStatsEnabled(true); - } else if (arg.matches("-bootclasspath") && i + 1 < args.length) { + } else if (arg.equals("-bootclasspath") && i + 1 < args.length) { javacBootClassPath = splitPath(args[++i]); - } else if (arg.matches("-classpath") && i + 1 < args.length) { + } else if (arg.equals("-classpath") && i + 1 < args.length) { javacClassPath = splitPath(args[++i]); - } else if (arg.matches("-sourcepath") && i + 1 < args.length) { + } else if (arg.equals("-sourcepath") && i + 1 < args.length) { javacSourcePath = splitPath(args[++i]); } else if (arg.equals(XMSGS_OPTION)) { env.messages.setOptions(null); @@ -234,6 +234,8 @@ out.println(" equivalent to -Xmsgs:all/protected, meaning that"); out.println(" all messages are reported for protected and public"); out.println(" declarations only. "); + out.println(" -stats"); + out.println(" Report statistics on the reported issues."); out.println(" -h -help --help -usage -?"); out.println(" Show this message."); out.println(""); @@ -247,7 +249,7 @@ List<File> splitPath(String path) { List<File> files = new ArrayList<File>(); - for (String f: path.split(File.separator)) { + for (String f: path.split(File.pathSeparator)) { if (f.length() > 0) files.add(new File(f)); }
--- a/langtools/src/share/classes/com/sun/tools/doclint/Entity.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclint/Entity.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -43,7 +43,7 @@ * risk. This code and its internal interfaces are subject to change * or deletion without notice.</b></p> */ -enum Entity { +public enum Entity { nbsp(160), iexcl(161), cent(162),
--- a/langtools/src/share/classes/com/sun/tools/doclint/HtmlTag.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclint/HtmlTag.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -57,16 +57,22 @@ B(BlockType.INLINE, EndKind.REQUIRED, EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), - BLOCKQUOTE, + BIG(BlockType.INLINE, EndKind.REQUIRED, + EnumSet.of(Flag.EXPECT_CONTENT)), + + BLOCKQUOTE(BlockType.BLOCK, EndKind.REQUIRED, + EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), BODY(BlockType.OTHER, EndKind.REQUIRED), BR(BlockType.INLINE, EndKind.NONE, attrs(AttrKind.USE_CSS, CLEAR)), - CAPTION(EnumSet.of(Flag.EXPECT_CONTENT)), + CAPTION(BlockType.TABLE_ITEM, EndKind.REQUIRED, + EnumSet.of(Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT)), - CENTER, + CENTER(BlockType.BLOCK, EndKind.REQUIRED, + EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), CITE(BlockType.INLINE, EndKind.REQUIRED, EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), @@ -74,17 +80,23 @@ CODE(BlockType.INLINE, EndKind.REQUIRED, EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), - DD(BlockType.BLOCK, EndKind.OPTIONAL, - EnumSet.of(Flag.EXPECT_CONTENT)), + DD(BlockType.LIST_ITEM, EndKind.OPTIONAL, + EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT)), - DIV, + DIV(BlockType.BLOCK, EndKind.REQUIRED, + EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), DL(BlockType.BLOCK, EndKind.REQUIRED, - EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_TEXT), - attrs(AttrKind.USE_CSS, COMPACT)), + EnumSet.of(Flag.EXPECT_CONTENT), + attrs(AttrKind.USE_CSS, COMPACT)) { + @Override + public boolean accepts(HtmlTag t) { + return (t == DT) || (t == DD); + } + }, - DT(BlockType.BLOCK, EndKind.OPTIONAL, - EnumSet.of(Flag.EXPECT_CONTENT)), + DT(BlockType.LIST_ITEM, EndKind.OPTIONAL, + EnumSet.of(Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT)), EM(BlockType.INLINE, EndKind.REQUIRED, EnumSet.of(Flag.NO_NEST)), @@ -97,12 +109,12 @@ FRAMESET(BlockType.OTHER, EndKind.REQUIRED), - H1, - H2, - H3, - H4, - H5, - H6, + H1(BlockType.BLOCK, EndKind.REQUIRED), + H2(BlockType.BLOCK, EndKind.REQUIRED), + H3(BlockType.BLOCK, EndKind.REQUIRED), + H4(BlockType.BLOCK, EndKind.REQUIRED), + H5(BlockType.BLOCK, EndKind.REQUIRED), + H6(BlockType.BLOCK, EndKind.REQUIRED), HEAD(BlockType.OTHER, EndKind.REQUIRED), @@ -118,31 +130,54 @@ attrs(AttrKind.OBSOLETE, NAME), attrs(AttrKind.USE_CSS, ALIGN, HSPACE, VSPACE, BORDER)), - LI(BlockType.BLOCK, EndKind.OPTIONAL), + LI(BlockType.LIST_ITEM, EndKind.OPTIONAL, + EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), LINK(BlockType.OTHER, EndKind.NONE), - MENU, + MENU(BlockType.BLOCK, EndKind.REQUIRED) { + @Override + public boolean accepts(HtmlTag t) { + return (t == LI); + } + }, META(BlockType.OTHER, EndKind.NONE), NOFRAMES(BlockType.OTHER, EndKind.REQUIRED), - NOSCRIPT(BlockType.OTHER, EndKind.REQUIRED), + NOSCRIPT(BlockType.BLOCK, EndKind.REQUIRED), OL(BlockType.BLOCK, EndKind.REQUIRED, - EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_TEXT), - attrs(AttrKind.USE_CSS, START, TYPE)), + EnumSet.of(Flag.EXPECT_CONTENT), + attrs(AttrKind.USE_CSS, START, TYPE)){ + @Override + public boolean accepts(HtmlTag t) { + return (t == LI); + } + }, P(BlockType.BLOCK, EndKind.OPTIONAL, EnumSet.of(Flag.EXPECT_CONTENT), attrs(AttrKind.USE_CSS, ALIGN)), - PRE(EnumSet.of(Flag.EXPECT_CONTENT)), + PRE(BlockType.BLOCK, EndKind.REQUIRED, + EnumSet.of(Flag.EXPECT_CONTENT)) { + @Override + public boolean accepts(HtmlTag t) { + switch (t) { + case IMG: case BIG: case SMALL: case SUB: case SUP: + return false; + default: + return (t.blockType == BlockType.INLINE); + } + } + }, SCRIPT(BlockType.OTHER, EndKind.REQUIRED), - SMALL(BlockType.INLINE, EndKind.REQUIRED), + SMALL(BlockType.INLINE, EndKind.REQUIRED, + EnumSet.of(Flag.EXPECT_CONTENT)), SPAN(BlockType.INLINE, EndKind.REQUIRED, EnumSet.of(Flag.EXPECT_CONTENT)), @@ -157,37 +192,70 @@ EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), TABLE(BlockType.BLOCK, EndKind.REQUIRED, - EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_TEXT), + EnumSet.of(Flag.EXPECT_CONTENT), attrs(AttrKind.OK, SUMMARY, Attr.FRAME, RULES, BORDER, CELLPADDING, CELLSPACING), - attrs(AttrKind.USE_CSS, ALIGN, WIDTH, BGCOLOR)), + attrs(AttrKind.USE_CSS, ALIGN, WIDTH, BGCOLOR)) { + @Override + public boolean accepts(HtmlTag t) { + switch (t) { + case CAPTION: + case THEAD: case TBODY: case TFOOT: + case TR: // HTML 3.2 + return true; + default: + return false; + } + } + }, - TBODY(BlockType.BLOCK, EndKind.REQUIRED, - EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_TEXT), - attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)), + TBODY(BlockType.TABLE_ITEM, EndKind.REQUIRED, + EnumSet.of(Flag.EXPECT_CONTENT), + attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)) { + @Override + public boolean accepts(HtmlTag t) { + return (t == TR); + } + }, - TD(BlockType.BLOCK, EndKind.OPTIONAL, + TD(BlockType.TABLE_ITEM, EndKind.OPTIONAL, + EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE), attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS, SCOPE, ABBR, AXIS, ALIGN, CHAR, CHAROFF, VALIGN), attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)), - TFOOT(BlockType.BLOCK, EndKind.REQUIRED, - attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)), + TFOOT(BlockType.TABLE_ITEM, EndKind.REQUIRED, + attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)) { + @Override + public boolean accepts(HtmlTag t) { + return (t == TR); + } + }, - TH(BlockType.BLOCK, EndKind.OPTIONAL, + TH(BlockType.TABLE_ITEM, EndKind.OPTIONAL, + EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE), attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS, SCOPE, ABBR, AXIS, ALIGN, CHAR, CHAROFF, VALIGN), attrs(AttrKind.USE_CSS, WIDTH, BGCOLOR, HEIGHT, NOWRAP)), - THEAD(BlockType.BLOCK, EndKind.REQUIRED, - attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)), + THEAD(BlockType.TABLE_ITEM, EndKind.REQUIRED, + attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN)) { + @Override + public boolean accepts(HtmlTag t) { + return (t == TR); + } + }, TITLE(BlockType.OTHER, EndKind.REQUIRED), - TR(BlockType.BLOCK, EndKind.OPTIONAL, - EnumSet.of(Flag.NO_TEXT), + TR(BlockType.TABLE_ITEM, EndKind.OPTIONAL, attrs(AttrKind.OK, ALIGN, CHAR, CHAROFF, VALIGN), - attrs(AttrKind.USE_CSS, BGCOLOR)), + attrs(AttrKind.USE_CSS, BGCOLOR)) { + @Override + public boolean accepts(HtmlTag t) { + return (t == TH) || (t == TD); + } + }, TT(BlockType.INLINE, EndKind.REQUIRED, EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), @@ -196,8 +264,13 @@ EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), UL(BlockType.BLOCK, EndKind.REQUIRED, - EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_TEXT), - attrs(AttrKind.USE_CSS, COMPACT, TYPE)), + EnumSet.of(Flag.EXPECT_CONTENT), + attrs(AttrKind.USE_CSS, COMPACT, TYPE)){ + @Override + public boolean accepts(HtmlTag t) { + return (t == LI); + } + }, VAR(BlockType.INLINE, EndKind.REQUIRED); @@ -207,6 +280,8 @@ public static enum BlockType { BLOCK, INLINE, + LIST_ITEM, + TABLE_ITEM, OTHER; } @@ -220,9 +295,10 @@ } public static enum Flag { + ACCEPTS_BLOCK, + ACCEPTS_INLINE, EXPECT_CONTENT, - NO_NEST, - NO_TEXT + NO_NEST } public static enum Attr { @@ -273,7 +349,7 @@ static final Map<String,Attr> index = new HashMap<String,Attr>(); static { for (Attr t: values()) { - index.put(t.name().toLowerCase(), t); + index.put(t.getText(), t); } } } @@ -300,22 +376,14 @@ public final Set<Flag> flags; private final Map<Attr,AttrKind> attrs; - - HtmlTag() { - this(BlockType.BLOCK, EndKind.REQUIRED); - } - - HtmlTag(Set<Flag> flags) { - this(BlockType.BLOCK, EndKind.REQUIRED, flags); - } - HtmlTag(BlockType blockType, EndKind endKind, AttrMap... attrMaps) { this(blockType, endKind, Collections.<Flag>emptySet(), attrMaps); } HtmlTag(BlockType blockType, EndKind endKind, Set<Flag> flags, AttrMap... attrMaps) { this.blockType = blockType; - this.endKind = endKind;this.flags = flags; + this.endKind = endKind; + this.flags = flags; this.attrs = new EnumMap<Attr,AttrKind>(Attr.class); for (Map<Attr,AttrKind> m: attrMaps) this.attrs.putAll(m); @@ -324,6 +392,35 @@ attrs.put(Attr.STYLE, AttrKind.OK); } + public boolean accepts(HtmlTag t) { + if (flags.contains(Flag.ACCEPTS_BLOCK) && flags.contains(Flag.ACCEPTS_INLINE)) { + return (t.blockType == BlockType.BLOCK) || (t.blockType == BlockType.INLINE); + } else if (flags.contains(Flag.ACCEPTS_BLOCK)) { + return (t.blockType == BlockType.BLOCK); + } else if (flags.contains(Flag.ACCEPTS_INLINE)) { + return (t.blockType == BlockType.INLINE); + } else + switch (blockType) { + case BLOCK: + case INLINE: + return (t.blockType == BlockType.INLINE); + case OTHER: + // OTHER tags are invalid in doc comments, and will be + // reported separately, so silently accept/ignore any content + return true; + default: + // any combination which could otherwise arrive here + // ought to have been handled in an overriding method + throw new AssertionError(this + ":" + t); + } + } + + public boolean acceptsText() { + // generally, anywhere we can put text we can also put inline tag + // so check if a typical inline tag is allowed + return accepts(B); + } + public String getText() { return name().toLowerCase(); } @@ -346,7 +443,7 @@ private static final Map<String,HtmlTag> index = new HashMap<String,HtmlTag>(); static { for (HtmlTag t: values()) { - index.put(t.name().toLowerCase(), t); + index.put(t.getText(), t); } }
--- a/langtools/src/share/classes/com/sun/tools/doclint/resources/doclint.properties Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclint/resources/doclint.properties Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 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 @@ -24,6 +24,7 @@ # dc.anchor.already.defined = anchor already defined: {0} +dc.anchor.value.missing = no value given for anchor dc.attr.lacks.value = attribute lacks value dc.attr.obsolete = attribute obsolete: {0} dc.attr.obsolete.use.css = attribute obsolete, use CSS instead: {0} @@ -47,12 +48,14 @@ dc.no.summary.or.caption.for.table=no summary or caption for table dc.param.name.not.found = @param name not found dc.ref.not.found = reference not found +dc.tag.code.within.code = '{@code'} within <code> dc.tag.empty = empty <{0}> tag dc.tag.end.not.permitted = invalid end tag: </{0}> dc.tag.end.unexpected = unexpected end tag: </{0}> dc.tag.header.sequence.1 = header used out of sequence: <{0}> dc.tag.header.sequence.2 = header used out of sequence: <{0}> dc.tag.nested.not.allowed=nested tag not allowed: <{0}> +dc.tag.not.allowed.here = tag not allowed here: <{0}> dc.tag.not.allowed = element not allowed in documentation comments: <{0}> dc.tag.not.allowed.inline.element = block element not allowed within inline element <{1}>: {0} dc.tag.not.allowed.inline.tag = block element not allowed within @{1}: {0}
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Annotations.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Annotations.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -48,7 +48,7 @@ * * An instance of this class can be in one of three states: * - * NOT_STARTED indicates that the Symbol this instance belongs to have not been + * NOT_STARTED indicates that the Symbol this instance belongs to has not been * annotated (yet). Specifically if the declaration is not annotated this * instance will never move past NOT_STARTED. You can never go back to * NOT_STARTED. @@ -59,7 +59,7 @@ * * "unnamed" this Annotations contains some attributes, possibly the final set. * While in this state you can only prepend or append to the attributes not set - * it directly. You can also move back to the IN_PROGRESS sate using reset(). + * it directly. You can also move back to the IN_PROGRESS state using reset(). * * <p><b>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 @@ -67,14 +67,21 @@ */ public class Annotations { - private static final List<Attribute.Compound> NOT_STARTED = List.of(null); - private static final List<Attribute.Compound> IN_PROGRESS = List.of(null); + private static final List<Attribute.Compound> DECL_NOT_STARTED = List.of(null); + private static final List<Attribute.Compound> DECL_IN_PROGRESS = List.of(null); + /* * This field should never be null */ - private List<Attribute.Compound> attributes = NOT_STARTED; + private List<Attribute.Compound> attributes = DECL_NOT_STARTED; + /* - * The Symbol this Annotations belong to + * This field should never be null + */ + private List<Attribute.TypeCompound> type_attributes = List.<Attribute.TypeCompound>nil(); + + /* + * The Symbol this Annotations instance belongs to */ private final Symbol sym; @@ -82,11 +89,15 @@ this.sym = sym; } - public List<Attribute.Compound> getAttributes() { - return filterSentinels(attributes); + public List<Attribute.Compound> getDeclarationAttributes() { + return filterDeclSentinels(attributes); } - public void setAttributes(List<Attribute.Compound> a) { + public List<Attribute.TypeCompound> getTypeAttributes() { + return type_attributes; + } + + public void setDeclarationAttributes(List<Attribute.Compound> a) { Assert.check(pendingCompletion() || !isStarted()); if (a == null) { throw new NullPointerException(); @@ -94,31 +105,51 @@ attributes = a; } + public void setTypeAttributes(List<Attribute.TypeCompound> a) { + if (a == null) { + throw new NullPointerException(); + } + type_attributes = a; + } + public void setAttributes(Annotations other) { if (other == null) { throw new NullPointerException(); } - setAttributes(other.getAttributes()); + setDeclarationAttributes(other.getDeclarationAttributes()); + setTypeAttributes(other.getTypeAttributes()); } - public void setAttributesWithCompletion(final Annotate.AnnotateRepeatedContext ctx) { + public void setDeclarationAttributesWithCompletion(final Annotate.AnnotateRepeatedContext<Attribute.Compound> ctx) { Assert.check(pendingCompletion() || (!isStarted() && sym.kind == PCK)); + this.setDeclarationAttributes(getAttributesForCompletion(ctx)); + } - Map<Symbol.TypeSymbol, ListBuffer<Attribute.Compound>> annotated = ctx.annotated; + public void appendTypeAttributesWithCompletion(final Annotate.AnnotateRepeatedContext<Attribute.TypeCompound> ctx) { + this.appendUniqueTypes(getAttributesForCompletion(ctx)); + } + + private <T extends Attribute.Compound> List<T> getAttributesForCompletion( + final Annotate.AnnotateRepeatedContext<T> ctx) { + + Map<Symbol.TypeSymbol, ListBuffer<T>> annotated = ctx.annotated; boolean atLeastOneRepeated = false; - List<Attribute.Compound> buf = List.<Attribute.Compound>nil(); - for (ListBuffer<Attribute.Compound> lb : annotated.values()) { + List<T> buf = List.<T>nil(); + for (ListBuffer<T> lb : annotated.values()) { if (lb.size() == 1) { buf = buf.prepend(lb.first()); } else { // repeated - buf = buf.prepend(new Placeholder(lb.toList(), sym)); + // This will break when other subtypes of Attributs.Compound + // are introduced, because PlaceHolder is a subtype of TypeCompound. + T res; + @SuppressWarnings("unchecked") + T ph = (T) new Placeholder<T>(ctx, lb.toList(), sym); + res = ph; + buf = buf.prepend(res); atLeastOneRepeated = true; } } - // Add non-repeating attributes - setAttributes(buf.reverse()); - if (atLeastOneRepeated) { // The Symbol s is now annotated with a combination of // finished non-repeating annotations and placeholders for @@ -126,19 +157,18 @@ // // We need to do this in two passes because when creating // a container for a repeating annotation we must - // guarantee that the @ContainedBy on the + // guarantee that the @Repeatable on the // contained annotation is fully annotated // // The way we force this order is to do all repeating // annotations in a pass after all non-repeating are - // finished. This will work because @ContainedBy + // finished. This will work because @Repeatable // is non-repeating and therefore will be annotated in the // fist pass. // Queue a pass that will replace Attribute.Placeholders // with Attribute.Compound (made from synthesized containers). ctx.annotateRepeated(new Annotate.Annotator() { - @Override public String toString() { return "repeated annotation pass of: " + sym + " in: " + sym.owner; @@ -150,10 +180,12 @@ } }); } + // Add non-repeating attributes + return buf.reverse(); } public Annotations reset() { - attributes = IN_PROGRESS; + attributes = DECL_IN_PROGRESS; return this; } @@ -163,12 +195,16 @@ || attributes.isEmpty(); } + public boolean isTypesEmpty() { + return type_attributes.isEmpty(); + } + public boolean pendingCompletion() { - return attributes == IN_PROGRESS; + return attributes == DECL_IN_PROGRESS; } public Annotations append(List<Attribute.Compound> l) { - attributes = filterSentinels(attributes); + attributes = filterDeclSentinels(attributes); if (l.isEmpty()) { ; // no-op @@ -180,8 +216,24 @@ return this; } + public Annotations appendUniqueTypes(List<Attribute.TypeCompound> l) { + if (l.isEmpty()) { + ; // no-op + } else if (type_attributes.isEmpty()) { + type_attributes = l; + } else { + // TODO: in case we expect a large number of annotations, this + // might be inefficient. + for (Attribute.TypeCompound tc : l) { + if (!type_attributes.contains(tc)) + type_attributes = type_attributes.append(tc); + } + } + return this; + } + public Annotations prepend(List<Attribute.Compound> l) { - attributes = filterSentinels(attributes); + attributes = filterDeclSentinels(attributes); if (l.isEmpty()) { ; // no-op @@ -193,19 +245,29 @@ return this; } - private List<Attribute.Compound> filterSentinels(List<Attribute.Compound> a) { - return (a == IN_PROGRESS || a == NOT_STARTED) + private List<Attribute.Compound> filterDeclSentinels(List<Attribute.Compound> a) { + return (a == DECL_IN_PROGRESS || a == DECL_NOT_STARTED) ? List.<Attribute.Compound>nil() : a; } private boolean isStarted() { - return attributes != NOT_STARTED; + return attributes != DECL_NOT_STARTED; } private List<Attribute.Compound> getPlaceholders() { List<Attribute.Compound> res = List.<Attribute.Compound>nil(); - for (Attribute.Compound a : filterSentinels(attributes)) { + for (Attribute.Compound a : filterDeclSentinels(attributes)) { + if (a instanceof Placeholder) { + res = res.prepend(a); + } + } + return res.reverse(); + } + + private List<Attribute.TypeCompound> getTypePlaceholders() { + List<Attribute.TypeCompound> res = List.<Attribute.TypeCompound>nil(); + for (Attribute.TypeCompound a : type_attributes) { if (a instanceof Placeholder) { res = res.prepend(a); } @@ -216,68 +278,100 @@ /* * Replace Placeholders for repeating annotations with their containers */ - private void complete(Annotate.AnnotateRepeatedContext ctx) { - Assert.check(!pendingCompletion()); + private <T extends Attribute.Compound> void complete(Annotate.AnnotateRepeatedContext<T> ctx) { Log log = ctx.log; Env<AttrContext> env = ctx.env; JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile); try { + // TODO: can we reduce duplication in the following branches? + if (ctx.isTypeCompound) { + Assert.check(!isTypesEmpty()); - if (isEmpty()) { - return; + if (isTypesEmpty()) { + return; + } + + List<Attribute.TypeCompound> result = List.nil(); + for (Attribute.TypeCompound a : getTypeAttributes()) { + if (a instanceof Placeholder) { + @SuppressWarnings("unchecked") + Placeholder<Attribute.TypeCompound> ph = (Placeholder<Attribute.TypeCompound>) a; + Attribute.TypeCompound replacement = replaceOne(ph, ph.getRepeatedContext()); + + if (null != replacement) { + result = result.prepend(replacement); + } + } else { + result = result.prepend(a); + } + } + + type_attributes = result.reverse(); + + Assert.check(Annotations.this.getTypePlaceholders().isEmpty()); + } else { + Assert.check(!pendingCompletion()); + + if (isEmpty()) { + return; + } + + List<Attribute.Compound> result = List.nil(); + for (Attribute.Compound a : getDeclarationAttributes()) { + if (a instanceof Placeholder) { + @SuppressWarnings("unchecked") + Attribute.Compound replacement = replaceOne((Placeholder<T>) a, ctx); + + if (null != replacement) { + result = result.prepend(replacement); + } + } else { + result = result.prepend(a); + } + } + + attributes = result.reverse(); + + Assert.check(Annotations.this.getPlaceholders().isEmpty()); } - - List<Attribute.Compound> result = List.nil(); - for (Attribute.Compound a : getAttributes()) { - if (a instanceof Placeholder) { - Attribute.Compound replacement = replaceOne((Placeholder) a, ctx); - - if (null != replacement) { - result = result.prepend(replacement); - } - } else { - result = result.prepend(a); - } - } - - attributes = result.reverse(); - - Assert.check(Annotations.this.getPlaceholders().isEmpty()); } finally { log.useSource(oldSource); } } - private Attribute.Compound replaceOne(Placeholder placeholder, Annotate.AnnotateRepeatedContext ctx) { + private <T extends Attribute.Compound> T replaceOne(Placeholder<T> placeholder, Annotate.AnnotateRepeatedContext<T> ctx) { Log log = ctx.log; // Process repeated annotations - Attribute.Compound validRepeated = - ctx.processRepeatedAnnotations(placeholder.getPlaceholderFor(), sym); + T validRepeated = ctx.processRepeatedAnnotations(placeholder.getPlaceholderFor(), sym); if (validRepeated != null) { // Check that the container isn't manually // present along with repeated instances of // its contained annotation. - ListBuffer<Attribute.Compound> manualContainer = ctx.annotated.get(validRepeated.type.tsym); + ListBuffer<T> manualContainer = ctx.annotated.get(validRepeated.type.tsym); if (manualContainer != null) { - log.error(ctx.pos.get(manualContainer.first()), "invalid.containedby.annotation.repeated.and.container.present", + log.error(ctx.pos.get(manualContainer.first()), "invalid.repeatable.annotation.repeated.and.container.present", manualContainer.first().type.tsym); } } // A null return will delete the Placeholder return validRepeated; - } - private static class Placeholder extends Attribute.Compound { + private static class Placeholder<T extends Attribute.Compound> extends Attribute.TypeCompound { - private List<Attribute.Compound> placeholderFor; - private Symbol on; + private final Annotate.AnnotateRepeatedContext<T> ctx; + private final List<T> placeholderFor; + private final Symbol on; - public Placeholder(List<Attribute.Compound> placeholderFor, Symbol on) { - super(Type.noType, List.<Pair<Symbol.MethodSymbol, Attribute>>nil()); + public Placeholder(Annotate.AnnotateRepeatedContext<T> ctx, List<T> placeholderFor, Symbol on) { + super(on.type, List.<Pair<Symbol.MethodSymbol, Attribute>>nil(), + ctx.isTypeCompound ? + ((Attribute.TypeCompound)placeholderFor.head).position : + null); + this.ctx = ctx; this.placeholderFor = placeholderFor; this.on = on; } @@ -287,8 +381,12 @@ return "<placeholder: " + placeholderFor + " on: " + on + ">"; } - public List<Attribute.Compound> getPlaceholderFor() { + public List<T> getPlaceholderFor() { return placeholderFor; } + + public Annotate.AnnotateRepeatedContext<T> getRepeatedContext() { + return ctx; + } } }
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -217,6 +217,21 @@ } } + public static class TypeCompound extends Compound { + public TypeAnnotationPosition position; + public TypeCompound(Compound compound, + TypeAnnotationPosition position) { + this(compound.type, compound.values, position); + } + public TypeCompound(Type type, + List<Pair<MethodSymbol, Attribute>> values, + TypeAnnotationPosition position) { + super(type, values); + this.position = position; + } + + } + /** The value for an annotation element of an array type. */ public static class Array extends Attribute {
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Flags.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Flags.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -233,23 +233,23 @@ public static final long PROPRIETARY = 1L<<38; /** - * Flag that marks a a multi-catch parameter + * Flag that marks a multi-catch parameter. */ public static final long UNION = 1L<<39; /** - * Flag that marks a special kind of bridge methods (the ones that - * come from restricted supertype bounds) + * Flag that marks a special kind of bridge method (the ones that + * come from restricted supertype bounds). */ public static final long OVERRIDE_BRIDGE = 1L<<40; /** - * Flag that marks an 'effectively final' local variable + * Flag that marks an 'effectively final' local variable. */ public static final long EFFECTIVELY_FINAL = 1L<<41; /** - * Flag that marks non-override equivalent methods with the same signature + * Flag that marks non-override equivalent methods with the same signature. */ public static final long CLASH = 1L<<42; @@ -280,7 +280,7 @@ SYNCHRONIZED | FINAL | STRICTFP; public static final long ExtendedStandardFlags = (long)StandardFlags | DEFAULT, - InterfaceDefaultMethodMask = ABSTRACT | PUBLIC | STRICTFP | SYNCHRONIZED | DEFAULT, + InterfaceMethodMask = ABSTRACT | STATIC | PUBLIC | STRICTFP | DEFAULT, LocalVarFlags = FINAL | PARAMETER;
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Lint.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Lint.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -74,7 +74,7 @@ * the given annotations. */ public Lint augment(Annotations annots) { - return augmentor.augment(this, annots.getAttributes()); + return augmentor.augment(this, annots.getDeclarationAttributes()); } /** @@ -82,7 +82,7 @@ * the given annotations and flags. */ public Lint augment(Annotations annots, long flags) { - Lint l = augmentor.augment(this, annots.getAttributes()); + Lint l = augmentor.augment(this, annots.getDeclarationAttributes()); if ((flags & DEPRECATED) != 0) { if (l == this) l = new Lint(this);
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -27,7 +27,10 @@ import java.util.Locale; +import javax.lang.model.type.TypeKind; + import com.sun.tools.javac.api.Messages; +import com.sun.tools.javac.code.Type.AnnotatedType; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.util.List; @@ -35,7 +38,6 @@ import static com.sun.tools.javac.code.BoundKind.*; import static com.sun.tools.javac.code.Flags.*; -import static com.sun.tools.javac.code.TypeTag.ARRAY; import static com.sun.tools.javac.code.TypeTag.CLASS; import static com.sun.tools.javac.code.TypeTag.FORALL; @@ -188,7 +190,7 @@ StringBuilder buf = new StringBuilder(); if (t.getEnclosingType().tag == CLASS && t.tsym.owner.kind == Kinds.TYP) { buf.append(visit(t.getEnclosingType(), locale)); - buf.append("."); + buf.append('.'); buf.append(className(t, false, locale)); } else { buf.append(className(t, true, locale)); @@ -196,7 +198,7 @@ if (t.getTypeArguments().nonEmpty()) { buf.append('<'); buf.append(visitTypes(t.getTypeArguments(), locale)); - buf.append(">"); + buf.append('>'); } return buf.toString(); } @@ -231,6 +233,17 @@ return visitType(t, locale); } + @Override + public String visitAnnotatedType(AnnotatedType t, Locale locale) { + if (t.typeAnnotations != null && + t.typeAnnotations.nonEmpty()) { + // TODO: better logic for arrays, ... + return "(" + t.typeAnnotations + " :: " + visit(t.underlyingType, locale) + ")"; + } else { + return "({} :: " + visit(t.underlyingType, locale) + ")"; + } + } + public String visitType(Type t, Locale locale) { String s = (t.tsym == null || t.tsym.name == null) ? localize(locale, "compiler.misc.type.none") @@ -296,8 +309,13 @@ args = args.tail; buf.append(','); } - if (args.head.tag == ARRAY) { - buf.append(visit(((ArrayType) args.head).elemtype, locale)); + if (args.head.unannotatedType().getKind() == TypeKind.ARRAY) { + buf.append(visit(((ArrayType) args.head.unannotatedType()).elemtype, locale)); + if (args.head.getAnnotations().nonEmpty()) { + buf.append(' '); + buf.append(args.head.getAnnotations()); + buf.append(' '); + } buf.append("..."); } else { buf.append(visit(args.head, locale));
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -176,9 +176,6 @@ public boolean allowTryWithResources() { return compareTo(JDK1_7) >= 0; } - public boolean allowTypeAnnotations() { - return compareTo(JDK1_7) >= 0; - } public boolean allowBinaryLiterals() { return compareTo(JDK1_7) >= 0; } @@ -206,18 +203,30 @@ public boolean allowDefaultMethods() { return compareTo(JDK1_8) >= 0; } + public boolean allowStaticInterfaceMethods() { + return compareTo(JDK1_8) >= 0; + } public boolean allowStrictMethodClashCheck() { return compareTo(JDK1_8) >= 0; } public boolean allowEffectivelyFinalInInnerClasses() { return compareTo(JDK1_8) >= 0; } + public boolean allowTypeAnnotations() { + return compareTo(JDK1_8) >= 0; + } public boolean allowRepeatedAnnotations() { return compareTo(JDK1_8) >= 0; } public boolean allowIntersectionTypesInCast() { return compareTo(JDK1_8) >= 0; } + public boolean allowEarlyReturnConstraints() { + return compareTo(JDK1_8) >= 0; + } + public boolean allowStructuralMostSpecific() { + return compareTo(JDK1_8) >= 0; + } public static SourceVersion toSourceVersion(Source source) { switch(source) { case JDK1_2:
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -84,7 +84,15 @@ * method to make sure that the class symbol is loaded. */ public List<Attribute.Compound> getRawAttributes() { - return annotations.getAttributes(); + return annotations.getDeclarationAttributes(); + } + + /** An accessor method for the type attributes of this symbol. + * Attributes of class symbols should be accessed through the accessor + * method to make sure that the class symbol is loaded. + */ + public List<Attribute.TypeCompound> getRawTypeAttributes() { + return annotations.getTypeAttributes(); } /** Fetch a particular annotation from a symbol. */ @@ -450,11 +458,19 @@ * This is the implementation for {@code * javax.lang.model.element.Element.getAnnotationMirrors()}. */ - public final List<Attribute.Compound> getAnnotationMirrors() { + public final List<? extends AnnotationMirror> getAnnotationMirrors() { return getRawAttributes(); } /** + * TODO: Should there be a {@code + * javax.lang.model.element.Element.getTypeAnnotationMirrors()}. + */ + public final List<Attribute.TypeCompound> getTypeAnnotationMirrors() { + return getRawTypeAttributes(); + } + + /** * @deprecated this method should never be used by javac internally. */ @Deprecated @@ -462,6 +478,11 @@ return JavacElements.getAnnotation(this, annoType); } + // This method is part of the javax.lang.model API, do not use this in javac code. + public <A extends java.lang.annotation.Annotation> A[] getAnnotations(Class<A> annoType) { + return JavacElements.getAnnotations(this, annoType); + } + // TODO: getEnclosedElements should return a javac List, fix in FilteredMemberList public java.util.List<Symbol> getEnclosedElements() { return List.nil(); @@ -790,6 +811,12 @@ return super.getRawAttributes(); } + @Override + public List<Attribute.TypeCompound> getRawTypeAttributes() { + if (completer != null) complete(); + return super.getRawTypeAttributes(); + } + public Type erasure(Types types) { if (erasure_field == null) erasure_field = new ClassType(types.erasure(type.getEnclosingType()), @@ -1228,7 +1255,8 @@ case Flags.PRIVATE: return false; case Flags.PUBLIC: - return true; + return !this.owner.isInterface() || + (flags_field & STATIC) == 0; case Flags.PROTECTED: return (origin.flags() & INTERFACE) == 0; case 0: @@ -1242,6 +1270,18 @@ } } + @Override + public boolean isInheritedIn(Symbol clazz, Types types) { + switch ((int)(flags_field & Flags.AccessFlags)) { + case PUBLIC: + return !this.owner.isInterface() || + clazz == owner || + (flags_field & STATIC) == 0; + default: + return super.isInheritedIn(clazz, types); + } + } + /** The implementation of this (abstract) symbol in class origin; * null if none exists. Synthetic methods are not considered * as possible implementations. @@ -1369,7 +1409,7 @@ return defaultValue; } - public List<VarSymbol> getParameters() { + public List<VarSymbol> getParameters() { return params(); }
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -161,10 +161,10 @@ public final Type autoCloseableType; public final Type trustMeType; public final Type lambdaMetafactory; - public final Type containedByType; - public final Type containerForType; + public final Type repeatableType; public final Type documentedType; public final Type elementTypeType; + public final Type functionalInterfaceType; /** The symbol representing the length field of an array. */ @@ -494,8 +494,7 @@ deprecatedType = enterClass("java.lang.Deprecated"); suppressWarningsType = enterClass("java.lang.SuppressWarnings"); inheritedType = enterClass("java.lang.annotation.Inherited"); - containedByType = enterClass("java.lang.annotation.ContainedBy"); - containerForType = enterClass("java.lang.annotation.ContainerFor"); + repeatableType = enterClass("java.lang.annotation.Repeatable"); documentedType = enterClass("java.lang.annotation.Documented"); elementTypeType = enterClass("java.lang.annotation.ElementType"); systemType = enterClass("java.lang.System"); @@ -509,6 +508,7 @@ nativeHeaderType = enterClass("java.lang.annotation.Native"); nativeHeaderType_old = enterClass("javax.tools.annotation.GenerateNativeHeader"); lambdaMetafactory = enterClass("java.lang.invoke.LambdaMetafactory"); + functionalInterfaceType = enterClass("java.lang.FunctionalInterface"); synthesizeEmptyInterfaceIfMissing(autoCloseableType); synthesizeEmptyInterfaceIfMissing(cloneableType);
--- a/langtools/src/share/classes/com/sun/tools/javac/code/TargetType.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/TargetType.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -25,10 +25,7 @@ package com.sun.tools.javac.code; -import java.util.EnumSet; -import java.util.Set; - -import static com.sun.tools.javac.code.TargetType.TargetAttribute.*; +import com.sun.tools.javac.util.Assert; /** * Describes the type of program element an extended annotation (or extended @@ -44,178 +41,89 @@ * This code and its internal interfaces are subject to change or * deletion without notice.</b> */ +// Code duplicated in com.sun.tools.classfile.TypeAnnotation.TargetType public enum TargetType { + /** For annotations on a class type parameter declaration. */ + CLASS_TYPE_PARAMETER(0x00), - // - // Some target types are commented out, because Java doesn't permit such - // targets. They are included here to confirm that their omission is - // intentional omission not an accidental omission. - // + /** For annotations on a method type parameter declaration. */ + METHOD_TYPE_PARAMETER(0x01), - /** For annotations on typecasts. */ - TYPECAST(0x00, IsLocal), + /** For annotations on the type of an "extends" or "implements" clause. */ + CLASS_EXTENDS(0x10), - /** For annotations on a type argument or nested array of a typecast. */ - TYPECAST_GENERIC_OR_ARRAY(0x01, HasLocation, IsLocal), + /** For annotations on a bound of a type parameter of a class. */ + CLASS_TYPE_PARAMETER_BOUND(0x11), - /** For annotations on type tests. */ - INSTANCEOF(0x02, IsLocal), + /** For annotations on a bound of a type parameter of a method. */ + METHOD_TYPE_PARAMETER_BOUND(0x12), - /** For annotations on a type argument or nested array of a type test. */ - INSTANCEOF_GENERIC_OR_ARRAY(0x03, HasLocation, IsLocal), + /** For annotations on a field. */ + FIELD(0x13), - /** For annotations on object creation expressions. */ - NEW(0x04, IsLocal), - - /** - * For annotations on a type argument or nested array of an object creation - * expression. - */ - NEW_GENERIC_OR_ARRAY(0x05, HasLocation, IsLocal), - + /** For annotations on a method return type. */ + METHOD_RETURN(0x14), /** For annotations on the method receiver. */ - METHOD_RECEIVER(0x06), + METHOD_RECEIVER(0x15), - // invalid location - //@Deprecated METHOD_RECEIVER_GENERIC_OR_ARRAY(0x07, HasLocation), - - /** For annotations on local variables. */ - LOCAL_VARIABLE(0x08, IsLocal), - - /** For annotations on a type argument or nested array of a local. */ - LOCAL_VARIABLE_GENERIC_OR_ARRAY(0x09, HasLocation, IsLocal), - - // handled by regular annotations - //@Deprecated METHOD_RETURN(0x0A), - - /** - * For annotations on a type argument or nested array of a method return - * type. - */ - METHOD_RETURN_GENERIC_OR_ARRAY(0x0B, HasLocation), - - // handled by regular annotations - //@Deprecated METHOD_PARAMETER(0x0C), - - /** For annotations on a type argument or nested array of a method parameter. */ - METHOD_PARAMETER_GENERIC_OR_ARRAY(0x0D, HasLocation), - - // handled by regular annotations - //@Deprecated FIELD(0x0E), - - /** For annotations on a type argument or nested array of a field. */ - FIELD_GENERIC_OR_ARRAY(0x0F, HasLocation), - - /** For annotations on a bound of a type parameter of a class. */ - CLASS_TYPE_PARAMETER_BOUND(0x10, HasBound, HasParameter), - - /** - * For annotations on a type argument or nested array of a bound of a type - * parameter of a class. - */ - CLASS_TYPE_PARAMETER_BOUND_GENERIC_OR_ARRAY(0x11, HasBound, HasLocation, HasParameter), - - /** For annotations on a bound of a type parameter of a method. */ - METHOD_TYPE_PARAMETER_BOUND(0x12, HasBound, HasParameter), - - /** - * For annotations on a type argument or nested array of a bound of a type - * parameter of a method. - */ - METHOD_TYPE_PARAMETER_BOUND_GENERIC_OR_ARRAY(0x13, HasBound, HasLocation, HasParameter), - - /** For annotations on the type of an "extends" or "implements" clause. */ - CLASS_EXTENDS(0x14), - - /** For annotations on the inner type of an "extends" or "implements" clause. */ - CLASS_EXTENDS_GENERIC_OR_ARRAY(0x15, HasLocation), + /** For annotations on a method parameter. */ + METHOD_FORMAL_PARAMETER(0x16), /** For annotations on a throws clause in a method declaration. */ - THROWS(0x16), + THROWS(0x17), - // invalid location - //@Deprecated THROWS_GENERIC_OR_ARRAY(0x17, HasLocation), + /** For annotations on a local variable. */ + LOCAL_VARIABLE(0x40, true), - /** For annotations in type arguments of object creation expressions. */ - NEW_TYPE_ARGUMENT(0x18, IsLocal), - NEW_TYPE_ARGUMENT_GENERIC_OR_ARRAY(0x19, HasLocation, IsLocal), + /** For annotations on a resource variable. */ + RESOURCE_VARIABLE(0x41, true), - METHOD_TYPE_ARGUMENT(0x1A, IsLocal), - METHOD_TYPE_ARGUMENT_GENERIC_OR_ARRAY(0x1B, HasLocation, IsLocal), + /** For annotations on an exception parameter. */ + EXCEPTION_PARAMETER(0x42, true), - WILDCARD_BOUND(0x1C, HasBound), - WILDCARD_BOUND_GENERIC_OR_ARRAY(0x1D, HasBound, HasLocation), + /** For annotations on a typecast. */ + CAST(0x43, true), - CLASS_LITERAL(0x1E, IsLocal), - CLASS_LITERAL_GENERIC_OR_ARRAY(0x1F, HasLocation, IsLocal), + /** For annotations on a type test. */ + INSTANCEOF(0x44, true), - METHOD_TYPE_PARAMETER(0x20, HasParameter), + /** For annotations on an object creation expression. */ + NEW(0x45, true), - // invalid location - //@Deprecated METHOD_TYPE_PARAMETER_GENERIC_OR_ARRAY(0x21, HasLocation, HasParameter), + /** For annotations on a type argument of an object creation expression. */ + CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(0x46, true), - CLASS_TYPE_PARAMETER(0x22, HasParameter), + /** For annotations on a type argument of a method call. */ + METHOD_INVOCATION_TYPE_ARGUMENT(0x47, true), - // invalid location - //@Deprecated CLASS_TYPE_PARAMETER_GENERIC_OR_ARRAY(0x23, HasLocation, HasParameter), + /** For annotations on a lambda parameter type. */ + LAMBDA_FORMAL_PARAMETER(0x48, true), + + /** For annotations on a method reference. */ + METHOD_REFERENCE(0x49, true), + + /** For annotations on a type argument of a method reference. */ + METHOD_REFERENCE_TYPE_ARGUMENT(0x50, true), /** For annotations with an unknown target. */ - UNKNOWN(-1); + UNKNOWN(0xFF); - static final int MAXIMUM_TARGET_TYPE_VALUE = 0x22; + private static final int MAXIMUM_TARGET_TYPE_VALUE = 0x92; private final int targetTypeValue; - private final Set<TargetAttribute> flags; + private final boolean isLocal; - TargetType(int targetTypeValue, TargetAttribute... attributes) { - if (targetTypeValue < Byte.MIN_VALUE - || targetTypeValue > Byte.MAX_VALUE) - throw new AssertionError("attribute type value needs to be a byte: " + targetTypeValue); - this.targetTypeValue = (byte)targetTypeValue; - flags = EnumSet.noneOf(TargetAttribute.class); - for (TargetAttribute attr : attributes) - flags.add(attr); + private TargetType(int targetTypeValue) { + this(targetTypeValue, false); } - /** - * Returns whether or not this TargetType represents an annotation whose - * target is an inner type of a generic or array type. - * - * @return true if this TargetType represents an annotation on an inner - * type, false otherwise - */ - public boolean hasLocation() { - return flags.contains(HasLocation); - } - - public TargetType getGenericComplement() { - if (hasLocation()) - return this; - else - return fromTargetTypeValue(targetTypeValue() + 1); - } - - /** - * Returns whether or not this TargetType represents an annotation whose - * target has a parameter index. - * - * @return true if this TargetType has a parameter index, - * false otherwise - */ - public boolean hasParameter() { - return flags.contains(HasParameter); - } - - /** - * Returns whether or not this TargetType represents an annotation whose - * target is a type parameter bound. - * - * @return true if this TargetType represents an type parameter bound - * annotation, false otherwise - */ - public boolean hasBound() { - return flags.contains(HasBound); + private TargetType(int targetTypeValue, boolean isLocal) { + if (targetTypeValue < 0 + || targetTypeValue > 255) + Assert.error("Attribute type value needs to be an unsigned byte: " + String.format("0x%02X", targetTypeValue)); + this.targetTypeValue = targetTypeValue; + this.isLocal = isLocal; } /** @@ -226,7 +134,7 @@ * member declaration signature tree */ public boolean isLocal() { - return flags.contains(IsLocal); + return isLocal; } public int targetTypeValue() { @@ -239,7 +147,7 @@ targets = new TargetType[MAXIMUM_TARGET_TYPE_VALUE + 1]; TargetType[] alltargets = values(); for (TargetType target : alltargets) { - if (target.targetTypeValue >= 0) + if (target.targetTypeValue != UNKNOWN.targetTypeValue) targets[target.targetTypeValue] = target; } for (int i = 0; i <= MAXIMUM_TARGET_TYPE_VALUE; ++i) { @@ -249,22 +157,18 @@ } public static boolean isValidTargetTypeValue(int tag) { - if (((byte)tag) == ((byte)UNKNOWN.targetTypeValue)) + if (tag == UNKNOWN.targetTypeValue) return true; return (tag >= 0 && tag < targets.length); } public static TargetType fromTargetTypeValue(int tag) { - if (((byte)tag) == ((byte)UNKNOWN.targetTypeValue)) + if (tag == UNKNOWN.targetTypeValue) return UNKNOWN; if (tag < 0 || tag >= targets.length) - throw new IllegalArgumentException("Unknown TargetType: " + tag); + Assert.error("Unknown TargetType: " + tag); return targets[tag]; } - - static enum TargetAttribute { - HasLocation, HasParameter, HasBound, IsLocal; - } }
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -31,6 +31,7 @@ import java.util.Map; import java.util.Set; +import javax.lang.model.element.AnnotationMirror; import javax.lang.model.type.*; import com.sun.tools.javac.code.Symbol.*; @@ -87,7 +88,7 @@ */ protected TypeTag tag; - /** The defining class / interface / package / type variable + /** The defining class / interface / package / type variable. */ public TypeSymbol tsym; @@ -166,7 +167,7 @@ /** * Get the representation of this type used for modelling purposes. * By default, this is itself. For ErrorType, a different value - * may be provided, + * may be provided. */ public Type getModelType() { return this; @@ -245,6 +246,14 @@ return this; } + /** + * If this is an annotated type, return the underlying type. + * Otherwise, return the type itself. + */ + public Type unannotatedType() { + return this; + } + /** Return the base types of a list of types. */ public static List<Type> baseTypes(List<Type> ts) { @@ -339,8 +348,11 @@ args = args.tail; buf.append(','); } - if (args.head.tag == ARRAY) { - buf.append(((ArrayType)args.head).elemtype); + if (args.head.unannotatedType().tag == ARRAY) { + buf.append(((ArrayType)args.head.unannotatedType()).elemtype); + if (args.head.getAnnotations().nonEmpty()) { + buf.append(args.head.getAnnotations()); + } buf.append("..."); } else { buf.append(args.head); @@ -350,10 +362,12 @@ /** Access methods. */ + public List<? extends AnnotationMirror> getAnnotations() { return List.nil(); } public List<Type> getTypeArguments() { return List.nil(); } - public Type getEnclosingType() { return null; } + public Type getEnclosingType() { return null; } public List<Type> getParameterTypes() { return List.nil(); } public Type getReturnType() { return null; } + public Type getReceiverType() { return null; } public List<Type> getThrownTypes() { return List.nil(); } public Type getUpperBound() { return null; } public Type getLowerBound() { return null; } @@ -600,7 +614,7 @@ /** The enclosing type of this type. If this is the type of an inner * class, outer_field refers to the type of its enclosing - * instance class, in all other cases it referes to noType. + * instance class, in all other cases it refers to noType. */ private Type outer_field; @@ -974,6 +988,10 @@ public Type restype; public List<Type> thrown; + /** The type annotations on the method receiver. + */ + public Type recvtype; + public MethodType(List<Type> argtypes, Type restype, List<Type> thrown, @@ -1000,6 +1018,7 @@ public List<Type> getParameterTypes() { return argtypes; } public Type getReturnType() { return restype; } + public Type getReceiverType() { return recvtype; } public List<Type> getThrownTypes() { return thrown; } public boolean isErroneous() { @@ -1028,6 +1047,7 @@ for (List<Type> l = argtypes; l.nonEmpty(); l = l.tail) l.head.complete(); restype.complete(); + recvtype.complete(); for (List<Type> l = thrown; l.nonEmpty(); l = l.tail) l.head.complete(); } @@ -1112,7 +1132,11 @@ } @Override - public Type getUpperBound() { return bound; } + public Type getUpperBound() { + if ((bound == null || bound.tag == NONE) && this != tsym.type) + bound = tsym.type.getUpperBound(); + return bound; + } int rank_field = -1; @@ -1183,6 +1207,7 @@ public Type getEnclosingType() { return qtype.getEnclosingType(); } public List<Type> getParameterTypes() { return qtype.getParameterTypes(); } public Type getReturnType() { return qtype.getReturnType(); } + public Type getReceiverType() { return qtype.getReceiverType(); } public List<Type> getThrownTypes() { return qtype.getThrownTypes(); } public List<Type> allparams() { return qtype.allparams(); } public Type getUpperBound() { return qtype.getUpperBound(); } @@ -1435,7 +1460,7 @@ } public Type constType(Object constValue) { return this; } - public Type getEnclosingType() { return this; } + public Type getEnclosingType() { return this; } public Type getReturnType() { return this; } public Type asSub(Symbol sym) { return this; } public Type map(Mapping f) { return this; } @@ -1461,11 +1486,165 @@ } } + public static class AnnotatedType extends Type + implements javax.lang.model.type.AnnotatedType { + /** The type annotations on this type. + */ + public List<Attribute.TypeCompound> typeAnnotations; + + /** The underlying type that is annotated. + */ + public Type underlyingType; + + public AnnotatedType(Type underlyingType) { + super(underlyingType.tag, underlyingType.tsym); + this.typeAnnotations = List.nil(); + this.underlyingType = underlyingType; + Assert.check(underlyingType.getKind() != TypeKind.ANNOTATED, + "Can't annotate already annotated type: " + underlyingType); + } + + public AnnotatedType(List<Attribute.TypeCompound> typeAnnotations, + Type underlyingType) { + super(underlyingType.tag, underlyingType.tsym); + this.typeAnnotations = typeAnnotations; + this.underlyingType = underlyingType; + Assert.check(underlyingType.getKind() != TypeKind.ANNOTATED, + "Can't annotate already annotated type: " + underlyingType + + "; adding: " + typeAnnotations); + } + + @Override + public TypeKind getKind() { + return TypeKind.ANNOTATED; + } + + @Override + public List<? extends AnnotationMirror> getAnnotations() { + return typeAnnotations; + } + + @Override + public TypeMirror getUnderlyingType() { + return underlyingType; + } + + @Override + public Type unannotatedType() { + return underlyingType; + } + + @Override + public <R,S> R accept(Type.Visitor<R,S> v, S s) { + return v.visitAnnotatedType(this, s); + } + + @Override + public <R, P> R accept(TypeVisitor<R, P> v, P p) { + return v.visitAnnotated(this, p); + } + + @Override + public Type map(Mapping f) { + underlyingType.map(f); + return this; + } + + @Override + public Type constType(Object constValue) { return underlyingType.constType(constValue); } + @Override + public Type getEnclosingType() { return underlyingType.getEnclosingType(); } + + @Override + public Type getReturnType() { return underlyingType.getReturnType(); } + @Override + public List<Type> getTypeArguments() { return underlyingType.getTypeArguments(); } + @Override + public List<Type> getParameterTypes() { return underlyingType.getParameterTypes(); } + @Override + public Type getReceiverType() { return underlyingType.getReceiverType(); } + @Override + public List<Type> getThrownTypes() { return underlyingType.getThrownTypes(); } + @Override + public Type getUpperBound() { return underlyingType.getUpperBound(); } + @Override + public Type getLowerBound() { return underlyingType.getLowerBound(); } + + @Override + public boolean isErroneous() { return underlyingType.isErroneous(); } + @Override + public boolean isCompound() { return underlyingType.isCompound(); } + @Override + public boolean isInterface() { return underlyingType.isInterface(); } + @Override + public List<Type> allparams() { return underlyingType.allparams(); } + @Override + public boolean isNumeric() { return underlyingType.isNumeric(); } + @Override + public boolean isReference() { return underlyingType.isReference(); } + @Override + public boolean isParameterized() { return underlyingType.isParameterized(); } + @Override + public boolean isRaw() { return underlyingType.isRaw(); } + @Override + public boolean isFinal() { return underlyingType.isFinal(); } + @Override + public boolean isSuperBound() { return underlyingType.isSuperBound(); } + @Override + public boolean isExtendsBound() { return underlyingType.isExtendsBound(); } + @Override + public boolean isUnbound() { return underlyingType.isUnbound(); } + + @Override + public String toString() { + // TODO more logic for arrays, etc. + if (typeAnnotations != null && + !typeAnnotations.isEmpty()) { + return "(" + typeAnnotations.toString() + " :: " + underlyingType.toString() + ")"; + } else { + return "({} :: " + underlyingType.toString() +")"; + } + } + + @Override + public boolean contains(Type t) { return underlyingType.contains(t); } + + // TODO: attach annotations? + @Override + public Type withTypeVar(Type t) { return underlyingType.withTypeVar(t); } + + // TODO: attach annotations? + @Override + public TypeSymbol asElement() { return underlyingType.asElement(); } + + // TODO: attach annotations? + @Override + public MethodType asMethodType() { return underlyingType.asMethodType(); } + + @Override + public void complete() { underlyingType.complete(); } + + @Override + public TypeMirror getComponentType() { return ((ArrayType)underlyingType).getComponentType(); } + + // The result is an ArrayType, but only in the model sense, not the Type sense. + public AnnotatedType makeVarargs() { + AnnotatedType atype = new AnnotatedType(((ArrayType)underlyingType).makeVarargs()); + atype.typeAnnotations = this.typeAnnotations; + return atype; + } + + @Override + public TypeMirror getExtendsBound() { return ((WildcardType)underlyingType).getExtendsBound(); } + @Override + public TypeMirror getSuperBound() { return ((WildcardType)underlyingType).getSuperBound(); } + } + /** * A visitor for types. A visitor is used to implement operations * (or relations) on types. Most common operations on types are * binary relations and this interface is designed for binary - * relations, that is, operations on the form + * relations, that is, operations of the form * Type × S → R. * <!-- In plain text: Type x S -> R --> * @@ -1486,6 +1665,7 @@ R visitForAll(ForAll t, S s); R visitUndetVar(UndetVar t, S s); R visitErrorType(ErrorType t, S s); + R visitAnnotatedType(AnnotatedType t, S s); R visitType(Type t, S s); } }
--- a/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,6 +25,8 @@ package com.sun.tools.javac.code; +import java.util.Iterator; + import com.sun.tools.javac.util.*; /** A type annotation position. @@ -34,12 +36,92 @@ * This code and its internal interfaces are subject to change or * deletion without notice.</b> */ +// Code duplicated in com.sun.tools.classfile.TypeAnnotation.Position public class TypeAnnotationPosition { + public enum TypePathEntryKind { + ARRAY(0), + INNER_TYPE(1), + WILDCARD(2), + TYPE_ARGUMENT(3); + + public final int tag; + + private TypePathEntryKind(int tag) { + this.tag = tag; + } + } + + public static class TypePathEntry { + /** The fixed number of bytes per TypePathEntry. */ + public static final int bytesPerEntry = 2; + + public final TypePathEntryKind tag; + public final int arg; + + public static final TypePathEntry ARRAY = new TypePathEntry(TypePathEntryKind.ARRAY); + public static final TypePathEntry INNER_TYPE = new TypePathEntry(TypePathEntryKind.INNER_TYPE); + public static final TypePathEntry WILDCARD = new TypePathEntry(TypePathEntryKind.WILDCARD); + + private TypePathEntry(TypePathEntryKind tag) { + Assert.check(tag == TypePathEntryKind.ARRAY || + tag == TypePathEntryKind.INNER_TYPE || + tag == TypePathEntryKind.WILDCARD, + "Invalid TypePathEntryKind: " + tag); + this.tag = tag; + this.arg = 0; + } + + public TypePathEntry(TypePathEntryKind tag, int arg) { + Assert.check(tag == TypePathEntryKind.TYPE_ARGUMENT, + "Invalid TypePathEntryKind: " + tag); + this.tag = tag; + this.arg = arg; + } + + public static TypePathEntry fromBinary(int tag, int arg) { + Assert.check(arg == 0 || tag == TypePathEntryKind.TYPE_ARGUMENT.tag, + "Invalid TypePathEntry tag/arg: " + tag + "/" + arg); + switch (tag) { + case 0: + return ARRAY; + case 1: + return INNER_TYPE; + case 2: + return WILDCARD; + case 3: + return new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, arg); + default: + Assert.error("Invalid TypePathEntryKind tag: " + tag); + return null; + } + } + + @Override + public String toString() { + return tag.toString() + + (tag == TypePathEntryKind.TYPE_ARGUMENT ? ("(" + arg + ")") : ""); + } + + @Override + public boolean equals(Object other) { + if (! (other instanceof TypePathEntry)) { + return false; + } + TypePathEntry tpe = (TypePathEntry) other; + return this.tag == tpe.tag && this.arg == tpe.arg; + } + + @Override + public int hashCode() { + return this.tag.hashCode() * 17 + this.arg; + } + } + public TargetType type = TargetType.UNKNOWN; // For generic/array types. - public List<Integer> location = List.nil(); + public List<TypePathEntry> location = List.nil(); // Tree position. public int pos = -1; @@ -59,11 +141,13 @@ // For type parameter and method parameter public int parameter_index = Integer.MIN_VALUE; - // For class extends, implements, and throws classes + // For class extends, implements, and throws clauses public int type_index = Integer.MIN_VALUE; - // For wildcards - public TypeAnnotationPosition wildcard_position = null; + // For exception parameters, index into exception table + public int exception_index = Integer.MIN_VALUE; + + public TypeAnnotationPosition() {} @Override public String toString() { @@ -72,27 +156,27 @@ sb.append(type); switch (type) { - // type case - case TYPECAST: - case TYPECAST_GENERIC_OR_ARRAY: - // object creation + // type cast + case CAST: + // instanceof case INSTANCEOF: - case INSTANCEOF_GENERIC_OR_ARRAY: - // new expression + // new expression case NEW: - case NEW_GENERIC_OR_ARRAY: - case NEW_TYPE_ARGUMENT: - case NEW_TYPE_ARGUMENT_GENERIC_OR_ARRAY: sb.append(", offset = "); sb.append(offset); break; - // local variable + // local variable case LOCAL_VARIABLE: - case LOCAL_VARIABLE_GENERIC_OR_ARRAY: + // resource variable + case RESOURCE_VARIABLE: + if (lvarOffset == null) { + sb.append(", lvarOffset is null!"); + break; + } sb.append(", {"); for (int i = 0; i < lvarOffset.length; ++i) { if (i != 0) sb.append("; "); - sb.append(", start_pc = "); + sb.append("start_pc = "); sb.append(lvarOffset[i]); sb.append(", length = "); sb.append(lvarLength[i]); @@ -101,73 +185,72 @@ } sb.append("}"); break; - // method receiver + // method receiver case METHOD_RECEIVER: // Do nothing break; - // type parameters + // type parameter case CLASS_TYPE_PARAMETER: case METHOD_TYPE_PARAMETER: sb.append(", param_index = "); sb.append(parameter_index); break; - // type parameters bound + // type parameter bound case CLASS_TYPE_PARAMETER_BOUND: - case CLASS_TYPE_PARAMETER_BOUND_GENERIC_OR_ARRAY: case METHOD_TYPE_PARAMETER_BOUND: - case METHOD_TYPE_PARAMETER_BOUND_GENERIC_OR_ARRAY: sb.append(", param_index = "); sb.append(parameter_index); sb.append(", bound_index = "); sb.append(bound_index); break; - // wildcard - case WILDCARD_BOUND: - case WILDCARD_BOUND_GENERIC_OR_ARRAY: - sb.append(", wild_card = "); - sb.append(wildcard_position); - break; - // Class extends and implements clauses + // class extends or implements clause case CLASS_EXTENDS: - case CLASS_EXTENDS_GENERIC_OR_ARRAY: sb.append(", type_index = "); sb.append(type_index); break; - // throws + // throws case THROWS: sb.append(", type_index = "); sb.append(type_index); break; - case CLASS_LITERAL: - case CLASS_LITERAL_GENERIC_OR_ARRAY: - sb.append(", offset = "); - sb.append(offset); + // exception parameter + case EXCEPTION_PARAMETER: + sb.append(", exception_index = "); + sb.append(exception_index); break; - // method parameter: not specified - case METHOD_PARAMETER_GENERIC_OR_ARRAY: + // method parameter + case METHOD_FORMAL_PARAMETER: sb.append(", param_index = "); sb.append(parameter_index); break; - // method type argument: wasn't specified - case METHOD_TYPE_ARGUMENT: - case METHOD_TYPE_ARGUMENT_GENERIC_OR_ARRAY: + // method/constructor/reference type argument + case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: + case METHOD_INVOCATION_TYPE_ARGUMENT: + case METHOD_REFERENCE_TYPE_ARGUMENT: sb.append(", offset = "); sb.append(offset); sb.append(", type_index = "); sb.append(type_index); break; - // We don't need to worry abut these - case METHOD_RETURN_GENERIC_OR_ARRAY: - case FIELD_GENERIC_OR_ARRAY: + // We don't need to worry about these + case METHOD_RETURN: + case FIELD: + break; + // lambda formal parameter + case LAMBDA_FORMAL_PARAMETER: + // TODO: also needs an offset? + sb.append(", param_index = "); + sb.append(parameter_index); break; case UNKNOWN: + sb.append(", position UNKNOWN!"); break; default: - // throw new AssertionError("unknown type: " + type); + Assert.error("Unknown target type: " + type); } // Append location data for generics/arrays. - if (type.hasLocation()) { + if (!location.isEmpty()) { sb.append(", location = ("); sb.append(location); sb.append(")"); @@ -186,10 +269,33 @@ * @return true if the target has not been optimized away */ public boolean emitToClassfile() { - if (type == TargetType.WILDCARD_BOUND - || type == TargetType.WILDCARD_BOUND_GENERIC_OR_ARRAY) - return wildcard_position.isValidOffset; - else - return !type.isLocal() || isValidOffset; + return !type.isLocal() || isValidOffset; + } + + /** + * Decode the binary representation for a type path and set + * the {@code location} field. + * + * @param list The bytecode representation of the type path. + */ + public static List<TypePathEntry> getTypePathFromBinary(java.util.List<Integer> list) { + ListBuffer<TypePathEntry> loc = ListBuffer.lb(); + Iterator<Integer> iter = list.iterator(); + while (iter.hasNext()) { + Integer fst = iter.next(); + Assert.check(iter.hasNext(), "Could not decode type path: " + list); + Integer snd = iter.next(); + loc = loc.append(TypePathEntry.fromBinary(fst, snd)); + } + return loc.toList(); + } + + public static List<Integer> getBinaryFromTypePath(java.util.List<TypePathEntry> locs) { + ListBuffer<Integer> loc = ListBuffer.lb(); + for (TypePathEntry tpe : locs) { + loc = loc.append(tpe.tag.tag); + loc = loc.append(tpe.arg); + } + return loc.toList(); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Sat Jan 26 19:24:46 2013 -0800 @@ -0,0 +1,1037 @@ +/* + * 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 com.sun.tools.javac.code.Attribute; +import com.sun.tools.javac.code.Attribute.TypeCompound; +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.code.Kinds; +import com.sun.tools.javac.code.Type.AnnotatedType; +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.TypeTag; +import com.sun.tools.javac.code.Symbol.VarSymbol; +import com.sun.tools.javac.comp.Annotate.Annotator; +import com.sun.tools.javac.tree.JCTree; +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.JCMethodDecl; +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.List; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.util.Names; + +/** + * 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 { + // Class cannot be instantiated. + private TypeAnnotations() {} + + /** + * 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 returns the Annotator object that should be added + * to the correct Annotate queue for later processing. + */ + public static Annotator organizeTypeAnnotationsSignatures(final Symtab syms, final Names names, + final Log log, final JCClassDecl tree) { + return new Annotator() { + @Override + public void enterAnnotation() { + new TypeAnnotationPositions(syms, names, log, true).scan(tree); + } + }; + } + + /** + * This version only visits types in bodies, that is, field initializers, + * top-level blocks, and method bodies, and should be called from Attr. + */ + public static void organizeTypeAnnotationsBodies(Symtab syms, Names names, Log log, JCClassDecl tree) { + new TypeAnnotationPositions(syms, names, log, false).scan(tree); + } + + private static class TypeAnnotationPositions extends TreeScanner { + + private enum AnnotationType { DECLARATION, TYPE, BOTH }; + + private final Symtab syms; + private final Names names; + private final Log log; + private final boolean sigOnly; + + private TypeAnnotationPositions(Symtab syms, Names names, Log log, boolean sigOnly) { + this.syms = syms; + this.names = names; + this.log = log; + this.sigOnly = sigOnly; + } + + /* + * When traversing the AST we keep the "frames" of visited + * trees in order to determine the position of annotations. + */ + private ListBuffer<JCTree> frames = ListBuffer.lb(); + + 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) { + /* + System.out.printf("separateAnnotationsKinds(typetree: %s, type: %s, symbol: %s, pos: %s%n", + typetree, type, sym, pos); + */ + List<Attribute.Compound> annotations = sym.getRawAttributes(); + ListBuffer<Attribute.Compound> declAnnos = new ListBuffer<Attribute.Compound>(); + ListBuffer<Attribute.TypeCompound> typeAnnos = new ListBuffer<Attribute.TypeCompound>(); + + 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); + break; + } + } + } + + sym.annotations.reset(); + sym.annotations.setDeclarationAttributes(declAnnos.toList()); + + List<Attribute.TypeCompound> 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 + // no appropriate type exists. + sym.annotations.appendUniqueTypes(typeAnnotations); + return; + } + + // type is non-null and annotations are added to that type + type = typeWithAnnotations(typetree, type, typeAnnotations, log); + + if (sym.getKind() == ElementKind.METHOD) { + sym.type.asMethodType().restype = type; + } else { + sym.type = type; + } + + sym.annotations.appendUniqueTypes(typeAnnotations); + if (sym.getKind() == ElementKind.PARAMETER && + sym.getQualifiedName().equals(names._this)) { + sym.owner.type.asMethodType().recvtype = type; + // note that the typeAnnotations will also be added to the owner below. + } + 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.annotations.appendUniqueTypes(sym.getTypeAnnotationMirrors()); + } + } + + // This method has a similar purpose as + // {@link com.sun.tools.javac.parser.JavacParser.insertAnnotationsToMostInner(JCExpression, List<JCTypeAnnotation>, 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. + private static Type typeWithAnnotations(final JCTree typetree, final Type type, + final List<Attribute.TypeCompound> annotations, Log log) { + // System.out.printf("typeWithAnnotations(typetree: %s, type: %s, annotations: %s)%n", + // typetree, type, annotations); + if (annotations.isEmpty()) { + return type; + } + if (type.hasTag(TypeTag.ARRAY)) { + Type toreturn; + Type.ArrayType tomodify; + Type.ArrayType arType; + { + Type touse = type; + if (type.getKind() == TypeKind.ANNOTATED) { + Type.AnnotatedType atype = (Type.AnnotatedType)type; + toreturn = new Type.AnnotatedType(atype.underlyingType); + ((Type.AnnotatedType)toreturn).typeAnnotations = atype.typeAnnotations; + touse = atype.underlyingType; + arType = (Type.ArrayType) touse; + tomodify = new Type.ArrayType(null, arType.tsym); + ((Type.AnnotatedType)toreturn).underlyingType = tomodify; + } else { + arType = (Type.ArrayType) touse; + tomodify = new Type.ArrayType(null, arType.tsym); + toreturn = tomodify; + } + } + JCArrayTypeTree arTree = arrayTypeTree(typetree); + + ListBuffer<TypePathEntry> depth = ListBuffer.lb(); + depth = depth.append(TypePathEntry.ARRAY); + while (arType.elemtype.hasTag(TypeTag.ARRAY)) { + if (arType.elemtype.getKind() == TypeKind.ANNOTATED) { + Type.AnnotatedType aelemtype = (Type.AnnotatedType) arType.elemtype; + Type.AnnotatedType newAT = new Type.AnnotatedType(aelemtype.underlyingType); + tomodify.elemtype = newAT; + newAT.typeAnnotations = aelemtype.typeAnnotations; + arType = (Type.ArrayType) aelemtype.underlyingType; + tomodify = new Type.ArrayType(null, arType.tsym); + newAT.underlyingType = tomodify; + } else { + arType = (Type.ArrayType) arType.elemtype; + tomodify.elemtype = new Type.ArrayType(null, arType.tsym); + tomodify = (Type.ArrayType) tomodify.elemtype; + } + arTree = arrayTypeTree(arTree.elemtype); + depth = depth.append(TypePathEntry.ARRAY); + } + Type arelemType = typeWithAnnotations(arTree.elemtype, arType.elemtype, annotations, log); + tomodify.elemtype = arelemType; + for (Attribute.TypeCompound a : annotations) { + TypeAnnotationPosition p = a.position; + p.location = p.location.prependList(depth.toList()); + } + return toreturn; + } else if (type.hasTag(TypeTag.TYPEVAR)) { + // Nothing to do for type variables. + 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.getKind() == TypeKind.NONE && + (enclTr.getKind() == JCTree.Kind.IDENTIFIER || + enclTr.getKind() == JCTree.Kind.MEMBER_SELECT || + enclTr.getKind() == JCTree.Kind.PARAMETERIZED_TYPE || + enclTr.getKind() == JCTree.Kind.ANNOTATED_TYPE)) { + // TODO: also if it's "java. @A lang.Object", that is, + // if it's on a package? + log.error(enclTr.pos(), "cant.annotate.nested.type", enclTr.toString()); + 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<TypePathEntry> depth = ListBuffer.lb(); + + 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. + for (Attribute.TypeCompound a : annotations) { + TypeAnnotationPosition p = a.position; + p.location = p.location.appendList(depth.toList()); + } + } + + Type ret = typeWithAnnotations(type, enclTy, annotations); + return ret; + } + } + + private static 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 static Type typeWithAnnotations(final Type type, + final Type stopAt, + final List<Attribute.TypeCompound> annotations) { + Visitor<Type, List<TypeCompound>> visitor = + new Type.Visitor<Type, List<Attribute.TypeCompound>>() { + @Override + public Type visitClassType(ClassType t, List<TypeCompound> s) { + // assert that t.constValue() == null? + if (t == stopAt || + t.getEnclosingType() == Type.noType) { + return new AnnotatedType(s, t); + } else { + ClassType ret = new ClassType(t.getEnclosingType().accept(this, s), + t.typarams_field, t.tsym); + 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 visitAnnotatedType(AnnotatedType t, List<TypeCompound> s) { + return new AnnotatedType(t.typeAnnotations, t.underlyingType.accept(this, s)); + } + + @Override + public Type visitWildcardType(WildcardType t, List<TypeCompound> s) { + return new AnnotatedType(s, t); + } + + @Override + public Type visitArrayType(ArrayType t, List<TypeCompound> s) { + ArrayType ret = new ArrayType(t.elemtype.accept(this, s), t.tsym); + return ret; + } + + @Override + public Type visitMethodType(MethodType t, List<TypeCompound> s) { + // Impossible? + return t; + } + + @Override + public Type visitPackageType(PackageType t, List<TypeCompound> s) { + // Impossible? + return t; + } + + @Override + public Type visitTypeVar(TypeVar t, List<TypeCompound> s) { + return new AnnotatedType(s, t); + } + + @Override + public Type visitCapturedType(CapturedType t, List<TypeCompound> s) { + return new AnnotatedType(s, t); + } + + @Override + public Type visitForAll(ForAll t, List<TypeCompound> s) { + // Impossible? + return t; + } + + @Override + public Type visitUndetVar(UndetVar t, List<TypeCompound> s) { + // Impossible? + return t; + } + + @Override + public Type visitErrorType(ErrorType t, List<TypeCompound> s) { + return new AnnotatedType(s, t); + } + + @Override + public Type visitType(Type t, List<TypeCompound> s) { + // Error? + return t; + } + }; + + return type.accept(visitor, annotations); + } + + private static Attribute.TypeCompound toTypeCompound(Attribute.Compound a, TypeAnnotationPosition p) { + // It is safe to alias the position. + return new Attribute.TypeCompound(a, p); + } + + private 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; + } + + + /* This is the beginning of the second part of organizing + * type annotations: determine the type annotation positions. + */ + + private void resolveFrame(JCTree tree, JCTree frame, + List<JCTree> path, TypeAnnotationPosition p) { + /* + System.out.println("Resolving tree: " + tree + " kind: " + tree.getKind()); + System.out.println(" Framing tree: " + frame + " kind: " + frame.getKind()); + */ + switch (frame.getKind()) { + case TYPE_CAST: + p.type = TargetType.CAST; + p.pos = frame.pos; + return; + + case INSTANCE_OF: + p.type = TargetType.INSTANCEOF; + p.pos = frame.pos; + return; + + case NEW_CLASS: + JCNewClass frameNewClass = (JCNewClass)frame; + if (frameNewClass.typeargs.contains(tree)) { + p.type = TargetType.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT; + p.type_index = frameNewClass.typeargs.indexOf(tree); + } else { + p.type = TargetType.NEW; + } + p.pos = frame.pos; + return; + + case NEW_ARRAY: + p.type = TargetType.NEW; + p.pos = frame.pos; + return; + + case ANNOTATION_TYPE: + case CLASS: + case ENUM: + case INTERFACE: + p.pos = frame.pos; + if (((JCClassDecl)frame).extending == tree) { + p.type = TargetType.CLASS_EXTENDS; + p.type_index = -1; + } else if (((JCClassDecl)frame).implementing.contains(tree)) { + p.type = TargetType.CLASS_EXTENDS; + p.type_index = ((JCClassDecl)frame).implementing.indexOf(tree); + } else if (((JCClassDecl)frame).typarams.contains(tree)) { + p.type = TargetType.CLASS_TYPE_PARAMETER; + p.parameter_index = ((JCClassDecl)frame).typarams.indexOf(tree); + } else { + Assert.error("Could not determine position of tree " + tree + + " within frame " + frame); + } + return; + + case METHOD: { + JCMethodDecl frameMethod = (JCMethodDecl) frame; + p.pos = frame.pos; + if (frameMethod.thrown.contains(tree)) { + p.type = TargetType.THROWS; + p.type_index = frameMethod.thrown.indexOf(tree); + } else if (frameMethod.restype == tree) { + p.type = TargetType.METHOD_RETURN; + } else if (frameMethod.typarams.contains(tree)) { + p.type = TargetType.METHOD_TYPE_PARAMETER; + p.parameter_index = frameMethod.typarams.indexOf(tree); + } else { + Assert.error("Could not determine position of tree " + tree + + " within frame " + frame); + } + return; + } + + case PARAMETERIZED_TYPE: { + 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); + p.location = p.location.prepend(new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, arg)); + + locateNestedTypes(taframe.type, p); + } else { + Assert.error("Could not determine type argument position of tree " + tree + + " within frame " + frame); + } + + List<JCTree> newPath = path.tail; + resolveFrame(newPath.head, newPath.tail.head, newPath, p); + return; + } + + case ARRAY_TYPE: { + ListBuffer<TypePathEntry> index = ListBuffer.lb(); + index = index.append(TypePathEntry.ARRAY); + List<JCTree> newPath = path.tail; + while (true) { + JCTree npHead = newPath.tail.head; + if (npHead.hasTag(JCTree.Tag.TYPEARRAY)) { + newPath = newPath.tail; + index = index.append(TypePathEntry.ARRAY); + } else if (npHead.hasTag(JCTree.Tag.ANNOTATED_TYPE)) { + newPath = newPath.tail; + } else { + break; + } + } + p.location = p.location.prependList(index.toList()); + resolveFrame(newPath.head, newPath.tail.head, newPath, p); + return; + } + + case TYPE_PARAMETER: + if (path.tail.tail.head.hasTag(JCTree.Tag.CLASSDEF)) { + JCClassDecl clazz = (JCClassDecl)path.tail.tail.head; + p.type = TargetType.CLASS_TYPE_PARAMETER_BOUND; + p.parameter_index = clazz.typarams.indexOf(path.tail.head); + p.bound_index = ((JCTypeParameter)frame).bounds.indexOf(tree); + if (((JCTypeParameter)frame).bounds.get(0).type.isInterface()) { + // Account for an implicit Object as bound 0 + p.bound_index += 1; + } + } else if (path.tail.tail.head.hasTag(JCTree.Tag.METHODDEF)) { + JCMethodDecl method = (JCMethodDecl)path.tail.tail.head; + p.type = TargetType.METHOD_TYPE_PARAMETER_BOUND; + p.parameter_index = method.typarams.indexOf(path.tail.head); + p.bound_index = ((JCTypeParameter)frame).bounds.indexOf(tree); + if (((JCTypeParameter)frame).bounds.get(0).type.isInterface()) { + // Account for an implicit Object as bound 0 + p.bound_index += 1; + } + } else { + Assert.error("Could not determine position of tree " + tree + + " within frame " + frame); + } + p.pos = frame.pos; + return; + + case VARIABLE: + VarSymbol v = ((JCVariableDecl)frame).sym; + p.pos = frame.pos; + switch (v.getKind()) { + case LOCAL_VARIABLE: + p.type = TargetType.LOCAL_VARIABLE; + break; + case FIELD: + p.type = TargetType.FIELD; + break; + case PARAMETER: + if (v.getQualifiedName().equals(names._this)) { + // TODO: Intro a separate ElementKind? + p.type = TargetType.METHOD_RECEIVER; + } else { + p.type = TargetType.METHOD_FORMAL_PARAMETER; + p.parameter_index = methodParamIndex(path, frame); + } + break; + case EXCEPTION_PARAMETER: + p.type = TargetType.EXCEPTION_PARAMETER; + break; + case RESOURCE_VARIABLE: + p.type = TargetType.RESOURCE_VARIABLE; + break; + default: + Assert.error("Found unexpected type annotation for variable: " + v + " with kind: " + v.getKind()); + } + return; + + 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; + 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 { + locateNestedTypes(utype, p); + } + } + List<JCTree> newPath = path.tail; + resolveFrame(newPath.head, newPath.tail.head, newPath, p); + return; + } + + case UNION_TYPE: { + // TODO: can we store any information here to help in + // determining the final position? + List<JCTree> newPath = path.tail; + resolveFrame(newPath.head, newPath.tail.head, newPath, p); + return; + } + + case METHOD_INVOCATION: { + JCMethodInvocation invocation = (JCMethodInvocation)frame; + if (!invocation.typeargs.contains(tree)) { + Assert.error("{" + tree + "} is not an argument in the invocation: " + invocation); + } + p.type = TargetType.METHOD_INVOCATION_TYPE_ARGUMENT; + p.pos = invocation.pos; + p.type_index = invocation.typeargs.indexOf(tree); + return; + } + + case EXTENDS_WILDCARD: + case SUPER_WILDCARD: { + // Annotations in wildcard bounds + p.location = p.location.prepend(TypePathEntry.WILDCARD); + List<JCTree> newPath = path.tail; + resolveFrame(newPath.head, newPath.tail.head, newPath, p); + return; + } + + case MEMBER_SELECT: { + List<JCTree> newPath = path.tail; + resolveFrame(newPath.head, newPath.tail.head, newPath, p); + return; + } + + default: + Assert.error("Unresolved frame: " + frame + " of kind: " + frame.getKind() + + "\n Looking for tree: " + tree); + return; + } + } + + private static void locateNestedTypes(Type type, TypeAnnotationPosition p) { + // The number of "steps" to get from the full type to the + // left-most outer type. + ListBuffer<TypePathEntry> depth = ListBuffer.lb(); + + Type encl = type.getEnclosingType(); + while (encl != null && + encl.getKind() != TypeKind.NONE && + encl.getKind() != TypeKind.ERROR) { + depth = depth.append(TypePathEntry.INNER_TYPE); + encl = encl.getEnclosingType(); + } + if (depth.nonEmpty()) { + p.location = p.location.prependList(depth.toList()); + } + } + + private static int methodParamIndex(List<JCTree> path, JCTree param) { + List<JCTree> curr = path; + while (curr.head.getTag() != Tag.METHODDEF) { + curr = curr.tail; + } + JCMethodDecl method = (JCMethodDecl)curr.head; + return method.params.indexOf(param); + } + + // 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) { + // Something most be wrong, e.g. a class not found. + // Quietly ignore. (See test FailOver15.java) + return; + } + if (sigOnly) { + { + TypeAnnotationPosition pos = new TypeAnnotationPosition(); + pos.type = TargetType.METHOD_RETURN; + if (tree.sym.isConstructor()) { + pos.pos = tree.pos; + // Use null to mark that the annotations go with the symbol. + separateAnnotationsKinds(tree, null, tree.sym, pos); + } else { + pos.pos = tree.restype.pos; + separateAnnotationsKinds(tree.restype, tree.sym.type.getReturnType(), + tree.sym, pos); + } + } + if (tree.recvparam != null && tree.recvparam.sym != null) { + // TODO: make sure there are no declaration annotations. + TypeAnnotationPosition pos = new TypeAnnotationPosition(); + pos.type = TargetType.METHOD_RECEIVER; + pos.pos = tree.recvparam.vartype.pos; + separateAnnotationsKinds(tree.recvparam.vartype, tree.recvparam.sym.type, + tree.recvparam.sym, pos); + } + int i = 0; + for (JCVariableDecl param : tree.params) { + TypeAnnotationPosition pos = new TypeAnnotationPosition(); + pos.type = TargetType.METHOD_FORMAL_PARAMETER; + pos.parameter_index = i; + pos.pos = 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(); + } + + /** + * Resolve declaration vs. type annotations in variable declarations and + * then determine the positions. + */ + @Override + public void visitVarDef(final JCVariableDecl tree) { + if (tree.sym == null) { + // Something is wrong already. Quietly ignore. + } else if (tree.sym.getKind() == ElementKind.FIELD) { + if (sigOnly) { + TypeAnnotationPosition pos = new TypeAnnotationPosition(); + pos.type = TargetType.FIELD; + pos.pos = tree.pos; + separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos); + } + } else if (tree.sym.getKind() == ElementKind.LOCAL_VARIABLE) { + TypeAnnotationPosition pos = new TypeAnnotationPosition(); + pos.type = TargetType.LOCAL_VARIABLE; + pos.pos = tree.pos; + separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos); + } else if (tree.sym.getKind() == ElementKind.EXCEPTION_PARAMETER) { + // System.out.println("Found exception param: " + tree); + TypeAnnotationPosition pos = new TypeAnnotationPosition(); + pos.type = TargetType.EXCEPTION_PARAMETER; + pos.pos = tree.pos; + separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos); + } else if (tree.sym.getKind() == ElementKind.RESOURCE_VARIABLE) { + TypeAnnotationPosition pos = new TypeAnnotationPosition(); + pos.type = TargetType.RESOURCE_VARIABLE; + pos.pos = tree.pos; + separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos); + } else { + // There is nothing else in a variable declaration that needs separation. + // System.out.println("We found a: " + tree); + } + + 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); + } + + @Override + public void visitNewArray(JCNewArray tree) { + findPosition(tree, tree, tree.annotations); + int dimAnnosCount = tree.dimAnnotations.size(); + ListBuffer<TypePathEntry> depth = ListBuffer.lb(); + + // handle annotations associated with dimensions + for (int i = 0; i < dimAnnosCount; ++i) { + TypeAnnotationPosition p = new TypeAnnotationPosition(); + p.pos = tree.pos; + p.type = TargetType.NEW; + if (i != 0) { + depth = depth.append(TypePathEntry.ARRAY); + p.location = p.location.appendList(depth.toList()); + } + + 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; + while (elemType != null) { + if (elemType.hasTag(JCTree.Tag.ANNOTATED_TYPE)) { + JCAnnotatedType at = (JCAnnotatedType)elemType; + TypeAnnotationPosition p = new TypeAnnotationPosition(); + p.type = TargetType.NEW; + p.pos = tree.pos; + p.location = p.location.appendList(depth.toList()); + setTypeAnnotationPos(at.annotations, p); + elemType = at.underlyingType; + } else if (elemType.hasTag(JCTree.Tag.TYPEARRAY)) { + depth = depth.append(TypePathEntry.ARRAY); + elemType = ((JCArrayTypeTree)elemType).elemtype; + } else { + break; + } + } + scan(tree.elems); + } + + private void findPosition(JCTree tree, JCTree frame, List<JCAnnotation> annotations) { + if (!annotations.isEmpty()) { + /* + System.out.println("Finding pos for: " + annotations); + System.out.println(" tree: " + tree); + System.out.println(" frame: " + frame); + */ + TypeAnnotationPosition p = new TypeAnnotationPosition(); + resolveFrame(tree, frame, frames.toList(), p); + setTypeAnnotationPos(annotations, p); + } + } + + private static void setTypeAnnotationPos(List<JCAnnotation> annotations, + TypeAnnotationPosition position) { + for (JCAnnotation anno : annotations) { + ((Attribute.TypeCompound) anno.attribute).position = position; + } + } + } +}
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -34,13 +34,14 @@ import java.util.Set; import java.util.WeakHashMap; +import javax.lang.model.type.TypeKind; + import com.sun.tools.javac.code.Attribute.RetentionPolicy; import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Type.UndetVar.InferenceBound; import com.sun.tools.javac.comp.Check; import com.sun.tools.javac.jvm.ClassReader; import com.sun.tools.javac.util.*; -import com.sun.tools.javac.util.List; import static com.sun.tools.javac.code.BoundKind.*; import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Scope.*; @@ -354,8 +355,29 @@ return descSym; } - public Type getType(Type origin) { - return memberType(origin, descSym); + public Type getType(Type site) { + if (capture(site) != site) { + Type formalInterface = site.tsym.type; + ListBuffer<Type> typeargs = ListBuffer.lb(); + List<Type> actualTypeargs = site.getTypeArguments(); + //simply replace the wildcards with its bound + for (Type t : formalInterface.getTypeArguments()) { + if (actualTypeargs.head.hasTag(WILDCARD)) { + WildcardType wt = (WildcardType)actualTypeargs.head; + typeargs.append(wt.type); + } else { + typeargs.append(actualTypeargs.head); + } + actualTypeargs = actualTypeargs.tail; + } + site = subst(formalInterface, formalInterface.getTypeArguments(), typeargs.toList()); + if (!chk.checkValidGenericType(site)) { + //if the inferred functional interface type is not well-formed, + //or if it's not a subtype of the original target, issue an error + throw failure(diags.fragment("no.suitable.functional.intf.inst", site)); + } + } + return memberType(site, descSym); } } @@ -392,9 +414,9 @@ * Compute the function descriptor associated with a given functional interface */ public FunctionDescriptor findDescriptorInternal(TypeSymbol origin, CompoundScope membersCache) throws FunctionDescriptorLookupError { - if (!origin.isInterface()) { + if (!origin.isInterface() || (origin.flags() & ANNOTATION) != 0) { //t must be an interface - throw failure("not.a.functional.intf"); + throw failure("not.a.functional.intf", origin); } final ListBuffer<Symbol> abstracts = ListBuffer.lb(); @@ -406,13 +428,13 @@ abstracts.append(sym); } else { //the target method(s) should be the only abstract members of t - throw failure("not.a.functional.intf.1", + throw failure("not.a.functional.intf.1", origin, diags.fragment("incompatible.abstracts", Kinds.kindName(origin), origin)); } } if (abstracts.isEmpty()) { //t must define a suitable non-generic method - throw failure("not.a.functional.intf.1", + throw failure("not.a.functional.intf.1", origin, diags.fragment("no.abstracts", Kinds.kindName(origin), origin)); } else if (abstracts.size() == 1) { return new FunctionDescriptor(abstracts.first()); @@ -553,6 +575,15 @@ return false; } } + + public boolean isFunctionalInterface(Type site) { + try { + findDescriptorType(site); + return true; + } catch (FunctionDescriptorLookupError ex) { + return false; + } + } // </editor-fold> /** @@ -654,6 +685,8 @@ //where private boolean isSubtypeUncheckedInternal(Type t, Type s, Warner warn) { if (t.hasTag(ARRAY) && s.hasTag(ARRAY)) { + t = t.unannotatedType(); + s = s.unannotatedType(); if (((ArrayType)t).elemtype.isPrimitive()) { return isSameType(elemtype(t), elemtype(s)); } else { @@ -679,7 +712,10 @@ } private void checkUnsafeVarargsConversion(Type t, Type s, Warner warn) { - if (t.tag != ARRAY || isReifiable(t)) return; + if (t.tag != ARRAY || isReifiable(t)) + return; + t = t.unannotatedType(); + s = s.unannotatedType(); ArrayType from = (ArrayType)t; boolean shouldWarn = false; switch (s.tag) { @@ -712,6 +748,12 @@ if (t == s) return true; + t = t.unannotatedType(); + s = s.unannotatedType(); + + if (t == s) + return true; + if (s.isPartial()) return isSuperType(s, t); @@ -1653,6 +1695,7 @@ case WILDCARD: return elemtype(upperBound(t)); case ARRAY: + t = t.unannotatedType(); return ((ArrayType)t).elemtype; case FORALL: return elemtype(((ForAll)t).qtype); @@ -1981,6 +2024,11 @@ public Type visitErrorType(ErrorType t, Boolean recurse) { return t; } + + @Override + public Type visitAnnotatedType(AnnotatedType t, Boolean recurse) { + return new AnnotatedType(t.typeAnnotations, erasure(t.underlyingType, recurse)); + } }; private Mapping erasureFun = new Mapping ("erasure") { @@ -2923,6 +2971,7 @@ * graph. Undefined for all but reference types. */ public int rank(Type t) { + t = t.unannotatedType(); switch(t.tag) { case CLASS: { ClassType cls = (ClassType)t; @@ -3624,6 +3673,7 @@ t = subst(type1, t.tsym.type.getTypeArguments(), t.getTypeArguments()); } } + t = t.unannotatedType(); ClassType cls = (ClassType)t; if (cls.isRaw() || !cls.isParameterized()) return cls; @@ -4142,6 +4192,8 @@ public R visitForAll(ForAll t, S s) { return visitType(t, s); } public R visitUndetVar(UndetVar t, S s) { return visitType(t, s); } public R visitErrorType(ErrorType t, S s) { return visitType(t, s); } + // Pretend annotations don't exist + public R visitAnnotatedType(AnnotatedType t, S s) { return visit(t.underlyingType, s); } } /**
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -26,6 +26,7 @@ package com.sun.tools.javac.comp; import java.util.Map; + import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.code.*; @@ -87,20 +88,30 @@ private int enterCount = 0; ListBuffer<Annotator> q = new ListBuffer<Annotator>(); + ListBuffer<Annotator> typesQ = new ListBuffer<Annotator>(); ListBuffer<Annotator> repeatedQ = new ListBuffer<Annotator>(); + ListBuffer<Annotator> afterRepeatedQ = new ListBuffer<Annotator>(); + + public void earlier(Annotator a) { + q.prepend(a); + } public void normal(Annotator a) { q.append(a); } - public void earlier(Annotator a) { - q.prepend(a); + public void typeAnnotation(Annotator a) { + typesQ.append(a); } public void repeated(Annotator a) { repeatedQ.append(a); } + public void afterRepeated(Annotator a) { + afterRepeatedQ.append(a); + } + /** Called when the Enter phase starts. */ public void enterStart() { enterCount++; @@ -116,12 +127,18 @@ if (enterCount != 0) return; enterCount++; try { - while (q.nonEmpty()) + while (q.nonEmpty()) { q.next().enterAnnotation(); - + } + while (typesQ.nonEmpty()) { + typesQ.next().enterAnnotation(); + } while (repeatedQ.nonEmpty()) { repeatedQ.next().enterAnnotation(); } + while (afterRepeatedQ.nonEmpty()) { + afterRepeatedQ.next().enterAnnotation(); + } } finally { enterCount--; } @@ -141,16 +158,18 @@ * This context contains all the information needed to synthesize new * annotations trees by the completer for repeating annotations. */ - public class AnnotateRepeatedContext { + public class AnnotateRepeatedContext<T extends Attribute.Compound> { public final Env<AttrContext> env; - public final Map<Symbol.TypeSymbol, ListBuffer<Attribute.Compound>> annotated; - public final Map<Attribute.Compound, JCDiagnostic.DiagnosticPosition> pos; + public final Map<Symbol.TypeSymbol, ListBuffer<T>> annotated; + public final Map<T, JCDiagnostic.DiagnosticPosition> pos; public final Log log; + public final boolean isTypeCompound; public AnnotateRepeatedContext(Env<AttrContext> env, - Map<Symbol.TypeSymbol, ListBuffer<Attribute.Compound>> annotated, - Map<Attribute.Compound, JCDiagnostic.DiagnosticPosition> pos, - Log log) { + Map<Symbol.TypeSymbol, ListBuffer<T>> annotated, + Map<T, JCDiagnostic.DiagnosticPosition> pos, + Log log, + boolean isTypeCompound) { Assert.checkNonNull(env); Assert.checkNonNull(annotated); Assert.checkNonNull(pos); @@ -160,6 +179,7 @@ this.annotated = annotated; this.pos = pos; this.log = log; + this.isTypeCompound = isTypeCompound; } /** @@ -170,7 +190,7 @@ * @param repeatingAnnotations a List of repeating annotations * @return a new Attribute.Compound that is the container for the repeatingAnnotations */ - public Attribute.Compound processRepeatedAnnotations(List<Attribute.Compound> repeatingAnnotations, Symbol sym) { + public T processRepeatedAnnotations(List<T> repeatingAnnotations, Symbol sym) { return Annotate.this.processRepeatedAnnotations(repeatingAnnotations, this, sym); } @@ -246,7 +266,12 @@ ((MethodSymbol)method, value)); t.type = result; } - return new Attribute.Compound(a.type, buf.toList()); + // TODO: this should be a TypeCompound if "a" is a JCTypeAnnotation. + // However, how do we find the correct position? + Attribute.Compound ac = new Attribute.Compound(a.type, buf.toList()); + // TODO: is this something we want? Who would use it? + // a.attribute = ac; + return ac; } Attribute enterAttributeValue(Type expected, @@ -329,6 +354,15 @@ return new Attribute.Error(attr.attribExpr(tree, env, expected)); } + Attribute.TypeCompound enterTypeAnnotation(JCAnnotation a, + Type expected, + Env<AttrContext> env) { + Attribute.Compound c = enterAnnotation(a, expected, env); + Attribute.TypeCompound tc = new Attribute.TypeCompound(c.type, c.values, new TypeAnnotationPosition()); + a.attribute = tc; + return tc; + } + /* ********************************* * Support for repeating annotations ***********************************/ @@ -337,10 +371,10 @@ * synthesized container annotation or null IFF all repeating * annotation are invalid. This method reports errors/warnings. */ - private Attribute.Compound processRepeatedAnnotations(List<Attribute.Compound> annotations, - AnnotateRepeatedContext ctx, - Symbol on) { - Attribute.Compound firstOccurrence = annotations.head; + private <T extends Attribute.Compound> T processRepeatedAnnotations(List<T> annotations, + AnnotateRepeatedContext<T> ctx, + Symbol on) { + T firstOccurrence = annotations.head; List<Attribute> repeated = List.nil(); Type origAnnoType = null; Type arrayOfOrigAnnoType = null; @@ -350,16 +384,16 @@ Assert.check(!annotations.isEmpty() && !annotations.tail.isEmpty()); // i.e. size() > 1 - for (List<Attribute.Compound> al = annotations; + for (List<T> al = annotations; !al.isEmpty(); al = al.tail) { - Attribute.Compound currentAnno = al.head; + T currentAnno = al.head; origAnnoType = currentAnno.type; if (arrayOfOrigAnnoType == null) { arrayOfOrigAnnoType = types.makeArrayType(origAnnoType); -} + } Type currentContainerType = getContainingType(currentAnno, ctx.pos.get(currentAnno)); if (currentContainerType == null) { @@ -383,25 +417,46 @@ if (!repeated.isEmpty()) { repeated = repeated.reverse(); - JCAnnotation annoTree; TreeMaker m = make.at(ctx.pos.get(firstOccurrence)); Pair<MethodSymbol, Attribute> p = new Pair<MethodSymbol, Attribute>(containerValueSymbol, new Attribute.Array(arrayOfOrigAnnoType, repeated)); - annoTree = m.Annotation(new Attribute.Compound(targetContainerType, - List.of(p))); + 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); - if (!chk.annotationApplicable(annoTree, on)) - log.error(annoTree.pos(), "invalid.containedby.annotation.incompatible.target", targetContainerType, origAnnoType); + // TODO: annotation applicability checks from below? - if (!chk.validateAnnotationDeferErrors(annoTree)) - log.error(annoTree.pos(), "duplicate.annotation.invalid.repeated", origAnnoType); + at.setSynthesized(true); - Attribute.Compound c = enterAnnotation(annoTree, - targetContainerType, - ctx.env); - c.setSynthesized(true); - return c; + @SuppressWarnings("unchecked") + T x = (T) at; + return x; + } else { + Attribute.Compound c = new Attribute.Compound(targetContainerType, List.of(p)); + JCAnnotation annoTree = m.Annotation(c); + + if (!chk.annotationApplicable(annoTree, on)) + log.error(annoTree.pos(), "invalid.repeatable.annotation.incompatible.target", targetContainerType, origAnnoType); + + if (!chk.validateAnnotationDeferErrors(annoTree)) + log.error(annoTree.pos(), "duplicate.annotation.invalid.repeated", origAnnoType); + + c = enterAnnotation(annoTree, targetContainerType, ctx.env); + c.setSynthesized(true); + + @SuppressWarnings("unchecked") + T x = (T) c; + return x; + } } else { return null; // errors should have been reported elsewhere } @@ -414,11 +469,11 @@ Type origAnnoType = currentAnno.type; TypeSymbol origAnnoDecl = origAnnoType.tsym; - // Fetch the ContainedBy annotation from the current + // Fetch the Repeatable annotation from the current // annotation's declaration, or null if it has none - Attribute.Compound ca = origAnnoDecl.attribute(syms.containedByType.tsym); - if (ca == null) { // has no ContainedBy annotation - log.error(pos, "duplicate.annotation.missing.container", origAnnoType, syms.containedByType); + Attribute.Compound ca = origAnnoDecl.attribute(syms.repeatableType.tsym); + if (ca == null) { // has no Repeatable annotation + log.error(pos, "duplicate.annotation.missing.container", origAnnoType, syms.repeatableType); return null; } @@ -440,23 +495,23 @@ DiagnosticPosition pos, TypeSymbol annoDecl) { - // The next three checks check that the ContainedBy annotation + // The next three checks check that the Repeatable annotation // on the declaration of the annotation type that is repeating is // valid. - // ContainedBy must have at least one element + // Repeatable must have at least one element if (ca.values.isEmpty()) { - log.error(pos, "invalid.containedby.annotation", annoDecl); + log.error(pos, "invalid.repeatable.annotation", annoDecl); return null; } Pair<MethodSymbol,Attribute> p = ca.values.head; Name name = p.fst.name; if (name != names.value) { // should contain only one element, named "value" - log.error(pos, "invalid.containedby.annotation", annoDecl); + log.error(pos, "invalid.repeatable.annotation", annoDecl); return null; } if (!(p.snd instanceof Attribute.Class)) { // check that the value of "value" is an Attribute.Class - log.error(pos, "invalid.containedby.annotation", annoDecl); + log.error(pos, "invalid.repeatable.annotation", annoDecl); return null; } @@ -491,13 +546,13 @@ } if (error) { log.error(pos, - "invalid.containedby.annotation.multiple.values", + "invalid.repeatable.annotation.multiple.values", targetContainerType, nr_value_elems); return null; } else if (nr_value_elems == 0) { log.error(pos, - "invalid.containedby.annotation.no.value", + "invalid.repeatable.annotation.no.value", targetContainerType); return null; } @@ -506,7 +561,7 @@ // probably "impossible" to fail this if (containerValueSymbol.kind != Kinds.MTH) { log.error(pos, - "invalid.containedby.annotation.invalid.value", + "invalid.repeatable.annotation.invalid.value", targetContainerType); fatalError = true; } @@ -518,7 +573,7 @@ if (!(types.isArray(valueRetType) && types.isSameType(expectedType, valueRetType))) { log.error(pos, - "invalid.containedby.annotation.value.return", + "invalid.repeatable.annotation.value.return", targetContainerType, valueRetType, expectedType); @@ -528,10 +583,7 @@ fatalError = true; } - // Explicitly no check for/validity of @ContainerFor. That is - // done on declaration of the container, and at reflect time. - - // The rest of the conditions for a valid containing annotation are made + // The conditions for a valid containing annotation are made // in Check.validateRepeatedAnnotaton(); return fatalError ? null : containerValueSymbol;
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -26,9 +26,9 @@ package com.sun.tools.javac.comp; import java.util.*; -import java.util.Set; import javax.lang.model.element.ElementKind; +import javax.lang.model.type.TypeKind; import javax.tools.JavaFileObject; import com.sun.source.tree.IdentifierTree; @@ -45,9 +45,9 @@ import com.sun.tools.javac.comp.Infer.InferenceContext; import com.sun.tools.javac.comp.Infer.InferenceContext.FreeTypeListener; import com.sun.tools.javac.jvm.*; -import com.sun.tools.javac.jvm.Target; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.tree.JCTree.*; +import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.List; @@ -879,6 +879,7 @@ deferredLintHandler.flush(tree.pos()); chk.checkDeprecatedAnnotation(tree.pos(), m); + // Create a new environment with local scope // for attributing the method. Env<AttrContext> localEnv = memberEnter.methodEnv(tree, env); @@ -922,6 +923,21 @@ // Check that result type is well-formed. chk.validate(tree.restype, localEnv); + // Check that receiver type is well-formed. + if (tree.recvparam != null) { + // Use a new environment to check the receiver parameter. + // Otherwise I get "might not have been initialized" errors. + // Is there a better way? + Env<AttrContext> newEnv = memberEnter.methodEnv(tree, env); + attribType(tree.recvparam, newEnv); + chk.validate(tree.recvparam, newEnv); + if (!(tree.recvparam.type == m.owner.type || types.isSameType(tree.recvparam.type, m.owner.type))) { + // The == covers the common non-generic case, but for generic classes we need isSameType; + // note that equals didn't work. + log.error(tree.recvparam.pos(), "incorrect.receiver.type"); + } + } + // annotation method checks if ((owner.flags() & ANNOTATION) != 0) { // annotation method cannot have throws clause @@ -953,8 +969,7 @@ // Empty bodies are only allowed for // abstract, native, or interface methods, or for methods // in a retrofit signature class. - if (isDefaultMethod || ((owner.flags() & INTERFACE) == 0 && - (tree.mods.flags & (ABSTRACT | NATIVE)) == 0) && + if (isDefaultMethod || (tree.sym.flags() & (ABSTRACT | NATIVE)) == 0 && !relax) log.error(tree.pos(), "missing.meth.body.or.decl.abstract"); if (tree.defaultValue != null) { @@ -996,9 +1011,14 @@ } } + // Attribute all type annotations in the body + memberEnter.typeAnnotate(tree.body, localEnv, m); + annotate.flush(); + // Attribute method body. attribStat(tree.body, localEnv); } + localEnv.info.scope.leave(); result = tree.type = m.type; chk.validateAnnotations(tree.mods.annotations, m); @@ -1019,6 +1039,12 @@ memberEnter.memberEnter(tree, env); annotate.flush(); } + } else { + if (tree.init != null) { + // Field initializer expression need to be entered. + memberEnter.typeAnnotate(tree.init, env, tree.sym); + annotate.flush(); + } } VarSymbol v = tree.sym; @@ -1076,6 +1102,11 @@ new MethodSymbol(tree.flags | BLOCK, names.empty, null, env.info.scope.owner); if ((tree.flags & STATIC) != 0) localEnv.info.staticLevel++; + + // Attribute all type annotations in the block + memberEnter.typeAnnotate(tree, localEnv, localEnv.info.scope.owner); + annotate.flush(); + attribStats(tree.stats, localEnv); } else { // Create a new local environment with a local scope. @@ -1376,18 +1407,19 @@ public void visitConditional(JCConditional tree) { Type condtype = attribExpr(tree.cond, env, syms.booleanType); - boolean standaloneConditional = !allowPoly || + tree.polyKind = (!allowPoly || pt().hasTag(NONE) && pt() != Type.recoveryType || - isBooleanOrNumeric(env, tree); - - if (!standaloneConditional && resultInfo.pt.hasTag(VOID)) { + isBooleanOrNumeric(env, tree)) ? + PolyKind.STANDALONE : PolyKind.POLY; + + if (tree.polyKind == PolyKind.POLY && resultInfo.pt.hasTag(VOID)) { //cannot get here (i.e. it means we are returning from void method - which is already an error) resultInfo.checkContext.report(tree, diags.fragment("conditional.target.cant.be.void")); result = tree.type = types.createErrorType(resultInfo.pt); return; } - ResultInfo condInfo = standaloneConditional ? + ResultInfo condInfo = tree.polyKind == PolyKind.STANDALONE ? unknownExprInfo : resultInfo.dup(new Check.NestedCheckContext(resultInfo.checkContext) { //this will use enclosing check context to check compatibility of @@ -1402,7 +1434,7 @@ Type truetype = attribTree(tree.truepart, env, condInfo); Type falsetype = attribTree(tree.falsepart, env, condInfo); - Type owntype = standaloneConditional ? condType(tree, truetype, falsetype) : pt(); + Type owntype = (tree.polyKind == PolyKind.STANDALONE) ? condType(tree, truetype, falsetype) : pt(); if (condtype.constValue() != null && truetype.constValue() != null && falsetype.constValue() != null && @@ -1424,12 +1456,30 @@ JCConditional condTree = (JCConditional)tree; return isBooleanOrNumeric(env, condTree.truepart) && isBooleanOrNumeric(env, condTree.falsepart); + case APPLY: + JCMethodInvocation speculativeMethodTree = + (JCMethodInvocation)deferredAttr.attribSpeculative(tree, env, unknownExprInfo); + Type owntype = TreeInfo.symbol(speculativeMethodTree.meth).type.getReturnType(); + return types.unboxedTypeOrType(owntype).isPrimitive(); + case NEWCLASS: + JCExpression className = + removeClassParams.translate(((JCNewClass)tree).clazz); + JCExpression speculativeNewClassTree = + (JCExpression)deferredAttr.attribSpeculative(className, env, unknownTypeInfo); + return types.unboxedTypeOrType(speculativeNewClassTree.type).isPrimitive(); default: Type speculativeType = deferredAttr.attribSpeculative(tree, env, unknownExprInfo).type; speculativeType = types.unboxedTypeOrType(speculativeType); return speculativeType.isPrimitive(); } } + //where + TreeTranslator removeClassParams = new TreeTranslator() { + @Override + public void visitTypeApply(JCTypeApply tree) { + result = translate(tree.clazz); + } + }; /** Compute the type of a conditional expression, after * checking that it exists. See JLS 15.25. Does not take into @@ -1828,10 +1878,24 @@ // If enclosing class is given, attribute it, and // complete class name to be fully qualified JCExpression clazz = tree.clazz; // Class field following new - JCExpression clazzid = // Identifier in class field - (clazz.hasTag(TYPEAPPLY)) - ? ((JCTypeApply) clazz).clazz - : clazz; + JCExpression clazzid; // Identifier in class field + JCAnnotatedType annoclazzid; // Annotated type enclosing clazzid + annoclazzid = null; + + if (clazz.hasTag(TYPEAPPLY)) { + clazzid = ((JCTypeApply) clazz).clazz; + if (clazzid.hasTag(ANNOTATED_TYPE)) { + annoclazzid = (JCAnnotatedType) clazzid; + clazzid = annoclazzid.underlyingType; + } + } else { + if (clazz.hasTag(ANNOTATED_TYPE)) { + annoclazzid = (JCAnnotatedType) clazz; + clazzid = annoclazzid.underlyingType; + } else { + clazzid = clazz; + } + } JCExpression clazzid1 = clazzid; // The same in fully qualified form @@ -1846,14 +1910,30 @@ // yields a clazz T.C. Type encltype = chk.checkRefType(tree.encl.pos(), attribExpr(tree.encl, env)); + // TODO 308: in <expr>.new C, do we also want to add the type annotations + // from expr to the combined type, or not? Yes, do this. clazzid1 = make.at(clazz.pos).Select(make.Type(encltype), ((JCIdent) clazzid).name); - if (clazz.hasTag(TYPEAPPLY)) - clazz = make.at(tree.pos). + + if (clazz.hasTag(ANNOTATED_TYPE)) { + JCAnnotatedType annoType = (JCAnnotatedType) clazz; + List<JCAnnotation> annos = annoType.annotations; + + if (annoType.underlyingType.hasTag(TYPEAPPLY)) { + clazzid1 = make.at(tree.pos). + TypeApply(clazzid1, + ((JCTypeApply) clazz).arguments); + } + + clazzid1 = make.at(tree.pos). + AnnotatedType(annos, clazzid1); + } else if (clazz.hasTag(TYPEAPPLY)) { + clazzid1 = make.at(tree.pos). TypeApply(clazzid1, ((JCTypeApply) clazz).arguments); - else - clazz = clazzid1; + } + + clazz = clazzid1; } // Attribute clazz expression and store @@ -1870,6 +1950,9 @@ tree.clazz.type = clazztype; TreeInfo.setSymbol(clazzid, TreeInfo.symbol(clazzid1)); clazzid.type = ((JCIdent) clazzid).sym.type; + if (annoclazzid != null) { + annoclazzid.type = clazzid.type; + } if (!clazztype.isErroneous()) { if (cdef != null && clazztype.tsym.isInterface()) { log.error(tree.encl.pos(), "anon.class.impl.intf.no.qual.for.new"); @@ -2173,17 +2256,18 @@ boolean needsRecovery = resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK; try { + Type target = pt(); List<Type> explicitParamTypes = null; - if (TreeInfo.isExplicitLambda(that)) { + if (that.paramKind == JCLambda.ParameterKind.EXPLICIT) { //attribute lambda parameters attribStats(that.params, localEnv); explicitParamTypes = TreeInfo.types(that.params); + target = infer.instantiateFunctionalInterface(that, target, explicitParamTypes, resultInfo.checkContext); } - Type target; Type lambdaType; if (pt() != Type.recoveryType) { - target = infer.instantiateFunctionalInterface(that, checkIntersectionTarget(that, resultInfo), explicitParamTypes, resultInfo.checkContext); + target = checkIntersectionTarget(that, target, resultInfo.checkContext); lambdaType = types.findDescriptorType(target); chk.checkFunctionalInterface(that, target); } else { @@ -2191,6 +2275,8 @@ lambdaType = fallbackDescriptorType(that); } + setFunctionalInfo(that, pt(), lambdaType, resultInfo.checkContext.inferenceContext()); + if (lambdaType.hasTag(FORALL)) { //lambda expression target desc cannot be a generic method resultInfo.checkContext.report(that, diags.fragment("invalid.generic.lambda.target", @@ -2199,7 +2285,7 @@ return; } - if (!TreeInfo.isExplicitLambda(that)) { + if (that.paramKind == JCLambda.ParameterKind.IMPLICIT) { //add param type info in the AST List<Type> actuals = lambdaType.getParameterTypes(); List<JCVariableDecl> params = that.params; @@ -2282,8 +2368,7 @@ } } - private Type checkIntersectionTarget(DiagnosticPosition pos, ResultInfo resultInfo) { - Type pt = resultInfo.pt; + private Type checkIntersectionTarget(DiagnosticPosition pos, Type pt, CheckContext checkContext) { if (pt != Type.recoveryType && pt.isCompound()) { IntersectionClassType ict = (IntersectionClassType)pt; List<Type> bounds = ict.allInterfaces ? @@ -2292,7 +2377,7 @@ types.findDescriptorType(bounds.head); //propagate exception outwards! for (Type bound : bounds.tail) { if (!types.isMarkerInterface(bound)) { - resultInfo.checkContext.report(pos, diags.fragment("secondary.bound.must.be.marker.intf", bound)); + checkContext.report(pos, diags.fragment("secondary.bound.must.be.marker.intf", bound)); } } //for now (translation doesn't support intersection types) @@ -2355,9 +2440,9 @@ @Override public boolean compatible(Type found, Type req, Warner warn) { //return type must be compatible in both current context and assignment context - return types.isAssignable(found, inferenceContext().asFree(req, types), warn) && - super.compatible(found, req, warn); + return chk.basicHandler.compatible(found, inferenceContext().asFree(req, types), warn); } + @Override public void report(DiagnosticPosition pos, JCDiagnostic details) { enclosingContext.report(pos, diags.fragment("incompatible.ret.type.in.lambda", details)); @@ -2473,7 +2558,7 @@ Type target; Type desc; if (pt() != Type.recoveryType) { - target = infer.instantiateFunctionalInterface(that, checkIntersectionTarget(that, resultInfo), null, resultInfo.checkContext); + target = checkIntersectionTarget(that, pt(), resultInfo.checkContext); desc = types.findDescriptorType(target); chk.checkFunctionalInterface(that, target); } else { @@ -2481,12 +2566,11 @@ desc = fallbackDescriptorType(that); } + setFunctionalInfo(that, pt(), desc, resultInfo.checkContext.inferenceContext()); List<Type> argtypes = desc.getParameterTypes(); - boolean allowBoxing = - resultInfo.checkContext.deferredAttrContext().phase.isBoxingRequired(); Pair<Symbol, Resolve.ReferenceLookupHelper> refResult = rs.resolveMemberReference(that.pos(), localEnv, that, - that.expr.type, that.name, argtypes, typeargtypes, allowBoxing); + that.expr.type, that.name, argtypes, typeargtypes, true); Symbol refSym = refResult.fst; Resolve.ReferenceLookupHelper lookupHelper = refResult.snd; @@ -2635,6 +2719,34 @@ } } + /** + * Set functional type info on the underlying AST. Note: as the target descriptor + * might contain inference variables, we might need to register an hook in the + * current inference context. + */ + private void setFunctionalInfo(final JCFunctionalExpression fExpr, final Type pt, final Type descriptorType, InferenceContext inferenceContext) { + if (inferenceContext.free(descriptorType)) { + inferenceContext.addFreeTypeListener(List.of(pt, descriptorType), new FreeTypeListener() { + public void typesInferred(InferenceContext inferenceContext) { + setFunctionalInfo(fExpr, pt, inferenceContext.asInstType(descriptorType, types), inferenceContext); + } + }); + } else { + ListBuffer<TypeSymbol> targets = ListBuffer.lb(); + if (pt.hasTag(CLASS)) { + if (pt.isCompound()) { + for (Type t : ((IntersectionClassType)pt()).interfaces_field) { + targets.append(t.tsym); + } + } else { + targets.append(pt.tsym); + } + } + fExpr.targets = targets.toList(); + fExpr.descriptorType = descriptorType; + } + } + public void visitParens(JCParens tree) { Type owntype = attribTree(tree.expr, env, resultInfo); result = check(tree, owntype, pkind(), resultInfo); @@ -3207,8 +3319,18 @@ // Tree<Point>.Visitor. else if (ownOuter.hasTag(CLASS) && site != ownOuter) { Type normOuter = site; - if (normOuter.hasTag(CLASS)) + if (normOuter.hasTag(CLASS)) { normOuter = types.asEnclosingSuper(site, ownOuter.tsym); + if (site.getKind() == TypeKind.ANNOTATED) { + // Propagate any type annotations. + // TODO: should asEnclosingSuper do this? + // Note that the type annotations in site will be updated + // by annotateType. Therefore, modify site instead + // of creating a new AnnotatedType. + ((AnnotatedType)site).underlyingType = normOuter; + normOuter = site; + } + } if (normOuter == null) // perhaps from an import normOuter = types.erasure(ownOuter); if (normOuter != ownOuter) @@ -3432,6 +3554,15 @@ env.info.defaultSuperCallSite = null; } + if (sym.isStatic() && site.isInterface()) { + Assert.check(env.tree.hasTag(APPLY)); + JCMethodInvocation app = (JCMethodInvocation)env.tree; + if (app.meth.hasTag(SELECT) && + !TreeInfo.isStaticSelector(((JCFieldAccess)app.meth).selected, names)) { + log.error(env.tree.pos(), "illegal.static.intf.meth.call", site); + } + } + // Compute the identifier's instantiated type. // For methods, we need to compute the instance type by // Resolve.instantiate from the symbol's type as well as @@ -3587,8 +3718,15 @@ tree.type = result = checkIntersection(tree, tree.bounds); } - public void visitTypeParameter(JCTypeParameter tree) { - TypeVar typeVar = (TypeVar)tree.type; + public void visitTypeParameter(JCTypeParameter tree) { + TypeVar typeVar = (TypeVar) tree.type; + + if (tree.annotations != null && tree.annotations.nonEmpty()) { + AnnotatedType antype = new AnnotatedType(typeVar); + annotateType(antype, tree.annotations); + tree.type = antype; + } + if (!typeVar.bound.isErroneous()) { //fixup type-parameter bound computed in 'attribTypeVariables' typeVar.bound = checkIntersection(tree, tree.bounds); @@ -3684,6 +3822,44 @@ result = tree.type = syms.errType; } + public void visitAnnotatedType(JCAnnotatedType tree) { + Type underlyingType = attribType(tree.getUnderlyingType(), env); + this.attribAnnotationTypes(tree.annotations, env); + AnnotatedType antype = new AnnotatedType(underlyingType); + annotateType(antype, tree.annotations); + result = tree.type = antype; + } + + /** + * Apply the annotations to the particular type. + */ + public void annotateType(final AnnotatedType type, final List<JCAnnotation> annotations) { + if (annotations.isEmpty()) + return; + annotate.typeAnnotation(new Annotate.Annotator() { + @Override + public String toString() { + return "annotate " + annotations + " onto " + type; + } + @Override + public void enterAnnotation() { + List<Attribute.TypeCompound> compounds = fromAnnotations(annotations); + type.typeAnnotations = compounds; + } + }); + } + + private static List<Attribute.TypeCompound> fromAnnotations(List<JCAnnotation> annotations) { + if (annotations.isEmpty()) + return List.nil(); + + ListBuffer<Attribute.TypeCompound> buf = ListBuffer.lb(); + for (JCAnnotation anno : annotations) { + buf.append((Attribute.TypeCompound) anno.attribute); + } + return buf.toList(); + } + public void visitErroneous(JCErroneous tree) { if (tree.errs != null) for (JCTree err : tree.errs) @@ -3844,24 +4020,14 @@ log.error(tree.typarams.head.pos(), "intf.annotation.cant.have.type.params"); - // If this annotation has a @ContainedBy, validate - Attribute.Compound containedBy = c.attribute(syms.containedByType.tsym); - if (containedBy != null) { - // get diagnositc position for error reporting - DiagnosticPosition cbPos = getDiagnosticPosition(tree, containedBy.type); + // If this annotation has a @Repeatable, validate + Attribute.Compound repeatable = c.attribute(syms.repeatableType.tsym); + if (repeatable != null) { + // get diagnostic position for error reporting + DiagnosticPosition cbPos = getDiagnosticPosition(tree, repeatable.type); Assert.checkNonNull(cbPos); - chk.validateContainedBy(c, containedBy, cbPos); - } - - // If this annotation has a @ContainerFor, validate - Attribute.Compound containerFor = c.attribute(syms.containerForType.tsym); - if (containerFor != null) { - // get diagnositc position for error reporting - DiagnosticPosition cfPos = getDiagnosticPosition(tree, containerFor.type); - Assert.checkNonNull(cfPos); - - chk.validateContainerFor(c, containerFor, cfPos); + chk.validateRepeatable(c, repeatable, cbPos); } } else { // Check that all extended classes and interfaces @@ -3925,6 +4091,12 @@ (c.flags() & ABSTRACT) == 0) { checkSerialVersionUID(tree, c); } + + // Correctly organize the postions of the type annotations + TypeAnnotations.organizeTypeAnnotationsBodies(this.syms, this.names, this.log, tree); + + // Check type annotations applicability rules + validateTypeAnnotations(tree); } // where /** get a diagnostic position for an attribute of Type t, or null if attribute missing */ @@ -3982,6 +4154,94 @@ return types.capture(type); } + private void validateTypeAnnotations(JCTree tree) { + tree.accept(typeAnnotationsValidator); + } + //where + private final JCTree.Visitor typeAnnotationsValidator = + new TreeScanner() { + public void visitAnnotation(JCAnnotation tree) { + if (tree.hasTag(TYPE_ANNOTATION)) { + // TODO: It seems to WMD as if the annotation in + // parameters, in particular also the recvparam, are never + // of type JCTypeAnnotation and therefore never checked! + // Luckily this check doesn't really do anything that isn't + // also done elsewhere. + chk.validateTypeAnnotation(tree, false); + } + super.visitAnnotation(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) { + // Static methods cannot have receiver type annotations. + // In test case FailOver15.java, the nested method getString has + // a null sym, because an unknown class is instantiated. + // I would say it's safe to skip. + if (tree.sym != null && (tree.sym.flags() & Flags.STATIC) != 0) { + if (tree.recvparam != null) { + // TODO: better error message. Is the pos good? + log.error(tree.recvparam.pos(), "annotation.type.not.applicable"); + } + } + if (tree.restype != null && tree.restype.type != null) { + validateAnnotatedType(tree.restype, tree.restype.type); + } + super.visitMethodDef(tree); + } + public void visitVarDef(final JCVariableDecl tree) { + if (tree.sym != null && tree.sym.type != null) + validateAnnotatedType(tree, tree.sym.type); + super.visitVarDef(tree); + } + 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); + } + // TODO: what else do we need? + // public void visitNewClass(JCNewClass tree) { + // public void visitNewArray(JCNewArray tree) { + + /* 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) { + if (type.getEnclosingType() != null && + type != type.getEnclosingType()) { + validateEnclosingAnnotatedType(errtree, type.getEnclosingType()); + } + for (Type targ : type.getTypeArguments()) { + validateAnnotatedType(errtree, targ); + } + } + private void validateEnclosingAnnotatedType(final JCTree errtree, final Type type) { + validateAnnotatedType(errtree, type); + if (type.tsym != null && + type.tsym.isStatic() && + type.getAnnotations().nonEmpty()) { + // Enclosing static classes cannot have type annotations. + log.error(errtree.pos(), "cant.annotate.static.class"); + } + } + }; + // <editor-fold desc="post-attribution visitor"> /** @@ -4088,11 +4348,28 @@ } @Override + public void visitLambda(JCLambda that) { + super.visitLambda(that); + if (that.descriptorType == null) { + that.descriptorType = syms.unknownType; + } + if (that.targets == null) { + that.targets = List.nil(); + } + } + + @Override public void visitReference(JCMemberReference that) { super.visitReference(that); if (that.sym == null) { that.sym = new MethodSymbol(0, names.empty, syms.unknownType, syms.noSymbol); } + if (that.descriptorType == null) { + that.descriptorType = syms.unknownType; + } + if (that.targets == null) { + that.targets = List.nil(); + } } } // </editor-fold>
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -26,7 +26,7 @@ package com.sun.tools.javac.comp; import java.util.*; -import java.util.Set; + import javax.tools.JavaFileManager; import com.sun.tools.javac.code.*; @@ -36,7 +36,6 @@ import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.List; -import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.code.Lint; import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Type.*; @@ -44,6 +43,8 @@ import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext; import com.sun.tools.javac.comp.Infer.InferenceContext; import com.sun.tools.javac.comp.Infer.InferenceContext.FreeTypeListener; +import com.sun.tools.javac.tree.JCTree.*; +import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*; import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Flags.ANNOTATION; @@ -100,6 +101,9 @@ context.put(checkKey, this); names = Names.instance(context); + dfltTargetMeta = new Name[] { names.PACKAGE, names.TYPE, + names.FIELD, names.METHOD, names.CONSTRUCTOR, + names.ANNOTATION_TYPE, names.LOCAL_VARIABLE, names.PARAMETER}; log = Log.instance(context); rs = Resolve.instance(context); syms = Symtab.instance(context); @@ -571,34 +575,27 @@ if (!tree.type.isErroneous() && (env.info.lint == null || env.info.lint.isEnabled(Lint.LintCategory.CAST)) && types.isSameType(tree.expr.type, tree.clazz.type) + && !(ignoreAnnotatedCasts && TreeInfo.containsTypeAnnotation(tree.clazz)) && !is292targetTypeCast(tree)) { log.warning(Lint.LintCategory.CAST, tree.pos(), "redundant.cast", tree.expr.type); } } //where - private boolean is292targetTypeCast(JCTypeCast tree) { - boolean is292targetTypeCast = false; - JCExpression expr = TreeInfo.skipParens(tree.expr); - if (expr.hasTag(APPLY)) { - JCMethodInvocation apply = (JCMethodInvocation)expr; - Symbol sym = TreeInfo.symbol(apply.meth); - is292targetTypeCast = sym != null && - sym.kind == MTH && - (sym.flags() & HYPOTHETICAL) != 0; - } - return is292targetTypeCast; + private boolean is292targetTypeCast(JCTypeCast tree) { + boolean is292targetTypeCast = false; + JCExpression expr = TreeInfo.skipParens(tree.expr); + if (expr.hasTag(APPLY)) { + JCMethodInvocation apply = (JCMethodInvocation)expr; + Symbol sym = TreeInfo.symbol(apply.meth); + is292targetTypeCast = sym != null && + sym.kind == MTH && + (sym.flags() & HYPOTHETICAL) != 0; } + return is292targetTypeCast; + } - - -//where - /** Is type a type variable, or a (possibly multi-dimensional) array of - * type variables? - */ - boolean isTypeVar(Type t) { - return t.hasTag(TYPEVAR) || t.hasTag(ARRAY) && isTypeVar(types.elemtype(t)); - } + private static final boolean ignoreAnnotatedCasts = true; /** Check that a type is within some bounds. * @@ -634,25 +631,40 @@ } } + Type checkClassOrArrayType(DiagnosticPosition pos, Type t) { + if (!t.hasTag(CLASS) && !t.hasTag(ARRAY) && !t.hasTag(ERROR)) { + return typeTagError(pos, + diags.fragment("type.req.class.array"), + asTypeParam(t)); + } else { + return t; + } + } + /** Check that type is a class or interface type. * @param pos Position to be used for error reporting. * @param t The type to be checked. */ Type checkClassType(DiagnosticPosition pos, Type t) { - if (!t.hasTag(CLASS) && !t.hasTag(ERROR)) + if (!t.hasTag(CLASS) && !t.hasTag(ERROR)) { return typeTagError(pos, diags.fragment("type.req.class"), - (t.hasTag(TYPEVAR)) - ? diags.fragment("type.parameter", t) - : t); - else + asTypeParam(t)); + } else { return t; + } } + //where + private Object asTypeParam(Type t) { + return (t.hasTag(TYPEVAR)) + ? diags.fragment("type.parameter", t) + : t; + } /** Check that type is a valid qualifier for a constructor reference expression */ Type checkConstructorRefType(DiagnosticPosition pos, Type t) { - t = checkClassType(pos, t); + t = checkClassOrArrayType(pos, t); if (t.hasTag(CLASS)) { if ((t.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) { log.error(pos, "abstract.cant.be.instantiated"); @@ -690,11 +702,8 @@ * @param t The type to be checked. */ Type checkReifiableReferenceType(DiagnosticPosition pos, Type t) { - if (!t.hasTag(CLASS) && !t.hasTag(ARRAY) && !t.hasTag(ERROR)) { - return typeTagError(pos, - diags.fragment("type.req.class.array"), - t); - } else if (!types.isReifiable(t)) { + t = checkClassOrArrayType(pos, t); + if (!t.isErroneous() && !types.isReifiable(t)) { log.error(pos, "illegal.generic.type.for.instof"); return types.createErrorType(t); } else { @@ -840,7 +849,7 @@ // System.out.println("actuals: " + argtypes); List<Type> formals = owntype.getParameterTypes(); Type last = useVarargs ? formals.last() : null; - if (sym.name==names.init && + if (sym.name == names.init && sym.owner == syms.enumSym) formals = formals.tail.tail; List<JCExpression> args = argtrees; @@ -888,7 +897,6 @@ syms.methodClass); } if (useVarargs) { - JCTree tree = env.tree; Type argtype = owntype.getParameterTypes().last(); if (!types.isReifiable(argtype) && (!allowSimplifiedVarargs || @@ -899,22 +907,13 @@ argtype); } if (!((MethodSymbol)sym.baseSymbol()).isSignaturePolymorphic(types)) { - Type elemtype = types.elemtype(argtype); - switch (tree.getTag()) { - case APPLY: - ((JCMethodInvocation) tree).varargsElement = elemtype; - break; - case NEWCLASS: - ((JCNewClass) tree).varargsElement = elemtype; - break; - case REFERENCE: - ((JCMemberReference) tree).varargsElement = elemtype; - break; - default: - throw new AssertionError(""+tree); - } + TreeInfo.setVarargsElement(env.tree, types.elemtype(argtype)); } } + PolyKind pkind = (sym.type.hasTag(FORALL) && + sym.type.getReturnType().containsAny(((ForAll)sym.type).tvars)) ? + PolyKind.POLY : PolyKind.STANDALONE; + TreeInfo.setPolyKind(env.tree, pkind); return owntype; } //where @@ -1055,9 +1054,12 @@ } else mask = ConstructorFlags; } else if ((sym.owner.flags_field & INTERFACE) != 0) { - if ((flags & DEFAULT) != 0) { - mask = InterfaceDefaultMethodMask; - implicit = PUBLIC | ABSTRACT; + if ((flags & (DEFAULT | STATIC)) != 0) { + mask = InterfaceMethodMask; + implicit = PUBLIC; + if ((flags & DEFAULT) != 0) { + implicit |= ABSTRACT; + } } else { mask = implicit = InterfaceMethodFlags; } @@ -1127,6 +1129,10 @@ PRIVATE | STATIC | DEFAULT)) && checkDisjoint(pos, flags, + STATIC, + DEFAULT) + && + checkDisjoint(pos, flags, ABSTRACT | INTERFACE, FINAL | NATIVE | SYNCHRONIZED) && @@ -1316,6 +1322,11 @@ } } + @Override + public void visitAnnotatedType(JCAnnotatedType tree) { + tree.underlyingType.accept(this); + } + /** Default visitor method: do nothing. */ @Override @@ -2236,7 +2247,7 @@ void checkImplementations(JCClassDecl tree) { checkImplementations(tree, tree.sym, tree.sym); } -//where + //where /** Check that all methods which implement some * method in `ic' conform to the method they implement. */ @@ -2577,6 +2588,13 @@ validateAnnotation(a, s); } + /** Check the type annotations. + */ + public void validateTypeAnnotations(List<JCAnnotation> annotations, boolean isTypeParameter) { + for (JCAnnotation a : annotations) + validateTypeAnnotation(a, isTypeParameter); + } + /** Check an annotation of a symbol. */ private void validateAnnotation(JCAnnotation a, Symbol s) { @@ -2589,33 +2607,53 @@ if (!isOverrider(s)) log.error(a.pos(), "method.does.not.override.superclass"); } + + if (a.annotationType.type.tsym == syms.functionalInterfaceType.tsym) { + if (s.kind != TYP) { + log.error(a.pos(), "bad.functional.intf.anno"); + } else { + try { + types.findDescriptorSymbol((TypeSymbol)s); + } catch (Types.FunctionDescriptorLookupError ex) { + log.error(a.pos(), "bad.functional.intf.anno.1", ex.getDiagnostic()); + } + } + } + } + + public void validateTypeAnnotation(JCAnnotation a, boolean isTypeParameter) { + Assert.checkNonNull(a.type, "annotation tree hasn't been attributed yet: " + a); + validateAnnotationTree(a); + + if (!isTypeAnnotation(a, isTypeParameter)) + log.error(a.pos(), "annotation.type.not.applicable"); } /** - * Validate the proposed container 'containedBy' on the + * Validate the proposed container 'repeatable' on the * annotation type symbol 's'. Report errors at position * 'pos'. * - * @param s The (annotation)type declaration annotated with a @ContainedBy - * @param containedBy the @ContainedBy on 's' + * @param s The (annotation)type declaration annotated with a @Repeatable + * @param repeatable the @Repeatable on 's' * @param pos where to report errors */ - public void validateContainedBy(TypeSymbol s, Attribute.Compound containedBy, DiagnosticPosition pos) { - Assert.check(types.isSameType(containedBy.type, syms.containedByType)); + public void validateRepeatable(TypeSymbol s, Attribute.Compound repeatable, DiagnosticPosition pos) { + Assert.check(types.isSameType(repeatable.type, syms.repeatableType)); Type t = null; - List<Pair<MethodSymbol,Attribute>> l = containedBy.values; + List<Pair<MethodSymbol,Attribute>> l = repeatable.values; if (!l.isEmpty()) { Assert.check(l.head.fst.name == names.value); t = ((Attribute.Class)l.head.snd).getValue(); } if (t == null) { - log.error(pos, "invalid.container.wrong.containedby", s, containedBy); + // errors should already have been reported during Annotate return; } - validateHasContainerFor(t.tsym, s, pos); + validateValue(t.tsym, s, pos); validateRetention(t.tsym, s, pos); validateDocumented(t.tsym, s, pos); validateInherited(t.tsym, s, pos); @@ -2623,79 +2661,18 @@ validateDefault(t.tsym, s, pos); } - /** - * Validate the proposed container 'containerFor' on the - * annotation type symbol 's'. Report errors at position - * 'pos'. - * - * @param s The (annotation)type declaration annotated with a @ContainerFor - * @param containerFor the @ContainedFor on 's' - * @param pos where to report errors - */ - public void validateContainerFor(TypeSymbol s, Attribute.Compound containerFor, DiagnosticPosition pos) { - Assert.check(types.isSameType(containerFor.type, syms.containerForType)); - - Type t = null; - List<Pair<MethodSymbol,Attribute>> l = containerFor.values; - if (!l.isEmpty()) { - Assert.check(l.head.fst.name == names.value); - t = ((Attribute.Class)l.head.snd).getValue(); + private void validateValue(TypeSymbol container, TypeSymbol contained, DiagnosticPosition pos) { + Scope.Entry e = container.members().lookup(names.value); + if (e.scope != null && e.sym.kind == MTH) { + MethodSymbol m = (MethodSymbol) e.sym; + Type ret = m.getReturnType(); + if (!(ret.hasTag(ARRAY) && types.isSameType(((ArrayType)ret).elemtype, contained.type))) { + log.error(pos, "invalid.repeatable.annotation.value.return", + container, ret, types.makeArrayType(contained.type)); + } + } else { + log.error(pos, "invalid.repeatable.annotation.no.value", container); } - - if (t == null) { - log.error(pos, "invalid.container.wrong.containerfor", s, containerFor); - return; - } - - validateHasContainedBy(t.tsym, s, pos); - } - - private void validateHasContainedBy(TypeSymbol container, TypeSymbol contained, DiagnosticPosition pos) { - Attribute.Compound containedBy = container.attribute(syms.containedByType.tsym); - - if (containedBy == null) { - log.error(pos, "invalid.container.no.containedby", container, syms.containedByType.tsym); - return; - } - - Type t = null; - List<Pair<MethodSymbol,Attribute>> l = containedBy.values; - if (!l.isEmpty()) { - Assert.check(l.head.fst.name == names.value); - t = ((Attribute.Class)l.head.snd).getValue(); - } - - if (t == null) { - log.error(pos, "invalid.container.wrong.containedby", container, contained); - return; - } - - if (!types.isSameType(t, contained.type)) - log.error(pos, "invalid.container.wrong.containedby", t.tsym, contained); - } - - private void validateHasContainerFor(TypeSymbol container, TypeSymbol contained, DiagnosticPosition pos) { - Attribute.Compound containerFor = container.attribute(syms.containerForType.tsym); - - if (containerFor == null) { - log.error(pos, "invalid.container.no.containerfor", container, syms.containerForType.tsym); - return; - } - - Type t = null; - List<Pair<MethodSymbol,Attribute>> l = containerFor.values; - if (!l.isEmpty()) { - Assert.check(l.head.fst.name == names.value); - t = ((Attribute.Class)l.head.snd).getValue(); - } - - if (t == null) { - log.error(pos, "invalid.container.wrong.containerfor", container, contained); - return; - } - - if (!types.isSameType(t, contained.type)) - log.error(pos, "invalid.container.wrong.containerfor", t.tsym, contained); } private void validateRetention(Symbol container, Symbol contained, DiagnosticPosition pos) { @@ -2715,7 +2692,7 @@ } } if (error ) { - log.error(pos, "invalid.containedby.annotation.retention", + log.error(pos, "invalid.repeatable.annotation.retention", container, containerRetention, contained, containedRetention); } @@ -2724,7 +2701,7 @@ private void validateDocumented(Symbol container, Symbol contained, DiagnosticPosition pos) { if (contained.attribute(syms.documentedType.tsym) != null) { if (container.attribute(syms.documentedType.tsym) == null) { - log.error(pos, "invalid.containedby.annotation.not.documented", container, contained); + log.error(pos, "invalid.repeatable.annotation.not.documented", container, contained); } } } @@ -2732,7 +2709,7 @@ private void validateInherited(Symbol container, Symbol contained, DiagnosticPosition pos) { if (contained.attribute(syms.inheritedType.tsym) != null) { if (container.attribute(syms.inheritedType.tsym) == null) { - log.error(pos, "invalid.containedby.annotation.not.inherited", container, contained); + log.error(pos, "invalid.repeatable.annotation.not.inherited", container, contained); } } } @@ -2752,7 +2729,7 @@ // contained has target, but container has not, error Attribute.Array containerTarget = getAttributeTargetAttribute(container); if (containerTarget == null) { - log.error(pos, "invalid.containedby.annotation.incompatible.target", container, contained); + log.error(pos, "invalid.repeatable.annotation.incompatible.target", container, contained); return; } @@ -2775,7 +2752,7 @@ } if (!isTargetSubset(containedTargets, containerTargets)) { - log.error(pos, "invalid.containedby.annotation.incompatible.target", container, contained); + log.error(pos, "invalid.repeatable.annotation.incompatible.target", container, contained); } } @@ -2809,7 +2786,7 @@ elm.kind == Kinds.MTH && ((MethodSymbol)elm).defaultValue == null) { log.error(pos, - "invalid.containedby.annotation.elem.nondefault", + "invalid.repeatable.annotation.elem.nondefault", container, elm); } @@ -2834,45 +2811,90 @@ return false; } + /** Is the annotation applicable to type annotations? */ + protected boolean isTypeAnnotation(JCAnnotation a, boolean isTypeParameter) { + Attribute.Compound atTarget = + a.annotationType.type.tsym.attribute(syms.annotationTargetType.tsym); + if (atTarget == null) { + // An annotation without @Target is not a type annotation. + return false; + } + + Attribute atValue = atTarget.member(names.value); + if (!(atValue instanceof Attribute.Array)) { + return false; // error recovery + } + + Attribute.Array arr = (Attribute.Array) atValue; + for (Attribute app : arr.values) { + if (!(app instanceof Attribute.Enum)) { + return false; // recovery + } + Attribute.Enum e = (Attribute.Enum) app; + + if (e.value.name == names.TYPE_USE) + return true; + else if (isTypeParameter && e.value.name == names.TYPE_PARAMETER) + return true; + } + return false; + } + /** Is the annotation applicable to the symbol? */ boolean annotationApplicable(JCAnnotation a, Symbol s) { Attribute.Array arr = getAttributeTargetAttribute(a.annotationType.type.tsym); + Name[] targets; + if (arr == null) { - return true; + targets = defaultTargetMetaInfo(a, s); + } else { + // TODO: can we optimize this? + targets = new Name[arr.values.length]; + for (int i=0; i<arr.values.length; ++i) { + Attribute app = arr.values[i]; + if (!(app instanceof Attribute.Enum)) { + return true; // recovery + } + Attribute.Enum e = (Attribute.Enum) app; + targets[i] = e.value.name; + } } - for (Attribute app : arr.values) { - if (!(app instanceof Attribute.Enum)) return true; // recovery - Attribute.Enum e = (Attribute.Enum) app; - if (e.value.name == names.TYPE) + for (Name target : targets) { + if (target == names.TYPE) { if (s.kind == TYP) return true; } - else if (e.value.name == names.FIELD) + else if (target == names.FIELD) { if (s.kind == VAR && s.owner.kind != MTH) return true; } - else if (e.value.name == names.METHOD) + else if (target == names.METHOD) { if (s.kind == MTH && !s.isConstructor()) return true; } - else if (e.value.name == names.PARAMETER) + else if (target == names.PARAMETER) { if (s.kind == VAR && s.owner.kind == MTH && (s.flags() & PARAMETER) != 0) return true; } - else if (e.value.name == names.CONSTRUCTOR) + else if (target == names.CONSTRUCTOR) { if (s.kind == MTH && s.isConstructor()) return true; } - else if (e.value.name == names.LOCAL_VARIABLE) + else if (target == names.LOCAL_VARIABLE) { if (s.kind == VAR && s.owner.kind == MTH && (s.flags() & PARAMETER) == 0) return true; } - else if (e.value.name == names.ANNOTATION_TYPE) + else if (target == names.ANNOTATION_TYPE) { if (s.kind == TYP && (s.flags() & ANNOTATION) != 0) return true; } - else if (e.value.name == names.PACKAGE) + else if (target == names.PACKAGE) { if (s.kind == PCK) return true; } - else if (e.value.name == names.TYPE_USE) + else if (target == names.TYPE_USE) { if (s.kind == TYP || s.kind == VAR || (s.kind == MTH && !s.isConstructor() && - !s.type.getReturnType().hasTag(VOID))) + !s.type.getReturnType().hasTag(VOID)) || + (s.kind == MTH && s.isConstructor())) + return true; + } + else if (target == names.TYPE_PARAMETER) + { if (s.kind == TYP && s.type.hasTag(TYPEVAR)) return true; } else @@ -2891,6 +2913,11 @@ return (Attribute.Array) atValue; } + private final Name[] dfltTargetMeta; + private Name[] defaultTargetMetaInfo(JCAnnotation a, Symbol s) { + return dfltTargetMeta; + } + /** Check an annotation value. * * @param a The annotation tree to check
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/ConstFold.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/ConstFold.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -29,8 +29,6 @@ import com.sun.tools.javac.jvm.*; import com.sun.tools.javac.util.*; -import com.sun.tools.javac.code.Type.*; - import static com.sun.tools.javac.code.TypeTag.BOOLEAN; import static com.sun.tools.javac.jvm.ByteCodes.*;
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Sat Jan 26 19:24:46 2013 -0800 @@ -65,6 +65,7 @@ final Attr attr; final Check chk; + final JCDiagnostic.Factory diags; final Enter enter; final Infer infer; final Log log; @@ -83,14 +84,20 @@ context.put(deferredAttrKey, this); attr = Attr.instance(context); chk = Check.instance(context); + diags = JCDiagnostic.Factory.instance(context); enter = Enter.instance(context); infer = Infer.instance(context); log = Log.instance(context); syms = Symtab.instance(context); make = TreeMaker.instance(context); types = Types.instance(context); + Names names = Names.instance(context); + stuckTree = make.Ident(names.empty).setType(Type.noType); } + /** shared tree for stuck expressions */ + final JCTree stuckTree; + /** * This type represents a deferred type. A deferred type starts off with * no information on the underlying expression type. Such info needs to be @@ -356,12 +363,11 @@ //scan a defensive copy of the node list - this is because a deferred //attribution round can add new nodes to the list for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) { - if (!deferredAttrNode.isStuck()) { - deferredAttrNode.process(); + if (!deferredAttrNode.process()) { + stuckVars.addAll(deferredAttrNode.stuckVars); + } else { deferredAttrNodes.remove(deferredAttrNode); progress = true; - } else { - stuckVars.addAll(deferredAttrNode.stuckVars); } } if (!progress) { @@ -404,21 +410,88 @@ } /** - * is this node stuck? + * Process a deferred attribution node. + * Invariant: a stuck node cannot be processed. */ - boolean isStuck() { - return stuckVars.nonEmpty(); + @SuppressWarnings("fallthrough") + boolean process() { + switch (mode) { + case SPECULATIVE: + dt.check(resultInfo, List.<Type>nil(), new StructuralStuckChecker()); + return true; + case CHECK: + if (stuckVars.nonEmpty()) { + return false; + } else { + dt.check(resultInfo, stuckVars, basicCompleter); + return true; + } + default: + throw new AssertionError("Bad mode"); + } } /** - * Process a deferred attribution node. - * Invariant: a stuck node cannot be processed. + * Structural checker for stuck expressions */ - void process() { - if (isStuck()) { - throw new IllegalStateException("Cannot process a stuck deferred node"); + class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter { + + ResultInfo resultInfo; + + public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) { + this.resultInfo = resultInfo; + dt.tree.accept(this); + dt.speculativeCache.put(msym, stuckTree, phase); + return Type.noType; } - dt.check(resultInfo); + + @Override + public void visitLambda(JCLambda tree) { + Check.CheckContext checkContext = resultInfo.checkContext; + Type pt = resultInfo.pt; + if (inferenceContext.inferencevars.contains(pt)) { + //ok + return; + } else { + //must be a functional descriptor + try { + Type desc = types.findDescriptorType(pt); + if (desc.getParameterTypes().length() != tree.params.length()) { + checkContext.report(tree, diags.fragment("incompatible.arg.types.in.lambda")); + } + } catch (Types.FunctionDescriptorLookupError ex) { + checkContext.report(null, ex.getDiagnostic()); + } + } + } + + @Override + public void visitNewClass(JCNewClass tree) { + //do nothing + } + + @Override + public void visitApply(JCMethodInvocation tree) { + //do nothing + } + + @Override + public void visitReference(JCMemberReference tree) { + Check.CheckContext checkContext = resultInfo.checkContext; + Type pt = resultInfo.pt; + if (inferenceContext.inferencevars.contains(pt)) { + //ok + return; + } else { + try { + //TODO: we should speculative determine if there's a match + //based on arity - if yes, method is applicable. + types.findDescriptorType(pt); + } catch (Types.FunctionDescriptorLookupError ex) { + checkContext.report(null, ex.getDiagnostic()); + } + } + } } } } @@ -624,12 +697,12 @@ if (inferenceContext.inferenceVars().contains(pt)) { stuckVars.add(pt); } - if (!types.isFunctionalInterface(pt.tsym)) { + if (!types.isFunctionalInterface(pt)) { return; } Type descType = types.findDescriptorType(pt); List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes()); - if (!TreeInfo.isExplicitLambda(tree) && + if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT && freeArgVars.nonEmpty()) { stuckVars.addAll(freeArgVars); } @@ -643,7 +716,7 @@ stuckVars.add(pt); return; } - if (!types.isFunctionalInterface(pt.tsym)) { + if (!types.isFunctionalInterface(pt)) { return; }
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -131,7 +131,11 @@ predefClassDef = make.ClassDef( make.Modifiers(PUBLIC), - syms.predefClass.name, null, null, null, null); + syms.predefClass.name, + List.<JCTypeParameter>nil(), + null, + List.<JCExpression>nil(), + List.<JCTree>nil()); predefClassDef.sym = syms.predefClass; todo = Todo.instance(context); fileManager = context.get(JavaFileManager.class);
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java Sat Jan 26 19:24:46 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -35,6 +35,7 @@ import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.code.Symbol.*; +import com.sun.tools.javac.comp.Resolve; import com.sun.tools.javac.tree.JCTree.*; import static com.sun.tools.javac.code.Flags.*; @@ -2175,6 +2176,11 @@ unrefdResources.remove(sym); } + public void visitAnnotatedType(JCAnnotatedType tree) { + // annotations don't get scanned + tree.underlyingType.accept(this); + } + public void visitTopLevel(JCCompilationUnit tree) { // Do nothing for TopLevel since each class is visited individually }
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Thu Jan 24 16:49:37 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Sat Jan 26 19:24:46 2013 -0800 @@ -66,6 +66,9 @@ Log log; JCDiagnostic.Factory diags; + /** Should we inject return-type constraints earlier? */ + boolean allowEarlyReturnConstraints; + public static Infer instance(Context context) { Infer instance = context.get(inferKey); if (instance == null) @@ -83,6 +86,7 @@ chk = Check.instance(context); diags = JCDiagnostic.Factory.instance(context); inferenceException = new InferenceException(diags); + allowEarlyReturnConstraints = Source.instance(context).allowEarlyReturnConstraints(); } /** @@ -188,19 +192,6 @@ MethodType mtype, Attr.ResultInfo resultInfo, Warner warn) throws InferenceException { - Type to = resultInfo.pt; - if (to.hasTag(NONE) || resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) { - to = mtype.getReturnType().isPrimitiveOrVoid() ? - mtype.getReturnType() : syms.objectType; - } - Type qtype1 = inferenceContext.asFree(mtype.getReturnType(), types); - if (!types.isSubtype(qtype1, - qtype1.hasTag(UNDETVAR) ? types.boxedTypeOrType(to) : to)) { - throw inferenceException - .setMessage("infer.no.conforming.instance.exists", - inferenceContext.restvars(), mtype.getReturnType(), to); - } - while (true) { boolean stuck = true; for (Type t : inferenceContext.undetvars) { @@ -283,6 +274,11 @@ try { methodCheck.argumentsAcceptable(env, deferredAttrContext, argtypes, mt.getParameterTypes(), warn); + if (resultInfo != null && allowEarlyReturnConstraints && + !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) { + generateReturnConstraints(mt, inferenceContext, resultInfo); + } + deferredAttrContext.complete(); // minimize as yet undetermined type variables @@ -298,6 +294,9 @@ if (!restvars.isEmpty()) { if (resultInfo != null && !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) { + if (!allowEarlyReturnConstraints) { + generateReturnConstraints(mt, inferenceContext, resultInfo); + } instantiateUninferred(env.tree.pos(), inferenceContext, mt, resultInfo, warn); checkWithinBounds(inferenceContext, warn); mt = (MethodType)inferenceContext.asInstType(mt, types); @@ -313,6 +312,25 @@ inferenceContext.notifyChange(types); } } + //where + void generateReturnConstraints(Type mt, InferenceContext inferenceContext, Attr.ResultInfo resultInfo) { + if (resultInfo != null) { + Type to = resultInfo.pt; + if (to.hasTag(NONE) || resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) { + to = mt.getReturnType().isPrimitiveOrVoid() ? + mt.getReturnType() : syms.objectType; + } + Type qtype1 = inferenceContext.asFree(mt.getReturnType(), types); + Warner retWarn = new Warner(); + if (!resultInfo.checkContext.compatible(qtype1, qtype1.hasTag(UNDETVAR) ? types.boxedTypeOrType(to) : to, retWarn) || + //unchecked conversion is not allowed + retWarn.hasLint(Lint.LintCategory.UNCHECKED)) { + throw inferenceException + .setMessage("infer.no.conforming.instance.exists", + inferenceContext.restvars(), mt.getReturnType(), to); + } + } + } /** check that type parameters are within their bounds. */ @@ -461,52 +479,40 @@ Type formalInterface = funcInterface.tsym.type; InferenceContext funcInterfaceContext = new InferenceContext(funcInterface.tsym.type.getTypeArguments(), this, false); - if (paramTypes != null) { - //get constraints from explicit params (this is done by - //checking that explicit param types are equal to the ones - //in the functional interface descriptors) - List<Type> descParameterTypes = types.findDescriptorType(formalInterface).getParameterTypes(); - if (descParameterTypes.size() != paramTypes.size()) { - checkContext.report(pos, diags.fragment("incompatible.arg.types.in.lambda")); + Assert.check(paramTypes != null); + //get constraints from explicit params (this is done by + //checking that explicit param types are equal to the ones + //in the functional interface descriptors) + List<Type> descParameterTypes = types.findDescriptorType(formalInterface).getParameterTypes(); + if (descParameterTypes.size() != paramTypes.size()) { + checkContext.report(pos, diags.fragment("incompatible.arg.types.in.lambda")); + return types.createErrorType(funcInterface); + } + for (Type p : descParameterTypes) { + if (!types.isSameType(funcInterfaceContext.asFree(p, types), paramTypes.head)) { + checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface)); return types.createErrorType(funcInterface); } - for (Type p : descParameterTypes) { - if (!types.isSameType(funcInterfaceContext.asFree(p, types), paramTypes.head)) { - checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface)); - return types.createErrorType(funcInterface); - } - paramTypes = paramTypes.tail; + paramTypes = paramTypes.tail; + } + List<Type> actualTypeargs = funcInterface.getTypeArguments(); + for (Type t : funcInterfaceContext.undetvars) { + UndetVar uv = (UndetVar)t; + minimizeInst(uv, types.noWarnings); + if (uv.inst == null && + Type.filter(uv.getBounds(InferenceBound.UPPER), boundFilter).nonEmpty()) { + maximizeInst(uv, types.noWarnings); } - for (Type t : funcInterfaceContext.undetvars) { - UndetVar uv = (UndetVar)t; - minimizeInst(uv, types.noWarnings); - if (uv.inst == null && - Type.filter(uv.getBounds(InferenceBound.UPPER), boundFilter).nonEmpty()) { - maximizeInst(uv, types.noWarnings); - } - } - - formalInterface = funcInterfaceContext.asInstType(formalInterface, types); - } - ListBuffer<Type> typeargs = ListBuffer.lb(); - List<Type> actualTypeargs = funcInterface.getTypeArguments(); - //for remaining uninferred type-vars in the functional interface type, - //simply replace the wildcards with its bound - for (Type t : formalInterface.getTypeArguments()) { - if (actualTypeargs.head.hasTag(WILDCARD)) { - WildcardType wt = (WildcardType)actualTypeargs.head; - typeargs.append(wt.type);