1 /*
2 * Copyright (c) 2022, 2025, 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 8281323
27 * @summary Check emission of LoadableDescriptors attribute to make sure javac does not emit unneeded entries.
28 * @enablePreview
29 * @run main NoUnnecessaryLoadableDescriptorsTest
30 */
31
32 import java.lang.classfile.Attributes;
33 import java.lang.classfile.ClassFile;
34 import java.lang.classfile.ClassModel;
35 import java.lang.classfile.attribute.LoadableDescriptorsAttribute;
36 import java.lang.classfile.constantpool.Utf8Entry;
37 import java.util.List;
38
39 public class NoUnnecessaryLoadableDescriptorsTest {
40
41 public value class LoadableDescriptorsTest1 {
42 byte b;
43 public LoadableDescriptorsTest1(byte b) {
44 this.b = b;
45 }
46 }
47
48 public class LoadableDescriptorsTest2 {
49 static class Inner1 {
50 static value class Inner2 {}
51 Inner2 inner;
52 }
53 }
54
55 public static void main(String[] args) throws Exception {
56 ClassModel cls;
57 LoadableDescriptorsAttribute loadableDescriptors;
58
59 // There should be no LoadableDescriptors attribute in NoUnnecessaryLoadableDescriptorsTest.class
60 try (var in = NoUnnecessaryLoadableDescriptorsTest.class.getResourceAsStream("NoUnnecessaryLoadableDescriptorsTest.class")) {
61 cls = ClassFile.of().parse(in.readAllBytes());
62 }
63
64 /* Check emission of LoadableDescriptors attribute */
65 if (cls.findAttribute(Attributes.loadableDescriptors()).isPresent()) {
66 throw new AssertionError("Unexpected LoadableDescriptors attribute!");
67 }
68
69 // There should be no LoadableDescriptors attribute in NoUnnecessaryLoadableDescriptorsTest$LoadableDescriptorsTest1.class
70 try (var in = NoUnnecessaryLoadableDescriptorsTest.class.getResourceAsStream("NoUnnecessaryLoadableDescriptorsTest$LoadableDescriptorsTest1.class")) {
71 cls = ClassFile.of().parse(in.readAllBytes());
72 }
73
74 /* Check emission of LoadableDescriptors attribute */
75 if (cls.findAttribute(Attributes.loadableDescriptors()).isPresent()) {
76 throw new AssertionError("Unexpected LoadableDescriptors attribute!");
77 }
78
79 // There should be no LoadableDescriptors attribute in NoUnnecessaryLoadableDescriptorsTest$LoadableDescriptorsTest2.class
80 try (var in = NoUnnecessaryLoadableDescriptorsTest.class.getResourceAsStream("NoUnnecessaryLoadableDescriptorsTest$LoadableDescriptorsTest2.class")) {
81 cls = ClassFile.of().parse(in.readAllBytes());
82 }
83
84 /* Check emission of LoadableDescriptors attribute */
85 if (cls.findAttribute(Attributes.loadableDescriptors()).isPresent()) {
86 throw new AssertionError("Unexpected LoadableDescriptors attribute!");
87 }
88
89 // There should be no LoadableDescriptors attribute in NoUnnecessaryLoadableDescriptorsTest$LoadableDescriptorsTest2$Inner2.class
90 try (var in = NoUnnecessaryLoadableDescriptorsTest.class.getResourceAsStream("NoUnnecessaryLoadableDescriptorsTest$LoadableDescriptorsTest2$Inner1$Inner2.class")) {
91 cls = ClassFile.of().parse(in.readAllBytes());
92 }
93
94 /* Check emission of LoadableDescriptors attribute */
95 if (cls.findAttribute(Attributes.loadableDescriptors()).isPresent()) {
96 throw new AssertionError("Unexpected LoadableDescriptors attribute!");
97 }
98
99 // There should be ONE LoadableDescriptors attribute entry in NoUnnecessaryLoadableDescriptorsTest$LoadableDescriptorsTest2$Inner1.class
100 try (var in = NoUnnecessaryLoadableDescriptorsTest.class.getResourceAsStream("NoUnnecessaryLoadableDescriptorsTest$LoadableDescriptorsTest2$Inner1.class")) {
101 cls = ClassFile.of().parse(in.readAllBytes());
102 }
103
104 if (cls == null) {
105 throw new AssertionError("Could not locate the class files");
106 }
107
108 /* Check emission of LoadableDescriptors attribute */
109 loadableDescriptors = cls.findAttribute(Attributes.loadableDescriptors()).orElseThrow();
110
111 List<String> expected = List.of("LNoUnnecessaryLoadableDescriptorsTest$LoadableDescriptorsTest2$Inner1$Inner2;");
112 List<String> found = loadableDescriptors.loadableDescriptors().stream().map(Utf8Entry::stringValue).toList();
113 if (!expected.equals(found)) {
114 throw new AssertionError("Expected one LoadableDescriptors class entry Inner2, but found " + found);
115 }
116 }
117 }