8173596: JavaCompiler.CompilationTask should support addModules
authorjjg
Wed, 15 Feb 2017 14:12:29 -0800
changeset 43871 f164f4506389
parent 43870 8805a0acaded
child 43872 b5ce3bc28931
8173596: JavaCompiler.CompilationTask should support addModules Reviewed-by: ksrini, jlahoda
langtools/src/java.compiler/share/classes/javax/tools/DocumentationTool.java
langtools/src/java.compiler/share/classes/javax/tools/JavaCompiler.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/BasicJavacTask.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java
langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/api/JavadocTaskImpl.java
langtools/test/jdk/javadoc/tool/api/basic/AddModulesTest.java
langtools/test/tools/javac/modules/AddModulesTest.java
--- a/langtools/src/java.compiler/share/classes/javax/tools/DocumentationTool.java	Wed Feb 15 11:55:16 2017 -0800
+++ b/langtools/src/java.compiler/share/classes/javax/tools/DocumentationTool.java	Wed Feb 15 14:12:29 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -121,7 +121,20 @@
      */
     interface DocumentationTask extends Callable<Boolean> {
         /**
-         * Set the locale to be applied when formatting diagnostics and
+         * Adds root modules to be taken into account during module
+         * resolution.
+         * Invalid module names may cause either
+         * {@code IllegalArgumentException} to be thrown,
+         * or diagnostics to be reported when the task is started.
+         * @param moduleNames the names of the root modules
+         * @throws IllegalArgumentException may be thrown for some
+         *      invalid module names
+         * @throws IllegalStateException if the task has started
+         */
+        void addModules(Iterable<String> moduleNames);
+
+        /**
+         * Sets the locale to be applied when formatting diagnostics and
          * other localized data.
          *
          * @param locale the locale to apply; {@code null} means apply no
--- a/langtools/src/java.compiler/share/classes/javax/tools/JavaCompiler.java	Wed Feb 15 11:55:16 2017 -0800
+++ b/langtools/src/java.compiler/share/classes/javax/tools/JavaCompiler.java	Wed Feb 15 14:12:29 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,6 @@
 
 package javax.tools;
 
-import java.io.File;
 import java.io.Writer;
 import java.nio.charset.Charset;
 import java.util.Locale;
@@ -296,6 +295,18 @@
      * {@linkplain #setProcessors setProcessors} method.
      */
     interface CompilationTask extends Callable<Boolean> {
+        /**
+         * Adds root modules to be taken into account during module
+         * resolution.
+         * Invalid module names may cause either
+         * {@code IllegalArgumentException} to be thrown,
+         * or diagnostics to be reported when the task is started.
+         * @param moduleNames the names of the root modules
+         * @throws IllegalArgumentException may be thrown for some
+         *      invalid module names
+         * @throws IllegalStateException if the task has started
+         */
+        void addModules(Iterable<String> moduleNames);
 
         /**
          * Sets processors (for annotation processing).  This will
@@ -307,7 +318,7 @@
         void setProcessors(Iterable<? extends Processor> processors);
 
         /**
-         * Set the locale to be applied when formatting diagnostics and
+         * Sets the locale to be applied when formatting diagnostics and
          * other localized data.
          *
          * @param locale the locale to apply; {@code null} means apply no
@@ -330,6 +341,7 @@
          * in user code.
          * @throws IllegalStateException if called more than once
          */
+        @Override
         Boolean call();
     }
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/BasicJavacTask.java	Wed Feb 15 11:55:16 2017 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/BasicJavacTask.java	Wed Feb 15 14:12:29 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -155,6 +155,11 @@
     }
 
     @Override @DefinedBy(Api.COMPILER)
+    public void addModules(Iterable<String> moduleNames) {
+        throw new IllegalStateException();
+    }
+
+    @Override @DefinedBy(Api.COMPILER)
     public void setProcessors(Iterable<? extends Processor> processors) {
         throw new IllegalStateException();
     }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java	Wed Feb 15 11:55:16 2017 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java	Wed Feb 15 14:12:29 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,17 +33,12 @@
 
 import javax.annotation.processing.Processor;
 import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.ElementFilter;
 import javax.tools.*;
