8209865: Incorrect 'multiple elements' notes with Elements#getTypeElement and --release
authorjlahoda
Fri, 21 Sep 2018 12:29:31 +0200 (2018-09-21)
changeset 51832 bf1d479fe7eb
parent 51831 ec03768578c2
child 51833 91fd24cf57d5
8209865: Incorrect 'multiple elements' notes with Elements#getTypeElement and --release Summary: Changing ct.sym to be module-path oriented, rather than class-path oriented. Reviewed-by: jjg
make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java
src/jdk.compiler/share/classes/com/sun/tools/javac/platform/JDKPlatformProvider.java
test/langtools/tools/javac/platform/ReleaseModulesAndTypeElement.java
--- a/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java	Fri Sep 21 16:13:49 2018 +0800
+++ b/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java	Fri Sep 21 12:29:31 2018 +0200
@@ -209,13 +209,15 @@
      * {@code ctDescriptionFile}, using the file as a recipe to create the sigfiles.
      */
     @SuppressWarnings("unchecked")
-    public void createSymbols(String ctDescriptionFileExtra, String ctDescriptionFile, String ctSymLocation, CtSymKind ctSymKind) throws IOException {
+    public void createSymbols(String ctDescriptionFileExtra, String ctDescriptionFile, String ctSymLocation) throws IOException {
         LoadDescriptions data = load(ctDescriptionFileExtra != null ? Paths.get(ctDescriptionFileExtra)
                                                                     : null,
                                      Paths.get(ctDescriptionFile), null);
 
         splitHeaders(data.classes);
 
+        Map<String, Map<Character, String>> package2Version2Module = new HashMap<>();
+
         for (ModuleDescription md : data.modules.values()) {
             for (ModuleHeaderDescription mhd : md.header) {
                 List<String> versionsList =
@@ -224,26 +226,41 @@
                                         md,
                                         mhd,
                                         versionsList);
+                mhd.exports.stream().forEach(pkg -> {
+                    for (char v : mhd.versions.toCharArray()) {
+                        package2Version2Module.computeIfAbsent(pkg, dummy -> new HashMap<>()).put(v, md.name);
+                    }
+                });
             }
         }
 
         for (ClassDescription classDescription : data.classes) {
+            Map<Character, String> version2Module = package2Version2Module.getOrDefault(classDescription.packge().replace('.', '/'), Collections.emptyMap());
             for (ClassHeaderDescription header : classDescription.header) {
-                switch (ctSymKind) {
-                    case JOINED_VERSIONS:
-                        Set<String> jointVersions = new HashSet<>();
-                        jointVersions.add(header.versions);
-                        limitJointVersion(jointVersions, classDescription.fields);
-                        limitJointVersion(jointVersions, classDescription.methods);
-                        writeClassesForVersions(ctSymLocation, classDescription, header, jointVersions);
-                        break;
-                    case SEPARATE:
-                        Set<String> versions = new HashSet<>();
-                        for (char v : header.versions.toCharArray()) {
-                            versions.add("" + v);
+                Set<String> jointVersions = new HashSet<>();
+                jointVersions.add(header.versions);
+                limitJointVersion(jointVersions, classDescription.fields);
+                limitJointVersion(jointVersions, classDescription.methods);
+                Map<String, StringBuilder> module2Versions = new HashMap<>();
+                for (char v : header.versions.toCharArray()) {
+                    String module = version2Module.get(v);
+                    if (module == null) {
+                        if (v >= '9') {
+                            throw new AssertionError("No module for " + classDescription.name +
+                                                     " and version " + v);
                         }
-                        writeClassesForVersions(ctSymLocation, classDescription, header, versions);
-                        break;
+                        module = version2Module.get('9');
+                        if (module == null) {
+                            module = "java.base";
+                        }
+                    }
+                    module2Versions.computeIfAbsent(module, dummy -> new StringBuilder()).append(v);
+                }
+                for (Entry<String, StringBuilder> e : module2Versions.entrySet()) {
+                    Set<String> currentVersions = new HashSet<>(jointVersions);
+                    limitJointVersion(currentVersions, e.getValue().toString());
+                    currentVersions = currentVersions.stream().filter(vers -> !disjoint(vers, e.getValue().toString())).collect(Collectors.toSet());
+                    writeClassesForVersions(ctSymLocation, classDescription, header, e.getKey(), currentVersions);
                 }
             }
         }
@@ -591,7 +608,7 @@
                     newHeader.innerClasses = header.innerClasses;
                     newHeader.runtimeAnnotations = header.runtimeAnnotations;
                     newHeader.signature = header.signature;
-                    newHeader.versions = reduce(versions, header.versions);
+                    newHeader.versions = reduce(header.versions, versions);
 
                     newHeaders.add(newHeader);
                 }
@@ -603,26 +620,30 @@
 
     void limitJointVersion(Set<String> jointVersions, List<? extends FeatureDescription> features) {
         for (FeatureDescription feature : features) {
-            for (String version : jointVersions) {
-                if (!containsAll(feature.versions, version) &&
-                    !disjoint(feature.versions, version)) {
-                    StringBuilder featurePart = new StringBuilder();
-                    StringBuilder otherPart = new StringBuilder();
-                    for (char v : version.toCharArray()) {
-                        if (feature.versions.indexOf(v) != (-1)) {
-                            featurePart.append(v);
-                        } else {
-                            otherPart.append(v);
-                        }
+            limitJointVersion(jointVersions, feature.versions);
+        }
+    }
+
+    void limitJointVersion(Set<String> jointVersions, String versions) {
+        for (String version : jointVersions) {
+            if (!containsAll(versions, version) &&
+                !disjoint(versions, version)) {
+                StringBuilder featurePart = new StringBuilder();
+                StringBuilder otherPart = new StringBuilder();
+                for (char v : version.toCharArray()) {
+                    if (versions.indexOf(v) != (-1)) {
+                        featurePart.append(v);
+                    } else {
+                        otherPart.append(v);
                     }
-                    jointVersions.remove(version);
-                    if (featurePart.length() == 0 || otherPart.length() == 0) {
-                        throw new AssertionError();
-                    }
-                    jointVersions.add(featurePart.toString());
-                    jointVersions.add(otherPart.toString());
-                    break;
                 }
+                jointVersions.remove(version);
+                if (featurePart.length() == 0 || otherPart.length() == 0) {
+                    throw new AssertionError();
+                }
+                jointVersions.add(featurePart.toString());
+                jointVersions.add(otherPart.toString());
+                break;
             }
         }
     }
@@ -646,10 +667,11 @@
     void writeClassesForVersions(String ctSymLocation,
                                  ClassDescription classDescription,
                                  ClassHeaderDescription header,
+                                 String module,
                                  Iterable<String> versions)
             throws IOException {
         for (String ver : versions) {
-            writeClass(ctSymLocation, classDescription, header, ver);
+            writeClass(ctSymLocation, classDescription, header, module, ver);
         }
     }
 
@@ -663,11 +685,6 @@
         }
     }
 
-    public enum CtSymKind {
-        JOINED_VERSIONS,
-        SEPARATE;
-    }
-
     //<editor-fold defaultstate="collapsed" desc="Class Writing">
     void writeModule(String ctSymLocation,
                     ModuleDescription moduleDescription,
@@ -697,7 +714,7 @@
                 attributes);
 
         Path outputClassFile = Paths.get(ctSymLocation,
-                                         version + "-modules",
+                                         version,
                                          moduleDescription.name,
                                          "module-info" + EXTENSION);
 
@@ -713,6 +730,7 @@
     void writeClass(String ctSymLocation,
                     ClassDescription classDescription,
                     ClassHeaderDescription header,
+                    String module,
                     String version) throws IOException {
         List<CPInfo> constantPool = new ArrayList<>();
         constantPool.add(null);
@@ -765,7 +783,13 @@
                 methods.toArray(new Method[0]),
                 attributes);
 
-        Path outputClassFile = Paths.get(ctSymLocation, version, classDescription.name + EXTENSION);
+        Path outputClassFile = Paths.get(ctSymLocation, version);
+
+        if (module != null) {
+            outputClassFile = outputClassFile.resolve(module);
+        }
+
+        outputClassFile = outputClassFile.resolve(classDescription.name + EXTENSION);
 
         Files.createDirectories(outputClassFile.getParent());
 
@@ -3652,8 +3676,7 @@
 
                 new CreateSymbols().createSymbols(ctDescriptionFileExtra,
                                                   ctDescriptionFile,
-                                                  ctSymLocation,
-                                                  CtSymKind.JOINED_VERSIONS);
+                                                  ctSymLocation);
                 break;
         }
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/platform/JDKPlatformProvider.java	Fri Sep 21 16:13:49 2018 +0800
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/platform/JDKPlatformProvider.java	Fri Sep 21 12:29:31 2018 +0200
@@ -45,6 +45,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.TreeSet;
@@ -61,6 +62,8 @@
 import javax.tools.StandardLocation;
 
 import com.sun.source.util.Plugin;
+import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.file.CacheFSInfo;
 import com.sun.tools.javac.file.JavacFileManager;
 import com.sun.tools.javac.jvm.Target;
@@ -252,52 +255,64 @@
                         ctSym2FileSystem.put(file, fs = FileSystems.newFileSystem(file, null));
                     }
 
