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