AnonymousClassFlags.java revision 3537:22e5938706c2
1/*
2 * Copyright (c) 2016, 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
24/*
25 * @test
26 * @bug 8161013
27 * @summary Verify that anonymous class binaries have the correct flags set
28 * @modules jdk.jdeps/com.sun.tools.classfile
29 * @run main AnonymousClassFlags
30 */
31
32import java.util.*;
33import java.nio.file.Path;
34import java.nio.file.Paths;
35
36import com.sun.tools.classfile.*;
37import static com.sun.tools.classfile.AccessFlags.*;
38
39public class AnonymousClassFlags {
40    public static void main(String[] args) throws Exception {
41        new AnonymousClassFlags().test(System.getProperty("test.classes", "."));
42    }
43
44    /** Maps names of anonymous classes to their expected inner_class_access_flags */
45    private static Map<String, Integer> anonClasses = new LinkedHashMap<>();
46
47    // ******* TEST CASES ********
48
49    static Object o1 = new Object() {
50        { anonClasses.put(getClass().getName(), 0); }
51    };
52
53    static void staticMethod() {
54        Object o2 = new Object() {
55            { anonClasses.put(getClass().getName(), 0); }
56        };
57    }
58
59    static {
60        staticMethod();
61
62        Object o3 = new Object() {
63            { anonClasses.put(getClass().getName(), 0); }
64        };
65    }
66
67    Object o4 = new Object() {
68        { anonClasses.put(getClass().getName(), 0); }
69    };
70
71    void instanceMethod() {
72        Object o5 = new Object() {
73            { anonClasses.put(getClass().getName(), 0); }
74        };
75    }
76
77    {
78        instanceMethod();
79
80        Object o6 = new Object() {
81            { anonClasses.put(getClass().getName(), 0); }
82        };
83    }
84
85    // ******* TEST IMPLEMENTATION ********
86
87    void test(String classesDir) throws Exception {
88        staticMethod();
89        instanceMethod();
90
91        Path outerFile = Paths.get(classesDir, getClass().getName() + ".class");
92        ClassFile outerClass = ClassFile.read(outerFile);
93        for (Map.Entry<String,Integer> entry : anonClasses.entrySet()) {
94            Path innerFile = Paths.get(classesDir, entry.getKey() + ".class");
95            ClassFile innerClass = ClassFile.read(innerFile);
96            String name = entry.getKey();
97            int expected = entry.getValue();
98            assertInnerFlags(outerClass, name, expected);
99            assertClassFlags(innerClass, name, expected);
100            assertInnerFlags(innerClass, name, expected);
101        }
102    }
103
104    static void assertClassFlags(ClassFile classFile, String name, int expected) {
105        int mask = ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT |
106                   ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM;
107        int classExpected = (expected & mask) | ACC_SUPER;
108        int classActual = classFile.access_flags.flags;
109        if (classActual != classExpected) {
110            throw new AssertionError("Incorrect access_flags for class " + name +
111                                     ": expected=" + classExpected + ", actual=" + classActual);
112        }
113
114    }
115
116    static void assertInnerFlags(ClassFile classFile, String name, int expected) throws ConstantPoolException {
117        int innerActual = lookupInnerFlags(classFile, name).flags;
118        if (innerActual != expected) {
119            throw new AssertionError("Incorrect inner_class_access_flags for class " + name +
120                                     " in class " + classFile.getName() +
121                                     ": expected=" + expected + ", actual=" + innerActual);
122        }
123    }
124
125    private static AccessFlags lookupInnerFlags(ClassFile classFile, String innerName) throws ConstantPoolException {
126        InnerClasses_attribute inners = (InnerClasses_attribute) classFile.getAttribute("InnerClasses");
127        if (inners == null) {
128            throw new AssertionError("InnerClasses attribute missing in class " + classFile.getName());
129        }
130        for (InnerClasses_attribute.Info info : inners.classes) {
131            String entryName = info.getInnerClassInfo(classFile.constant_pool).getName();
132            if (innerName.equals(entryName)) {
133                return info.inner_class_access_flags;
134            }
135        }
136        throw new AssertionError("No InnerClasses entry in class " + classFile.getName() + " for class " + innerName);
137    }
138
139}
140