-                    List<Path> paths = new ArrayList<>();
-                    Path modules = fs.getPath(ctSymVersion + "-modules");
                     Path root = fs.getRootDirectories().iterator().next();
-                    boolean pathsSet = false;
+                    boolean hasModules =
+                            Feature.MODULES.allowedInSource(Source.lookup(sourceVersion));
+                    Path systemModules = root.resolve(ctSymVersion).resolve("system-modules");
                     Charset utf8 = Charset.forName("UTF-8");
 
-                    try (DirectoryStream<Path> dir = Files.newDirectoryStream(root)) {
-                        for (Path section : dir) {
-                            if (section.getFileName().toString().contains(ctSymVersion) &&
-                                !section.getFileName().toString().contains("-")) {
-                                Path systemModules = section.resolve("system-modules");
-
-                                if (Files.isRegularFile(systemModules)) {
-                                    fm.handleOption("--system", Arrays.asList("none").iterator());
+                    if (!hasModules) {
+                        List<Path> paths = new ArrayList<>();
 
-                                    Path jrtModules =
-                                            FileSystems.getFileSystem(URI.create("jrt:/"))
-                                                       .getPath("modules");
-                                    try (Stream<String> lines =
-                                            Files.lines(systemModules, utf8)) {
-                                        lines.map(line -> jrtModules.resolve(line))
-                                             .filter(mod -> Files.exists(mod))
-                                             .forEach(mod -> setModule(fm, mod));
+                        try (DirectoryStream<Path> dir = Files.newDirectoryStream(root)) {
+                            for (Path section : dir) {
+                                if (section.getFileName().toString().contains(ctSymVersion) &&
+                                    !section.getFileName().toString().contains("-")) {
+                                    try (DirectoryStream<Path> modules = Files.newDirectoryStream(section)) {
+                                        for (Path module : modules) {
+                                            paths.add(module);
+                                        }
                                     }
-                                    pathsSet = true;
-                                } else {
-                                    paths.add(section);
                                 }
                             }
                         }
-                    }
 
-                    if (Files.isDirectory(modules)) {
-                        try (DirectoryStream<Path> dir = Files.newDirectoryStream(modules)) {
-                            fm.handleOption("--system", Arrays.asList("none").iterator());
+                        fm.setLocationFromPaths(StandardLocation.PLATFORM_CLASS_PATH, paths);
+                    } else if (Files.isRegularFile(systemModules)) {
+                        fm.handleOption("--system", Arrays.asList("none").iterator());
 
-                            for (Path module : dir) {
-                                fm.setLocationForModule(StandardLocation.SYSTEM_MODULES,
-                                                        module.getFileName().toString(),
-                                                        Stream.concat(paths.stream(),
-                                                                      Stream.of(module))
-                                  .collect(Collectors.toList()));
+                        Path jrtModules =
+                                FileSystems.getFileSystem(URI.create("jrt:/"))
+                                           .getPath("modules");
+                        try (Stream<String> lines =
+                                Files.lines(systemModules, utf8)) {
+                            lines.map(line -> jrtModules.resolve(line))
+                                 .filter(mod -> Files.exists(mod))
+                                 .forEach(mod -> setModule(fm, mod));
+                        }
+                    } else {
+                        Map<String, List<Path>> module2Paths = new HashMap<>();
+
+                        try (DirectoryStream<Path> dir = Files.newDirectoryStream(root)) {
+                            for (Path section : dir) {
+                                if (section.getFileName().toString().contains(ctSymVersion) &&
+                                    !section.getFileName().toString().contains("-")) {
+                                    try (DirectoryStream<Path> modules = Files.newDirectoryStream(section)) {
+                                        for (Path module : modules) {
+                                            module2Paths.computeIfAbsent(module.getFileName().toString(), dummy -> new ArrayList<>()).add(module);
+                                        }
+                                    }
+                                }
                             }
                         }
-                    } else if (!pathsSet) {
-                        fm.setLocationFromPaths(StandardLocation.PLATFORM_CLASS_PATH, paths);
+
+                        fm.handleOption("--system", Arrays.asList("none").iterator());
+
+                        for (Entry<String, List<Path>> e : module2Paths.entrySet()) {
+                            fm.setLocationForModule(StandardLocation.SYSTEM_MODULES,
+                                                    e.getKey(),
+                                                    e.getValue());
+                        }
                     }
 
                     return fm;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/platform/ReleaseModulesAndTypeElement.java	Fri Sep 21 12:29:31 2018 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018, 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 8209865
+ * @summary Verify that when reading from ct.sym, classes are only visible from modules from which
+ *          they are exported.
+ * @modules jdk.compiler
+ * @build ReleaseModulesAndTypeElement
+ * @compile -processor ReleaseModulesAndTypeElement --release 11 ReleaseModulesAndTypeElement.java
+ */
+
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.ModuleElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Elements;
+
+@SupportedAnnotationTypes("*")
+public class ReleaseModulesAndTypeElement extends AbstractProcessor {
+
+    @Override
+    public boolean process(Set<? extends TypeElement> roots, RoundEnvironment roundEnv) {
+        Elements elements = processingEnv.getElementUtils();
+        if (elements.getTypeElement(JX_A_P_GENERATED) == null) {
+            throw new AssertionError("jx.a.p.Generated not found by unqualified search!");
+        }
+        ModuleElement javaBase = elements.getModuleElement("java.base");
+        if (elements.getTypeElement(javaBase, JX_A_P_GENERATED) != null) {
+            throw new AssertionError("jx.a.p.Generated found in java.base!");
+        }
+        ModuleElement javaCompiler = elements.getModuleElement("java.compiler");
+        if (elements.getTypeElement(javaCompiler, JX_A_P_GENERATED) == null) {
+            throw new AssertionError("jx.a.p.Generated not found in java.compiler!");
+        }
+        return false;
+    }
+    //where:
+        private static final String JX_A_P_GENERATED = "javax.annotation.processing.Generated";
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latestSupported();
+    }
+
+}