-import javax.tools.JavaFileObject.Kind;
 
 import com.sun.source.tree.*;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
-import com.sun.tools.javac.code.Symbol.ModuleSymbol;
-import com.sun.tools.javac.code.Symbol.PackageSymbol;
 import com.sun.tools.javac.comp.*;
 import com.sun.tools.javac.file.BaseFileManager;
 import com.sun.tools.javac.main.*;
@@ -82,6 +77,7 @@
     private ListBuffer<Env<AttrContext>> genList;
     private final AtomicBoolean used = new AtomicBoolean();
     private Iterable<? extends Processor> processors;
+    private ListBuffer<String> addModules = new ListBuffer<>();
 
     protected JavacTaskImpl(Context context) {
         super(context, true);
@@ -101,7 +97,7 @@
                 prepareCompiler(false);
                 if (compiler.errorCount() > 0)
                     return Main.Result.ERROR;
-                compiler.compile(args.getFileObjects(), args.getClassNames(), processors);
+                compiler.compile(args.getFileObjects(), args.getClassNames(), processors, addModules);
                 return (compiler.errorCount() > 0) ? Main.Result.ERROR : Main.Result.OK; // FIXME?
             }, Main.Result.SYSERR, Main.Result.ABNORMAL);
         } finally {
@@ -114,6 +110,18 @@
     }
 
     @Override @DefinedBy(Api.COMPILER)
+    public void addModules(Iterable<String> moduleNames) {
+        Objects.requireNonNull(moduleNames);
+        // not mt-safe
+        if (used.get())
+            throw new IllegalStateException();
+        for (String m : moduleNames) {
+            Objects.requireNonNull(m);
+            addModules.add(m);
+        }
+    }
+
+    @Override @DefinedBy(Api.COMPILER)
     public void setProcessors(Iterable<? extends Processor> processors) {
         Objects.requireNonNull(processors);
         // not mt-safe
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Wed Feb 15 11:55:16 2017 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Wed Feb 15 14:12:29 2017 -0800
@@ -888,7 +888,7 @@
 
     public void compile(List<JavaFileObject> sourceFileObject)
         throws Throwable {
-        compile(sourceFileObject, List.nil(), null);
+        compile(sourceFileObject, List.nil(), null, List.nil());
     }
 
     /**
@@ -898,10 +898,13 @@
      * @param classnames class names to process for annotations
      * @param processors user provided annotation processors to bypass
      * discovery, {@code null} means that no processors were provided
+     * @param addModules additional root modules to be used during
+     * module resolution.
      */
     public void compile(Collection<JavaFileObject> sourceFileObjects,
                         Collection<String> classnames,
-                        Iterable<? extends Processor> processors)
+                        Iterable<? extends Processor> processors,
+                        Collection<String> addModules)
     {
         if (!taskListener.isEmpty()) {
             taskListener.started(new TaskEvent(TaskEvent.Kind.COMPILATION));
@@ -932,6 +935,10 @@
                 }
             }
 
