diff options
author | Stephan Herrmann | 2017-09-10 18:06:38 +0000 |
---|---|---|
committer | Stephan Herrmann | 2017-09-11 19:00:41 +0000 |
commit | 9b8300bd40097f83910af2d40fdc1cb6ee0c88af (patch) | |
tree | e351157e74684935db5f54f6df0c0e5e472b6502 | |
parent | 9228b527f2119ceb61b755b355bde00106082ec7 (diff) | |
download | eclipse.jdt.core-9b8300bd40097f83910af2d40fdc1cb6ee0c88af.tar.gz eclipse.jdt.core-9b8300bd40097f83910af2d40fdc1cb6ee0c88af.tar.xz eclipse.jdt.core-9b8300bd40097f83910af2d40fdc1cb6ee0c88af.zip |
Change-Id: Icff39b706fc8a78c404d15030551934ed0976fc9
8 files changed, 354 insertions, 64 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 01b88c51be..398656e3b8 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 @@ -46,8 +46,10 @@ import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.tests.util.Util; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; +import org.eclipse.jdt.internal.compiler.util.JRTUtil; import org.eclipse.jdt.internal.core.ClasspathAttribute; import org.eclipse.jdt.internal.core.ClasspathEntry; +import org.eclipse.jdt.internal.core.builder.ClasspathJrt; import org.eclipse.jdt.internal.core.util.Messages; import junit.framework.Test; @@ -5417,7 +5419,84 @@ public class ModuleBuilderTests extends ModifyingResourceTests { this.problemRequestor); } finally { - this.deleteProject("org.astro.patch"); + this.deleteProject("mod.one.patch"); + } + } + public void testLimitModules1() throws CoreException, IOException { + if (!isJRE9) return; + String save = System.getProperty("modules.to.load"); + JRTUtil.reset(); + ClasspathJrt.resetCaches(); + try { + // allow for a few more than we are using via limit-modules: + System.setProperty("modules.to.load", "java.base,java.desktop,java.datatransfer,java.rmi,java.sql,java.prefs,java.xml"); + IClasspathAttribute[] attributes = { + JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true"), + JavaCore.newClasspathAttribute(IClasspathAttribute.LIMIT_MODULES, "java.base,java.desktop") + }; + IJavaProject project = createJava9ProjectWithJREAttributes("org.astro", new String[]{"src", "src2"}, attributes); + + String[] sources = { + "src/module-info.java", + "module org.astro {\n" + + " requires java.base;\n" + + " requires java.desktop;\n" + + " requires java.datatransfer;\n" + // within the closure of java.desktop + " requires java.sql;\n" + // not included + "}\n", + "src/org/astro/Test2.java", + "package org.astro;\n" + + "class Test2 {\n" + + " java.awt.Window window;\n" + + "}\n", + "src2/org/astro/Test3.java", + "package org.astro;\n" + + "class Test3 {\n" + + " java.awt.datatransfer.Clipboard clippy;\n" + + "}\n" + }; + createSourceFiles(project, sources); + + getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null); + IMarker[] markers = project.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "java.sql cannot be resolved to a module", // outside limited scope + markers); + + this.problemRequestor.reset(); + ICompilationUnit cu = getCompilationUnit("/org.astro/src/module-info.java"); + cu.getWorkingCopy(this.wcOwner, null); + assertProblems( + "Unexpected problems", + "----------\n" + + "1. ERROR in /org.astro/src/module-info.java\n" + + "java.sql cannot be resolved to a module\n" + + "----------\n", + this.problemRequestor); + + this.problemRequestor.reset(); + cu = getCompilationUnit("/org.astro/src/org/astro/Test2.java"); + cu.getWorkingCopy(this.wcOwner, null); + assertProblems( + "Unexpected problems", + "----------\n" + + "----------\n", + this.problemRequestor); + + this.problemRequestor.reset(); + cu = getCompilationUnit("/org.astro/src/org/astro/Test3.java"); + cu.getWorkingCopy(this.wcOwner, null); + assertProblems( + "Unexpected problems", + "----------\n" + + "----------\n", + this.problemRequestor); + + } finally { + this.deleteProject("org.astro"); + System.setProperty("modules.to.load", save); + JRTUtil.reset(); + ClasspathJrt.resetCaches(); } } protected void assertNoErrors() throws CoreException { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java index d26a30c1dd..cda9dbb643 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java @@ -123,6 +123,11 @@ public class JRTUtil { return system; } + /** TEST ONLY (use when changing the "modules.to.load" property). */ + public static void reset() { + images = null; + } + /** * Given the path of a modular image file, this method walks the archive content and * notifies the supplied visitor about packages and files visited. 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 6b2d5a6ace..0b25df9c19 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 @@ -172,6 +172,23 @@ public interface IClasspathAttribute { String PATCH_MODULE = "patch-module"; //$NON-NLS-1$ /** + * Constant for the name of the limit-modules attribute. + * + * <p>The value of this attribute must be a comma-separated list of names of modules + * defined in the classpath entry, to which this attribute is attached. + * The set of modules observable through this entry will be limited to + * the transitive closure of modules in this list.</p> + * + * <p>This attribute is supported for classpath entries of kind + * {@link IClasspathEntry#CPE_CONTAINER}. + * A classpath entry having this attribute must also have the + * {@link #MODULE} attribute with value <code>"true"</code>.</p> + * + * @since 3.13 BETA_JAVA9 + */ + String LIMIT_MODULES = "limit-modules"; //$NON-NLS-1$ + + /** * Constant of the name of the module-main-class attribute. * The classpath entry holding this attribute must refer to a source folder * containing the implementation of a module. 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 914f902ba3..315631353e 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, 201y IBM Corporation and others. + * Copyright (c) 2000, 2017 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -22,6 +22,7 @@ import java.net.URI; import java.nio.file.FileVisitResult; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; @@ -29,6 +30,7 @@ import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.jar.Manifest; import java.util.stream.Collectors; @@ -79,6 +81,10 @@ import org.eclipse.jdt.core.WorkingCopyOwner; import org.eclipse.jdt.core.compiler.CategorizedProblem; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.core.eval.IEvaluationContext; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; +import org.eclipse.jdt.internal.compiler.env.IModule; +import org.eclipse.jdt.internal.compiler.env.IModule.IModuleReference; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.util.JRTUtil; import org.eclipse.jdt.internal.compiler.util.ObjectVector; @@ -643,6 +649,9 @@ public class JavaProject if (info.jrtRoots == null || !info.jrtRoots.containsKey(entryPath)) { ObjectVector imageRoots = new ObjectVector(); loadModulesInJimage(entryPath, imageRoots, rootToResolvedEntries, resolvedEntry, referringEntry); + String limitModules = ClasspathEntry.getExtraAttribute(resolvedEntry, IClasspathAttribute.LIMIT_MODULES); + if (limitModules != null) + imageRoots = filterLimitedModules(entryPath, imageRoots, limitModules); info.setJrtPackageRoots(entryPath, imageRoots); accumulatedRoots.addAll(imageRoots); rootIDs.add(rootID); @@ -691,6 +700,69 @@ public class JavaProject } } + private ObjectVector filterLimitedModules(IPath jrtPath, ObjectVector imageRoots, String limitModules) { + Set<String> limitModulesSet = new HashSet<>(Arrays.asList(limitModules.split(","))); //$NON-NLS-1$ + ModuleLookup lookup = new ModuleLookup(jrtPath.toFile()); + // collect all module roots: + for (int i = 0; i < imageRoots.size(); i++) { + lookup.recordRoot((JrtPackageFragmentRoot) imageRoots.elementAt(i)); + } + // for those contained in limitModules, add the transitive closure: + for (int i = 0; i < imageRoots.size(); i++) { + String moduleName = ((JrtPackageFragmentRoot) imageRoots.elementAt(i)).moduleName; + if (limitModulesSet.contains(moduleName)) + lookup.addTransitive(moduleName); + } + // map the result back to package fragment roots: + ObjectVector result = new ObjectVector(lookup.resultModuleSet.size()); + for (IModule mod : lookup.resultModuleSet) { + result.add(lookup.getRoot(mod)); + } + return result; + } + + /** Helper for computing the transitive closure of a set of modules. */ + private static class ModuleLookup { + File jrtFile; + Map<String, JrtPackageFragmentRoot> modNames2Roots = new HashMap<>(); + Map<String, IModule> modules = new HashMap<>(); + Set<IModule> resultModuleSet = new HashSet<>(); + + public ModuleLookup(File jrtFile) { + this.jrtFile = jrtFile; + } + + void recordRoot(JrtPackageFragmentRoot root) { + this.modNames2Roots.put(root.moduleName, root); + } + void addTransitive(String moduleName) { + IModule module = getModule(moduleName); + if (module != null && this.resultModuleSet.add(module)) { + for (IModuleReference reqRef : module.requires()) + addTransitive(String.valueOf(reqRef.name())); + } + } + private IModule getModule(String moduleName) { + IModule result = this.modules.get(moduleName); + if (result == null) { + JrtPackageFragmentRoot root = this.modNames2Roots.get(moduleName); + if (root != null) { + try { + ClassFileReader classFile = JRTUtil.getClassfile(this.jrtFile, TypeConstants.MODULE_INFO_CLASS_NAME_STRING, root.moduleName); + result = classFile.getModuleDeclaration(); + this.modules.put(moduleName, result); + } catch (IOException | ClassFormatException e) { + JavaCore.getJavaCore().getLog().log(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, "Failed to read module-info.class", e)); //$NON-NLS-1$ + } + } + } + return result; + } + JrtPackageFragmentRoot getRoot(IModule module) { + return this.modNames2Roots.get(String.valueOf(module.name())); + } + } + /** * This bogus package fragment root acts as placeholder plus bridge for the * real one until the module name becomes available. It is useful in certain diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModuleUpdater.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModuleUpdater.java index e570dc0e5f..0da310f22e 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModuleUpdater.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModuleUpdater.java @@ -33,8 +33,10 @@ import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; import org.eclipse.jdt.internal.core.util.Util; /** - * An instance of this class collects add-exports and add-reads options from a project's - * class path entries, and performs the corresponding updates when requested by the compiler. + * An instance of this class collects <code>add-exports</code> and <code>add-reads</code> options from + * a project's class path entries, and performs the corresponding updates when requested by the compiler. + * <p>For <code>patch-module</code> and <code>limit-modules</code> see + * org.eclipse.jdt.internal.core.builder.ModuleEntryProcessor.</p> */ public class ModuleUpdater { diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java index 45c8c7d6fb..97f430c138 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java @@ -271,4 +271,9 @@ public NameEnvironmentAnswer findClass(String typeName, String qualifiedPackageN // return findClass(typeName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, false); } +/** TEST ONLY */ +public static void resetCaches() { + PackageCache.clear(); + ModulesCache.clear(); +} } 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 new file mode 100644 index 0000000000..07736264fe --- /dev/null +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModuleEntryProcessor.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2017 GK Software AG, and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * This is an implementation of an early-draft specification developed under the Java + * Community Process (JCP) and is made available for testing and evaluation purposes + * only. The code is not compatible with any specification of the JCP. + * + * Contributors: + * Stephan Herrmann - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.builder; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jdt.core.IClasspathAttribute; +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IPackageFragmentRoot; +import org.eclipse.jdt.internal.compiler.env.IModule; +import org.eclipse.jdt.internal.compiler.env.IModule.IModuleReference; +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.JrtPackageFragmentRoot; +import org.eclipse.jdt.internal.core.ModuleUpdater; + +/** + * Collection of functions to process classpath attributes relating to modules (from JEP 261). + * For <code>add-exports</code> and <code>add-reads</code> see {@link ModuleUpdater}. + */ +class ModuleEntryProcessor { + + // ------------- patch-module: --------------- + + /** + * Establish that an entry with <code>patch-module</code> appears at position 0, if any. + * 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; + for (int i = 0; i < classpathEntries.length; i++) { + IClasspathEntry entry = classpathEntries[i]; + patchedModule = ClasspathEntry.getExtraAttribute(entry, IClasspathAttribute.PATCH_MODULE); + if (patchedModule != null) { + if (i > 0) { + IClasspathEntry tmp = classpathEntries[0]; + classpathEntries[0] = entry; + classpathEntries[i] = tmp; + } + return patchedModule; + } + } + return null; + } + + /** + * Given that sourceLocation belongs to the project that patches another module, combine this source location + * into the existing {@link IModulePathEntry} for the module to be patched. + * @param sourceLocation source location of the patch project + * @param patchedModule module defined in the target location + * @param moduleEntries map of known module locations + */ + static void combinePatchIntoModuleEntry(ClasspathLocation sourceLocation, IModule patchedModule, Map<String, IModulePathEntry> moduleEntries) { + sourceLocation.setModule(patchedModule); + String patchedModuleName = String.valueOf(patchedModule.name()); + IModulePathEntry mainEntry = moduleEntries.get(patchedModuleName); + ClasspathLocation[] combinedLocations = null; + if (mainEntry instanceof ModulePathEntry.Multi) { + ((ModulePathEntry.Multi) mainEntry).addPatchLocation(sourceLocation); + return; + } else if (mainEntry instanceof ClasspathJrt) { + combinedLocations = new ClasspathLocation[] { (ClasspathLocation) mainEntry, sourceLocation }; + moduleEntries.put(patchedModuleName, new ModulePathEntry.Multi(null, patchedModule, combinedLocations)); + return; + } else if (mainEntry instanceof ModulePathEntry) { + ClasspathLocation[] mainLocs = ((ModulePathEntry) mainEntry).locations; + combinedLocations = Arrays.copyOf(mainLocs, mainLocs.length+1); + combinedLocations[combinedLocations.length-1] = sourceLocation; + } else if (mainEntry instanceof ClasspathLocation) { + combinedLocations = new ClasspathLocation[] { (ClasspathLocation) mainEntry, sourceLocation }; + } else { + throw new IllegalStateException("Cannot patch the module of classpath entry "+mainEntry); //$NON-NLS-1$ + } + moduleEntries.put(patchedModuleName, new ModulePathEntry(null, patchedModule, combinedLocations)); + } + + // ------------- limit-modules: --------------- + + /** + * Reads a <code>limit-modules</code> attribute, and computes the transitive closure of requested modules. + * @param javaProject the current java project + * @param entry the classpath entry to process + * @return a set of module names or <code>null</code> if the classpath attribute was not set. + * @see IClasspathAttribute#LIMIT_MODULES + */ + static Set<String> computeLimitModules(JavaProject javaProject, ClasspathEntry entry) { + String extraAttribute = ClasspathEntry.getExtraAttribute(entry, IClasspathAttribute.LIMIT_MODULES); + if (extraAttribute == null) + return null; + + // collect all modules of this CP entry: + Map<String, IModule> modules = new HashMap<>(); + for (IPackageFragmentRoot root : javaProject.findPackageFragmentRoots(entry)) { + if (root instanceof JrtPackageFragmentRoot) { + IModule module = ((JrtPackageFragmentRoot) root).getModule(); + if (module != null) + modules.put(String.valueOf(module.name()), module); + } + } + + // collect the transitive closure of modules contained in limitSet + Set<String> limitSet = new HashSet<>(Arrays.asList(extraAttribute.split(","))); //$NON-NLS-1$ + Set<String> result = new HashSet<>(limitSet); + for (Map.Entry<String, IModule> moduleEntry: modules.entrySet()) { + if (limitSet.contains(moduleEntry.getKey())) + addTransitive(moduleEntry.getValue(), modules, result); + } + return result; + } + + private static void addTransitive(IModule module, Map<String, IModule> modules, Set<String> result) { + if (module.requires() != null) { + for (int i = 0; i < module.requires().length; i++) { + IModuleReference requires = module.requires()[i]; + String requiredName = String.valueOf(requires.name()); + if (result.add(requiredName)) { + IModule requiredModule = modules.get(requiredName); + if (requiredModule != null) + addTransitive(requiredModule, modules, result); + } + } + } + } +} 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 b587d14648..2a7a9abec3 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 @@ -118,7 +118,7 @@ private void computeClasspathLocations( } IModuleDescription mod = null; - String patchedModuleName = pushPatchToFront(classpathEntries); + String patchedModuleName = ModuleEntryProcessor.pushPatchToFront(classpathEntries); IModule patchedModule = null; nextEntry : for (int i = 0, l = classpathEntries.length; i < l; i++) { @@ -135,6 +135,12 @@ private void computeClasspathLocations( if (target == null) continue nextEntry; boolean isOnModulePath = isOnModulePath(entry); + Set<String> limitModules = ModuleEntryProcessor.computeLimitModules(javaProject, entry); + if (patchedModuleName != null && limitModules != null && !limitModules.contains(patchedModuleName)) { + // TODO(SHMOD) report an error + patchedModuleName = null; + } + if (this.moduleUpdater != null) this.moduleUpdater.computeModuleUpdates(entry); @@ -159,7 +165,7 @@ private void computeClasspathLocations( entry.fullExclusionPatternChars(), entry.ignoreOptionalProblems()); if (patchedModule != null) { - combineIntoModuleEntry(sourceLocation, patchedModule, moduleEntries); + ModuleEntryProcessor.combinePatchIntoModuleEntry(sourceLocation, patchedModule, moduleEntries); } sLocations.add(sourceLocation); continue nextEntry; @@ -218,9 +224,11 @@ private void computeClasspathLocations( ModulePathEntry projectEntry = new ModulePathEntry(prereqJavaProject.getPath(), info, projectLocations.toArray(new ClasspathLocation[projectLocations.size()])); String moduleName = String.valueOf(info.name()); - moduleEntries.put(moduleName, projectEntry); - if (moduleName.equals(patchedModuleName)) - patchedModule = info; + if (limitModules == null || limitModules.contains(moduleName)) { + moduleEntries.put(moduleName, projectEntry); + if (moduleName.equals(patchedModuleName)) + patchedModule = info; + } } continue nextEntry; @@ -247,7 +255,8 @@ private void computeClasspathLocations( // TODO: Ideally we need to do something like mapToModulePathEntry using the path and if it is indeed // a module path entry, then add the corresponding entry here, but that would need the target platform if (moduleEntries != null) { - patchedModule = collectModuleEntries(bLocation, path, isOnModulePath, patchedModuleName, patchedModule, moduleEntries); + patchedModule = collectModuleEntries(bLocation, path, isOnModulePath, + limitModules, patchedModuleName, patchedModule, moduleEntries); } if (binaryLocationsPerProject != null) { // normal builder mode IProject p = resource.getProject(); // can be the project being built @@ -270,7 +279,8 @@ private void computeClasspathLocations( ClasspathLocation bLocation = ClasspathLocation.forLibrary(path.toOSString(), accessRuleSet, externalAnnotationPath, isOnModulePath); bLocations.add(bLocation); if (moduleEntries != null) { - patchedModule = collectModuleEntries(bLocation, path, isOnModulePath, patchedModuleName, patchedModule, moduleEntries); + patchedModule = collectModuleEntries(bLocation, path, isOnModulePath, + limitModules, patchedModuleName, patchedModule, moduleEntries); } } continue nextEntry; @@ -326,35 +336,14 @@ private void computeClasspathLocations( this.modulePathEntries = moduleEntries; } -/** - * Establish that an entry with --patch-module appears at position 0, if any. - * 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 combineIntoModuleEntry()). - */ -private String pushPatchToFront(IClasspathEntry[] classpathEntries) { - String patchedModule = null; - for (int i = 0; i < classpathEntries.length; i++) { - IClasspathEntry entry = classpathEntries[i]; - patchedModule = ClasspathEntry.getExtraAttribute(entry, IClasspathAttribute.PATCH_MODULE); - if (patchedModule != null) { - if (i > 0) { - IClasspathEntry tmp = classpathEntries[0]; - classpathEntries[0] = entry; - classpathEntries[i] = tmp; - } - return patchedModule; - } - } - return null; -} - /** Returns the patched module if that is served by the current (binary) location. */ -IModule collectModuleEntries(ClasspathLocation bLocation, IPath path, boolean isOnModulePath, +IModule collectModuleEntries(ClasspathLocation bLocation, IPath path, boolean isOnModulePath, Set<String> limitModules, String patchedModuleName, IModule patchedModule, Map<String, IModulePathEntry> moduleEntries) { if (bLocation instanceof IMultiModuleEntry) { IMultiModuleEntry binaryModulePathEntry = (IMultiModuleEntry) bLocation; for (String moduleName : binaryModulePathEntry.getModuleNames()) { - moduleEntries.put(moduleName, binaryModulePathEntry); + if (limitModules == null || limitModules.contains(moduleName)) + moduleEntries.put(moduleName, binaryModulePathEntry); } if (patchedModuleName != null) { IModule module = binaryModulePathEntry.getModule(patchedModuleName.toCharArray()); @@ -367,41 +356,19 @@ IModule collectModuleEntries(ClasspathLocation bLocation, IPath path, boolean is IModule module = binaryModulePathEntry.getModule(); if (module != null) { String moduleName = String.valueOf(module.name()); - moduleEntries.put(moduleName, binaryModulePathEntry); - if (patchedModuleName != null) { - if (moduleName.equals(patchedModuleName)) - return module; - // TODO(SHMOD): report problem: patchedModuleName didn't match a module from this location + if (limitModules == null || limitModules.contains(moduleName)) { + moduleEntries.put(moduleName, binaryModulePathEntry); + if (patchedModuleName != null) { + if (moduleName.equals(patchedModuleName)) + return module; + // TODO(SHMOD): report problem: patchedModuleName didn't match a module from this location + } } } } return patchedModule; } -void combineIntoModuleEntry(ClasspathLocation sourceLocation, IModule patchedModule, Map<String, IModulePathEntry> moduleEntries) { - sourceLocation.setModule(patchedModule); - String patchedModuleName = String.valueOf(patchedModule.name()); - IModulePathEntry mainEntry = moduleEntries.get(patchedModuleName); - ClasspathLocation[] combinedLocations = null; - if (mainEntry instanceof ModulePathEntry.Multi) { - ((ModulePathEntry.Multi) mainEntry).addPatchLocation(sourceLocation); - return; - } else if (mainEntry instanceof ClasspathJrt) { - combinedLocations = new ClasspathLocation[] { (ClasspathLocation) mainEntry, sourceLocation }; - moduleEntries.put(patchedModuleName, new ModulePathEntry.Multi(null, patchedModule, combinedLocations)); - return; - } else if (mainEntry instanceof ModulePathEntry) { - ClasspathLocation[] mainLocs = ((ModulePathEntry) mainEntry).locations; - combinedLocations = Arrays.copyOf(mainLocs, mainLocs.length+1); - combinedLocations[combinedLocations.length-1] = sourceLocation; - } else if (mainEntry instanceof ClasspathLocation) { - combinedLocations = new ClasspathLocation[] { (ClasspathLocation) mainEntry, sourceLocation }; - } else { - throw new IllegalStateException("Cannot patch the module of classpath entry "+mainEntry); //$NON-NLS-1$ - } - moduleEntries.put(patchedModuleName, new ModulePathEntry(null, patchedModule, combinedLocations)); -} - protected boolean isOnModulePath(ClasspathEntry entry) { return entry.isModular(); } |