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