changeset 4813:d457e90d4906

8176045: No compile error when a package is not declared Summary: Fixing handling of otherwise empty files with package clauses and empty files without package clauses. Reviewed-by: jjg
author jlahoda
date Tue, 14 Mar 2017 08:19:41 +0100
parents 24fa5d195595
children adef848660f9
files src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java test/tools/javac/modules/EdgeCases.java
diffstat 3 files changed, 178 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java	Tue Mar 14 07:11:45 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java	Tue Mar 14 08:19:41 2017 +0100
@@ -89,7 +89,6 @@
 import com.sun.tools.javac.tree.JCTree.JCExpression;
 import com.sun.tools.javac.tree.JCTree.JCModuleDecl;
 import com.sun.tools.javac.tree.JCTree.JCOpens;
-import com.sun.tools.javac.tree.JCTree.JCPackageDecl;
 import com.sun.tools.javac.tree.JCTree.JCProvides;
 import com.sun.tools.javac.tree.JCTree.JCRequires;
 import com.sun.tools.javac.tree.JCTree.JCUses;
@@ -112,6 +111,7 @@
 import static com.sun.tools.javac.code.Flags.ENUM;
 import static com.sun.tools.javac.code.Flags.PUBLIC;
 import static com.sun.tools.javac.code.Flags.UNATTRIBUTED;
+import com.sun.tools.javac.code.Kinds;
 import static com.sun.tools.javac.code.Kinds.Kind.ERR;
 import static com.sun.tools.javac.code.Kinds.Kind.MDL;
 import static com.sun.tools.javac.code.Kinds.Kind.MTH;
@@ -167,6 +167,8 @@
     private Set<ModuleSymbol> rootModules = null;
     private final Set<ModuleSymbol> warnedMissing = new HashSet<>();
 
+    public PackageNameFinder findPackageInFile;
+
     public static Modules instance(Context context) {
         Modules instance = context.get(Modules.class);
         if (instance == null)
@@ -956,7 +958,30 @@
 
         @Override
         public void visitExports(JCExports tree) {
-            if (tree.directive.packge.members().isEmpty()) {
+            Iterable<Symbol> packageContent = tree.directive.packge.members().getSymbols();
+            List<JavaFileObject> filesToCheck = List.nil();
+            boolean packageNotEmpty = false;
+            for (Symbol sym : packageContent) {
+                if (sym.kind != Kinds.Kind.TYP)
+                    continue;
+                ClassSymbol csym = (ClassSymbol) sym;
+                if (sym.completer.isTerminal() ||
+                    csym.classfile.getKind() == Kind.CLASS) {
+                    packageNotEmpty = true;
+                    filesToCheck = List.nil();
+                    break;
+                }
+                if (csym.classfile.getKind() == Kind.SOURCE) {
+                    filesToCheck = filesToCheck.prepend(csym.classfile);
+                }
+            }
+            for (JavaFileObject jfo : filesToCheck) {
+                if (findPackageInFile.findPackageNameOf(jfo) == tree.directive.packge.fullname) {
+                    packageNotEmpty = true;
+                    break;
+                }
+            }
+            if (!packageNotEmpty) {
                 log.error(tree.qualid.pos(), Errors.PackageEmptyOrNotFound(tree.directive.packge));
             }
             msym.directives = msym.directives.prepend(tree.directive);
@@ -1676,4 +1701,8 @@
         rootModules = null;
         warnedMissing.clear();
     }
+
+    public interface PackageNameFinder {
+        public Name findPackageNameOf(JavaFileObject jfo);
+    }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Tue Mar 14 07:11:45 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Tue Mar 14 08:19:41 2017 +0100
@@ -412,6 +412,7 @@
         diags = Factory.instance(context);
 
         finder.sourceCompleter = sourceCompleter;
+        modules.findPackageInFile = this::findPackageInFile;
         moduleFinder.moduleNameFromSourceReader = this::readModuleName;
 
         options = Options.instance(context);
@@ -1737,6 +1738,11 @@
         });
     }
 
+    private Name findPackageInFile(JavaFileObject fo) {
+        return parseAndGetName(fo, t -> t.getPackage() != null ?
+                                        TreeInfo.fullName(t.getPackage().getPackageName()) : null);
+    }
+
     private Name parseAndGetName(JavaFileObject fo,
                                  Function<JCTree.JCCompilationUnit, Name> tree2Name) {
         DiagnosticHandler dh = new DiscardDiagnosticHandler(log);
--- a/test/tools/javac/modules/EdgeCases.java	Tue Mar 14 07:11:45 2017 +0100
+++ b/test/tools/javac/modules/EdgeCases.java	Tue Mar 14 08:19:41 2017 +0100
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8154283 8167320 8171098 8172809 8173068 8173117
+ * @bug 8154283 8167320 8171098 8172809 8173068 8173117 8176045
  * @summary tests for multi-module mode compilation
  * @library /tools/lib
  * @modules
@@ -36,6 +36,7 @@
  * @run main EdgeCases
  */
 
+import java.io.BufferedWriter;
 import java.io.Writer;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -67,10 +68,7 @@
 //import com.sun.source.util.JavacTask; // conflicts with toolbox.JavacTask
 import com.sun.tools.javac.api.JavacTaskImpl;
 import com.sun.tools.javac.code.Symbol.ModuleSymbol;
-import com.sun.tools.javac.code.Symbol.PackageSymbol;
 import com.sun.tools.javac.code.Symtab;
-import com.sun.tools.javac.processing.JavacProcessingEnvironment;
-import com.sun.tools.javac.util.Context;
 
 import toolbox.JarTask;
 import toolbox.JavacTask;
@@ -821,4 +819,143 @@
         }
 
     }
