--- old/src/share/classes/sun/reflect/generics/parser/SignatureParser.java 2011-09-02 08:45:18.000000000 -0700 +++ new/src/share/classes/sun/reflect/generics/parser/SignatureParser.java 2011-09-02 08:45:18.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,17 +25,15 @@ package sun.reflect.generics.parser; - import java.lang.reflect.GenericSignatureFormatError; import java.util.*; import sun.reflect.generics.tree.*; - /** * Parser for type signatures, as defined in the Java Virtual -// Machine Specification (JVMS) chapter 4. + * Machine Specification (JVMS) chapter 4. * Converts the signatures into an abstract syntax tree (AST) representation. -// See the package sun.reflect.generics.tree for details of the AST. + * See the package sun.reflect.generics.tree for details of the AST. */ public class SignatureParser { // The input is conceptually a character stream (though currently it's @@ -58,8 +56,8 @@ // if (current != x {error("expected an x"); // // where x is some character constant. - // The assertion inidcates, that, as currently written, - // the code should nver reach this point unless the input is an + // The assertion indicates, that, as currently written, + // the code should never reach this point unless the input is an // x. On the other hand, the test is there to check the legality // of the input wrt to a given production. It may be that at a later // time the code might be called directly, and if the input is @@ -68,7 +66,7 @@ private char[] input; // the input signature private int index = 0; // index into the input -// used to mark end of input + // used to mark end of input private static final char EOI = ':'; private static final boolean DEBUG = false; @@ -104,6 +102,11 @@ index++; } + // For debugging, prints current character to the end of the input. + private String remainder() { + return new String(input, index, input.length-index); + } + // Match c against a "set" of characters private boolean matches(char c, char... set) { for (char e : set) { @@ -117,11 +120,22 @@ // Currently throws a GenericSignatureFormatError. private Error error(String errorMsg) { - if (DEBUG) System.out.println("Parse error:" + errorMsg); + if (DEBUG) + System.out.println("Signature Parse error: " + errorMsg + + "\n\tRemaining input: " + remainder()); return new GenericSignatureFormatError(); } /** + * Verify the parse has made forward progress; throw an exception + * if no progress. + */ + private void progress(int startingPosition) { + if (index <= startingPosition) + throw error("Failure to make progress!"); + } + + /** * Static factory method. Produces a parser instance. * @return an instance of SignatureParser */ @@ -163,6 +177,7 @@ /** * Parses a type signature * and produces an abstract syntax tree representing it. + * * @param s a string representing the input type signature * @return An abstract syntax tree for a type signature * corresponding to the input string @@ -183,38 +198,58 @@ // and when it completes parsing, it leaves the input at the first // character after the input parses. - // parse a class signature based on the implicit input. + /* + * Note on grammar conventions: a trailing "*" matches zero or + * more occurrences, a trailing "+" matches one or more occurrences, + * "_opt" indicates an optional component. + */ + + /** + * ClassSignature: + * FormalTypeParameters_opt SuperclassSignature SuperinterfaceSignature* + */ private ClassSignature parseClassSignature() { + // parse a class signature based on the implicit input. assert(index == 0); return ClassSignature.make(parseZeroOrMoreFormalTypeParameters(), - parseClassTypeSignature(), + parseClassTypeSignature(), // Only rule for SuperclassSignature parseSuperInterfaces()); } private FormalTypeParameter[] parseZeroOrMoreFormalTypeParameters(){ - if (current() == '<') { return parseFormalTypeParameters();} - else {return new FormalTypeParameter[0];} + if (current() == '<') { + return parseFormalTypeParameters(); + } else { + return new FormalTypeParameter[0]; + } } - + /** + * FormalTypeParameters: + * "<" FormalTypeParameter+ ">" + */ private FormalTypeParameter[] parseFormalTypeParameters(){ - Collection ftps = - new ArrayList(3); + List ftps = new ArrayList<>(3); assert(current() == '<'); // should not have been called at all - if (current() != '<') { throw error("expected <");} + if (current() != '<') { throw error("expected '<'");} advance(); ftps.add(parseFormalTypeParameter()); while (current() != '>') { + int startingPosition = index; ftps.add(parseFormalTypeParameter()); + progress(startingPosition); } advance(); - FormalTypeParameter[] ftpa = new FormalTypeParameter[ftps.size()]; - return ftps.toArray(ftpa); + return ftps.toArray(new FormalTypeParameter[ftps.size()]); } + /** + * FormalTypeParameter: + * Identifier ClassBound InterfaceBound* + */ private FormalTypeParameter parseFormalTypeParameter(){ String id = parseIdentifier(); - FieldTypeSignature[] bs = parseZeroOrMoreBounds(); + FieldTypeSignature[] bs = parseBounds(); return FormalTypeParameter.make(id, bs); } @@ -229,7 +264,8 @@ case '[': case ':': case '>': - case '<': return result.toString(); + case '<': + return result.toString(); default:{ result.append(c); advance(); @@ -239,26 +275,42 @@ } return result.toString(); } - + /** + * FieldTypeSignature: + * ClassTypeSignature + * ArrayTypeSignature + * TypeVariableSignature + */ private FieldTypeSignature parseFieldTypeSignature() { + return parseFieldTypeSignature(true); + } + + private FieldTypeSignature parseFieldTypeSignature(boolean allowArrays) { switch(current()) { case 'L': return parseClassTypeSignature(); case 'T': return parseTypeVariableSignature(); case '[': - return parseArrayTypeSignature(); + if (allowArrays) + return parseArrayTypeSignature(); + else + throw error("Array signature not allowed here."); default: throw error("Expected Field Type Signature"); } } + /** + * ClassTypeSignature: + * "L" PackageSpecifier_opt SimpleClassTypeSignature ClassTypeSignatureSuffix* ";" + */ private ClassTypeSignature parseClassTypeSignature(){ assert(current() == 'L'); if (current() != 'L') { throw error("expected a class type");} advance(); - List scts = - new ArrayList(5); - scts.add(parseSimpleClassTypeSignature(false)); + List scts = new ArrayList<>(5); + scts.add(parsePackageNameAndSimpleClassTypeSignature()); + parseClassTypeSignatureSuffix(scts); if (current() != ';') throw error("expected ';' got '" + current() + "'"); @@ -267,25 +319,65 @@ return ClassTypeSignature.make(scts); } - private SimpleClassTypeSignature parseSimpleClassTypeSignature(boolean dollar){ - String id = parseIdentifier(); - char c = current(); - switch (c) { - case ';': - case '/': - return SimpleClassTypeSignature.make(id, dollar, new TypeArgument[0]) ; - case '<': { - return SimpleClassTypeSignature.make(id, dollar, parseTypeArguments()); - } - default: {throw error("expected < or ; or /");} + /** + * PackageSpecifier: + * Identifier "/" PackageSpecifier* + */ + private SimpleClassTypeSignature parsePackageNameAndSimpleClassTypeSignature() { + // Parse both any optional leading PackageSpecifier as well as + // the following SimpleClassTypeSignature. + + String id = parseIdentifier(); + + if (current() == '/') { // package name + StringBuilder idBuild = new StringBuilder(id); + + while(current() == '/') { + advance(); + idBuild.append("."); + idBuild.append(parseIdentifier()); } + id = idBuild.toString(); + } + + switch (current()) { + case ';': + return SimpleClassTypeSignature.make(id, false, new TypeArgument[0]); // all done! + case '<': + if (DEBUG) System.out.println("\t remainder: " + remainder()); + return SimpleClassTypeSignature.make(id, false, parseTypeArguments()); + default: + throw error("expected '<' or ';' but got " + current()); + } } + /** + * SimpleClassTypeSignature: + * Identifier TypeArguments_opt + */ + private SimpleClassTypeSignature parseSimpleClassTypeSignature(boolean dollar){ + String id = parseIdentifier(); + char c = current(); + + switch (c) { + case ';': + case '.': + return SimpleClassTypeSignature.make(id, dollar, new TypeArgument[0]) ; + case '<': + return SimpleClassTypeSignature.make(id, dollar, parseTypeArguments()); + default: + throw error("expected '<' or ';' or '.', got '" + c + "'."); + } + } + + /** + * ClassTypeSignatureSuffix: + * "." SimpleClassTypeSignature + */ private void parseClassTypeSignatureSuffix(List scts) { - while (current() == '/' || current() == '.') { - boolean dollar = (current() == '.'); + while (current() == '.') { advance(); - scts.add(parseSimpleClassTypeSignature(dollar)); + scts.add(parseSimpleClassTypeSignature(true)); } } @@ -294,10 +386,14 @@ else {return new TypeArgument[0];} } + /** + * TypeArguments: + * "<" TypeArgument+ ">" + */ private TypeArgument[] parseTypeArguments() { - Collection tas = new ArrayList(3); + List tas = new ArrayList<>(3); assert(current() == '<'); - if (current() != '<') { throw error("expected <");} + if (current() != '<') { throw error("expected '<'");} advance(); tas.add(parseTypeArgument()); while (current() != '>') { @@ -305,10 +401,14 @@ tas.add(parseTypeArgument()); } advance(); - TypeArgument[] taa = new TypeArgument[tas.size()]; - return tas.toArray(taa); + return tas.toArray(new TypeArgument[tas.size()]); } + /** + * TypeArgument: + * WildcardIndicator_opt FieldTypeSignature + * "*" + */ private TypeArgument parseTypeArgument() { FieldTypeSignature[] ub, lb; ub = new FieldTypeSignature[1]; @@ -334,18 +434,20 @@ ub[0] = SimpleClassTypeSignature.make("java.lang.Object", false, ta); return Wildcard.make(ub, lb); } - default: return parseFieldTypeSignature(); + default: + return parseFieldTypeSignature(); } } - // TypeVariableSignature -> T identifier - - private TypeVariableSignature parseTypeVariableSignature(){ + /** + * TypeVariableSignature: + * "T" Identifier ";" + */ + private TypeVariableSignature parseTypeVariableSignature() { assert(current() == 'T'); if (current() != 'T') { throw error("expected a type variable usage");} advance(); - TypeVariableSignature ts = - TypeVariableSignature.make(parseIdentifier()); + TypeVariableSignature ts = TypeVariableSignature.make(parseIdentifier()); if (current() != ';') { throw error("; expected in signature of type variable named" + ts.getIdentifier()); @@ -354,16 +456,21 @@ return ts; } - // ArrayTypeSignature -> [ TypeSignature - + /** + * ArrayTypeSignature: + * "[" TypeSignature + */ private ArrayTypeSignature parseArrayTypeSignature() { if (current() != '[') {throw error("expected array type signature");} advance(); return ArrayTypeSignature.make(parseTypeSignature()); } - // TypeSignature -> BaseType | FieldTypeSignature - + /** + * TypeSignature: + * FieldTypeSignature + * BaseType + */ private TypeSignature parseTypeSignature() { switch (current()) { case 'B': @@ -373,8 +480,11 @@ case 'I': case 'J': case 'S': - case 'Z':return parseBaseType(); - default: return parseFieldTypeSignature(); + case 'Z': + return parseBaseType(); + + default: + return parseFieldTypeSignature(); } } @@ -408,12 +518,18 @@ assert(false); throw error("expected primitive type"); } - } + } } - private FieldTypeSignature[] parseZeroOrMoreBounds() { - Collection fts = - new ArrayList(3); + /** + * ClassBound: + * ":" FieldTypeSignature_opt + * + * InterfaceBound: + * ":" FieldTypeSignature + */ + private FieldTypeSignature[] parseBounds() { + List fts = new ArrayList<>(3); if (current() == ':') { advance(); @@ -430,24 +546,31 @@ advance(); fts.add(parseFieldTypeSignature()); } - } + } else + error("Bound expected"); - FieldTypeSignature[] fta = new FieldTypeSignature[fts.size()]; - return fts.toArray(fta); + return fts.toArray(new FieldTypeSignature[fts.size()]); } + /** + * SuperclassSignature: + * ClassTypeSignature + */ private ClassTypeSignature[] parseSuperInterfaces() { - Collection cts = - new ArrayList(5); + List cts = new ArrayList<>(5); while(current() == 'L') { cts.add(parseClassTypeSignature()); } - ClassTypeSignature[] cta = new ClassTypeSignature[cts.size()]; - return cts.toArray(cta); + return cts.toArray(new ClassTypeSignature[cts.size()]); } - // parse a method signature based on the implicit input. + + /** + * MethodTypeSignature: + * FormalTypeParameters_opt "(" TypeSignature* ")" ReturnType ThrowsSignature* + */ private MethodTypeSignature parseMethodTypeSignature() { + // Parse a method signature based on the implicit input. FieldTypeSignature[] ets; assert(index == 0); @@ -457,19 +580,19 @@ parseZeroOrMoreThrowsSignatures()); } - // (TypeSignature*) + // "(" TypeSignature* ")" private TypeSignature[] parseFormalParameters() { - if (current() != '(') {throw error("expected (");} + if (current() != '(') {throw error("expected '('");} advance(); TypeSignature[] pts = parseZeroOrMoreTypeSignatures(); - if (current() != ')') {throw error("expected )");} + if (current() != ')') {throw error("expected ')'");} advance(); return pts; } - // TypeSignature* + // TypeSignature* private TypeSignature[] parseZeroOrMoreTypeSignatures() { - Collection ts = new ArrayList(); + List ts = new ArrayList<>(); boolean stop = false; while (!stop) { switch(current()) { @@ -484,47 +607,46 @@ case 'L': case 'T': case '[': { - ts.add(parseTypeSignature()); - break; - } + ts.add(parseTypeSignature()); + break; + } default: stop = true; } } - /* while( matches(current(), - 'B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z', 'L', 'T', '[') - ) { - ts.add(parseTypeSignature()); - }*/ - TypeSignature[] ta = new TypeSignature[ts.size()]; - return ts.toArray(ta); + return ts.toArray(new TypeSignature[ts.size()]); } - // ReturnType -> V | TypeSignature - + /** + * ReturnType: + * TypeSignature + * VoidDescriptor + */ private ReturnType parseReturnType(){ - if (current() == 'V') { + if (current() == 'V') { advance(); return VoidDescriptor.make(); - } else return parseTypeSignature(); + } else + return parseTypeSignature(); } // ThrowSignature* private FieldTypeSignature[] parseZeroOrMoreThrowsSignatures(){ - Collection ets = - new ArrayList(3); + List ets = new ArrayList<>(3); while( current() == '^') { ets.add(parseThrowsSignature()); } - FieldTypeSignature[] eta = new FieldTypeSignature[ets.size()]; - return ets.toArray(eta); + return ets.toArray(new FieldTypeSignature[ets.size()]); } - // ThrowSignature -> ^ FieldTypeSignature - + /** + * ThrowsSignature: + * "^" ClassTypeSignature + * "^" TypeVariableSignature + */ private FieldTypeSignature parseThrowsSignature() { assert(current() == '^'); if (current() != '^') { throw error("expected throws signature");} advance(); - return parseFieldTypeSignature(); + return parseFieldTypeSignature(false); } } --- old/test/java/lang/reflect/Generics/Probe.java 2011-09-02 08:45:19.000000000 -0700 +++ new/test/java/lang/reflect/Generics/Probe.java 2011-09-02 08:45:19.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2011, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 5003916 6704655 6873951 + * @bug 5003916 6704655 6873951 6476261 * @summary Testing parsing of signatures attributes of nested classes * @author Joseph D. Darcy */ @@ -38,12 +38,12 @@ "java.util.concurrent.ConcurrentHashMap$KeyIterator", "java.util.concurrent.ConcurrentHashMap$ValueIterator", "java.util.AbstractList$ListItr", -// "java.util.EnumMap$EntryIterator", -// "java.util.EnumMap$KeyIterator", -// "java.util.EnumMap$ValueIterator", -// "java.util.IdentityHashMap$EntryIterator", -// "java.util.IdentityHashMap$KeyIterator", -// "java.util.IdentityHashMap$ValueIterator", + "java.util.EnumMap$EntryIterator", + "java.util.EnumMap$KeyIterator", + "java.util.EnumMap$ValueIterator", + "java.util.IdentityHashMap$EntryIterator", + "java.util.IdentityHashMap$KeyIterator", + "java.util.IdentityHashMap$ValueIterator", "java.util.WeakHashMap$EntryIterator", "java.util.WeakHashMap$KeyIterator", "java.util.WeakHashMap$ValueIterator", @@ -52,12 +52,12 @@ "java.util.HashMap$ValueIterator", "java.util.LinkedHashMap$EntryIterator", "java.util.LinkedHashMap$KeyIterator", - "java.util.LinkedHashMap$ValueIterator"}) + "java.util.LinkedHashMap$ValueIterator", + "javax.swing.JComboBox$AccessibleJComboBox"}) public class Probe { public static void main (String... args) throws Throwable { Classes classesAnnotation = (Probe.class).getAnnotation(Classes.class); - List names = - new ArrayList(asList(classesAnnotation.value())); + List names = new ArrayList<>(asList(classesAnnotation.value())); int errs = 0; for(String name: names) { --- /dev/null 2011-09-01 02:03:34.128260089 -0700 +++ new/test/java/lang/reflect/Generics/SignatureTest.java 2011-09-02 08:45:20.000000000 -0700 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2006, 2011, 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. + * + * 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. + */ + +/* + * @test + * @bug 6476261 + * @summary More testing of parsing of signatures attributes of nested classes + */ + +import java.lang.reflect.*; + +public class SignatureTest { + class Inner1 { + class Inner11 { + } + } + + public void f(SignatureTest.Inner1.Inner11 x) {} + public void g(SignatureTest.Inner1 x) {} + + public static void main(String[] args) throws Exception { + Class clazz = SignatureTest.class; + for (Method m : clazz.getDeclaredMethods()) { + System.out.println(); + System.out.println(m.toString()); + System.out.println(m.toGenericString()); + System.out.println(m.getGenericParameterTypes()); + } + } +} --- /dev/null 2011-09-01 02:03:34.128260089 -0700 +++ new/test/java/lang/reflect/Generics/TestBadSignatures.java 2011-09-02 08:45:20.000000000 -0700 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011, 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. + * + * 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. + */ + +/* + * @test + * @bug 6832374 7052898 + * @summary Test bad signatures get a GenericSignatureFormatError thrown. + * @author Joseph D. Darcy + */ + +import java.lang.reflect.*; +import sun.reflect.generics.parser.SignatureParser; + +public class TestBadSignatures { + public static void main(String[] args) { + String[] badSignatures = { + // Missing ":" after first type bound + "(TE;[Ljava/lang/RuntimeException;)V^[TE;", + }; + + for(String badSig : badSignatures) { + try { + SignatureParser.make().parseMethodSig(badSig); + throw new RuntimeException("Expected GenericSignatureFormatError for " + + badSig); + } catch(GenericSignatureFormatError gsfe) { + System.out.println(gsfe.toString()); // Expected + } + } + } +}