From c798229d351d6daa2232cff6c15750336659223e Mon Sep 17 00:00:00 2001 From: Jay Arthanareeswaran Date: Thu, 6 Jul 2017 17:13:33 +0530 Subject: Bug 477291: [1.9] Support JRE 9 in JSR199 implementation Change-Id: Idfbcd6c2e40fbbc1a325dbe43950284404642fc8 Signed-off-by: Jay Arthanareeswaran --- modules/mod.one/model9/abc/A.java | 2 + modules/mod.one/module-info.java | 8 + org.eclipse.jdt.compiler.apt.tests/.classpath | 2 +- .../META-INF/MANIFEST.MF | 2 + .../build.properties | 4 +- .../java9/java9api.jar | Bin 0 -> 25089 bytes .../lib/apttestprocessors.jar | Bin 206804 -> 206825 bytes .../lib/apttestprocessors8.jar | Bin 216090 -> 216111 bytes org.eclipse.jdt.compiler.apt.tests/pom.xml | 6 +- .../modules/mod.a/abc/internal/A.java | 3 + .../modules/mod.a/abc/internal/TypeInAModule.java | 5 + .../modules/mod.a/abc/internal/pqr/A.java | 2 + .../mod_locations/modules/mod.a/module-info.java | 7 + .../mod_locations/modules/mod.b/abc/A.java | 3 + .../mod_locations/modules/mod.b/module-info.java | 6 + .../mod_locations/modules/mod.b/pqr/ext/B.java | 2 + .../resources/targets/model9/p/A.java | 3 + .../targets/model9a/internal/GenericType.java | 7 + org.eclipse.jdt.compiler.apt/.classpath | 1 + org.eclipse.jdt.compiler.apt/META-INF/MANIFEST.MF | 2 + org.eclipse.jdt.compiler.apt/build.properties | 8 +- org.eclipse.jdt.compiler.apt/lib/java9api.jar | Bin 0 -> 25089 bytes org.eclipse.jdt.compiler.apt/pom.xml | 21 +- .../jdt/internal/compiler/apt/util/Archive.java | 4 +- .../compiler/apt/util/EclipseFileManager.java | 672 +++++++++++++++----- .../compiler/apt/util/EclipseFileObject.java | 4 +- .../internal/compiler/apt/util/JrtFileSystem.java | 188 +++--- .../compiler/apt/util/ModuleLocationHandler.java | 246 ++++++++ org.eclipse.jdt.compiler.tool.tests/.classpath | 1 + org.eclipse.jdt.compiler.tool.tests/.gitignore | 1 + .../META-INF/MANIFEST.MF | 2 + .../build.properties | 2 + .../lib/java9api.jar | Bin 0 -> 25089 bytes org.eclipse.jdt.compiler.tool.tests/pom.xml | 23 + .../tool/tests/CompilerInvocationTests.java | 22 +- .../tool/tests/CompilerToolJava9Tests.java | 374 +++++++++++ .../tests/ForwardingStandardJavaFileManager.java | 36 +- org.eclipse.jdt.compiler.tool/.classpath | 1 + org.eclipse.jdt.compiler.tool/META-INF/MANIFEST.MF | 2 + org.eclipse.jdt.compiler.tool/build.properties | 6 +- org.eclipse.jdt.compiler.tool/lib/java9api.jar | Bin 0 -> 25089 bytes org.eclipse.jdt.compiler.tool/pom.xml | 21 +- .../internal/compiler/tool/EclipseCompiler.java | 10 + .../compiler/tool/EclipseCompilerImpl.java | 220 +++++-- .../internal/compiler/tool/EclipseFileManager.java | 700 ++++++++++++++++----- .../internal/compiler/tool/EclipseFileObject.java | 4 +- .../jdt/internal/compiler/tool/JrtFileSystem.java | 177 +++--- .../compiler/tool/ModuleLocationHandler.java | 260 ++++++++ .../compiler/regression/BatchCompilerTest.java | 4 +- .../jdt/internal/compiler/batch/ClasspathJar.java | 10 +- .../jdt/internal/compiler/batch/ClasspathJrt.java | 10 +- .../internal/compiler/batch/CompilationUnit.java | 3 + .../eclipse/jdt/internal/compiler/batch/Main.java | 89 ++- .../jdt/internal/compiler/batch/ModuleFinder.java | 50 +- .../internal/compiler/env/ICompilationUnit.java | 3 + org.eclipse.jdt.core/jdtCompilerAdapter.jar | Bin 0 -> 14525 bytes pom.xml | 1 + 57 files changed, 2611 insertions(+), 629 deletions(-) create mode 100644 modules/mod.one/model9/abc/A.java create mode 100644 modules/mod.one/module-info.java create mode 100644 org.eclipse.jdt.compiler.apt.tests/java9/java9api.jar create mode 100644 org.eclipse.jdt.compiler.apt.tests/resources/mod_locations/modules/mod.a/abc/internal/A.java create mode 100644 org.eclipse.jdt.compiler.apt.tests/resources/mod_locations/modules/mod.a/abc/internal/TypeInAModule.java create mode 100644 org.eclipse.jdt.compiler.apt.tests/resources/mod_locations/modules/mod.a/abc/internal/pqr/A.java create mode 100644 org.eclipse.jdt.compiler.apt.tests/resources/mod_locations/modules/mod.a/module-info.java create mode 100644 org.eclipse.jdt.compiler.apt.tests/resources/mod_locations/modules/mod.b/abc/A.java create mode 100644 org.eclipse.jdt.compiler.apt.tests/resources/mod_locations/modules/mod.b/module-info.java create mode 100644 org.eclipse.jdt.compiler.apt.tests/resources/mod_locations/modules/mod.b/pqr/ext/B.java create mode 100644 org.eclipse.jdt.compiler.apt.tests/resources/targets/model9/p/A.java create mode 100644 org.eclipse.jdt.compiler.apt.tests/resources/targets/model9a/internal/GenericType.java create mode 100644 org.eclipse.jdt.compiler.apt/lib/java9api.jar create mode 100644 org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/ModuleLocationHandler.java create mode 100644 org.eclipse.jdt.compiler.tool.tests/.gitignore create mode 100644 org.eclipse.jdt.compiler.tool.tests/lib/java9api.jar create mode 100644 org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/CompilerToolJava9Tests.java create mode 100644 org.eclipse.jdt.compiler.tool/lib/java9api.jar create mode 100644 org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/ModuleLocationHandler.java create mode 100644 org.eclipse.jdt.core/jdtCompilerAdapter.jar diff --git a/modules/mod.one/model9/abc/A.java b/modules/mod.one/model9/abc/A.java new file mode 100644 index 0000000000..c9f3f0aa06 --- /dev/null +++ b/modules/mod.one/model9/abc/A.java @@ -0,0 +1,2 @@ +package targets.model9.abc; +public class A {} \ No newline at end of file diff --git a/modules/mod.one/module-info.java b/modules/mod.one/module-info.java new file mode 100644 index 0000000000..1fc3123a21 --- /dev/null +++ b/modules/mod.one/module-info.java @@ -0,0 +1,8 @@ +@java.lang.Deprecated() +module mod.one { + exports targets.model9; + + requires java.base; + requires java.compiler; + requires java.sql; +} diff --git a/org.eclipse.jdt.compiler.apt.tests/.classpath b/org.eclipse.jdt.compiler.apt.tests/.classpath index 6d510c6323..2dc14fa091 100644 --- a/org.eclipse.jdt.compiler.apt.tests/.classpath +++ b/org.eclipse.jdt.compiler.apt.tests/.classpath @@ -4,7 +4,7 @@ - + diff --git a/org.eclipse.jdt.compiler.apt.tests/META-INF/MANIFEST.MF b/org.eclipse.jdt.compiler.apt.tests/META-INF/MANIFEST.MF index 31d60e1a90..5db66bc805 100644 --- a/org.eclipse.jdt.compiler.apt.tests/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.compiler.apt.tests/META-INF/MANIFEST.MF @@ -19,3 +19,5 @@ Export-Package: org.eclipse.jdt.compiler.apt.tests, org.eclipse.jdt.compiler.apt.tests.processors.visitors Import-Package: org.eclipse.jdt.internal.compiler.tool;resolution:=optional Eclipse-BundleShape: dir +Bundle-ClassPath: java9/java9api.jar, + . diff --git a/org.eclipse.jdt.compiler.apt.tests/build.properties b/org.eclipse.jdt.compiler.apt.tests/build.properties index bc8963d977..7df12f4db2 100644 --- a/org.eclipse.jdt.compiler.apt.tests/build.properties +++ b/org.eclipse.jdt.compiler.apt.tests/build.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2006, 2013 BEA Systems Inc. and others +# Copyright (c) 2006, 2017 BEA Systems Inc. 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 @@ -20,7 +20,9 @@ bin.includes = about.html,\ test.xml,\ META-INF/,\ resources/,\ + java9/,\ lib/,\ . src.includes = about.html compilerArg=-proc:none +jars.extra.classpath = java9/java9api.jar diff --git a/org.eclipse.jdt.compiler.apt.tests/java9/java9api.jar b/org.eclipse.jdt.compiler.apt.tests/java9/java9api.jar new file mode 100644 index 0000000000..fd56ad100e Binary files /dev/null and b/org.eclipse.jdt.compiler.apt.tests/java9/java9api.jar differ diff --git a/org.eclipse.jdt.compiler.apt.tests/lib/apttestprocessors.jar b/org.eclipse.jdt.compiler.apt.tests/lib/apttestprocessors.jar index bb84956cf9..856d5d047d 100644 Binary files a/org.eclipse.jdt.compiler.apt.tests/lib/apttestprocessors.jar and b/org.eclipse.jdt.compiler.apt.tests/lib/apttestprocessors.jar differ diff --git a/org.eclipse.jdt.compiler.apt.tests/lib/apttestprocessors8.jar b/org.eclipse.jdt.compiler.apt.tests/lib/apttestprocessors8.jar index 64ef0d26d8..e312f51cb8 100644 Binary files a/org.eclipse.jdt.compiler.apt.tests/lib/apttestprocessors8.jar and b/org.eclipse.jdt.compiler.apt.tests/lib/apttestprocessors8.jar differ diff --git a/org.eclipse.jdt.compiler.apt.tests/pom.xml b/org.eclipse.jdt.compiler.apt.tests/pom.xml index 8207b4da7b..5f86a1629a 100644 --- a/org.eclipse.jdt.compiler.apt.tests/pom.xml +++ b/org.eclipse.jdt.compiler.apt.tests/pom.xml @@ -1,6 +1,6 @@ + xml + ${project.build.directory}/compilelogs + true + + **/package.html + + false + + maven-antrun-plugin diff --git a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/Archive.java b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/Archive.java index 8b46bbb4fc..3f8da7c636 100644 --- a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/Archive.java +++ b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/Archive.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2016 IBM Corporation and others. + * Copyright (c) 2006, 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 @@ -75,7 +75,7 @@ public class Archive { } } - public ArchiveFileObject getArchiveFileObject(String fileName, Charset charset) { + public ArchiveFileObject getArchiveFileObject(String fileName, String module, Charset charset) { return new ArchiveFileObject(this.file, fileName, charset); } diff --git a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java index 4f287645bf..76d1b62df7 100644 --- a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java +++ b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java @@ -22,20 +22,27 @@ import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.nio.charset.Charset; +import java.nio.file.Path; +import java.nio.file.Paths; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.MissingResourceException; +import java.util.Objects; import java.util.ResourceBundle; +import java.util.ServiceLoader; import java.util.Set; import java.util.StringTokenizer; import java.util.zip.ZipException; +import javax.lang.model.SourceVersion; import javax.tools.FileObject; import javax.tools.JavaFileObject; import javax.tools.JavaFileObject.Kind; @@ -43,14 +50,25 @@ import javax.tools.StandardJavaFileManager; import javax.tools.StandardLocation; import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; +import org.eclipse.jdt.internal.compiler.apt.util.JrtFileSystem.JrtFileObject; +import org.eclipse.jdt.internal.compiler.apt.util.ModuleLocationHandler.LocationContainer; +import org.eclipse.jdt.internal.compiler.apt.util.ModuleLocationHandler.LocationWrapper; +import org.eclipse.jdt.internal.compiler.apt.util.ModuleLocationHandler.ModuleLocationWrapper; import org.eclipse.jdt.internal.compiler.batch.FileSystem; +import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; import org.eclipse.jdt.internal.compiler.batch.Main; import org.eclipse.jdt.internal.compiler.batch.Main.ResourceBundleFactory; +import org.eclipse.jdt.internal.compiler.batch.ModuleFinder; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.env.AccessRestriction; import org.eclipse.jdt.internal.compiler.env.AccessRule; import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.parser.Parser; +import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; +import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; +import org.eclipse.jdt.internal.compiler.util.Util; /** * Implementation of the Standard Java File Manager @@ -61,27 +79,30 @@ public class EclipseFileManager implements StandardJavaFileManager { static final int HAS_BOOTCLASSPATH = 2; static final int HAS_ENDORSED_DIRS = 4; static final int HAS_PROCESSORPATH = 8; + static final int HAS_PROC_MODULEPATH = 16; Map archivesCache; Charset charset; Locale locale; - Map> locations; + ModuleLocationHandler locationHandler; final Map classloaders; int flags; + boolean isOnJvm9; + File jrtHome; + JrtFileSystem jrtSystem; public ResourceBundle bundle; public EclipseFileManager(Locale locale, Charset charset) { this.locale = locale == null ? Locale.getDefault() : locale; this.charset = charset == null ? Charset.defaultCharset() : charset; - this.locations = new HashMap<>(); + this.locationHandler = new ModuleLocationHandler(); this.classloaders = new HashMap<>(); this.archivesCache = new HashMap<>(); + this.isOnJvm9 = isRunningJvm9(); try { - this.setLocation(StandardLocation.PLATFORM_CLASS_PATH, getDefaultBootclasspath()); - Iterable defaultClasspath = getDefaultClasspath(); - this.setLocation(StandardLocation.CLASS_PATH, defaultClasspath); - this.setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, defaultClasspath); + initialize(Util.getJavaHome()); } catch (IOException e) { + e.printStackTrace(); // ignore } try { @@ -90,13 +111,27 @@ public class EclipseFileManager implements StandardJavaFileManager { System.out.println("Missing resource : " + Main.bundleName.replace('.', '/') + ".properties for locale " + locale); //$NON-NLS-1$//$NON-NLS-2$ } } + protected void initialize(File javahome) throws IOException { + if (this.isOnJvm9) { + this.jrtSystem = new JrtFileSystem(javahome); + this.archivesCache.put(javahome, this.jrtSystem); + this.jrtHome = javahome; + this.locationHandler.newSystemLocation(StandardLocation.SYSTEM_MODULES, this.jrtSystem); + } else { + this.setLocation(StandardLocation.PLATFORM_CLASS_PATH, getDefaultBootclasspath()); + } + Iterable defaultClasspath = getDefaultClasspath(); + this.setLocation(StandardLocation.CLASS_PATH, defaultClasspath); + // No annotation module path by default + this.setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, defaultClasspath); + } /* (non-Javadoc) * @see javax.tools.JavaFileManager#close() */ @Override public void close() throws IOException { - if (this.locations != null) this.locations.clear(); + this.locationHandler.close(); for (Archive archive : this.archivesCache.values()) { archive.close(); } @@ -107,35 +142,18 @@ public class EclipseFileManager implements StandardJavaFileManager { this.classloaders.clear(); } - private void collectAllMatchingFiles(File file, String normalizedPackageName, Set kinds, boolean recurse, ArrayList collector) { - if (!isArchive(file)) { - // we must have a directory - File currentFile = new File(file, normalizedPackageName); - if (!currentFile.exists()) return; - String path; - try { - path = currentFile.getCanonicalPath(); - } catch (IOException e) { - return; - } - if (File.separatorChar == '/') { - if (!path.endsWith(normalizedPackageName)) return; - } else if (!path.endsWith(normalizedPackageName.replace('/', File.separatorChar))) return; - File[] files = currentFile.listFiles(); - if (files != null) { - // this was a directory - for (File f : files) { - if (f.isDirectory() && recurse) { - collectAllMatchingFiles(file, normalizedPackageName + '/' + f.getName(), kinds, recurse, collector); - } else { - final Kind kind = getKind(f); - if (kinds.contains(kind)) { - collector.add(new EclipseFileObject(normalizedPackageName + f.getName(), f.toURI(), kind, this.charset)); - } + private void collectAllMatchingFiles(Location location, File file, String normalizedPackageName, Set kinds, boolean recurse, ArrayList collector) { + if (file.equals(this.jrtHome)) { + if (location instanceof ModuleLocationWrapper) { + List list = this.jrtSystem.list((ModuleLocationWrapper) location, normalizedPackageName, kinds, recurse, this.charset); + for (JrtFileObject fo : list) { + Kind kind = getKind(getExtension(fo.entryName)); + if (kinds.contains(kind)) { + collector.add(fo); } } } - } else { + } else if (isArchive(file)) { Archive archive = this.getArchive(file); if (archive == Archive.UNKNOWN_ARCHIVE) return; String key = normalizedPackageName; @@ -151,8 +169,7 @@ public class EclipseFileManager implements StandardJavaFileManager { for (String[] entry : types) { final Kind kind = getKind(getExtension(entry[0])); if (kinds.contains(kind)) { - // TODO BETA_JAVA9 - entry[1] contains the module, use it. - collector.add(archive.getArchiveFileObject(packageName + entry[0], this.charset)); + collector.add(archive.getArchiveFileObject(packageName + entry[0], entry[1], this.charset)); } } } @@ -164,8 +181,34 @@ public class EclipseFileManager implements StandardJavaFileManager { for (String[] entry : types) { final Kind kind = getKind(getExtension(entry[0])); if (kinds.contains(kind)) { - // TODO BETA_JAVA9 - entry[1] contains the module, use it. - collector.add(archive.getArchiveFileObject(key + entry[0], this.charset)); + collector.add(archive.getArchiveFileObject(key + entry[0], entry[1], this.charset)); + } + } + } + } + } else { + // we must have a directory + File currentFile = new File(file, normalizedPackageName); + if (!currentFile.exists()) return; + String path; + try { + path = currentFile.getCanonicalPath(); + } catch (IOException e) { + return; + } + if (File.separatorChar == '/') { + if (!path.endsWith(normalizedPackageName)) return; + } else if (!path.endsWith(normalizedPackageName.replace('/', File.separatorChar))) return; + File[] files = currentFile.listFiles(); + if (files != null) { + // this was a directory + for (File f : files) { + if (f.isDirectory() && recurse) { + collectAllMatchingFiles(location, file, normalizedPackageName + '/' + f.getName(), kinds, recurse, collector); + } else { + final Kind kind = getKind(f); + if (kinds.contains(kind)) { + collector.add(new EclipseFileObject(normalizedPackageName + f.getName(), f.toURI(), kind, this.charset)); } } } @@ -223,6 +266,7 @@ public class EclipseFileManager implements StandardJavaFileManager { */ @Override public ClassLoader getClassLoader(Location location) { + validateNonModuleLocation(location); Iterable files = getLocation(location); if (files == null) { // location is unknown @@ -342,6 +386,7 @@ public class EclipseFileManager implements StandardJavaFileManager { */ @Override public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException { + validateNonModuleLocation(location); Iterable files = getLocation(location); if (files == null) { throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$ @@ -361,7 +406,7 @@ public class EclipseFileManager implements StandardJavaFileManager { Archive archive = getArchive(file); if (archive != Archive.UNKNOWN_ARCHIVE) { if (archive.contains(normalizedFileName)) { - return archive.getArchiveFileObject(normalizedFileName, this.charset); + return archive.getArchiveFileObject(normalizedFileName, null, this.charset); } } } @@ -385,6 +430,7 @@ public class EclipseFileManager implements StandardJavaFileManager { @Override public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException { + validateOutputLocation(location); Iterable files = getLocation(location); if (files == null) { throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$ @@ -405,6 +451,7 @@ public class EclipseFileManager implements StandardJavaFileManager { */ @Override public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) throws IOException { + validateNonModuleLocation(location); if (kind != Kind.CLASS && kind != Kind.SOURCE) { throw new IllegalArgumentException("Invalid kind : " + kind);//$NON-NLS-1$ } @@ -428,7 +475,7 @@ public class EclipseFileManager implements StandardJavaFileManager { Archive archive = getArchive(file); if (archive != Archive.UNKNOWN_ARCHIVE) { if (archive.contains(normalizedFileName)) { - return archive.getArchiveFileObject(normalizedFileName, this.charset); + return archive.getArchiveFileObject(normalizedFileName, null, this.charset); } } } @@ -442,6 +489,7 @@ public class EclipseFileManager implements StandardJavaFileManager { @Override public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException { + validateOutputLocation(location); if (kind != Kind.CLASS && kind != Kind.SOURCE) { throw new IllegalArgumentException("Invalid kind : " + kind);//$NON-NLS-1$ } @@ -554,8 +602,14 @@ public class EclipseFileManager implements StandardJavaFileManager { */ @Override public Iterable getLocation(Location location) { - if (this.locations == null) return null; - return this.locations.get(location.getName()); + if (location instanceof LocationWrapper) { + return getFiles(((LocationWrapper) location).paths); + } + LocationWrapper loc = this.locationHandler.getLocation(location, ""); //$NON-NLS-1$ + if (loc == null) { + return null; + } + return getFiles(loc.getPaths()); } private Iterable getOutputDir(String string) { @@ -577,123 +631,193 @@ public class EclipseFileManager implements StandardJavaFileManager { @Override public boolean handleOption(String current, Iterator remaining) { try { - if ("-bootclasspath".equals(current)) {//$NON-NLS-1$ - if (remaining.hasNext()) { - final Iterable bootclasspaths = getPathsFrom(remaining.next()); - if (bootclasspaths != null) { - Iterable iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH); - if ((this.flags & EclipseFileManager.HAS_ENDORSED_DIRS) == 0 - && (this.flags & EclipseFileManager.HAS_EXT_DIRS) == 0) { - // override default bootclasspath - setLocation(StandardLocation.PLATFORM_CLASS_PATH, bootclasspaths); - } else if ((this.flags & EclipseFileManager.HAS_ENDORSED_DIRS) != 0) { - // endorseddirs have been processed first - setLocation(StandardLocation.PLATFORM_CLASS_PATH, - concatFiles(iterable, bootclasspaths)); - } else { - // extdirs have been processed first - setLocation(StandardLocation.PLATFORM_CLASS_PATH, - prependFiles(iterable, bootclasspaths)); + switch(current) { + case "-bootclasspath": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable bootclasspaths = getPathsFrom(remaining.next()); + if (bootclasspaths != null) { + Iterable iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH); + if ((this.flags & EclipseFileManager.HAS_ENDORSED_DIRS) == 0 + && (this.flags & EclipseFileManager.HAS_EXT_DIRS) == 0) { + // override default bootclasspath + setLocation(StandardLocation.PLATFORM_CLASS_PATH, bootclasspaths); + } else if ((this.flags & EclipseFileManager.HAS_ENDORSED_DIRS) != 0) { + // endorseddirs have been processed first + setLocation(StandardLocation.PLATFORM_CLASS_PATH, + concatFiles(iterable, bootclasspaths)); + } else { + // extdirs have been processed first + setLocation(StandardLocation.PLATFORM_CLASS_PATH, + prependFiles(iterable, bootclasspaths)); + } } + this.flags |= EclipseFileManager.HAS_BOOTCLASSPATH; + return true; + } else { + throw new IllegalArgumentException(); } - this.flags |= EclipseFileManager.HAS_BOOTCLASSPATH; - return true; - } else { - throw new IllegalArgumentException(); - } - } - if ("-classpath".equals(current) || "-cp".equals(current)) {//$NON-NLS-1$//$NON-NLS-2$ - if (remaining.hasNext()) { + case "--system": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable classpaths = getPathsFrom(remaining.next()); + if (classpaths != null) { + Iterable iterable = getLocation(StandardLocation.SYSTEM_MODULES); + if (iterable != null) { + setLocation(StandardLocation.SYSTEM_MODULES, + concatFiles(iterable, classpaths)); + } else { + setLocation(StandardLocation.SYSTEM_MODULES, classpaths); + } + } + return true; + } else { + throw new IllegalArgumentException(); + } + case "--upgrade-module-path": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable classpaths = getPathsFrom(remaining.next()); + if (classpaths != null) { + Iterable iterable = getLocation(StandardLocation.UPGRADE_MODULE_PATH); + if (iterable != null) { + setLocation(StandardLocation.UPGRADE_MODULE_PATH, + concatFiles(iterable, classpaths)); + } else { + setLocation(StandardLocation.UPGRADE_MODULE_PATH, classpaths); + } + } + return true; + } else { + throw new IllegalArgumentException(); + } + case "-classpath": //$NON-NLS-1$ + case "-cp": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable classpaths = getPathsFrom(remaining.next()); + if (classpaths != null) { + Iterable iterable = getLocation(StandardLocation.CLASS_PATH); + if (iterable != null) { + setLocation(StandardLocation.CLASS_PATH, + concatFiles(iterable, classpaths)); + } else { + setLocation(StandardLocation.CLASS_PATH, classpaths); + } + if ((this.flags & EclipseFileManager.HAS_PROCESSORPATH) == 0) { + setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, classpaths); + } else if ((this.flags & EclipseFileManager.HAS_PROC_MODULEPATH) == 0) { + if (this.isOnJvm9) + setLocation(StandardLocation.ANNOTATION_PROCESSOR_MODULE_PATH, classpaths); + } + } + return true; + } else { + throw new IllegalArgumentException(); + } + case "--module-path": //$NON-NLS-1$ + case "-p": //$NON-NLS-1$ final Iterable classpaths = getPathsFrom(remaining.next()); if (classpaths != null) { - Iterable iterable = getLocation(StandardLocation.CLASS_PATH); + Iterable iterable = getLocation(StandardLocation.MODULE_PATH); if (iterable != null) { - setLocation(StandardLocation.CLASS_PATH, - concatFiles(iterable, classpaths)); + setLocation(StandardLocation.MODULE_PATH, concatFiles(iterable, classpaths)); } else { - setLocation(StandardLocation.CLASS_PATH, classpaths); + setLocation(StandardLocation.MODULE_PATH, classpaths); } if ((this.flags & EclipseFileManager.HAS_PROCESSORPATH) == 0) { setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, classpaths); + } else if ((this.flags & EclipseFileManager.HAS_PROC_MODULEPATH) == 0) { + if (this.isOnJvm9) + setLocation(StandardLocation.ANNOTATION_PROCESSOR_MODULE_PATH, classpaths); } } return true; - } else { - throw new IllegalArgumentException(); - } - } - if ("-encoding".equals(current)) {//$NON-NLS-1$ - if (remaining.hasNext()) { - this.charset = Charset.forName(remaining.next()); - return true; - } else { - throw new IllegalArgumentException(); - } - } - if ("-sourcepath".equals(current)) {//$NON-NLS-1$ - if (remaining.hasNext()) { - final Iterable sourcepaths = getPathsFrom(remaining.next()); - if (sourcepaths != null) setLocation(StandardLocation.SOURCE_PATH, sourcepaths); - return true; - } else { - throw new IllegalArgumentException(); - } - } - if ("-extdirs".equals(current)) {//$NON-NLS-1$ - if (remaining.hasNext()) { - Iterable iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH); - setLocation(StandardLocation.PLATFORM_CLASS_PATH, - concatFiles(iterable, getExtdirsFrom(remaining.next()))); - this.flags |= EclipseFileManager.HAS_EXT_DIRS; - return true; - } else { - throw new IllegalArgumentException(); - } - } - if ("-endorseddirs".equals(current)) {//$NON-NLS-1$ - if (remaining.hasNext()) { - Iterable iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH); - setLocation(StandardLocation.PLATFORM_CLASS_PATH, - prependFiles(iterable, getEndorsedDirsFrom(remaining.next()))); - this.flags |= EclipseFileManager.HAS_ENDORSED_DIRS; - return true; - } else { - throw new IllegalArgumentException(); - } - } - if ("-d".equals(current)) { //$NON-NLS-1$ - if (remaining.hasNext()) { - final Iterable outputDir = getOutputDir(remaining.next()); - if (outputDir != null) { - setLocation(StandardLocation.CLASS_OUTPUT, outputDir); + case "-encoding": //$NON-NLS-1$ + if (remaining.hasNext()) { + this.charset = Charset.forName(remaining.next()); + return true; + } else { + throw new IllegalArgumentException(); } - return true; - } else { - throw new IllegalArgumentException(); - } - } - if ("-s".equals(current)) { //$NON-NLS-1$ - if (remaining.hasNext()) { - final Iterable outputDir = getOutputDir(remaining.next()); - if (outputDir != null) { - setLocation(StandardLocation.SOURCE_OUTPUT, outputDir); + case "-sourcepath": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable sourcepaths = getPathsFrom(remaining.next()); + if (sourcepaths != null) setLocation(StandardLocation.SOURCE_PATH, sourcepaths); + return true; + } else { + throw new IllegalArgumentException(); } - return true; - } else { - throw new IllegalArgumentException(); - } - } - if ("-processorpath".equals(current)) {//$NON-NLS-1$ - if (remaining.hasNext()) { - final Iterable processorpaths = getPathsFrom(remaining.next()); - if (processorpaths != null) { - setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, processorpaths); + case "--module-source-path": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable sourcepaths = getPathsFrom(remaining.next()); + if (sourcepaths != null && this.isOnJvm9) + setLocation(StandardLocation.MODULE_SOURCE_PATH, sourcepaths); + return true; + } else { + throw new IllegalArgumentException(); + } + case "-extdirs": //$NON-NLS-1$ + if (this.isOnJvm9) { + throw new IllegalArgumentException(); + } + if (remaining.hasNext()) { + Iterable iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH); + setLocation(StandardLocation.PLATFORM_CLASS_PATH, + concatFiles(iterable, getExtdirsFrom(remaining.next()))); + this.flags |= EclipseFileManager.HAS_EXT_DIRS; + return true; + } else { + throw new IllegalArgumentException(); + } + case "-endorseddirs": //$NON-NLS-1$ + if (remaining.hasNext()) { + Iterable iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH); + setLocation(StandardLocation.PLATFORM_CLASS_PATH, + prependFiles(iterable, getEndorsedDirsFrom(remaining.next()))); + this.flags |= EclipseFileManager.HAS_ENDORSED_DIRS; + return true; + } else { + throw new IllegalArgumentException(); + } + case "-d": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable outputDir = getOutputDir(remaining.next()); + if (outputDir != null) { + setLocation(StandardLocation.CLASS_OUTPUT, outputDir); + } + return true; + } else { + throw new IllegalArgumentException(); + } + case "-s": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable outputDir = getOutputDir(remaining.next()); + if (outputDir != null) { + setLocation(StandardLocation.SOURCE_OUTPUT, outputDir); + } + return true; + } else { + throw new IllegalArgumentException(); + } + case "-processorpath": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable processorpaths = getPathsFrom(remaining.next()); + if (processorpaths != null) { + setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, processorpaths); + } + this.flags |= EclipseFileManager.HAS_PROCESSORPATH; + return true; + } else { + throw new IllegalArgumentException(); + } + case "--processor-module-path": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable processorpaths = getPathsFrom(remaining.next()); + if (processorpaths != null && this.isOnJvm9) { + setLocation(StandardLocation.ANNOTATION_PROCESSOR_MODULE_PATH, processorpaths); + this.flags |= EclipseFileManager.HAS_PROC_MODULEPATH; + } + return true; + } else { + throw new IllegalArgumentException(); } - this.flags |= EclipseFileManager.HAS_PROCESSORPATH; - return true; - } else { - throw new IllegalArgumentException(); - } } } catch (IOException e) { // ignore @@ -706,7 +830,12 @@ public class EclipseFileManager implements StandardJavaFileManager { */ @Override public boolean hasLocation(Location location) { - return this.locations != null && this.locations.containsKey(location.getName()); + try { + return getLocationForModule(location, "") != null; //$NON-NLS-1$ + } catch (IOException e) { + // nothing to do + } + return false; } /* (non-Javadoc) @@ -714,6 +843,7 @@ public class EclipseFileManager implements StandardJavaFileManager { */ @Override public String inferBinaryName(Location location, JavaFileObject file) { + validateNonModuleLocation(location); String name = file.getName(); JavaFileObject javaFileObject = null; int index = name.lastIndexOf('.'); @@ -762,7 +892,7 @@ public class EclipseFileManager implements StandardJavaFileManager { @Override public Iterable list(Location location, String packageName, Set kinds, boolean recurse) throws IOException { - + validateNonModuleLocation(location); Iterable allFilesInLocations = getLocation(location); if (allFilesInLocations == null) { throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$ @@ -771,7 +901,7 @@ public class EclipseFileManager implements StandardJavaFileManager { ArrayList collector = new ArrayList<>(); String normalizedPackageName = normalized(packageName); for (File file : allFilesInLocations) { - collectAllMatchingFiles(file, normalizedPackageName, kinds, recurse, collector); + collectAllMatchingFiles(location, file, normalizedPackageName, kinds, recurse, collector); } return collector; } @@ -802,26 +932,26 @@ public class EclipseFileManager implements StandardJavaFileManager { } return list; } - + private boolean isRunningJvm9() { + return (SourceVersion.latest().compareTo(SourceVersion.RELEASE_8) > 0); + } /* (non-Javadoc) * @see javax.tools.StandardJavaFileManager#setLocation(javax.tools.JavaFileManager.Location, java.lang.Iterable) */ @Override - public void setLocation(Location location, Iterable path) throws IOException { - if (path != null) { - if (location.isOutputLocation()) { - // output location - int count = 0; - for (Iterator iterator = path.iterator(); iterator.hasNext(); ) { - iterator.next(); - count++; - } - if (count != 1) { - throw new IllegalArgumentException("output location can only have one path");//$NON-NLS-1$ - } + public void setLocation(Location location, Iterable files) throws IOException { + if (location.isOutputLocation()) { + // output location + int count = 0; + for (Iterator iterator = files.iterator(); iterator.hasNext(); ) { + iterator.next(); + count++; + } + if (count != 1) { + throw new IllegalArgumentException("output location can only have one path");//$NON-NLS-1$ } - this.locations.put(location.getName(), path); } + this.locationHandler.setLocation(location, "", getPaths(files)); //$NON-NLS-1$ } public void setLocale(Locale locale) { @@ -1110,4 +1240,226 @@ public class EclipseFileManager implements StandardJavaFileManager { } return MessageFormat.format(message, (Object[]) arguments); } + private Iterable getFiles(final Iterable paths) { + if (paths == null) + return null; + return () -> new Iterator() { + Iterator original = paths.iterator(); + @Override + public boolean hasNext() { + return this.original.hasNext(); + } + @Override + public File next() { + return this.original.next().toFile(); + } + }; + } + private Iterable getPaths(final Iterable files) { + if (files == null) + return null; + return () -> new Iterator() { + Iterator original = files.iterator(); + @Override + public boolean hasNext() { + return this.original.hasNext(); + } + @Override + public Path next() { + return this.original.next().toPath(); + } + }; + } + + private void validateFileObject(FileObject file) { + // FIXME: fill-up + } + private void validateModuleLocation(Location location, String modName) { + Objects.requireNonNull(location); + if (modName == null) { + throw new IllegalArgumentException("module must not be null"); //$NON-NLS-1$ + } + if (this.isOnJvm9) { + if (!location.isModuleOrientedLocation() && !location.isOutputLocation()) { + throw new IllegalArgumentException("location is module related :" + location.getName()); //$NON-NLS-1$ + } + } + } + private void validateNonModuleLocation(Location location) { + Objects.requireNonNull(location); + if (this.isOnJvm9) { + if (location.isModuleOrientedLocation() && location.isOutputLocation()) { + throw new IllegalArgumentException("location is module related :" + location.getName()); //$NON-NLS-1$ + } + } + } + private void validateOutputLocation(Location location) { + Objects.requireNonNull(location); + if (!location.isOutputLocation()) { + throw new IllegalArgumentException("location is not output location :" + location.getName()); //$NON-NLS-1$ + } + } + @Override + public Iterable getJavaFileObjects(Path... paths) { + return getJavaFileObjectsFromPaths(Arrays.asList(paths)); + } + + @Override + public Iterable getJavaFileObjectsFromPaths(Iterable paths) { + return getJavaFileObjectsFromFiles(getFiles(paths)); + } + + @Override + public Iterable getLocationAsPaths(Location location) { + if (location instanceof LocationWrapper) { + return ((LocationWrapper) location).paths; + } + LocationWrapper loc = this.locationHandler.getLocation(location); + if (loc == null) { + return null; + } + return loc.getPaths(); + } + + @Override + public void setLocationFromPaths(Location location, Collection paths) throws IOException { + setLocation(location, getFiles(paths)); + if (location == StandardLocation.MODULE_PATH) { + // FIXME: same for module source path? + Map options = new HashMap<>(); + // FIXME: Find a way to get the options from the EclipseCompiler and pass it to the parser. + // FIXME: need to be the latest and not hardcoded value + options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_9); + options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_9); + options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_9); + CompilerOptions compilerOptions = new CompilerOptions(options); + ProblemReporter problemReporter = + new ProblemReporter( + DefaultErrorHandlingPolicies.proceedWithAllProblems(), + compilerOptions, + new DefaultProblemFactory()); + for (Path path : paths) { + List mp = ModuleFinder.findModules(path.toFile(), null, + new Parser(problemReporter, true), null, true); + for (Classpath cp : mp) { + Collection moduleNames = cp.getModuleNames(null); + for (String string : moduleNames) { + Path p = Paths.get(cp.getPath()); + setLocationForModule(StandardLocation.MODULE_PATH, string, Collections.singletonList(p)); + } + } + } + } + } + + @Override + public boolean contains(Location location, FileObject fo) throws IOException { + validateFileObject(fo); + Iterable files = getLocation(location); + if (files == null) { + throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$ + } + for (File file : files) { + if (file.isDirectory()) { + if (fo instanceof EclipseFileObject) { + Path filepath = ((EclipseFileObject) fo).f.toPath(); + if (filepath.startsWith(Paths.get(file.toURI()).toAbsolutePath())) { + return true; + } + } + } else if (isArchive(file)) { + if (fo instanceof ArchiveFileObject) { + Archive archive = getArchive(file); + if (archive != Archive.UNKNOWN_ARCHIVE) { + if (archive.contains(((ArchiveFileObject) fo ).entryName)) { + return true; + } + } + } + } + } + return false; + } + + @Override + public Location getLocationForModule(Location location, String moduleName) throws IOException { + validateModuleLocation(location, moduleName); + return this.locationHandler.getLocation(location, moduleName); + } + + @Override + public Location getLocationForModule(Location location, JavaFileObject fo) { + validateModuleLocation(location, ""); //$NON-NLS-1$ + Path path = null; + if (fo instanceof ArchiveFileObject) { + path = ((ArchiveFileObject) fo).file.toPath(); + return this.locationHandler.getLocation(location, path); + } else if (fo instanceof EclipseFileObject) { + path = ((EclipseFileObject) fo).f.toPath(); + try { + path = path.toRealPath(); + } catch (IOException e) { + e.printStackTrace(); + } + LocationContainer container = this.locationHandler.getLocation(location); + while (path != null) { + Location loc = container.get(path); + if (loc != null) + return loc; + path = path.getParent(); + } + } + return null; + } + + @Override + public ServiceLoader getServiceLoader(Location location, Class service) throws IOException { + // FIXME: Need special handling in case of module class loaders. + return ServiceLoader.load(service, getClassLoader(location)); + } + + @Override + public String inferModuleName(Location location) throws IOException { + if (location instanceof ModuleLocationWrapper) { + ModuleLocationWrapper wrapper = (ModuleLocationWrapper) location; + return wrapper.modName; + } + return null; + } + + @Override + public Iterable> listLocationsForModules(Location location) { + validateModuleLocation(location, ""); //$NON-NLS-1$ + return this.locationHandler.listLocationsForModules(location); + } + + @Override + public Path asPath(FileObject file) { + validateFileObject(file); + EclipseFileObject eclFile = (EclipseFileObject) file; + if (eclFile.f != null) { + return eclFile.f.toPath(); + } + return null; + } + + @Override + public void setLocationForModule(Location location, String moduleName, Collection paths) throws IOException { + validateModuleLocation(location, moduleName); + this.locationHandler.setLocation(location, moduleName, paths); + if (location == StandardLocation.MODULE_SOURCE_PATH) { + LocationWrapper wrapper = this.locationHandler.getLocation(StandardLocation.CLASS_OUTPUT, moduleName); + if (wrapper == null) { + wrapper = this.locationHandler.getLocation(StandardLocation.CLASS_OUTPUT, ""); //$NON-NLS-1$ + if (wrapper != null) { + Iterator iterator = wrapper.paths.iterator(); + if (iterator.hasNext()) { + // Per module output location is always a singleton list + Path path = iterator.next().resolve(moduleName); + this.locationHandler.setLocation(StandardLocation.CLASS_OUTPUT, moduleName, Collections.singletonList(path)); + } + } + } + } + } } diff --git a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileObject.java b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileObject.java index e72f450caa..ac0c637e19 100644 --- a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileObject.java +++ b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileObject.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2011 IBM Corporation and others. + * Copyright (c) 2006, 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 @@ -37,7 +37,7 @@ import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; * Implementation of a Java file object that corresponds to a file on the file system */ public class EclipseFileObject extends SimpleJavaFileObject { - private File f; + File f; private Charset charset; private boolean parentsExist; // parent directories exist diff --git a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/JrtFileSystem.java b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/JrtFileSystem.java index 56e5708b67..ccc41133ec 100644 --- a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/JrtFileSystem.java +++ b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/JrtFileSystem.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2017 IBM Corporation. + * Copyright (c) 2015, 2017 IBM Corporation. * 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,142 +22,128 @@ import java.io.Reader; import java.io.Writer; import java.net.URI; import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; import java.nio.charset.Charset; -import java.nio.file.DirectoryStream; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.Hashtable; +import java.util.HashMap; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import java.util.zip.ZipException; +import javax.tools.JavaFileObject; + +import org.eclipse.jdt.internal.compiler.apt.util.ModuleLocationHandler.ModuleLocationWrapper; 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.util.JRTUtil; public class JrtFileSystem extends Archive { private static URI JRT_URI = URI.create("jrt:/"); //$NON-NLS-1$ - private static final String BOOT_MODULE = "jrt-fs.jar"; //$NON-NLS-1$ - - private static final String MODULES_SUBDIR = "/modules"; //$NON-NLS-1$ + static final String BOOT_MODULE = "jrt-fs.jar"; //$NON-NLS-1$ - private static final String DEFAULT_PACKAGE = ""; //$NON-NLS-1$ - - private Set typesCache = null; + public HashMap modulePathMap; + Path modules; + private java.nio.file.FileSystem jrtfs; public JrtFileSystem(File file) throws ZipException, IOException { this.file = file; initialize(); } - private void initialize() throws IOException { + public void initialize() throws IOException { // initialize packages - this.packagesCache = new Hashtable<>(); - this.typesCache = new HashSet<>(); - if (!this.file.getName().equals(BOOT_MODULE)) return; - java.nio.file.FileSystem fs = FileSystems.getFileSystem(JRT_URI); - Iterable roots = fs.getRootDirectories(); - for (java.nio.file.Path path : roots) { - try (DirectoryStream stream = Files.newDirectoryStream(path)) { - for (final java.nio.file.Path subdir: stream) { - if (subdir.toString().equals(MODULES_SUBDIR)) { - Files.walkFileTree(subdir, new FileVisitor() { + this.modulePathMap = new HashMap<>(); + URL jrtPath = null; + + if (this.file.exists()) { + jrtPath = Paths.get(this.file.toPath().toString(), "lib", JRTUtil.JRT_FS_JAR).toUri().toURL(); //$NON-NLS-1$ + try (URLClassLoader loader = new URLClassLoader(new URL[] { jrtPath })) { + HashMap env = new HashMap<>(); + this.jrtfs = FileSystems.newFileSystem(JRT_URI, env, loader); + this.modules = this.jrtfs.getPath("/modules"); //$NON-NLS-1$ + } + } else { + return; + } - @Override - public FileVisitResult preVisitDirectory(java.nio.file.Path entry, BasicFileAttributes attrs) - throws IOException { - int count = entry.getNameCount(); - if (count < 2) return FileVisitResult.CONTINUE; - return FileVisitResult.CONTINUE; - } + org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(this.file, + new org.eclipse.jdt.internal.compiler.util.JRTUtil.JrtFileVisitor() { - @Override - public FileVisitResult visitFile(java.nio.file.Path entry, BasicFileAttributes attrs) throws IOException { - int count = entry.getNameCount(); - if (entry == subdir || count < 3) return FileVisitResult.CONTINUE; - if (count == 3) { - cacheTypes(DEFAULT_PACKAGE, entry.getName(2).toString(), entry.getName(1).toString()); - } else { - cacheTypes(entry.subpath(2, count - 1).toString(), - entry.getName(count - 1).toString(), entry.getName(1).toString()); - } - return FileVisitResult.CONTINUE; - } + @Override + public FileVisitResult visitPackage(Path dir, Path mod, BasicFileAttributes attrs) + throws IOException { + return FileVisitResult.CONTINUE; + } - @Override - public FileVisitResult visitFileFailed(java.nio.file.Path entry, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } + @Override + public FileVisitResult visitFile(Path f, Path mod, BasicFileAttributes attrs) + throws IOException { + return FileVisitResult.CONTINUE; + } - @Override - public FileVisitResult postVisitDirectory(java.nio.file.Path entry, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - }); - } - } - } catch (Exception e) { - throw new IOException(e.getMessage()); + @Override + public FileVisitResult visitModule(Path mod) throws IOException { + JrtFileSystem.this.modulePathMap.put(mod.getFileName().toString(), mod); + return FileVisitResult.CONTINUE; } - } - } - - public ArchiveFileObject getArchiveFileObject(String fileName, Charset charset) { - return new JrtFileObject(this.file, fileName, null, charset); + }, JRTUtil.NOTIFY_MODULES); } - + + public List list(ModuleLocationWrapper location, String packageName, + Set kinds, boolean recurse, Charset charset) { + String module = location.modName; + Path mPath = this.modules.resolve(module); + Path resolve = mPath.resolve(packageName); + java.util.List files = null; + try (Stream p = Files.list(resolve)) { + files = p.filter((path) -> { + if (Files.isDirectory(path)) + return false; + else + return true; + }).collect(Collectors.toList()); + } catch (IOException e) { + // ignore + } + List result = new ArrayList<>(); + for (Path p: files) { + result.add(new JrtFileObject(this.file, p, module, charset)); + } + return result; + } @Override - public boolean contains(String entryName) { - return this.typesCache.contains(entryName); + public ArchiveFileObject getArchiveFileObject(String fileName, String module, Charset charset) { + return new JrtFileObject(this.file, this.modules.resolve(module).resolve(fileName), module, charset); } - protected void cacheTypes(String packageName, String typeName, String module) { - int length = packageName.length(); - if (length > 0 && packageName.charAt(packageName.length() - 1) != '/') { - packageName = packageName + '/'; - } - ArrayList types = this.packagesCache.get(packageName); - if (typeName == null) return; - if (types == null) { - types = new ArrayList<>(); - types.add(new String[]{typeName, module}); - this.packagesCache.put(packageName, types); - } else { - types.add(new String[]{typeName, module}); - } - this.typesCache.add(packageName + typeName); - } @Override - public List getTypes(String packageName) { - // package name is expected to ends with '/' - if (this.packagesCache == null) { - try { - this.initialize(); - } catch(IOException e) { - return Collections.emptyList(); - } - } - return this.packagesCache.get(packageName); + public boolean contains(String entryName) { + // FIXME + return false; } - + @Override public String toString() { return "JRT: " + (this.file == null ? "UNKNOWN_ARCHIVE" : this.file.getAbsolutePath()); //$NON-NLS-1$ //$NON-NLS-2$ } class JrtFileObject extends ArchiveFileObject { - IModule module = null; // FIXME(SHMOD): always null?? https://bugs.eclipse.org/517059 - private JrtFileObject(File file, String fileName, IModule module, Charset charset) { - super(file, fileName, charset); - this.module = module; + String module; + Path path; + private JrtFileObject(File file, Path path, String module, Charset charset) { + super(file, path.toString(), charset); + this.path = path; } @Override @@ -169,7 +155,9 @@ public class JrtFileSystem extends Archive { protected ClassFileReader getClassReader() { ClassFileReader reader = null; try { - reader = ClassFileReader.readFromJrt(this.file, this.module, this.entryName); + byte[] content = JRTUtil.getClassfileContent(this.file, this.entryName, this.module); + if (content == null) return null; + return new ClassFileReader(content, this.entryName.toCharArray()); } catch (ClassFormatException e) { e.printStackTrace(); } catch (IOException e) { @@ -186,12 +174,12 @@ public class JrtFileSystem extends Archive { public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { try { return Util.getCharContents(this, ignoreEncodingErrors, - org.eclipse.jdt.internal.compiler.util.JRTUtil.getClassfileContent(this.file, this.entryName, new String(this.module.name())), + org.eclipse.jdt.internal.compiler.util.JRTUtil.getClassfileContent(this.file, this.entryName, this.module), this.charset.name()); } catch (ClassFormatException e) { e.printStackTrace(); + return null; } - return null; } /* (non-Javadoc) @@ -207,7 +195,7 @@ public class JrtFileSystem extends Archive { */ @Override public String getName() { - return this.entryName; + return this.path.toString(); } /* (non-Javadoc) @@ -215,7 +203,7 @@ public class JrtFileSystem extends Archive { */ @Override public InputStream openInputStream() throws IOException { - return org.eclipse.jdt.internal.compiler.util.JRTUtil.getContentFromJrt(this.file, this.entryName, null); + return Files.newInputStream(this.path); } /* (non-Javadoc) diff --git a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/ModuleLocationHandler.java b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/ModuleLocationHandler.java new file mode 100644 index 0000000000..eee15f6b1c --- /dev/null +++ b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/ModuleLocationHandler.java @@ -0,0 +1,246 @@ +package org.eclipse.jdt.internal.compiler.apt.util; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.tools.JavaFileManager.Location; +import javax.tools.StandardLocation; + +import org.eclipse.jdt.internal.compiler.batch.ClasspathJrt; + +public class ModuleLocationHandler { + + Map containers; + + ModuleLocationHandler() { + this.containers = new HashMap<>(); + } + + public void newSystemLocation(Location loc, ClasspathJrt cp) throws IOException { + SystemLocationContainer systemLocationWrapper = new SystemLocationContainer(StandardLocation.SYSTEM_MODULES, cp); + this.containers.put(loc, systemLocationWrapper); + } + public void newSystemLocation(Location loc, JrtFileSystem jrt) throws IOException { + SystemLocationContainer systemLocationWrapper = new SystemLocationContainer(StandardLocation.SYSTEM_MODULES, jrt); + this.containers.put(loc, systemLocationWrapper); + } + + public LocationWrapper getLocation(Location loc, String moduleName) { + if (loc instanceof LocationWrapper) { + loc = ((LocationWrapper) loc).loc; + } + LocationContainer forwarder = this.containers.get(loc); + if (forwarder != null) { + return forwarder.get(moduleName); + } + return null; + } + + public Location getLocation(Location loc, Path path) { + LocationContainer forwarder = this.containers.get(loc); + if (forwarder != null) { + return forwarder.get(path); + } + return null; + } + public LocationContainer getLocation(Location location) { + return this.containers.get(location); + } + public void setLocation(Location location, Iterable paths) { + LocationContainer container = this.containers.get(location); + if (container == null) { + container = new LocationContainer(location); + this.containers.put(location, container); + } + container.setPaths(paths); + } + public void setLocation(Location location, String moduleName, Iterable paths) { + LocationWrapper wrapper = null; + LocationContainer container = this.containers.get(location); + if (container != null) { + wrapper = container.get(moduleName); + } else { + container = new LocationContainer(location); + this.containers.put(location, container); + } + if (wrapper == null) { + // module name can't be null + // TODO: Check unnamed modules can have their own module specific path - probably not + if (moduleName.equals("")) { //$NON-NLS-1$ + wrapper = new LocationWrapper(location, location.isOutputLocation(), paths); + } else { + wrapper = new ModuleLocationWrapper(location, moduleName, location.isOutputLocation(), paths); + for (Path path : paths) { + container.put(path, wrapper); + } + } + } else { + wrapper.setPaths(paths); + } + container.put(moduleName, wrapper); + } + public Iterable> listLocationsForModules(Location location) { + LocationContainer locationContainer = this.containers.get(location); + if (locationContainer == null) { + return Collections.emptyList(); + } + Set set = new HashSet<>(locationContainer.locationNames.values()); + List> singletonList = Collections.singletonList(set); + return singletonList; + } + + class LocationContainer extends LocationWrapper { + + Map locationNames; + Map locationPaths; + LocationContainer(Location loc) { + super(); + this.loc = loc; + this.locationNames = new HashMap<>(); + this.locationPaths = new HashMap<>(); + } + + LocationWrapper get(String moduleName) { + return this.locationNames.get(moduleName); + } + + void put(String moduleName, LocationWrapper impl) { + this.locationNames.put(moduleName, impl); + this.paths = null; + } + + void put(Path path, LocationWrapper impl) { + this.locationPaths.put(path, impl); + this.paths = null; + } + + Location get(Path path) { + return this.locationPaths.get(path); + } + + @Override + void setPaths(Iterable paths) { + super.setPaths(paths); + this.clear(); + } + @Override + Iterable getPaths() { + if (this.paths != null) + return this.paths; + return this.locationPaths.keySet(); + } + + public void clear() { + this.locationNames.clear(); + this.locationPaths.clear(); + } + } + + class SystemLocationContainer extends LocationContainer { + + public SystemLocationContainer(Location loc, JrtFileSystem jrt) throws IOException { + super(loc); + jrt.initialize(); + HashMap modulePathMap = jrt.modulePathMap; + Set keySet = modulePathMap.keySet(); + for (String mod : keySet) { + Path path = jrt.file.toPath(); + ModuleLocationWrapper wrapper = new ModuleLocationWrapper(loc, mod, false, + Collections.singletonList(path)); + this.locationNames.put(mod, wrapper); + this.locationPaths.put(path, wrapper); + } + } + public SystemLocationContainer(Location loc, ClasspathJrt cp) throws IOException { + this(loc, new JrtFileSystem(cp.file)); + } + } + + class LocationWrapper implements Location { + + Location loc; + boolean output; + List paths; + LocationWrapper() { + } + public LocationWrapper(Location loc, boolean output, Iterable paths) { + this.loc = loc; + this.output = output; + setPaths(paths); + } + + @Override + public String getName() { + return this.loc.getName(); + } + + @Override + public boolean isOutputLocation() { + return this.output; + } + + Iterable getPaths() { + return this.paths; + } + + void setPaths(Iterable paths) { + if (paths == null) { + this.paths = null; + } else { + List newPaths = new ArrayList<>(); + for (Path file : paths) { + newPaths.add(file); + } + this.paths = Collections.unmodifiableList(newPaths); + } + } + + @Override + public String toString() { + return this.loc.toString() + "[]"; //$NON-NLS-1$ + } + } + + class ModuleLocationWrapper extends LocationWrapper { + String modName; + + public ModuleLocationWrapper(Location loc, String mod, boolean output, Iterable paths) { + super(loc, output, paths); + this.modName = mod; + } + + @Override + public String getName() { + return this.loc.getName() + "[" + this.modName + "]"; //$NON-NLS-1$//$NON-NLS-2$ + } + + @Override + public boolean isOutputLocation() { + return this.output; + } + + @Override + Iterable getPaths() { + return this.paths; + } + + @Override + public String toString() { + return this.loc.toString() + "[" + this.modName + "]"; //$NON-NLS-1$//$NON-NLS-2$ + } + } + public void close() { + Collection values = this.containers.values(); + for (LocationContainer locationContainer : values) { + locationContainer.clear(); + } + } +} diff --git a/org.eclipse.jdt.compiler.tool.tests/.classpath b/org.eclipse.jdt.compiler.tool.tests/.classpath index 01836c4842..2ae2e50653 100644 --- a/org.eclipse.jdt.compiler.tool.tests/.classpath +++ b/org.eclipse.jdt.compiler.tool.tests/.classpath @@ -2,6 +2,7 @@ + diff --git a/org.eclipse.jdt.compiler.tool.tests/.gitignore b/org.eclipse.jdt.compiler.tool.tests/.gitignore new file mode 100644 index 0000000000..eb8e3c750d --- /dev/null +++ b/org.eclipse.jdt.compiler.tool.tests/.gitignore @@ -0,0 +1 @@ +/Y.class diff --git a/org.eclipse.jdt.compiler.tool.tests/META-INF/MANIFEST.MF b/org.eclipse.jdt.compiler.tool.tests/META-INF/MANIFEST.MF index 5a9ed3fa41..19864cdec4 100644 --- a/org.eclipse.jdt.compiler.tool.tests/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.compiler.tool.tests/META-INF/MANIFEST.MF @@ -8,6 +8,8 @@ Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Require-Bundle: org.eclipse.jdt.core;bundle-version="3.2.2", org.junit, + org.eclipse.core.resources, + org.eclipse.core.runtime, org.eclipse.test.performance, org.eclipse.jdt.core.tests.compiler Export-Package: org.eclipse.jdt.compiler.tool.tests diff --git a/org.eclipse.jdt.compiler.tool.tests/build.properties b/org.eclipse.jdt.compiler.tool.tests/build.properties index 9fc5c55fd2..2de2e64f6c 100644 --- a/org.eclipse.jdt.compiler.tool.tests/build.properties +++ b/org.eclipse.jdt.compiler.tool.tests/build.properties @@ -13,7 +13,9 @@ bin.includes = META-INF/,\ about.html,\ plugin.properties,\ test.xml,\ + lib/java9api.jar . src.includes = about.html source.. = src/ output.. = bin/ +jars.extra.classpath = lib/java9api.jar diff --git a/org.eclipse.jdt.compiler.tool.tests/lib/java9api.jar b/org.eclipse.jdt.compiler.tool.tests/lib/java9api.jar new file mode 100644 index 0000000000..fd56ad100e Binary files /dev/null and b/org.eclipse.jdt.compiler.tool.tests/lib/java9api.jar differ diff --git a/org.eclipse.jdt.compiler.tool.tests/pom.xml b/org.eclipse.jdt.compiler.tool.tests/pom.xml index 693f0ad650..f00ca99ac3 100644 --- a/org.eclipse.jdt.compiler.tool.tests/pom.xml +++ b/org.eclipse.jdt.compiler.tool.tests/pom.xml @@ -26,4 +26,27 @@ ${project.artifactId} org.eclipse.jdt.compiler.tool.tests.AllTests + + + + org.eclipse.tycho + tycho-compiler-plugin + 1.1.0-SNAPSHOT + + + -endorseddirs + ${basedir}/lib + + + xml + ${project.build.directory}/compilelogs + true + + **/package.html + + false + + + + diff --git a/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/CompilerInvocationTests.java b/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/CompilerInvocationTests.java index a2f7590a53..bdf11f7c1b 100644 --- a/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/CompilerInvocationTests.java +++ b/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/CompilerInvocationTests.java @@ -32,21 +32,22 @@ import java.util.Properties; import java.util.Set; import java.util.logging.LogRecord; +import javax.lang.model.SourceVersion; import javax.tools.FileObject; import javax.tools.ForwardingJavaFileObject; +import javax.tools.JavaCompiler.CompilationTask; import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; import javax.tools.StandardJavaFileManager; import javax.tools.StandardLocation; -import javax.tools.JavaCompiler.CompilationTask; -import javax.tools.JavaFileObject.Kind; - -import junit.framework.Test; import org.eclipse.jdt.internal.compiler.batch.Main; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; +import junit.framework.Test; + public class CompilerInvocationTests extends AbstractCompilerToolTest { static { // TESTS_NAMES = new String[] { "test019_sourcepath_without_destination" }; @@ -62,7 +63,14 @@ public static Test suite() { public static Class testClass() { return CompilerInvocationTests.class; } - +private boolean isOnJRE9() { + try { + SourceVersion.valueOf("RELEASE_9"); + } catch(IllegalArgumentException iae) { + return false; + } + return true; +} protected void checkClassFiles(String[] fileNames) { for (int i = 0, l = fileNames.length; i < l; i++) { ClassFileReader reader = null; @@ -204,6 +212,7 @@ class GetJavaFileForInputDetector extends GetJavaFileDetector { return super.openReader(ignoreEncodingErrors); } } + @Override JavaFileObject detector(JavaFileObject original) { if (original != null && original.getKind() == this.discriminatingKind && (this.discriminatingSuffix == null || original.getName().endsWith(this.discriminatingSuffix))) { @@ -250,6 +259,7 @@ class GetJavaFileForOutputDetector extends GetJavaFileDetector { return super.openWriter(); } } + @Override JavaFileObject detector(JavaFileObject original) { if (original != null && original.getKind() == Kind.CLASS && (this.discriminatingSuffix == null || original.getName().endsWith(this.discriminatingSuffix))) { @@ -553,6 +563,8 @@ public void test009_options_consumption() throws IOException { StandardJavaFileManager ecjStandardJavaFileManager = COMPILER.getStandardFileManager(null /* diagnosticListener */, null /* locale */, null /* charset */); for (String option: CompilerToolTests.ONE_ARG_OPTIONS) { + if (isOnJRE9() && (option.equals("-extdirs") || option.equals("-endorseddirs"))) + continue; if (ecjStandardJavaFileManager.isSupportedOption(option) != -1) { // some options that the compiler support could well not be supported by the file manager Iterator remaining = remainingAsList.iterator(); assertTrue("does not support " + option + " option", ecjStandardJavaFileManager.handleOption(option, remaining)); diff --git a/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/CompilerToolJava9Tests.java b/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/CompilerToolJava9Tests.java new file mode 100644 index 0000000000..64ca57c69e --- /dev/null +++ b/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/CompilerToolJava9Tests.java @@ -0,0 +1,374 @@ +/******************************************************************************* + * Copyright (c) 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 + * 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.compiler.tool.tests; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.nio.charset.Charset; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Locale; +import java.util.ServiceLoader; + +import javax.lang.model.SourceVersion; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileManager.Location; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jdt.internal.compiler.tool.EclipseCompiler; + +import junit.framework.TestCase; + +public class CompilerToolJava9Tests extends TestCase { + private static final String RESOURCES_DIR = "resources"; + private JavaCompiler[] compilers; + private String[] compilerNames; + private boolean isJREBelow9; + private static String _tmpFolder; + private static String _tmpSrcFolderName; + private static File _tmpSrcDir; + private static String _tmpBinFolderName; + private static File _tmpBinDir; + public static String _tmpGenFolderName; + private static File _tmpGenDir; + + private static String modules_directory; + public CompilerToolJava9Tests(String name) { + super(name); + } + @Override + protected void setUp() throws Exception { + this.isJREBelow9 = SourceVersion.latest().compareTo(SourceVersion.RELEASE_8) <= 0; + this.compilers = new JavaCompiler[2]; + this.compilerNames = new String[2]; + ServiceLoader javaCompilerLoader = ServiceLoader.load(JavaCompiler.class); + int compilerCounter = 0; + for (JavaCompiler compiler : javaCompilerLoader) { + compilerCounter++; + if (compiler instanceof EclipseCompiler) { + this.compilers[1] = compiler; + this.compilerNames[1] = "Eclipse Compiler"; + } + } + this.compilerNames[0] = "System compiler"; + this.compilers[0] = ToolProvider.getSystemJavaCompiler(); + assertEquals("Only one compiler available", 2, compilerCounter); + assertNotNull("System compiler unavailable", this.compilers[0]); + assertNotNull("Eclipse compiler unavailable", this.compilers[1]); + initializeLocations(); + } + protected void initializeLocations() { + _tmpFolder = System.getProperty("java.io.tmpdir"); + if (_tmpFolder.endsWith(File.separator)) { + _tmpFolder += "eclipse-temp"; + } else { + _tmpFolder += (File.separator + "eclipse-temp"); + } + _tmpBinFolderName = _tmpFolder + File.separator + "bin"; + _tmpBinDir = new File(_tmpBinFolderName); + deleteTree(_tmpBinDir); // remove existing contents + _tmpBinDir.mkdirs(); + assert _tmpBinDir.exists() : "couldn't mkdirs " + _tmpBinFolderName; + + _tmpGenFolderName = _tmpFolder + File.separator + "gen-src"; + _tmpGenDir = new File(_tmpGenFolderName); + deleteTree(_tmpGenDir); // remove existing contents + _tmpGenDir.mkdirs(); + assert _tmpGenDir.exists() : "couldn't mkdirs " + _tmpGenFolderName; + + _tmpSrcFolderName = _tmpFolder + File.separator + "src"; + _tmpSrcDir = new File(_tmpSrcFolderName); + deleteTree(_tmpSrcDir); // remove existing contents + _tmpSrcDir.mkdirs(); + assert _tmpSrcDir.exists() : "couldn't mkdirs " + _tmpSrcFolderName; + + modules_directory = getPluginDirectoryPath() + File.separator + "resources" + File.separator + "module_locations"; + } + public void testGetLocationForModule1() { + if (this.isJREBelow9) return; + for(int i = 0; i < 2; i++) { + String cName = this.compilerNames[i]; + JavaCompiler compiler = this.compilers[i]; + StandardJavaFileManager manager = compiler.getStandardFileManager(null, Locale.getDefault(), Charset.defaultCharset()); + try { + Location location = manager.getLocationForModule(StandardLocation.SYSTEM_MODULES, "java.base"); + assertNotNull(cName + ": Location should not be null", location); + } catch (UnsupportedOperationException ex) { + fail(cName + ": Should support getLocationForModule()"); + } + catch (IOException e) { + fail(cName + ": Should support getLocationForModule()"); + } + } + + } + + public void testGetLocationForModule2() throws IOException { + if (this.isJREBelow9) return; + for(int i = 0; i < 2; i++) { + String cName = this.compilerNames[i]; + JavaCompiler compiler = this.compilers[i]; + StandardJavaFileManager manager = compiler.getStandardFileManager(null, Locale.getDefault(), Charset.defaultCharset()); + Path path = Paths.get(modules_directory + File.separator + "SimpleModules"); + manager.setLocationFromPaths(StandardLocation.MODULE_PATH, Arrays.asList(path)); + try { + JavaFileManager.Location location = manager.getLocationForModule(StandardLocation.MODULE_PATH, "module.two"); + assertNotNull(cName + ":module path location should not be null", location); + } catch (UnsupportedOperationException ex) { + fail(cName + ":Should support getLocationForModule()"); + } + } + } + public void testGetLocationForModule3() throws IOException { + if (this.isJREBelow9) return; + for(int i = 0; i < 2; i++) { + String cName = this.compilerNames[i]; + JavaCompiler compiler = this.compilers[i]; + StandardJavaFileManager manager = compiler.getStandardFileManager(null, Locale.getDefault(), Charset.defaultCharset()); + Path path = Paths.get(modules_directory + File.separator + "SimpleModules" + File.separator + "module.one"); + manager.setLocationFromPaths(StandardLocation.MODULE_PATH, Arrays.asList(path)); + try { + JavaFileManager.Location location = manager.getLocationForModule(StandardLocation.MODULE_PATH, "module.one"); + assertNotNull(cName + ":module path location should not be null", location); + } catch (UnsupportedOperationException ex) { + fail(cName + ":Should support getLocationForModule()"); + } + } + } + public void testGetJavaFileObjects() { + if (this.isJREBelow9) return; + } + public void testGetJavaFileObjects2() { + if (this.isJREBelow9) return; + } + public void testSetLocationAsPaths() { + if (this.isJREBelow9) return; + } + public void testContains() { + if (this.isJREBelow9) return; + } + public void testGetServiceLoader() { + if (this.isJREBelow9) return; + } + public void testInferModuleName() { + if (this.isJREBelow9) return; + } + public void testListLocationsForModules() { + if (this.isJREBelow9) return; + } + public void testAsPath() { + if (this.isJREBelow9) return; + } + /** + * Recursively delete the contents of a directory, including any subdirectories. + * This is not optimized to handle very large or deep directory trees efficiently. + * @param f is either a normal file (which will be deleted) or a directory + * (which will be emptied and then deleted). + */ + public static void deleteTree(File f) + { + if (null == f) { + return; + } + File[] children = f.listFiles(); + if (null != children) { + // if f has any children, (recursively) delete them + for (File child : children) { + deleteTree(child); + } + } + // At this point f is either a normal file or an empty directory + f.delete(); + } + /** + * Copy a file from one location to another, unless the destination file already exists and has + * the same timestamp and file size. Create the destination location if necessary. Convert line + * delimiters according to {@link #shouldConvertToIndependentLineDelimiter(File)}. + * + * @param src + * the full path to the resource location. + * @param destFolder + * the full path to the destination location. + * @throws IOException + */ + public static void copyResource(File src, File dest) throws IOException { + if (dest.exists() && + src.lastModified() < dest.lastModified() && + src.length() == dest.length()) + { + return; + } + + // read source bytes + byte[] srcBytes = null; + srcBytes = read(src); + + if (shouldConvertToIndependentLineDelimiter(src)) { + String contents = new String(srcBytes); + contents = convertToIndependentLineDelimiter(contents); + srcBytes = contents.getBytes(); + } + writeFile(dest, srcBytes); + } + + public static void writeFile(File dest, byte[] srcBytes) throws IOException { + + File destFolder = dest.getParentFile(); + if (!destFolder.exists()) { + if (!destFolder.mkdirs()) { + throw new IOException("Unable to create directory " + destFolder); + } + } + // write bytes to dest + FileOutputStream out = null; + try { + out = new FileOutputStream(dest); + out.write(srcBytes); + out.flush(); + } finally { + if (out != null) { + out.close(); + } + } + } + + /** + * Copy a resource that is located under the resources folder of the plugin to a + * corresponding location under the specified target folder. Convert line delimiters according + * to {@link #shouldConvertToIndependentLineDelimiter(File)}. + * + * @param resourcePath + * the relative path under [plugin-root]/resources of the resource to + * be copied + * @param targetFolder + * the absolute path of the folder under which the resource will be copied. Folder + * and subfolders will be created if necessary. + * @return a file representing the copied resource + * @throws IOException + */ + public static File copyResource(String resourcePath, File targetFolder) throws IOException { + File resDir = new File(getPluginDirectoryPath(), RESOURCES_DIR); + File resourceFile = new File(resDir, resourcePath); + File targetFile = new File(targetFolder, resourcePath); + copyResource(resourceFile, targetFile); + return targetFile; + } + + /** + * Copy all the files under the directory specified by src to the directory + * specified by dest. The src and dest directories must exist; child directories + * under dest will be created as required. Existing files in dest will be + * overwritten. Newlines will be converted according to + * {@link #shouldConvertToIndependentLineDelimiter(File)}. Directories + * named "CVS" will be ignored. + * @param resourceFolderName the name of the source folder, relative to + * [plugin-root]/resources + * @param the absolute path of the destination folder + * @throws IOException + */ + public static void copyResources(String resourceFolderName, File destFolder) throws IOException { + File resDir = new File(getPluginDirectoryPath(), RESOURCES_DIR); + File resourceFolder = new File(resDir, resourceFolderName); + copyResources(resourceFolder, destFolder); + } + + private static void copyResources(File resourceFolder, File destFolder) throws IOException { + if (resourceFolder == null) { + return; + } + // Copy all resources in this folder + String[] children = resourceFolder.list(); + if (null == children) { + return; + } + // if there are any children, (recursively) copy them + for (String child : children) { + if ("CVS".equals(child)) { + continue; + } + File childRes = new File(resourceFolder, child); + File childDest = new File(destFolder, child); + if (childRes.isDirectory()) { + copyResources(childRes, childDest); + } + else { + copyResource(childRes, childDest); + } + } + } + protected static String getPluginDirectoryPath() { + try { + if (Platform.isRunning()) { + URL platformURL = Platform.getBundle("org.eclipse.jdt.compiler.tool.tests").getEntry("/"); + return new File(FileLocator.toFileURL(platformURL).getFile()).getAbsolutePath(); + } + return new File(System.getProperty("user.dir")).getAbsolutePath(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + /** + * @return true if this file's end-of-line delimiters should be replaced with + * a platform-independent value, e.g. for compilation. + */ + public static boolean shouldConvertToIndependentLineDelimiter(File file) { + return file.getName().endsWith(".java"); + } + public static byte[] read(java.io.File file) throws java.io.IOException { + int fileLength; + byte[] fileBytes = new byte[fileLength = (int) file.length()]; + java.io.FileInputStream stream = null; + try { + stream = new java.io.FileInputStream(file); + int bytesRead = 0; + int lastReadSize = 0; + while ((lastReadSize != -1) && (bytesRead != fileLength)) { + lastReadSize = stream.read(fileBytes, bytesRead, fileLength - bytesRead); + bytesRead += lastReadSize; + } + } finally { + if (stream != null) { + stream.close(); + } + } + return fileBytes; + } + + public static String convertToIndependentLineDelimiter(String source) { + if (source.indexOf('\n') == -1 && source.indexOf('\r') == -1) return source; + StringBuffer buffer = new StringBuffer(); + for (int i = 0, length = source.length(); i < length; i++) { + char car = source.charAt(i); + if (car == '\r') { + buffer.append('\n'); + if (i < length-1 && source.charAt(i+1) == '\n') { + i++; // skip \n after \r + } + } else { + buffer.append(car); + } + } + return buffer.toString(); + } +} diff --git a/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/ForwardingStandardJavaFileManager.java b/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/ForwardingStandardJavaFileManager.java index 7705be966b..cb5f676c7b 100644 --- a/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/ForwardingStandardJavaFileManager.java +++ b/org.eclipse.jdt.compiler.tool.tests/src/org/eclipse/jdt/compiler/tool/tests/ForwardingStandardJavaFileManager.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008 IBM Corporation and others. + * Copyright (c) 2008, 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 @@ -12,6 +12,10 @@ package org.eclipse.jdt.compiler.tool.tests; import java.io.File; import java.io.IOException; +import java.nio.file.Path; +import java.util.Collection; + +import javax.tools.FileObject; import javax.tools.ForwardingJavaFileManager; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; @@ -54,4 +58,34 @@ class ForwardingStandardJavaFileManager exten throws IOException { this.fileManager.setLocation(location, path); } + + @Override + public Path asPath(FileObject arg0) { + return this.fileManager.asPath(arg0); + } + + @Override + public Iterable getJavaFileObjects(Path... arg0) { + return this.fileManager.getJavaFileObjects(arg0); + } + + @Override + public Iterable getJavaFileObjectsFromPaths(Iterable arg0) { + return this.fileManager.getJavaFileObjectsFromPaths(arg0); + } + + @Override + public Iterable getLocationAsPaths(Location arg0) { + return this.fileManager.getLocationAsPaths(arg0); + } + + @Override + public void setLocationForModule(Location arg0, String arg1, Collection arg2) throws IOException { + this.fileManager.setLocationForModule(arg0, arg1, arg2); + } + + @Override + public void setLocationFromPaths(Location arg0, Collection arg1) throws IOException { + this.fileManager.setLocationFromPaths(arg0, arg1); + } } diff --git a/org.eclipse.jdt.compiler.tool/.classpath b/org.eclipse.jdt.compiler.tool/.classpath index 01836c4842..2ae2e50653 100644 --- a/org.eclipse.jdt.compiler.tool/.classpath +++ b/org.eclipse.jdt.compiler.tool/.classpath @@ -2,6 +2,7 @@ + diff --git a/org.eclipse.jdt.compiler.tool/META-INF/MANIFEST.MF b/org.eclipse.jdt.compiler.tool/META-INF/MANIFEST.MF index e689b6de91..d050921bb4 100644 --- a/org.eclipse.jdt.compiler.tool/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.compiler.tool/META-INF/MANIFEST.MF @@ -9,3 +9,5 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Export-Package: META-INF.services, org.eclipse.jdt.internal.compiler.tool;x-internal:=true Fragment-Host: org.eclipse.jdt.core;bundle-version="[3.3.0,4.0.0)" +Bundle-ClassPath: lib/java9api.jar, + . diff --git a/org.eclipse.jdt.compiler.tool/build.properties b/org.eclipse.jdt.compiler.tool/build.properties index 5d28d8152e..5158a97629 100644 --- a/org.eclipse.jdt.compiler.tool/build.properties +++ b/org.eclipse.jdt.compiler.tool/build.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2000, 2007 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 @@ -14,5 +14,7 @@ output.. = bin/ bin.includes = META-INF/,\ .,\ about.html,\ - compiler_tool_fragment.properties + compiler_tool_fragment.properties,\ + lib/java9api.jar src.includes = about.html +jars.extra.classpath = lib/java9api.jar \ No newline at end of file diff --git a/org.eclipse.jdt.compiler.tool/lib/java9api.jar b/org.eclipse.jdt.compiler.tool/lib/java9api.jar new file mode 100644 index 0000000000..fd56ad100e Binary files /dev/null and b/org.eclipse.jdt.compiler.tool/lib/java9api.jar differ diff --git a/org.eclipse.jdt.compiler.tool/pom.xml b/org.eclipse.jdt.compiler.tool/pom.xml index 5eb9c00781..b5e0f07ded 100644 --- a/org.eclipse.jdt.compiler.tool/pom.xml +++ b/org.eclipse.jdt.compiler.tool/pom.xml @@ -1,6 +1,6 @@ + xml + ${project.build.directory}/compilelogs + true + + **/package.html + + false + + maven-antrun-plugin diff --git a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompiler.java b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompiler.java index 65801d2276..0647554c72 100644 --- a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompiler.java +++ b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompiler.java @@ -209,6 +209,16 @@ public class EclipseCompiler implements JavaCompiler { temp.toArray(processors2); eclipseCompiler2.processors = processors2; } + @Override + public void addModules(Iterable mods) { + ArrayList temp = new ArrayList<>(); + for (String mod : mods) { + temp.add(mod); + } + String[] mods2 = new String[temp.size()]; + temp.toArray(mods2); + eclipseCompiler2.modules = mods2; + } }; } /* diff --git a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompilerImpl.java b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompilerImpl.java index dd203a1a8b..74d59e83f9 100644 --- a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompilerImpl.java +++ b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseCompilerImpl.java @@ -5,6 +5,10 @@ * 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: * IBM Corporation - initial API and implementation * IBM Corporation - fix for 342936 @@ -19,17 +23,24 @@ import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.nio.charset.Charset; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Map.Entry; import javax.annotation.processing.Processor; +import javax.lang.model.SourceVersion; import javax.tools.Diagnostic; import javax.tools.DiagnosticListener; import javax.tools.JavaFileManager; +import javax.tools.JavaFileManager.Location; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.StandardLocation; @@ -46,12 +57,14 @@ import org.eclipse.jdt.internal.compiler.batch.ClasspathJsr199; import org.eclipse.jdt.internal.compiler.batch.CompilationUnit; import org.eclipse.jdt.internal.compiler.batch.FileSystem; import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.batch.Main; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.problem.AbortCompilationUnit; import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; +import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; import org.eclipse.jdt.internal.compiler.util.Messages; import org.eclipse.jdt.internal.compiler.util.SuffixConstants; import org.eclipse.jdt.internal.compiler.util.Util; @@ -62,6 +75,8 @@ public class EclipseCompilerImpl extends Main { Iterable compilationUnits; public JavaFileManager fileManager; protected Processor[] processors; + // TODO: This is not yet used anywhere + protected String[] modules; public DiagnosticListener diagnosticListener; public EclipseCompilerImpl(PrintWriter out, PrintWriter err, boolean systemExitWhenFinished) { @@ -70,6 +85,7 @@ public class EclipseCompilerImpl extends Main { public boolean call() { try { + handleLocations(); if (this.proceed) { this.globalProblemsCount = 0; this.globalErrorsCount = 0; @@ -87,6 +103,7 @@ public class EclipseCompilerImpl extends Main { } return false; } catch (RuntimeException e) { // internal compiler failure + e.printStackTrace(); this.logger.logException(e); return false; } finally { @@ -112,31 +129,60 @@ public class EclipseCompilerImpl extends Main { @Override public CompilationUnit[] getCompilationUnits() { + // This method is largely a copy of Main#getCompilationUnits() if (this.compilationUnits == null) return EclipseCompilerImpl.NO_UNITS; + Map pathToModCU = new HashMap<>(); + HashtableOfObject knownFileNames = new HashtableOfObject(); ArrayList units = new ArrayList<>(); - for (final JavaFileObject javaFileObject : this.compilationUnits) { - if (javaFileObject.getKind() != JavaFileObject.Kind.SOURCE) { - throw new IllegalArgumentException(); - } - String name = javaFileObject.getName(); - CompilationUnit compilationUnit = new CompilationUnit(null, - name, - null, - null, - shouldIgnoreOptionalProblems(this.ignoreOptionalProblemsFromFolders, name.toCharArray()), null) { + for (int round = 0; round < 2; round++) { + int i = 0; + for (final JavaFileObject javaFileObject : this.compilationUnits) { + String name = javaFileObject.getName(); + char[] charName = name.toCharArray(); + boolean isModuleInfo = CharOperation.endsWith(charName, TypeConstants.MODULE_INFO_FILE_NAME); + if (isModuleInfo == (round==0)) { // 1st round: modules, 2nd round others (to ensure populating pathToModCU well in time) + if (knownFileNames.get(charName) != null) + throw new IllegalArgumentException(this.bind("unit.more", name)); //$NON-NLS-1$ + knownFileNames.put(charName, charName); + File file = new File(name); + if (!file.exists()) + throw new IllegalArgumentException(this.bind("unit.missing", name)); //$NON-NLS-1$ + CompilationUnit cu = new CompilationUnit(null, + name, + null, + this.destinationPaths[i], + shouldIgnoreOptionalProblems(this.ignoreOptionalProblemsFromFolders, name.toCharArray()), this.modNames[i]) { - @Override - public char[] getContents() { - try { - return javaFileObject.getCharContent(true).toString().toCharArray(); - } catch(IOException e) { - e.printStackTrace(); - throw new AbortCompilationUnit(null, e, null); - } + @Override + public char[] getContents() { + try { + return javaFileObject.getCharContent(true).toString().toCharArray(); + } catch(IOException e) { + e.printStackTrace(); + throw new AbortCompilationUnit(null, e, null); + } + } + }; + units.add(cu); + this.javaFileObjectMap.put(cu, javaFileObject); + if (isModuleInfo) { + int lastSlash = CharOperation.lastIndexOf(File.separatorChar, cu.fileName); + if (lastSlash != -1) { + pathToModCU.put(String.valueOf(CharOperation.subarray(cu.fileName, 0, lastSlash)), cu); + } + } else { + for (Entry entry : pathToModCU.entrySet()) { + Path modPath = Paths.get(entry.getKey()); + Path cuPath = Paths.get(name); + while (cuPath != null && cuPath.startsWith(modPath)) { + cu.setModule(entry.getValue()); + break; + } + } + } } - }; - units.add(compilationUnit); - this.javaFileObjectMap.put(compilationUnit, javaFileObject); + i++; + } } CompilationUnit[] result = new CompilationUnit[units.size()]; units.toArray(result); @@ -339,8 +385,10 @@ public class EclipseCompilerImpl extends Main { if (!((unitResult == null) || (unitResult.hasErrors() && !this.proceedOnError))) { ClassFile[] classFiles = unitResult.getClassFiles(); boolean generateClasspathStructure = this.fileManager.hasLocation(StandardLocation.CLASS_OUTPUT); - String currentDestinationPath = this.destinationPath; File outputLocation = null; + String currentDestinationPath = unitResult.getCompilationUnit().getDestinationPath(); + if (currentDestinationPath == null) + currentDestinationPath = this.destinationPath; if (currentDestinationPath != null) { outputLocation = new File(currentDestinationPath); outputLocation.mkdirs(); @@ -365,9 +413,20 @@ public class EclipseCompilerImpl extends Main { })); } try { + char[] modName = unitResult.compilationUnit.getModuleName(); + Location location = null; + if (modName == null) { + location = StandardLocation.CLASS_OUTPUT; + } else { + // TODO: Still possible to end up with a non-null module name without JDK 9 in build path + System.out.println("module name:" + new String(modName)); //$NON-NLS-1$ + System.out.println("CU:" + new String(unitResult.compilationUnit.getFileName())); //$NON-NLS-1$ + location = this.fileManager.getLocationForModule(StandardLocation.CLASS_OUTPUT, new String(modName)); + System.out.println("Location from getLocationForModule(): " + location); //$NON-NLS-1$ + } JavaFileObject javaFileForOutput = this.fileManager.getJavaFileForOutput( - StandardLocation.CLASS_OUTPUT, + location, new String(filename), JavaFileObject.Kind.CLASS, this.javaFileObjectMap.get(unitResult.compilationUnit)); @@ -419,7 +478,11 @@ public class EclipseCompilerImpl extends Main { ArrayList extdirsClasspaths, ArrayList endorsedDirClasspaths, String customEncoding) { + // Sometimes this gets called too early there by losing locations set after that point. + // The code is now moved to handleLocations() which is invoked just before compilation + } + protected void handleLocations() { ArrayList fileSystemClasspaths = new ArrayList<>(); EclipseFileManager eclipseJavaFileManager = null; StandardJavaFileManager standardJavaFileManager = null; @@ -440,13 +503,27 @@ public class EclipseCompilerImpl extends Main { fileSystemClasspaths.addAll(this.handleEndorseddirs(null)); } } - Iterable location = null; + Iterable locationFiles = null; if (standardJavaFileManager != null) { - location = standardJavaFileManager.getLocation(StandardLocation.PLATFORM_CLASS_PATH); - if (location != null) { - for (File file : location) { + locationFiles = standardJavaFileManager.getLocation(StandardLocation.PLATFORM_CLASS_PATH); + if (locationFiles != null) { + for (File file : locationFiles) { if (file.isDirectory()) { - setPlatformLocations(fileSystemClasspaths, file); + List platformLocations = getPlatformLocations(fileSystemClasspaths, file); + if (standardJavaFileManager instanceof EclipseFileManager) { + if (platformLocations.size() == 1) { + Classpath jrt = platformLocations.get(0); + if (jrt instanceof ClasspathJrt) { + // TODO: double check, should it be platform or system module? + try { + ((EclipseFileManager) standardJavaFileManager).locationHandler.newSystemLocation(StandardLocation.SYSTEM_MODULES, (ClasspathJrt) jrt); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + fileSystemClasspaths.addAll(platformLocations); break; // Only possible scenario is, we have one and only entry representing the Java home. } else { Classpath classpath = FileSystem.getClasspath( @@ -479,9 +556,9 @@ public class EclipseCompilerImpl extends Main { } } if (standardJavaFileManager != null) { - location = standardJavaFileManager.getLocation(StandardLocation.SOURCE_PATH); - if (location != null) { - for (File file : location) { + locationFiles = standardJavaFileManager.getLocation(StandardLocation.SOURCE_PATH); + if (locationFiles != null) { + for (File file : locationFiles) { Classpath classpath = FileSystem.getClasspath( file.getAbsolutePath(), null, @@ -491,9 +568,9 @@ public class EclipseCompilerImpl extends Main { } } } - location = standardJavaFileManager.getLocation(StandardLocation.CLASS_PATH); - if (location != null) { - for (File file : location) { + locationFiles = standardJavaFileManager.getLocation(StandardLocation.CLASS_PATH); + if (locationFiles != null) { + for (File file : locationFiles) { Classpath classpath = FileSystem.getClasspath( file.getAbsolutePath(), null, @@ -504,12 +581,81 @@ public class EclipseCompilerImpl extends Main { } } } + if (SourceVersion.latest().compareTo(SourceVersion.RELEASE_8) > 0) { + try { + Iterable locationAsPaths = standardJavaFileManager.getLocationAsPaths(StandardLocation.MODULE_SOURCE_PATH); + if (locationAsPaths != null) { + for (Path path : locationAsPaths) { + ArrayList modulepaths = handleModuleSourcepath(path.toFile().getCanonicalPath()); + for (Classpath classpath : modulepaths) { + Collection moduleNames = classpath.getModuleNames(null); + for (String modName : moduleNames) { + Path p = Paths.get(classpath.getPath()); + standardJavaFileManager.setLocationForModule(StandardLocation.MODULE_SOURCE_PATH, modName, + Collections.singletonList(p)); + p = Paths.get(classpath.getDestinationPath()); + standardJavaFileManager.setLocationForModule(StandardLocation.CLASS_OUTPUT, modName, + Collections.singletonList(p)); + } + } + fileSystemClasspaths.addAll(modulepaths); + } + } + } catch (Exception e) { + // TODO: Revisit when JRE 9 no longer throws IllegalStateException for getLocation. + } + try { + locationFiles = standardJavaFileManager.getLocation(StandardLocation.MODULE_PATH); + if (locationFiles != null) { + for (File file : locationFiles) { + try { + ArrayList modulepaths = handleModulepath(file.getCanonicalPath()); + for (Classpath classpath : modulepaths) { + Collection moduleNames = classpath.getModuleNames(null); + for (String string : moduleNames) { + Path path = Paths.get(classpath.getPath()); + standardJavaFileManager.setLocationForModule(StandardLocation.MODULE_PATH, string, + Collections.singletonList(path)); + } + } + fileSystemClasspaths.addAll(modulepaths); + } catch (IOException e) { + throw new AbortCompilationUnit(null, e, null); + } + } + } + } catch (Exception e) { + // TODO: Revisit when JRE 9 no longer throws IllegalStateException for getLocation. + } + } } else if (javaFileManager != null) { Classpath classpath = null; if (this.fileManager.hasLocation(StandardLocation.SOURCE_PATH)) { classpath = new ClasspathJsr199(this.fileManager, StandardLocation.SOURCE_PATH); fileSystemClasspaths.add(classpath); } + if (SourceVersion.latest().compareTo(SourceVersion.RELEASE_8) > 0) { + // Add the locations to search for in specific order + if (this.fileManager.hasLocation(StandardLocation.UPGRADE_MODULE_PATH)) { + classpath = new ClasspathJsr199(this.fileManager, StandardLocation.UPGRADE_MODULE_PATH); + } + if (this.fileManager.hasLocation(StandardLocation.SYSTEM_MODULES)) { + classpath = new ClasspathJsr199(this.fileManager, StandardLocation.SYSTEM_MODULES); + fileSystemClasspaths.add(classpath); + } + if (this.fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH)) { + classpath = new ClasspathJsr199(this.fileManager, StandardLocation.PATCH_MODULE_PATH); + fileSystemClasspaths.add(classpath); + } + if (this.fileManager.hasLocation(StandardLocation.MODULE_SOURCE_PATH)) { + classpath = new ClasspathJsr199(this.fileManager, StandardLocation.MODULE_SOURCE_PATH); + fileSystemClasspaths.add(classpath); + } + if (this.fileManager.hasLocation(StandardLocation.MODULE_PATH)) { + classpath = new ClasspathJsr199(this.fileManager, StandardLocation.MODULE_PATH); + fileSystemClasspaths.add(classpath); + } + } classpath = new ClasspathJsr199(this.fileManager, StandardLocation.CLASS_PATH); fileSystemClasspaths.add(classpath); haveClassPaths = true; @@ -533,9 +679,9 @@ public class EclipseCompilerImpl extends Main { } } - protected void setPlatformLocations(ArrayList fileSystemClasspaths, File file) { + protected List getPlatformLocations(ArrayList fileSystemClasspaths, File file) { List platformLibraries = Util.collectPlatformLibraries(file); - fileSystemClasspaths.addAll(platformLibraries); + return platformLibraries; } @Override protected void loggingExtraProblems() { diff --git a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java index eca44dd094..89fe7c8b59 100644 --- a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java +++ b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileManager.java @@ -22,20 +22,27 @@ import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.nio.charset.Charset; +import java.nio.file.Path; +import java.nio.file.Paths; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.MissingResourceException; +import java.util.Objects; import java.util.ResourceBundle; +import java.util.ServiceLoader; import java.util.Set; import java.util.StringTokenizer; import java.util.zip.ZipException; +import javax.lang.model.SourceVersion; import javax.tools.FileObject; import javax.tools.JavaFileObject; import javax.tools.JavaFileObject.Kind; @@ -43,14 +50,25 @@ import javax.tools.StandardJavaFileManager; import javax.tools.StandardLocation; import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; import org.eclipse.jdt.internal.compiler.batch.FileSystem; +import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; import org.eclipse.jdt.internal.compiler.batch.Main; import org.eclipse.jdt.internal.compiler.batch.Main.ResourceBundleFactory; +import org.eclipse.jdt.internal.compiler.batch.ModuleFinder; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.env.AccessRestriction; import org.eclipse.jdt.internal.compiler.env.AccessRule; import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.parser.Parser; +import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; +import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; +import org.eclipse.jdt.internal.compiler.tool.JrtFileSystem.JrtFileObject; +import org.eclipse.jdt.internal.compiler.tool.ModuleLocationHandler.LocationContainer; +import org.eclipse.jdt.internal.compiler.tool.ModuleLocationHandler.LocationWrapper; +import org.eclipse.jdt.internal.compiler.tool.ModuleLocationHandler.ModuleLocationWrapper; +import org.eclipse.jdt.internal.compiler.util.Util; /** * Implementation of the Standard Java File Manager @@ -61,27 +79,30 @@ public class EclipseFileManager implements StandardJavaFileManager { static final int HAS_BOOTCLASSPATH = 2; static final int HAS_ENDORSED_DIRS = 4; static final int HAS_PROCESSORPATH = 8; + static final int HAS_PROC_MODULEPATH = 16; Map archivesCache; Charset charset; Locale locale; - Map> locations; + ModuleLocationHandler locationHandler; final Map classloaders; int flags; + boolean isOnJvm9; + File jrtHome; + JrtFileSystem jrtSystem; public ResourceBundle bundle; public EclipseFileManager(Locale locale, Charset charset) { this.locale = locale == null ? Locale.getDefault() : locale; this.charset = charset == null ? Charset.defaultCharset() : charset; - this.locations = new HashMap<>(); + this.locationHandler = new ModuleLocationHandler(); this.classloaders = new HashMap<>(); this.archivesCache = new HashMap<>(); + this.isOnJvm9 = isRunningJvm9(); try { - this.setLocation(StandardLocation.PLATFORM_CLASS_PATH, getDefaultBootclasspath()); - Iterable defaultClasspath = getDefaultClasspath(); - this.setLocation(StandardLocation.CLASS_PATH, defaultClasspath); - this.setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, defaultClasspath); + initialize(Util.getJavaHome()); } catch (IOException e) { + e.printStackTrace(); // ignore } try { @@ -90,13 +111,26 @@ public class EclipseFileManager implements StandardJavaFileManager { System.out.println("Missing resource : " + Main.bundleName.replace('.', '/') + ".properties for locale " + locale); //$NON-NLS-1$//$NON-NLS-2$ } } - + protected void initialize(File javahome) throws IOException { + if (this.isOnJvm9) { + this.jrtSystem = new JrtFileSystem(javahome); + this.archivesCache.put(javahome, this.jrtSystem); + this.jrtHome = javahome; + this.locationHandler.newSystemLocation(StandardLocation.SYSTEM_MODULES, this.jrtSystem); + } else { + this.setLocation(StandardLocation.PLATFORM_CLASS_PATH, getDefaultBootclasspath()); + } + Iterable defaultClasspath = getDefaultClasspath(); + this.setLocation(StandardLocation.CLASS_PATH, defaultClasspath); + // No annotation module path by default + this.setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, defaultClasspath); + } /* (non-Javadoc) * @see javax.tools.JavaFileManager#close() */ @Override public void close() throws IOException { - if (this.locations != null) this.locations.clear(); + this.locationHandler.close(); for (Archive archive : this.archivesCache.values()) { archive.close(); } @@ -107,35 +141,18 @@ public class EclipseFileManager implements StandardJavaFileManager { this.classloaders.clear(); } - private void collectAllMatchingFiles(File file, String normalizedPackageName, Set kinds, boolean recurse, ArrayList collector) { - if (!isArchive(file)) { - // we must have a directory - File currentFile = new File(file, normalizedPackageName); - if (!currentFile.exists()) return; - String path; - try { - path = currentFile.getCanonicalPath(); - } catch (IOException e) { - return; - } - if (File.separatorChar == '/') { - if (!path.endsWith(normalizedPackageName)) return; - } else if (!path.endsWith(normalizedPackageName.replace('/', File.separatorChar))) return; - File[] files = currentFile.listFiles(); - if (files != null) { - // this was a directory - for (File f : files) { - if (f.isDirectory() && recurse) { - collectAllMatchingFiles(file, normalizedPackageName + '/' + f.getName(), kinds, recurse, collector); - } else { - final Kind kind = getKind(f); - if (kinds.contains(kind)) { - collector.add(new EclipseFileObject(normalizedPackageName + f.getName(), f.toURI(), kind, this.charset)); - } + private void collectAllMatchingFiles(Location location, File file, String normalizedPackageName, Set kinds, boolean recurse, ArrayList collector) { + if (file.equals(this.jrtHome)) { + if (location instanceof ModuleLocationWrapper) { + List list = this.jrtSystem.list((ModuleLocationWrapper) location, normalizedPackageName, kinds, recurse, this.charset); + for (JrtFileObject fo : list) { + Kind kind = getKind(getExtension(fo.entryName)); + if (kinds.contains(kind)) { + collector.add(fo); } } } - } else { + } else if (isArchive(file)) { Archive archive = this.getArchive(file); if (archive == Archive.UNKNOWN_ARCHIVE) return; String key = normalizedPackageName; @@ -168,6 +185,33 @@ public class EclipseFileManager implements StandardJavaFileManager { } } } + } else { + // we must have a directory + File currentFile = new File(file, normalizedPackageName); + if (!currentFile.exists()) return; + String path; + try { + path = currentFile.getCanonicalPath(); + } catch (IOException e) { + return; + } + if (File.separatorChar == '/') { + if (!path.endsWith(normalizedPackageName)) return; + } else if (!path.endsWith(normalizedPackageName.replace('/', File.separatorChar))) return; + File[] files = currentFile.listFiles(); + if (files != null) { + // this was a directory + for (File f : files) { + if (f.isDirectory() && recurse) { + collectAllMatchingFiles(location, file, normalizedPackageName + '/' + f.getName(), kinds, recurse, collector); + } else { + final Kind kind = getKind(f); + if (kinds.contains(kind)) { + collector.add(new EclipseFileObject(normalizedPackageName + f.getName(), f.toURI(), kind, this.charset)); + } + } + } + } } } @@ -225,6 +269,7 @@ public class EclipseFileManager implements StandardJavaFileManager { */ @Override public ClassLoader getClassLoader(Location location) { + validateNonModuleLocation(location); Iterable files = getLocation(location); if (files == null) { // location is unknown @@ -344,6 +389,7 @@ public class EclipseFileManager implements StandardJavaFileManager { */ @Override public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException { + validateNonModuleLocation(location); Iterable files = getLocation(location); if (files == null) { throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$ @@ -377,6 +423,7 @@ public class EclipseFileManager implements StandardJavaFileManager { @Override public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException { + validateOutputLocation(location); Iterable files = getLocation(location); if (files == null) { throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$ @@ -397,6 +444,7 @@ public class EclipseFileManager implements StandardJavaFileManager { */ @Override public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) throws IOException { + validateNonModuleLocation(location); if (kind != Kind.CLASS && kind != Kind.SOURCE) { throw new IllegalArgumentException("Invalid kind : " + kind);//$NON-NLS-1$ } @@ -407,7 +455,15 @@ public class EclipseFileManager implements StandardJavaFileManager { String normalizedFileName = normalized(className); normalizedFileName += kind.extension; for (File file : files) { - if (file.isDirectory()) { + if (file.equals(this.jrtHome)) { + String modName; + if (location instanceof ModuleLocationWrapper) { + modName = ((ModuleLocationWrapper) location).modName; + } else { + modName = ""; //$NON-NLS-1$ + } + return this.jrtSystem.getArchiveFileObject(normalizedFileName, modName, this.charset); + } else if (file.isDirectory()) { // handle directory File f = new File(file, normalizedFileName); if (f.exists()) { @@ -434,6 +490,7 @@ public class EclipseFileManager implements StandardJavaFileManager { @Override public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException { + validateOutputLocation(location); if (kind != Kind.CLASS && kind != Kind.SOURCE) { throw new IllegalArgumentException("Invalid kind : " + kind);//$NON-NLS-1$ } @@ -546,8 +603,14 @@ public class EclipseFileManager implements StandardJavaFileManager { */ @Override public Iterable getLocation(Location location) { - if (this.locations == null) return null; - return this.locations.get(location.getName()); + if (location instanceof LocationWrapper) { + return getFiles(((LocationWrapper) location).paths); + } + LocationWrapper loc = this.locationHandler.getLocation(location); + if (loc == null) { + return null; + } + return getFiles(loc.getPaths()); } private Iterable getOutputDir(String string) { @@ -569,123 +632,192 @@ public class EclipseFileManager implements StandardJavaFileManager { @Override public boolean handleOption(String current, Iterator remaining) { try { - if ("-bootclasspath".equals(current)) {//$NON-NLS-1$ - if (remaining.hasNext()) { - final Iterable bootclasspaths = getPathsFrom(remaining.next()); - if (bootclasspaths != null) { - Iterable iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH); - if ((this.flags & EclipseFileManager.HAS_ENDORSED_DIRS) == 0 - && (this.flags & EclipseFileManager.HAS_EXT_DIRS) == 0) { - // override default bootclasspath - setLocation(StandardLocation.PLATFORM_CLASS_PATH, bootclasspaths); - } else if ((this.flags & EclipseFileManager.HAS_ENDORSED_DIRS) != 0) { - // endorseddirs have been processed first - setLocation(StandardLocation.PLATFORM_CLASS_PATH, - concatFiles(iterable, bootclasspaths)); - } else { - // extdirs have been processed first - setLocation(StandardLocation.PLATFORM_CLASS_PATH, - prependFiles(iterable, bootclasspaths)); + switch(current) { + case "-bootclasspath": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable bootclasspaths = getPathsFrom(remaining.next()); + if (bootclasspaths != null) { + Iterable iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH); + if ((this.flags & EclipseFileManager.HAS_ENDORSED_DIRS) == 0 + && (this.flags & EclipseFileManager.HAS_EXT_DIRS) == 0) { + // override default bootclasspath + setLocation(StandardLocation.PLATFORM_CLASS_PATH, bootclasspaths); + } else if ((this.flags & EclipseFileManager.HAS_ENDORSED_DIRS) != 0) { + // endorseddirs have been processed first + setLocation(StandardLocation.PLATFORM_CLASS_PATH, + concatFiles(iterable, bootclasspaths)); + } else { + // extdirs have been processed first + setLocation(StandardLocation.PLATFORM_CLASS_PATH, + prependFiles(iterable, bootclasspaths)); + } } + this.flags |= EclipseFileManager.HAS_BOOTCLASSPATH; + return true; + } else { + throw new IllegalArgumentException(); } - this.flags |= EclipseFileManager.HAS_BOOTCLASSPATH; - return true; - } else { - throw new IllegalArgumentException(); - } - } - if ("-classpath".equals(current) || "-cp".equals(current)) {//$NON-NLS-1$//$NON-NLS-2$ - if (remaining.hasNext()) { + case "--system": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable classpaths = getPathsFrom(remaining.next()); + if (classpaths != null) { + Iterable iterable = getLocation(StandardLocation.SYSTEM_MODULES); + if (iterable != null) { + setLocation(StandardLocation.SYSTEM_MODULES, concatFiles(iterable, classpaths)); + } else { + setLocation(StandardLocation.SYSTEM_MODULES, classpaths); + } + } + return true; + } else { + throw new IllegalArgumentException(); + } + case "--upgrade-module-path": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable classpaths = getPathsFrom(remaining.next()); + if (classpaths != null) { + Iterable iterable = getLocation(StandardLocation.UPGRADE_MODULE_PATH); + if (iterable != null) { + setLocation(StandardLocation.UPGRADE_MODULE_PATH, + concatFiles(iterable, classpaths)); + } else { + setLocation(StandardLocation.UPGRADE_MODULE_PATH, classpaths); + } + } + return true; + } else { + throw new IllegalArgumentException(); + } + case "-classpath": //$NON-NLS-1$ + case "-cp": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable classpaths = getPathsFrom(remaining.next()); + if (classpaths != null) { + Iterable iterable = getLocation(StandardLocation.CLASS_PATH); + if (iterable != null) { + setLocation(StandardLocation.CLASS_PATH, + concatFiles(iterable, classpaths)); + } else { + setLocation(StandardLocation.CLASS_PATH, classpaths); + } + if ((this.flags & EclipseFileManager.HAS_PROCESSORPATH) == 0) { + setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, classpaths); + } else if ((this.flags & EclipseFileManager.HAS_PROC_MODULEPATH) == 0) { + if (this.isOnJvm9) + setLocation(StandardLocation.ANNOTATION_PROCESSOR_MODULE_PATH, classpaths); + } + } + return true; + } else { + throw new IllegalArgumentException(); + } + case "--module-path": //$NON-NLS-1$ + case "-p": //$NON-NLS-1$ final Iterable classpaths = getPathsFrom(remaining.next()); if (classpaths != null) { - Iterable iterable = getLocation(StandardLocation.CLASS_PATH); + Iterable iterable = getLocation(StandardLocation.MODULE_PATH); if (iterable != null) { - setLocation(StandardLocation.CLASS_PATH, - concatFiles(iterable, classpaths)); + setLocation(StandardLocation.MODULE_PATH, concatFiles(iterable, classpaths)); } else { - setLocation(StandardLocation.CLASS_PATH, classpaths); + setLocation(StandardLocation.MODULE_PATH, classpaths); } if ((this.flags & EclipseFileManager.HAS_PROCESSORPATH) == 0) { setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, classpaths); + } else if ((this.flags & EclipseFileManager.HAS_PROC_MODULEPATH) == 0) { + if (this.isOnJvm9) + setLocation(StandardLocation.ANNOTATION_PROCESSOR_MODULE_PATH, classpaths); } } return true; - } else { - throw new IllegalArgumentException(); - } - } - if ("-encoding".equals(current)) {//$NON-NLS-1$ - if (remaining.hasNext()) { - this.charset = Charset.forName(remaining.next()); - return true; - } else { - throw new IllegalArgumentException(); - } - } - if ("-sourcepath".equals(current)) {//$NON-NLS-1$ - if (remaining.hasNext()) { - final Iterable sourcepaths = getPathsFrom(remaining.next()); - if (sourcepaths != null) setLocation(StandardLocation.SOURCE_PATH, sourcepaths); - return true; - } else { - throw new IllegalArgumentException(); - } - } - if ("-extdirs".equals(current)) {//$NON-NLS-1$ - if (remaining.hasNext()) { - Iterable iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH); - setLocation(StandardLocation.PLATFORM_CLASS_PATH, - concatFiles(iterable, getExtdirsFrom(remaining.next()))); - this.flags |= EclipseFileManager.HAS_EXT_DIRS; - return true; - } else { - throw new IllegalArgumentException(); - } - } - if ("-endorseddirs".equals(current)) {//$NON-NLS-1$ - if (remaining.hasNext()) { - Iterable iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH); - setLocation(StandardLocation.PLATFORM_CLASS_PATH, - prependFiles(iterable, getEndorsedDirsFrom(remaining.next()))); - this.flags |= EclipseFileManager.HAS_ENDORSED_DIRS; - return true; - } else { - throw new IllegalArgumentException(); - } - } - if ("-d".equals(current)) { //$NON-NLS-1$ - if (remaining.hasNext()) { - final Iterable outputDir = getOutputDir(remaining.next()); - if (outputDir != null) { - setLocation(StandardLocation.CLASS_OUTPUT, outputDir); + case "-encoding": //$NON-NLS-1$ + if (remaining.hasNext()) { + this.charset = Charset.forName(remaining.next()); + return true; + } else { + throw new IllegalArgumentException(); } - return true; - } else { - throw new IllegalArgumentException(); - } - } - if ("-s".equals(current)) { //$NON-NLS-1$ - if (remaining.hasNext()) { - final Iterable outputDir = getOutputDir(remaining.next()); - if (outputDir != null) { - setLocation(StandardLocation.SOURCE_OUTPUT, outputDir); + case "-sourcepath": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable sourcepaths = getPathsFrom(remaining.next()); + if (sourcepaths != null) setLocation(StandardLocation.SOURCE_PATH, sourcepaths); + return true; + } else { + throw new IllegalArgumentException(); } - return true; - } else { - throw new IllegalArgumentException(); - } - } - if ("-processorpath".equals(current)) {//$NON-NLS-1$ - if (remaining.hasNext()) { - final Iterable processorpaths = getPathsFrom(remaining.next()); - if (processorpaths != null) { - setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, processorpaths); + case "--module-source-path": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable sourcepaths = getPathsFrom(remaining.next()); + if (sourcepaths != null && this.isOnJvm9) + setLocation(StandardLocation.MODULE_SOURCE_PATH, sourcepaths); + return true; + } else { + throw new IllegalArgumentException(); + } + case "-extdirs": //$NON-NLS-1$ + if (this.isOnJvm9) { + throw new IllegalArgumentException(); + } + if (remaining.hasNext()) { + Iterable iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH); + setLocation(StandardLocation.PLATFORM_CLASS_PATH, + concatFiles(iterable, getExtdirsFrom(remaining.next()))); + this.flags |= EclipseFileManager.HAS_EXT_DIRS; + return true; + } else { + throw new IllegalArgumentException(); + } + case "-endorseddirs": //$NON-NLS-1$ + if (remaining.hasNext()) { + Iterable iterable = getLocation(StandardLocation.PLATFORM_CLASS_PATH); + setLocation(StandardLocation.PLATFORM_CLASS_PATH, + prependFiles(iterable, getEndorsedDirsFrom(remaining.next()))); + this.flags |= EclipseFileManager.HAS_ENDORSED_DIRS; + return true; + } else { + throw new IllegalArgumentException(); + } + case "-d": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable outputDir = getOutputDir(remaining.next()); + if (outputDir != null) { + setLocation(StandardLocation.CLASS_OUTPUT, outputDir); + } + return true; + } else { + throw new IllegalArgumentException(); + } + case "-s": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable outputDir = getOutputDir(remaining.next()); + if (outputDir != null) { + setLocation(StandardLocation.SOURCE_OUTPUT, outputDir); + } + return true; + } else { + throw new IllegalArgumentException(); + } + case "-processorpath": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable processorpaths = getPathsFrom(remaining.next()); + if (processorpaths != null) { + setLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH, processorpaths); + } + this.flags |= EclipseFileManager.HAS_PROCESSORPATH; + return true; + } else { + throw new IllegalArgumentException(); + } + case "--processor-module-path": //$NON-NLS-1$ + if (remaining.hasNext()) { + final Iterable processorpaths = getPathsFrom(remaining.next()); + if (processorpaths != null && this.isOnJvm9) { + setLocation(StandardLocation.ANNOTATION_PROCESSOR_MODULE_PATH, processorpaths); + this.flags |= EclipseFileManager.HAS_PROC_MODULEPATH; + } + return true; + } else { + throw new IllegalArgumentException(); } - this.flags |= EclipseFileManager.HAS_PROCESSORPATH; - return true; - } else { - throw new IllegalArgumentException(); - } } } catch (IOException e) { // ignore @@ -698,7 +830,17 @@ public class EclipseFileManager implements StandardJavaFileManager { */ @Override public boolean hasLocation(Location location) { - return this.locations != null && this.locations.containsKey(location.getName()); + String mod = null; + if (location instanceof ModuleLocationWrapper) { + mod = ((ModuleLocationWrapper) location).modName; + } + LocationWrapper impl = null; + if (mod == null) { + impl = this.locationHandler.getLocation(location); + } else { + impl = this.locationHandler.getLocation(location, mod); + } + return (impl != null); } /* (non-Javadoc) @@ -706,6 +848,21 @@ public class EclipseFileManager implements StandardJavaFileManager { */ @Override public String inferBinaryName(Location location, JavaFileObject file) { + validateNonModuleLocation(location); + Iterable paths = getLocationAsPaths(location); + if (paths == null) { + return null; + } + if (file instanceof JrtFileObject) { + Path filePath = ((JrtFileObject) file).path; + filePath = filePath.subpath(2, filePath.getNameCount()); + String name = filePath.toString(); + int index = name.lastIndexOf('.'); + if (index != -1) { + name = name.substring(0, index); + } + return name.replace('/', '.'); + } String name = file.getName(); JavaFileObject javaFileObject = null; int index = name.lastIndexOf('.'); @@ -760,16 +917,16 @@ public class EclipseFileManager implements StandardJavaFileManager { @Override public Iterable list(Location location, String packageName, Set kinds, boolean recurse) throws IOException { - - Iterable allFilesInLocations = getLocation(location); - if (allFilesInLocations == null) { + validateNonModuleLocation(location); + Iterable allPaths = getLocationAsPaths(location); + if (allPaths == null) { throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$ } ArrayList collector = new ArrayList<>(); String normalizedPackageName = normalized(packageName); - for (File file : allFilesInLocations) { - collectAllMatchingFiles(file, normalizedPackageName, kinds, recurse, collector); + for (Path file : allPaths) { + collectAllMatchingFiles(location, file.toFile(), normalizedPackageName, kinds, recurse, collector); } return collector; } @@ -800,28 +957,28 @@ public class EclipseFileManager implements StandardJavaFileManager { } return list; } - + private boolean isRunningJvm9() { + return (SourceVersion.latest().compareTo(SourceVersion.RELEASE_8) > 0); + } /* (non-Javadoc) * @see javax.tools.StandardJavaFileManager#setLocation(javax.tools.JavaFileManager.Location, java.lang.Iterable) */ @Override - public void setLocation(Location location, Iterable path) throws IOException { - if (path != null) { - if (location.isOutputLocation()) { - // output location - int count = 0; - for (Iterator iterator = path.iterator(); iterator.hasNext(); ) { - iterator.next(); - count++; - } - if (count != 1) { - throw new IllegalArgumentException("output location can only have one path");//$NON-NLS-1$ - } + public void setLocation(Location location, Iterable files) throws IOException { + if (location.isOutputLocation() && files != null) { + // output location + int count = 0; + for (Iterator iterator = files.iterator(); iterator.hasNext(); ) { + iterator.next(); + count++; + } + if (count != 1) { + throw new IllegalArgumentException("output location can only have one path");//$NON-NLS-1$ } - this.locations.put(location.getName(), path); } + this.locationHandler.setLocation(location, getPaths(files)); } - + public void setLocale(Locale locale) { this.locale = locale == null ? Locale.getDefault() : locale; try { @@ -1108,4 +1265,227 @@ public class EclipseFileManager implements StandardJavaFileManager { } return MessageFormat.format(message, (Object[]) arguments); } + + private Iterable getFiles(final Iterable paths) { + if (paths == null) + return null; + return () -> new Iterator() { + Iterator original = paths.iterator(); + @Override + public boolean hasNext() { + return this.original.hasNext(); + } + @Override + public File next() { + return this.original.next().toFile(); + } + }; + } + private Iterable getPaths(final Iterable files) { + if (files == null) + return null; + return () -> new Iterator() { + Iterator original = files.iterator(); + @Override + public boolean hasNext() { + return this.original.hasNext(); + } + @Override + public Path next() { + return this.original.next().toPath(); + } + }; + } + + private void validateFileObject(FileObject file) { + // FIXME: fill-up + } + private void validateModuleLocation(Location location, String modName) { + Objects.requireNonNull(location); + if (modName == null) { + throw new IllegalArgumentException("module must not be null"); //$NON-NLS-1$ + } + if (this.isOnJvm9) { + if (!location.isModuleOrientedLocation() && !location.isOutputLocation()) { + throw new IllegalArgumentException("location is module related :" + location.getName()); //$NON-NLS-1$ + } + } + } + private void validateNonModuleLocation(Location location) { + Objects.requireNonNull(location); + if (this.isOnJvm9) { + if (location.isModuleOrientedLocation() && location.isOutputLocation()) { + throw new IllegalArgumentException("location is module related :" + location.getName()); //$NON-NLS-1$ + } + } + } + private void validateOutputLocation(Location location) { + Objects.requireNonNull(location); + if (!location.isOutputLocation()) { + throw new IllegalArgumentException("location is not output location :" + location.getName()); //$NON-NLS-1$ + } + } + @Override + public Iterable getJavaFileObjects(Path... paths) { + return getJavaFileObjectsFromPaths(Arrays.asList(paths)); + } + + @Override + public Iterable getJavaFileObjectsFromPaths(Iterable paths) { + return getJavaFileObjectsFromFiles(getFiles(paths)); + } + + @Override + public Iterable getLocationAsPaths(Location location) { + if (location instanceof LocationWrapper) { + return ((LocationWrapper) location).paths; + } + LocationWrapper loc = this.locationHandler.getLocation(location); + if (loc == null) { + return null; + } + return loc.getPaths(); + } + + @Override + public void setLocationFromPaths(Location location, Collection paths) throws IOException { + setLocation(location, getFiles(paths)); + if (location == StandardLocation.MODULE_PATH) { + // FIXME: same for module source path? + Map options = new HashMap<>(); + // FIXME: Find a way to get the options from the EclipseCompiler and pass it to the parser. + // FIXME: need to be the latest and not hardcoded value + options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_9); + options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_9); + options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_9); + CompilerOptions compilerOptions = new CompilerOptions(options); + ProblemReporter problemReporter = + new ProblemReporter( + DefaultErrorHandlingPolicies.proceedWithAllProblems(), + compilerOptions, + new DefaultProblemFactory()); + for (Path path : paths) { + List mp = ModuleFinder.findModules(path.toFile(), null, + new Parser(problemReporter, true), null, true); + for (Classpath cp : mp) { + Collection moduleNames = cp.getModuleNames(null); + for (String string : moduleNames) { + Path p = Paths.get(cp.getPath()); + setLocationForModule(StandardLocation.MODULE_PATH, string, Collections.singletonList(p)); + } + } + } + } + } + + @Override + public boolean contains(Location location, FileObject fo) throws IOException { + validateFileObject(fo); + Iterable files = getLocation(location); + if (files == null) { + throw new IllegalArgumentException("Unknown location : " + location);//$NON-NLS-1$ + } + for (File file : files) { + if (file.isDirectory()) { + if (fo instanceof EclipseFileObject) { + Path filepath = ((EclipseFileObject) fo).f.toPath(); + if (filepath.startsWith(Paths.get(file.toURI()).toAbsolutePath())) { + return true; + } + } + } else if (isArchive(file)) { + if (fo instanceof ArchiveFileObject) { + Archive archive = getArchive(file); + if (archive != Archive.UNKNOWN_ARCHIVE) { + if (archive.contains(((ArchiveFileObject) fo ).entryName)) { + return true; + } + } + } + } + } + return false; + } + + @Override + public Location getLocationForModule(Location location, String moduleName) throws IOException { + validateModuleLocation(location, moduleName); + return this.locationHandler.getLocation(location, moduleName); + } + + @Override + public Location getLocationForModule(Location location, JavaFileObject fo) { + validateModuleLocation(location, ""); //$NON-NLS-1$ + Path path = null; + if (fo instanceof ArchiveFileObject) { + path = ((ArchiveFileObject) fo).file.toPath(); + return this.locationHandler.getLocation(location, path); + } else if (fo instanceof EclipseFileObject) { + path = ((EclipseFileObject) fo).f.toPath(); + try { + path = path.toRealPath(); + } catch (IOException e) { + e.printStackTrace(); + } + LocationContainer container = this.locationHandler.getLocation(location); + while (path != null) { + Location loc = container.get(path); + if (loc != null) + return loc; + path = path.getParent(); + } + } + return null; + } + + @Override + public ServiceLoader getServiceLoader(Location location, Class service) throws IOException { + // FIXME: Need special handling in case of module class loaders. + return ServiceLoader.load(service, getClassLoader(location)); + } + + @Override + public String inferModuleName(Location location) throws IOException { + if (location instanceof ModuleLocationWrapper) { + ModuleLocationWrapper wrapper = (ModuleLocationWrapper) location; + return wrapper.modName; + } + return null; + } + + @Override + public Iterable> listLocationsForModules(Location location) { + validateModuleLocation(location, ""); //$NON-NLS-1$ + return this.locationHandler.listLocationsForModules(location); + } + + @Override + public Path asPath(FileObject file) { + validateFileObject(file); + EclipseFileObject eclFile = (EclipseFileObject) file; + if (eclFile.f != null) { + return eclFile.f.toPath(); + } + return null; + } + + @Override + public void setLocationForModule(Location location, String moduleName, Collection paths) throws IOException { + validateModuleLocation(location, moduleName); + this.locationHandler.setLocation(location, moduleName, paths); + if (location == StandardLocation.MODULE_SOURCE_PATH) { + LocationWrapper wrapper = this.locationHandler.getLocation(StandardLocation.CLASS_OUTPUT, moduleName); + if (wrapper == null) { + wrapper = this.locationHandler.getLocation(StandardLocation.CLASS_OUTPUT, ""); //$NON-NLS-1$ + if (wrapper != null) { + Iterator iterator = wrapper.paths.iterator(); + if (iterator.hasNext()) { + // Per module output location is always a singleton list + Path path = iterator.next().resolve(moduleName); + this.locationHandler.setLocation(StandardLocation.CLASS_OUTPUT, moduleName, Collections.singletonList(path)); + } + } + } + } + } } diff --git a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileObject.java b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileObject.java index 615268e6ed..c00f341725 100644 --- a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileObject.java +++ b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/EclipseFileObject.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2015 IBM Corporation and others. + * Copyright (c) 2006, 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 @@ -41,7 +41,7 @@ import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; * Implementation of a Java file object that corresponds to a file on the file system */ public class EclipseFileObject extends SimpleJavaFileObject { - private File f; + File f; private Charset charset; private boolean parentsExist; // parent directories exist diff --git a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/JrtFileSystem.java b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/JrtFileSystem.java index 36ffc04150..e47d64fe34 100644 --- a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/JrtFileSystem.java +++ b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/JrtFileSystem.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2015, 2016 IBM Corporation. + * Copyright (c) 2015, 2017 IBM Corporation. * 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,23 +22,28 @@ import java.io.Reader; import java.io.Writer; import java.net.URI; import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; import java.nio.charset.Charset; -import java.nio.file.DirectoryStream; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.Hashtable; +import java.util.HashMap; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import java.util.zip.ZipException; +import javax.tools.JavaFileObject; + import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; +import org.eclipse.jdt.internal.compiler.tool.ModuleLocationHandler.ModuleLocationWrapper; import org.eclipse.jdt.internal.compiler.util.JRTUtil; public class JrtFileSystem extends Archive { @@ -47,122 +52,98 @@ public class JrtFileSystem extends Archive { static final String BOOT_MODULE = "jrt-fs.jar"; //$NON-NLS-1$ - private static final String MODULES_SUBDIR = "/modules"; //$NON-NLS-1$ - - private static final String DEFAULT_PACKAGE = ""; //$NON-NLS-1$ - - private Set typesCache = null; + public HashMap modulePathMap; + Path modules; + private java.nio.file.FileSystem jrtfs; public JrtFileSystem(File file) throws ZipException, IOException { this.file = file; initialize(); } - @SuppressWarnings("resource") - private void initialize() throws IOException { + public void initialize() throws IOException { // initialize packages - this.packagesCache = new Hashtable<>(); - this.typesCache = new HashSet<>(); - if (!this.file.getName().equals(BOOT_MODULE)) return; - java.nio.file.FileSystem fs = FileSystems.getFileSystem(JRT_URI); - Iterable roots = fs.getRootDirectories(); - for (java.nio.file.Path path : roots) { - try (DirectoryStream stream = Files.newDirectoryStream(path)) { - for (final java.nio.file.Path subdir: stream) { - if (subdir.toString().equals(MODULES_SUBDIR)) { - Files.walkFileTree(subdir, new FileVisitor() { + this.modulePathMap = new HashMap<>(); + URL jrtPath = null; + + if (this.file.exists()) { + jrtPath = Paths.get(this.file.toPath().toString(), "lib", JRTUtil.JRT_FS_JAR).toUri().toURL(); //$NON-NLS-1$ + try (URLClassLoader loader = new URLClassLoader(new URL[] { jrtPath })) { + HashMap env = new HashMap<>(); + this.jrtfs = FileSystems.newFileSystem(JRT_URI, env, loader); + this.modules = this.jrtfs.getPath("/modules"); //$NON-NLS-1$ + } + } else { + return; + } - @Override - public FileVisitResult preVisitDirectory(java.nio.file.Path entry, BasicFileAttributes attrs) - throws IOException { - int count = entry.getNameCount(); - if (count < 2) return FileVisitResult.CONTINUE; - return FileVisitResult.CONTINUE; - } + org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(this.file, + new org.eclipse.jdt.internal.compiler.util.JRTUtil.JrtFileVisitor() { - @Override - public FileVisitResult visitFile(java.nio.file.Path entry, BasicFileAttributes attrs) throws IOException { - int count = entry.getNameCount(); - if (entry == subdir || count < 3) return FileVisitResult.CONTINUE; - if (count == 3) { - cacheTypes(DEFAULT_PACKAGE, entry.getName(2).toString(), entry.getName(1).toString()); - } else { - cacheTypes(entry.subpath(2, count - 1).toString(), - entry.getName(count - 1).toString(), entry.getName(1).toString()); - } - return FileVisitResult.CONTINUE; - } + @Override + public FileVisitResult visitPackage(Path dir, Path mod, BasicFileAttributes attrs) + throws IOException { + return FileVisitResult.CONTINUE; + } - @Override - public FileVisitResult visitFileFailed(java.nio.file.Path entry, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } + @Override + public FileVisitResult visitFile(Path f, Path mod, BasicFileAttributes attrs) + throws IOException { + return FileVisitResult.CONTINUE; + } - @Override - public FileVisitResult postVisitDirectory(java.nio.file.Path entry, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - }); - } - } - } catch (Exception e) { - throw new IOException(e.getMessage()); + @Override + public FileVisitResult visitModule(Path mod) throws IOException { + JrtFileSystem.this.modulePathMap.put(mod.getFileName().toString(), mod); + return FileVisitResult.CONTINUE; } - } + }, JRTUtil.NOTIFY_MODULES); } - + + public List list(ModuleLocationWrapper location, String packageName, + Set kinds, boolean recurse, Charset charset) { + String module = location.modName; + Path mPath = this.modules.resolve(module); + Path resolve = mPath.resolve(packageName); + java.util.List files = null; + try (Stream p = Files.list(resolve)) { + files = p.filter((path) -> { + if (Files.isDirectory(path)) + return false; + else + return true; + }).collect(Collectors.toList()); + } catch (IOException e) { + // ignore + } + List result = new ArrayList<>(); + for (Path p: files) { + result.add(new JrtFileObject(this.file, p, module, charset)); + } + return result; + } @Override public ArchiveFileObject getArchiveFileObject(String fileName, String module, Charset charset) { - return new JrtFileObject(this.file, fileName, module, charset); - } - public ArchiveFileObject getArchiveFileObject(String fileName, Charset charset) { - return new JrtFileObject(this.file, fileName, null, charset); + return new JrtFileObject(this.file, this.modules.resolve(module).resolve(fileName), module, charset); } - + @Override public boolean contains(String entryName) { - return this.typesCache.contains(entryName); + // FIXME + return false; } - protected void cacheTypes(String packageName, String typeName, String module) { - int length = packageName.length(); - if (length > 0 && packageName.charAt(packageName.length() - 1) != '/') { - packageName = packageName + '/'; - } - ArrayList types = this.packagesCache.get(packageName); - if (typeName == null) return; - if (types == null) { - types = new ArrayList<>(); - types.add(new String[]{typeName, module}); - this.packagesCache.put(packageName, types); - } else { - types.add(new String[]{typeName, module}); - } - this.typesCache.add(packageName + typeName); - } - @Override - public List getTypes(String packageName) { - // package name is expected to ends with '/' - if (this.packagesCache == null) { - try { - this.initialize(); - } catch(IOException e) { - return Collections.emptyList(); - } - } - return this.packagesCache.get(packageName); - } - @Override public String toString() { return "JRT: " + (this.file == null ? "UNKNOWN_ARCHIVE" : this.file.getAbsolutePath()); //$NON-NLS-1$ //$NON-NLS-2$ } class JrtFileObject extends ArchiveFileObject { - String module = null; - private JrtFileObject(File file, String fileName, String module, Charset charset) { - super(file, fileName, charset); - this.module = module; + String module; + Path path; + private JrtFileObject(File file, Path path, String module, Charset charset) { + super(file, path.toString(), charset); + this.path = path; } @Override @@ -214,7 +195,7 @@ public class JrtFileSystem extends Archive { */ @Override public String getName() { - return this.entryName; + return this.path.toString(); } /* (non-Javadoc) @@ -222,7 +203,7 @@ public class JrtFileSystem extends Archive { */ @Override public InputStream openInputStream() throws IOException { - return org.eclipse.jdt.internal.compiler.util.JRTUtil.getContentFromJrt(this.file, this.entryName, null); + return Files.newInputStream(this.path); } /* (non-Javadoc) diff --git a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/ModuleLocationHandler.java b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/ModuleLocationHandler.java new file mode 100644 index 0000000000..bcbbb9b023 --- /dev/null +++ b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/ModuleLocationHandler.java @@ -0,0 +1,260 @@ +/******************************************************************************* + * Copyright (c) 2017 IBM Corporation. + * 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.tool; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.tools.JavaFileManager.Location; +import javax.tools.StandardLocation; + +import org.eclipse.jdt.internal.compiler.batch.ClasspathJrt; + +public class ModuleLocationHandler { + + Map containers; + + ModuleLocationHandler() { + this.containers = new HashMap<>(); + } + + public void newSystemLocation(Location loc, ClasspathJrt cp) throws IOException { + SystemLocationContainer systemLocationWrapper = new SystemLocationContainer(StandardLocation.SYSTEM_MODULES, cp); + this.containers.put(loc, systemLocationWrapper); + } + public void newSystemLocation(Location loc, JrtFileSystem jrt) throws IOException { + SystemLocationContainer systemLocationWrapper = new SystemLocationContainer(StandardLocation.SYSTEM_MODULES, jrt); + this.containers.put(loc, systemLocationWrapper); + } + + public LocationWrapper getLocation(Location loc, String moduleName) { + if (loc instanceof LocationWrapper) { + loc = ((LocationWrapper) loc).loc; + } + LocationContainer forwarder = this.containers.get(loc); + if (forwarder != null) { + return forwarder.get(moduleName); + } + return null; + } + + public Location getLocation(Location loc, Path path) { + LocationContainer forwarder = this.containers.get(loc); + if (forwarder != null) { + return forwarder.get(path); + } + return null; + } + public LocationContainer getLocation(Location location) { + return this.containers.get(location); + } + public void setLocation(Location location, Iterable paths) { + LocationContainer container = this.containers.get(location); + if (container == null) { + container = new LocationContainer(location); + this.containers.put(location, container); + } + container.setPaths(paths); + } + public void setLocation(Location location, String moduleName, Iterable paths) { + LocationWrapper wrapper = null; + LocationContainer container = this.containers.get(location); + if (container != null) { + wrapper = container.get(moduleName); + } else { + container = new LocationContainer(location); + this.containers.put(location, container); + } + if (wrapper == null) { + // module name can't be null + // TODO: Check unnamed modules can have their own module specific path - probably not + if (moduleName.equals("")) { //$NON-NLS-1$ + wrapper = new LocationWrapper(location, location.isOutputLocation(), paths); + } else { + wrapper = new ModuleLocationWrapper(location, moduleName, location.isOutputLocation(), paths); + for (Path path : paths) { + container.put(path, wrapper); + } + } + } else { + wrapper.setPaths(paths); + } + container.put(moduleName, wrapper); + } + public Iterable> listLocationsForModules(Location location) { + LocationContainer locationContainer = this.containers.get(location); + if (locationContainer == null) { + return Collections.emptyList(); + } + Set set = new HashSet<>(locationContainer.locationNames.values()); + List> singletonList = Collections.singletonList(set); + return singletonList; + } + + class LocationContainer extends LocationWrapper { + + Map locationNames; + Map locationPaths; + LocationContainer(Location loc) { + super(); + this.loc = loc; + this.locationNames = new HashMap<>(); + this.locationPaths = new HashMap<>(); + } + + LocationWrapper get(String moduleName) { + return this.locationNames.get(moduleName); + } + + void put(String moduleName, LocationWrapper impl) { + this.locationNames.put(moduleName, impl); + this.paths = null; + } + + void put(Path path, LocationWrapper impl) { + this.locationPaths.put(path, impl); + this.paths = null; + } + + Location get(Path path) { + return this.locationPaths.get(path); + } + + @Override + void setPaths(Iterable paths) { + super.setPaths(paths); + this.clear(); + } + @Override + Iterable getPaths() { + if (this.paths != null) + return this.paths; + return this.locationPaths.keySet(); + } + + public void clear() { + this.locationNames.clear(); + this.locationPaths.clear(); + } + } + + class SystemLocationContainer extends LocationContainer { + + public SystemLocationContainer(Location loc, JrtFileSystem jrt) throws IOException { + super(loc); + jrt.initialize(); + HashMap modulePathMap = jrt.modulePathMap; + Set keySet = modulePathMap.keySet(); + for (String mod : keySet) { + Path path = jrt.file.toPath(); + ModuleLocationWrapper wrapper = new ModuleLocationWrapper(loc, mod, false, + Collections.singletonList(path)); + this.locationNames.put(mod, wrapper); + this.locationPaths.put(path, wrapper); + } + } + public SystemLocationContainer(Location loc, ClasspathJrt cp) throws IOException { + this(loc, new JrtFileSystem(cp.file)); + } + } + + class LocationWrapper implements Location { + + Location loc; + boolean output; + List paths; + LocationWrapper() { + } + public LocationWrapper(Location loc, boolean output, Iterable paths) { + this.loc = loc; + this.output = output; + setPaths(paths); + } + + @Override + public String getName() { + return this.loc.getName(); + } + + @Override + public boolean isOutputLocation() { + return this.output; + } + + Iterable getPaths() { + return this.paths; + } + + void setPaths(Iterable paths) { + if (paths == null) { + this.paths = null; + } else { + List newPaths = new ArrayList<>(); + for (Path file : paths) { + newPaths.add(file); + } + this.paths = Collections.unmodifiableList(newPaths); + } + } + + @Override + public String toString() { + return this.loc.toString() + "[]"; //$NON-NLS-1$ + } + } + + class ModuleLocationWrapper extends LocationWrapper { + String modName; + + public ModuleLocationWrapper(Location loc, String mod, boolean output, Iterable paths) { + super(loc, output, paths); + this.modName = mod; + } + + @Override + public String getName() { + return this.loc.getName() + "[" + this.modName + "]"; //$NON-NLS-1$//$NON-NLS-2$ + } + + @Override + public boolean isOutputLocation() { + return this.output; + } + + @Override + Iterable getPaths() { + return this.paths; + } + + @Override + public String toString() { + return this.loc.toString() + "[" + this.modName + "]"; //$NON-NLS-1$//$NON-NLS-2$ + } + } + public void close() { + Collection values = this.containers.values(); + for (LocationContainer locationContainer : values) { + locationContainer.clear(); + } + } +} diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java index 48e18155a5..ecedb323e1 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java @@ -52,6 +52,7 @@ import junit.framework.Test; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.core.tests.util.AbstractCompilerTest; import org.eclipse.jdt.core.tests.util.Util; import org.eclipse.jdt.internal.compiler.batch.ClasspathDirectory; import org.eclipse.jdt.internal.compiler.batch.ClasspathJar; @@ -12561,7 +12562,8 @@ public void test385780_warn_option() { } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=405225 public void test405225_extdirs() { - // check the option introduced in bug 359721 + if (AbstractCompilerTest.isJRE9) + return; this.runConformTest( new String[] { "X.java", diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java index c6a543a4da..3a0f7371ae 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java @@ -242,10 +242,16 @@ public synchronized char[][] getModulesDeclaringPackage(String qualifiedPackageN } @Override public boolean hasCompilationUnit(String qualifiedPackageName, String moduleName) { + qualifiedPackageName += '/'; for (Enumeration e = this.zipFile.entries(); e.hasMoreElements(); ) { String fileName = e.nextElement().getName(); - if (fileName.startsWith(qualifiedPackageName) && fileName.toLowerCase().endsWith(SUFFIX_STRING_class)) - return true; + if (fileName.startsWith(qualifiedPackageName) && fileName.length() > qualifiedPackageName.length()) { + String tail = fileName.substring(qualifiedPackageName.length()); + if (tail.indexOf('/') != -1) + continue; + if (tail.toLowerCase().endsWith(SUFFIX_STRING_class)) + return true; + } } return false; } diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJrt.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJrt.java index 21a9af6093..aef02498bb 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJrt.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJrt.java @@ -43,10 +43,11 @@ import org.eclipse.jdt.internal.compiler.util.SuffixConstants; @SuppressWarnings({"rawtypes", "unchecked"}) public class ClasspathJrt extends ClasspathLocation implements IMultiModuleEntry { - protected File file; + public File file; protected ZipFile annotationZipFile; protected boolean closeZipFileAtEnd; private static HashMap> ModulesCache = new HashMap<>(); + public HashMap modulePathMap; //private Set packageCache; protected List annotationPaths; @@ -55,6 +56,7 @@ public class ClasspathJrt extends ClasspathLocation implements IMultiModuleEntry super(accessRuleSet, destinationPath); this.file = file; this.closeZipFileAtEnd = closeZipFileAtEnd; + this.modulePathMap = new HashMap<>(); } public List fetchLinkedJars(FileSystem.ClasspathSectionProblemReporter problemReporter) { @@ -134,7 +136,10 @@ public class ClasspathJrt extends ClasspathLocation implements IMultiModuleEntry @Override public FileVisitResult visitFile(java.nio.file.Path dir, java.nio.file.Path modPath, BasicFileAttributes attrs) throws IOException { - if (!dir.getParent().toString().equals(qualifiedPackageName)) { + Path parent = dir.getParent(); + if (parent == null) + return FileVisitResult.CONTINUE; + if (!parent.toString().equals(qualifiedPackageName)) { return FileVisitResult.CONTINUE; } String fileName = dir.getName(dir.getNameCount() - 1).toString(); @@ -209,6 +214,7 @@ public class ClasspathJrt extends ClasspathLocation implements IMultiModuleEntry public FileVisitResult visitModule(Path mod) throws IOException { try { ClasspathJrt.this.acceptModule(JRTUtil.getClassfileContent(ClasspathJrt.this.file, IModule.MODULE_INFO_CLASS, mod.toString())); + ClasspathJrt.this.modulePathMap.put(mod.getFileName().toString(), mod); } catch (ClassFormatException e) { e.printStackTrace(); } diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/CompilationUnit.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/CompilationUnit.java index 68d8cf5a50..f6a45bd0db 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/CompilationUnit.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/CompilationUnit.java @@ -131,4 +131,7 @@ public ModuleBinding module(LookupEnvironment rootEnvironment) { } return rootEnvironment.UnNamedModule; } +public String getDestinationPath() { + return this.destinationPath; +} } diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java index 97ab977294..85bd890253 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java @@ -1405,6 +1405,7 @@ public class Main implements ProblemSeverities, SuffixConstants { public Logger logger; public int maxProblems; public Map options; + long complianceLevel; public char[][] ignoreOptionalProblemsFromFolders; protected PrintWriter out; public boolean proceed = true; @@ -1841,6 +1842,7 @@ public void configure(String[] argv) { final int INSIDE_ADD_EXPORTS = 25; final int INSIDE_ADD_READS = 26; final int INSIDE_SYSTEM = 27; + final int INSIDE_PROCESSOR_MODULE_PATH_start = 28; final int DEFAULT = 0; ArrayList bootclasspaths = new ArrayList<>(DEFAULT_SIZE_CLASSPATH); @@ -2191,7 +2193,7 @@ public void configure(String[] argv) { mode = INSIDE_SYSTEM; continue; } - if (currentArg.equals("--module-path") || currentArg.equals("-p")) { //$NON-NLS-1$ //$NON-NLS-2$ + if (currentArg.equals("--module-path") || currentArg.equals("-p") || currentArg.equals("--processor-module-path")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ mode = INSIDE_MODULEPATH_start; continue; } @@ -2598,6 +2600,10 @@ public void configure(String[] argv) { mode = INSIDE_PROCESSOR_start; continue; } + if (currentArg.equals("--processor-module-path")) { //$NON-NLS-1$ + mode = INSIDE_PROCESSOR_MODULE_PATH_start; + continue; + } if (currentArg.equals("-proc:only")) { //$NON-NLS-1$ this.options.put( CompilerOptions.OPTION_GenerateClassFiles, @@ -2858,6 +2864,9 @@ public void configure(String[] argv) { // nothing to do here. This is consumed again by the AnnotationProcessorManager mode = DEFAULT; continue; + case INSIDE_PROCESSOR_MODULE_PATH_start : + mode = DEFAULT; + continue; case INSIDE_S_start : // nothing to do here. This is consumed again by the AnnotationProcessorManager mode = DEFAULT; @@ -4550,7 +4559,6 @@ public void outputClassFiles(CompilationResult unitResult) { * Low-level API performing the actual compilation */ public void performCompilation() { - this.startTime = System.currentTimeMillis(); FileSystem environment = getLibraryAccess(); @@ -4631,30 +4639,52 @@ private ReferenceBinding[] processClassNames(LookupEnvironment environment) { // check for .class file presence in case of apt processing int length = this.classNames.length; ReferenceBinding[] referenceBindings = new ReferenceBinding[length]; + ModuleBinding[] modules = new ModuleBinding[length]; + Set modSet = new HashSet<>(); + String[] typeNames = new String[length]; + if (this.complianceLevel <= ClassFileConstants.JDK1_8) { + typeNames = this.classNames; + } else { + for (int i = 0; i < length; i++) { + String currentName = this.classNames[i]; + int idx = currentName.indexOf('/'); + ModuleBinding mod = null; + if (idx > 0) { + String m = currentName.substring(0, idx); + mod = environment.getModule(m.toCharArray()); + if (mod == null) { + throw new IllegalArgumentException(this.bind("configure.invalidModuleName", m)); //$NON-NLS-1$ + } + modules[i] = mod; + modSet.add(mod); + currentName = currentName.substring(idx + 1); + } + typeNames[i] = currentName; + } + for (ModuleBinding mod : modSet) { + mod.getExports(); + mod.getRequires(); + mod.getOpens(); + mod.getServices(); + } + } + for (int i = 0; i < length; i++) { - String currentName = this.classNames[i]; char[][] compoundName = null; - int idx = currentName.indexOf('/'); - ModuleBinding mod = null; - if (idx > 0) { - String m = currentName.substring(0, idx); - mod = environment.getModule(m.toCharArray()); - if (mod == null) { - throw new IllegalArgumentException(this.bind("configure.invalidModuleName", m)); //$NON-NLS-1$ - } - currentName = currentName.substring(idx + 1); - } - if (currentName.indexOf('.') != -1) { + String cls = typeNames[i]; + if (cls.indexOf('.') != -1) { // consider names with '.' as fully qualified names - char[] typeName = currentName.toCharArray(); + char[] typeName = cls.toCharArray(); compoundName = CharOperation.splitOn('.', typeName); } else { - compoundName = new char[][] { currentName.toCharArray() }; + compoundName = new char[][] { cls.toCharArray() }; } + ModuleBinding mod = modules[i]; ReferenceBinding type = mod != null ? environment.getType(compoundName, mod) : environment.getType(compoundName); if (type != null && type.isValidBinding()) { if (type.isBinaryBinding()) { referenceBindings[i] = type; + type.superclass(); } } else { throw new IllegalArgumentException( @@ -5019,8 +5049,12 @@ protected void setPaths(ArrayList bootclasspaths, ArrayList endorsedDirClasspaths, String customEncoding) { - String version = this.options.get(CompilerOptions.OPTION_Compliance); - if (CompilerOptions.versionToJdkLevel(version) > ClassFileConstants.JDK1_8) { + if (this.complianceLevel == 0) { + String version = this.options.get(CompilerOptions.OPTION_Compliance); + this.complianceLevel = CompilerOptions.versionToJdkLevel(version); + } + + if (this.complianceLevel > ClassFileConstants.JDK1_8) { if (bootclasspaths != null && bootclasspaths.size() > 0) throw new IllegalArgumentException( this.bind("configure.unsupportedOption", "-bootclasspath")); //$NON-NLS-1$ //$NON-NLS-2$ @@ -5218,25 +5252,28 @@ protected void validateOptions(boolean didSpecifyCompliance) { } final String sourceVersion = this.options.get(CompilerOptions.OPTION_Source); - final String compliance = this.options.get(CompilerOptions.OPTION_Compliance); + if (this.complianceLevel == 0) { + final String compliance = this.options.get(CompilerOptions.OPTION_Compliance); + this.complianceLevel = CompilerOptions.versionToJdkLevel(compliance); + } if (sourceVersion.equals(CompilerOptions.VERSION_1_8) - && CompilerOptions.versionToJdkLevel(compliance) < ClassFileConstants.JDK1_8) { + && this.complianceLevel < ClassFileConstants.JDK1_8) { // compliance must be 1.8 if source is 1.8 throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_8)); //$NON-NLS-1$ } else if (sourceVersion.equals(CompilerOptions.VERSION_1_7) - && CompilerOptions.versionToJdkLevel(compliance) < ClassFileConstants.JDK1_7) { + && this.complianceLevel < ClassFileConstants.JDK1_7) { // compliance must be 1.7 if source is 1.7 throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_7)); //$NON-NLS-1$ } else if (sourceVersion.equals(CompilerOptions.VERSION_1_6) - && CompilerOptions.versionToJdkLevel(compliance) < ClassFileConstants.JDK1_6) { + && this.complianceLevel < ClassFileConstants.JDK1_6) { // compliance must be 1.6 if source is 1.6 throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_6)); //$NON-NLS-1$ } else if (sourceVersion.equals(CompilerOptions.VERSION_1_5) - && CompilerOptions.versionToJdkLevel(compliance) < ClassFileConstants.JDK1_5) { + && this.complianceLevel < ClassFileConstants.JDK1_5) { // compliance must be 1.5 if source is 1.5 throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_5)); //$NON-NLS-1$ } else if (sourceVersion.equals(CompilerOptions.VERSION_1_4) - && CompilerOptions.versionToJdkLevel(compliance) < ClassFileConstants.JDK1_4) { + && this.complianceLevel < ClassFileConstants.JDK1_4) { // compliance must be 1.4 if source is 1.4 throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_4)); //$NON-NLS-1$ } @@ -5254,7 +5291,7 @@ protected void validateOptions(boolean didSpecifyCompliance) { if (this.didSpecifySource && CompilerOptions.versionToJdkLevel(sourceVersion) >= ClassFileConstants.JDK1_4) { throw new IllegalArgumentException(this.bind("configure.incompatibleSourceForCldcTarget", targetVersion, sourceVersion)); //$NON-NLS-1$ } - if (CompilerOptions.versionToJdkLevel(compliance) >= ClassFileConstants.JDK1_5) { + if (this.complianceLevel >= ClassFileConstants.JDK1_5) { throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForCldcTarget", targetVersion, sourceVersion)); //$NON-NLS-1$ } } else { @@ -5284,7 +5321,7 @@ protected void validateOptions(boolean didSpecifyCompliance) { throw new IllegalArgumentException(this.bind("configure.incompatibleTargetForSource", targetVersion, CompilerOptions.VERSION_1_4)); //$NON-NLS-1$ } // target cannot be greater than compliance level - if (CompilerOptions.versionToJdkLevel(compliance) < CompilerOptions.versionToJdkLevel(targetVersion)){ + if (this.complianceLevel < CompilerOptions.versionToJdkLevel(targetVersion)){ throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForTarget", this.options.get(CompilerOptions.OPTION_Compliance), targetVersion)); //$NON-NLS-1$ } } diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java index e9ce993594..f3b2a9ad80 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java @@ -18,7 +18,6 @@ import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.StringTokenizer; @@ -39,34 +38,45 @@ import org.eclipse.jdt.internal.compiler.util.Util; public class ModuleFinder { - protected static List findModules(File f, String destinationPath, Parser parser, Map options, boolean isModulepath) { + public static List findModules(File f, String destinationPath, Parser parser, Map options, boolean isModulepath) { List collector = new ArrayList<>(); - if (f.isDirectory()) { - File[] files = f.listFiles(); - if (files == null) - return Collections.EMPTY_LIST; - for (final File file : files) { - Classpath modulePath = findModule(file, destinationPath, parser, options, isModulepath); - if (modulePath != null) - collector.add(modulePath); - } - } + scanForModules(destinationPath, parser, options, isModulepath, false, collector, f); return collector; } - protected static FileSystem.Classpath findModule(final File file, String destinationPath, Parser parser, Map options, boolean isModulepath) { - FileSystem.Classpath modulePath = FileSystem.getClasspath( + + protected static FileSystem.Classpath findModule(final File file, String destinationPath, Parser parser, + Map options, boolean isModulepath) { + FileSystem.Classpath modulePath = FileSystem.getClasspath(file.getAbsolutePath(), null, !isModulepath, null, + destinationPath == null ? null : (destinationPath + File.separator + file.getName()), options); + if (modulePath != null) { + scanForModule(modulePath, file, parser, isModulepath); + } + return modulePath; + } + protected static void scanForModules(String destinationPath, Parser parser, Map options, boolean isModulepath, + boolean thisAnAutomodule, List collector, final File file) { + FileSystem.Classpath entry = FileSystem.getClasspath( file.getAbsolutePath(), null, !isModulepath, null, destinationPath == null ? null : (destinationPath + File.separator + file.getName()), options); - if (modulePath != null) { - scanForModule(modulePath, file, parser, isModulepath); + if (entry != null) { + IModule module = scanForModule(entry, file, parser, thisAnAutomodule); + if (module != null) { + collector.add(entry); + } else { + if (file.isDirectory()) { + File[] files = file.listFiles(); + for (File f : files) { + scanForModules(destinationPath, parser, options, isModulepath, isModulepath, collector, f); + } + } + } } - return modulePath; } - protected static IModule scanForModule(FileSystem.Classpath modulePath, final File file, Parser parser, boolean isModulepath) { + protected static IModule scanForModule(FileSystem.Classpath modulePath, final File file, Parser parser, boolean considerAutoModules) { IModule module = null; if (file.isDirectory()) { String[] list = file.list(new FilenameFilter() { @@ -97,7 +107,7 @@ public class ModuleFinder { } else if (isJar(file)) { module = extractModuleFromJar(file, modulePath); } - if (isModulepath && module == null && !(modulePath instanceof ClasspathJrt)) { + if (considerAutoModules && module == null && !(modulePath instanceof ClasspathJrt)) { module = IModule.createAutomatic(getFileName(file), file.isFile(), getManifest(file)); } if (module != null) @@ -203,7 +213,7 @@ public class ModuleFinder { } return null; } catch (ClassFormatException | IOException e) { - e.printStackTrace(); + // Nothing to be done here } finally { if (zipFile != null) { try { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java index aa55d3db61..a17ec46549 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java @@ -72,4 +72,7 @@ default ModuleBinding module(LookupEnvironment environment) { default char[] getModuleName() { return null; } +default String getDestinationPath() { + return null; +} } diff --git a/org.eclipse.jdt.core/jdtCompilerAdapter.jar b/org.eclipse.jdt.core/jdtCompilerAdapter.jar new file mode 100644 index 0000000000..f5a110881e Binary files /dev/null and b/org.eclipse.jdt.core/jdtCompilerAdapter.jar differ diff --git a/pom.xml b/pom.xml index 1e1c68a894..64b74b9f7b 100644 --- a/pom.xml +++ b/pom.xml @@ -25,6 +25,7 @@ pom + 3.14.0.v20170830-0152 scm:git:git://git.eclipse.org/gitroot/jdt/eclipse.jdt.core.git -- cgit v1.2.3