+
+    @Test
+    public void testEmptyInExportedPackage(Path base) throws Exception {
+        Path src = base.resolve("src");
+        Path m = src.resolve("m");
+        tb.writeJavaFiles(m,
+                          "module m { exports api; }");
+        Path apiFile = m.resolve("api").resolve("Api.java");
+        Files.createDirectories(apiFile.getParent());
+        try (BufferedWriter w = Files.newBufferedWriter(apiFile)) {
+            w.write("//no package decl");
+        }
+        Path classes = base.resolve("classes");
+        tb.createDirectories(classes);
+
+        List<String> log;
+        List<String> expected =
+                Arrays.asList("module-info.java:1:20: compiler.err.package.empty.or.not.found: api",
+                              "1 error");
+
+        System.err.println("file explicitly specified:");
+
+        log = new JavacTask(tb)
+            .options("-XDrawDiagnostics",
+                     "--module-source-path", src.toString())
+            .outdir(classes)
+            .files(findJavaFiles(src))
+            .run(Task.Expect.FAIL)
+            .writeAll()
+            .getOutputLines(Task.OutputKind.DIRECT);
+
+        if (!expected.equals(log))
+            throw new Exception("expected output not found: " + log);
+
+        System.err.println("file not specified:");
+
+        tb.cleanDirectory(classes);
+
+        log = new JavacTask(tb)
+            .options("-XDrawDiagnostics",
+                     "--module-source-path", src.toString())
+            .outdir(classes)
+            .files(findJavaFiles(m.resolve("module-info.java")))
+            .run(Task.Expect.FAIL)
+            .writeAll()
+            .getOutputLines(Task.OutputKind.DIRECT);
+
+        if (!expected.equals(log))
+            throw new Exception("expected output not found: " + log);
+    }
+
+    @Test
+    public void testJustPackageInExportedPackage(Path base) throws Exception {
+        Path src = base.resolve("src");
+        Path m = src.resolve("m");
+        tb.writeJavaFiles(m,
+                          "module m { exports api; }");
+        Path apiFile = m.resolve("api").resolve("Api.java");
+        Files.createDirectories(apiFile.getParent());
+        try (BufferedWriter w = Files.newBufferedWriter(apiFile)) {
+            w.write("package api;");
+        }
+        Path classes = base.resolve("classes");
+        tb.createDirectories(classes);
+
+        System.err.println("file explicitly specified:");
+
+        new JavacTask(tb)
+            .options("-XDrawDiagnostics",
+                     "--module-source-path", src.toString())
+            .outdir(classes)
+            .files(findJavaFiles(src))
+            .run()
+            .writeAll();
+
+        System.err.println("file not specified:");
+
+        tb.cleanDirectory(classes);
+
+        new JavacTask(tb)
+            .options("-XDrawDiagnostics",
+                     "--module-source-path", src.toString())
+            .outdir(classes)
+            .files(findJavaFiles(m.resolve("module-info.java")))
+            .run()
+            .writeAll();
+    }
+
+    @Test
+    public void testWrongPackageInExportedPackage(Path base) throws Exception {
+        Path src = base.resolve("src");
+        Path m = src.resolve("m");
+        tb.writeJavaFiles(m,
+                          "module m { exports api; }");
+        Path apiFile = m.resolve("api").resolve("Api.java");
+        Files.createDirectories(apiFile.getParent());
+        try (BufferedWriter w = Files.newBufferedWriter(apiFile)) {
+            w.write("package impl; public class Api { }");
+        }
+        Path classes = base.resolve("classes");
+        tb.createDirectories(classes);
+
+        List<String> log;
+
+        List<String> expected =
+                Arrays.asList("module-info.java:1:20: compiler.err.package.empty.or.not.found: api",
+                              "1 error");
+
+        System.err.println("file explicitly specified:");
+
+        log = new JavacTask(tb)
+                .options("-XDrawDiagnostics",
+                         "--module-source-path", src.toString())
+                .outdir(classes)
+                .files(findJavaFiles(src))
+                .run(Task.Expect.FAIL)
+                .writeAll()
+                .getOutputLines(Task.OutputKind.DIRECT);
+
+        if (!expected.equals(log))
+            throw new Exception("expected output not found: " + log);
+
+        System.err.println("file not specified:");
+
+        tb.cleanDirectory(classes);
+
+        log = new JavacTask(tb)
+                .options("-XDrawDiagnostics",
+                         "--module-source-path", src.toString())
+                .outdir(classes)
+                .files(findJavaFiles(m.resolve("module-info.java")))
+                .run(Task.Expect.FAIL)
+                .writeAll()
+                .getOutputLines(Task.OutputKind.DIRECT);
+
+        if (!expected.equals(log))
+            throw new Exception("expected output not found: " + log);
+    }
+
 }