1 /* 2 * Copyright (c) 2014, 2024, 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 outer_class_info_index of local and anonymous class is zero. 28 * @library /tools/lib /tools/javac/lib ../lib 29 * @modules jdk.compiler/com.sun.tools.javac.api 30 * jdk.compiler/com.sun.tools.javac.main 31 * @build toolbox.ToolBox InMemoryFileManager TestResult TestBase 32 * @run main InnerClassesIndexTest 33 */ 34 35 import java.lang.classfile.*; 36 import java.lang.classfile.attribute.*; 37 import java.lang.classfile.constantpool.ClassEntry; 38 import java.io.File; 39 import java.io.FilenameFilter; 40 import java.util.Arrays; 41 import java.util.HashSet; 42 import java.util.Objects; 43 import java.util.Set; 44 import java.util.stream.Collectors; 45 46 47 public class InnerClassesIndexTest extends TestResult { 48 49 public static void main(String[] args) throws TestFailedException { 50 new InnerClassesIndexTest().test(); 51 } 52 53 private boolean isExcluded(String className) { 54 return !className.startsWith(InnerClassesIndexTest.class.getName()) 55 || "InnerClassesIndexTest$Inner".equals(className); 56 } 57 58 private Set<String> getInnerClasses() { 59 FilenameFilter filter = (dir, name) -> name.matches("InnerClassesIndexTest\\$.*\\.class"); 60 return Arrays.stream(Objects.requireNonNull(getClassDir().listFiles(filter))) 61 .map(File::getName) 62 .map(s -> s.replace(".class", "")) 63 .collect(Collectors.toSet()); 64 } 65 66 public void test() throws TestFailedException { 67 try { 68 addTestCase("Source is InnerClassesIndexTest.java"); 69 ClassModel classFile = readClassFile(InnerClassesIndexTest.class); 70 InnerClassesAttribute attr = classFile.findAttribute(Attributes.innerClasses()).orElse(null); 71 72 Set<String> foundClasses = new HashSet<>(); 73 assert attr != null; 74 for (InnerClassInfo info : attr.classes()) { 75 String innerName = info.innerClass().asInternalName(); 76 echo("Testing class : " + innerName); 77 if (isExcluded(innerName)) { 78 echo("Ignored : " + innerName); 79 continue; 80 } 81 foundClasses.add(innerName); 82 ClassEntry out = info.outerClass().orElse(null); 83 checkEquals(out == null? 0: out.index(), 0, 84 "outer_class_info_index of " + innerName); 85 if (innerName.matches("\\$\\d+")) { 86 checkEquals(Objects.requireNonNull(info.innerName().orElse(null)).index(), 0, 87 "inner_name_index of anonymous class"); 88 } 89 } 90 Set<String> expectedClasses = getInnerClasses(); 91 expectedClasses.remove("InnerClassesIndexTest$Inner"); 92 checkEquals(foundClasses, expectedClasses, "All classes are found"); 93 } catch (Exception e) { 94 addFailure(e); 95 } finally { 96 checkStatus(); 97 } 98 } 99 100 static class Inner { 101 } 102 103 Inner inner1 = new Inner() { 104 }; 105 106 static Inner inner2 = new Inner() { 107 }; 108 109 Runnable r = () -> { 110 class Local { 111 } 112 new Local() { 113 }; 114 }; 115 116 public void local() { 117 class Local { 118 } 119 new Local() { 120 }; 121 } 122 123 public InnerClassesIndexTest() { 124 class Local { 125 } 126 new Local() { 127 }; 128 } 129 130 { 131 class Local { 132 } 133 new Local() { 134 }; 135 } 136 137 static { 138 class Local { 139 } 140 new Local() { 141 }; 142 } 143 }