ConvenientAccessErrorsTest.java revision 3994:2815405955ee
1/*
2 * Copyright (c) 2016, 2017, 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 8169197 8172668 8173117 8175007
27 * @summary Check convenient errors are produced for inaccessible classes.
28 * @library /tools/lib
29 * @modules jdk.compiler/com.sun.tools.javac.api
30 *          jdk.compiler/com.sun.tools.javac.main
31 *          jdk.compiler/com.sun.tools.javac.util
32 * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask ModuleTestBase
33 * @run main ConvenientAccessErrorsTest
34 */
35
36import java.nio.file.Files;
37import java.nio.file.Path;
38import java.util.Arrays;
39import java.util.List;
40
41import com.sun.tools.javac.util.Context;
42import com.sun.tools.javac.util.Convert;
43import com.sun.tools.javac.util.Name;
44import com.sun.tools.javac.util.Names;
45import toolbox.JarTask;
46import toolbox.JavacTask;
47import toolbox.Task;
48
49public class ConvenientAccessErrorsTest extends ModuleTestBase {
50
51    public static void main(String... args) throws Exception {
52        new ConvenientAccessErrorsTest().runTests();
53    }
54
55    @Test
56    public void testNoDep(Path base) throws Exception {
57        Path src = base.resolve("src");
58        Path src_m1 = src.resolve("m1x");
59        tb.writeJavaFiles(src_m1,
60                          "module m1x { exports api; }",
61                          "package api; public class Api { public void call() { } }");
62        Path src_m2 = src.resolve("m2x");
63        tb.writeJavaFiles(src_m2,
64                          "module m2x { }",
65                          "package test; public class Test { api.Api api; }");
66        Path classes = base.resolve("classes");
67        tb.createDirectories(classes);
68
69        List<String> log = new JavacTask(tb)
70                .options("-XDrawDiagnostics",
71                         "--module-source-path", src.toString())
72                .outdir(classes)
73                .files(findJavaFiles(src))
74                .run(Task.Expect.FAIL)
75                .writeAll()
76                .getOutputLines(Task.OutputKind.DIRECT);
77
78        List<String> expected = Arrays.asList(
79                "Test.java:1:35: compiler.err.package.not.visible: api, (compiler.misc.not.def.access.does.not.read: m2x, api, m1x)",
80                "1 error");
81
82        if (!expected.equals(log))
83            throw new Exception("expected output not found; actual: " + log);
84    }
85
86    @Test
87    public void testNoDepNested(Path base) throws Exception {
88        Path src = base.resolve("src");
89        Path src_m1 = src.resolve("m1x");
90        tb.writeJavaFiles(src_m1,
91                          "module m1x { exports api; }",
92                          "package api; public class Api { public static class Nested {} }");
93        Path src_m2 = src.resolve("m2x");
94        tb.writeJavaFiles(src_m2,
95                          "module m2x { }",
96                          "package test; public class Test { api.Api.Nested nested; }");
97        Path classes = base.resolve("classes");
98        tb.createDirectories(classes);
99
100        List<String> log = new JavacTask(tb)
101                .options("-XDrawDiagnostics",
102                         "--module-source-path", src.toString())
103                .outdir(classes)
104                .files(findJavaFiles(src))
105                .run(Task.Expect.FAIL)
106                .writeAll()
107                .getOutputLines(Task.OutputKind.DIRECT);
108
109        List<String> expected = Arrays.asList(
110                "Test.java:1:35: compiler.err.package.not.visible: api, (compiler.misc.not.def.access.does.not.read: m2x, api, m1x)",
111                "1 error");
112
113        if (!expected.equals(log))
114            throw new Exception("expected output not found; actual: " + log);
115    }
116
117    @Test
118    public void testNotExported(Path base) throws Exception {
119        Path src = base.resolve("src");
120        Path src_m1 = src.resolve("m1x");
121        tb.writeJavaFiles(src_m1,
122                          "module m1x { exports api; }",
123                          "package api; public class Api { }",
124                          "package impl; public class Impl { }");
125        Path src_m2 = src.resolve("m2x");
126        tb.writeJavaFiles(src_m2,
127                          "module m2x { requires m1x; }",
128                          "package test; public class Test { impl.Impl api; }");
129        Path src_m3 = src.resolve("m3x");
130        tb.writeJavaFiles(src_m3,
131                          "module m3x { requires m1x; }");
132        Path classes = base.resolve("classes");
133        tb.createDirectories(classes);
134
135        List<String> log = new JavacTask(tb)
136                .options("-XDrawDiagnostics",
137                         "--module-source-path", src.toString())
138                .outdir(classes)
139                .files(findJavaFiles(src))
140                .run(Task.Expect.FAIL)
141                .writeAll()
142                .getOutputLines(Task.OutputKind.DIRECT);
143
144        List<String> expected = Arrays.asList(
145                "Test.java:1:35: compiler.err.package.not.visible: impl, (compiler.misc.not.def.access.not.exported: impl, m1x)",
146                "1 error");
147
148        if (!expected.equals(log))
149            throw new Exception("expected output not found; actual: " + log);
150
151        tb.writeJavaFiles(src_m1,
152                          "module m1x { exports api; exports impl to m3x;}");
153
154        log = new JavacTask(tb)
155                .options("-XDrawDiagnostics",
156                         "--module-source-path", src.toString())
157                .outdir(classes)
158                .files(findJavaFiles(src))
159                .run(Task.Expect.FAIL)
160                .writeAll()
161                .getOutputLines(Task.OutputKind.DIRECT);
162
163        expected = Arrays.asList(
164                "Test.java:1:35: compiler.err.package.not.visible: impl, (compiler.misc.not.def.access.not.exported.to.module: impl, m1x, m2x)",
165                "1 error");
166
167        if (!expected.equals(log))
168            throw new Exception("expected output not found; actual: " + log);
169    }
170
171    @Test
172    public void testInaccessibleInExported(Path base) throws Exception {
173        Path src = base.resolve("src");
174        Path src_m1 = src.resolve("m1x");
175        tb.writeJavaFiles(src_m1,
176                          "module m1x { exports api; }",
177                          "package api; class Api { }");
178        Path src_m2 = src.resolve("m2x");
179        tb.writeJavaFiles(src_m2,
180                          "module m2x { requires m1x; }",
181                          "package test; public class Test { api.Api api; }");
182        Path classes = base.resolve("classes");
183        tb.createDirectories(classes);
184
185        List<String> log = new JavacTask(tb)
186                .options("-XDrawDiagnostics",
187                         "--module-source-path", src.toString())
188                .outdir(classes)
189                .files(findJavaFiles(src))
190                .run(Task.Expect.FAIL)
191                .writeAll()
192                .getOutputLines(Task.OutputKind.DIRECT);
193
194        List<String> expected = Arrays.asList(
195                "Test.java:1:38: compiler.err.not.def.public.cant.access: api.Api, api",
196                "1 error");
197
198        if (!expected.equals(log))
199            throw new Exception("expected output not found; actual: " + log);
200    }
201
202//    @Test
203    public void testInaccessibleUnnamedModule(Path base) throws Exception {
204        Path jar = prepareTestJar(base, "package api; class Api { public static class Foo {} }");
205
206        Path moduleSrc = base.resolve("module-src");
207        Path m1x = moduleSrc.resolve("m1x");
208
209        Path classes = base.resolve("classes");
210
211        Files.createDirectories(classes);
212
213        tb.writeJavaFiles(m1x,
214                          "module m1x { }",
215                          "package test; public class Test { api.Api api; api.Api.Foo api; }");
216
217        List<String> log = new JavacTask(tb)
218                .options("-classpath", jar.toString(),
219                         "-XDrawDiagnostics")
220                .outdir(classes)
221                .files(findJavaFiles(moduleSrc))
222                .run(Task.Expect.FAIL)
223                .writeAll()
224                .getOutputLines(Task.OutputKind.DIRECT);
225
226        List<String> expected = Arrays.asList(
227                "Test.java:1:38: compiler.err.not.def.access.package.cant.access: api.Api, api, (compiler.misc.not.def.access.does.not.read.unnamed: api, m1x)",
228                "Test.java:1:51: compiler.err.not.def.access.package.cant.access: api.Api, api, (compiler.misc.not.def.access.does.not.read.unnamed: api, m1x)",
229                "2 errors");
230
231        if (!expected.equals(log))
232            throw new Exception("expected output not found; actual: " + log);
233    }
234
235    @Test
236    public void testIndirectReferenceToUnnamedModule(Path base) throws Exception {
237        Path jar = prepareTestJar(base, "package api; public class Api { public void test() {} }");
238
239        Path moduleSrc = base.resolve("module-src");
240        Path m1x = moduleSrc.resolve("m1x");
241        Path auxiliary = moduleSrc.resolve("auxiliary");
242
243        Path classes = base.resolve("classes");
244
245        Files.createDirectories(classes);
246
247        tb.writeJavaFiles(m1x,
248                          "module m1x { requires auxiliary; }",
249                          "package test; public class Test { { auxiliary.Auxiliary.get().test(); } }");
250
251        tb.writeJavaFiles(auxiliary,
252                          "module auxiliary { exports auxiliary; }",
253                          "package auxiliary; public class Auxiliary { public static api.Api get() { return null; } }");
254
255        List<String> log = new JavacTask(tb)
256                .options("-classpath", jar.toString(),
257                         "-XDrawDiagnostics",
258                         "--add-reads", "auxiliary=ALL-UNNAMED",
259                         "--module-source-path", moduleSrc.toString())
260                .outdir(classes)
261                .files(findJavaFiles(moduleSrc))
262                .run(Task.Expect.FAIL)
263                .writeAll()
264                .getOutputLines(Task.OutputKind.DIRECT);
265
266        List<String> expected = Arrays.asList(
267                "Test.java:1:62: compiler.err.not.def.access.class.intf.cant.access.reason: test(), api.Api, api, (compiler.misc.not.def.access.does.not.read.unnamed: api, m1x)",
268                "1 error");
269
270        if (!expected.equals(log))
271            throw new Exception("expected output not found; actual: " + log);
272    }
273
274    private Path prepareTestJar(Path base, String code) throws Exception {
275        Path legacySrc = base.resolve("legacy-src");
276        tb.writeJavaFiles(legacySrc, code);
277        Path legacyClasses = base.resolve("legacy-classes");
278        Files.createDirectories(legacyClasses);
279
280        String log = new JavacTask(tb)
281                .options()
282                .outdir(legacyClasses)
283                .files(findJavaFiles(legacySrc))
284                .run()
285                .writeAll()
286                .getOutput(Task.OutputKind.DIRECT);
287
288        if (!log.isEmpty()) {
289            throw new Exception("unexpected output: " + log);
290        }
291
292        Path lib = base.resolve("lib");
293
294        Files.createDirectories(lib);
295
296        Path jar = lib.resolve("test-api-1.0.jar");
297
298        new JarTask(tb, jar)
299          .baseDir(legacyClasses)
300          .files("api/Api.class")
301          .run();
302
303        return jar;
304    }
305
306    @Test
307    public void testUnnamedModuleAccess(Path base) throws Exception {
308        Path src = base.resolve("src");
309        Path src_m1 = src.resolve("m1x");
310        tb.writeJavaFiles(src_m1,
311                          "module m1x { exports api to m2x; }",
312                          "package api; class Api { }",
313                          "package impl; class Impl { }");
314        Path src_m2 = src.resolve("m2x");
315        tb.writeJavaFiles(src_m2,
316                          "module m2x { requires m1x; }");
317        Path modulepath = base.resolve("modulepath");
318        tb.createDirectories(modulepath);
319
320        new JavacTask(tb)
321                .options("--module-source-path", src.toString())
322                .outdir(modulepath)
323                .files(findJavaFiles(src))
324                .run()
325                .writeAll();
326
327        Path unnamedSrc = base.resolve("unnamedSrc");
328        tb.writeJavaFiles(unnamedSrc,
329                          "public class Test { api.Api api; impl.Impl impl; }");
330        Path unnamedClasses = base.resolve("unnamed-classes");
331        Files.createDirectories(unnamedClasses);
332
333        List<String> log = new JavacTask(tb)
334                .options("--module-path", modulepath.toString(),
335                         "-XDrawDiagnostics")
336                .outdir(unnamedClasses)
337                .files(findJavaFiles(unnamedSrc))
338                .run(Task.Expect.FAIL)
339                .writeAll()
340                .getOutputLines(Task.OutputKind.DIRECT);
341
342        List<String> expected = Arrays.asList(
343                "Test.java:1:21: compiler.err.package.not.visible: api, (compiler.misc.not.def.access.does.not.read.from.unnamed: api, m1x)",
344                "Test.java:1:34: compiler.err.package.not.visible: impl, (compiler.misc.not.def.access.does.not.read.from.unnamed: impl, m1x)",
345                "2 errors"
346        );
347
348        if (!expected.equals(log)) {
349            throw new Exception("unexpected output: " + log);
350        }
351
352        log = new JavacTask(tb)
353                .options("--module-path", modulepath.toString(),
354                         "--add-modules", "m1x",
355                         "-XDrawDiagnostics")
356                .outdir(unnamedClasses)
357                .files(findJavaFiles(unnamedSrc))
358                .run(Task.Expect.FAIL)
359                .writeAll()
360                .getOutputLines(Task.OutputKind.DIRECT);
361
362        expected = Arrays.asList(
363                "Test.java:1:21: compiler.err.package.not.visible: api, (compiler.misc.not.def.access.not.exported.to.module.from.unnamed: api, m1x)",
364                "Test.java:1:34: compiler.err.package.not.visible: impl, (compiler.misc.not.def.access.not.exported.from.unnamed: impl, m1x)",
365                "2 errors"
366        );
367
368        if (!expected.equals(log)) {
369            throw new Exception("unexpected output: " + log);
370        }
371    }
372
373    @Test
374    public void testInImport(Path base) throws Exception {
375        Path src = base.resolve("src");
376        Path src_m1 = src.resolve("m1x");
377        tb.writeJavaFiles(src_m1,
378                          "module m1x { }",
379                          "package api; public class Api { public String test() { return null; } }");
380        Path src_m2 = src.resolve("m2x");
381        tb.writeJavaFiles(src_m2,
382                          "module m2x { requires m1x; }",
383                          "package test; import api.Api; public class Test { Api api; { api.test().length(); } }");
384        Path classes = base.resolve("classes");
385        tb.createDirectories(classes);
386
387        List<String> log = new JavacTask(tb)
388                .options("-XDrawDiagnostics",
389                         "--module-source-path", src.toString())
390                .outdir(classes)
391                .files(findJavaFiles(src))
392                .run(Task.Expect.FAIL)
393                .writeAll()
394                .getOutputLines(Task.OutputKind.DIRECT);
395
396        List<String> expected = Arrays.asList(
397                "Test.java:1:22: compiler.err.package.not.visible: api, (compiler.misc.not.def.access.not.exported: api, m1x)",
398                "1 error");
399
400        if (!expected.equals(log))
401            throw new Exception("expected output not found; actual: " + log);
402    }
403
404    @Test
405    public void testInImportOnDemand(Path base) throws Exception {
406        Path src = base.resolve("src");
407        Path src_m1 = src.resolve("m1x");
408        tb.writeJavaFiles(src_m1,
409                          "module m1x { }",
410                          "package api; public class Api { public String test() { return null; } }");
411        Path src_m2 = src.resolve("m2x");
412        tb.writeJavaFiles(src_m2,
413                          "module m2x { requires m1x; }",
414                          "package test; import api.*; public class Test { Api api; { api.test().length(); } }");
415        Path classes = base.resolve("classes");
416        tb.createDirectories(classes);
417
418        List<String> log = new JavacTask(tb)
419                .options("-XDrawDiagnostics",
420                         "--module-source-path", src.toString())
421                .outdir(classes)
422                .files(findJavaFiles(src))
423                .run(Task.Expect.FAIL)
424                .writeAll()
425                .getOutputLines(Task.OutputKind.DIRECT);
426
427        List<String> expected = Arrays.asList(
428                "Test.java:1:22: compiler.err.package.not.visible: api, (compiler.misc.not.def.access.not.exported: api, m1x)",
429                "1 error");
430
431        if (!expected.equals(log))
432            throw new Exception("expected output not found; actual: " + log);
433    }
434
435    @Test
436    public void testUnusedImportOnDemand1(Path base) throws Exception {
437        Path src = base.resolve("src");
438        tb.writeJavaFiles(src,
439                          "package test; import javax.annotation.*; public class Test { }");
440        Path classes = base.resolve("classes");
441        tb.createDirectories(classes);
442
443        List<String> log = new JavacTask(tb)
444                .options("-XDrawDiagnostics",
445                         "--add-modules", "java.compiler")
446                .outdir(classes)
447                .files(findJavaFiles(src))
448                .run()
449                .writeAll()
450                .getOutputLines(Task.OutputKind.DIRECT);
451
452        List<String> expected = Arrays.asList("");
453
454        if (!expected.equals(log))
455            throw new Exception("expected output not found; actual: " + log);
456    }
457
458    @Test
459    public void testUnusedImportOnDemand2(Path base) throws Exception {
460        Path src = base.resolve("src");
461        Path src_m1 = src.resolve("m1x");
462        tb.writeJavaFiles(src_m1,
463                          "module m1x { }",
464                          "package api; public class Api { }");
465        Path src_m2 = src.resolve("m2x");
466        tb.writeJavaFiles(src_m2,
467                          "module m2x { requires m1x; }",
468                          "package test; import api.*; public class Test { }");
469        Path classes = base.resolve("classes");
470        tb.createDirectories(classes);
471
472        List<String> log = new JavacTask(tb)
473                .options("-XDrawDiagnostics",
474                         "--module-source-path", src.toString())
475                .outdir(classes)
476                .files(findJavaFiles(src))
477                .run(Task.Expect.FAIL)
478                .writeAll()
479                .getOutputLines(Task.OutputKind.DIRECT);
480
481        List<String> expected = Arrays.asList(
482                "Test.java:1:22: compiler.err.package.not.visible: api, (compiler.misc.not.def.access.not.exported: api, m1x)",
483                "1 error");
484
485        if (!expected.equals(log))
486            throw new Exception("expected output not found; actual: " + log);
487    }
488
489    @Test
490    public void testClassPackageConflict(Path base) throws Exception {
491        Path libSrc = base.resolve("libSrc");
492        tb.writeJavaFiles(libSrc,
493                          "package test.desktop; public class Any { }");
494        Path libClasses = base.resolve("libClasses");
495        tb.createDirectories(libClasses);
496
497        new JavacTask(tb)
498                .outdir(libClasses)
499                .files(findJavaFiles(libSrc))
500                .run()
501                .writeAll()
502                .getOutputLines(Task.OutputKind.DIRECT);
503
504        Path src = base.resolve("src");
505        tb.writeJavaFiles(src,
506                          "package test; public class desktop { public static class Action { } }",
507                          "package use; import test.desktop.*; public class Use { test.desktop.Action a; }");
508        Path classes = base.resolve("classes");
509        tb.createDirectories(classes);
510
511        new JavacTask(tb)
512                .options("-XDrawDiagnostics")
513                .classpath(libClasses)
514                .outdir(classes)
515                .files(findJavaFiles(src))
516                .run()
517                .writeAll();
518    }
519
520    @Test
521    public void testClassPackageConflictInUnnamed(Path base) throws Exception {
522        Path libSrc = base.resolve("libSrc");
523        tb.writeJavaFiles(libSrc,
524                          "package desktop; public class Any { }");
525        Path libClasses = base.resolve("libClasses");
526        tb.createDirectories(libClasses);
527
528        new JavacTask(tb)
529                .outdir(libClasses)
530                .files(findJavaFiles(libSrc))
531                .run()
532                .writeAll()
533                .getOutputLines(Task.OutputKind.DIRECT);
534
535        Path src = base.resolve("src");
536        tb.writeJavaFiles(src,
537                          "public class desktop { public static class Action { } }",
538                          "import desktop.*; public class Use { desktop.Action a; }");
539        Path classes = base.resolve("classes");
540        tb.createDirectories(classes);
541
542        new JavacTask(tb)
543                .options("-XDrawDiagnostics")
544                .classpath(libClasses)
545                .outdir(classes)
546                .files(findJavaFiles(src))
547                .run()
548                .writeAll();
549    }
550
551    @Test
552    public void testUnresolvableInImport(Path base) throws Exception {
553        Path src = base.resolve("src");
554        Path src_m1 = src.resolve("m1x");
555        tb.writeJavaFiles(src_m1,
556                          "module m1x { }",
557                          "package api; import can.not.resolve; public class Api { }");
558        Path classes = base.resolve("classes");
559        tb.createDirectories(classes);
560
561        List<String> log = new JavacTask(tb)
562                .options("-XDrawDiagnostics",
563                         "--module-source-path", src.toString())
564                .outdir(classes)
565                .files(findJavaFiles(src))
566                .run(Task.Expect.FAIL)
567                .writeAll()
568                .getOutputLines(Task.OutputKind.DIRECT);
569
570        List<String> expected = Arrays.asList(
571                "Api.java:1:28: compiler.err.doesnt.exist: can.not",
572                "1 error");
573
574        if (!expected.equals(log))
575            throw new Exception("expected output not found; actual: " + log);
576    }
577
578    @Test
579    public void testMissingKnownClass(Path base) throws Exception {
580        Path src = base.resolve("src");
581        Path src_m1 = src.resolve("m1x");
582        tb.writeJavaFiles(src_m1,
583                          "module m1x { exports api; }",
584                          "package api; public class Base { }",
585                          "package api; public class Sub extends Base { }");
586        Path classes = base.resolve("classes");
587        tb.createDirectories(classes);
588        Path m1xClasses = classes.resolve("m1x");
589        tb.createDirectories(m1xClasses);
590
591        new JavacTask(tb)
592                .options("-XDrawDiagnostics")
593                .outdir(m1xClasses)
594                .files(findJavaFiles(src_m1))
595                .run(Task.Expect.SUCCESS)
596                .writeAll();
597
598        Files.delete(m1xClasses.resolve("api").resolve("Base.class"));
599
600        Path src_m2 = src.resolve("m2x");
601        tb.writeJavaFiles(src_m2,
602                          "module m2x { requires m1x; }",
603                          "package test;\n" +
604                          "import api.Sub;\n" +
605                          "import api.Base;\n" +
606                          "public class Test {\n" +
607                          "    Sub a2;\n" +
608                          "    Base a;\n" +
609                          "}\n");
610        Path m2xClasses = classes.resolve("m2x");
611        tb.createDirectories(m2xClasses);
612        List<String> log = new JavacTask(tb)
613                .options("-XDrawDiagnostics",
614                         "--module-path", classes.toString(),
615                         "-XDdev")
616                .outdir(m2xClasses)
617                .files(findJavaFiles(src_m2))
618                .run(Task.Expect.FAIL)
619                .writeAll()
620                .getOutputLines(Task.OutputKind.DIRECT);
621
622        List<String> expected = Arrays.asList(
623                "Test.java:3:11: compiler.err.cant.resolve.location: kindname.class, Base, , , (compiler.misc.location: kindname.package, api, null)",
624                "Test.java:6:5: compiler.err.cant.resolve.location: kindname.class, Base, , , (compiler.misc.location: kindname.class, test.Test, null)",
625                "2 errors");
626
627        if (!expected.equals(log))
628            throw new Exception("expected output not found; actual: " + log);
629    }
630
631    @Test
632    public void testInaccessibleInSourceModuleViaBinaryModule(Path base) throws Exception {
633        Path src = base.resolve("src");
634        Path src_m1 = src.resolve("m1x");
635        tb.writeJavaFiles(src_m1,
636                          "@Deprecated module m1x { }");
637        Path src_m2 = src.resolve("m2x");
638        tb.writeJavaFiles(src_m2,
639                          "module m2x { requires transitive m1x; }");
640        Path src_m3 = src.resolve("m3x");
641        tb.writeJavaFiles(src_m3,
642                          "module m3x { requires transitive m2x; exports api; }",
643                          "package api; class Api { }");
644        Path classes = base.resolve("classes");
645        tb.createDirectories(classes);
646
647        new JavacTask(tb)
648            .options("-XDrawDiagnostics",
649                     "--module-source-path", src.toString())
650            .outdir(classes)
651            .files(findJavaFiles(src))
652            .run()
653            .writeAll();
654
655        tb.cleanDirectory(classes.resolve("m2x")); //force completion from source if needed
656        Files.delete(classes.resolve("m2x"));
657
658        tb.cleanDirectory(src_m3); //binary only module
659        Files.delete(src_m3);
660
661        //m4x does not depend on m1x/m2x/m3x, so cannot access api.Api
662        //but the recovery search should not complete m2x, as that would cause a deprecation warning:
663        Path src_m4 = src.resolve("m4x");
664        tb.writeJavaFiles(src_m4,
665                          "module m4x { }",
666                          "package m4x; public class Test extends api.Api { }");
667
668        List<String> log = new JavacTask(tb)
669                .options("-XDrawDiagnostics",
670                         "--module-source-path", src.toString(),
671                         "--module-path", classes.toString(),
672                         "-Xlint:deprecation")
673                .outdir(classes)
674                .files(findJavaFiles(src_m4))
675                .run(Task.Expect.FAIL)
676                .writeAll()
677                .getOutputLines(Task.OutputKind.DIRECT);
678
679        List<String> expected = Arrays.asList(
680                "Test.java:1:40: compiler.err.package.not.visible: api, (compiler.misc.not.def.access.does.not.read: m4x, api, m3x)",
681                "1 error");
682
683        if (!expected.equals(log))
684            throw new Exception("expected output not found; actual: " + log);
685    }
686
687    @Test
688    public void testConvertNameCandidates(Path base) throws Exception {
689        Context ctx = new Context();
690        Names names = Names.instance(ctx);
691        Name name = names.fromString("com.sun.tools.javac.Attr.BreakAttr");
692
693        com.sun.tools.javac.util.List<String> actual =
694                Convert.classCandidates(name).map(n -> n.toString());
695        List<String> expected = Arrays.asList(
696                "com.sun$tools$javac$Attr$BreakAttr",
697                "com.sun.tools$javac$Attr$BreakAttr",
698                "com.sun.tools.javac$Attr$BreakAttr",
699                "com.sun.tools.javac.Attr$BreakAttr",
700                "com.sun.tools.javac.Attr.BreakAttr"
701        );
702
703        if (!expected.equals(actual)) {
704            throw new Exception("Expected names not generated: " + actual);
705        }
706    }
707
708    @Test
709    public void testInaccessibleInVisible(Path base) throws Exception {
710        Path src = base.resolve("src");
711        Path src_ma = src.resolve("ma");
712        tb.writeJavaFiles(src_ma,
713                          "module ma { exports ma; }",
714                          "package ma; class NotApi { public static class Inner { } }");
715        Path classes = base.resolve("classes");
716        tb.createDirectories(classes);
717
718        new JavacTask(tb)
719            .outdir(classes)
720            .files(findJavaFiles(src_ma))
721            .run()
722            .writeAll();
723
724        Path src_mb = src.resolve("mb");
725        tb.writeJavaFiles(src_mb,
726                          "module mb { requires ma; }",
727                          "package mb.a; public class Test { ma.NotApi.Inner i1; mb.b.NotApi.Inner i2; }",
728                          "package mb.b; class NotApi { public static class Inner { } }");
729
730        List<String> log = new JavacTask(tb)
731                .options("-XDrawDiagnostics",
732                         "--module-path", classes.toString())
733                .outdir(classes)
734                .files(findJavaFiles(src_mb))
735                .run(Task.Expect.FAIL)
736                .writeAll()
737                .getOutputLines(Task.OutputKind.DIRECT);
738
739        List<String> expected = Arrays.asList(
740                "Test.java:1:44: compiler.err.not.def.access.class.intf.cant.access: ma.NotApi.Inner, ma.NotApi",
741                "Test.java:1:66: compiler.err.not.def.access.class.intf.cant.access: mb.b.NotApi.Inner, mb.b.NotApi",
742                "2 errors");
743
744        if (!expected.equals(log))
745            throw new Exception("expected output not found; actual: " + log);
746    }
747}
748