InnerClassesHierarchyTest.java revision 3294:9adfb22ff08f
1/*
2 * Copyright (c) 2014, 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
24/*
25 * @test
26 * @bug 8042251
27 * @summary Test that inner classes have in its inner classes attribute enclosing classes and its immediate members.
28 * @library /tools/lib /tools/javac/lib ../lib
29 * @modules jdk.compiler/com.sun.tools.javac.api
30 *          jdk.compiler/com.sun.tools.javac.file
31 *          jdk.compiler/com.sun.tools.javac.main
32 *          jdk.jdeps/com.sun.tools.classfile
33 *          jdk.jdeps/com.sun.tools.javap
34 * @build TestResult TestBase InMemoryFileManager ToolBox
35 * @run main InnerClassesHierarchyTest
36 */
37
38import com.sun.tools.classfile.*;
39import com.sun.tools.classfile.InnerClasses_attribute.Info;
40
41import java.io.File;
42import java.io.FilenameFilter;
43import java.io.IOException;
44import java.lang.annotation.Annotation;
45import java.util.*;
46import java.util.stream.Collectors;
47
48public class InnerClassesHierarchyTest extends TestResult {
49
50    private final Map<String, Set<String>> innerClasses;
51    private final String outerClassName;
52
53    public InnerClassesHierarchyTest() throws IOException, ConstantPoolException {
54        innerClasses = new HashMap<>();
55        outerClassName = InnerClassesHierarchyTest.class.getSimpleName();
56        File classDir = getClassDir();
57        FilenameFilter filter =
58                (dir, name) -> name.matches(outerClassName + ".*\\.class");
59        for (File file : Arrays.asList(classDir.listFiles(filter))) {
60            ClassFile classFile = readClassFile(file);
61            String className = classFile.getName();
62            for (ConstantPool.CPInfo info : classFile.constant_pool.entries()) {
63                if (info instanceof ConstantPool.CONSTANT_Class_info) {
64                    ConstantPool.CONSTANT_Class_info classInfo =
65                            (ConstantPool.CONSTANT_Class_info) info;
66                    String cpClassName = classInfo.getBaseName();
67                    if (isInnerClass(cpClassName)) {
68                        get(className).add(cpClassName);
69                    }
70                }
71            }
72        }
73    }
74
75    private boolean isInnerClass(String cpClassName) {
76        return cpClassName.contains("$");
77    }
78
79    private Set<String> get(String className) {
80        if (!innerClasses.containsKey(className)) {
81            innerClasses.put(className, new HashSet<>());
82        }
83        return innerClasses.get(className);
84    }
85
86    public static void main(String[] args) throws IOException, ConstantPoolException, TestFailedException {
87        new InnerClassesHierarchyTest().test();
88    }
89
90    private void test() throws TestFailedException {
91        addTestCase("Source file is InnerClassesHierarchyTest.java");
92        try {
93            Queue<String> queue = new LinkedList<>();
94            Set<String> visitedClasses = new HashSet<>();
95            queue.add(outerClassName);
96            while (!queue.isEmpty()) {
97                String currentClassName = queue.poll();
98                if (!currentClassName.startsWith(outerClassName)) {
99                    continue;
100                }
101                ClassFile cf = readClassFile(currentClassName);
102                InnerClasses_attribute attr = (InnerClasses_attribute)
103                        cf.getAttribute(Attribute.InnerClasses);
104                checkNotNull(attr, "Class should not contain "
105                        + "inner classes attribute : " + currentClassName);
106                checkTrue(innerClasses.containsKey(currentClassName),
107                        "map contains class name : " + currentClassName);
108                Set<String> setClasses = innerClasses.get(currentClassName);
109                if (setClasses == null) {
110                    continue;
111                }
112                checkEquals(attr.number_of_classes,
113                        setClasses.size(),
114                        "Check number of inner classes : " + setClasses);
115                for (Info info : attr.classes) {
116                    String innerClassName = info
117                            .getInnerClassInfo(cf.constant_pool).getBaseName();
118                    checkTrue(setClasses.contains(innerClassName),
119                            currentClassName + " contains inner class : "
120                                    + innerClassName);
121                    if (visitedClasses.add(innerClassName)) {
122                        queue.add(innerClassName);
123                    }
124                }
125            }
126            Set<String> allClasses = innerClasses.entrySet().stream()
127                    .flatMap(entry -> entry.getValue().stream())
128                    .collect(Collectors.toSet());
129
130            Set<String> a_b = removeAll(visitedClasses, allClasses);
131            Set<String> b_a = removeAll(allClasses, visitedClasses);
132            checkEquals(visitedClasses, allClasses,
133                    "All classes are found\n"
134                            + "visited - all classes : " + a_b
135                            + "\nall classes - visited : " + b_a);
136        } catch (Exception e) {
137            addFailure(e);
138        } finally {
139            checkStatus();
140        }
141    }
142
143    private Set<String> removeAll(Set<String> set1, Set<String> set2) {
144        Set<String> set = new HashSet<>(set1);
145        set.removeAll(set2);
146        return set;
147    }
148
149    public static class A1 {
150
151        public class B1 {
152        }
153
154        public enum B2 {
155        }
156
157        public interface B3 {
158        }
159
160        public @interface B4 {
161        }
162
163        public void f() {
164            new B1() {
165            };
166            new B3() {
167            };
168            new B4() {
169                @Override
170                public Class<? extends Annotation> annotationType() {
171                    return null;
172                }
173            };
174            class B5 {
175            }
176        }
177
178        Runnable r = () -> {
179            new B1() {
180            };
181            new B3() {
182            };
183            new B4() {
184                @Override
185                public Class<? extends Annotation> annotationType() {
186                    return null;
187                }
188            };
189            class B5 {
190            }
191        };
192    }
193
194    public enum A2 {;
195
196        public class B1 {
197        }
198
199        public enum B2 {
200        }
201
202        public interface B3 {
203        }
204
205        public @interface B4 {
206        }
207
208        public void a2() {
209            new B1() {
210            };
211            new B3() {
212            };
213            new B4() {
214                @Override
215                public Class<? extends Annotation> annotationType() {
216                    return null;
217                }
218            };
219            class B5 {
220            }
221        }
222
223        Runnable r = () -> {
224            new B1() {
225            };
226            new B3() {
227            };
228            new B4() {
229                @Override
230                public Class<? extends Annotation> annotationType() {
231                    return null;
232                }
233            };
234            class B5 {
235            }
236        };
237    }
238
239    public interface A3 {
240
241        public class B1 {
242        }
243
244        public enum B2 {
245        }
246
247        public interface B3 {
248        }
249
250        public @interface B4 {
251        }
252
253        default void a1() {
254            new B1() {
255            };
256            new B3() {
257            };
258            new B4() {
259                @Override
260                public Class<? extends Annotation> annotationType() {
261                    return null;
262                }
263            };
264            class B5 {
265            }
266        }
267
268        static void a2() {
269            new B1() {
270            };
271            new B3() {
272            };
273            new B4() {
274                @Override
275                public Class<? extends Annotation> annotationType() {
276                    return null;
277                }
278            };
279            class B5 {
280            }
281        }
282    }
283
284    public @interface A4 {
285
286        public class B1 {
287        }
288
289        public enum B2 {
290        }
291
292        public interface B3 {
293        }
294
295        public @interface B4 {
296        }
297    }
298
299    {
300        new A1() {
301            class B1 {
302            }
303
304            public void a2() {
305                new B1() {
306                };
307                class B5 {
308                }
309            }
310        };
311        new A3() {
312            class B1 {
313            }
314
315            public void a3() {
316                new B1() {
317                };
318                class B5 {
319                }
320            }
321        };
322        new A4() {
323            @Override
324            public Class<? extends Annotation> annotationType() {
325                return null;
326            }
327
328            class B1 {
329            }
330
331            public void a4() {
332                new B1() {
333                };
334                class B5 {
335                }
336            }
337        };
338        Runnable r = () -> {
339            new A1() {
340            };
341            new A3() {
342            };
343            new A4() {
344                @Override
345                public Class<? extends Annotation> annotationType() {
346                    return null;
347                }
348            };
349            class B5 {
350            }
351        };
352    }
353
354    static {
355        new A1() {
356            class B1 {
357            }
358
359            public void a2() {
360                new B1() {
361                };
362                class B5 {
363                }
364            }
365        };
366        new A3() {
367            class B1 {
368            }
369
370            public void a3() {
371                new B1() {
372                };
373                class B5 {
374                }
375            }
376        };
377        new A4() {
378            @Override
379            public Class<? extends Annotation> annotationType() {
380                return null;
381            }
382
383            class B1 {
384            }
385
386            public void a4() {
387                new B1() {
388                };
389                class B5 {
390                }
391            }
392        };
393        Runnable r = () -> {
394            new A1() {
395            };
396            new A3() {
397            };
398            new A4() {
399                @Override
400                public Class<? extends Annotation> annotationType() {
401                    return null;
402                }
403            };
404            class B5 {
405            }
406        };
407    }
408
409    public void a5() {
410        class A5 {
411
412            class B1 {
413            }
414
415            public void a5() {
416                new B1() {
417                };
418
419                class B5 {
420                }
421            }
422        }
423        Runnable r = () -> {
424            new A1() {
425            };
426            new A3() {
427            };
428            new A4() {
429                @Override
430                public Class<? extends Annotation> annotationType() {
431                    return null;
432                }
433            };
434            class B5 {
435            }
436        };
437    }
438}
439