From 134ff1f738789c12523e5e04627bcf666c2a08a4 Mon Sep 17 00:00:00 2001 From: Stephan Herrmann Date: Tue, 23 Apr 2019 12:40:19 +0200 Subject: Bug 546653 - [9] More details in module-related classpath attributes: add add-opens, enhance patch-module Change-Id: I7585b97f7b73ce7948bccb6dd7798fc0b3d9682e Signed-off-by: Stephan Herrmann --- .../jdt/core/tests/model/ModuleBuilderTests.java | 4 +- .../org/eclipse/jdt/core/IClasspathAttribute.java | 43 ++++++++++++++++++++-- .../model/org/eclipse/jdt/core/IJavaProject.java | 3 +- .../org/eclipse/jdt/internal/core/JavaProject.java | 38 ++++++++++++++++--- .../core/builder/ModuleEntryProcessor.java | 13 ++++--- .../jdt/internal/core/builder/NameEnvironment.java | 2 +- 6 files changed, 83 insertions(+), 20 deletions(-) diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java index 2a4edf1f0e..967662fa78 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java @@ -5410,7 +5410,7 @@ public class ModuleBuilderTests extends ModifyingResourceTests { try { IClasspathAttribute[] attributes = { JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true"), - JavaCore.newClasspathAttribute(IClasspathAttribute.PATCH_MODULE, "java.base") + JavaCore.newClasspathAttribute(IClasspathAttribute.PATCH_MODULE, "java.desktop=/missing.path::java.base=/org.astro.patch/src:/org.astro.patch/src2") }; IJavaProject patchProject = createJava9ProjectWithJREAttributes("org.astro.patch", new String[]{"src", "src2"}, attributes); @@ -5466,7 +5466,7 @@ public class ModuleBuilderTests extends ModifyingResourceTests { IJavaProject patchProject = createJava9Project("mod.one.patch"); IClasspathAttribute[] attributes = { JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true"), - JavaCore.newClasspathAttribute(IClasspathAttribute.PATCH_MODULE, "mod.one") + JavaCore.newClasspathAttribute(IClasspathAttribute.PATCH_MODULE, "mod.one=/mod.one.patch") }; addClasspathEntry(patchProject, JavaCore.newLibraryEntry(new Path(jarPath), null, null, null, attributes, false)); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathAttribute.java index c841fb8601..84cd2bd1ac 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathAttribute.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathAttribute.java @@ -136,6 +136,7 @@ public interface IClasspathAttribute { * {@code --add-exports} command line option: {@code /=(,)*}. * Multiple such options are packed as a ':' separated list into a single classpath attribute. * The given exports will be added at compile time.

+ * *

Classpath entries with this attribute should also have a {@link #MODULE} attribute * with value "true".

* @@ -143,11 +144,27 @@ public interface IClasspathAttribute { */ String ADD_EXPORTS = "add-exports"; //$NON-NLS-1$ + /** + * Constant for the name of the add-opens attribute. + * + *

The value of this attribute must adhere to the syntax of javac's + * {@code --add-opens} command line option: {@code /=(,)*}. + * Multiple such options are packed as a ':' separated list into a single classpath attribute. + * The given opens will be added at launch time.

+ * + *

Classpath entries with this attribute should also have a {@link #MODULE} attribute + * with value "true".

+ * + * @since 3.18 + */ + String ADD_OPENS = "add-opens"; //$NON-NLS-1$ + /** * Constant for the name of the add-reads attribute. * *

The value of this attribute must adhere to the syntax of javac's * {@code --add-reads} command line option: {@code =}. + * Multiple such options are packed as a ':' separated list into a single classpath attribute. * The given reads edge will be added at compile time.

* * @since 3.14 @@ -156,10 +173,28 @@ public interface IClasspathAttribute { /** * Constant for the name of the patch-module attribute. - * - *

The value of this attribute must be the name of a module defined in the - * classpath entry, to which this attribute is attached.

- * + * + *

The value of this attribute must adhere to the syntax of javac's + * {@code --patch-module} command line option: {@code =()*}. + * All compilation units found in the locations specified as {@code } + * will be associated with the module specified using its name.

+ * + *

The specified module must be defined by the container, library or project + * referenced by the current classpath entry.

+ * + *

Each {@code } location is the workspace path of either a Java project, + * or a source folder. Specifying a Java project is a shorthand for listing + * all source folders of that project.

+ * + *

The attribute value can be further shortened to just the module name, in which + * case the {@code file} locations will be assumed as all source folders of the + * current Java project. This short format is still understood to maintain compatibility + * with versions prior to 3.18, but it is discouraged moving forward.

+ * + *

If this attributes is attached to a multi-module container, multiple + * attribute values of the format defined above are concatenated into one attribute, + * using {@code "::"} as the separator.

+ * *

This attribute is supported for classpath entries of kind * {@link IClasspathEntry#CPE_CONTAINER}, {@link IClasspathEntry#CPE_LIBRARY} * and {@link IClasspathEntry#CPE_PROJECT}. diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java index 9c9c818f6b..f095b8f82b 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java @@ -615,7 +615,8 @@ public interface IJavaProject extends IParent, IJavaElement, IOpenable { * project is said to represent a module if any of its source package * fragment roots (see {@link IPackageFragmentRoot#K_SOURCE}) contains a * valid Java module descriptor, or if one of its classpath entries - * has a valid {@link IClasspathAttribute#PATCH_MODULE} attribute. + * has a valid {@link IClasspathAttribute#PATCH_MODULE} attribute + * affecting the current project. * In the latter case the corresponding module description of the * location referenced by that classpath entry is returned. * diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java index fdb13ad30c..a2607ba49f 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -22,6 +22,7 @@ import java.nio.file.FileVisitResult; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; @@ -3719,8 +3720,9 @@ public class JavaProject if (module != null) return module; for(IClasspathEntry entry : getRawClasspath()) { - String mainModule = ClasspathEntry.getExtraAttribute(entry, IClasspathAttribute.PATCH_MODULE); - if (mainModule != null) { + List patchedModules = getPatchedModules(entry); + if (patchedModules.size() == 1) { // > 1 is malformed, 0 means not affecting this project + String mainModule = patchedModules.get(0); switch (entry.getEntryKind()) { case IClasspathEntry.CPE_PROJECT: IJavaProject referencedProject = getJavaModel().getJavaProject(entry.getPath().toString()); @@ -3741,6 +3743,32 @@ public class JavaProject return null; } + public List getPatchedModules(IClasspathEntry cpEntry) { + String patchModules = ClasspathEntry.getExtraAttribute(cpEntry, IClasspathAttribute.PATCH_MODULE); + if (patchModules != null) { + List result = new ArrayList<>(); + IPath prjPath = getPath(); + for (String patchModule : patchModules.split("::")) { //$NON-NLS-1$ + int equalsIdx = patchModule.indexOf('='); + if (equalsIdx != -1) { + if (equalsIdx < patchModule.length()-1) { // otherwise malformed? + String locations = patchModule.substring(equalsIdx + 1); + for (String location : locations.split(File.pathSeparator)) { + if (prjPath.isPrefixOf(new Path(location))) { + result.add(patchModule.substring(0, equalsIdx)); + break; + } + } + } + } else { + result.add(patchModule); // old format not specifying a location + } + } + return result; + } + return Collections.emptyList(); + } + public IModuleDescription getAutomaticModuleDescription() throws JavaModelException { boolean nameFromManifest = true; char[] moduleName = AutomaticModuleNaming.determineAutomaticModuleNameFromManifest(getManifest()); @@ -3770,10 +3798,8 @@ public class JavaProject if (module != null) return false; for(IClasspathEntry entry : getRawClasspath()) { - String mainModule = ClasspathEntry.getExtraAttribute(entry, IClasspathAttribute.PATCH_MODULE); - if (mainModule != null) + if (!getPatchedModules(entry).isEmpty()) return false; - } return true; } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModuleEntryProcessor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModuleEntryProcessor.java index 587f64facf..69a77bafab 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModuleEntryProcessor.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModuleEntryProcessor.java @@ -15,6 +15,7 @@ package org.eclipse.jdt.internal.core.builder; import java.util.Arrays; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -23,6 +24,7 @@ import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.internal.compiler.env.IModule; import org.eclipse.jdt.internal.compiler.env.IModulePathEntry; import org.eclipse.jdt.internal.core.ClasspathEntry; +import org.eclipse.jdt.internal.core.JavaProject; import org.eclipse.jdt.internal.core.ModuleUpdater; /** @@ -34,23 +36,22 @@ class ModuleEntryProcessor { // ------------- patch-module: --------------- /** - * Establish that an entry with patch-module appears at position 0, if any. + * Establish that an entry with patch-module appears at position 0, if any and if it affects this project or its source folder(s). * This ensures that in the first iteration we find the patchedModule (see e.g., collectModuleEntries()), * which later can be combined into each src-entry (see {@link #combinePatchIntoModuleEntry(ClasspathLocation, IModule, Map)}). * @see IClasspathAttribute#PATCH_MODULE */ - static String pushPatchToFront(IClasspathEntry[] classpathEntries) { - String patchedModule = null; + static String pushPatchToFront(IClasspathEntry[] classpathEntries, JavaProject javaProject) { for (int i = 0; i < classpathEntries.length; i++) { IClasspathEntry entry = classpathEntries[i]; - patchedModule = ClasspathEntry.getExtraAttribute(entry, IClasspathAttribute.PATCH_MODULE); - if (patchedModule != null) { + List patchedModules = javaProject.getPatchedModules(entry); + if (patchedModules.size() == 1) { if (i > 0) { IClasspathEntry tmp = classpathEntries[0]; classpathEntries[0] = entry; classpathEntries[i] = tmp; } - return patchedModule; + return patchedModules.get(0); } } return null; diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java index 12371d0e28..ba00f5f45c 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java @@ -127,7 +127,7 @@ private void computeClasspathLocations( } IModuleDescription projectModule = javaProject.getModuleDescription(); - String patchedModuleName = ModuleEntryProcessor.pushPatchToFront(classpathEntries); + String patchedModuleName = ModuleEntryProcessor.pushPatchToFront(classpathEntries, javaProject); IModule patchedModule = null; nextEntry : for (int i = 0, l = classpathEntries.length; i < l; i++) { -- cgit v1.2.3