+            for (String moduleName : addModules) {
+                modules.addExtraAddModules(moduleName);
+            }
+
             // These method calls must be chained to avoid memory leaks
             processAnnotations(
                 enterTrees(
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java	Wed Feb 15 11:55:16 2017 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java	Wed Feb 15 14:12:29 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -304,7 +304,7 @@
         }
 
         try {
-            comp.compile(args.getFileObjects(), args.getClassNames(), null);
+            comp.compile(args.getFileObjects(), args.getClassNames(), null, List.nil());
 
             if (log.expectDiagKeys != null) {
                 if (log.expectDiagKeys.isEmpty()) {
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/api/JavadocTaskImpl.java	Wed Feb 15 11:55:16 2017 -0800
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/api/JavadocTaskImpl.java	Wed Feb 15 14:12:29 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,15 +25,20 @@
 
 package jdk.javadoc.internal.api;
 
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.tools.DocumentationTool.DocumentationTask;
 import javax.tools.JavaFileObject;
 
+import com.sun.tools.javac.main.Option;
 import com.sun.tools.javac.util.ClientCodeException;
 import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Options;
 import jdk.javadoc.internal.tool.Start;
 
 /**
@@ -53,6 +58,7 @@
     private Iterable<String> options;
     private Iterable<? extends JavaFileObject> fileObjects;
     private Locale locale;
+    private List<String> addModules = new ArrayList<>();
 
     public JavadocTaskImpl(Context context, Class<?> docletClass,
             Iterable<String> options, Iterable<? extends JavaFileObject> fileObjects) {
@@ -72,6 +78,16 @@
         this.locale = locale;
     }
 
+    @Override
+    public void addModules(Iterable<String> moduleNames) {
+        nullCheck(moduleNames);
+        if (used.get())
+            throw new IllegalStateException();
+        for (String name : moduleNames) {
+            addModules.add(name);
+        }
+    }
+
     public Boolean call() {
         if (!used.getAndSet(true)) {
             initContext();
@@ -89,6 +105,12 @@
     private void initContext() {
         //initialize compiler's default locale
         context.put(Locale.class, locale);
+        if (!addModules.isEmpty()) {
+            String names = String.join(",", addModules);
+            Options opts = Options.instance(context);
+            String prev = opts.get(Option.ADD_MODULES);
+            opts.put(Option.ADD_MODULES, (prev == null) ? names : prev + "," + names);
+        }
     }
 
     private static <T> Iterable<T> nullCheck(Iterable<T> items) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/javadoc/tool/api/basic/AddModulesTest.java	Wed Feb 15 14:12:29 2017 -0800
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8173596
+ * @summary DocumentationTool.DocumentationTask should support addModules
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.main
+ * @library /tools/lib
+ * @build APITest toolbox.JavacTask toolbox.ToolBox
+ * @run main AddModulesTest
+ */
+
+import java.io.StringWriter;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+
+import javax.tools.DocumentationTool;
+import javax.tools.DocumentationTool.DocumentationTask;
+import javax.tools.DocumentationTool.Location;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+
+import toolbox.Assert;
+import toolbox.JavacTask;
+import toolbox.ToolBox;
+
+/**
+ * Tests for DocumentationTask.addModules method.
+ */
+public class AddModulesTest extends APITest {
+    public static void main(String... args) throws Exception {
+        new AddModulesTest().run();
+    }
+
+    private final ToolBox tb = new ToolBox();
+
+    /**
+     * Verify that addModules works as expected.
+     */
+    @Test
+    public void testAddModules() throws Exception {
+        Path base = Paths.get("testAddModules");
+        Path src = base.resolve("src");
+
+        // setup some utility modules
+        Path src_m1 = src.resolve("m1x");
+        tb.writeJavaFiles(src_m1,
+                          "module m1x { exports p1; }",
+                          "package p1; public class C1 { }");
+        Path src_m2 = src.resolve("m2x");
+        tb.writeJavaFiles(src_m2,
+                          "module m2x { exports p2; }",
+                          "package p2; public class C2 { }");
+        Path modules = base.resolve("modules");
+        tb.createDirectories(modules);
+
+        new JavacTask(tb)
+                .options("--module-source-path", src.toString())
+                .outdir(modules)
+                .files(tb.findJavaFiles(src))
+                .run()
+                .writeAll();
+
+        // now test access to the modules
+        Path src2 = base.resolve("src2");
+        tb.writeJavaFiles(src2,
+                          "public class Dummy { p1.C1 c1; p2.C2 c2; }");
+        Path api = base.resolve("api");
+        tb.createDirectories(api);
+
+        DocumentationTool tool = ToolProvider.getSystemDocumentationTool();
+        try (StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null)) {
+            fm.setLocationFromPaths(StandardLocation.MODULE_PATH, Arrays.asList(modules));
+            fm.setLocationFromPaths(Location.DOCUMENTATION_OUTPUT, Arrays.asList(api));
+            Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(tb.findJavaFiles(src2));
+
+            for (boolean useOption : new boolean[] { false, true }) {
+                System.err.println("Use --add-modules option: " + useOption);
+                StringWriter sw = new StringWriter();
+                DocumentationTask t = tool.getTask(sw, fm, null, null, null, files);
+                if (useOption) {
+                    t.addModules(Arrays.asList("m1x", "m2x"));
+                }
+                String out;
+                boolean ok;
+                try {
+                    ok = t.call();
+                } finally {
+                    out = sw.toString();
+                    System.err.println(out);
+                }
+                System.err.println("ok: " + ok);
+                boolean expectErrors = !useOption;
+                check(out, "package p1 is not visible", expectErrors);
+                check(out, "package p2 is not visible", expectErrors);
+                System.err.println();
+            }
+        }
+    }
+
+    void check(String out, String text, boolean expected) {
+        System.err.println("Checking for "
+            + (expected ? "expected" : "unexpected")
+            + " text: " + text);
+
+        if (expected) {
+            if (!out.contains(text)) {
+                error("expected text not found: " + text);
+            }
+        } else {
+            if (out.contains(text)) {
+                error("unexpected text found: " + text);
+            }
+        }
+    }
+}
+
--- a/langtools/test/tools/javac/modules/AddModulesTest.java	Wed Feb 15 11:55:16 2017 -0800
+++ b/langtools/test/tools/javac/modules/AddModulesTest.java	Wed Feb 15 14:12:29 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,17 +23,27 @@
 
 /*
  * @test
+ * @bug 8167975 8173596
  * @summary Test the --add-modules option
  * @library /tools/lib
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
- * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase
+ * @build toolbox.Assert toolbox.ToolBox toolbox.JavacTask ModuleTestBase
  * @run main AddModulesTest
  */
 
 
 import java.nio.file.Path;
+import java.util.Arrays;
 
+import javax.tools.JavaCompiler;
+import javax.tools.JavaCompiler.CompilationTask;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+
+import toolbox.Assert;
 import toolbox.JavacTask;
 import toolbox.Task;
 
@@ -227,5 +237,46 @@
                 .run()
                 .writeAll();
     }
+
+    @Test
+    public void testAddModulesAPI(Path base) throws Exception {
+        Path src = base.resolve("src");
+
+        // setup some utility modules
+        Path src_m1 = src.resolve("m1x");
+        tb.writeJavaFiles(src_m1,
+                          "module m1x { exports p1; }",
+                          "package p1; public class C1 { }");
+        Path src_m2 = src.resolve("m2x");
+        tb.writeJavaFiles(src_m2,
+                          "module m2x { exports p2; }",
+                          "package p2; public class C2 { }");
+        Path modules = base.resolve("modules");
+        tb.createDirectories(modules);
+
+        new JavacTask(tb)
+                .options("--module-source-path", src.toString())
+                .outdir(modules)
+                .files(findJavaFiles(src))
+                .run()
+                .writeAll();
+
+        // now test access to the modules
+        Path src2 = base.resolve("src2");
+        tb.writeJavaFiles(src2,
+                          "class Dummy { p1.C1 c1; p2.C2 c2; }");
+        Path classes = base.resolve("classes");
+        tb.createDirectories(classes);
+
+        JavaCompiler c = ToolProvider.getSystemJavaCompiler();
+        try (StandardJavaFileManager fm = c.getStandardFileManager(null, null, null)) {
+            fm.setLocationFromPaths(StandardLocation.MODULE_PATH, Arrays.asList(modules));
+            fm.setLocationFromPaths(StandardLocation.CLASS_OUTPUT, Arrays.asList(classes));
+            Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(findJavaFiles(src2));
+            CompilationTask t = c.getTask(null, fm, null, null, null, files);
+            t.addModules(Arrays.asList("m1x", "m2x"));
+            Assert.check(t.call());
+        }
+    }
 }