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