1/* 2 * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24import java.io.*; 25import java.net.*; 26import java.util.*; 27 28import com.sun.tools.classfile.*; 29import com.sun.tools.classfile.Type.ArrayType; 30import com.sun.tools.classfile.Type.ClassSigType; 31import com.sun.tools.classfile.Type.ClassType; 32import com.sun.tools.classfile.Type.MethodType; 33import com.sun.tools.classfile.Type.SimpleType; 34import com.sun.tools.classfile.Type.TypeParamType; 35import com.sun.tools.classfile.Type.WildcardType; 36 37/* 38 * @test 39 * @bug 6888367 40 * @summary classfile library parses signature attributes incorrectly 41 * @modules jdk.jdeps/com.sun.tools.classfile 42 */ 43 44/* 45 * This test is a pretty detailed test both of javac signature generation and classfile 46 * signature parsing. The first part of the test tests all the examples given in the 47 * second part of the test. Each example comes with one or two annotations, @Desc, @Sig, 48 * for the descriptor and signature of the annotated declaration. Annotations are 49 * provided whenever the annotated item is expected to have a corresponding value. 50 * Each annotation has two argument values. The first arg is the expected value of the 51 * descriptor/signature as found in the class file. This value is mostly for documentation 52 * purposes in reading the test. The second value is the rendering of the descriptor or 53 * signature using a custom Type visitor that explicitly includes an indication of the 54 * Type classes being used to represent the descriptor/signature. Thus we test 55 * that the descriptor/signature is being parsed into the expected type tree structure. 56 */ 57public class T6888367 { 58 59 public static void main(String... args) throws Exception { 60 new T6888367().run(); 61 } 62 63 public void run() throws Exception { 64 ClassFile cf = getClassFile("Test"); 65 66 testFields(cf); 67 testMethods(cf); 68 testInnerClasses(cf); // recursive 69 70 if (errors > 0) 71 throw new Exception(errors + " errors found"); 72 } 73 74 void testFields(ClassFile cf) throws Exception { 75 String cn = cf.getName(); 76 ConstantPool cp = cf.constant_pool; 77 for (Field f: cf.fields) { 78 test("field " + cn + "." + f.getName(cp), f.descriptor, f.attributes, cp); 79 } 80 } 81 82 void testMethods(ClassFile cf) throws Exception { 83 String cn = cf.getName(); 84 ConstantPool cp = cf.constant_pool; 85 for (Method m: cf.methods) { 86 test("method " + cn + "." + m.getName(cp), m.descriptor, m.attributes, cp); 87 } 88 } 89 90 void testInnerClasses(ClassFile cf) throws Exception { 91 ConstantPool cp = cf.constant_pool; 92 InnerClasses_attribute ic = 93 (InnerClasses_attribute) cf.attributes.get(Attribute.InnerClasses); 94 for (InnerClasses_attribute.Info info: ic.classes) { 95 String outerClassName = cp.getClassInfo(info.outer_class_info_index).getName(); 96 if (!outerClassName.equals(cf.getName())) { 97 continue; 98 } 99 String innerClassName = cp.getClassInfo(info.inner_class_info_index).getName(); 100 ClassFile icf = getClassFile(innerClassName); 101 test("class " + innerClassName, null, icf.attributes, icf.constant_pool); 102 testInnerClasses(icf); 103 } 104 } 105 106 void test(String name, Descriptor desc, Attributes attrs, ConstantPool cp) 107 throws Exception { 108 AnnotValues d = getDescValue(attrs, cp); 109 AnnotValues s = getSigValue(attrs, cp); 110 if (d == null && s == null) // not a test field or method if no @Desc or @Sig given 111 return; 112 113 System.err.println(name); 114 115 if (desc != null) { 116 System.err.println(" descriptor: " + desc.getValue(cp)); 117 checkEqual(d.raw, desc.getValue(cp)); 118 Type dt = new Signature(desc.index).getType(cp); 119 checkEqual(d.type, tp.print(dt)); 120 } 121 122 Signature_attribute sa = (Signature_attribute) attrs.get(Attribute.Signature); 123 if (sa != null) 124 System.err.println(" signature: " + sa.getSignature(cp)); 125 126 if (s != null || sa != null) { 127 if (s != null && sa != null) { 128 checkEqual(s.raw, sa.getSignature(cp)); 129 Type st = new Signature(sa.signature_index).getType(cp); 130 checkEqual(s.type, tp.print(st)); 131 } else if (s != null) 132 error("@Sig annotation found but not Signature attribute"); 133 else 134 error("Signature attribute found but no @Sig annotation"); 135 } 136 137 System.err.println(); 138 } 139 140 141 ClassFile getClassFile(String name) throws IOException, ConstantPoolException { 142 URL url = getClass().getResource(name + ".class"); 143 InputStream in = url.openStream(); 144 try { 145 return ClassFile.read(in); 146 } finally { 147 in.close(); 148 } 149 } 150 151 AnnotValues getDescValue(Attributes attrs, ConstantPool cp) throws Exception { 152 return getAnnotValues(Desc.class.getName(), attrs, cp); 153 } 154 155 AnnotValues getSigValue(Attributes attrs, ConstantPool cp) throws Exception { 156 return getAnnotValues(Sig.class.getName(), attrs, cp); 157 } 158 159 static class AnnotValues { 160 AnnotValues(String raw, String type) { 161 this.raw = raw; 162 this.type = type; 163 } 164 final String raw; 165 final String type; 166 } 167 168 AnnotValues getAnnotValues(String annotName, Attributes attrs, ConstantPool cp) 169 throws Exception { 170 RuntimeInvisibleAnnotations_attribute annots = 171 (RuntimeInvisibleAnnotations_attribute)attrs.get(Attribute.RuntimeInvisibleAnnotations); 172 if (annots != null) { 173 for (Annotation a: annots.annotations) { 174 if (cp.getUTF8Value(a.type_index).equals("L" + annotName + ";")) { 175 Annotation.Primitive_element_value pv0 = 176 (Annotation.Primitive_element_value) a.element_value_pairs[0].value; 177 Annotation.Primitive_element_value pv1 = 178 (Annotation.Primitive_element_value) a.element_value_pairs[1].value; 179 return new AnnotValues( 180 cp.getUTF8Value(pv0.const_value_index), 181 cp.getUTF8Value(pv1.const_value_index)); 182 } 183 } 184 } 185 return null; 186 187 } 188 189 void checkEqual(String expect, String found) { 190 if (!(expect == null ? found == null : expect.equals(found))) { 191 System.err.println("expected: " + expect); 192 System.err.println(" found: " + found); 193 error("unexpected values found"); 194 } 195 } 196 197 void error(String msg) { 198 System.err.println("error: " + msg); 199 errors++; 200 } 201 202 int errors; 203 204 TypePrinter tp = new TypePrinter(); 205 206 class TypePrinter implements Type.Visitor<String,Void> { 207 String print(Type t) { 208 return t == null ? null : t.accept(this, null); 209 } 210 String print(String pre, List<? extends Type> ts, String post) { 211 if (ts == null) 212 return null; 213 StringBuilder sb = new StringBuilder(); 214 sb.append(pre); 215 String sep = ""; 216 for (Type t: ts) { 217 sb.append(sep); 218 sb.append(print(t)); 219 sep = ","; 220 } 221 sb.append(post); 222 return sb.toString(); 223 } 224 225 public String visitSimpleType(SimpleType type, Void p) { 226 return "S{" + type.name + "}"; 227 } 228 229 public String visitArrayType(ArrayType type, Void p) { 230 return "A{" + print(type.elemType) + "}"; 231 } 232 233 public String visitMethodType(MethodType type, Void p) { 234 StringBuilder sb = new StringBuilder(); 235 sb.append("M{"); 236 if (type.typeParamTypes != null) 237 sb.append(print("<", type.typeParamTypes, ">")); 238 sb.append(print(type.returnType)); 239 sb.append(print("(", type.paramTypes, ")")); 240 if (type.throwsTypes != null) 241 sb.append(print("", type.throwsTypes, "")); 242 sb.append("}"); 243 return sb.toString(); 244 } 245 246 public String visitClassSigType(ClassSigType type, Void p) { 247 StringBuilder sb = new StringBuilder(); 248 sb.append("CS{"); 249 if (type.typeParamTypes != null) 250 sb.append(print("<", type.typeParamTypes, ">")); 251 sb.append(print(type.superclassType)); 252 if (type.superinterfaceTypes != null) 253 sb.append(print("i(", type.superinterfaceTypes, ")")); 254 sb.append("}"); 255 return sb.toString(); 256 } 257 258 public String visitClassType(ClassType type, Void p) { 259 StringBuilder sb = new StringBuilder(); 260 sb.append("C{"); 261 if (type.outerType != null) { 262 sb.append(print(type.outerType)); 263 sb.append("."); 264 } 265 sb.append(type.name); 266 if (type.typeArgs != null) 267 sb.append(print("<", type.typeArgs, ">")); 268 sb.append("}"); 269 return sb.toString(); 270 } 271 272 public String visitTypeParamType(TypeParamType type, Void p) { 273 StringBuilder sb = new StringBuilder(); 274 sb.append("TA{"); 275 sb.append(type.name); 276 if (type.classBound != null) { 277 sb.append(":c"); 278 sb.append(print(type.classBound)); 279 } 280 if (type.interfaceBounds != null) 281 sb.append(print(":i", type.interfaceBounds, "")); 282 sb.append("}"); 283 return sb.toString(); 284 } 285 286 public String visitWildcardType(WildcardType type, Void p) { 287 switch (type.kind) { 288 case UNBOUNDED: 289 return "W{?}"; 290 case EXTENDS: 291 return "W{e," + print(type.boundType) + "}"; 292 case SUPER: 293 return "W{s," + print(type.boundType) + "}"; 294 default: 295 throw new AssertionError(); 296 } 297 } 298 299 }; 300} 301 302 303@interface Desc { 304 String d(); 305 String t(); 306} 307 308@interface Sig { 309 String s(); 310 String t(); 311} 312 313class Clss { } 314interface Intf { } 315class GenClss<T> { } 316 317class Test { 318 // fields 319 320 @Desc(d="Z", t="S{boolean}") 321 boolean z; 322 323 @Desc(d="B", t="S{byte}") 324 byte b; 325 326 @Desc(d="C", t="S{char}") 327 char c; 328 329 @Desc(d="D", t="S{double}") 330 double d; 331 332 @Desc(d="F", t="S{float}") 333 float f; 334 335 @Desc(d="I", t="S{int}") 336 int i; 337 338 @Desc(d="J", t="S{long}") 339 long l; 340 341 @Desc(d="S", t="S{short}") 342 short s; 343 344 @Desc(d="LClss;", t="C{Clss}") 345 Clss clss; 346 347 @Desc(d="LIntf;", t="C{Intf}") 348 Intf intf; 349 350 @Desc(d="[I", t="A{S{int}}") 351 int[] ai; 352 353 @Desc(d="[LClss;", t="A{C{Clss}}") 354 Clss[] aClss; 355 356 @Desc(d="LGenClss;", t="C{GenClss}") 357 @Sig(s="LGenClss<LClss;>;", t="C{GenClss<C{Clss}>}") 358 GenClss<Clss> genClass; 359 360 // methods, return types 361 362 @Desc(d="()V", t="M{S{void}()}") 363 void mv0() { } 364 365 @Desc(d="()I", t="M{S{int}()}") 366 int mi0() { return 0; } 367 368 @Desc(d="()LClss;", t="M{C{Clss}()}") 369 Clss mclss0() { return null; } 370 371 @Desc(d="()[I", t="M{A{S{int}}()}") 372 int[] mai0() { return null; } 373 374 @Desc(d="()[LClss;", t="M{A{C{Clss}}()}") 375 Clss[] maClss0() { return null; } 376 377 @Desc(d="()LGenClss;", t="M{C{GenClss}()}") 378 @Sig(s="()LGenClss<LClss;>;", t="M{C{GenClss<C{Clss}>}()}") 379 GenClss<Clss> mgenClss0() { return null; } 380 381 @Desc(d="()LGenClss;", t="M{C{GenClss}()}") 382 @Sig(s="()LGenClss<*>;", t="M{C{GenClss<W{?}>}()}") 383 GenClss<?> mgenClssW0() { return null; } 384 385 @Desc(d="()LGenClss;", t="M{C{GenClss}()}") 386 @Sig(s="()LGenClss<+LClss;>;", t="M{C{GenClss<W{e,C{Clss}}>}()}") 387 GenClss<? extends Clss> mgenClssWExtClss0() { return null; } 388 389 @Desc(d="()LGenClss;", t="M{C{GenClss}()}") 390 @Sig(s="()LGenClss<-LClss;>;", t="M{C{GenClss<W{s,C{Clss}}>}()}") 391 GenClss<? super Clss> mgenClssWSupClss0() { return null; } 392 393 @Desc(d="()Ljava/lang/Object;", t="M{C{java/lang/Object}()}") 394 @Sig(s="<T:Ljava/lang/Object;>()TT;", t="M{<TA{T:cC{java/lang/Object}}>S{T}()}") 395 <T> T mt0() { return null; } 396 397 @Desc(d="()LGenClss;", t="M{C{GenClss}()}") 398 @Sig(s="<T:Ljava/lang/Object;>()LGenClss<+TT;>;", 399 t="M{<TA{T:cC{java/lang/Object}}>C{GenClss<W{e,S{T}}>}()}") 400 <T> GenClss<? extends T> mgenClssWExtT0() { return null; } 401 402 @Desc(d="()LGenClss;", t="M{C{GenClss}()}") 403 @Sig(s="<T:Ljava/lang/Object;>()LGenClss<-TT;>;", t="M{<TA{T:cC{java/lang/Object}}>C{GenClss<W{s,S{T}}>}()}") 404 <T> GenClss<? super T> mgenClssWSupT0() { return null; } 405 406 // methods, arg types 407 408 @Desc(d="(I)V", t="M{S{void}(S{int})}") 409 void mi1(int arg) { } 410 411 @Desc(d="(LClss;)V", t="M{S{void}(C{Clss})}") 412 void mclss1(Clss arg) { } 413 414 @Desc(d="([I)V", t="M{S{void}(A{S{int}})}") 415 void mai1(int[] arg) { } 416 417 @Desc(d="([LClss;)V", t="M{S{void}(A{C{Clss}})}") 418 void maClss1(Clss[] arg) { } 419 420 @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}") 421 @Sig(s="(LGenClss<LClss;>;)V", t="M{S{void}(C{GenClss<C{Clss}>})}") 422 void mgenClss1(GenClss<Clss> arg) { } 423 424 @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}") 425 @Sig(s="(LGenClss<*>;)V", t="M{S{void}(C{GenClss<W{?}>})}") 426 void mgenClssW1(GenClss<?> arg) { } 427 428 @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}") 429 @Sig(s="(LGenClss<+LClss;>;)V", t="M{S{void}(C{GenClss<W{e,C{Clss}}>})}") 430 void mgenClssWExtClss1(GenClss<? extends Clss> arg) { } 431 432 @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}") 433 @Sig(s="(LGenClss<-LClss;>;)V", t="M{S{void}(C{GenClss<W{s,C{Clss}}>})}") 434 void mgenClssWSupClss1(GenClss<? super Clss> arg) { } 435 436 @Desc(d="(Ljava/lang/Object;)V", t="M{S{void}(C{java/lang/Object})}") 437 @Sig(s="<T:Ljava/lang/Object;>(TT;)V", 438 t="M{<TA{T:cC{java/lang/Object}}>S{void}(S{T})}") 439 <T> void mt1(T arg) { } 440 441 @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}") 442 @Sig(s="<T:Ljava/lang/Object;>(LGenClss<+TT;>;)V", 443 t="M{<TA{T:cC{java/lang/Object}}>S{void}(C{GenClss<W{e,S{T}}>})}") 444 <T> void mgenClssWExtT1(GenClss<? extends T> arg) { } 445 446 @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}") 447 @Sig(s="<T:Ljava/lang/Object;>(LGenClss<-TT;>;)V", 448 t="M{<TA{T:cC{java/lang/Object}}>S{void}(C{GenClss<W{s,S{T}}>})}") 449 <T> void mgenClssWSupT1(GenClss<? super T> arg) { } 450 451 // methods, throws 452 453 @Desc(d="()V", t="M{S{void}()}") 454 void m_E() throws Exception { } 455 456 @Desc(d="()V", t="M{S{void}()}") 457 @Sig(s="<T:Ljava/lang/Throwable;>()V^TT;", 458 t="M{<TA{T:cC{java/lang/Throwable}}>S{void}()S{T}}") 459 <T extends Throwable> void m_T() throws T { } 460 461 // inner classes 462 463 static class X { 464 // no sig 465 class P { } 466 467 @Sig(s="<TQ:Ljava/lang/Object;>LTest$X$P;", 468 t="CS{<TA{TQ:cC{java/lang/Object}}>C{Test$X$P}}") 469 class Q<TQ> extends P { } 470 471 @Sig(s="<TR:Ljava/lang/Object;>LTest$X$Q<TTR;>;", 472 t="CS{<TA{TR:cC{java/lang/Object}}>C{Test$X$Q<S{TR}>}}") 473 class R<TR> extends Q<TR> { } 474 } 475 476 @Sig(s="<TY:Ljava/lang/Object;>Ljava/lang/Object;", 477 t="CS{<TA{TY:cC{java/lang/Object}}>C{java/lang/Object}}") 478 static class Y<TY> { 479 // no sig 480 class P { } 481 482 @Sig(s="<TQ:Ljava/lang/Object;>LTest$Y<TTY;>.P;", 483 t="CS{<TA{TQ:cC{java/lang/Object}}>C{C{Test$Y<S{TY}>}.P}}") 484 class Q<TQ> extends P { } 485 486 @Sig(s="<TR:Ljava/lang/Object;>LTest$Y<TTY;>.Q<TTR;>;", 487 t="CS{<TA{TR:cC{java/lang/Object}}>C{C{Test$Y<S{TY}>}.Q<S{TR}>}}") 488 class R<TR> extends Q<TR> { 489 // no sig 490 class R1 { } 491 492 @Sig(s="<TR2:Ljava/lang/Object;>LTest$Y<TTY;>.R<TTR;>.R1;", 493 t="CS{<TA{TR2:cC{java/lang/Object}}>C{C{C{Test$Y<S{TY}>}.R<S{TR}>}.R1}}") 494 class R2<TR2> extends R1 { } 495 } 496 497 @Sig(s="LTest$Y<TTY;>.Q<TTY;>;", t="C{C{Test$Y<S{TY}>}.Q<S{TY}>}") 498 class S extends Q<TY> { 499 // no sig 500 class S1 { } 501 502 @Sig(s="<TS2:Ljava/lang/Object;>LTest$Y<TTY;>.S.S1;", 503 t="CS{<TA{TS2:cC{java/lang/Object}}>C{C{C{Test$Y<S{TY}>}.S}.S1}}") 504 class S2<TS2> extends S1 { } 505 506 @Sig(s="LTest$Y<TTY;>.S.S2<TTY;>;", 507 t="C{C{C{Test$Y<S{TY}>}.S}.S2<S{TY}>}") 508 class S3 extends S2<TY> { } 509 } 510 } 511} 512 513 514