1/*
2 * Copyright (c) 2016, 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 * @summary tests for module resolution
27 * @library /tools/lib
28 * @modules
29 *      jdk.compiler/com.sun.tools.javac.api
30 *      jdk.compiler/com.sun.tools.javac.main
31 * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase
32 * @run main QueryBeforeEnter
33 */
34
35import java.io.File;
36import java.io.OutputStream;
37import java.nio.file.*;
38import java.util.Arrays;
39import java.util.Set;
40
41import javax.annotation.processing.AbstractProcessor;
42import javax.annotation.processing.RoundEnvironment;
43import javax.annotation.processing.SupportedAnnotationTypes;
44import javax.annotation.processing.SupportedSourceVersion;
45import javax.lang.model.SourceVersion;
46import javax.lang.model.element.TypeElement;
47import javax.tools.JavaCompiler;
48import javax.tools.StandardJavaFileManager;
49import javax.tools.ToolProvider;
50
51// import com.sun.source.util.JavacTask;
52import com.sun.source.util.Plugin;
53import com.sun.source.util.TaskEvent;
54import com.sun.source.util.TaskListener;
55import com.sun.tools.javac.Main;
56
57import toolbox.JavacTask;
58import toolbox.Task;
59import toolbox.ToolBox;
60
61public class QueryBeforeEnter extends ModuleTestBase {
62    public static void main(String... args) throws Exception {
63        QueryBeforeEnter t = new QueryBeforeEnter();
64        t.runTests();
65    }
66
67    @Test
68    public void testEmpty(Path base) throws Exception {
69        JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
70        com.sun.source.util.JavacTask task =
71            (com.sun.source.util.JavacTask) javaCompiler.getTask(null, null, null, null, null, null);
72        TypeElement jlString = task.getElements().getTypeElement("java.lang.String");
73
74        assertNotNull(jlString);
75    }
76
77    @Test
78    public void testUnnamed(Path base) throws Exception {
79        Path moduleSrc = base.resolve("module-src");
80        Path m1 = moduleSrc.resolve("m1x");
81
82        tb.writeJavaFiles(m1,
83                          "module m1x { exports m1x; }",
84                          "package m1x; public class M1 {}");
85
86        Path m2 = moduleSrc.resolve("m2x");
87
88        tb.writeJavaFiles(m2,
89                          "module m2x { exports m2x; }",
90                          "package m2x; public class M2 {}");
91
92        Path modulePath = base.resolve("module-path");
93
94        Files.createDirectories(modulePath);
95
96        new JavacTask(tb)
97                .options("--module-source-path", moduleSrc.toString())
98                .outdir(modulePath)
99                .files(findJavaFiles(moduleSrc))
100                .run()
101                .writeAll();
102
103        Path cpSrc = base.resolve("cp-src");
104
105        tb.writeJavaFiles(cpSrc,
106                          "package cp; public class CP {}");
107
108        Path cp = base.resolve("cp");
109
110        Files.createDirectories(cp);
111
112        new JavacTask(tb)
113                .outdir(cp)
114                .files(findJavaFiles(cpSrc))
115                .run()
116                .writeAll();
117
118        Path src = base.resolve("src");
119
120        tb.writeJavaFiles(src,
121                          "package test; public class Test1 {}",
122                          "package test; public class Test2 {}");
123
124        Path out = base.resolve("out");
125
126        Files.createDirectories(out);
127
128        JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
129        try (StandardJavaFileManager fm = javaCompiler.getStandardFileManager(null, null, null)) {
130            com.sun.source.util.JavacTask task =
131                (com.sun.source.util.JavacTask) javaCompiler.getTask(null,
132                                                              null,
133                                                              d -> { throw new IllegalStateException(d.toString()); },
134                                                              Arrays.asList("--module-path", modulePath.toString(),
135                                                                            "--class-path", cp.toString(),
136                                                                            "-sourcepath", src.toString()),
137                                                              null,
138                                                              fm.getJavaFileObjects(src.resolve("test").resolve("Test2.java")));
139            assertNotNull(task.getElements().getTypeElement("java.lang.String"));
140            assertNotNull(task.getElements().getTypeElement("javax.tools.ToolProvider"));
141            assertNull(task.getElements().getTypeElement("m1x.M1"));
142            assertNull(task.getElements().getTypeElement("m2x.M2"));
143            assertNotNull(task.getElements().getTypeElement("cp.CP"));
144            assertNotNull(task.getElements().getTypeElement("test.Test1"));
145            assertNotNull(task.getElements().getTypeElement("test.Test2"));
146            assertNotNull(task.getElements().getModuleElement("java.base"));
147            assertNotNull(task.getElements().getModuleElement("java.compiler"));
148            assertNull(task.getElements().getModuleElement("m1x"));
149            assertNull(task.getElements().getModuleElement("m2x"));
150        }
151    }
152
153    @Test
154    public void testSingleNamed(Path base) throws Exception {
155        Path moduleSrc = base.resolve("module-src");
156        Path m1 = moduleSrc.resolve("m1x");
157
158        tb.writeJavaFiles(m1,
159                          "module m1x { exports m1x; }",
160                          "package m1x; public class M1 {}");
161
162        Path m2 = moduleSrc.resolve("m2x");
163
164        tb.writeJavaFiles(m2,
165                          "module m2x { exports m2x; }",
166                          "package m2x; public class M2 {}");
167
168        Path modulePath = base.resolve("module-path");
169
170        Files.createDirectories(modulePath);
171
172        new JavacTask(tb)
173                .options("--module-source-path", moduleSrc.toString())
174                .outdir(modulePath)
175                .files(findJavaFiles(moduleSrc))
176                .run()
177                .writeAll();
178
179        Path cpSrc = base.resolve("cp-src");
180
181        tb.writeJavaFiles(cpSrc,
182                          "package cp; public class CP {}");
183
184        Path cp = base.resolve("cp");
185
186        Files.createDirectories(cp);
187
188        new JavacTask(tb)
189                .outdir(cp)
190                .files(findJavaFiles(cpSrc))
191                .run()
192                .writeAll();
193
194        Path src = base.resolve("src");
195
196        tb.writeJavaFiles(src,
197                          "module test { requires java.base; requires m1x; } ",
198                          "package test; public class Test {}");
199
200        Path out = base.resolve("out");
201
202        Files.createDirectories(out);
203
204        JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
205        try (StandardJavaFileManager fm = javaCompiler.getStandardFileManager(null, null, null)) {
206            com.sun.source.util.JavacTask task =
207                (com.sun.source.util.JavacTask) javaCompiler.getTask(null,
208                                                              null,
209                                                              d -> { throw new IllegalStateException(d.toString()); },
210                                                              Arrays.asList("--module-path", modulePath.toString(),
211                                                                            "--class-path", cp.toString(),
212                                                                            "-sourcepath", src.toString()),
213                                                              null,
214                                                              fm.getJavaFileObjects(findJavaFiles(src)));
215            assertNotNull(task.getElements().getTypeElement("java.lang.String"));
216            assertNull(task.getElements().getTypeElement("javax.tools.ToolProvider"));
217            assertNotNull(task.getElements().getTypeElement("m1x.M1"));
218            assertNull(task.getElements().getTypeElement("m2x.M2"));
219            assertNotNull(task.getElements().getTypeElement("test.Test"));
220            assertNotNull(task.getElements().getModuleElement("java.base"));
221            assertNull(task.getElements().getModuleElement("java.compiler"));
222            assertNotNull(task.getElements().getModuleElement("m1x"));
223            assertNull(task.getElements().getModuleElement("m2x"));
224            assertNotNull(task.getElements().getModuleElement("test"));
225        }
226    }
227
228    @Test
229    public void testMultiModule(Path base) throws Exception {
230        Path modulePathSrc = base.resolve("module-path-src");
231        Path m1 = modulePathSrc.resolve("m1x");
232
233        tb.writeJavaFiles(m1,
234                          "module m1x { exports m1x; }",
235                          "package m1x; public class M1 {}");
236
237        Path m2 = modulePathSrc.resolve("m2x");
238
239        tb.writeJavaFiles(m2,
240                          "module m2x { exports m2x; }",
241                          "package m2x; public class M2 {}");
242
243        Path modulePath = base.resolve("module-path");
244
245        Files.createDirectories(modulePath);
246
247        new JavacTask(tb)
248                .options("--module-source-path", modulePathSrc.toString())
249                .outdir(modulePath)
250                .files(findJavaFiles(modulePathSrc))
251                .run()
252                .writeAll();
253
254        Path cpSrc = base.resolve("cp-src");
255
256        tb.writeJavaFiles(cpSrc,
257                          "package cp; public class CP {}");
258
259        Path cp = base.resolve("cp");
260
261        Files.createDirectories(cp);
262
263        new JavacTask(tb)
264                .outdir(cp)
265                .files(findJavaFiles(cpSrc))
266                .run()
267                .writeAll();
268
269        Path moduleSrc = base.resolve("module-src");
270        Path m3 = moduleSrc.resolve("m3x");
271
272        tb.writeJavaFiles(m3,
273                          "module m3x { requires m1x; exports m3x; }",
274                          "package m3x; public class M3 {  }");
275
276        Path m4 = moduleSrc.resolve("m4x");
277
278        tb.writeJavaFiles(m4,
279                          "module m4x { exports m4x; }",
280                          "package m4x; public class M4 {}");
281
282        Path out = base.resolve("out");
283
284        Files.createDirectories(out);
285
286        JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
287        try (StandardJavaFileManager fm = javaCompiler.getStandardFileManager(null, null, null)) {
288            com.sun.source.util.JavacTask task =
289                (com.sun.source.util.JavacTask) javaCompiler.getTask(null,
290                                                              null,
291                                                              d -> { throw new IllegalStateException(d.toString()); },
292                                                              Arrays.asList("--module-path", modulePath.toString(),
293                                                                            "--class-path", cp.toString(),
294                                                                            "--module-source-path", moduleSrc.toString(),
295                                                                            "-d", out.toString()),
296                                                              null,
297                                                              fm.getJavaFileObjects(findJavaFiles(moduleSrc)));
298            assertNotNull(task.getElements().getTypeElement("java.lang.String"));
299            assertNull(task.getElements().getTypeElement("javax.tools.ToolProvider"));
300            assertNotNull(task.getElements().getTypeElement("m1x.M1"));
301            assertNull(task.getElements().getTypeElement("m2x.M2"));
302            assertNotNull(task.getElements().getTypeElement("m3x.M3"));
303            assertNotNull(task.getElements().getTypeElement("m4x.M4"));
304            assertNotNull(task.getElements().getModuleElement("java.base"));
305            assertNull(task.getElements().getModuleElement("java.compiler"));
306            assertNotNull(task.getElements().getModuleElement("m1x"));
307            assertNull(task.getElements().getModuleElement("m2x"));
308            assertNotNull(task.getElements().getModuleElement("m3x"));
309            assertNotNull(task.getElements().getModuleElement("m4x"));
310        }
311    }
312
313    @Test
314    public void testTooSoon(Path base) throws Exception {
315        Path src = base.resolve("src");
316
317        tb.writeJavaFiles(src,
318                          "package test; public class Test {}");
319
320        Path out = base.resolve("out");
321
322        Files.createDirectories(out);
323
324        Path reg = base.resolve("reg");
325        Path regFile = reg.resolve("META-INF").resolve("services").resolve(Plugin.class.getName());
326
327        Files.createDirectories(regFile.getParent());
328
329        try (OutputStream regOut = Files.newOutputStream(regFile)) {
330            regOut.write(PluginImpl.class.getName().getBytes());
331        }
332
333        String processorPath = System.getProperty("test.class.path") + File.pathSeparator + reg.toString();
334
335        JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
336        Path testSource = src.resolve("test").resolve("Test.java");
337        try (StandardJavaFileManager fm = javaCompiler.getStandardFileManager(null, null, null)) {
338            com.sun.source.util.JavacTask task =
339                (com.sun.source.util.JavacTask) javaCompiler.getTask(null,
340                                                              null,
341                                                              d -> { throw new IllegalStateException(d.toString()); },
342                                                              Arrays.asList("--processor-path", processorPath,
343                                                                            "-processor", AP.class.getName(),
344                                                                            "-Xplugin:test"),
345                                                              null,
346                                                              fm.getJavaFileObjects(testSource));
347            task.call();
348        }
349
350        Main.compile(new String[] {"--processor-path", processorPath,
351                                   "-Xplugin:test",
352                                   testSource.toString()});
353    }
354
355    public static class PluginImpl implements Plugin {
356
357        @Override
358        public String getName() {
359            return "test";
360        }
361
362        @Override
363        public void init(com.sun.source.util.JavacTask task, String... args) {
364            task.addTaskListener(new TaskListener() {
365                boolean wasEntered;
366                @Override
367                public void started(TaskEvent e) {
368                    switch (e.getKind()) {
369                        case COMPILATION: case PARSE:
370                            shouldFail(e.getKind());
371                            break;
372                        case ANNOTATION_PROCESSING: case ENTER:
373                            if (wasEntered) {
374                                shouldPass(e.getKind());
375                            } else {
376                                shouldFail(e.getKind());
377                            }
378                            break;
379                        default:
380                            shouldPass(e.getKind());
381                            break;
382                    }
383                }
384                @Override
385                public void finished(TaskEvent e) {
386                    switch (e.getKind()) {
387                        case PARSE:
388                            shouldFail(e.getKind());
389                            break;
390                        case ENTER:
391                            wasEntered = true;
392                            //fall-through:
393                        default:
394                            shouldPass(e.getKind());
395                            break;
396                    }
397                }
398                private void shouldFail(TaskEvent.Kind kind) {
399                    try {
400                        task.getElements().getTypeElement("java.lang.String");
401                        throw new AssertionError("Expected exception not observed; kind=" + kind.name());
402                    } catch (IllegalStateException ex) {
403                        //correct
404                    }
405                }
406                private void shouldPass(TaskEvent.Kind kind) {
407                    assertNotNull(task.getElements().getTypeElement("java.lang.String"));
408                }
409            });
410
411        }
412
413    }
414
415    @SupportedAnnotationTypes("*")
416    public static final class AP extends AbstractProcessor {
417
418        @Override
419        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
420            return false;
421        }
422
423        @Override
424        public SourceVersion getSupportedSourceVersion() {
425            return SourceVersion.latest();
426        }
427
428    }
429
430    private static void assertNotNull(Object actual) {
431        if (actual == null) {
432            throw new AssertionError("unexpected null!");
433        }
434    }
435
436    private static void assertNull(Object actual) {
437        if (actual != null) {
438            throw new AssertionError("unexpected non null!");
439        }
440    }
441
442}
443