# HG changeset patch # User lana # Date 1357861982 28800 # Node ID b568005e66bdd1c340bb96271736c6fa316dea97 # Parent 8e66fb334fb163c27d86d43fc25b0eb0f37a2222# Parent b3a4a1002b19f2cdff7b9b0730dfe79c1cb8c948 Merge diff -r 8e66fb334fb1 -r b568005e66bd langtools/make/build.properties --- a/langtools/make/build.properties Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/make/build.properties Thu Jan 10 15:53:02 2013 -0800 @@ -153,6 +153,7 @@ javap.includes = \ com/sun/tools/classfile/ \ com/sun/tools/javap/ \ + com/sun/tools/jdeps/ \ sun/tools/javap/ javap.tests = \ diff -r 8e66fb334fb1 -r b568005e66bd langtools/makefiles/BuildLangtools.gmk --- a/langtools/makefiles/BuildLangtools.gmk Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/makefiles/BuildLangtools.gmk Thu Jan 10 15:53:02 2013 -0800 @@ -75,6 +75,7 @@ printf "jdk=$(JDK_VERSION)\nfull=$(FULL_VERSION)\nrelease=$(RELEASE)\n" > $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javah/resources/version.properties printf "jdk=$(JDK_VERSION)\nfull=$(FULL_VERSION)\nrelease=$(RELEASE)\n" > $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javap/resources/version.properties printf "jdk=$(JDK_VERSION)\nfull=$(FULL_VERSION)\nrelease=$(RELEASE)\n" > $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javac/resources/version.properties + printf "jdk=$(JDK_VERSION)\nfull=$(FULL_VERSION)\nrelease=$(RELEASE)\n" > $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/jdeps/resources/version.properties echo Compiling $(words $(PROPSOURCES) v1 v2 v3) properties into resource bundles $(TOOL_COMPILEPROPS_CMD) $(PROPCMDLINE) \ -compile $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javah/resources/version.properties \ @@ -85,6 +86,9 @@ java.util.ListResourceBundle \ -compile $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javac/resources/version.properties \ $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javac/resources/version.java \ + java.util.ListResourceBundle \ + -compile $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/jdeps/resources/version.properties \ + $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/jdeps/resources/version.java \ java.util.ListResourceBundle echo PROPS_ARE_CREATED=yes > $@ diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/javadoc/AnnotationDesc.java --- a/langtools/src/share/classes/com/sun/javadoc/AnnotationDesc.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/javadoc/AnnotationDesc.java Thu Jan 10 15:53:02 2013 -0800 @@ -52,6 +52,12 @@ */ ElementValuePair[] elementValues(); + /** + * Check for the synthesized bit on the annotation. + * + * @return true if the annotation is synthesized. + */ + boolean isSynthesized(); /** * Represents an association between an annotation type element diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/classfile/Attribute.java --- a/langtools/src/share/classes/com/sun/tools/classfile/Attribute.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/classfile/Attribute.java Thu Jan 10 15:53:02 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2012, 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 @@ -51,6 +51,7 @@ public static final String LineNumberTable = "LineNumberTable"; public static final String LocalVariableTable = "LocalVariableTable"; public static final String LocalVariableTypeTable = "LocalVariableTypeTable"; + public static final String MethodParameters = "MethodParameters"; public static final String RuntimeVisibleAnnotations = "RuntimeVisibleAnnotations"; public static final String RuntimeInvisibleAnnotations = "RuntimeInvisibleAnnotations"; public static final String RuntimeVisibleParameterAnnotations = "RuntimeVisibleParameterAnnotations"; @@ -113,6 +114,7 @@ standardAttributes.put(LocalVariableTypeTable, LocalVariableTypeTable_attribute.class); if (!compat) { // old javap does not recognize recent attributes + standardAttributes.put(MethodParameters, MethodParameters_attribute.class); standardAttributes.put(CompilationID, CompilationID_attribute.class); standardAttributes.put(RuntimeInvisibleAnnotations, RuntimeInvisibleAnnotations_attribute.class); standardAttributes.put(RuntimeInvisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations_attribute.class); @@ -171,6 +173,7 @@ R visitLineNumberTable(LineNumberTable_attribute attr, P p); R visitLocalVariableTable(LocalVariableTable_attribute attr, P p); R visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, P p); + R visitMethodParameters(MethodParameters_attribute attr, P p); R visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, P p); R visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, P p); R visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, P p); diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/classfile/ClassWriter.java --- a/langtools/src/share/classes/com/sun/tools/classfile/ClassWriter.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/classfile/ClassWriter.java Thu Jan 10 15:53:02 2013 -0800 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2012, 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 @@ -479,6 +479,15 @@ out.writeShort(entry.index); } + public Void visitMethodParameters(MethodParameters_attribute attr, ClassOutputStream out) { + out.writeByte(attr.method_parameter_table.length); + for (MethodParameters_attribute.Entry e : attr.method_parameter_table) { + out.writeShort(e.name_index); + out.writeInt(e.flags); + } + return null; + } + public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, ClassOutputStream out) { annotationWriter.write(attr.annotations, out); return null; diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java --- a/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java Thu Jan 10 15:53:02 2013 -0800 @@ -142,6 +142,15 @@ } /** + * Get a finder to do class dependency analysis. + * + * @return a Class dependency finder + */ + public static Finder getClassDependencyFinder() { + return new ClassDependencyFinder(); + } + + /** * Get the finder used to locate the dependencies for a class. * @return the finder */ @@ -246,8 +255,6 @@ return results; } - - /** * Find the dependencies of a class, using the current * {@link Dependencies#getFinder finder} and @@ -306,38 +313,44 @@ * A location identifying a class. */ static class SimpleLocation implements Location { - public SimpleLocation(String className) { - this.className = className; + public SimpleLocation(String name) { + this.name = name; + this.className = name.replace('/', '.').replace('$', '.'); } - /** - * Get the name of the class being depended on. This name will be used to - * locate the class file for transitive dependency analysis. - * @return the name of the class being depended on - */ + public String getName() { + return name; + } + public String getClassName() { return className; } + public String getPackageName() { + int i = name.lastIndexOf('/'); + return (i > 0) ? name.substring(0, i).replace('/', '.') : ""; + } + @Override public boolean equals(Object other) { if (this == other) return true; if (!(other instanceof SimpleLocation)) return false; - return (className.equals(((SimpleLocation) other).className)); + return (name.equals(((SimpleLocation) other).name)); } @Override public int hashCode() { - return className.hashCode(); + return name.hashCode(); } @Override public String toString() { - return className; + return name; } + private String name; private String className; } @@ -431,9 +444,7 @@ } public boolean accepts(Dependency dependency) { - String cn = dependency.getTarget().getClassName(); - int lastSep = cn.lastIndexOf("/"); - String pn = (lastSep == -1 ? "" : cn.substring(0, lastSep)); + String pn = dependency.getTarget().getPackageName(); if (packageNames.contains(pn)) return true; @@ -451,8 +462,6 @@ private final boolean matchSubpackages; } - - /** * This class identifies class names directly or indirectly in the constant pool. */ @@ -462,6 +471,26 @@ for (CPInfo cpInfo: classfile.constant_pool.entries()) { v.scan(cpInfo); } + try { + v.addClass(classfile.super_class); + v.addClasses(classfile.interfaces); + v.scan(classfile.attributes); + + for (Field f : classfile.fields) { + v.scan(f.descriptor, f.attributes); + } + for (Method m : classfile.methods) { + v.scan(m.descriptor, m.attributes); + Exceptions_attribute e = + (Exceptions_attribute)m.attributes.get(Attribute.Exceptions); + if (e != null) { + v.addClasses(e.exception_index_table); + } + } + } catch (ConstantPoolException e) { + throw new ClassFileError(e); + } + return v.deps; } } @@ -558,9 +587,7 @@ void scan(Descriptor d, Attributes attrs) { try { scan(new Signature(d.index).getType(constant_pool)); - Signature_attribute sa = (Signature_attribute) attrs.get(Attribute.Signature); - if (sa != null) - scan(new Signature(sa.signature_index).getType(constant_pool)); + scan(attrs); } catch (ConstantPoolException e) { throw new ClassFileError(e); } @@ -574,6 +601,43 @@ t.accept(this, null); } + void scan(Attributes attrs) { + try { + Signature_attribute sa = (Signature_attribute)attrs.get(Attribute.Signature); + if (sa != null) + scan(sa.getParsedSignature().getType(constant_pool)); + + scan((RuntimeVisibleAnnotations_attribute) + attrs.get(Attribute.RuntimeVisibleAnnotations)); + scan((RuntimeVisibleParameterAnnotations_attribute) + attrs.get(Attribute.RuntimeVisibleParameterAnnotations)); + } catch (ConstantPoolException e) { + throw new ClassFileError(e); + } + } + + private void scan(RuntimeAnnotations_attribute attr) throws ConstantPoolException { + if (attr == null) { + return; + } + for (int i = 0; i < attr.annotations.length; i++) { + int index = attr.annotations[i].type_index; + scan(new Signature(index).getType(constant_pool)); + } + } + + private void scan(RuntimeParameterAnnotations_attribute attr) throws ConstantPoolException { + if (attr == null) { + return; + } + for (int param = 0; param < attr.parameter_annotations.length; param++) { + for (int i = 0; i < attr.parameter_annotations[param].length; i++) { + int index = attr.parameter_annotations[param][i].type_index; + scan(new Signature(index).getType(constant_pool)); + } + } + } + void addClass(int index) throws ConstantPoolException { if (index != 0) { String name = constant_pool.getClassInfo(index).getBaseName(); @@ -698,6 +762,7 @@ findDependencies(type.paramTypes); findDependencies(type.returnType); findDependencies(type.throwsTypes); + findDependencies(type.typeParamTypes); return null; } @@ -709,7 +774,7 @@ public Void visitClassType(ClassType type, Void p) { findDependencies(type.outerType); - addDependency(type.name); + addDependency(type.getBinaryName()); findDependencies(type.typeArgs); return null; } diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/classfile/Dependency.java --- a/langtools/src/share/classes/com/sun/tools/classfile/Dependency.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/classfile/Dependency.java Thu Jan 10 15:53:02 2013 -0800 @@ -71,7 +71,19 @@ * dependency analysis. * @return the name of the class containing the location. */ + String getName(); + + /** + * Get the fully-qualified name of the class containing the location. + * @return the fully-qualified name of the class containing the location. + */ String getClassName(); + + /** + * Get the package name of the class containing the location. + * @return the package name of the class containing the location. + */ + String getPackageName(); } diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/classfile/MethodParameters_attribute.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/com/sun/tools/classfile/MethodParameters_attribute.java Thu Jan 10 15:53:02 2013 -0800 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2012, 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 JVMS, section 4.8.13. + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class MethodParameters_attribute extends Attribute { + + public final int method_parameter_table_length; + public final Entry[] method_parameter_table; + + MethodParameters_attribute(ClassReader cr, + int name_index, + int length) + throws IOException { + super(name_index, length); + + method_parameter_table_length = cr.readUnsignedByte(); + method_parameter_table = new Entry[method_parameter_table_length]; + for (int i = 0; i < method_parameter_table_length; i++) + method_parameter_table[i] = new Entry(cr); + } + + public MethodParameters_attribute(ConstantPool constant_pool, + Entry[] method_parameter_table) + throws ConstantPoolException { + this(constant_pool.getUTF8Index(Attribute.MethodParameters), + method_parameter_table); + } + + public MethodParameters_attribute(int name_index, + Entry[] method_parameter_table) { + super(name_index, 1 + method_parameter_table.length * Entry.length()); + this.method_parameter_table_length = method_parameter_table.length; + this.method_parameter_table = method_parameter_table; + } + + public R accept(Visitor visitor, D data) { + return visitor.visitMethodParameters(this, data); + } + + public static class Entry { + Entry(ClassReader cr) throws IOException { + name_index = cr.readUnsignedShort(); + flags = cr.readInt(); + } + + public static int length() { + return 6; + } + + public final int name_index; + public final int flags; + } + +} diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractMemberWriter.java Thu Jan 10 15:53:02 2013 -0800 @@ -321,7 +321,8 @@ code.addContent(" "); } if (member.isMethod()) { - if (((MethodDoc)member).isAbstract()) { + if (!(member.containingClass().isInterface()) && + ((MethodDoc)member).isAbstract()) { code.addContent("abstract "); } // This check for isDefault() and the default modifier needs to be @@ -329,7 +330,7 @@ // method summary section. Once the default modifier is added // to the Modifier list on DocEnv and once it is updated to use the // javax.lang.model.element.Modifier, we will need to remove this. - else if (((MethodDoc)member).isDefault()) { + if (((MethodDoc)member).isDefault()) { code.addContent("default "); } } @@ -561,11 +562,14 @@ if (member instanceof MethodDoc && !member.isAnnotationTypeElement()) { int methodType = (member.isStatic()) ? MethodTypes.STATIC.value() : MethodTypes.INSTANCE.value(); - methodType = (classdoc.isInterface() || ((MethodDoc)member).isAbstract()) ? - methodType | MethodTypes.ABSTRACT.value() : - methodType | MethodTypes.CONCRETE.value(); - if (((MethodDoc)member).isDefault()) { - methodType = methodType | MethodTypes.DEFAULT.value(); + if (member.containingClass().isInterface()) { + methodType = (((MethodDoc) member).isAbstract()) + ? methodType | MethodTypes.ABSTRACT.value() + : methodType | MethodTypes.DEFAULT.value(); + } else { + methodType = (((MethodDoc) member).isAbstract()) + ? methodType | MethodTypes.ABSTRACT.value() + : methodType | MethodTypes.CONCRETE.value(); } if (Util.isDeprecated(member) || Util.isDeprecated(classdoc)) { methodType = methodType | MethodTypes.DEPRECATED.value(); diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java Thu Jan 10 15:53:02 2013 -0800 @@ -90,6 +90,16 @@ protected boolean printedAnnotationHeading = false; /** + * To check whether the repeated annotations is documented or not. + */ + private boolean isAnnotationDocumented = false; + + /** + * To check whether the container annotations is documented or not. + */ + private boolean isContainerDocumented = false; + + /** * Constructor to construct the HtmlStandardWriter object. * * @param path File to be generated. @@ -1793,50 +1803,66 @@ StringBuilder annotation; for (int i = 0; i < descList.length; i++) { AnnotationTypeDoc annotationDoc = descList[i].annotationType(); - if (! Util.isDocumentedAnnotation(annotationDoc)){ + // If an annotation is not documented, do not add it to the list. If + // the annotation is of a repeatable type, and if it is not documented + // and also if its container annotation is not documented, do not add it + // to the list. If an annotation of a repeatable type is not documented + // but its container is documented, it will be added to the list. + if (! Util.isDocumentedAnnotation(annotationDoc) && + (!isAnnotationDocumented && !isContainerDocumented)) { continue; } annotation = new StringBuilder(); + isAnnotationDocumented = false; LinkInfoImpl linkInfo = new LinkInfoImpl(configuration, LinkInfoImpl.CONTEXT_ANNOTATION, annotationDoc); - linkInfo.label = "@" + annotationDoc.name(); - annotation.append(getLink(linkInfo)); AnnotationDesc.ElementValuePair[] pairs = descList[i].elementValues(); - if (pairs.length > 0) { - annotation.append('('); + // If the annotation is synthesized, do not print the container. + if (descList[i].isSynthesized()) { for (int j = 0; j < pairs.length; j++) { - if (j > 0) { - annotation.append(","); - if (linkBreak) { - annotation.append(DocletConstants.NL); - int spaces = annotationDoc.name().length() + 2; - for (int k = 0; k < (spaces + indent); k++) { - annotation.append(' '); - } - } - } - annotation.append(getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION, - pairs[j].element(), pairs[j].element().name(), false)); - annotation.append('='); AnnotationValue annotationValue = pairs[j].value(); List annotationTypeValues = new ArrayList(); if (annotationValue.value() instanceof AnnotationValue[]) { AnnotationValue[] annotationArray = - (AnnotationValue[]) annotationValue.value(); - for (int k = 0; k < annotationArray.length; k++) { - annotationTypeValues.add(annotationArray[k]); - } + (AnnotationValue[]) annotationValue.value(); + annotationTypeValues.addAll(Arrays.asList(annotationArray)); } else { annotationTypeValues.add(annotationValue); } - annotation.append(annotationTypeValues.size() == 1 ? "" : "{"); - for (Iterator iter = annotationTypeValues.iterator(); iter.hasNext(); ) { - annotation.append(annotationValueToString(iter.next())); - annotation.append(iter.hasNext() ? "," : ""); + String sep = ""; + for (AnnotationValue av : annotationTypeValues) { + annotation.append(sep); + annotation.append(annotationValueToString(av)); + sep = " "; } - annotation.append(annotationTypeValues.size() == 1 ? "" : "}"); } - annotation.append(")"); + } + else if (isAnnotationArray(pairs)) { + // If the container has 1 or more value defined and if the + // repeatable type annotation is not documented, do not print + // the container. + if (pairs.length == 1 && isAnnotationDocumented) { + AnnotationValue[] annotationArray = + (AnnotationValue[]) (pairs[0].value()).value(); + List annotationTypeValues = new ArrayList(); + annotationTypeValues.addAll(Arrays.asList(annotationArray)); + String sep = ""; + for (AnnotationValue av : annotationTypeValues) { + annotation.append(sep); + annotation.append(annotationValueToString(av)); + sep = " "; + } + } + // If the container has 1 or more value defined and if the + // repeatable type annotation is not documented, print the container. + else { + addAnnotations(annotationDoc, linkInfo, annotation, pairs, + indent, false); + } + } + else { + addAnnotations(annotationDoc, linkInfo, annotation, pairs, + indent, linkBreak); } annotation.append(linkBreak ? DocletConstants.NL : ""); results.add(annotation.toString()); @@ -1844,6 +1870,91 @@ return results; } + /** + * Add annotation to the annotation string. + * + * @param annotationDoc the annotation being documented + * @param linkInfo the information about the link + * @param annotation the annotation string to which the annotation will be added + * @param pairs annotation type element and value pairs + * @param indent the number of extra spaces to indent the annotations. + * @param linkBreak if true, add new line between each member value + */ + private void addAnnotations(AnnotationTypeDoc annotationDoc, LinkInfoImpl linkInfo, + StringBuilder annotation, AnnotationDesc.ElementValuePair[] pairs, + int indent, boolean linkBreak) { + linkInfo.label = "@" + annotationDoc.name(); + annotation.append(getLink(linkInfo)); + if (pairs.length > 0) { + annotation.append('('); + for (int j = 0; j < pairs.length; j++) { + if (j > 0) { + annotation.append(","); + if (linkBreak) { + annotation.append(DocletConstants.NL); + int spaces = annotationDoc.name().length() + 2; + for (int k = 0; k < (spaces + indent); k++) { + annotation.append(' '); + } + } + } + annotation.append(getDocLink(LinkInfoImpl.CONTEXT_ANNOTATION, + pairs[j].element(), pairs[j].element().name(), false)); + annotation.append('='); + AnnotationValue annotationValue = pairs[j].value(); + List annotationTypeValues = new ArrayList(); + if (annotationValue.value() instanceof AnnotationValue[]) { + AnnotationValue[] annotationArray = + (AnnotationValue[]) annotationValue.value(); + annotationTypeValues.addAll(Arrays.asList(annotationArray)); + } else { + annotationTypeValues.add(annotationValue); + } + annotation.append(annotationTypeValues.size() == 1 ? "" : "{"); + String sep = ""; + for (AnnotationValue av : annotationTypeValues) { + annotation.append(sep); + annotation.append(annotationValueToString(av)); + sep = ","; + } + annotation.append(annotationTypeValues.size() == 1 ? "" : "}"); + isContainerDocumented = false; + } + annotation.append(")"); + } + } + + /** + * Check if the annotation contains an array of annotation as a value. This + * check is to verify if a repeatable type annotation is present or not. + * + * @param pairs annotation type element and value pairs + * + * @return true if the annotation contains an array of annotation as a value. + */ + private boolean isAnnotationArray(AnnotationDesc.ElementValuePair[] pairs) { + AnnotationValue annotationValue; + for (int j = 0; j < pairs.length; j++) { + annotationValue = pairs[j].value(); + if (annotationValue.value() instanceof AnnotationValue[]) { + AnnotationValue[] annotationArray = + (AnnotationValue[]) annotationValue.value(); + if (annotationArray.length > 1) { + if (annotationArray[0].value() instanceof AnnotationDesc) { + AnnotationTypeDoc annotationDoc = + ((AnnotationDesc) annotationArray[0].value()).annotationType(); + isContainerDocumented = true; + if (Util.isDocumentedAnnotation(annotationDoc)) { + isAnnotationDocumented = true; + } + return true; + } + } + } + } + return false; + } + private String annotationValueToString(AnnotationValue annotationValue) { if (annotationValue.value() instanceof Type) { Type type = (Type) annotationValue.value(); diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java --- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Thu Jan 10 15:53:02 2013 -0800 @@ -1283,8 +1283,9 @@ List paramNames = savedParameterNames; savedParameterNames = null; // discard the provided names if the list of names is the wrong size. - if (paramNames == null || paramNames.size() != type.getParameterTypes().size()) + if (paramNames == null || paramNames.size() != type.getParameterTypes().size()) { paramNames = List.nil(); + } ListBuffer buf = new ListBuffer(); List remaining = paramNames; // assert: remaining and paramNames are both empty or both diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Thu Jan 10 15:53:02 2013 -0800 @@ -38,6 +38,7 @@ import javax.tools.JavaFileObject; import java.util.ArrayList; +import java.util.EnumSet; import java.util.LinkedHashSet; import java.util.Map; import java.util.Queue; @@ -177,29 +178,19 @@ * attribution round must follow one or more speculative rounds. */ Type check(ResultInfo resultInfo) { + return check(resultInfo, stuckVars(tree, env, resultInfo), basicCompleter); + } + + Type check(ResultInfo resultInfo, List stuckVars, DeferredTypeCompleter deferredTypeCompleter) { DeferredAttrContext deferredAttrContext = resultInfo.checkContext.deferredAttrContext(); Assert.check(deferredAttrContext != emptyDeferredAttrContext); - List stuckVars = stuckVars(tree, env, resultInfo); if (stuckVars.nonEmpty()) { deferredAttrContext.addDeferredAttrNode(this, resultInfo, stuckVars); return Type.noType; } else { try { - switch (deferredAttrContext.mode) { - case SPECULATIVE: - Assert.check(mode == null || - (mode == AttrMode.SPECULATIVE && - speculativeType(deferredAttrContext.msym, deferredAttrContext.phase).hasTag(NONE))); - JCTree speculativeTree = attribSpeculative(tree, env, resultInfo); - speculativeCache.put(deferredAttrContext.msym, speculativeTree, deferredAttrContext.phase); - return speculativeTree.type; - case CHECK: - Assert.check(mode == AttrMode.SPECULATIVE); - return attr.attribTree(tree, env, resultInfo); - } - Assert.error(); - return null; + return deferredTypeCompleter.complete(this, resultInfo, deferredAttrContext); } finally { mode = deferredAttrContext.mode; } @@ -208,6 +199,43 @@ } /** + * A completer for deferred types. Defines an entry point for type-checking + * a deferred type. + */ + interface DeferredTypeCompleter { + /** + * Entry point for type-checking a deferred type. Depending on the + * circumstances, type-checking could amount to full attribution + * or partial structural check (aka potential applicability). + */ + Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext); + } + + /** + * A basic completer for deferred types. This completer type-checks a deferred type + * using attribution; depending on the attribution mode, this could be either standard + * or speculative attribution. + */ + DeferredTypeCompleter basicCompleter = new DeferredTypeCompleter() { + public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) { + switch (deferredAttrContext.mode) { + case SPECULATIVE: + Assert.check(dt.mode == null || + (dt.mode == AttrMode.SPECULATIVE && + dt.speculativeType(deferredAttrContext.msym, deferredAttrContext.phase).hasTag(NONE))); + JCTree speculativeTree = attribSpeculative(dt.tree, dt.env, resultInfo); + dt.speculativeCache.put(deferredAttrContext.msym, speculativeTree, deferredAttrContext.phase); + return speculativeTree.type; + case CHECK: + Assert.check(dt.mode == AttrMode.SPECULATIVE); + return attr.attribTree(dt.tree, dt.env, resultInfo); + } + Assert.error(); + return null; + } + }; + + /** * The 'mode' in which the deferred type is to be type-checked */ public enum AttrMode { @@ -498,10 +526,80 @@ if (resultInfo.pt.hasTag(NONE) || resultInfo.pt.isErroneous()) { return List.nil(); } else { - StuckChecker sc = new StuckChecker(resultInfo, env); + return stuckVarsInternal(tree, resultInfo.pt, resultInfo.checkContext.inferenceContext()); + } + } + //where + private List stuckVarsInternal(JCTree tree, Type pt, Infer.InferenceContext inferenceContext) { + StuckChecker sc = new StuckChecker(pt, inferenceContext); sc.scan(tree); return List.from(sc.stuckVars); } + + /** + * A special tree scanner that would only visit portions of a given tree. + * The set of nodes visited by the scanner can be customized at construction-time. + */ + abstract static class FilterScanner extends TreeScanner { + + final Filter treeFilter; + + FilterScanner(final Set validTags) { + this.treeFilter = new Filter() { + public boolean accepts(JCTree t) { + return validTags.contains(t.getTag()); + } + }; + } + + @Override + public void scan(JCTree tree) { + if (tree != null) { + if (treeFilter.accepts(tree)) { + super.scan(tree); + } else { + skip(tree); + } + } + } + + /** + * handler that is executed when a node has been discarded + */ + abstract void skip(JCTree tree); + } + + /** + * A tree scanner suitable for visiting the target-type dependent nodes of + * a given argument expression. + */ + static class PolyScanner extends FilterScanner { + + PolyScanner() { + super(EnumSet.of(CONDEXPR, PARENS, LAMBDA, REFERENCE)); + } + + @Override + void skip(JCTree tree) { + //do nothing + } + } + + /** + * A tree scanner suitable for visiting the target-type dependent nodes nested + * within a lambda expression body. + */ + static class LambdaReturnScanner extends FilterScanner { + + LambdaReturnScanner() { + super(EnumSet.of(BLOCK, CASE, CATCH, DOLOOP, FOREACHLOOP, + FORLOOP, RETURN, SYNCHRONIZED, SWITCH, TRY, WHILELOOP)); + } + + @Override + void skip(JCTree tree) { + //do nothing + } } /** @@ -510,83 +608,32 @@ * inferring types that make some of the nested expressions incompatible * with their corresponding instantiated target */ - class StuckChecker extends TreeScanner { + class StuckChecker extends PolyScanner { Type pt; - Filter treeFilter; Infer.InferenceContext inferenceContext; Set stuckVars = new LinkedHashSet(); - Env env; - final Filter argsFilter = new Filter() { - public boolean accepts(JCTree t) { - switch (t.getTag()) { - case CONDEXPR: - case LAMBDA: - case PARENS: - case REFERENCE: - return true; - default: - return false; - } - } - }; - - final Filter lambdaBodyFilter = new Filter() { - public boolean accepts(JCTree t) { - switch (t.getTag()) { - case BLOCK: case CASE: case CATCH: case DOLOOP: - case FOREACHLOOP: case FORLOOP: case RETURN: - case SYNCHRONIZED: case SWITCH: case TRY: case WHILELOOP: - return true; - default: - return false; - } - } - }; - - StuckChecker(ResultInfo resultInfo, Env env) { - this.pt = resultInfo.pt; - this.inferenceContext = resultInfo.checkContext.inferenceContext(); - this.treeFilter = argsFilter; - this.env = env; - } - - @Override - public void scan(JCTree tree) { - if (tree != null && treeFilter.accepts(tree)) { - super.scan(tree); - } + StuckChecker(Type pt, Infer.InferenceContext inferenceContext) { + this.pt = pt; + this.inferenceContext = inferenceContext; } @Override public void visitLambda(JCLambda tree) { - Type prevPt = pt; - Filter prevFilter = treeFilter; - try { - if (inferenceContext.inferenceVars().contains(pt)) { - stuckVars.add(pt); - } - if (!types.isFunctionalInterface(pt.tsym)) { - return; - } - Type descType = types.findDescriptorType(pt); - List freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes()); - if (!TreeInfo.isExplicitLambda(tree) && - freeArgVars.nonEmpty()) { - stuckVars.addAll(freeArgVars); - } - pt = descType.getReturnType(); - if (tree.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) { - scan(tree.getBody()); - } else { - treeFilter = lambdaBodyFilter; - super.visitLambda(tree); - } - } finally { - pt = prevPt; - treeFilter = prevFilter; + if (inferenceContext.inferenceVars().contains(pt)) { + stuckVars.add(pt); + } + if (!types.isFunctionalInterface(pt.tsym)) { + return; } + Type descType = types.findDescriptorType(pt); + List freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes()); + if (!TreeInfo.isExplicitLambda(tree) && + freeArgVars.nonEmpty()) { + stuckVars.addAll(freeArgVars); + } + scanLambdaBody(tree, descType.getReturnType()); } @Override @@ -605,16 +652,19 @@ stuckVars.addAll(freeArgVars); } - @Override - public void visitReturn(JCReturn tree) { - Filter prevFilter = treeFilter; - try { - treeFilter = argsFilter; - if (tree.expr != null) { - scan(tree.expr); - } - } finally { - treeFilter = prevFilter; + void scanLambdaBody(JCLambda lambda, final Type pt) { + if (lambda.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) { + stuckVars.addAll(stuckVarsInternal(lambda.body, pt, inferenceContext)); + } else { + LambdaReturnScanner lambdaScanner = new LambdaReturnScanner() { + @Override + public void visitReturn(JCReturn tree) { + if (tree.expr != null) { + stuckVars.addAll(stuckVarsInternal(tree.expr, pt, inferenceContext)); + } + } + }; + lambdaScanner.scan(lambda.body); } } } diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Thu Jan 10 15:53:02 2013 -0800 @@ -114,7 +114,7 @@ } } - private final InferenceException inferenceException; + final InferenceException inferenceException; /*************************************************************************** * Mini/Maximization of UndetVars @@ -271,15 +271,19 @@ boolean allowBoxing, boolean useVarargs, Resolve.MethodResolutionContext resolveContext, + Resolve.MethodCheck methodCheck, Warner warn) throws InferenceException { //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG final InferenceContext inferenceContext = new InferenceContext(tvars, this, true); inferenceException.clear(); + DeferredAttr.DeferredAttrContext deferredAttrContext = + resolveContext.deferredAttrContext(msym, inferenceContext); + try { - rs.checkRawArgumentsAcceptable(env, msym, resolveContext.attrMode(), inferenceContext, - argtypes, mt.getParameterTypes(), allowBoxing, useVarargs, warn, - new InferenceCheckHandler(inferenceContext)); + methodCheck.argumentsAcceptable(env, deferredAttrContext, argtypes, mt.getParameterTypes(), warn); + + deferredAttrContext.complete(); // minimize as yet undetermined type variables for (Type t : inferenceContext.undetvars) { @@ -309,32 +313,6 @@ inferenceContext.notifyChange(types); } } - //where - - /** inference check handler **/ - class InferenceCheckHandler implements Resolve.MethodCheckHandler { - - InferenceContext inferenceContext; - - public InferenceCheckHandler(InferenceContext inferenceContext) { - this.inferenceContext = inferenceContext; - } - - public InapplicableMethodException arityMismatch() { - return inferenceException.setMessage("infer.arg.length.mismatch", inferenceContext.inferenceVars()); - } - public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details) { - String key = varargs ? - "infer.varargs.argument.mismatch" : - "infer.no.conforming.assignment.exists"; - return inferenceException.setMessage(key, - inferenceContext.inferenceVars(), details); - } - public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) { - return inferenceException.setMessage("inaccessible.varargs.type", - expected, Kinds.kindName(location), location); - } - } /** check that type parameters are within their bounds. */ diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Thu Jan 10 15:53:02 2013 -0800 @@ -506,6 +506,7 @@ List typeargtypes, boolean allowBoxing, boolean useVarargs, + MethodCheck methodCheck, Warner warn) throws Infer.InferenceException { Type mt = types.memberType(site, m); @@ -558,10 +559,11 @@ allowBoxing, useVarargs, currentResolutionContext, + methodCheck, warn); - checkRawArgumentsAcceptable(env, m, argtypes, mt.getParameterTypes(), - allowBoxing, useVarargs, warn); + methodCheck.argumentsAcceptable(env, currentResolutionContext.deferredAttrContext(m, infer.emptyContext), + argtypes, mt.getParameterTypes(), warn); return mt; } @@ -578,7 +580,7 @@ currentResolutionContext.attrMode = DeferredAttr.AttrMode.CHECK; MethodResolutionPhase step = currentResolutionContext.step = env.info.pendingResolutionPhase; return rawInstantiate(env, site, m, resultInfo, argtypes, typeargtypes, - step.isBoxingRequired(), step.isVarargsRequired(), warn); + step.isBoxingRequired(), step.isVarargsRequired(), resolveMethodCheck, warn); } finally { currentResolutionContext = prevContext; @@ -595,80 +597,65 @@ List typeargtypes, boolean allowBoxing, boolean useVarargs, + MethodCheck methodCheck, Warner warn) { try { return rawInstantiate(env, site, m, resultInfo, argtypes, typeargtypes, - allowBoxing, useVarargs, warn); + allowBoxing, useVarargs, methodCheck, warn); } catch (InapplicableMethodException ex) { return null; } } - /** Check if a parameter list accepts a list of args. + /** + * This interface defines an entry point that should be used to perform a + * method check. A method check usually consist in determining as to whether + * a set of types (actuals) is compatible with another set of types (formals). + * Since the notion of compatibility can vary depending on the circumstances, + * this interfaces allows to easily add new pluggable method check routines. */ - boolean argumentsAcceptable(Env env, - Symbol msym, + interface MethodCheck { + /** + * Main method check routine. A method check usually consist in determining + * as to whether a set of types (actuals) is compatible with another set of + * types (formals). If an incompatibility is found, an unchecked exception + * is assumed to be thrown. + */ + void argumentsAcceptable(Env env, + DeferredAttrContext deferredAttrContext, List argtypes, List formals, - boolean allowBoxing, - boolean useVarargs, - Warner warn) { - try { - checkRawArgumentsAcceptable(env, msym, argtypes, formals, allowBoxing, useVarargs, warn); - return true; - } catch (InapplicableMethodException ex) { - return false; - } - } - /** - * A check handler is used by the main method applicability routine in order - * to handle specific method applicability failures. It is assumed that a class - * implementing this interface should throw exceptions that are a subtype of - * InapplicableMethodException (see below). Such exception will terminate the - * method applicability check and propagate important info outwards (for the - * purpose of generating better diagnostics). - */ - interface MethodCheckHandler { - /* The number of actuals and formals differ */ - InapplicableMethodException arityMismatch(); - /* An actual argument type does not conform to the corresponding formal type */ - InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details); - /* The element type of a varargs is not accessible in the current context */ - InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected); + Warner warn); } /** - * Basic method check handler used within Resolve - all methods end up - * throwing InapplicableMethodException; a diagnostic fragment that describes - * the cause as to why the method is not applicable is set on the exception - * before it is thrown. + * Helper enum defining all method check diagnostics (used by resolveMethodCheck). */ - MethodCheckHandler resolveHandler = new MethodCheckHandler() { - public InapplicableMethodException arityMismatch() { - return inapplicableMethodException.setMessage("arg.length.mismatch"); - } - public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details) { - String key = varargs ? - "varargs.argument.mismatch" : - "no.conforming.assignment.exists"; - return inapplicableMethodException.setMessage(key, - details); - } - public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) { - return inapplicableMethodException.setMessage("inaccessible.varargs.type", - expected, Kinds.kindName(location), location); - } - }; - - void checkRawArgumentsAcceptable(Env env, - Symbol msym, - List argtypes, - List formals, - boolean allowBoxing, - boolean useVarargs, - Warner warn) { - checkRawArgumentsAcceptable(env, msym, currentResolutionContext.attrMode(), infer.emptyContext, argtypes, formals, - allowBoxing, useVarargs, warn, resolveHandler); + enum MethodCheckDiag { + /** + * Actuals and formals differs in length. + */ + ARITY_MISMATCH("arg.length.mismatch", "infer.arg.length.mismatch"), + /** + * An actual is incompatible with a formal. + */ + ARG_MISMATCH("no.conforming.assignment.exists", "infer.no.conforming.assignment.exists"), + /** + * An actual is incompatible with the varargs element type. + */ + VARARG_MISMATCH("varargs.argument.mismatch", "infer.varargs.argument.mismatch"), + /** + * The varargs element type is inaccessible. + */ + INACCESSIBLE_VARARGS("inaccessible.varargs.type", "inaccessible.varargs.type"); + + final String basicKey; + final String inferKey; + + MethodCheckDiag(String basicKey, String inferKey) { + this.basicKey = basicKey; + this.inferKey = inferKey; + } } /** @@ -689,68 +676,94 @@ * * A method check handler (see above) is used in order to report errors. */ - void checkRawArgumentsAcceptable(final Env env, - Symbol msym, - DeferredAttr.AttrMode mode, - final Infer.InferenceContext inferenceContext, - List argtypes, - List formals, - boolean allowBoxing, - boolean useVarargs, - Warner warn, - final MethodCheckHandler handler) { - Type varargsFormal = useVarargs ? formals.last() : null; - - if (varargsFormal == null && - argtypes.size() != formals.size()) { - throw handler.arityMismatch(); // not enough args - } - - DeferredAttr.DeferredAttrContext deferredAttrContext = - deferredAttr.new DeferredAttrContext(mode, msym, currentResolutionContext.step, inferenceContext); - - while (argtypes.nonEmpty() && formals.head != varargsFormal) { - ResultInfo mresult = methodCheckResult(formals.head, allowBoxing, false, inferenceContext, deferredAttrContext, handler, warn); - mresult.check(null, argtypes.head); - argtypes = argtypes.tail; - formals = formals.tail; - } - - if (formals.head != varargsFormal) { - throw handler.arityMismatch(); // not enough args - } - - if (useVarargs) { - //note: if applicability check is triggered by most specific test, - //the last argument of a varargs is _not_ an array type (see JLS 15.12.2.5) - final Type elt = types.elemtype(varargsFormal); - ResultInfo mresult = methodCheckResult(elt, allowBoxing, true, inferenceContext, deferredAttrContext, handler, warn); - while (argtypes.nonEmpty()) { + MethodCheck resolveMethodCheck = new MethodCheck() { + @Override + public void argumentsAcceptable(final Env env, + DeferredAttrContext deferredAttrContext, + List argtypes, + List formals, + Warner warn) { + //should we expand formals? + boolean useVarargs = deferredAttrContext.phase.isVarargsRequired(); + + //inference context used during this method check + InferenceContext inferenceContext = deferredAttrContext.inferenceContext; + + Type varargsFormal = useVarargs ? formals.last() : null; + + if (varargsFormal == null && + argtypes.size() != formals.size()) { + report(MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args + } + + while (argtypes.nonEmpty() && formals.head != varargsFormal) { + ResultInfo mresult = methodCheckResult(false, formals.head, deferredAttrContext, warn); mresult.check(null, argtypes.head); argtypes = argtypes.tail; + formals = formals.tail; } - //check varargs element type accessibility - varargsAccessible(env, elt, handler, inferenceContext); - } - - deferredAttrContext.complete(); - } - - void varargsAccessible(final Env env, final Type t, final Resolve.MethodCheckHandler handler, final InferenceContext inferenceContext) { - if (inferenceContext.free(t)) { - inferenceContext.addFreeTypeListener(List.of(t), new FreeTypeListener() { - @Override - public void typesInferred(InferenceContext inferenceContext) { - varargsAccessible(env, inferenceContext.asInstType(t, types), handler, inferenceContext); + + if (formals.head != varargsFormal) { + report(MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args + } + + if (useVarargs) { + //note: if applicability check is triggered by most specific test, + //the last argument of a varargs is _not_ an array type (see JLS 15.12.2.5) + final Type elt = types.elemtype(varargsFormal); + ResultInfo mresult = methodCheckResult(true, elt, deferredAttrContext, warn); + while (argtypes.nonEmpty()) { + mresult.check(null, argtypes.head); + argtypes = argtypes.tail; } - }); - } else { - if (!isAccessible(env, t)) { - Symbol location = env.enclClass.sym; - throw handler.inaccessibleVarargs(location, t); + //check varargs element type accessibility + varargsAccessible(env, elt, inferenceContext); } } - } + + private void report(MethodCheckDiag diag, InferenceContext inferenceContext, Object... args) { + boolean inferDiag = inferenceContext != infer.emptyContext; + InapplicableMethodException ex = inferDiag ? + infer.inferenceException : inapplicableMethodException; + if (inferDiag && (!diag.inferKey.equals(diag.basicKey))) { + Object[] args2 = new Object[args.length + 1]; + System.arraycopy(args, 0, args2, 1, args.length); + args2[0] = inferenceContext.inferenceVars(); + args = args2; + } + throw ex.setMessage(inferDiag ? diag.inferKey : diag.basicKey, args); + } + + private void varargsAccessible(final Env env, final Type t, final InferenceContext inferenceContext) { + if (inferenceContext.free(t)) { + inferenceContext.addFreeTypeListener(List.of(t), new FreeTypeListener() { + @Override + public void typesInferred(InferenceContext inferenceContext) { + varargsAccessible(env, inferenceContext.asInstType(t, types), inferenceContext); + } + }); + } else { + if (!isAccessible(env, t)) { + Symbol location = env.enclClass.sym; + report(MethodCheckDiag.INACCESSIBLE_VARARGS, inferenceContext, t, Kinds.kindName(location), location); + } + } + } + + private ResultInfo methodCheckResult(final boolean varargsCheck, Type to, + final DeferredAttr.DeferredAttrContext deferredAttrContext, Warner rsWarner) { + CheckContext checkContext = new MethodCheckContext(!deferredAttrContext.phase.isBoxingRequired(), deferredAttrContext, rsWarner) { + MethodCheckDiag methodDiag = varargsCheck ? + MethodCheckDiag.VARARG_MISMATCH : MethodCheckDiag.ARG_MISMATCH; + + @Override + public void report(DiagnosticPosition pos, JCDiagnostic details) { + report(methodDiag, deferredAttrContext.inferenceContext, details); + } + }; + return new MethodResultInfo(to, checkContext); + } + }; /** * Check context to be used during method applicability checks. A method check @@ -758,23 +771,24 @@ */ abstract class MethodCheckContext implements CheckContext { - MethodCheckHandler handler; - boolean useVarargs; - Infer.InferenceContext inferenceContext; + boolean strict; DeferredAttrContext deferredAttrContext; Warner rsWarner; - public MethodCheckContext(MethodCheckHandler handler, boolean useVarargs, - Infer.InferenceContext inferenceContext, DeferredAttrContext deferredAttrContext, Warner rsWarner) { - this.handler = handler; - this.useVarargs = useVarargs; - this.inferenceContext = inferenceContext; - this.deferredAttrContext = deferredAttrContext; - this.rsWarner = rsWarner; + public MethodCheckContext(boolean strict, DeferredAttrContext deferredAttrContext, Warner rsWarner) { + this.strict = strict; + this.deferredAttrContext = deferredAttrContext; + this.rsWarner = rsWarner; + } + + public boolean compatible(Type found, Type req, Warner warn) { + return strict ? + types.isSubtypeUnchecked(found, deferredAttrContext.inferenceContext.asFree(req, types), warn) : + types.isConvertible(found, deferredAttrContext.inferenceContext.asFree(req, types), warn); } public void report(DiagnosticPosition pos, JCDiagnostic details) { - throw handler.argumentMismatch(useVarargs, details); + throw inapplicableMethodException.setMessage(details); } public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) { @@ -782,7 +796,7 @@ } public InferenceContext inferenceContext() { - return inferenceContext; + return deferredAttrContext.inferenceContext; } public DeferredAttrContext deferredAttrContext() { @@ -791,56 +805,13 @@ } /** - * Subclass of method check context class that implements strict method conversion. - * Strict method conversion checks compatibility between types using subtyping tests. - */ - class StrictMethodContext extends MethodCheckContext { - - public StrictMethodContext(MethodCheckHandler handler, boolean useVarargs, - Infer.InferenceContext inferenceContext, DeferredAttrContext deferredAttrContext, Warner rsWarner) { - super(handler, useVarargs, inferenceContext, deferredAttrContext, rsWarner); - } - - public boolean compatible(Type found, Type req, Warner warn) { - return types.isSubtypeUnchecked(found, inferenceContext.asFree(req, types), warn); - } - } - - /** - * Subclass of method check context class that implements loose method conversion. - * Loose method conversion checks compatibility between types using method conversion tests. + * ResultInfo class to be used during method applicability checks. Check + * for deferred types goes through special path. */ - class LooseMethodContext extends MethodCheckContext { - - public LooseMethodContext(MethodCheckHandler handler, boolean useVarargs, - Infer.InferenceContext inferenceContext, DeferredAttrContext deferredAttrContext, Warner rsWarner) { - super(handler, useVarargs, inferenceContext, deferredAttrContext, rsWarner); - } - - public boolean compatible(Type found, Type req, Warner warn) { - return types.isConvertible(found, inferenceContext.asFree(req, types), warn); - } - } - - /** - * Create a method check context to be used during method applicability check - */ - ResultInfo methodCheckResult(Type to, boolean allowBoxing, boolean useVarargs, - Infer.InferenceContext inferenceContext, DeferredAttr.DeferredAttrContext deferredAttrContext, - MethodCheckHandler methodHandler, Warner rsWarner) { - MethodCheckContext checkContext = allowBoxing ? - new LooseMethodContext(methodHandler, useVarargs, inferenceContext, deferredAttrContext, rsWarner) : - new StrictMethodContext(methodHandler, useVarargs, inferenceContext, deferredAttrContext, rsWarner); - return new MethodResultInfo(to, checkContext, deferredAttrContext); - } - class MethodResultInfo extends ResultInfo { - DeferredAttr.DeferredAttrContext deferredAttrContext; - - public MethodResultInfo(Type pt, CheckContext checkContext, DeferredAttr.DeferredAttrContext deferredAttrContext) { + public MethodResultInfo(Type pt, CheckContext checkContext) { attr.super(VAL, pt, checkContext); - this.deferredAttrContext = deferredAttrContext; } @Override @@ -855,12 +826,12 @@ @Override protected MethodResultInfo dup(Type newPt) { - return new MethodResultInfo(newPt, checkContext, deferredAttrContext); + return new MethodResultInfo(newPt, checkContext); } @Override protected ResultInfo dup(CheckContext newContext) { - return new MethodResultInfo(pt, newContext, deferredAttrContext); + return new MethodResultInfo(pt, newContext); } } @@ -1071,7 +1042,7 @@ Assert.check(sym.kind < AMBIGUOUS); try { Type mt = rawInstantiate(env, site, sym, null, argtypes, typeargtypes, - allowBoxing, useVarargs, types.noWarnings); + allowBoxing, useVarargs, resolveMethodCheck, types.noWarnings); if (!operator) currentResolutionContext.addApplicableCandidate(sym, mt); } catch (InapplicableMethodException ex) { @@ -1151,52 +1122,20 @@ if (m1Abstract && !m2Abstract) return m2; if (m2Abstract && !m1Abstract) return m1; // both abstract or both concrete - if (!m1Abstract && !m2Abstract) - return ambiguityError(m1, m2); - // check that both signatures have the same erasure - if (!types.isSameTypes(m1.erasure(types).getParameterTypes(), - m2.erasure(types).getParameterTypes())) - return ambiguityError(m1, m2); - // both abstract, neither overridden; merge throws clause and result type - Type mst = mostSpecificReturnType(mt1, mt2); - if (mst == null) { - // Theoretically, this can't happen, but it is possible - // due to error recovery or mixing incompatible class files - return ambiguityError(m1, m2); - } - Symbol mostSpecific = mst == mt1 ? m1 : m2; - List allThrown = chk.intersect(mt1.getThrownTypes(), mt2.getThrownTypes()); - Type newSig = types.createMethodTypeWithThrown(mostSpecific.type, allThrown); - MethodSymbol result = new MethodSymbol( - mostSpecific.flags(), - mostSpecific.name, - newSig, - mostSpecific.owner) { - @Override - public MethodSymbol implementation(TypeSymbol origin, Types types, boolean checkResult) { - if (origin == site.tsym) - return this; - else - return super.implementation(origin, types, checkResult); - } - }; - return result; + return ambiguityError(m1, m2); } if (m1SignatureMoreSpecific) return m1; if (m2SignatureMoreSpecific) return m2; return ambiguityError(m1, m2); case AMBIGUOUS: + //check if m1 is more specific than all ambiguous methods in m2 AmbiguityError e = (AmbiguityError)m2; - Symbol err1 = mostSpecific(argtypes, m1, e.sym, env, site, allowBoxing, useVarargs); - Symbol err2 = mostSpecific(argtypes, m1, e.sym2, env, site, allowBoxing, useVarargs); - if (err1 == err2) return err1; - if (err1 == e.sym && err2 == e.sym2) return m2; - if (err1 instanceof AmbiguityError && - err2 instanceof AmbiguityError && - ((AmbiguityError)err1).sym == ((AmbiguityError)err2).sym) - return ambiguityError(m1, m2); - else - return ambiguityError(err1, err2); + for (Symbol s : e.ambiguousSyms) { + if (mostSpecific(argtypes, m1, s, env, site, allowBoxing, useVarargs) != m1) { + return e.addAmbiguousSymbol(m1); + } + } + return m1; default: throw new AssertionError(); } @@ -1274,12 +1213,19 @@ } //where private boolean invocationMoreSpecific(Env env, Type site, Symbol m2, List argtypes1, boolean allowBoxing, boolean useVarargs) { - noteWarner.clear(); - Type mst = instantiate(env, site, m2, null, - types.lowerBounds(argtypes1), null, - allowBoxing, false, noteWarner); - return mst != null && - !noteWarner.hasLint(Lint.LintCategory.UNCHECKED); + MethodResolutionContext prevContext = currentResolutionContext; + try { + currentResolutionContext = new MethodResolutionContext(); + currentResolutionContext.step = allowBoxing ? BOX : BASIC; + noteWarner.clear(); + Type mst = instantiate(env, site, m2, null, + types.lowerBounds(argtypes1), null, + allowBoxing, false, resolveMethodCheck, noteWarner); + return mst != null && + !noteWarner.hasLint(Lint.LintCategory.UNCHECKED); + } finally { + currentResolutionContext = prevContext; + } } //where private Symbol adjustVarargs(Symbol to, Symbol from, boolean useVarargs) { @@ -2366,9 +2312,11 @@ try { currentResolutionContext = new MethodResolutionContext(); Name name = treeinfo.operatorName(optag); + env.info.pendingResolutionPhase = currentResolutionContext.step = BASIC; Symbol sym = findMethod(env, syms.predefClass.type, name, argtypes, null, false, false, true); if (boxingEnabled && sym.kind >= WRONG_MTHS) + env.info.pendingResolutionPhase = currentResolutionContext.step = BOX; sym = findMethod(env, syms.predefClass.type, name, argtypes, null, true, false, true); return accessMethod(sym, pos, env.enclClass.sym.type, name, @@ -2524,6 +2472,10 @@ @Override Symbol access(Env env, DiagnosticPosition pos, Symbol location, Symbol sym) { + if (sym.kind == AMBIGUOUS) { + AmbiguityError a_err = (AmbiguityError)sym; + sym = a_err.mergeAbstracts(site); + } if (sym.kind >= AMBIGUOUS) { //if nothing is found return the 'first' error sym = accessMethod(sym, pos, location, site, name, true, argtypes, typeargtypes); @@ -2579,6 +2531,10 @@ abstract JCMemberReference.ReferenceKind referenceKind(Symbol sym); Symbol access(Env env, DiagnosticPosition pos, Symbol location, Symbol sym) { + if (sym.kind == AMBIGUOUS) { + AmbiguityError a_err = (AmbiguityError)sym; + sym = a_err.mergeAbstracts(site); + } //skip error reporting return sym; } @@ -3014,9 +2970,7 @@ @Override public Symbol access(Name name, TypeSymbol location) { - if (sym.kind >= AMBIGUOUS) - return ((ResolveError)sym).access(name, location); - else if ((sym.kind & ERRONEOUS) == 0 && (sym.kind & TYP) != 0) + if ((sym.kind & ERRONEOUS) == 0 && (sym.kind & TYP) != 0) return types.createErrorType(name, location, sym.type).tsym; else return sym; @@ -3338,14 +3292,32 @@ * (either methods, constructors or operands) are ambiguous * given an actual arguments/type argument list. */ - class AmbiguityError extends InvalidSymbolError { + class AmbiguityError extends ResolveError { /** The other maximally specific symbol */ - Symbol sym2; + List ambiguousSyms = List.nil(); + + @Override + public boolean exists() { + return true; + } AmbiguityError(Symbol sym1, Symbol sym2) { - super(AMBIGUOUS, sym1, "ambiguity error"); - this.sym2 = sym2; + super(AMBIGUOUS, "ambiguity error"); + ambiguousSyms = flatten(sym2).appendList(flatten(sym1)); + } + + private List flatten(Symbol sym) { + if (sym.kind == AMBIGUOUS) { + return ((AmbiguityError)sym).ambiguousSyms; + } else { + return List.of(sym); + } + } + + AmbiguityError addAmbiguousSymbol(Symbol s) { + ambiguousSyms = ambiguousSyms.prepend(s); + return this; } @Override @@ -3356,24 +3328,60 @@ Name name, List argtypes, List typeargtypes) { - AmbiguityError pair = this; - while (true) { - if (pair.sym.kind == AMBIGUOUS) - pair = (AmbiguityError)pair.sym; - else if (pair.sym2.kind == AMBIGUOUS) - pair = (AmbiguityError)pair.sym2; - else break; - } - Name sname = pair.sym.name; - if (sname == names.init) sname = pair.sym.owner.name; + List diagSyms = ambiguousSyms.reverse(); + Symbol s1 = diagSyms.head; + Symbol s2 = diagSyms.tail.head; + Name sname = s1.name; + if (sname == names.init) sname = s1.owner.name; return diags.create(dkind, log.currentSource(), pos, "ref.ambiguous", sname, - kindName(pair.sym), - pair.sym, - pair.sym.location(site, types), - kindName(pair.sym2), - pair.sym2, - pair.sym2.location(site, types)); + kindName(s1), + s1, + s1.location(site, types), + kindName(s2), + s2, + s2.location(site, types)); + } + + /** + * If multiple applicable methods are found during overload and none of them + * is more specific than the others, attempt to merge their signatures. + */ + Symbol mergeAbstracts(Type site) { + Symbol fst = ambiguousSyms.last(); + Symbol res = fst; + for (Symbol s : ambiguousSyms.reverse()) { + Type mt1 = types.memberType(site, res); + Type mt2 = types.memberType(site, s); + if ((s.flags() & ABSTRACT) == 0 || + !types.overrideEquivalent(mt1, mt2) || + !types.isSameTypes(fst.erasure(types).getParameterTypes(), + s.erasure(types).getParameterTypes())) { + //ambiguity cannot be resolved + return this; + } else { + Type mst = mostSpecificReturnType(mt1, mt2); + if (mst == null) { + // Theoretically, this can't happen, but it is possible + // due to error recovery or mixing incompatible class files + return this; + } + Symbol mostSpecific = mst == mt1 ? res : s; + List allThrown = chk.intersect(mt1.getThrownTypes(), mt2.getThrownTypes()); + Type newSig = types.createMethodTypeWithThrown(mostSpecific.type, allThrown); + res = new MethodSymbol( + mostSpecific.flags(), + mostSpecific.name, + newSig, + mostSpecific.owner); + } + } + return res; + } + + @Override + protected Symbol access(Name name, TypeSymbol location) { + return ambiguousSyms.last(); } } @@ -3450,6 +3458,10 @@ candidates = candidates.append(c); } + DeferredAttrContext deferredAttrContext(Symbol sym, InferenceContext inferenceContext) { + return deferredAttr.new DeferredAttrContext(attrMode, sym, step, inferenceContext); + } + /** * This class represents an overload resolution candidate. There are two * kinds of candidates: applicable methods and inapplicable methods; diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Thu Jan 10 15:53:02 2013 -0800 @@ -217,6 +217,13 @@ */ boolean haveParameterNameIndices; + /** Set this to false every time we start reading a method + * and are saving parameter names. Set it to true when we see + * MethodParameters, if it's set when we see a LocalVariableTable, + * then we ignore the parameter names from the LVT. + */ + boolean sawMethodParameters; + /** * The set of attribute names for which warnings have been generated for the current class */ @@ -984,7 +991,7 @@ new AttributeReader(names.LocalVariableTable, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) { protected void read(Symbol sym, int attrLen) { int newbp = bp + attrLen; - if (saveParameterNames) { + if (saveParameterNames && !sawMethodParameters) { // Pick up parameter names from the variable table. // Parameter names are not explicitly identified as such, // but all parameter name entries in the LocalVariableTable @@ -1017,6 +1024,25 @@ } }, + new AttributeReader(names.MethodParameters, V52, MEMBER_ATTRIBUTE) { + protected void read(Symbol sym, int attrlen) { + int newbp = bp + attrlen; + if (saveParameterNames) { + sawMethodParameters = true; + int numEntries = nextByte(); + parameterNameIndices = new int[numEntries]; + haveParameterNameIndices = true; + for (int i = 0; i < numEntries; i++) { + int nameIndex = nextChar(); + int flags = nextInt(); + parameterNameIndices[i] = nameIndex; + } + } + bp = newbp; + } + }, + + new AttributeReader(names.SourceFile, V45_3, CLASS_ATTRIBUTE) { protected void read(Symbol sym, int attrLen) { ClassSymbol c = (ClassSymbol) sym; @@ -1826,6 +1852,7 @@ } else Arrays.fill(parameterNameIndices, 0); haveParameterNameIndices = false; + sawMethodParameters = false; } /** @@ -1845,12 +1872,16 @@ // if no names were found in the class file, there's nothing more to do if (!haveParameterNameIndices) return; - - int firstParam = ((sym.flags() & STATIC) == 0) ? 1 : 0; - // the code in readMethod may have skipped the first parameter when - // setting up the MethodType. If so, we make a corresponding allowance - // here for the position of the first parameter. Note that this - // assumes the skipped parameter has a width of 1 -- i.e. it is not + // If we get parameter names from MethodParameters, then we + // don't need to skip. + int firstParam = 0; + if (!sawMethodParameters) { + firstParam = ((sym.flags() & STATIC) == 0) ? 1 : 0; + // the code in readMethod may have skipped the first + // parameter when setting up the MethodType. If so, we + // make a corresponding allowance here for the position of + // the first parameter. Note that this assumes the + // skipped parameter has a width of 1 -- i.e. it is not // a double width type (long or double.) if (sym.name == names.init && currentOwner.hasOuterInstance()) { // Sometimes anonymous classes don't have an outer @@ -1861,17 +1892,20 @@ } if (sym.type != jvmType) { - // reading the method attributes has caused the symbol's type to - // be changed. (i.e. the Signature attribute.) This may happen if - // there are hidden (synthetic) parameters in the descriptor, but - // not in the Signature. The position of these hidden parameters - // is unspecified; for now, assume they are at the beginning, and - // so skip over them. The primary case for this is two hidden - // parameters passed into Enum constructors. + // reading the method attributes has caused the + // symbol's type to be changed. (i.e. the Signature + // attribute.) This may happen if there are hidden + // (synthetic) parameters in the descriptor, but not + // in the Signature. The position of these hidden + // parameters is unspecified; for now, assume they are + // at the beginning, and so skip over them. The + // primary case for this is two hidden parameters + // passed into Enum constructors. int skip = Code.width(jvmType.getParameterTypes()) - Code.width(sym.type.getParameterTypes()); firstParam += skip; } + } List paramNames = List.nil(); int index = firstParam; for (Type t: sym.type.getParameterTypes()) { diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Thu Jan 10 15:53:02 2013 -0800 @@ -725,6 +725,28 @@ return acount; } + /** + * Write method parameter names attribute. + */ + int writeMethodParametersAttr(MethodSymbol m) { + if (m.params != null && 0 != m.params.length()) { + int attrIndex = writeAttr(names.MethodParameters); + databuf.appendByte(m.params.length()); + for (VarSymbol s : m.params) { + // TODO: expand to cover synthesized, once we figure out + // how to represent that. + final int flags = (int) s.flags() & (FINAL | SYNTHETIC); + // output parameter info + databuf.appendChar(pool.put(s.name)); + databuf.appendInt(flags); + } + endAttr(attrIndex); + return 1; + } else + return 0; + } + + /** Write method parameter annotations; * return number of attributes written. */ @@ -1034,6 +1056,8 @@ endAttr(alenIdx); acount++; } + if (options.isSet(PARAMETERS)) + acount += writeMethodParametersAttr(m); acount += writeMemberAttrs(m); acount += writeParameterAttrs(m); endAttrs(acountIdx, acount); diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/javac/main/Option.java --- a/langtools/src/share/classes/com/sun/tools/javac/main/Option.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/main/Option.java Thu Jan 10 15:53:02 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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,6 +176,8 @@ PROCESSORPATH("-processorpath", "opt.arg.path", "opt.processorpath", STANDARD, FILEMANAGER), + PARAMETERS("-parameters","opt.parameters", STANDARD, BASIC), + D("-d", "opt.arg.directory", "opt.d", STANDARD, FILEMANAGER), S("-s", "opt.arg.directory", "opt.sourceDest", STANDARD, FILEMANAGER), @@ -309,7 +311,7 @@ // This option exists only for the purpose of documenting itself. // It's actually implemented by the launcher. - J("-J", "opt.arg.flag", "opt.J", STANDARD, INFO) { + J("-J", "opt.arg.flag", "opt.J", STANDARD, INFO, true) { @Override public boolean process(OptionHelper helper, String option) { throw new AssertionError @@ -414,7 +416,7 @@ // This option exists only for the purpose of documenting itself. // It's actually implemented by the CommandLine class. - AT("@", "opt.arg.file", "opt.AT", STANDARD, INFO) { + AT("@", "opt.arg.file", "opt.AT", STANDARD, INFO, true) { @Override public boolean process(OptionHelper helper, String option) { throw new AssertionError("the @ flag should be caught by CommandLine."); diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties --- a/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties Thu Jan 10 15:53:02 2013 -0800 @@ -55,6 +55,8 @@ Specify where to find annotation processors javac.opt.processor=\ Names of the annotation processors to run; bypasses default discovery process +javac.opt.parameters=\ + Generate metadata for reflection on method parameters javac.opt.proc.none.only=\ Control whether annotation processing and/or compilation is done. javac.opt.d=\ diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java --- a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java Thu Jan 10 15:53:02 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 @@ -154,12 +154,13 @@ } //we need to (i) replace all line terminators with a space and (ii) remove //occurrences of 'missing' in the Pretty output (generated when types are missing) - String res = s.toString().replaceAll("\\s+", " ").replaceAll("/\\*missing\\*/", ""); + String res = s.toString().trim().replaceAll("\\s+", " ").replaceAll("/\\*missing\\*/", ""); if (res.length() < maxLength) { return res; } else { - int split = (maxLength - trimSequence.length()) * 2 / 3; - return res.substring(0, split) + trimSequence + res.substring(split); + int head = (maxLength - trimSequence.length()) * 2 / 3; + int tail = maxLength - trimSequence.length() - head; + return res.substring(0, head) + trimSequence + res.substring(res.length() - tail); } } diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/javac/util/Names.java --- a/langtools/src/share/classes/com/sun/tools/javac/util/Names.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/util/Names.java Thu Jan 10 15:53:02 2013 -0800 @@ -132,6 +132,7 @@ public final Name LineNumberTable; public final Name LocalVariableTable; public final Name LocalVariableTypeTable; + public final Name MethodParameters; public final Name RuntimeInvisibleAnnotations; public final Name RuntimeInvisibleParameterAnnotations; public final Name RuntimeInvisibleTypeAnnotations; @@ -265,6 +266,7 @@ LineNumberTable = fromString("LineNumberTable"); LocalVariableTable = fromString("LocalVariableTable"); LocalVariableTypeTable = fromString("LocalVariableTypeTable"); + MethodParameters = fromString("MethodParameters"); RuntimeInvisibleAnnotations = fromString("RuntimeInvisibleAnnotations"); RuntimeInvisibleParameterAnnotations = fromString("RuntimeInvisibleParameterAnnotations"); RuntimeInvisibleTypeAnnotations = fromString("RuntimeInvisibleTypeAnnotations"); diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/javadoc/AnnotationDescImpl.java --- a/langtools/src/share/classes/com/sun/tools/javadoc/AnnotationDescImpl.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javadoc/AnnotationDescImpl.java Thu Jan 10 15:53:02 2013 -0800 @@ -89,6 +89,15 @@ } /** + * Check for the synthesized bit on the annotation. + * + * @return true if the annotation is synthesized. + */ + public boolean isSynthesized() { + return annotation.isSynthesized(); + } + + /** * Returns a string representation of this annotation. * String is of one of the forms: * @com.example.foo(name1=val1, name2=val2) diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/javadoc/Messager.java --- a/langtools/src/share/classes/com/sun/tools/javadoc/Messager.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javadoc/Messager.java Thu Jan 10 15:53:02 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 @@ -133,16 +133,6 @@ this.programName = programName; } - @Override - protected int getDefaultMaxErrors() { - return Integer.MAX_VALUE; - } - - @Override - protected int getDefaultMaxWarnings() { - return Integer.MAX_VALUE; - } - public void setLocale(Locale locale) { this.locale = locale; } diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/javadoc/MethodDocImpl.java --- a/langtools/src/share/classes/com/sun/tools/javadoc/MethodDocImpl.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javadoc/MethodDocImpl.java Thu Jan 10 15:53:02 2013 -0800 @@ -86,16 +86,7 @@ * Return true if this method is abstract */ public boolean isAbstract() { - //### This is dubious, but old 'javadoc' apparently does it. - //### I regard this as a bug and an obstacle to treating the - //### doclet API as a proper compile-time reflection facility. - //### (maddox 09/26/2000) - if (containingClass().isInterface()) { - //### Don't force creation of ClassDocImpl for super here. - // Abstract modifier is implicit. Strip/canonicalize it. - return false; - } - return Modifier.isAbstract(getModifiers()); + return (Modifier.isAbstract(getModifiers()) && !isDefault()); } /** diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/javap/AttributeWriter.java --- a/langtools/src/share/classes/com/sun/tools/javap/AttributeWriter.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javap/AttributeWriter.java Thu Jan 10 15:53:02 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2012, 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,6 +46,7 @@ import com.sun.tools.classfile.LineNumberTable_attribute; import com.sun.tools.classfile.LocalVariableTable_attribute; import com.sun.tools.classfile.LocalVariableTypeTable_attribute; +import com.sun.tools.classfile.MethodParameters_attribute; import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute; import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute; import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute; @@ -386,6 +387,28 @@ return null; } + private static final String format = "%-31s%s"; + + public Void visitMethodParameters(MethodParameters_attribute attr, + Void ignore) { + + final String header = String.format(format, "Name", "Flags"); + println("MethodParameters:"); + indent(+1); + println(header); + for (MethodParameters_attribute.Entry entry : + attr.method_parameter_table) { + String flagstr = + (0 != (entry.flags & ACC_FINAL) ? " final" : "") + + (0 != (entry.flags & ACC_SYNTHETIC) ? " synthetic" : ""); + println(String.format(format, + constantWriter.stringValue(entry.name_index), + flagstr)); + } + indent(-1); + return null; + } + public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, Void ignore) { println("RuntimeVisibleAnnotations:"); indent(+1); diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java --- a/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java Thu Jan 10 15:53:02 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, 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 @@ -206,7 +206,7 @@ println("minor version: " + cf.minor_version); println("major version: " + cf.major_version); if (!options.compat) - writeList("flags: ", flags.getClassFlags(), NEWLINE); + writeList("flags: ", flags.getClassFlags(), "\n"); indent(-1); constantWriter.writeConstantPool(); } else { @@ -383,7 +383,7 @@ println("Signature: " + getValue(f.descriptor)); if (options.verbose && !options.compat) - writeList("flags: ", flags.getFieldFlags(), NEWLINE); + writeList("flags: ", flags.getFieldFlags(), "\n"); if (options.showAllAttrs) { for (Attribute attr: f.attributes) @@ -480,7 +480,7 @@ } if (options.verbose && !options.compat) { - writeList("flags: ", flags.getMethodFlags(), NEWLINE); + writeList("flags: ", flags.getMethodFlags(), "\n"); } Code_attribute code = null; @@ -749,5 +749,4 @@ private int size; private ConstantPool constant_pool; private Method method; - private static final String NEWLINE = System.getProperty("line.separator", "\n"); } diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/jdeps/Archive.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/com/sun/tools/jdeps/Archive.java Thu Jan 10 15:53:02 2013 -0800 @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2012, 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.jdeps; + +import com.sun.tools.classfile.Dependency; +import com.sun.tools.classfile.Dependency.Location; +import java.io.File; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; + +/** + * Represents the source of the class files. + */ +public class Archive { + private static Map archiveForClass = new HashMap(); + public static Archive find(Location loc) { + return archiveForClass.get(loc.getName()); + } + + private final File file; + private final String filename; + private final DependencyRecorder recorder; + private final ClassFileReader reader; + public Archive(String name) { + this.file = null; + this.filename = name; + this.recorder = new DependencyRecorder(); + this.reader = null; + } + + public Archive(File f, ClassFileReader reader) { + this.file = f; + this.filename = f.getName(); + this.recorder = new DependencyRecorder(); + this.reader = reader; + } + + public ClassFileReader reader() { + return reader; + } + + public String getFileName() { + return filename; + } + + public void addClass(String classFileName) { + Archive a = archiveForClass.get(classFileName); + assert(a == null || a == this); // ## issue warning? + if (!archiveForClass.containsKey(classFileName)) { + archiveForClass.put(classFileName, this); + } + } + + public void addDependency(Dependency d) { + recorder.addDependency(d); + } + + /** + * Returns a sorted map of a class to its dependencies. + */ + public SortedMap> getDependencies() { + DependencyRecorder.Filter filter = new DependencyRecorder.Filter() { + public boolean accept(Location origin, Location target) { + return (archiveForClass.get(origin.getName()) != + archiveForClass.get(target.getName())); + }}; + + SortedMap> result = + new TreeMap>(locationComparator); + for (Map.Entry> e : recorder.dependencies().entrySet()) { + Location o = e.getKey(); + for (Location t : e.getValue()) { + if (filter.accept(o, t)) { + SortedSet odeps = result.get(o); + if (odeps == null) { + odeps = new TreeSet(locationComparator); + result.put(o, odeps); + } + odeps.add(t); + } + } + } + return result; + } + + /** + * Returns the set of archives this archive requires. + */ + public Set getRequiredArchives() { + SortedSet deps = new TreeSet(new Comparator() { + public int compare(Archive a1, Archive a2) { + return a1.toString().compareTo(a2.toString()); + } + }); + + for (Map.Entry> e : recorder.dependencies().entrySet()) { + Location o = e.getKey(); + Archive origin = Archive.find(o); + for (Location t : e.getValue()) { + Archive target = Archive.find(t); + assert(origin != null && target != null); + if (origin != target) { + if (!deps.contains(target)) { + deps.add(target); + } + } + } + } + return deps; + } + + public String toString() { + return file != null ? file.getPath() : filename; + } + + private static class DependencyRecorder { + static interface Filter { + boolean accept(Location origin, Location target); + } + + public void addDependency(Dependency d) { + Set odeps = map.get(d.getOrigin()); + if (odeps == null) { + odeps = new HashSet(); + map.put(d.getOrigin(), odeps); + } + odeps.add(d.getTarget()); + } + + public Map> dependencies() { + return map; + } + + private final Map> map = + new HashMap>(); + } + + private static Comparator locationComparator = + new Comparator() { + public int compare(Location o1, Location o2) { + return o1.toString().compareTo(o2.toString()); + } + }; +} diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/jdeps/ClassFileReader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/com/sun/tools/jdeps/ClassFileReader.java Thu Jan 10 15:53:02 2013 -0800 @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2012, 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.jdeps; + +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.ConstantPoolException; +import com.sun.tools.classfile.Dependencies.ClassFileError; +import java.io.*; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.*; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + * ClassFileReader reads ClassFile(s) of a given path that can be + * a .class file, a directory, or a JAR file. + */ +public class ClassFileReader { + /** + * Returns a ClassFileReader instance of a given path. + */ + public static ClassFileReader newInstance(File path) throws IOException { + if (!path.exists()) { + throw new FileNotFoundException(path.getAbsolutePath()); + } + + if (path.isDirectory()) { + return new DirectoryReader(path.toPath()); + } else if (path.getName().endsWith(".jar")) { + return new JarFileReader(path.toPath()); + } else { + return new ClassFileReader(path.toPath()); + } + } + + protected final Path path; + protected final String baseFileName; + private ClassFileReader(Path path) { + this.path = path; + this.baseFileName = path.getFileName() != null + ? path.getFileName().toString() + : path.toString(); + } + + public String getFileName() { + return baseFileName; + } + + /** + * Returns the ClassFile matching the given binary name + * or a fully-qualified class name. + */ + public ClassFile getClassFile(String name) throws IOException { + if (name.indexOf('.') > 0) { + int i = name.lastIndexOf('.'); + String pathname = name.replace('.', File.separatorChar) + ".class"; + if (baseFileName.equals(pathname) || + baseFileName.equals(pathname.substring(0, i) + "$" + + pathname.substring(i+1, pathname.length()))) { + return readClassFile(path); + } + } else { + if (baseFileName.equals(name.replace('/', File.separatorChar) + ".class")) { + return readClassFile(path); + } + } + return null; + } + + public Iterable getClassFiles() throws IOException { + return new Iterable() { + public Iterator iterator() { + return new FileIterator(); + } + }; + } + + protected ClassFile readClassFile(Path p) throws IOException { + InputStream is = null; + try { + is = Files.newInputStream(p); + return ClassFile.read(is); + } catch (ConstantPoolException e) { + throw new ClassFileError(e); + } finally { + if (is != null) { + is.close(); + } + } + } + + class FileIterator implements Iterator { + int count; + FileIterator() { + this.count = 0; + } + public boolean hasNext() { + return count == 0 && baseFileName.endsWith(".class"); + } + + public ClassFile next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + try { + ClassFile cf = readClassFile(path); + count++; + return cf; + } catch (IOException e) { + throw new ClassFileError(e); + } + } + + public void remove() { + throw new UnsupportedOperationException("Not supported yet."); + } + } + + public String toString() { + return path.toString(); + } + + private static class DirectoryReader extends ClassFileReader { + DirectoryReader(Path path) throws IOException { + super(path); + } + + public ClassFile getClassFile(String name) throws IOException { + if (name.indexOf('.') > 0) { + int i = name.lastIndexOf('.'); + String pathname = name.replace('.', File.separatorChar) + ".class"; + Path p = path.resolve(pathname); + if (!p.toFile().exists()) { + p = path.resolve(pathname.substring(0, i) + "$" + + pathname.substring(i+1, pathname.length())); + } + if (p.toFile().exists()) { + return readClassFile(p); + } + } else { + Path p = path.resolve(name + ".class"); + if (p.toFile().exists()) { + return readClassFile(p); + } + } + return null; + } + + public Iterable getClassFiles() throws IOException { + final Iterator iter = new DirectoryIterator(); + return new Iterable() { + public Iterator iterator() { + return iter; + } + }; + } + + private List walkTree(Path dir) throws IOException { + final List files = new ArrayList(); + Files.walkFileTree(dir, new SimpleFileVisitor() { + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + if (file.toFile().getName().endsWith(".class")) { + files.add(file); + } + return FileVisitResult.CONTINUE; + } + }); + return files; + } + + class DirectoryIterator implements Iterator { + private List entries; + private int index = 0; + DirectoryIterator() throws IOException { + entries = walkTree(path); + index = 0; + } + + public boolean hasNext() { + return index != entries.size(); + } + + public ClassFile next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + Path path = entries.get(index++); + try { + return readClassFile(path); + } catch (IOException e) { + throw new ClassFileError(e); + } + } + + public void remove() { + throw new UnsupportedOperationException("Not supported yet."); + } + } + } + + private static class JarFileReader extends ClassFileReader { + final JarFile jarfile; + JarFileReader(Path path) throws IOException { + super(path); + this.jarfile = new JarFile(path.toFile()); + } + + public ClassFile getClassFile(String name) throws IOException { + if (name.indexOf('.') > 0) { + int i = name.lastIndexOf('.'); + String entryName = name.replace('.', '/') + ".class"; + JarEntry e = jarfile.getJarEntry(entryName); + if (e == null) { + e = jarfile.getJarEntry(entryName.substring(0, i) + "$" + + entryName.substring(i + 1, entryName.length())); + } + if (e != null) { + return readClassFile(e); + } + } else { + JarEntry e = jarfile.getJarEntry(name + ".class"); + if (e != null) { + return readClassFile(e); + } + } + return null; + } + + private ClassFile readClassFile(JarEntry e) throws IOException { + InputStream is = null; + try { + is = jarfile.getInputStream(e); + return ClassFile.read(is); + } catch (ConstantPoolException ex) { + throw new ClassFileError(ex); + } finally { + if (is != null) + is.close(); + } + } + + public Iterable getClassFiles() throws IOException { + final Iterator iter = new JarFileIterator(); + return new Iterable() { + public Iterator iterator() { + return iter; + } + }; + } + + class JarFileIterator implements Iterator { + private Enumeration entries; + private JarEntry nextEntry; + JarFileIterator() { + this.entries = jarfile.entries(); + while (entries.hasMoreElements()) { + JarEntry e = entries.nextElement(); + String name = e.getName(); + if (name.endsWith(".class")) { + this.nextEntry = e; + break; + } + } + } + + public boolean hasNext() { + return nextEntry != null; + } + + public ClassFile next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + ClassFile cf; + try { + cf = readClassFile(nextEntry); + } catch (IOException ex) { + throw new ClassFileError(ex); + } + JarEntry entry = nextEntry; + nextEntry = null; + while (entries.hasMoreElements()) { + JarEntry e = entries.nextElement(); + String name = e.getName(); + if (name.endsWith(".class")) { + nextEntry = e; + break; + } + } + return cf; + } + + public void remove() { + throw new UnsupportedOperationException("Not supported yet."); + } + } + } +} diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/jdeps/JdepsTask.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/com/sun/tools/jdeps/JdepsTask.java Thu Jan 10 15:53:02 2013 -0800 @@ -0,0 +1,650 @@ +/* + * Copyright (c) 2012, 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.jdeps; + +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.ConstantPoolException; +import com.sun.tools.classfile.Dependencies; +import com.sun.tools.classfile.Dependencies.ClassFileError; +import com.sun.tools.classfile.Dependency; +import com.sun.tools.classfile.Dependency.Location; +import java.io.*; +import java.text.MessageFormat; +import java.util.*; +import java.util.regex.Pattern; + +/** + * Implementation for the jdeps tool for static class dependency analysis. + */ +class JdepsTask { + class BadArgs extends Exception { + static final long serialVersionUID = 8765093759964640721L; + BadArgs(String key, Object... args) { + super(JdepsTask.this.getMessage(key, args)); + this.key = key; + this.args = args; + } + + BadArgs showUsage(boolean b) { + showUsage = b; + return this; + } + final String key; + final Object[] args; + boolean showUsage; + } + + static abstract class Option { + Option(boolean hasArg, String... aliases) { + this.hasArg = hasArg; + this.aliases = aliases; + } + + boolean isHidden() { + return false; + } + + boolean matches(String opt) { + for (String a : aliases) { + if (a.equals(opt)) { + return true; + } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) { + return true; + } + } + return false; + } + + boolean ignoreRest() { + return false; + } + + abstract void process(JdepsTask task, String opt, String arg) throws BadArgs; + final boolean hasArg; + final String[] aliases; + } + + static abstract class HiddenOption extends Option { + HiddenOption(boolean hasArg, String... aliases) { + super(hasArg, aliases); + } + + boolean isHidden() { + return true; + } + } + + static Option[] recognizedOptions = { + new Option(false, "-h", "-?", "--help") { + void process(JdepsTask task, String opt, String arg) { + task.options.help = true; + } + }, + new Option(false, "-s", "--summary") { + void process(JdepsTask task, String opt, String arg) { + task.options.showSummary = true; + task.options.verbose = Options.Verbose.SUMMARY; + } + }, + new Option(false, "-v", "--verbose") { + void process(JdepsTask task, String opt, String arg) { + task.options.verbose = Options.Verbose.VERBOSE; + } + }, + new Option(true, "-V", "--verbose-level") { + void process(JdepsTask task, String opt, String arg) throws BadArgs { + switch (arg) { + case "package": + task.options.verbose = Options.Verbose.PACKAGE; + break; + case "class": + task.options.verbose = Options.Verbose.CLASS; + break; + default: + throw task.new BadArgs("err.invalid.arg.for.option", opt); + } + } + }, + new Option(true, "-c", "--classpath") { + void process(JdepsTask task, String opt, String arg) { + task.options.classpath = arg; + } + }, + new Option(true, "-p", "--package") { + void process(JdepsTask task, String opt, String arg) { + task.options.packageNames.add(arg); + } + }, + new Option(true, "-e", "--regex") { + void process(JdepsTask task, String opt, String arg) { + task.options.regex = arg; + } + }, + new Option(false, "-P", "--profile") { + void process(JdepsTask task, String opt, String arg) { + task.options.showProfile = true; + } + }, + new Option(false, "-R", "--recursive") { + void process(JdepsTask task, String opt, String arg) { + task.options.depth = 0; + } + }, + new HiddenOption(true, "-d", "--depth") { + void process(JdepsTask task, String opt, String arg) throws BadArgs { + try { + task.options.depth = Integer.parseInt(arg); + } catch (NumberFormatException e) { + throw task.new BadArgs("err.invalid.arg.for.option", opt); + } + } + }, + new Option(false, "--version") { + void process(JdepsTask task, String opt, String arg) { + task.options.version = true; + } + }, + new HiddenOption(false, "--fullversion") { + void process(JdepsTask task, String opt, String arg) { + task.options.fullVersion = true; + } + }, + + }; + + private static final String PROGNAME = "jdeps"; + private final Options options = new Options(); + private final List classes = new ArrayList(); + + private PrintWriter log; + void setLog(PrintWriter out) { + log = out; + } + + /** + * Result codes. + */ + static final int EXIT_OK = 0, // Completed with no errors. + EXIT_ERROR = 1, // Completed but reported errors. + EXIT_CMDERR = 2, // Bad command-line arguments + EXIT_SYSERR = 3, // System error or resource exhaustion. + EXIT_ABNORMAL = 4;// terminated abnormally + + int run(String[] args) { + if (log == null) { + log = new PrintWriter(System.out); + } + try { + handleOptions(args); + if (options.help) { + showHelp(); + } + if (options.version || options.fullVersion) { + showVersion(options.fullVersion); + } + if (classes.isEmpty() && !options.wildcard) { + if (options.help || options.version || options.fullVersion) { + return EXIT_OK; + } else { + showHelp(); + return EXIT_CMDERR; + } + } + if (options.regex != null && options.packageNames.size() > 0) { + showHelp(); + return EXIT_CMDERR; + } + if (options.showSummary && options.verbose != Options.Verbose.SUMMARY) { + showHelp(); + return EXIT_CMDERR; + } + boolean ok = run(); + return ok ? EXIT_OK : EXIT_ERROR; + } catch (BadArgs e) { + reportError(e.key, e.args); + if (e.showUsage) { + log.println(getMessage("main.usage.summary", PROGNAME)); + } + return EXIT_CMDERR; + } catch (IOException e) { + return EXIT_ABNORMAL; + } finally { + log.flush(); + } + } + + private final List sourceLocations = new ArrayList(); + private final Archive NOT_FOUND = new Archive(getMessage("artifact.not.found")); + private boolean run() throws IOException { + findDependencies(); + switch (options.verbose) { + case VERBOSE: + case CLASS: + printClassDeps(log); + break; + case PACKAGE: + printPackageDeps(log); + break; + case SUMMARY: + for (Archive origin : sourceLocations) { + for (Archive target : origin.getRequiredArchives()) { + log.format("%-30s -> %s%n", origin, target); + } + } + break; + default: + throw new InternalError("Should not reach here"); + } + return true; + } + + private boolean isValidClassName(String name) { + if (!Character.isJavaIdentifierStart(name.charAt(0))) { + return false; + } + for (int i=1; i < name.length(); i++) { + char c = name.charAt(i); + if (c != '.' && !Character.isJavaIdentifierPart(c)) { + return false; + } + } + return true; + } + + private void findDependencies() throws IOException { + Dependency.Finder finder = Dependencies.getClassDependencyFinder(); + Dependency.Filter filter; + if (options.regex != null) { + filter = Dependencies.getRegexFilter(Pattern.compile(options.regex)); + } else if (options.packageNames.size() > 0) { + filter = Dependencies.getPackageFilter(options.packageNames, false); + } else { + filter = new Dependency.Filter() { + public boolean accepts(Dependency dependency) { + return !dependency.getOrigin().equals(dependency.getTarget()); + } + }; + } + + List archives = new ArrayList(); + Deque roots = new LinkedList(); + for (String s : classes) { + File f = new File(s); + if (f.exists()) { + archives.add(new Archive(f, ClassFileReader.newInstance(f))); + } else { + if (isValidClassName(s)) { + roots.add(s); + } else { + warning("warn.invalid.arg", s); + } + } + } + + List classpaths = new ArrayList(); // for class file lookup + if (options.wildcard) { + // include all archives from classpath to the initial list + archives.addAll(getClassPathArchives(options.classpath)); + } else { + classpaths.addAll(getClassPathArchives(options.classpath)); + } + classpaths.addAll(PlatformClassPath.getArchives()); + + // add all archives to the source locations for reporting + sourceLocations.addAll(archives); + sourceLocations.addAll(classpaths); + + // Work queue of names of classfiles to be searched. + // Entries will be unique, and for classes that do not yet have + // dependencies in the results map. + Deque deque = new LinkedList(); + Set doneClasses = new HashSet(); + + // get the immediate dependencies of the input files + for (Archive a : archives) { + for (ClassFile cf : a.reader().getClassFiles()) { + String classFileName; + try { + classFileName = cf.getName(); + } catch (ConstantPoolException e) { + throw new ClassFileError(e); + } + a.addClass(classFileName); + if (!doneClasses.contains(classFileName)) { + doneClasses.add(classFileName); + } + for (Dependency d : finder.findDependencies(cf)) { + if (filter.accepts(d)) { + String cn = d.getTarget().getName(); + if (!doneClasses.contains(cn) && !deque.contains(cn)) { + deque.add(cn); + } + a.addDependency(d); + } + } + } + } + + // add Archive for looking up classes from the classpath + // for transitive dependency analysis + Deque unresolved = roots; + int depth = options.depth > 0 ? options.depth : Integer.MAX_VALUE; + do { + String name; + while ((name = unresolved.poll()) != null) { + if (doneClasses.contains(name)) { + continue; + } + ClassFile cf = null; + for (Archive a : classpaths) { + cf = a.reader().getClassFile(name); + if (cf != null) { + String classFileName; + try { + classFileName = cf.getName(); + } catch (ConstantPoolException e) { + throw new ClassFileError(e); + } + a.addClass(classFileName); + if (!doneClasses.contains(classFileName)) { + // if name is a fully-qualified class name specified + // from command-line, this class might already be parsed + doneClasses.add(classFileName); + if (depth > 0) { + for (Dependency d : finder.findDependencies(cf)) { + if (filter.accepts(d)) { + String cn = d.getTarget().getName(); + if (!doneClasses.contains(cn) && !deque.contains(cn)) { + deque.add(cn); + } + a.addDependency(d); + } + } + } + } + break; + } + } + if (cf == null) { + NOT_FOUND.addClass(name); + } + } + unresolved = deque; + deque = new LinkedList(); + } while (!unresolved.isEmpty() && depth-- > 0); + } + + private void printPackageDeps(PrintWriter out) { + for (Archive source : sourceLocations) { + SortedMap> deps = source.getDependencies(); + if (deps.isEmpty()) + continue; + + for (Archive target : source.getRequiredArchives()) { + out.format("%s -> %s%n", source, target); + } + + Map pkgs = new TreeMap(); + SortedMap targets = new TreeMap(); + String pkg = ""; + for (Map.Entry> e : deps.entrySet()) { + String cn = e.getKey().getClassName(); + String p = packageOf(e.getKey()); + Archive origin = Archive.find(e.getKey()); + assert origin != null; + if (!pkgs.containsKey(p)) { + pkgs.put(p, origin); + } else if (pkgs.get(p) != origin) { + warning("warn.split.package", p, origin, pkgs.get(p)); + } + + if (!p.equals(pkg)) { + printTargets(out, targets); + pkg = p; + targets.clear(); + out.format(" %s (%s)%n", p, origin.getFileName()); + } + + for (Location t : e.getValue()) { + p = packageOf(t); + Archive target = Archive.find(t); + if (!targets.containsKey(p)) { + targets.put(p, target); + } + } + } + printTargets(out, targets); + out.println(); + } + } + + private void printTargets(PrintWriter out, Map targets) { + for (Map.Entry t : targets.entrySet()) { + String pn = t.getKey(); + out.format(" -> %-40s %s%n", pn, getPackageInfo(pn, t.getValue())); + } + } + + private String getPackageInfo(String pn, Archive source) { + if (PlatformClassPath.contains(source)) { + String name = PlatformClassPath.getProfileName(pn); + if (name.isEmpty()) { + return "JDK internal API (" + source.getFileName() + ")"; + } + return options.showProfile ? name : ""; + } + return source.getFileName(); + } + + private static String packageOf(Location loc) { + String pkg = loc.getPackageName(); + return pkg.isEmpty() ? "" : pkg; + } + + private void printClassDeps(PrintWriter out) { + for (Archive source : sourceLocations) { + SortedMap> deps = source.getDependencies(); + if (deps.isEmpty()) + continue; + + for (Archive target : source.getRequiredArchives()) { + out.format("%s -> %s%n", source, target); + } + out.format("%s%n", source); + for (Map.Entry> e : deps.entrySet()) { + String cn = e.getKey().getClassName(); + Archive origin = Archive.find(e.getKey()); + out.format(" %s (%s)%n", cn, origin.getFileName()); + for (Location t : e.getValue()) { + cn = t.getClassName(); + Archive target = Archive.find(t); + out.format(" -> %-60s %s%n", cn, getPackageInfo(t.getPackageName(), target)); + } + } + out.println(); + } + } + public void handleOptions(String[] args) throws BadArgs { + // process options + for (int i=0; i < args.length; i++) { + if (args[i].charAt(0) == '-') { + String name = args[i]; + Option option = getOption(name); + String param = null; + if (option.hasArg) { + if (name.startsWith("--") && name.indexOf('=') > 0) { + param = name.substring(name.indexOf('=') + 1, name.length()); + } else if (i + 1 < args.length) { + param = args[++i]; + } + if (param == null || param.isEmpty() || param.charAt(0) == '-') { + throw new BadArgs("err.missing.arg", name).showUsage(true); + } + } + option.process(this, name, param); + if (option.ignoreRest()) { + i = args.length; + } + } else { + // process rest of the input arguments + for (; i < args.length; i++) { + String name = args[i]; + if (name.charAt(0) == '-') { + throw new BadArgs("err.option.after.class", name).showUsage(true); + } + if (name.equals("*") || name.equals("\"*\"")) { + options.wildcard = true; + } else { + classes.add(name); + } + } + } + } + } + + private Option getOption(String name) throws BadArgs { + for (Option o : recognizedOptions) { + if (o.matches(name)) { + return o; + } + } + throw new BadArgs("err.unknown.option", name).showUsage(true); + } + + private void reportError(String key, Object... args) { + log.println(getMessage("error.prefix") + " " + getMessage(key, args)); + } + + private void warning(String key, Object... args) { + log.println(getMessage("warn.prefix") + " " + getMessage(key, args)); + } + + private void showHelp() { + log.println(getMessage("main.usage", PROGNAME)); + for (Option o : recognizedOptions) { + String name = o.aliases[0].substring(1); // there must always be at least one name + name = name.charAt(0) == '-' ? name.substring(1) : name; + if (o.isHidden() || name.equals("h")) { + continue; + } + log.println(getMessage("main.opt." + name)); + } + } + + private void showVersion(boolean full) { + log.println(version(full ? "full" : "release")); + } + + private String version(String key) { + // key=version: mm.nn.oo[-milestone] + // key=full: mm.mm.oo[-milestone]-build + if (ResourceBundleHelper.versionRB == null) { + return System.getProperty("java.version"); + } + try { + return ResourceBundleHelper.versionRB.getString(key); + } catch (MissingResourceException e) { + return getMessage("version.unknown", System.getProperty("java.version")); + } + } + + public String getMessage(String key, Object... args) { + try { + return MessageFormat.format(ResourceBundleHelper.bundle.getString(key), args); + } catch (MissingResourceException e) { + throw new InternalError("Missing message: " + key); + } + } + + private static class Options { + enum Verbose { + CLASS, + PACKAGE, + SUMMARY, + VERBOSE + }; + + boolean help; + boolean version; + boolean fullVersion; + boolean showFlags; + boolean showProfile; + boolean showSummary; + boolean wildcard; + String regex; + String classpath = ""; + int depth = 1; + Verbose verbose = Verbose.PACKAGE; + Set packageNames = new HashSet(); + } + + private static class ResourceBundleHelper { + static final ResourceBundle versionRB; + static final ResourceBundle bundle; + + static { + Locale locale = Locale.getDefault(); + try { + bundle = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdeps", locale); + } catch (MissingResourceException e) { + throw new InternalError("Cannot find jdeps resource bundle for locale " + locale); + } + try { + versionRB = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.version"); + } catch (MissingResourceException e) { + throw new InternalError("version.resource.missing"); + } + } + } + + private List getArchives(List filenames) throws IOException { + List result = new ArrayList(); + for (String s : filenames) { + File f = new File(s); + if (f.exists()) { + result.add(new Archive(f, ClassFileReader.newInstance(f))); + } else { + warning("warn.file.not.exist", s); + } + } + return result; + } + + private List getClassPathArchives(String paths) throws IOException { + List result = new ArrayList(); + if (paths.isEmpty()) { + return result; + } + for (String p : paths.split(File.pathSeparator)) { + if (p.length() > 0) { + File f = new File(p); + if (f.exists()) { + result.add(new Archive(f, ClassFileReader.newInstance(f))); + } + } + } + return result; + } +} diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/jdeps/Main.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/com/sun/tools/jdeps/Main.java Thu Jan 10 15:53:02 2013 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012, 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.jdeps; + +import java.io.*; + +/** + * + * Usage: + * jdeps [options] files ... + * where options include: + * -p package-name restrict analysis to classes in this package + * (may be given multiple times) + * -e regex restrict analysis to packages matching pattern + * (-p and -e are exclusive) + * -v show class-level dependencies + * default: package-level dependencies + * -r --recursive transitive dependencies analysis + * -classpath paths Classpath to locate class files + * -all process all class files in the given classpath + */ +public class Main { + public static void main(String... args) throws Exception { + JdepsTask t = new JdepsTask(); + int rc = t.run(args); + System.exit(rc); + } + + + /** + * Entry point that does not call System.exit. + * + * @param args command line arguments + * @param out output stream + * @return an exit code. 0 means success, non-zero means an error occurred. + */ + public static int run(String[] args, PrintWriter out) { + JdepsTask t = new JdepsTask(); + t.setLog(out); + return t.run(args); + } +} + diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/jdeps/PlatformClassPath.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/com/sun/tools/jdeps/PlatformClassPath.java Thu Jan 10 15:53:02 2013 -0800 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2012, 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.jdeps; + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.*; + +/** + * ClassPath for Java SE and JDK + */ +class PlatformClassPath { + /* + * Profiles for Java SE + * + * This is a temporary workaround until a common API is defined for langtools + * to determine which profile a given classname belongs to. The list of + * packages and profile names are hardcoded in jdk.properties and + * split packages are not supported. + */ + static class Profile { + final String name; + final Set packages; + + Profile(String name) { + this.name = name; + this.packages = new HashSet(); + } + } + + private final static String JAVAFX = "javafx"; + private final static Map map = getProfilePackages(); + static String getProfileName(String packageName) { + Profile profile = map.get(packageName); + if (packageName.startsWith(JAVAFX + ".")) { + profile = map.get(JAVAFX); + } + return profile != null ? profile.name : ""; + } + + private final static List javaHomeArchives = init(); + static List getArchives() { + return javaHomeArchives; + } + + static boolean contains(Archive archive) { + return javaHomeArchives.contains(archive); + } + + private static List init() { + List result = new ArrayList(); + String javaHome = System.getProperty("java.home"); + List files = new ArrayList(); + File jre = new File(javaHome, "jre"); + File lib = new File(javaHome, "lib"); + + try { + if (jre.exists() && jre.isDirectory()) { + result.addAll(addJarFiles(new File(jre, "lib"))); + result.addAll(addJarFiles(lib)); + } else if (lib.exists() && lib.isDirectory()) { + // either a JRE or a jdk build image + File classes = new File(javaHome, "classes"); + if (classes.exists() && classes.isDirectory()) { + // jdk build outputdir + result.add(new Archive(classes, ClassFileReader.newInstance(classes))); + } + // add other JAR files + result.addAll(addJarFiles(lib)); + } else { + throw new RuntimeException("\"" + javaHome + "\" not a JDK home"); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + + // add a JavaFX profile if there is jfxrt.jar + for (Archive archive : result) { + if (archive.getFileName().equals("jfxrt.jar")) { + map.put(JAVAFX, new Profile("jfxrt.jar")); + } + } + return result; + } + + private static List addJarFiles(File f) throws IOException { + final List result = new ArrayList(); + final Path root = f.toPath(); + final Path ext = root.resolve("ext"); + Files.walkFileTree(root, new SimpleFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) + throws IOException + { + if (dir.equals(root) || dir.equals(ext)) { + return FileVisitResult.CONTINUE; + } else { + // skip other cobundled JAR files + return FileVisitResult.SKIP_SUBTREE; + } + } + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException + { + File f = file.toFile(); + String fn = f.getName(); + if (fn.endsWith(".jar") && !fn.equals("alt-rt.jar")) { + result.add(new Archive(f, ClassFileReader.newInstance(f))); + } + return FileVisitResult.CONTINUE; + } + }); + return result; + } + + private static Map getProfilePackages() { + Map map = new HashMap(); + + // read the properties as a ResourceBundle as the build compiles + // the properties file into Java class. Another alternative is + // to load it as Properties and fix the build to exclude this file. + ResourceBundle profileBundle = + ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdk"); + + int i=1; + String key; + while (profileBundle.containsKey((key = "profile." + i + ".name"))) { + Profile profile = new Profile(profileBundle.getString(key)); + String n = profileBundle.getString("profile." + i + ".packages"); + String[] pkgs = n.split("\\s+"); + for (String p : pkgs) { + if (p.isEmpty()) continue; + assert(map.containsKey(p) == false); + profile.packages.add(p); + map.put(p, profile); + } + i++; + } + return map; + } +} diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Thu Jan 10 15:53:02 2013 -0800 @@ -0,0 +1,57 @@ +main.usage.summary=\ +Usage: {0} \n\ +use -h, -? or --help for a list of possible options + +main.usage=\ +Usage: {0} \n\ +where can be a pathname to a .class file, a directory, a JAR file,\n\ +or a fully-qualified classname or wildcard "*". Possible options include: + +error.prefix=Error: +warn.prefix=Warning: + +main.opt.h=\ +\ -h -? --help Print this usage message + +main.opt.version=\ +\ --version Version information + +main.opt.V=\ +\ -V --verbose-level= Print package-level or class-level dependencies\n\ +\ Valid levels are: "package" and "class" + +main.opt.v=\ +\ -v --verbose Print additional information + +main.opt.s=\ +\ -s --summary Print dependency summary only + +main.opt.p=\ +\ -p --package= Restrict analysis to classes in this package\n\ +\ (may be given multiple times) + +main.opt.e=\ +\ -e --regex= Restrict analysis to packages matching pattern\n\ +\ (-p and -e are exclusive) + +main.opt.P=\ +\ -P --profile Show profile or the file containing a package + +main.opt.c=\ +\ -c --classpath= Specify where to find class files + +main.opt.R=\ +\ -R --recursive Recursively traverse all dependencies + +main.opt.d=\ +\ -d --depth= Specify the depth of the transitive dependency analysis + +err.unknown.option=unknown option: {0} +err.missing.arg=no value given for {0} +err.internal.error=internal error: {0} {1} {2} +err.invalid.arg.for.option=invalid argument for option: {0} +err.option.after.class=option must be specified before classes: {0} +warn.invalid.arg=Invalid classname or pathname not exist: {0} +warn.split.package=package {0} defined in {1} {2} + +artifact.not.found=not found diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/jdeps/resources/jdk.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/com/sun/tools/jdeps/resources/jdk.properties Thu Jan 10 15:53:02 2013 -0800 @@ -0,0 +1,262 @@ +# This properties file does not need localization. + +profile.1.name = compact1 +profile.1.packages = \ + java.io \ + java.lang \ + java.lang.annotation \ + java.lang.invoke \ + java.lang.ref \ + java.lang.reflect \ + java.math \ + java.net \ + java.nio \ + java.nio.channels \ + java.nio.channels.spi \ + java.nio.charset \ + java.nio.charset.spi \ + java.nio.file \ + java.nio.file.attribute \ + java.nio.file.spi \ + java.security \ + java.security.cert \ + java.security.interfaces \ + java.security.spec \ + java.text \ + java.text.spi \ + java.util \ + java.util.concurrent \ + java.util.concurrent.atomic \ + java.util.concurrent.locks \ + java.util.jar \ + java.util.logging \ + java.util.regex \ + java.util.spi \ + java.util.zip \ + javax.crypto \ + javax.crypto.interfaces \ + javax.crypto.spec \ + javax.security.auth \ + javax.security.auth.callback \ + javax.security.auth.login \ + javax.security.auth.spi \ + javax.security.auth.x500 \ + javax.net \ + javax.net.ssl \ + javax.security.cert \ + \ + com.sun.net.ssl \ + com.sun.nio.file \ + com.sun.nio.sctp \ + com.sun.security.auth \ + com.sun.security.auth.login + +profile.2.name = compact2 +profile.2.packages = \ + java.sql \ + javax.sql \ + javax.xml \ + javax.xml.datatype \ + javax.xml.namespace \ + javax.xml.parsers \ + javax.xml.stream \ + javax.xml.stream.events \ + javax.xml.stream.util \ + javax.xml.transform \ + javax.xml.transform.dom \ + javax.xml.transform.sax \ + javax.xml.transform.stax \ + javax.xml.transform.stream \ + javax.xml.validation \ + javax.xml.xpath \ + org.w3c.dom \ + org.w3c.dom.bootstrap \ + org.w3c.dom.events \ + org.w3c.dom.ls \ + org.xml.sax \ + org.xml.sax.ext \ + org.xml.sax.helpers \ + java.rmi \ + java.rmi.activation \ + java.rmi.dgc \ + java.rmi.registry \ + java.rmi.server \ + javax.rmi.ssl \ + javax.transaction \ + javax.transaction.xa \ + \ + com.sun.net.httpserver \ + com.sun.net.httpserver.spi + +profile.3.name = compact3 +profile.3.packages = \ + java.lang.instrument \ + java.lang.management \ + java.security.acl \ + java.util.prefs \ + javax.management \ + javax.management.loading \ + javax.management.modelmbean \ + javax.management.monitor \ + javax.management.openmbean \ + javax.management.relation \ + javax.management.remote \ + javax.management.remote.rmi \ + javax.management.timer \ + javax.naming \ + javax.naming.directory \ + javax.naming.event \ + javax.naming.ldap \ + javax.naming.spi \ + javax.sql.rowset \ + javax.sql.rowset.serial \ + javax.sql.rowset.spi \ + javax.security.auth.kerberos \ + javax.security.sasl \ + javax.script \ + javax.smartcardio \ + javax.xml.crypto \ + javax.xml.crypto.dom \ + javax.xml.crypto.dsig \ + javax.xml.crypto.dsig.dom \ + javax.xml.crypto.dsig.keyinfo \ + javax.xml.crypto.dsig.spec \ + javax.annotation.processing \ + javax.lang.model \ + javax.lang.model.element \ + javax.lang.model.type \ + javax.lang.model.util \ + javax.tools \ + javax.tools.annotation \ + org.ietf.jgss \ + \ + com.sun.management \ + com.sun.security.auth.callback \ + com.sun.security.auth.module \ + com.sun.security.jgss + +profile.4.name = Full JRE +profile.4.packages = \ + java.applet \ + java.awt \ + java.awt.color \ + java.awt.datatransfer \ + java.awt.dnd \ + java.awt.dnd.peer \ + java.awt.event \ + java.awt.font \ + java.awt.geom \ + java.awt.im \ + java.awt.im.spi \ + java.awt.image \ + java.awt.image.renderable \ + java.awt.peer \ + java.awt.print \ + java.beans \ + java.beans.beancontext \ + javax.accessibility \ + javax.imageio \ + javax.imageio.event \ + javax.imageio.metadata \ + javax.imageio.plugins.bmp \ + javax.imageio.plugins.jpeg \ + javax.imageio.spi \ + javax.imageio.stream \ + javax.print \ + javax.print.attribute \ + javax.print.attribute.standard \ + javax.print.event \ + javax.sound.midi \ + javax.sound.midi.spi \ + javax.sound.sampled \ + javax.sound.sampled.spi \ + javax.swing \ + javax.swing.border \ + javax.swing.colorchooser \ + javax.swing.event \ + javax.swing.filechooser \ + javax.swing.plaf \ + javax.swing.plaf.basic \ + javax.swing.plaf.metal \ + javax.swing.plaf.multi \ + javax.swing.plaf.nimbus \ + javax.swing.plaf.synth \ + javax.swing.table \ + javax.swing.text \ + javax.swing.text.html \ + javax.swing.text.html.parser \ + javax.swing.text.rtf \ + javax.swing.tree \ + javax.swing.undo \ + javax.activation \ + javax.jws \ + javax.jws.soap \ + javax.rmi \ + javax.rmi.CORBA \ + javax.xml.bind \ + javax.xml.bind.annotation \ + javax.xml.bind.annotation.adapters \ + javax.xml.bind.attachment \ + javax.xml.bind.helpers \ + javax.xml.bind.util \ + javax.xml.soap \ + javax.xml.ws \ + javax.xml.ws.handler \ + javax.xml.ws.handler.soap \ + javax.xml.ws.http \ + javax.xml.ws.soap \ + javax.xml.ws.spi \ + javax.xml.ws.spi.http \ + javax.xml.ws.wsaddressing \ + javax.annotation \ + org.omg.CORBA \ + org.omg.CORBA.DynAnyPackage \ + org.omg.CORBA.ORBPackage \ + org.omg.CORBA.TypeCodePackage \ + org.omg.CORBA.portable \ + org.omg.CORBA_2_3 \ + org.omg.CORBA_2_3.portable \ + org.omg.CosNaming \ + org.omg.CosNaming.NamingContextExtPackage \ + org.omg.CosNaming.NamingContextPackage \ + org.omg.Dynamic \ + org.omg.DynamicAny \ + org.omg.DynamicAny.DynAnyFactoryPackage \ + org.omg.DynamicAny.DynAnyPackage \ + org.omg.IOP \ + org.omg.IOP.CodecFactoryPackage \ + org.omg.IOP.CodecPackage \ + org.omg.Messaging \ + org.omg.PortableInterceptor \ + org.omg.PortableInterceptor.ORBInitInfoPackage \ + org.omg.PortableServer \ + org.omg.PortableServer.CurrentPackage \ + org.omg.PortableServer.POAManagerPackage \ + org.omg.PortableServer.POAPackage \ + org.omg.PortableServer.ServantLocatorPackage \ + org.omg.PortableServer.portable \ + org.omg.SendingContext \ + org.omg.stub.java.rmi \ + org.omg.stub.javax.management.remote.rmi + +# Remaining JDK supported API +profile.5.name = JDK tools +profile.5.packages = \ + com.sun.jdi \ + com.sun.jdi.connect \ + com.sun.jdi.connect.spi \ + com.sun.jdi.event \ + com.sun.jdi.request \ + com.sun.javadoc \ + com.sun.tools.doclets \ + com.sun.tools.doctree \ + com.sun.source.tree \ + com.sun.source.util \ + com.sun.tools.attach \ + com.sun.tools.attach.spi \ + com.sun.tools.jconsole \ + com.sun.tools.javac \ + com.sun.tools.javah \ + com.sun.tools.javap \ + com.sun.tools.javadoc \ + com.sun.servicetag diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/com/sun/tools/jdeps/resources/version.properties-template --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/com/sun/tools/jdeps/resources/version.properties-template Thu Jan 10 15:53:02 2013 -0800 @@ -0,0 +1,28 @@ +# +# Copyright (c) 2012, 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. +# + +jdk=$(JDK_VERSION) +full=$(FULL_VERSION) +release=$(RELEASE) diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/javax/lang/model/element/Element.java --- a/langtools/src/share/classes/javax/lang/model/element/Element.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/javax/lang/model/element/Element.java Thu Jan 10 15:53:02 2013 -0800 @@ -179,6 +179,10 @@ * instance initializer}, an empty name is returned. * * @return the simple name of this element + * @see PackageElement#getSimpleName + * @see ExecutableElement#getSimpleName + * @see TypeElement#getSimpleName + * @see VariableElement#getSimpleName */ Name getSimpleName(); @@ -202,6 +206,11 @@ * {@linkplain TypeParameterElement#getGenericElement the * generic element} of the type parameter is returned. * + *

  • If this is a {@linkplain + * VariableElement#getEnclosingElement method or constructor + * parameter}, {@linkplain ExecutableElement the executable + * element} which declares the parameter is returned. + * * * * @return the enclosing element, or {@code null} if there is none diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/javax/lang/model/element/VariableElement.java --- a/langtools/src/share/classes/javax/lang/model/element/VariableElement.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/javax/lang/model/element/VariableElement.java Thu Jan 10 15:53:02 2013 -0800 @@ -62,4 +62,29 @@ * @jls 4.12.4 final Variables */ Object getConstantValue(); + + /** + * Returns the simple name of this variable element. + * + *

    For method and constructor parameters, the name of each + * parameter must be distinct from the names of all other + * parameters of the same executable. If the original source + * names are not available, an implementation may synthesize names + * subject to the distinctness requirement above. + * + * @return the simple name of this variable element + */ + @Override + Name getSimpleName(); + + /** + * Returns the enclosing element of this variable. + * + * The enclosing element of a method or constructor parameter is + * the executable declaring the parameter. + * + * @return the enclosing element of this variable + */ + @Override + Element getEnclosingElement(); } diff -r 8e66fb334fb1 -r b568005e66bd langtools/src/share/classes/javax/lang/model/element/package-info.java --- a/langtools/src/share/classes/javax/lang/model/element/package-info.java Thu Jan 10 09:56:09 2013 -0800 +++ b/langtools/src/share/classes/javax/lang/model/element/package-info.java Thu Jan 10 15:53:02 2013 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2012, 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,9 +48,12 @@ * {@linkplain java.lang.annotation.RetentionPolicy#SOURCE source} * {@linkplain java.lang.annotation.Retention retention} cannot be * recovered from class files and class files might not be able to - * provide source position information. The {@linkplain - * javax.lang.model.element.Modifier modifiers} on an element may - * differ in some cases including + * provide source position information. + * + * Names of parameters may not be recoverable from class files. + * + * The {@linkplain javax.lang.model.element.Modifier modifiers} on an + * element may differ in some cases including: * *