1 /*
2  * Copyright (c) 2018, 2021, 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 8193717
27  * @summary Check that code with a lot named imports can compile.
28  * @library /tools/lib
29  * @modules jdk.jdeps/com.sun.tools.classfile
30  *          jdk.compiler/com.sun.tools.javac.api
31  *          jdk.compiler/com.sun.tools.javac.main
32  *          jdk.jdeps/com.sun.tools.javap
33  * @build toolbox.ToolBox toolbox.JavapTask
34  * @run main T8193717
35  */
36 
37 import java.io.ByteArrayInputStream;
38 import java.io.ByteArrayOutputStream;
39 import java.io.IOException;
40 import java.io.InputStream;
41 import java.net.URI;
42 import java.net.URISyntaxException;
43 import java.nio.file.Paths;
44 import java.util.ArrayList;
45 import java.util.List;
46 import java.util.Set;
47 
48 import javax.tools.ForwardingJavaFileManager;
49 import javax.tools.JavaCompiler;
50 import javax.tools.JavaFileManager;
51 import javax.tools.JavaFileObject;
52 import javax.tools.JavaFileObject.Kind;
53 import javax.tools.SimpleJavaFileObject;
54 import javax.tools.StandardJavaFileManager;
55 import javax.tools.StandardLocation;
56 import javax.tools.ToolProvider;
57 
58 import com.sun.tools.classfile.AccessFlags;
59 import com.sun.tools.classfile.Attribute;
60 import com.sun.tools.classfile.Attributes;
61 import com.sun.tools.classfile.ClassFile;
62 import com.sun.tools.classfile.ClassWriter;
63 import com.sun.tools.classfile.ConstantPool;
64 import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info;
65 import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info;
66 import com.sun.tools.classfile.ConstantPool.CPInfo;
67 import com.sun.tools.classfile.Field;
68 import com.sun.tools.classfile.Method;
69 
70 import toolbox.JavacTask;
71 import toolbox.ToolBox;
72 
73 public class T8193717 {
main(String... args)74     public static void main(String... args) throws IOException {
75         new T8193717().run();
76     }
77 
78     private static final int CLASSES = 50000;
79 
run()80     private void run() throws IOException {
81         StringBuilder imports = new StringBuilder();
82         StringBuilder use = new StringBuilder();
83 
84         for (int c = 0; c < CLASSES; c++) {
85             String simpleName = getSimpleName(c);
86             String pack = "p";
87             imports.append("import " + pack + "." + simpleName + ";\n");
88             use.append(simpleName + " " + simpleName + ";\n");
89         }
90         String source = imports.toString() + "public class T {\n" + use.toString() + "}";
91         ToolBox tb = new ToolBox();
92         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
93 
94         try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
95             fm.setLocationFromPaths(StandardLocation.CLASS_OUTPUT, List.of(Paths.get(".")));
96             new JavacTask(tb).sources(source)
97                              .options("-XDshould-stop.ifError=ATTR",
98                                       "-XDshould-stop.ifNoError=ATTR") //the source is too big for a classfile
99                              .fileManager(new TestJFM(fm))
100                              .run();
101         }
102     }
103 
getSimpleName(int c)104     private static String getSimpleName(int c) {
105         return "T" + String.format("%0" + (int) Math.ceil(Math.log10(CLASSES)) + "d", c);
106     }
107 
generateClassFile(String name)108     private byte[] generateClassFile(String name) throws IOException {
109         ConstantPool cp = new ConstantPool(new CPInfo[] {
110             new CONSTANT_Utf8_info(""),                     //0
111             new CONSTANT_Utf8_info(name.replace(".", "/")), //1
112             new CONSTANT_Class_info(null, 1),               //2
113             new CONSTANT_Utf8_info("java/lang/Object"),     //3
114             new CONSTANT_Class_info(null, 3),               //4
115         });
116         ClassFile cf = new ClassFile(0xCAFEBABE,
117                       0,
118                       51,
119                       cp,
120                       new AccessFlags(AccessFlags.ACC_ABSTRACT |
121                                       AccessFlags.ACC_INTERFACE |
122                                       AccessFlags.ACC_PUBLIC),
123                       2,
124                       4,
125                       new int[0],
126                       new Field[0],
127                       new Method[0],
128                       new Attributes(cp, new Attribute[0]));
129         ByteArrayOutputStream baos = new ByteArrayOutputStream();
130         new ClassWriter().write(cf, baos);
131         return baos.toByteArray();
132     }
133 
134     final class TestJFM extends ForwardingJavaFileManager<JavaFileManager> {
135 
TestJFM(JavaFileManager fileManager)136         public TestJFM(JavaFileManager fileManager) {
137             super(fileManager);
138         }
139 
140         @Override
list(Location location, String packageName, Set<Kind> kinds, boolean recurse)141         public Iterable<JavaFileObject> list(Location location, String packageName,
142                                              Set<Kind> kinds, boolean recurse) throws IOException {
143             if (location == StandardLocation.CLASS_PATH) {
144                 if (packageName.equals("p")) {
145                     try {
146                         List<JavaFileObject> result = new ArrayList<>(CLASSES);
147 
148                         for (int c = 0; c < CLASSES; c++) {
149                             result.add(new TestJFO("p." + getSimpleName(c)));
150                         }
151 
152                         return result;
153                     } catch (URISyntaxException ex) {
154                         throw new IllegalStateException(ex);
155                     }
156                 }
157             }
158             return super.list(location, packageName, kinds, recurse);
159         }
160 
161         @Override
inferBinaryName(Location location, JavaFileObject file)162         public String inferBinaryName(Location location, JavaFileObject file) {
163             if (file instanceof TestJFO) {
164                 return ((TestJFO) file).name;
165             }
166             return super.inferBinaryName(location, file);
167         }
168 
169         private class TestJFO extends SimpleJavaFileObject {
170 
171             private final String name;
172 
TestJFO(String name)173             public TestJFO(String name) throws URISyntaxException {
174                 super(new URI("mem://" + name.replace(".", "/") + ".class"), Kind.CLASS);
175                 this.name = name;
176             }
177 
178             @Override
openInputStream()179             public InputStream openInputStream() throws IOException {
180                 return new ByteArrayInputStream(generateClassFile(name));
181             }
182         }
183 
184     }
185 }
186