Fri, 16 Oct 2009 12:56:50 -0700
6888367: classfile library parses signature attributes incorrectly
Reviewed-by: ksrini
1.1 --- a/src/share/classes/com/sun/tools/classfile/Signature.java Thu Oct 15 22:48:34 2009 -0700 1.2 +++ b/src/share/classes/com/sun/tools/classfile/Signature.java Fri Oct 16 12:56:50 2009 -0700 1.3 @@ -27,6 +27,7 @@ 1.4 1.5 import java.util.ArrayList; 1.6 import java.util.List; 1.7 +import com.sun.tools.classfile.Type.*; 1.8 1.9 /** 1.10 * See JVMS3 4.4.4. 1.11 @@ -50,19 +51,19 @@ 1.12 1.13 @Override 1.14 public int getParameterCount(ConstantPool constant_pool) throws ConstantPoolException { 1.15 - Type.MethodType m = (Type.MethodType) getType(constant_pool); 1.16 - return m.argTypes.size(); 1.17 + MethodType m = (MethodType) getType(constant_pool); 1.18 + return m.paramTypes.size(); 1.19 } 1.20 1.21 @Override 1.22 public String getParameterTypes(ConstantPool constant_pool) throws ConstantPoolException { 1.23 - Type.MethodType m = (Type.MethodType) getType(constant_pool); 1.24 + MethodType m = (MethodType) getType(constant_pool); 1.25 StringBuilder sb = new StringBuilder(); 1.26 sb.append("("); 1.27 String sep = ""; 1.28 - for (Type argType: m.argTypes) { 1.29 + for (Type paramType: m.paramTypes) { 1.30 sb.append(sep); 1.31 - sb.append(argType); 1.32 + sb.append(paramType); 1.33 sep = ", "; 1.34 } 1.35 sb.append(")"); 1.36 @@ -71,7 +72,7 @@ 1.37 1.38 @Override 1.39 public String getReturnType(ConstantPool constant_pool) throws ConstantPoolException { 1.40 - Type.MethodType m = (Type.MethodType) getType(constant_pool); 1.41 + MethodType m = (MethodType) getType(constant_pool); 1.42 return m.returnType.toString(); 1.43 } 1.44 1.45 @@ -84,12 +85,12 @@ 1.46 this.sig = sig; 1.47 sigp = 0; 1.48 1.49 - List<Type> typeArgTypes = null; 1.50 + List<TypeParamType> typeParamTypes = null; 1.51 if (sig.charAt(sigp) == '<') 1.52 - typeArgTypes = parseTypeArgTypes(); 1.53 + typeParamTypes = parseTypeParamTypes(); 1.54 1.55 if (sig.charAt(sigp) == '(') { 1.56 - List<Type> argTypes = parseTypeSignatures(')'); 1.57 + List<Type> paramTypes = parseTypeSignatures(')'); 1.58 Type returnType = parseTypeSignature(); 1.59 List<Type> throwsTypes = null; 1.60 while (sigp < sig.length() && sig.charAt(sigp) == '^') { 1.61 @@ -98,16 +99,19 @@ 1.62 throwsTypes = new ArrayList<Type>(); 1.63 throwsTypes.add(parseTypeSignature()); 1.64 } 1.65 - return new Type.MethodType(typeArgTypes, argTypes, returnType, throwsTypes); 1.66 + return new MethodType(typeParamTypes, paramTypes, returnType, throwsTypes); 1.67 } else { 1.68 Type t = parseTypeSignature(); 1.69 - if (typeArgTypes == null && sigp == sig.length()) 1.70 + if (typeParamTypes == null && sigp == sig.length()) 1.71 return t; 1.72 Type superclass = t; 1.73 - List<Type> superinterfaces = new ArrayList<Type>(); 1.74 - while (sigp < sig.length()) 1.75 + List<Type> superinterfaces = null; 1.76 + while (sigp < sig.length()) { 1.77 + if (superinterfaces == null) 1.78 + superinterfaces = new ArrayList<Type>(); 1.79 superinterfaces.add(parseTypeSignature()); 1.80 - return new Type.ClassSigType(typeArgTypes, superclass, superinterfaces); 1.81 + } 1.82 + return new ClassSigType(typeParamTypes, superclass, superinterfaces); 1.83 1.84 } 1.85 } 1.86 @@ -116,61 +120,61 @@ 1.87 switch (sig.charAt(sigp)) { 1.88 case 'B': 1.89 sigp++; 1.90 - return new Type.SimpleType("byte"); 1.91 + return new SimpleType("byte"); 1.92 1.93 case 'C': 1.94 sigp++; 1.95 - return new Type.SimpleType("char"); 1.96 + return new SimpleType("char"); 1.97 1.98 case 'D': 1.99 sigp++; 1.100 - return new Type.SimpleType("double"); 1.101 + return new SimpleType("double"); 1.102 1.103 case 'F': 1.104 sigp++; 1.105 - return new Type.SimpleType("float"); 1.106 + return new SimpleType("float"); 1.107 1.108 case 'I': 1.109 sigp++; 1.110 - return new Type.SimpleType("int"); 1.111 + return new SimpleType("int"); 1.112 1.113 case 'J': 1.114 sigp++; 1.115 - return new Type.SimpleType("long"); 1.116 + return new SimpleType("long"); 1.117 1.118 case 'L': 1.119 return parseClassTypeSignature(); 1.120 1.121 case 'S': 1.122 sigp++; 1.123 - return new Type.SimpleType("short"); 1.124 + return new SimpleType("short"); 1.125 1.126 case 'T': 1.127 return parseTypeVariableSignature(); 1.128 1.129 case 'V': 1.130 sigp++; 1.131 - return new Type.SimpleType("void"); 1.132 + return new SimpleType("void"); 1.133 1.134 case 'Z': 1.135 sigp++; 1.136 - return new Type.SimpleType("boolean"); 1.137 + return new SimpleType("boolean"); 1.138 1.139 case '[': 1.140 sigp++; 1.141 - return new Type.ArrayType(parseTypeSignature()); 1.142 + return new ArrayType(parseTypeSignature()); 1.143 1.144 case '*': 1.145 sigp++; 1.146 - return new Type.WildcardType(); 1.147 + return new WildcardType(); 1.148 1.149 case '+': 1.150 sigp++; 1.151 - return new Type.WildcardType("extends", parseTypeSignature()); 1.152 + return new WildcardType(WildcardType.Kind.EXTENDS, parseTypeSignature()); 1.153 1.154 case '-': 1.155 sigp++; 1.156 - return new Type.WildcardType("super", parseTypeSignature()); 1.157 + return new WildcardType(WildcardType.Kind.SUPER, parseTypeSignature()); 1.158 1.159 default: 1.160 throw new IllegalStateException(debugInfo()); 1.161 @@ -194,30 +198,22 @@ 1.162 1.163 private Type parseClassTypeSignatureRest() { 1.164 StringBuilder sb = new StringBuilder(); 1.165 - Type t = null; 1.166 - char sigch; 1.167 - while (true) { 1.168 + List<Type> argTypes = null; 1.169 + ClassType t = null; 1.170 + char sigch ; 1.171 + 1.172 + do { 1.173 switch (sigch = sig.charAt(sigp)) { 1.174 - case '/': 1.175 - sigp++; 1.176 - sb.append("."); 1.177 + case '<': 1.178 + argTypes = parseTypeSignatures('>'); 1.179 break; 1.180 1.181 case '.': 1.182 - sigp++; 1.183 - if (t == null) 1.184 - t = new Type.SimpleType(sb.toString()); 1.185 - return new Type.InnerClassType(t, parseClassTypeSignatureRest()); 1.186 - 1.187 case ';': 1.188 sigp++; 1.189 - if (t == null) 1.190 - t = new Type.SimpleType(sb.toString()); 1.191 - return t; 1.192 - 1.193 - case '<': 1.194 - List<Type> argTypes = parseTypeSignatures('>'); 1.195 - t = new Type.ClassType(sb.toString(), argTypes); 1.196 + t = new ClassType(t, sb.toString(), argTypes); 1.197 + sb.setLength(0); 1.198 + argTypes = null; 1.199 break; 1.200 1.201 default: 1.202 @@ -225,21 +221,22 @@ 1.203 sb.append(sigch); 1.204 break; 1.205 } 1.206 - } 1.207 + } while (sigch != ';'); 1.208 + 1.209 + return t; 1.210 } 1.211 1.212 - private List<Type> parseTypeArgTypes() { 1.213 + private List<TypeParamType> parseTypeParamTypes() { 1.214 assert sig.charAt(sigp) == '<'; 1.215 sigp++; 1.216 - List<Type> types = null; 1.217 - types = new ArrayList<Type>(); 1.218 + List<TypeParamType> types = new ArrayList<TypeParamType>(); 1.219 while (sig.charAt(sigp) != '>') 1.220 - types.add(parseTypeArgType()); 1.221 + types.add(parseTypeParamType()); 1.222 sigp++; 1.223 return types; 1.224 } 1.225 1.226 - private Type parseTypeArgType() { 1.227 + private TypeParamType parseTypeParamType() { 1.228 int sep = sig.indexOf(":", sigp); 1.229 String name = sig.substring(sigp, sep); 1.230 Type classBound = null; 1.231 @@ -253,13 +250,13 @@ 1.232 interfaceBounds = new ArrayList<Type>(); 1.233 interfaceBounds.add(parseTypeSignature()); 1.234 } 1.235 - return new Type.TypeArgType(name, classBound, interfaceBounds); 1.236 + return new TypeParamType(name, classBound, interfaceBounds); 1.237 } 1.238 1.239 private Type parseTypeVariableSignature() { 1.240 sigp++; 1.241 int sep = sig.indexOf(';', sigp); 1.242 - Type t = new Type.SimpleType(sig.substring(sigp, sep)); 1.243 + Type t = new SimpleType(sig.substring(sigp, sep)); 1.244 sigp = sep + 1; 1.245 return t; 1.246 }
2.1 --- a/src/share/classes/com/sun/tools/classfile/Type.java Thu Oct 15 22:48:34 2009 -0700 2.2 +++ b/src/share/classes/com/sun/tools/classfile/Type.java Fri Oct 16 12:56:50 2009 -0700 2.3 @@ -31,6 +31,9 @@ 2.4 import java.util.Set; 2.5 2.6 /* 2.7 + * Family of classes used to represent the parsed form of a {@link Descriptor} 2.8 + * or {@link Signature}. 2.9 + * 2.10 * <p><b>This is NOT part of any API supported by Sun Microsystems. If 2.11 * you write code that depends on this, you do so at your own risk. 2.12 * This code and its internal interfaces are subject to change or 2.13 @@ -62,11 +65,26 @@ 2.14 R visitMethodType(MethodType type, P p); 2.15 R visitClassSigType(ClassSigType type, P p); 2.16 R visitClassType(ClassType type, P p); 2.17 - R visitInnerClassType(InnerClassType type, P p); 2.18 - R visitTypeArgType(TypeArgType type, P p); 2.19 + R visitTypeParamType(TypeParamType type, P p); 2.20 R visitWildcardType(WildcardType type, P p); 2.21 } 2.22 2.23 + /** 2.24 + * Represents a type signature with a simple name. The name may be that of a 2.25 + * primitive type, such "{@code int}, {@code float}, etc 2.26 + * or that of a type argument, such as {@code T}, {@code K}, {@code V}, etc. 2.27 + * 2.28 + * See: 2.29 + * JVMS 4.3.2 2.30 + * BaseType: 2.31 + * {@code B}, {@code C}, {@code D}, {@code F}, {@code I}, 2.32 + * {@code J}, {@code S}, {@code Z}; 2.33 + * VoidDescriptor: 2.34 + * {@code V}; 2.35 + * JVMS 4.3.4 2.36 + * TypeVariableSignature: 2.37 + * {@code T} Identifier {@code ;} 2.38 + */ 2.39 public static class SimpleType extends Type { 2.40 public SimpleType(String name) { 2.41 this.name = name; 2.42 @@ -91,6 +109,14 @@ 2.43 public final String name; 2.44 } 2.45 2.46 + /** 2.47 + * Represents an array type signature. 2.48 + * 2.49 + * See: 2.50 + * JVMS 4.3.4 2.51 + * ArrayTypeSignature: 2.52 + * {@code [} TypeSignature {@code ]} 2.53 + */ 2.54 public static class ArrayType extends Type { 2.55 public ArrayType(Type elemType) { 2.56 this.elemType = elemType; 2.57 @@ -108,17 +134,26 @@ 2.58 public final Type elemType; 2.59 } 2.60 2.61 + /** 2.62 + * Represents a method type signature. 2.63 + * 2.64 + * See; 2.65 + * JVMS 4.3.4 2.66 + * MethodTypeSignature: 2.67 + * FormalTypeParameters_opt {@code (} TypeSignature* {@code)} ReturnType 2.68 + * ThrowsSignature* 2.69 + */ 2.70 public static class MethodType extends Type { 2.71 - public MethodType(List<? extends Type> argTypes, Type resultType) { 2.72 - this(null, argTypes, resultType, null); 2.73 + public MethodType(List<? extends Type> paramTypes, Type resultType) { 2.74 + this(null, paramTypes, resultType, null); 2.75 } 2.76 2.77 - public MethodType(List<? extends Type> typeArgTypes, 2.78 - List<? extends Type> argTypes, 2.79 + public MethodType(List<? extends TypeParamType> typeParamTypes, 2.80 + List<? extends Type> paramTypes, 2.81 Type returnType, 2.82 List<? extends Type> throwsTypes) { 2.83 - this.typeArgTypes = typeArgTypes; 2.84 - this.argTypes = argTypes; 2.85 + this.typeParamTypes = typeParamTypes; 2.86 + this.paramTypes = paramTypes; 2.87 this.returnType = returnType; 2.88 this.throwsTypes = throwsTypes; 2.89 } 2.90 @@ -130,22 +165,32 @@ 2.91 @Override 2.92 public String toString() { 2.93 StringBuilder sb = new StringBuilder(); 2.94 - appendIfNotEmpty(sb, "<", typeArgTypes, "> "); 2.95 + appendIfNotEmpty(sb, "<", typeParamTypes, "> "); 2.96 sb.append(returnType); 2.97 - append(sb, " (", argTypes, ")"); 2.98 + append(sb, " (", paramTypes, ")"); 2.99 appendIfNotEmpty(sb, " throws ", throwsTypes, ""); 2.100 return sb.toString(); 2.101 } 2.102 2.103 - public final List<? extends Type> typeArgTypes; 2.104 - public final List<? extends Type> argTypes; 2.105 + public final List<? extends TypeParamType> typeParamTypes; 2.106 + public final List<? extends Type> paramTypes; 2.107 public final Type returnType; 2.108 public final List<? extends Type> throwsTypes; 2.109 } 2.110 2.111 + /** 2.112 + * Represents a class signature. These describe the signature of 2.113 + * a class that has type arguments. 2.114 + * 2.115 + * See: 2.116 + * JVMS 4.3.4 2.117 + * ClassSignature: 2.118 + * FormalTypeParameters_opt SuperclassSignature SuperinterfaceSignature* 2.119 + */ 2.120 public static class ClassSigType extends Type { 2.121 - public ClassSigType(List<Type> typeArgTypes, Type superclassType, List<Type> superinterfaceTypes) { 2.122 - this.typeArgTypes = typeArgTypes; 2.123 + public ClassSigType(List<TypeParamType> typeParamTypes, Type superclassType, 2.124 + List<Type> superinterfaceTypes) { 2.125 + this.typeParamTypes = typeParamTypes; 2.126 this.superclassType = superclassType; 2.127 this.superinterfaceTypes = superinterfaceTypes; 2.128 } 2.129 @@ -157,7 +202,7 @@ 2.130 @Override 2.131 public String toString() { 2.132 StringBuilder sb = new StringBuilder(); 2.133 - appendIfNotEmpty(sb, "<", typeArgTypes, ">"); 2.134 + appendIfNotEmpty(sb, "<", typeParamTypes, ">"); 2.135 if (superclassType != null) { 2.136 sb.append(" extends "); 2.137 sb.append(superclassType); 2.138 @@ -166,13 +211,30 @@ 2.139 return sb.toString(); 2.140 } 2.141 2.142 - public final List<Type> typeArgTypes; 2.143 + public final List<TypeParamType> typeParamTypes; 2.144 public final Type superclassType; 2.145 public final List<Type> superinterfaceTypes; 2.146 } 2.147 2.148 + /** 2.149 + * Represents a class type signature. This is used to represent a 2.150 + * reference to a class, such as in a field, parameter, return type, etc. 2.151 + * 2.152 + * See: 2.153 + * JVMS 4.3.4 2.154 + * ClassTypeSignature: 2.155 + * {@code L} PackageSpecifier_opt SimpleClassTypeSignature 2.156 + * ClassTypeSignatureSuffix* {@code ;} 2.157 + * PackageSpecifier: 2.158 + * Identifier {@code /} PackageSpecifier* 2.159 + * SimpleClassTypeSignature: 2.160 + * Identifier TypeArguments_opt } 2.161 + * ClassTypeSignatureSuffix: 2.162 + * {@code .} SimpleClassTypeSignature 2.163 + */ 2.164 public static class ClassType extends Type { 2.165 - public ClassType(String name, List<Type> typeArgs) { 2.166 + public ClassType(ClassType outerType, String name, List<Type> typeArgs) { 2.167 + this.outerType = outerType; 2.168 this.name = name; 2.169 this.typeArgs = typeArgs; 2.170 } 2.171 @@ -181,47 +243,54 @@ 2.172 return visitor.visitClassType(this, data); 2.173 } 2.174 2.175 + public String getBinaryName() { 2.176 + if (outerType == null) 2.177 + return name; 2.178 + else 2.179 + return (outerType.getBinaryName() + "$" + name); 2.180 + } 2.181 + 2.182 @Override 2.183 public String toString() { 2.184 StringBuilder sb = new StringBuilder(); 2.185 + if (outerType != null) { 2.186 + sb.append(outerType); 2.187 + sb.append("."); 2.188 + } 2.189 sb.append(name); 2.190 appendIfNotEmpty(sb, "<", typeArgs, ">"); 2.191 return sb.toString(); 2.192 } 2.193 2.194 + public final ClassType outerType; 2.195 public final String name; 2.196 public final List<Type> typeArgs; 2.197 } 2.198 2.199 - 2.200 - public static class InnerClassType extends Type { 2.201 - public InnerClassType(Type outerType, Type innerType) { 2.202 - this.outerType = outerType; 2.203 - this.innerType = innerType; 2.204 - } 2.205 - 2.206 - public <R, D> R accept(Visitor<R, D> visitor, D data) { 2.207 - return visitor.visitInnerClassType(this, data); 2.208 - } 2.209 - 2.210 - @Override 2.211 - public String toString() { 2.212 - return outerType + "." + innerType; 2.213 - } 2.214 - 2.215 - public final Type outerType; 2.216 - public final Type innerType; 2.217 - } 2.218 - 2.219 - public static class TypeArgType extends Type { 2.220 - public TypeArgType(String name, Type classBound, List<Type> interfaceBounds) { 2.221 + /** 2.222 + * Represents a FormalTypeParameter. These are used to declare the type 2.223 + * parameters for generic classes and methods. 2.224 + * 2.225 + * See: 2.226 + * JVMS 4.3.4 2.227 + * FormalTypeParameters: 2.228 + * {@code <} FormalTypeParameter+ {@code >} 2.229 + * FormalTypeParameter: 2.230 + * Identifier ClassBound InterfaceBound* 2.231 + * ClassBound: 2.232 + * {@code :} FieldTypeSignature_opt 2.233 + * InterfaceBound: 2.234 + * {@code :} FieldTypeSignature 2.235 + */ 2.236 + public static class TypeParamType extends Type { 2.237 + public TypeParamType(String name, Type classBound, List<Type> interfaceBounds) { 2.238 this.name = name; 2.239 this.classBound = classBound; 2.240 this.interfaceBounds = interfaceBounds; 2.241 } 2.242 2.243 public <R, D> R accept(Visitor<R, D> visitor, D data) { 2.244 - return visitor.visitTypeArgType(this, data); 2.245 + return visitor.visitTypeParamType(this, data); 2.246 } 2.247 2.248 @Override 2.249 @@ -249,12 +318,25 @@ 2.250 public final List<Type> interfaceBounds; 2.251 } 2.252 2.253 + /** 2.254 + * Represents a wildcard type argument. A type argument that is not a 2.255 + * wildcard type argument will be represented by a ClassType, ArrayType, etc. 2.256 + * 2.257 + * See: 2.258 + * JVMS 4.3.4 2.259 + * TypeArgument: 2.260 + * WildcardIndicator_opt FieldTypeSignature 2.261 + * {@code *} 2.262 + * WildcardIndicator: 2.263 + * {@code +} 2.264 + * {@code -} 2.265 + */ 2.266 public static class WildcardType extends Type { 2.267 + public enum Kind { UNBOUNDED, EXTENDS, SUPER }; 2.268 public WildcardType() { 2.269 - this(null, null); 2.270 + this(Kind.UNBOUNDED, null); 2.271 } 2.272 - 2.273 - public WildcardType(String kind, Type boundType) { 2.274 + public WildcardType(Kind kind, Type boundType) { 2.275 this.kind = kind; 2.276 this.boundType = boundType; 2.277 } 2.278 @@ -265,13 +347,19 @@ 2.279 2.280 @Override 2.281 public String toString() { 2.282 - if (kind == null) 2.283 - return "?"; 2.284 - else 2.285 - return "? " + kind + " " + boundType; 2.286 + switch (kind) { 2.287 + case UNBOUNDED: 2.288 + return "?"; 2.289 + case EXTENDS: 2.290 + return "? extends " + boundType; 2.291 + case SUPER: 2.292 + return "? super " + boundType; 2.293 + default: 2.294 + throw new AssertionError(); 2.295 + } 2.296 } 2.297 2.298 - public final String kind; 2.299 + public final Kind kind; 2.300 public final Type boundType; 2.301 } 2.302 }
3.1 --- a/src/share/classes/com/sun/tools/javap/ClassWriter.java Thu Oct 15 22:48:34 2009 -0700 3.2 +++ b/src/share/classes/com/sun/tools/javap/ClassWriter.java Fri Oct 16 12:56:50 2009 -0700 3.3 @@ -179,10 +179,10 @@ 3.4 // The signature parser cannot disambiguate between a 3.5 // FieldType and a ClassSignatureType that only contains a superclass type. 3.6 if (t instanceof Type.ClassSigType) 3.7 - print(t); 3.8 + print(getJavaName(t.toString())); 3.9 else { 3.10 print(" extends "); 3.11 - print(t); 3.12 + print(getJavaName(t.toString())); 3.13 } 3.14 } catch (ConstantPoolException e) { 3.15 print(report(e)); 3.16 @@ -310,7 +310,7 @@ 3.17 3.18 writeModifiers(flags.getMethodModifiers()); 3.19 if (methodType != null) { 3.20 - writeListIfNotEmpty("<", methodType.typeArgTypes, "> "); 3.21 + writeListIfNotEmpty("<", methodType.typeParamTypes, "> "); 3.22 } 3.23 if (getName(m).equals("<init>")) { 3.24 print(getJavaName(classFile));
4.1 --- a/src/share/classes/com/sun/tools/javap/LocalVariableTypeTableWriter.java Thu Oct 15 22:48:34 2009 -0700 4.2 +++ b/src/share/classes/com/sun/tools/javap/LocalVariableTypeTableWriter.java Fri Oct 16 12:56:50 2009 -0700 4.3 @@ -125,7 +125,7 @@ 4.4 print(" // "); 4.5 Descriptor d = new Signature(entry.signature_index); 4.6 try { 4.7 - print(d.getFieldType(constant_pool)); 4.8 + print(d.getFieldType(constant_pool).toString().replace("/", ".")); 4.9 } catch (InvalidDescriptor e) { 4.10 print(report(e)); 4.11 } catch (ConstantPoolException e) {
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/test/tools/javap/classfile/6888367/T6888367.java Fri Oct 16 12:56:50 2009 -0700 5.3 @@ -0,0 +1,511 @@ 5.4 +/* 5.5 + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. 5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5.7 + * 5.8 + * This code is free software; you can redistribute it and/or modify it 5.9 + * under the terms of the GNU General Public License version 2 only, as 5.10 + * published by the Free Software Foundation. 5.11 + * 5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 5.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 5.15 + * version 2 for more details (a copy is included in the LICENSE file that 5.16 + * accompanied this code). 5.17 + * 5.18 + * You should have received a copy of the GNU General Public License version 5.19 + * 2 along with this work; if not, write to the Free Software Foundation, 5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 5.21 + * 5.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 5.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 5.24 + * have any questions. 5.25 + */ 5.26 + 5.27 +import java.io.*; 5.28 +import java.net.*; 5.29 +import java.util.*; 5.30 +import com.sun.tools.classfile.*; 5.31 +import com.sun.tools.classfile.Type.ArrayType; 5.32 +import com.sun.tools.classfile.Type.ClassSigType; 5.33 +import com.sun.tools.classfile.Type.ClassType; 5.34 +import com.sun.tools.classfile.Type.MethodType; 5.35 +import com.sun.tools.classfile.Type.SimpleType; 5.36 +import com.sun.tools.classfile.Type.TypeParamType; 5.37 +import com.sun.tools.classfile.Type.WildcardType; 5.38 + 5.39 +/* 5.40 + * @test 5.41 + * @bug 6888367 5.42 + * @summary classfile library parses signature attributes incorrectly 5.43 + */ 5.44 + 5.45 +/* 5.46 + * This test is a pretty detailed test both of javac signature generation and classfile 5.47 + * signature parsing. The first part of the test tests all the examples given in the 5.48 + * second part of the test. Each example comes with one or two annotations, @Desc, @Sig, 5.49 + * for the descriptor and signature of the annotated declaration. Annotations are 5.50 + * provided whenever the annotated item is expected to have a corresponding value. 5.51 + * Each annotation has two argument values. The first arg is the expected value of the 5.52 + * descriptor/signature as found in the class file. This value is mostly for documentation 5.53 + * purposes in reading the test. The second value is the rendering of the descriptor or 5.54 + * signature using a custom Type visitor that explicitly includes an indication of the 5.55 + * Type classes being used to represent the descriptor/signature. Thus we test 5.56 + * that the descriptor/signature is being parsed into the expected type tree structure. 5.57 + */ 5.58 +public class T6888367 { 5.59 + 5.60 + public static void main(String... args) throws Exception { 5.61 + new T6888367().run(); 5.62 + } 5.63 + 5.64 + public void run() throws Exception { 5.65 + ClassFile cf = getClassFile("Test"); 5.66 + 5.67 + testFields(cf); 5.68 + testMethods(cf); 5.69 + testInnerClasses(cf); // recursive 5.70 + 5.71 + if (errors > 0) 5.72 + throw new Exception(errors + " errors found"); 5.73 + } 5.74 + 5.75 + void testFields(ClassFile cf) throws Exception { 5.76 + String cn = cf.getName(); 5.77 + ConstantPool cp = cf.constant_pool; 5.78 + for (Field f: cf.fields) { 5.79 + test("field " + cn + "." + f.getName(cp), f.descriptor, f.attributes, cp); 5.80 + } 5.81 + } 5.82 + 5.83 + void testMethods(ClassFile cf) throws Exception { 5.84 + String cn = cf.getName(); 5.85 + ConstantPool cp = cf.constant_pool; 5.86 + for (Method m: cf.methods) { 5.87 + test("method " + cn + "." + m.getName(cp), m.descriptor, m.attributes, cp); 5.88 + } 5.89 + } 5.90 + 5.91 + void testInnerClasses(ClassFile cf) throws Exception { 5.92 + ConstantPool cp = cf.constant_pool; 5.93 + InnerClasses_attribute ic = 5.94 + (InnerClasses_attribute) cf.attributes.get(Attribute.InnerClasses); 5.95 + for (InnerClasses_attribute.Info info: ic.classes) { 5.96 + String outerClassName = cp.getClassInfo(info.outer_class_info_index).getName(); 5.97 + if (!outerClassName.equals(cf.getName())) { 5.98 + continue; 5.99 + } 5.100 + String innerClassName = cp.getClassInfo(info.inner_class_info_index).getName(); 5.101 + ClassFile icf = getClassFile(innerClassName); 5.102 + test("class " + innerClassName, null, icf.attributes, icf.constant_pool); 5.103 + testInnerClasses(icf); 5.104 + } 5.105 + } 5.106 + 5.107 + void test(String name, Descriptor desc, Attributes attrs, ConstantPool cp) 5.108 + throws Exception { 5.109 + AnnotValues d = getDescValue(attrs, cp); 5.110 + AnnotValues s = getSigValue(attrs, cp); 5.111 + if (d == null && s == null) // not a test field or method if no @Desc or @Sig given 5.112 + return; 5.113 + 5.114 + System.err.println(name); 5.115 + 5.116 + if (desc != null) { 5.117 + System.err.println(" descriptor: " + desc.getValue(cp)); 5.118 + checkEqual(d.raw, desc.getValue(cp)); 5.119 + Type dt = new Signature(desc.index).getType(cp); 5.120 + checkEqual(d.type, tp.print(dt)); 5.121 + } 5.122 + 5.123 + Signature_attribute sa = (Signature_attribute) attrs.get(Attribute.Signature); 5.124 + if (sa != null) 5.125 + System.err.println(" signature: " + sa.getSignature(cp)); 5.126 + 5.127 + if (s != null || sa != null) { 5.128 + if (s != null && sa != null) { 5.129 + checkEqual(s.raw, sa.getSignature(cp)); 5.130 + Type st = new Signature(sa.signature_index).getType(cp); 5.131 + checkEqual(s.type, tp.print(st)); 5.132 + } else if (s != null) 5.133 + error("@Sig annotation found but not Signature attribute"); 5.134 + else 5.135 + error("Signature attribute found but no @Sig annotation"); 5.136 + } 5.137 + 5.138 + System.err.println(); 5.139 + } 5.140 + 5.141 + 5.142 + ClassFile getClassFile(String name) throws IOException, ConstantPoolException { 5.143 + URL url = getClass().getResource(name + ".class"); 5.144 + InputStream in = url.openStream(); 5.145 + try { 5.146 + return ClassFile.read(in); 5.147 + } finally { 5.148 + in.close(); 5.149 + } 5.150 + } 5.151 + 5.152 + AnnotValues getDescValue(Attributes attrs, ConstantPool cp) throws Exception { 5.153 + return getAnnotValues(Desc.class.getName(), attrs, cp); 5.154 + } 5.155 + 5.156 + AnnotValues getSigValue(Attributes attrs, ConstantPool cp) throws Exception { 5.157 + return getAnnotValues(Sig.class.getName(), attrs, cp); 5.158 + } 5.159 + 5.160 + static class AnnotValues { 5.161 + AnnotValues(String raw, String type) { 5.162 + this.raw = raw; 5.163 + this.type = type; 5.164 + } 5.165 + final String raw; 5.166 + final String type; 5.167 + } 5.168 + 5.169 + AnnotValues getAnnotValues(String annotName, Attributes attrs, ConstantPool cp) 5.170 + throws Exception { 5.171 + RuntimeInvisibleAnnotations_attribute annots = 5.172 + (RuntimeInvisibleAnnotations_attribute)attrs.get(Attribute.RuntimeInvisibleAnnotations); 5.173 + if (annots != null) { 5.174 + for (Annotation a: annots.annotations) { 5.175 + if (cp.getUTF8Value(a.type_index).equals("L" + annotName + ";")) { 5.176 + Annotation.Primitive_element_value pv0 = 5.177 + (Annotation.Primitive_element_value) a.element_value_pairs[0].value; 5.178 + Annotation.Primitive_element_value pv1 = 5.179 + (Annotation.Primitive_element_value) a.element_value_pairs[1].value; 5.180 + return new AnnotValues( 5.181 + cp.getUTF8Value(pv0.const_value_index), 5.182 + cp.getUTF8Value(pv1.const_value_index)); 5.183 + } 5.184 + } 5.185 + } 5.186 + return null; 5.187 + 5.188 + } 5.189 + 5.190 + void checkEqual(String expect, String found) { 5.191 + if (!(expect == null ? found == null : expect.equals(found))) { 5.192 + System.err.println("expected: " + expect); 5.193 + System.err.println(" found: " + found); 5.194 + error("unexpected values found"); 5.195 + } 5.196 + } 5.197 + 5.198 + void error(String msg) { 5.199 + System.err.println("error: " + msg); 5.200 + errors++; 5.201 + } 5.202 + 5.203 + int errors; 5.204 + 5.205 + TypePrinter tp = new TypePrinter(); 5.206 + 5.207 + class TypePrinter implements Type.Visitor<String,Void> { 5.208 + String print(Type t) { 5.209 + return t == null ? null : t.accept(this, null); 5.210 + } 5.211 + String print(String pre, List<? extends Type> ts, String post) { 5.212 + if (ts == null) 5.213 + return null; 5.214 + StringBuilder sb = new StringBuilder(); 5.215 + sb.append(pre); 5.216 + String sep = ""; 5.217 + for (Type t: ts) { 5.218 + sb.append(sep); 5.219 + sb.append(print(t)); 5.220 + sep = ","; 5.221 + } 5.222 + sb.append(post); 5.223 + return sb.toString(); 5.224 + } 5.225 + 5.226 + public String visitSimpleType(SimpleType type, Void p) { 5.227 + return "S{" + type.name + "}"; 5.228 + } 5.229 + 5.230 + public String visitArrayType(ArrayType type, Void p) { 5.231 + return "A{" + print(type.elemType) + "}"; 5.232 + } 5.233 + 5.234 + public String visitMethodType(MethodType type, Void p) { 5.235 + StringBuilder sb = new StringBuilder(); 5.236 + sb.append("M{"); 5.237 + if (type.typeParamTypes != null) 5.238 + sb.append(print("<", type.typeParamTypes, ">")); 5.239 + sb.append(print(type.returnType)); 5.240 + sb.append(print("(", type.paramTypes, ")")); 5.241 + if (type.throwsTypes != null) 5.242 + sb.append(print("", type.throwsTypes, "")); 5.243 + sb.append("}"); 5.244 + return sb.toString(); 5.245 + } 5.246 + 5.247 + public String visitClassSigType(ClassSigType type, Void p) { 5.248 + StringBuilder sb = new StringBuilder(); 5.249 + sb.append("CS{"); 5.250 + if (type.typeParamTypes != null) 5.251 + sb.append(print("<", type.typeParamTypes, ">")); 5.252 + sb.append(print(type.superclassType)); 5.253 + if (type.superinterfaceTypes != null) 5.254 + sb.append(print("i(", type.superinterfaceTypes, ")")); 5.255 + sb.append("}"); 5.256 + return sb.toString(); 5.257 + } 5.258 + 5.259 + public String visitClassType(ClassType type, Void p) { 5.260 + StringBuilder sb = new StringBuilder(); 5.261 + sb.append("C{"); 5.262 + if (type.outerType != null) { 5.263 + sb.append(print(type.outerType)); 5.264 + sb.append("."); 5.265 + } 5.266 + sb.append(type.name); 5.267 + if (type.typeArgs != null) 5.268 + sb.append(print("<", type.typeArgs, ">")); 5.269 + sb.append("}"); 5.270 + return sb.toString(); 5.271 + } 5.272 + 5.273 + public String visitTypeParamType(TypeParamType type, Void p) { 5.274 + StringBuilder sb = new StringBuilder(); 5.275 + sb.append("TA{"); 5.276 + sb.append(type.name); 5.277 + if (type.classBound != null) { 5.278 + sb.append(":c"); 5.279 + sb.append(print(type.classBound)); 5.280 + } 5.281 + if (type.interfaceBounds != null) 5.282 + sb.append(print(":i", type.interfaceBounds, "")); 5.283 + sb.append("}"); 5.284 + return sb.toString(); 5.285 + } 5.286 + 5.287 + public String visitWildcardType(WildcardType type, Void p) { 5.288 + switch (type.kind) { 5.289 + case UNBOUNDED: 5.290 + return "W{?}"; 5.291 + case EXTENDS: 5.292 + return "W{e," + print(type.boundType) + "}"; 5.293 + case SUPER: 5.294 + return "W{s," + print(type.boundType) + "}"; 5.295 + default: 5.296 + throw new AssertionError(); 5.297 + } 5.298 + } 5.299 + 5.300 + }; 5.301 +} 5.302 + 5.303 + 5.304 +@interface Desc { 5.305 + String d(); 5.306 + String t(); 5.307 +} 5.308 + 5.309 +@interface Sig { 5.310 + String s(); 5.311 + String t(); 5.312 +} 5.313 + 5.314 +class Clss { } 5.315 +interface Intf { } 5.316 +class GenClss<T> { } 5.317 + 5.318 +class Test { 5.319 + // fields 5.320 + 5.321 + @Desc(d="Z", t="S{boolean}") 5.322 + boolean z; 5.323 + 5.324 + @Desc(d="B", t="S{byte}") 5.325 + byte b; 5.326 + 5.327 + @Desc(d="C", t="S{char}") 5.328 + char c; 5.329 + 5.330 + @Desc(d="D", t="S{double}") 5.331 + double d; 5.332 + 5.333 + @Desc(d="F", t="S{float}") 5.334 + float f; 5.335 + 5.336 + @Desc(d="I", t="S{int}") 5.337 + int i; 5.338 + 5.339 + @Desc(d="J", t="S{long}") 5.340 + long l; 5.341 + 5.342 + @Desc(d="S", t="S{short}") 5.343 + short s; 5.344 + 5.345 + @Desc(d="LClss;", t="C{Clss}") 5.346 + Clss clss; 5.347 + 5.348 + @Desc(d="LIntf;", t="C{Intf}") 5.349 + Intf intf; 5.350 + 5.351 + @Desc(d="[I", t="A{S{int}}") 5.352 + int[] ai; 5.353 + 5.354 + @Desc(d="[LClss;", t="A{C{Clss}}") 5.355 + Clss[] aClss; 5.356 + 5.357 + @Desc(d="LGenClss;", t="C{GenClss}") 5.358 + @Sig(s="LGenClss<LClss;>;", t="C{GenClss<C{Clss}>}") 5.359 + GenClss<Clss> genClass; 5.360 + 5.361 + // methods, return types 5.362 + 5.363 + @Desc(d="()V", t="M{S{void}()}") 5.364 + void mv0() { } 5.365 + 5.366 + @Desc(d="()I", t="M{S{int}()}") 5.367 + int mi0() { return 0; } 5.368 + 5.369 + @Desc(d="()LClss;", t="M{C{Clss}()}") 5.370 + Clss mclss0() { return null; } 5.371 + 5.372 + @Desc(d="()[I", t="M{A{S{int}}()}") 5.373 + int[] mai0() { return null; } 5.374 + 5.375 + @Desc(d="()[LClss;", t="M{A{C{Clss}}()}") 5.376 + Clss[] maClss0() { return null; } 5.377 + 5.378 + @Desc(d="()LGenClss;", t="M{C{GenClss}()}") 5.379 + @Sig(s="()LGenClss<LClss;>;", t="M{C{GenClss<C{Clss}>}()}") 5.380 + GenClss<Clss> mgenClss0() { return null; } 5.381 + 5.382 + @Desc(d="()LGenClss;", t="M{C{GenClss}()}") 5.383 + @Sig(s="()LGenClss<*>;", t="M{C{GenClss<W{?}>}()}") 5.384 + GenClss<?> mgenClssW0() { return null; } 5.385 + 5.386 + @Desc(d="()LGenClss;", t="M{C{GenClss}()}") 5.387 + @Sig(s="()LGenClss<+LClss;>;", t="M{C{GenClss<W{e,C{Clss}}>}()}") 5.388 + GenClss<? extends Clss> mgenClssWExtClss0() { return null; } 5.389 + 5.390 + @Desc(d="()LGenClss;", t="M{C{GenClss}()}") 5.391 + @Sig(s="()LGenClss<-LClss;>;", t="M{C{GenClss<W{s,C{Clss}}>}()}") 5.392 + GenClss<? super Clss> mgenClssWSupClss0() { return null; } 5.393 + 5.394 + @Desc(d="()Ljava/lang/Object;", t="M{C{java/lang/Object}()}") 5.395 + @Sig(s="<T:Ljava/lang/Object;>()TT;", t="M{<TA{T:cC{java/lang/Object}}>S{T}()}") 5.396 + <T> T mt0() { return null; } 5.397 + 5.398 + @Desc(d="()LGenClss;", t="M{C{GenClss}()}") 5.399 + @Sig(s="<T:Ljava/lang/Object;>()LGenClss<+TT;>;", 5.400 + t="M{<TA{T:cC{java/lang/Object}}>C{GenClss<W{e,S{T}}>}()}") 5.401 + <T> GenClss<? extends T> mgenClssWExtT0() { return null; } 5.402 + 5.403 + @Desc(d="()LGenClss;", t="M{C{GenClss}()}") 5.404 + @Sig(s="<T:Ljava/lang/Object;>()LGenClss<-TT;>;", t="M{<TA{T:cC{java/lang/Object}}>C{GenClss<W{s,S{T}}>}()}") 5.405 + <T> GenClss<? super T> mgenClssWSupT0() { return null; } 5.406 + 5.407 + // methods, arg types 5.408 + 5.409 + @Desc(d="(I)V", t="M{S{void}(S{int})}") 5.410 + void mi1(int arg) { } 5.411 + 5.412 + @Desc(d="(LClss;)V", t="M{S{void}(C{Clss})}") 5.413 + void mclss1(Clss arg) { } 5.414 + 5.415 + @Desc(d="([I)V", t="M{S{void}(A{S{int}})}") 5.416 + void mai1(int[] arg) { } 5.417 + 5.418 + @Desc(d="([LClss;)V", t="M{S{void}(A{C{Clss}})}") 5.419 + void maClss1(Clss[] arg) { } 5.420 + 5.421 + @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}") 5.422 + @Sig(s="(LGenClss<LClss;>;)V", t="M{S{void}(C{GenClss<C{Clss}>})}") 5.423 + void mgenClss1(GenClss<Clss> arg) { } 5.424 + 5.425 + @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}") 5.426 + @Sig(s="(LGenClss<*>;)V", t="M{S{void}(C{GenClss<W{?}>})}") 5.427 + void mgenClssW1(GenClss<?> arg) { } 5.428 + 5.429 + @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}") 5.430 + @Sig(s="(LGenClss<+LClss;>;)V", t="M{S{void}(C{GenClss<W{e,C{Clss}}>})}") 5.431 + void mgenClssWExtClss1(GenClss<? extends Clss> arg) { } 5.432 + 5.433 + @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}") 5.434 + @Sig(s="(LGenClss<-LClss;>;)V", t="M{S{void}(C{GenClss<W{s,C{Clss}}>})}") 5.435 + void mgenClssWSupClss1(GenClss<? super Clss> arg) { } 5.436 + 5.437 + @Desc(d="(Ljava/lang/Object;)V", t="M{S{void}(C{java/lang/Object})}") 5.438 + @Sig(s="<T:Ljava/lang/Object;>(TT;)V", 5.439 + t="M{<TA{T:cC{java/lang/Object}}>S{void}(S{T})}") 5.440 + <T> void mt1(T arg) { } 5.441 + 5.442 + @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}") 5.443 + @Sig(s="<T:Ljava/lang/Object;>(LGenClss<+TT;>;)V", 5.444 + t="M{<TA{T:cC{java/lang/Object}}>S{void}(C{GenClss<W{e,S{T}}>})}") 5.445 + <T> void mgenClssWExtT1(GenClss<? extends T> arg) { } 5.446 + 5.447 + @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}") 5.448 + @Sig(s="<T:Ljava/lang/Object;>(LGenClss<-TT;>;)V", 5.449 + t="M{<TA{T:cC{java/lang/Object}}>S{void}(C{GenClss<W{s,S{T}}>})}") 5.450 + <T> void mgenClssWSupT1(GenClss<? super T> arg) { } 5.451 + 5.452 + // methods, throws 5.453 + 5.454 + @Desc(d="()V", t="M{S{void}()}") 5.455 + void m_E() throws Exception { } 5.456 + 5.457 + @Desc(d="()V", t="M{S{void}()}") 5.458 + @Sig(s="<T:Ljava/lang/Throwable;>()V^TT;", 5.459 + t="M{<TA{T:cC{java/lang/Throwable}}>S{void}()S{T}}") 5.460 + <T extends Throwable> void m_T() throws T { } 5.461 + 5.462 + // inner classes 5.463 + 5.464 + static class X { 5.465 + // no sig 5.466 + class P { } 5.467 + 5.468 + @Sig(s="<TQ:Ljava/lang/Object;>LTest$X$P;", 5.469 + t="CS{<TA{TQ:cC{java/lang/Object}}>C{Test$X$P}}") 5.470 + class Q<TQ> extends P { } 5.471 + 5.472 + @Sig(s="<TR:Ljava/lang/Object;>LTest$X$Q<TTR;>;", 5.473 + t="CS{<TA{TR:cC{java/lang/Object}}>C{Test$X$Q<S{TR}>}}") 5.474 + class R<TR> extends Q<TR> { } 5.475 + } 5.476 + 5.477 + @Sig(s="<TY:Ljava/lang/Object;>Ljava/lang/Object;", 5.478 + t="CS{<TA{TY:cC{java/lang/Object}}>C{java/lang/Object}}") 5.479 + static class Y<TY> { 5.480 + // no sig 5.481 + class P { } 5.482 + 5.483 + @Sig(s="<TQ:Ljava/lang/Object;>LTest$Y<TTY;>.P;", 5.484 + t="CS{<TA{TQ:cC{java/lang/Object}}>C{C{Test$Y<S{TY}>}.P}}") 5.485 + class Q<TQ> extends P { } 5.486 + 5.487 + @Sig(s="<TR:Ljava/lang/Object;>LTest$Y<TTY;>.Q<TTR;>;", 5.488 + t="CS{<TA{TR:cC{java/lang/Object}}>C{C{Test$Y<S{TY}>}.Q<S{TR}>}}") 5.489 + class R<TR> extends Q<TR> { 5.490 + // no sig 5.491 + class R1 { } 5.492 + 5.493 + @Sig(s="<TR2:Ljava/lang/Object;>LTest$Y<TTY;>.R<TTR;>.R1;", 5.494 + t="CS{<TA{TR2:cC{java/lang/Object}}>C{C{C{Test$Y<S{TY}>}.R<S{TR}>}.R1}}") 5.495 + class R2<TR2> extends R1 { } 5.496 + } 5.497 + 5.498 + @Sig(s="LTest$Y<TTY;>.Q<TTY;>;", t="C{C{Test$Y<S{TY}>}.Q<S{TY}>}") 5.499 + class S extends Q<TY> { 5.500 + // no sig 5.501 + class S1 { } 5.502 + 5.503 + @Sig(s="<TS2:Ljava/lang/Object;>LTest$Y<TTY;>.S.S1;", 5.504 + t="CS{<TA{TS2:cC{java/lang/Object}}>C{C{C{Test$Y<S{TY}>}.S}.S1}}") 5.505 + class S2<TS2> extends S1 { } 5.506 + 5.507 + @Sig(s="LTest$Y<TTY;>.S.S2<TTY;>;", 5.508 + t="C{C{C{Test$Y<S{TY}>}.S}.S2<S{TY}>}") 5.509 + class S3 extends S2<TY> { } 5.510 + } 5.511 + } 5.512 +} 5.513 + 5.514 +