8175346: javadoc does not handle Locations correctly with --patch-module jdk-9+162
authorksrini
Thu, 16 Mar 2017 18:50:50 -0700
changeset 5844440c45c2e8ce
parent 5843 7b92442057a8
child 5845 8cfb71a78258
child 5846 ad45b4519f1b
8175346: javadoc does not handle Locations correctly with --patch-module
Reviewed-by: jjg
src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java
src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties
test/jdk/javadoc/tool/modules/ModuleTestBase.java
test/jdk/javadoc/tool/modules/Modules.java
test/jdk/javadoc/tool/modules/PatchModules.java
test/jdk/javadoc/tool/modules/ReleaseOptions.java
     1.1 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java	Thu Mar 16 17:13:10 2017 -0700
     1.2 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java	Thu Mar 16 18:50:50 2017 -0700
     1.3 @@ -53,6 +53,7 @@
     1.4  import javax.tools.StandardLocation;
     1.5  
     1.6  import com.sun.tools.javac.code.Kinds.Kind;
     1.7 +import com.sun.tools.javac.code.Source;
     1.8  import com.sun.tools.javac.code.Symbol;
     1.9  import com.sun.tools.javac.code.Symbol.ClassSymbol;
    1.10  import com.sun.tools.javac.code.Symbol.CompletionFailure;
    1.11 @@ -60,8 +61,11 @@
    1.12  import com.sun.tools.javac.code.Symbol.PackageSymbol;
    1.13  import com.sun.tools.javac.code.Symtab;
    1.14  import com.sun.tools.javac.comp.Modules;
    1.15 +import com.sun.tools.javac.main.JavaCompiler;
    1.16  import com.sun.tools.javac.tree.JCTree.JCClassDecl;
    1.17  import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
    1.18 +import com.sun.tools.javac.tree.JCTree.JCModuleDecl;
    1.19 +import com.sun.tools.javac.tree.TreeInfo;
    1.20  import com.sun.tools.javac.util.Context;
    1.21  import com.sun.tools.javac.util.ListBuffer;
    1.22  import com.sun.tools.javac.util.Name;
    1.23 @@ -70,7 +74,9 @@
    1.24  import jdk.javadoc.doclet.DocletEnvironment.ModuleMode;
    1.25  
    1.26  import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
    1.27 +
    1.28  import static javax.tools.JavaFileObject.Kind.*;
    1.29 +
    1.30  import static jdk.javadoc.internal.tool.Main.Result.*;
    1.31  import static jdk.javadoc.internal.tool.JavadocTool.isValidClassName;
    1.32  
    1.33 @@ -153,10 +159,11 @@
    1.34      private final Symtab syms;
    1.35      private final Names names;
    1.36      private final JavaFileManager fm;
    1.37 -    private final Location location;
    1.38 +    private final List<Location> locations;
    1.39      private final Modules modules;
    1.40      private final Map<ToolOption, Object> opts;
    1.41      private final Messager messager;
    1.42 +    private final JavaCompiler compiler;
    1.43  
    1.44      private final Map<String, Entry> entries = new LinkedHashMap<>();
    1.45  
    1.46 @@ -201,12 +208,22 @@
    1.47          this.modules = Modules.instance(context);
    1.48          this.opts = opts;
    1.49          this.messager = Messager.instance0(context);
    1.50 +        this.compiler = JavaCompiler.instance(context);
    1.51 +        Source source = Source.instance(context);
    1.52  
    1.53 -        this.location = modules.multiModuleMode
    1.54 -                ? StandardLocation.MODULE_SOURCE_PATH
    1.55 -                : toolEnv.fileManager.hasLocation(StandardLocation.SOURCE_PATH)
    1.56 -                    ? StandardLocation.SOURCE_PATH
    1.57 -                    : StandardLocation.CLASS_PATH;
    1.58 +        List<Location> locs = new ArrayList<>();
    1.59 +        if (modules.multiModuleMode) {
    1.60 +            locs.add(StandardLocation.MODULE_SOURCE_PATH);
    1.61 +        } else {
    1.62 +            if (toolEnv.fileManager.hasLocation(StandardLocation.SOURCE_PATH))
    1.63 +                locs.add(StandardLocation.SOURCE_PATH);
    1.64 +            else
    1.65 +                locs.add(StandardLocation.CLASS_PATH);
    1.66 +        }
    1.67 +        if (source.allowModules() && toolEnv.fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH))
    1.68 +            locs.add(StandardLocation.PATCH_MODULE_PATH);
    1.69 +        this.locations = Collections.unmodifiableList(locs);
    1.70 +
    1.71          getEntry("").excluded = false;
    1.72  
    1.73          accessFilter = new ModifierFilter(opts);
    1.74 @@ -341,6 +358,52 @@
    1.75          return this;
    1.76      }
    1.77  
    1.78 +    /*
    1.79 +     * This method sanity checks the following cases:
    1.80 +     * a. a source-path containing a single module and many modules specified with --module
    1.81 +     * b. no modules on source-path
    1.82 +     * c. mismatched source-path and many modules specified with --module
    1.83 +     */
    1.84 +    void sanityCheckSourcePathModules(List<String> moduleNames) throws ToolException {
    1.85 +        if (!haveSourceLocationWithModule)
    1.86 +            return;
    1.87 +
    1.88 +        if (moduleNames.size() > 1) {
    1.89 +            String text = messager.getText("main.cannot_use_sourcepath_for_modules",
    1.90 +                    String.join(", ", moduleNames));
    1.91 +            throw new ToolException(CMDERR, text);
    1.92 +        }
    1.93 +
    1.94 +        String foundModule = getModuleName(StandardLocation.SOURCE_PATH);
    1.95 +        if (foundModule == null) {
    1.96 +            String text = messager.getText("main.module_not_found_on_sourcepath", moduleNames.get(0));
    1.97 +            throw new ToolException(CMDERR, text);
    1.98 +        }
    1.99 +
   1.100 +        if (!moduleNames.get(0).equals(foundModule)) {
   1.101 +            String text = messager.getText("main.sourcepath_does_not_contain_module", moduleNames.get(0));
   1.102 +            throw new ToolException(CMDERR, text);
   1.103 +        }
   1.104 +    }
   1.105 +
   1.106 +    private String getModuleName(Location location) throws ToolException {
   1.107 +        try {
   1.108 +            JavaFileObject jfo = fm.getJavaFileForInput(location,
   1.109 +                    "module-info", JavaFileObject.Kind.SOURCE);
   1.110 +            if (jfo != null) {
   1.111 +                JCCompilationUnit jcu = compiler.parse(jfo);
   1.112 +                JCModuleDecl module = TreeInfo.getModule(jcu);
   1.113 +                if (module != null) {
   1.114 +                    return module.getName().toString();
   1.115 +                }
   1.116 +            }
   1.117 +        } catch (IOException ioe) {
   1.118 +            String text = messager.getText("main.file.manager.list", location);
   1.119 +            throw new ToolException(SYSERR, text, ioe);
   1.120 +        }
   1.121 +        return null;
   1.122 +    }
   1.123 +
   1.124      @SuppressWarnings("unchecked")
   1.125      ElementsTable scanSpecifiedItems() throws ToolException {
   1.126  
   1.127 @@ -349,15 +412,17 @@
   1.128                  s -> Collections.EMPTY_LIST);
   1.129          List<String> mlist = new ArrayList<>();
   1.130          for (String m : moduleNames) {
   1.131 -            Location moduleLoc = getModuleLocation(location, m);
   1.132 -            if (moduleLoc == null) {
   1.133 +            List<Location> moduleLocations = getModuleLocation(locations, m);
   1.134 +            if (moduleLocations.isEmpty()) {
   1.135                  String text = messager.getText("main.module_not_found", m);
   1.136                  throw new ToolException(CMDERR, text);
   1.137 -            } else {
   1.138 -                mlist.add(m);
   1.139 -                ModuleSymbol msym = syms.enterModule(names.fromString(m));
   1.140 -                specifiedModuleElements.add((ModuleElement) msym);
   1.141              }
   1.142 +            if (moduleLocations.contains(StandardLocation.SOURCE_PATH)) {
   1.143 +                sanityCheckSourcePathModules(moduleNames);
   1.144 +            }
   1.145 +            mlist.add(m);
   1.146 +            ModuleSymbol msym = syms.enterModule(names.fromString(m));
   1.147 +            specifiedModuleElements.add((ModuleElement) msym);
   1.148          }
   1.149  
   1.150          // scan for modules with qualified packages
   1.151 @@ -448,35 +513,41 @@
   1.152          });
   1.153  
   1.154          for (ModulePackage modpkg : subPackages) {
   1.155 -            Location packageLocn = getLocation(modpkg);
   1.156 -            Iterable<JavaFileObject> list = null;
   1.157 -            try {
   1.158 -                list = fm.list(packageLocn, modpkg.packageName, sourceKinds, true);
   1.159 -            } catch (IOException ioe) {
   1.160 -                String text = messager.getText("main.file.manager.list", modpkg.packageName);
   1.161 -                throw new ToolException(SYSERR, text, ioe);
   1.162 +            List<Location> locs = getLocation(modpkg);
   1.163 +            for (Location loc : locs) {
   1.164 +                addPackagesFromLocations(loc, modpkg);
   1.165              }
   1.166 -            for (JavaFileObject fo : list) {
   1.167 -                String binaryName = fm.inferBinaryName(packageLocn, fo);
   1.168 -                String pn = getPackageName(binaryName);
   1.169 -                String simpleName = getSimpleName(binaryName);
   1.170 -                Entry e = getEntry(pn);
   1.171 -                if (!e.isExcluded() && isValidClassName(simpleName)) {
   1.172 -                    ModuleSymbol msym = (modpkg.hasModule())
   1.173 -                            ? syms.getModule(names.fromString(modpkg.moduleName))
   1.174 -                            : findModuleOfPackageName(modpkg.packageName);
   1.175 +        }
   1.176 +    }
   1.177  
   1.178 -                    if (msym != null && !msym.isUnnamed()) {
   1.179 -                        syms.enterPackage(msym, names.fromString(pn));
   1.180 -                        ModulePackage npkg = new ModulePackage(msym.toString(), pn);
   1.181 -                        cmdLinePackages.add(npkg);
   1.182 -                    } else {
   1.183 -                        cmdLinePackages.add(e.modpkg);
   1.184 -                    }
   1.185 -                    e.files = (e.files == null
   1.186 -                            ? com.sun.tools.javac.util.List.of(fo)
   1.187 -                            : e.files.prepend(fo));
   1.188 +    private void addPackagesFromLocations(Location packageLocn, ModulePackage modpkg) throws ToolException {
   1.189 +        Iterable<JavaFileObject> list = null;
   1.190 +        try {
   1.191 +            list = fm.list(packageLocn, modpkg.packageName, sourceKinds, true);
   1.192 +        } catch (IOException ioe) {
   1.193 +            String text = messager.getText("main.file.manager.list", modpkg.packageName);
   1.194 +            throw new ToolException(SYSERR, text, ioe);
   1.195 +        }
   1.196 +        for (JavaFileObject fo : list) {
   1.197 +            String binaryName = fm.inferBinaryName(packageLocn, fo);
   1.198 +            String pn = getPackageName(binaryName);
   1.199 +            String simpleName = getSimpleName(binaryName);
   1.200 +            Entry e = getEntry(pn);
   1.201 +            if (!e.isExcluded() && isValidClassName(simpleName)) {
   1.202 +                ModuleSymbol msym = (modpkg.hasModule())
   1.203 +                        ? syms.getModule(names.fromString(modpkg.moduleName))
   1.204 +                        : findModuleOfPackageName(modpkg.packageName);
   1.205 +
   1.206 +                if (msym != null && !msym.isUnnamed()) {
   1.207 +                    syms.enterPackage(msym, names.fromString(pn));
   1.208 +                    ModulePackage npkg = new ModulePackage(msym.toString(), pn);
   1.209 +                    cmdLinePackages.add(npkg);
   1.210 +                } else {
   1.211 +                    cmdLinePackages.add(e.modpkg);
   1.212                  }
   1.213 +                e.files = (e.files == null
   1.214 +                        ? com.sun.tools.javac.util.List.of(fo)
   1.215 +                        : e.files.prepend(fo));
   1.216              }
   1.217          }
   1.218      }
   1.219 @@ -544,20 +615,23 @@
   1.220      private Set<PackageElement> getAllModulePackages(ModuleElement mdle) throws ToolException {
   1.221          Set<PackageElement> result = new HashSet<>();
   1.222          ModuleSymbol msym = (ModuleSymbol) mdle;
   1.223 -        Location msymloc = getModuleLocation(location, msym.name.toString());
   1.224 -        try {
   1.225 -            for (JavaFileObject fo : fm.list(msymloc, "", sourceKinds, true)) {
   1.226 -                if (fo.getName().endsWith("module-info.java"))
   1.227 -                    continue;
   1.228 -                String binaryName = fm.inferBinaryName(msymloc, fo);
   1.229 -                String pn = getPackageName(binaryName);
   1.230 -                PackageSymbol psym = syms.enterPackage(msym, names.fromString(pn));
   1.231 -                result.add((PackageElement) psym);
   1.232 +        List<Location> msymlocs = getModuleLocation(locations, msym.name.toString());
   1.233 +        for (Location msymloc : msymlocs) {
   1.234 +            try {
   1.235 +                for (JavaFileObject fo : fm.list(msymloc, "", sourceKinds, true)) {
   1.236 +                    if (fo.getName().endsWith("module-info.java")) {
   1.237 +                        continue;
   1.238 +                    }
   1.239 +                    String binaryName = fm.inferBinaryName(msymloc, fo);
   1.240 +                    String pn = getPackageName(binaryName);
   1.241 +                    PackageSymbol psym = syms.enterPackage(msym, names.fromString(pn));
   1.242 +                    result.add((PackageElement) psym);
   1.243 +                }
   1.244 +
   1.245 +            } catch (IOException ioe) {
   1.246 +                String text = messager.getText("main.file.manager.list", msymloc.getName());
   1.247 +                throw new ToolException(SYSERR, text, ioe);
   1.248              }
   1.249 -
   1.250 -        } catch (IOException ioe) {
   1.251 -            String text = messager.getText("main.file.manager.list", msymloc.getName());
   1.252 -            throw new ToolException(SYSERR, text, ioe);
   1.253          }
   1.254          return result;
   1.255      }
   1.256 @@ -741,25 +815,25 @@
   1.257          }
   1.258  
   1.259          ListBuffer<JavaFileObject> lb = new ListBuffer<>();
   1.260 -        Location packageLocn = getLocation(modpkg);
   1.261 -        if (packageLocn == null) {
   1.262 +        List<Location> locs = getLocation(modpkg);
   1.263 +        if (locs.isEmpty()) {
   1.264              return Collections.emptyList();
   1.265          }
   1.266          String pname = modpkg.packageName;
   1.267 -
   1.268 -        try {
   1.269 -            for (JavaFileObject fo : fm.list(packageLocn, pname, sourceKinds, recurse)) {
   1.270 -                String binaryName = fm.inferBinaryName(packageLocn, fo);
   1.271 -                String simpleName = getSimpleName(binaryName);
   1.272 -                if (isValidClassName(simpleName)) {
   1.273 -                    lb.append(fo);
   1.274 +        for (Location packageLocn : locs) {
   1.275 +            try {
   1.276 +                for (JavaFileObject fo : fm.list(packageLocn, pname, sourceKinds, recurse)) {
   1.277 +                    String binaryName = fm.inferBinaryName(packageLocn, fo);
   1.278 +                    String simpleName = getSimpleName(binaryName);
   1.279 +                    if (isValidClassName(simpleName)) {
   1.280 +                        lb.append(fo);
   1.281 +                    }
   1.282                  }
   1.283 +            } catch (IOException ioe) {
   1.284 +                String text = messager.getText("main.file.manager.list", pname);
   1.285 +                throw new ToolException(SYSERR, text, ioe);
   1.286              }
   1.287 -        } catch (IOException ioe) {
   1.288 -            String text = messager.getText("main.file.manager.list", pname);
   1.289 -            throw new ToolException(SYSERR, text, ioe);
   1.290          }
   1.291 -
   1.292          return lb.toList();
   1.293      }
   1.294  
   1.295 @@ -774,24 +848,49 @@
   1.296              return null;
   1.297      }
   1.298  
   1.299 -    private Location getLocation(ModulePackage modpkg) throws ToolException {
   1.300 -        if (location != StandardLocation.MODULE_SOURCE_PATH) {
   1.301 -            return location;
   1.302 +    private List<Location> getLocation(ModulePackage modpkg) throws ToolException {
   1.303 +        if (locations.size() == 1 && !locations.contains(StandardLocation.MODULE_SOURCE_PATH)) {
   1.304 +            return Collections.singletonList(locations.get(0));
   1.305          }
   1.306  
   1.307          if (modpkg.hasModule()) {
   1.308 -            return getModuleLocation(location, modpkg.moduleName);
   1.309 +            return getModuleLocation(locations, modpkg.moduleName);
   1.310          }
   1.311          // TODO: handle invalid results better.
   1.312          ModuleSymbol msym = findModuleOfPackageName(modpkg.packageName);
   1.313          if (msym == null) {
   1.314 -            return null;
   1.315 +            return Collections.emptyList();
   1.316          }
   1.317 -        return getModuleLocation(location, msym.name.toString());
   1.318 +        return getModuleLocation(locations, msym.name.toString());
   1.319      }
   1.320  
   1.321 -    private Location getModuleLocation(Location location, String msymName)
   1.322 -            throws ToolException {
   1.323 +    boolean haveSourceLocationWithModule = false;
   1.324 +
   1.325 +    private List<Location> getModuleLocation(List<Location> locations, String msymName) throws ToolException {
   1.326 +        List<Location> out = new ArrayList<>();
   1.327 +        // search in the patch module first, this overrides others
   1.328 +        if (locations.contains(StandardLocation.PATCH_MODULE_PATH)) {
   1.329 +            Location loc = getModuleLocation(StandardLocation.PATCH_MODULE_PATH, msymName);
   1.330 +            if (loc != null)
   1.331 +                out.add(loc);
   1.332 +        }
   1.333 +        for (Location location : locations) {
   1.334 +            // skip patch module, already done
   1.335 +            if (location == StandardLocation.PATCH_MODULE_PATH) {
   1.336 +                continue;
   1.337 +            } else if (location == StandardLocation.MODULE_SOURCE_PATH) {
   1.338 +                Location loc = getModuleLocation(location, msymName);
   1.339 +                if (loc != null)
   1.340 +                    out.add(loc);
   1.341 +            } else if (location == StandardLocation.SOURCE_PATH) {
   1.342 +                haveSourceLocationWithModule = true;
   1.343 +                out.add(StandardLocation.SOURCE_PATH);
   1.344 +            }
   1.345 +        }
   1.346 +        return out;
   1.347 +    }
   1.348 +
   1.349 +    private Location getModuleLocation(Location location, String msymName) throws ToolException {
   1.350          try {
   1.351              return fm.getLocationForModule(location, msymName);
   1.352          } catch (IOException ioe) {
     2.1 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties	Thu Mar 16 17:13:10 2017 -0700
     2.2 +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties	Thu Mar 16 18:50:50 2017 -0700
     2.3 @@ -258,6 +258,9 @@
     2.4  main.invalid_flag=invalid flag: {0}
     2.5  main.No_modules_packages_or_classes_specified=No modules, packages or classes specified.
     2.6  main.module_not_found=module {0} not found.\n
     2.7 +main.cannot_use_sourcepath_for_modules=cannot use source path for multiple modules {0}
     2.8 +main.module_not_found_on_sourcepath=module {0} not found on source path
     2.9 +main.sourcepath_does_not_contain_module=source path does not contain module {0}
    2.10  main.cant.read=cannot read {0}
    2.11  main.Loading_source_files_for_package=Loading source files for package {0}...
    2.12  main.Loading_source_file=Loading source file {0}...
     3.1 --- a/test/jdk/javadoc/tool/modules/ModuleTestBase.java	Thu Mar 16 17:13:10 2017 -0700
     3.2 +++ b/test/jdk/javadoc/tool/modules/ModuleTestBase.java	Thu Mar 16 18:50:50 2017 -0700
     3.3 @@ -27,7 +27,7 @@
     3.4  import java.nio.file.Path;
     3.5  import java.nio.file.Paths;
     3.6  import java.util.Arrays;
     3.7 -import java.util.Collections;
     3.8 +import java.util.HashSet;
     3.9  import java.util.List;
    3.10  import java.util.Locale;
    3.11  import java.util.Set;
    3.12 @@ -158,6 +158,12 @@
    3.13          }
    3.14      }
    3.15  
    3.16 +    void checkTypesSelected(String... args) throws Exception {
    3.17 +        for (String arg : args) {
    3.18 +            checkDocletOutputPresent("Selected", ElementKind.CLASS, arg);
    3.19 +        }
    3.20 +    }
    3.21 +
    3.22      void checkMembersSelected(String... args) throws Exception {
    3.23          for (String arg : args) {
    3.24              checkDocletOutputPresent("Selected", ElementKind.METHOD, arg);
    3.25 @@ -280,6 +286,17 @@
    3.26          StringWriter sw = new StringWriter();
    3.27          PrintWriter ps = new PrintWriter(sw);
    3.28  
    3.29 +        DocletEnvironment docEnv = null;
    3.30 +
    3.31 +        boolean hasDocComments = false;
    3.32 +
    3.33 +        String hasDocComments(Element e) {
    3.34 +            String comment = docEnv.getElementUtils().getDocComment(e);
    3.35 +            return comment != null && !comment.isEmpty()
    3.36 +                    ? "hasDocComments"
    3.37 +                    : "noDocComments";
    3.38 +        }
    3.39 +
    3.40          // csv style output, for simple regex verification
    3.41          void printDataSet(String header, Set<? extends Element> set) {
    3.42              for (Element e : set) {
    3.43 @@ -290,7 +307,12 @@
    3.44                          ps.print(FS);
    3.45                          ps.print(e.getKind());
    3.46                          ps.print(FS);
    3.47 -                        ps.println(e.getQualifiedName());
    3.48 +                        ps.print(e.getQualifiedName());
    3.49 +                        if (hasDocComments) {
    3.50 +                            ps.print(FS);
    3.51 +                            ps.print(hasDocComments(e));
    3.52 +                        }
    3.53 +                        ps.println();
    3.54                          return null;
    3.55                      }
    3.56  
    3.57 @@ -299,7 +321,12 @@
    3.58                          ps.print(FS);
    3.59                          ps.print(e.getKind());
    3.60                          ps.print(FS);
    3.61 -                        ps.println(e.getQualifiedName());
    3.62 +                        ps.print(e.getQualifiedName());
    3.63 +                        if (hasDocComments) {
    3.64 +                            ps.print(FS);
    3.65 +                            ps.print(hasDocComments(e));
    3.66 +                        }
    3.67 +                        ps.println();
    3.68                          return null;
    3.69                      }
    3.70  
    3.71 @@ -308,7 +335,12 @@
    3.72                          ps.print(FS);
    3.73                          ps.print(ElementKind.CLASS);
    3.74                          ps.print(FS);
    3.75 -                        ps.println(e.getQualifiedName());
    3.76 +                        ps.print(e.getQualifiedName());
    3.77 +                        if (hasDocComments) {
    3.78 +                            ps.print(FS);
    3.79 +                            ps.print(hasDocComments(e));
    3.80 +                        }
    3.81 +                        ps.println();
    3.82                          return null;
    3.83                      }
    3.84  
    3.85 @@ -338,7 +370,12 @@
    3.86                          ps.print(FS);
    3.87                          ps.print(fqn);
    3.88                          ps.print(".");
    3.89 -                        ps.println(e.getSimpleName());
    3.90 +                        ps.print(e.getSimpleName());
    3.91 +                        if (hasDocComments) {
    3.92 +                            ps.print(FS);
    3.93 +                            ps.print(hasDocComments(e));
    3.94 +                        }
    3.95 +                        ps.println();
    3.96                          return null;
    3.97                      }
    3.98                  }.visit(e);
    3.99 @@ -347,6 +384,7 @@
   3.100  
   3.101          @Override
   3.102          public boolean run(DocletEnvironment docenv) {
   3.103 +            this.docEnv = docenv;
   3.104              ps.println("ModuleMode" + FS + docenv.getModuleMode());
   3.105              printDataSet("Specified", docenv.getSpecifiedElements());
   3.106              printDataSet("Included", docenv.getIncludedElements());
   3.107 @@ -369,7 +407,9 @@
   3.108                  addEnclosedElements(docenv, result, me);
   3.109              }
   3.110              for (PackageElement pe : ElementFilter.packagesIn(elements)) {
   3.111 -                addEnclosedElements(docenv, result, docenv.getElementUtils().getModuleOf(pe));
   3.112 +                ModuleElement mdle = docenv.getElementUtils().getModuleOf(pe);
   3.113 +                if (mdle != null)
   3.114 +                    addEnclosedElements(docenv, result, mdle);
   3.115                  addEnclosedElements(docenv, result, pe);
   3.116              }
   3.117              for (TypeElement te : ElementFilter.typesIn(elements)) {
   3.118 @@ -390,7 +430,45 @@
   3.119  
   3.120          @Override
   3.121          public Set<Doclet.Option> getSupportedOptions() {
   3.122 -            return Collections.emptySet();
   3.123 +            Option[] options = {
   3.124 +                new Option() {
   3.125 +                    private final List<String> someOption = Arrays.asList(
   3.126 +                            "-hasDocComments"
   3.127 +                    );
   3.128 +
   3.129 +                    @Override
   3.130 +                    public int getArgumentCount() {
   3.131 +                        return 0;
   3.132 +                    }
   3.133 +
   3.134 +                    @Override
   3.135 +                    public String getDescription() {
   3.136 +                        return "print disposition of doc comments on an element";
   3.137 +                    }
   3.138 +
   3.139 +                    @Override
   3.140 +                    public Option.Kind getKind() {
   3.141 +                        return Option.Kind.STANDARD;
   3.142 +                    }
   3.143 +
   3.144 +                    @Override
   3.145 +                    public List<String> getNames() {
   3.146 +                        return someOption;
   3.147 +                    }
   3.148 +
   3.149 +                    @Override
   3.150 +                    public String getParameters() {
   3.151 +                        return "flag";
   3.152 +                    }
   3.153 +
   3.154 +                    @Override
   3.155 +                    public boolean process(String opt, List<String> arguments) {
   3.156 +                        hasDocComments = true;
   3.157 +                        return true;
   3.158 +                    }
   3.159 +                }
   3.160 +            };
   3.161 +            return new HashSet<>(Arrays.asList(options));
   3.162          }
   3.163  
   3.164          @Override
     4.1 --- a/test/jdk/javadoc/tool/modules/Modules.java	Thu Mar 16 17:13:10 2017 -0700
     4.2 +++ b/test/jdk/javadoc/tool/modules/Modules.java	Thu Mar 16 18:50:50 2017 -0700
     4.3 @@ -35,6 +35,7 @@
     4.4   * @run main Modules
     4.5   */
     4.6  
     4.7 +import java.io.File;
     4.8  import java.io.IOException;
     4.9  import java.nio.file.Files;
    4.10  import java.nio.file.Path;
    4.11 @@ -321,38 +322,6 @@
    4.12      }
    4.13  
    4.14      @Test
    4.15 -    public void testPatchModuleOption(Path base) throws Exception {
    4.16 -        Path src = base.resolve("src");
    4.17 -        Path modulePath = base.resolve("modules");
    4.18 -        Path patchPath = base.resolve("patch");
    4.19 -
    4.20 -        ModuleBuilder mb1 = new ModuleBuilder(tb, "m1");
    4.21 -        mb1.comment("Module on module path.")
    4.22 -                .exports("pkg1")
    4.23 -                .classes("package pkg1; /** Class A */ public class A { }")
    4.24 -                .build(modulePath);
    4.25 -
    4.26 -        tb.writeJavaFiles(patchPath, "package pkg1; /** Class A */ public class A { public static int k; }");
    4.27 -        new JavacTask(tb)
    4.28 -                .files(patchPath.resolve("pkg1/A.java"))
    4.29 -                .run();
    4.30 -
    4.31 -        ModuleBuilder mb2 = new ModuleBuilder(tb, "m2");
    4.32 -        mb2.comment("The second module.")
    4.33 -                .exports("pkg2")
    4.34 -                .requires("m1")
    4.35 -                .classes("package pkg2; /** Class B */ public class B { /** Field f */ public int f = pkg1.A.k; }")
    4.36 -                .write(src);
    4.37 -        execTask("--module-source-path", src.toString(),
    4.38 -                "--patch-module", "m1=" + patchPath.toString(),
    4.39 -                "--module-path", modulePath.toString(),
    4.40 -                "--module", "m2");
    4.41 -        checkModulesSpecified("m2");
    4.42 -        checkPackagesIncluded("pkg2");
    4.43 -        checkMembersSelected("pkg2.B.f");
    4.44 -    }
    4.45 -
    4.46 -    @Test
    4.47      public void testAddReadsOption(Path base) throws Exception {
    4.48          Path src = base.resolve("src");
    4.49          Path modulePath = base.resolve("modules");
    4.50 @@ -550,6 +519,52 @@
    4.51          assertMessagePresent("javadoc: error - module MIA not found");
    4.52      }
    4.53  
    4.54 +    @Test
    4.55 +    public void testSingleModuleOptionWithSourcePath(Path base) throws Exception {
    4.56 +        Path src = base.resolve("src");
    4.57 +        Path mod = createSimpleModule(src, "m1");
    4.58 +        execTask("--source-path", mod.toString(),
    4.59 +                 "--module", "m1");
    4.60 +        checkModulesSpecified("m1");
    4.61 +        checkPackagesIncluded("p");
    4.62 +        checkTypesIncluded("p.C");
    4.63 +    }
    4.64 +
    4.65 +    @Test
    4.66 +    public void testSingleModuleOptionWithMissingModuleInSourcePath(Path base) throws Exception {
    4.67 +        Path src = base.resolve("src");
    4.68 +        Path mod = createSimpleModule(src, "m1");
    4.69 +        execNegativeTask("--source-path", mod.toString(),
    4.70 +                 "--module", "m2");
    4.71 +        assertMessagePresent("source path does not contain module m2");
    4.72 +    }
    4.73 +
    4.74 +    @Test
    4.75 +    public void testMultipleModuleOptionWithSourcePath(Path base) throws Exception {
    4.76 +        Path src = base.resolve("src");
    4.77 +        Path mod = createSimpleModule(src, "m1");
    4.78 +        execNegativeTask("--source-path", mod.toString(),
    4.79 +                 "--module", "m1,m2,m3");
    4.80 +        assertMessagePresent("cannot use source path for multiple modules m1, m2, m3");
    4.81 +    }
    4.82 +
    4.83 +    @Test
    4.84 +    public void testSingleModuleOptionWithNoModuleOnSourcePath(Path base) throws Exception {
    4.85 +        Path src = base.resolve("src");
    4.86 +        Path mod1 = Paths.get(src.toString(), "m1");
    4.87 +        execNegativeTask("--source-path", mod1.toString(),
    4.88 +                 "--module", "m1");
    4.89 +        assertMessagePresent("module m1 not found on source path");
    4.90 +    }
    4.91 +
    4.92 +    Path createSimpleModule(Path src, String mname) throws IOException {
    4.93 +        Path mpath = Paths.get(src.toString(), mname);
    4.94 +        tb.writeJavaFiles(mpath,
    4.95 +                "module " + mname + " { exports p; }",
    4.96 +                "package p; public class C { }");
    4.97 +        return mpath;
    4.98 +    }
    4.99 +
   4.100      void createAuxiliaryModules(Path src) throws IOException {
   4.101  
   4.102          new ModuleBuilder(tb, "J")
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/test/jdk/javadoc/tool/modules/PatchModules.java	Thu Mar 16 18:50:50 2017 -0700
     5.3 @@ -0,0 +1,210 @@
     5.4 +/*
     5.5 + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
     5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     5.7 + *
     5.8 + * This code is free software; you can redistribute it and/or modify it
     5.9 + * under the terms of the GNU General Public License version 2 only, as
    5.10 + * published by the Free Software Foundation.
    5.11 + *
    5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    5.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    5.15 + * version 2 for more details (a copy is included in the LICENSE file that
    5.16 + * accompanied this code).
    5.17 + *
    5.18 + * You should have received a copy of the GNU General Public License version
    5.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    5.21 + *
    5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    5.23 + * or visit www.oracle.com if you need additional information or have any
    5.24 + * questions.
    5.25 + */
    5.26 +
    5.27 +/**
    5.28 + * @test
    5.29 + * @bug 8175346
    5.30 + * @summary Test patch module options
    5.31 + * @modules
    5.32 + *      jdk.javadoc/jdk.javadoc.internal.api
    5.33 + *      jdk.javadoc/jdk.javadoc.internal.tool
    5.34 + *      jdk.compiler/com.sun.tools.javac.api
    5.35 + *      jdk.compiler/com.sun.tools.javac.main
    5.36 + * @library /tools/lib
    5.37 + * @build toolbox.ToolBox toolbox.TestRunner
    5.38 + * @run main PatchModules
    5.39 + */
    5.40 +
    5.41 +import java.nio.file.Path;
    5.42 +import java.nio.file.Paths;
    5.43 +
    5.44 +import toolbox.*;
    5.45 +
    5.46 +public class PatchModules extends ModuleTestBase {
    5.47 +
    5.48 +    public static void main(String... args) throws Exception {
    5.49 +        new PatchModules().runTests();
    5.50 +    }
    5.51 +
    5.52 +    // Case A.1, m2 augmenting m1
    5.53 +    @Test
    5.54 +    public void testPatchModuleOption(Path base) throws Exception {
    5.55 +        Path src = base.resolve("src");
    5.56 +        Path modulePath = base.resolve("modules");
    5.57 +        Path patchPath = base.resolve("patch");
    5.58 +
    5.59 +        ModuleBuilder mb1 = new ModuleBuilder(tb, "m1");
    5.60 +        mb1.comment("Module on module path.")
    5.61 +                .exports("pkg1")
    5.62 +                .classes("package pkg1; /** Class A */ public class A { }")
    5.63 +                .build(modulePath);
    5.64 +
    5.65 +        tb.writeJavaFiles(patchPath, "package pkg1; /** Class A */ public class A { public static int k; }");
    5.66 +        new JavacTask(tb)
    5.67 +                .files(patchPath.resolve("pkg1/A.java"))
    5.68 +                .run();
    5.69 +
    5.70 +        ModuleBuilder mb2 = new ModuleBuilder(tb, "m2");
    5.71 +        mb2.comment("The second module.")
    5.72 +                .exports("pkg2")
    5.73 +                .requires("m1")
    5.74 +                .classes("package pkg2; /** Class B */ public class B { /** Field f */ public int f = pkg1.A.k; }")
    5.75 +                .write(src);
    5.76 +        execTask("--module-source-path", src.toString(),
    5.77 +                "--patch-module", "m1=" + patchPath.toString(),
    5.78 +                "--module-path", modulePath.toString(),
    5.79 +                "--module", "m2");
    5.80 +        checkModulesSpecified("m2");
    5.81 +        checkPackagesIncluded("pkg2");
    5.82 +        checkMembersSelected("pkg2.B.f");
    5.83 +    }
    5.84 +
    5.85 +    // Case A.2: use package, source form of m1 augmenting binary form of m1
    5.86 +    @Test
    5.87 +    public void testPatchModuleWithPackage(Path base)  throws Exception {
    5.88 +        Path modulePath = base.resolve("modules");
    5.89 +        Path moduleSrcPath = base.resolve("modulesSrc");
    5.90 +
    5.91 +        Path mpath = Paths.get(moduleSrcPath.toString(),  "m1");
    5.92 +
    5.93 +        ModuleBuilder mb1 = new ModuleBuilder(tb, "m1");
    5.94 +        mb1.comment("Module m1.")
    5.95 +                .exports("pkg1")
    5.96 +                .classes("package pkg1; /** Class A */ public class A { }")
    5.97 +                .classes("package pkg1.pkg2; /** Class B */ public class B { }")
    5.98 +                .build(modulePath);
    5.99 +
   5.100 +        execTask("-hasDocComments",
   5.101 +                "--module-path", modulePath.toString(),
   5.102 +                "--add-modules", "m1",
   5.103 +                "--patch-module", "m1=" + mpath.toString(),
   5.104 +                "pkg1");
   5.105 +        checkTypesIncluded("pkg1.A hasDocComments");
   5.106 +    }
   5.107 +
   5.108 +     // Case A.2: use subpackages, source form of m1 augmenting binary form of m1
   5.109 +    @Test
   5.110 +    public void testPatchModuleWithSubPackages(Path base) throws Exception {
   5.111 +        Path modulePath = base.resolve("modules");
   5.112 +        Path moduleSrcPath = base.resolve("modulesSrc");
   5.113 +
   5.114 +        Path mpath = Paths.get(moduleSrcPath.toString(),  "m1");
   5.115 +
   5.116 +        ModuleBuilder mb1 = new ModuleBuilder(tb, "m1");
   5.117 +        mb1.comment("Module m1.")
   5.118 +                .exports("pkg1")
   5.119 +                .classes("package pkg1; /** Class A */ public class A { }")
   5.120 +                .classes("package pkg1.pkg2; /** Class B */ public class B { }")
   5.121 +                .build(modulePath);
   5.122 +
   5.123 +        execTask("-hasDocComments",
   5.124 +                "--module-path", modulePath.toString(),
   5.125 +                "--add-modules", "m1",
   5.126 +                "--patch-module", "m1=" + mpath.toString(),
   5.127 +                "-subpackages", "pkg1");
   5.128 +        checkTypesIncluded("pkg1.A hasDocComments");
   5.129 +        checkTypesIncluded("pkg1.pkg2.B hasDocComments");
   5.130 +    }
   5.131 +
   5.132 +    // Case B.1: (jsr166) augment and override system module
   5.133 +    @Test
   5.134 +    public void testPatchModuleModifyingSystemModule(Path base) throws Exception {
   5.135 +        Path src = base.resolve("src");
   5.136 +        Path patchSrc = base.resolve("patch");
   5.137 +
   5.138 +        // build the patching sources
   5.139 +        tb.writeJavaFiles(patchSrc, "package java.util;\n" +
   5.140 +                "/** Class Collection */\n" +
   5.141 +                "public interface Collection<K> {}");
   5.142 +
   5.143 +        tb.writeJavaFiles(patchSrc, "package java.util;\n"
   5.144 +                + "/** Class MyCollection */\n" +
   5.145 +                "public interface MyCollection<K> extends Collection {}");
   5.146 +
   5.147 +        execTask("-hasDocComments", "--patch-module", "java.base=" + patchSrc.toString(),
   5.148 +                "java.util");
   5.149 +
   5.150 +        checkPackagesSpecified("java.util");
   5.151 +        checkTypesIncluded("java.util.Collection hasDocComments",
   5.152 +                "java.util.MyCollection hasDocComments");
   5.153 +    }
   5.154 +
   5.155 +    // Case C.1: patch a user module's sources using source path
   5.156 +    @Test
   5.157 +    public void testPatchModuleUsingSourcePath(Path base) throws Exception {
   5.158 +        Path src = base.resolve("src");
   5.159 +        Path patchSrc = base.resolve("patch");
   5.160 +
   5.161 +        ModuleBuilder mb1 = new ModuleBuilder(tb, "m1");
   5.162 +        mb1.comment("Module m1.")
   5.163 +                .exports("pkg1")
   5.164 +                .classes("package pkg1; /** Class A */ public class A { }")
   5.165 +                .write(src);
   5.166 +
   5.167 +        // build the patching module
   5.168 +        tb.writeJavaFiles(patchSrc, "package pkg1;\n" +
   5.169 +                "/** Class A */ public class A extends java.util.ArrayList { }");
   5.170 +        tb.writeJavaFiles(patchSrc, "package pkg1;\n"
   5.171 +                + "/** Class B */ public class B { }");
   5.172 +
   5.173 +        Path m1src = Paths.get(src.toString(), "m1");
   5.174 +
   5.175 +        execTask("--source-path", m1src.toString(),
   5.176 +                "--patch-module", "m1=" + patchSrc.toString(),
   5.177 +                "pkg1");
   5.178 +
   5.179 +        checkPackagesSpecified("pkg1");
   5.180 +        checkModulesIncluded("m1");
   5.181 +        checkTypesIncluded("pkg1.A", "pkg1.B");
   5.182 +    }
   5.183 +
   5.184 +    // Case C.2: patch a user module's sources using module source path
   5.185 +    @Test
   5.186 +    public void testPatchModuleWithModuleSourcePath(Path base) throws Exception {
   5.187 +        Path src = base.resolve("src");
   5.188 +        Path patchSrc = base.resolve("patch");
   5.189 +
   5.190 +        ModuleBuilder mb1 = new ModuleBuilder(tb, "m1");
   5.191 +        mb1.comment("Module on module-source-path.")
   5.192 +                .exports("pkg1")
   5.193 +                .classes("package pkg1; /** Class A */ public class A { }")
   5.194 +                .write(src);
   5.195 +
   5.196 +        // build the patching module
   5.197 +        tb.writeJavaFiles(patchSrc, "package pkg1;\n" +
   5.198 +                "/** Class A */ public class A extends java.util.ArrayList { }");
   5.199 +        tb.writeJavaFiles(patchSrc, "package pkg1;\n"
   5.200 +                + "/** Class B */ public class B { }");
   5.201 +
   5.202 +
   5.203 +        execTask("--module-source-path", src.toString(),
   5.204 +                "--add-modules", "m1",
   5.205 +                "--patch-module", "m1=" + patchSrc.toString(),
   5.206 +                "pkg1");
   5.207 +
   5.208 +        checkPackagesSpecified("pkg1");
   5.209 +        checkModulesIncluded("m1");
   5.210 +        checkTypesIncluded("pkg1.A", "pkg1.B");
   5.211 +    }
   5.212 +
   5.213 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/test/jdk/javadoc/tool/modules/ReleaseOptions.java	Thu Mar 16 18:50:50 2017 -0700
     6.3 @@ -0,0 +1,99 @@
     6.4 +/*
     6.5 + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
     6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     6.7 + *
     6.8 + * This code is free software; you can redistribute it and/or modify it
     6.9 + * under the terms of the GNU General Public License version 2 only, as
    6.10 + * published by the Free Software Foundation.
    6.11 + *
    6.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    6.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    6.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    6.15 + * version 2 for more details (a copy is included in the LICENSE file that
    6.16 + * accompanied this code).
    6.17 + *
    6.18 + * You should have received a copy of the GNU General Public License version
    6.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    6.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    6.21 + *
    6.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    6.23 + * or visit www.oracle.com if you need additional information or have any
    6.24 + * questions.
    6.25 + */
    6.26 +
    6.27 +/**
    6.28 + * @test
    6.29 + * @bug 8175346
    6.30 + * @summary Test release option interactions
    6.31 + * @modules
    6.32 + *      jdk.javadoc/jdk.javadoc.internal.api
    6.33 + *      jdk.javadoc/jdk.javadoc.internal.tool
    6.34 + *      jdk.compiler/com.sun.tools.javac.api
    6.35 + *      jdk.compiler/com.sun.tools.javac.main
    6.36 + * @library /tools/lib
    6.37 + * @build toolbox.ToolBox toolbox.TestRunner
    6.38 + * @run main ReleaseOptions
    6.39 + */
    6.40 +
    6.41 +import java.nio.file.Path;
    6.42 +import java.nio.file.Paths;
    6.43 +
    6.44 +import toolbox.*;
    6.45 +
    6.46 +public class ReleaseOptions extends ModuleTestBase {
    6.47 +
    6.48 +    public static void main(String... args) throws Exception {
    6.49 +        new ReleaseOptions().runTests();
    6.50 +    }
    6.51 +
    6.52 +    @Test
    6.53 +    public void testReleaseWithPatchModule(Path base) throws Exception {
    6.54 +        Path src = Paths.get(base.toString(), "src");
    6.55 +        Path mpath = Paths.get(src. toString(), "m");
    6.56 +
    6.57 +        tb.writeJavaFiles(mpath,
    6.58 +                "module m { exports p; }",
    6.59 +                "package p; public class C { }");
    6.60 +
    6.61 +        Task.Result result = execNegativeTask("--release", "8",
    6.62 +                "--patch-module", "m=" + mpath.toString(),
    6.63 +                "p");
    6.64 +        assertMessagePresent(".*No source files for package p.*");
    6.65 +        assertMessageNotPresent(".*Exception*");
    6.66 +        assertMessageNotPresent(".java.lang.AssertionError.*");
    6.67 +    }
    6.68 +
    6.69 +    @Test
    6.70 +    public void testReleaseWithSourcepath(Path base) throws Exception {
    6.71 +        Path src = Paths.get(base.toString(), "src");
    6.72 +        Path mpath = Paths.get(src. toString(), "m");
    6.73 +
    6.74 +        tb.writeJavaFiles(mpath,
    6.75 +                "module m { exports p; }",
    6.76 +                "package p; public class C { }");
    6.77 +
    6.78 +        Task.Result result = execNegativeTask("--release", "8",
    6.79 +                "--source-path", mpath.toString(),
    6.80 +                "--module", "m");
    6.81 +        assertMessagePresent(".*(use -source 9 or higher to enable modules).*");
    6.82 +        assertMessageNotPresent(".*Exception*");
    6.83 +        assertMessageNotPresent(".java.lang.AssertionError.*");
    6.84 +    }
    6.85 +
    6.86 +//    @Test TBD, JDK-8175277, argument validation should fail on this
    6.87 +//    public void testReleaseWithModuleSourcepath(Path base) throws Exception {
    6.88 +//        Path src = Paths.get(base.toString(), "src");
    6.89 +//        Path mpath = Paths.get(src.toString(), "m");
    6.90 +//
    6.91 +//        tb.writeJavaFiles(mpath,
    6.92 +//                "module m { exports p; }",
    6.93 +//                "package p; public class C { }");
    6.94 +//
    6.95 +//        Task.Result result = execNegativeTask("--release", "8",
    6.96 +//                "--module-source-path", src.toString(),
    6.97 +//                "--module", "m");
    6.98 +//        assertMessagePresent(".*(use -source 9 or higher to enable modules).*");
    6.99 +//        assertMessageNotPresent(".*Exception*");
   6.100 +//        assertMessageNotPresent(".java.lang.AssertionError.*");
   6.101 +//    }
   6.102 +}