diff --git a/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java b/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java index 151f7bcac3ad..a610e1d7b86f 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompilerManagerImpl.java @@ -45,7 +45,8 @@ import org.jetbrains.jps.incremental.BinaryContent; import org.jetbrains.jps.javac.*; import org.jetbrains.jps.javac.ast.api.JavacFileData; -import javax.tools.*; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; import java.io.File; import java.io.IOException; import java.net.URI; @@ -415,7 +416,7 @@ public class CompilerManagerImpl extends CompilerManager { final Map> outs = Collections.singletonMap(outputDir, sourceRoots); final ExternalJavacManager javacManager = getJavacManager(); - final CompilationPaths paths = CompilationPaths.create(platformCp, classpath, upgradeModulePath, modulePath, sourcePath); + final CompilationPaths paths = CompilationPaths.create(platformCp, classpath, upgradeModulePath, ModulePath.create(modulePath), sourcePath); // do not keep process alive in tests since every test expects all spawned processes to terminate in teardown boolean compiledOk = javacManager != null && javacManager.forkJavac( javaHome, -1, Collections.emptyList(), options, paths, files, outs, diagnostic, outputCollector, diff --git a/java/compiler/tests/com/intellij/compiler/JavaCompilerBasicTest.java b/java/compiler/tests/com/intellij/compiler/JavaCompilerBasicTest.java index 336931c711d6..4cd2dcdcbbd6 100644 --- a/java/compiler/tests/com/intellij/compiler/JavaCompilerBasicTest.java +++ b/java/compiler/tests/com/intellij/compiler/JavaCompilerBasicTest.java @@ -8,6 +8,7 @@ import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.io.Compressor; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.javac.JpsJavacFileManager; import org.jetbrains.jps.javac.OutputFileObject; import org.jetbrains.jps.javac.ZipFileObject; @@ -66,27 +67,7 @@ public class JavaCompilerBasicTest extends BaseCompilerTestCase { public void report(Diagnostic diagnostic) { } }, Locale.US, null); - final JpsJavacFileManager fileManager = new JpsJavacFileManager(new JpsJavacFileManager.Context() { - @Override - public boolean isCanceled() { - return false; - } - - @NotNull - @Override - public StandardJavaFileManager getStandardFileManager() { - return stdFileManager; - } - - @Override - public void consumeOutputFile(@NotNull OutputFileObject obj) { - } - - @Override - public void reportMessage(Diagnostic.Kind kind, String message) { - - } - }, true, Collections.emptyList()); + final JpsJavacFileManager fileManager = new JpsJavacFileManager(new DummyContext(stdFileManager), true, Collections.emptyList()); fileManager.setLocation(StandardLocation.CLASS_PATH, Collections.singleton(jarFile)); fileManager.setLocation(StandardLocation.SOURCE_PATH, Collections.emptyList()); @@ -123,27 +104,7 @@ public class JavaCompilerBasicTest extends BaseCompilerTestCase { public void report(Diagnostic diagnostic) { } }, Locale.US, null); - final JpsJavacFileManager fileManager = new JpsJavacFileManager(new JpsJavacFileManager.Context() { - @Override - public boolean isCanceled() { - return false; - } - - @NotNull - @Override - public StandardJavaFileManager getStandardFileManager() { - return stdFileManager; - } - - @Override - public void consumeOutputFile(@NotNull OutputFileObject obj) { - } - - @Override - public void reportMessage(Diagnostic.Kind kind, String message) { - - } - }, true, Collections.emptyList()); + final JpsJavacFileManager fileManager = new JpsJavacFileManager(new DummyContext(stdFileManager), true, Collections.emptyList()); fileManager.setLocation(StandardLocation.CLASS_PATH, Collections.singleton(jarFile)); fileManager.setLocation(StandardLocation.SOURCE_PATH, Collections.emptyList()); @@ -187,7 +148,7 @@ public class JavaCompilerBasicTest extends BaseCompilerTestCase { private static void checkFileObjectsBelongToLocation(JpsJavacFileManager fileManager, final JavaFileManager.Location location, - Iterable fileObjects) { + Iterable fileObjects) throws IOException { for (FileObject source : fileObjects) { assertTrue(source.getName() + " should belong to " + location.getName(), fileManager.contains(location, source)); } @@ -212,4 +173,37 @@ public class JavaCompilerBasicTest extends BaseCompilerTestCase { make(module); assertOutput(module, fs().file("A.class")); } + + private static final class DummyContext implements JpsJavacFileManager.Context { + private final StandardJavaFileManager myStdFileManager; + + DummyContext(StandardJavaFileManager stdFileManager) { + myStdFileManager = stdFileManager; + } + + @Nullable + @Override + public String getExplodedAutomaticModuleName(File pathElement) { + return null; + } + + @Override + public boolean isCanceled() { + return false; + } + + @NotNull + @Override + public StandardJavaFileManager getStandardFileManager() { + return myStdFileManager; + } + + @Override + public void consumeOutputFile(@NotNull OutputFileObject obj) { + } + + @Override + public void reportMessage(Diagnostic.Kind kind, String message) { + } + } } diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModule/moduleA/src/ppp/Util.java b/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModule/moduleA/src/ppp/Util.java new file mode 100644 index 000000000000..5ca0951a94f0 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModule/moduleA/src/ppp/Util.java @@ -0,0 +1,7 @@ +package ppp; + +public class Util { + public static void perform() { + System.out.println("Util.perform"); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModule/moduleB/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModule/moduleB/src/module-info.java new file mode 100644 index 000000000000..33f12a89b194 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModule/moduleB/src/module-info.java @@ -0,0 +1,3 @@ +module B { + requires A; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModule/moduleB/src/qqq/Main.java b/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModule/moduleB/src/qqq/Main.java new file mode 100644 index 000000000000..b18eef72d02a --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModule/moduleB/src/qqq/Main.java @@ -0,0 +1,9 @@ +package qqq; + +import ppp.Util; + +public class Main { + public static void main(String[] args) { + Util.perform(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModuleWithManifest/moduleA/src/META-INF/MANIFEST.MF b/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModuleWithManifest/moduleA/src/META-INF/MANIFEST.MF new file mode 100644 index 000000000000..9d08edcf1355 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModuleWithManifest/moduleA/src/META-INF/MANIFEST.MF @@ -0,0 +1 @@ +Automatic-Module-Name: custom.a diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModuleWithManifest/moduleA/src/ppp/Util.java b/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModuleWithManifest/moduleA/src/ppp/Util.java new file mode 100644 index 000000000000..5ca0951a94f0 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModuleWithManifest/moduleA/src/ppp/Util.java @@ -0,0 +1,7 @@ +package ppp; + +public class Util { + public static void perform() { + System.out.println("Util.perform"); + } +} diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModuleWithManifest/moduleB/src/module-info.java b/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModuleWithManifest/moduleB/src/module-info.java new file mode 100644 index 000000000000..c305fcd97900 --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModuleWithManifest/moduleB/src/module-info.java @@ -0,0 +1,3 @@ +module B { + requires custom.a; +} \ No newline at end of file diff --git a/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModuleWithManifest/moduleB/src/qqq/Main.java b/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModuleWithManifest/moduleB/src/qqq/Main.java new file mode 100644 index 000000000000..b18eef72d02a --- /dev/null +++ b/java/java-tests/testData/compileServer/incremental/java9-features/explodedAutoModuleWithManifest/moduleB/src/qqq/Main.java @@ -0,0 +1,9 @@ +package qqq; + +import ppp.Util; + +public class Main { + public static void main(String[] args) { + Util.perform(); + } +} \ No newline at end of file diff --git a/jps/jps-builders-6/proto/javac_remote_proto.proto b/jps/jps-builders-6/proto/javac_remote_proto.proto index 463b18f0d078..605d403cbb21 100644 --- a/jps/jps-builders-6/proto/javac_remote_proto.proto +++ b/jps/jps-builders-6/proto/javac_remote_proto.proto @@ -44,6 +44,7 @@ message Message { repeated OutputGroup output = 7; repeated string module_path = 8; repeated string upgrade_module_path = 9; + map module_names = 10; } message Response { diff --git a/jps/jps-builders-6/src/org/jetbrains/jps/javac/ExternalJavacProcess.java b/jps/jps-builders-6/src/org/jetbrains/jps/javac/ExternalJavacProcess.java index d3325b8c8000..60167055c1fd 100644 --- a/jps/jps-builders-6/src/org/jetbrains/jps/javac/ExternalJavacProcess.java +++ b/jps/jps-builders-6/src/org/jetbrains/jps/javac/ExternalJavacProcess.java @@ -142,7 +142,7 @@ public class ExternalJavacProcess { Collection files, Collection classpath, Collection platformCp, - Collection modulePath, + ModulePath modulePath, Collection upgradeModulePath, Collection sourcePath, Map> outs, @@ -237,7 +237,14 @@ public class ExternalJavacProcess { final List cp = toFiles(request.getClasspathList()); final List platformCp = toFiles(request.getPlatformClasspathList()); final List srcPath = toFiles(request.getSourcepathList()); - final List modulePath = toFiles(request.getModulePathList()); + + final ModulePath.Builder modulePathBuilder = ModulePath.newBuilder(); + final Map namesMap = request.getModuleNamesMap(); + for (String path : request.getModulePathList()) { + modulePathBuilder.add(namesMap.get(path), new File(path)); + } + final ModulePath modulePath = modulePathBuilder.create(); + final List upgradeModulePath = toFiles(request.getUpgradeModulePathList()); final Map> outs = new HashMap>(); diff --git a/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavacMain.java b/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavacMain.java index 4754f521b2d4..7e61620fee33 100644 --- a/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavacMain.java +++ b/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavacMain.java @@ -40,7 +40,7 @@ public class JavacMain { final Collection sources, Collection classpath, Collection platformClasspath, - Collection modulePath, + ModulePath modulePath, Collection upgradeModulePath, Collection sourcePath, final Map> outputDirToRoots, @@ -63,7 +63,7 @@ public class JavacMain { final boolean usingJavac = compilingTool instanceof JavacCompilerTool; final boolean javacBefore9 = isJavacBefore9(compilingTool); final JpsJavacFileManager fileManager = new JpsJavacFileManager( - new ContextImpl(compiler, diagnosticConsumer, outputSink, canceledStatus), javacBefore9, JavaSourceTransformer.getTransformers() + new ContextImpl(compiler, diagnosticConsumer, outputSink, modulePath, canceledStatus), javacBefore9, JavaSourceTransformer.getTransformers() ); if (!platformClasspath.isEmpty()) { // for javac6 this will prevent lazy initialization of Paths.bootClassPathRtJar @@ -120,12 +120,12 @@ public class JavacMain { if (!modulePath.isEmpty()) { try { - setLocation(fileManager, "MODULE_PATH", modulePath); + setLocation(fileManager, "MODULE_PATH", modulePath.getPath()); if (isAnnotationProcessingEnabled(_options) && getLocation(fileManager, "ANNOTATION_PROCESSOR_MODULE_PATH") == null && fileManager.getLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH) == null) { // default annotation processing discovery path to module path if not explicitly set - setLocation(fileManager, "ANNOTATION_PROCESSOR_MODULE_PATH", JpsJavacFileManager.filter(modulePath, new BooleanFunction() { + setLocation(fileManager, "ANNOTATION_PROCESSOR_MODULE_PATH", JpsJavacFileManager.filter(modulePath.getPath(), new BooleanFunction() { @Override public boolean fun(File file) { return !outputDirToRoots.containsKey(file); @@ -534,15 +534,27 @@ public class JavacMain { private final StandardJavaFileManager myStdManager; private final DiagnosticOutputConsumer myOutConsumer; private final OutputFileConsumer myOutputFileSink; + private final ModulePath myModulePath; private final CanceledStatus myCanceledStatus; - ContextImpl(@NotNull JavaCompiler compiler, @NotNull DiagnosticOutputConsumer outConsumer, @NotNull OutputFileConsumer sink, CanceledStatus canceledStatus) { + ContextImpl(@NotNull JavaCompiler compiler, + @NotNull DiagnosticOutputConsumer outConsumer, + @NotNull OutputFileConsumer sink, + @NotNull ModulePath modulePath, + CanceledStatus canceledStatus) { myOutConsumer = outConsumer; myOutputFileSink = sink; + myModulePath = modulePath; myCanceledStatus = canceledStatus; myStdManager = compiler.getStandardFileManager(outConsumer, Locale.US, null); } + @Nullable + @Override + public String getExplodedAutomaticModuleName(File pathElement) { + return myModulePath.getModuleName(pathElement); + } + @Override public boolean isCanceled() { return myCanceledStatus.isCanceled(); diff --git a/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavacProtoUtil.java b/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavacProtoUtil.java index e0fab11a991d..353faad2f27b 100644 --- a/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavacProtoUtil.java +++ b/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavacProtoUtil.java @@ -6,7 +6,9 @@ import com.intellij.openapi.util.io.FileUtilRt; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.incremental.BinaryContent; -import javax.tools.*; +import javax.tools.Diagnostic; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.PrintStream; @@ -30,7 +32,7 @@ public class JavacProtoUtil { Collection files, Collection classpath, Collection platformCp, - Collection modulePath, + ModulePath modulePath, Collection upgradeModulePath, Collection sourcePath, Map> outs) { @@ -46,8 +48,13 @@ public class JavacProtoUtil { for (File file : platformCp) { builder.addPlatformClasspath(FileUtilRt.toSystemIndependentName(file.getPath())); } - for (File file : modulePath) { - builder.addModulePath(FileUtilRt.toSystemIndependentName(file.getPath())); + for (File file : modulePath.getPath()) { + final String pathEntry = FileUtilRt.toSystemIndependentName(file.getPath()); + builder.addModulePath(pathEntry); + final String moduleName = modulePath.getModuleName(file); + if (moduleName != null) { + builder.putModuleNames(pathEntry, moduleName); + } } for (File file : upgradeModulePath) { builder.addUpgradeModulePath(FileUtilRt.toSystemIndependentName(file.getPath())); diff --git a/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavacRemoteProto.java b/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavacRemoteProto.java index 444504e3fadb..93115a524301 100644 --- a/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavacRemoteProto.java +++ b/jps/jps-builders-6/src/org/jetbrains/jps/javac/JavacRemoteProto.java @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. // Generated by the protocol buffer compiler. DO NOT EDIT! // source: javac_remote_proto.proto @@ -1277,6 +1277,40 @@ public final class JavacRemoteProto { */ com.google.protobuf.ByteString getUpgradeModulePathBytes(int index); + + /** + * map<string, string> module_names = 10; + */ + int getModuleNamesCount(); + /** + * map<string, string> module_names = 10; + */ + boolean containsModuleNames( + java.lang.String key); + /** + * Use {@link #getModuleNamesMap()} instead. + */ + @java.lang.Deprecated + java.util.Map + getModuleNames(); + /** + * map<string, string> module_names = 10; + */ + java.util.Map + getModuleNamesMap(); + /** + * map<string, string> module_names = 10; + */ + + java.lang.String getModuleNamesOrDefault( + java.lang.String key, + java.lang.String defaultValue); + /** + * map<string, string> module_names = 10; + */ + + java.lang.String getModuleNamesOrThrow( + java.lang.String key); } /** * Protobuf type {@code org.jetbrains.javac.Message.Request} @@ -2672,6 +2706,93 @@ public final class JavacRemoteProto { upgradeModulePath_.add(value.toStringUtf8()); } + public static final int MODULE_NAMES_FIELD_NUMBER = 10; + private static final class ModuleNamesDefaultEntryHolder { + static final com.google.protobuf.MapEntryLite< + java.lang.String, java.lang.String> defaultEntry = + com.google.protobuf.MapEntryLite + .newDefaultInstance( + com.google.protobuf.WireFormat.FieldType.STRING, + "", + com.google.protobuf.WireFormat.FieldType.STRING, + ""); + } + private com.google.protobuf.MapFieldLite< + java.lang.String, java.lang.String> moduleNames_ = + com.google.protobuf.MapFieldLite.emptyMapField(); + private com.google.protobuf.MapFieldLite + internalGetModuleNames() { + return moduleNames_; + } + private com.google.protobuf.MapFieldLite + internalGetMutableModuleNames() { + if (!moduleNames_.isMutable()) { + moduleNames_ = moduleNames_.mutableCopy(); + } + return moduleNames_; + } + + public int getModuleNamesCount() { + return internalGetModuleNames().size(); + } + /** + * map<string, string> module_names = 10; + */ + + public boolean containsModuleNames( + java.lang.String key) { + if (key == null) { throw new java.lang.NullPointerException(); } + return internalGetModuleNames().containsKey(key); + } + /** + * Use {@link #getModuleNamesMap()} instead. + */ + @java.lang.Deprecated + public java.util.Map getModuleNames() { + return getModuleNamesMap(); + } + /** + * map<string, string> module_names = 10; + */ + + public java.util.Map getModuleNamesMap() { + return java.util.Collections.unmodifiableMap( + internalGetModuleNames()); + } + /** + * map<string, string> module_names = 10; + */ + + public java.lang.String getModuleNamesOrDefault( + java.lang.String key, + java.lang.String defaultValue) { + if (key == null) { throw new java.lang.NullPointerException(); } + java.util.Map map = + internalGetModuleNames(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + * map<string, string> module_names = 10; + */ + + public java.lang.String getModuleNamesOrThrow( + java.lang.String key) { + if (key == null) { throw new java.lang.NullPointerException(); } + java.util.Map map = + internalGetModuleNames(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + /** + * map<string, string> module_names = 10; + */ + private java.util.Map + getMutableModuleNamesMap() { + return internalGetMutableModuleNames(); + } + public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { if (((bitField0_ & 0x00000001) == 0x00000001)) { @@ -2701,6 +2822,11 @@ public final class JavacRemoteProto { for (int i = 0; i < upgradeModulePath_.size(); i++) { output.writeString(9, upgradeModulePath_.get(i)); } + for (java.util.Map.Entry entry + : internalGetModuleNames().entrySet()) { + ModuleNamesDefaultEntryHolder.defaultEntry.serializeTo( + output, 10, entry.getKey(), entry.getValue()); + } unknownFields.writeTo(output); } @@ -2780,6 +2906,11 @@ public final class JavacRemoteProto { size += dataSize; size += 1 * getUpgradeModulePathList().size(); } + for (java.util.Map.Entry entry + : internalGetModuleNames().entrySet()) { + size += ModuleNamesDefaultEntryHolder.defaultEntry.computeMessageSize( + 10, entry.getKey(), entry.getValue()); + } size += unknownFields.getSerializedSize(); memoizedSerializedSize = size; return size; @@ -3510,6 +3641,98 @@ public final class JavacRemoteProto { return this; } + + public int getModuleNamesCount() { + return instance.getModuleNamesMap().size(); + } + /** + * map<string, string> module_names = 10; + */ + + public boolean containsModuleNames( + java.lang.String key) { + if (key == null) { throw new java.lang.NullPointerException(); } + return instance.getModuleNamesMap().containsKey(key); + } + + public Builder clearModuleNames() { + copyOnWrite(); + instance.getMutableModuleNamesMap().clear(); + return this; + } + /** + * map<string, string> module_names = 10; + */ + + public Builder removeModuleNames( + java.lang.String key) { + if (key == null) { throw new java.lang.NullPointerException(); } + copyOnWrite(); + instance.getMutableModuleNamesMap().remove(key); + return this; + } + /** + * Use {@link #getModuleNamesMap()} instead. + */ + @java.lang.Deprecated + public java.util.Map getModuleNames() { + return getModuleNamesMap(); + } + /** + * map<string, string> module_names = 10; + */ + public java.util.Map getModuleNamesMap() { + return java.util.Collections.unmodifiableMap( + instance.getModuleNamesMap()); + } + /** + * map<string, string> module_names = 10; + */ + + public java.lang.String getModuleNamesOrDefault( + java.lang.String key, + java.lang.String defaultValue) { + if (key == null) { throw new java.lang.NullPointerException(); } + java.util.Map map = + instance.getModuleNamesMap(); + return map.containsKey(key) ? map.get(key) : defaultValue; + } + /** + * map<string, string> module_names = 10; + */ + + public java.lang.String getModuleNamesOrThrow( + java.lang.String key) { + if (key == null) { throw new java.lang.NullPointerException(); } + java.util.Map map = + instance.getModuleNamesMap(); + if (!map.containsKey(key)) { + throw new java.lang.IllegalArgumentException(); + } + return map.get(key); + } + /** + * map<string, string> module_names = 10; + */ + public Builder putModuleNames( + java.lang.String key, + java.lang.String value) { + if (key == null) { throw new java.lang.NullPointerException(); } + if (value == null) { throw new java.lang.NullPointerException(); } + copyOnWrite(); + instance.getMutableModuleNamesMap().put(key, value); + return this; + } + /** + * map<string, string> module_names = 10; + */ + public Builder putAllModuleNames( + java.util.Map values) { + copyOnWrite(); + instance.getMutableModuleNamesMap().putAll(values); + return this; + } + // @@protoc_insertion_point(builder_scope:org.jetbrains.javac.Message.Request) } private byte memoizedIsInitialized = 2; @@ -3547,6 +3770,7 @@ public final class JavacRemoteProto { output_.makeImmutable(); modulePath_.makeImmutable(); upgradeModulePath_.makeImmutable(); + moduleNames_.makeImmutable(); return null; } case NEW_BUILDER: { @@ -3565,6 +3789,8 @@ public final class JavacRemoteProto { output_= visitor.visitList(output_, other.output_); modulePath_= visitor.visitList(modulePath_, other.modulePath_); upgradeModulePath_= visitor.visitList(upgradeModulePath_, other.upgradeModulePath_); + moduleNames_ = visitor.visitMap( + moduleNames_, other.internalGetModuleNames()); if (visitor == com.google.protobuf.GeneratedMessageLite.MergeFromVisitor .INSTANCE) { bitField0_ |= other.bitField0_; @@ -3676,6 +3902,12 @@ public final class JavacRemoteProto { upgradeModulePath_.add(s); break; } + case 82: { + if (!moduleNames_.isMutable()) { + moduleNames_ = moduleNames_.mutableCopy(); + } + ModuleNamesDefaultEntryHolder.defaultEntry.parseInto(moduleNames_, input, extensionRegistry); break; + } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { diff --git a/jps/jps-builders-6/src/org/jetbrains/jps/javac/JpsJavacFileManager.java b/jps/jps-builders-6/src/org/jetbrains/jps/javac/JpsJavacFileManager.java index e20b7ca3ed8c..1e81a97239bb 100644 --- a/jps/jps-builders-6/src/org/jetbrains/jps/javac/JpsJavacFileManager.java +++ b/jps/jps-builders-6/src/org/jetbrains/jps/javac/JpsJavacFileManager.java @@ -13,6 +13,7 @@ import javax.tools.*; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; @@ -61,17 +62,7 @@ public class JpsJavacFileManager extends ForwardingJavaFileManager> myOutputsMap = Collections.emptyMap(); @Nullable private String myEncodingName; @@ -82,6 +73,12 @@ public class JpsJavacFileManager extends ForwardingJavaFileManager path) throws IOException{ getStdManager().setLocation(location, path); + if ("MODULE_PATH".equals(location.getName())) { + initExplodedModuleNames(location, path); + } } @Override @@ -485,21 +488,15 @@ public class JpsJavacFileManager extends ForwardingJavaFileManager myContainsCall = new DelegateCallHandler( + JavaFileManager.class, "contains", Location.class, FileObject.class + ); public void onOutputFileGenerated(File file) { final File parent = file.getParentFile(); @@ -530,6 +527,76 @@ public class JpsJavacFileManager extends ForwardingJavaFileManager mySetLocationForModuleCall = new DelegateCallHandler( + StandardJavaFileManager.class, "setLocationForModule", Location.class, String.class, Collection.class + ); + private final DelegateCallHandler myToPathCall = new DelegateCallHandler(File.class, "toPath"); + + private void initExplodedModuleNames(final Location modulePathLocation, Iterable path) throws IOException { + if (mySetLocationForModuleCall.isAvailable() && myToPathCall.isAvailable()) { + for (File pathEntry : path) { + final String explodedModuleName = myContext.getExplodedAutomaticModuleName(pathEntry); + if (explodedModuleName != null) { + mySetLocationForModuleCall.callDefaultImpl( + getStdManager(), modulePathLocation, explodedModuleName, Collections.singleton(myToPathCall.callDefaultImpl(pathEntry)) + ); + } + } + } + } + + @SuppressWarnings("unchecked") + private static class DelegateCallHandler { + private final Method myMethod; + private final String myUnsupportedMessage; + + DelegateCallHandler(final Class apiInterface, String methodName, Class... argTypes) { + myUnsupportedMessage = "Operation "+ methodName + " is not supported"; + Method m = null; + try { + m = apiInterface.getDeclaredMethod(methodName, argTypes); + } + catch (Throwable ignored) { + } + myMethod = m; + } + + boolean isAvailable() { + return myMethod != null; + } + + R callDefaultImpl(final T callTarget, Object... args) throws IOException { + return callDefaultImpl(callTarget, "", args); + } + + R callDefaultImpl(final T callTarget, String errorDetails, Object... args) throws IOException{ + if (!isAvailable()) { + throw new UnsupportedOperationException(getErrorMessage(errorDetails)); + } + // delegate the call further + try { + return (R)myMethod.invoke(callTarget, args); + } + catch (InvocationTargetException e) { + final Throwable cause = e.getCause(); + if (cause instanceof IOException) { + throw (IOException)cause; + } + if (cause instanceof RuntimeException) { + throw (RuntimeException)cause; + } + throw new UnsupportedOperationException(getErrorMessage(errorDetails), cause != null ? cause : e); + } + catch (Throwable e) { + throw new UnsupportedOperationException(getErrorMessage(errorDetails), e); + } + } + + private String getErrorMessage(String errorDetails) { + return errorDetails.isEmpty() ? myUnsupportedMessage : myUnsupportedMessage + ": " + errorDetails; + } + } + public static Iterable merge(final Iterable first, final Iterable second) { return new Iterable() { @Override diff --git a/jps/jps-builders-6/src/org/jetbrains/jps/javac/ModulePath.java b/jps/jps-builders-6/src/org/jetbrains/jps/javac/ModulePath.java new file mode 100644 index 000000000000..e5b55b27c572 --- /dev/null +++ b/jps/jps-builders-6/src/org/jetbrains/jps/javac/ModulePath.java @@ -0,0 +1,102 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.jps.javac; + +import gnu.trove.THashMap; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +/** + * @author Eugene Zhuravlev + * Date: 17-Oct-19 + */ +public abstract class ModulePath { + + public interface Builder { + Builder add(String moduleName, File pathElement); + ModulePath create(); + } + + public abstract Collection getPath(); + + /** + * @param pathElement a single module path enntry + * @return a JPMS module name associated with the passed module path element. + * null value does not necessarily mean the entry cannot be treated as a JPMS module. null only + * means that there is no module name information stored for the file in this ModulePath object + */ + public abstract String getModuleName(File pathElement); + + public boolean isEmpty() { + return getPath().isEmpty(); + } + + public static final ModulePath EMPTY = new ModulePath() { + @Override + public Collection getPath() { + return Collections.emptyList(); + } + + @Override + public String getModuleName(File pathElement) { + return null; + } + }; + + public static ModulePath create(Collection path) { + if (path.isEmpty()) { + return EMPTY; + } + final Collection files = Collections.unmodifiableCollection(path); + return new ModulePath() { + @Override + public Collection getPath() { + return files; + } + + @Override + public String getModuleName(File pathElement) { + return null; + } + }; + } + + public static Builder newBuilder() { + return new Builder() { + private final Map myMap = new THashMap(); + private final Collection myPath = new ArrayList(); + + @Override + public Builder add(String moduleName, File pathElement) { + myPath.add(pathElement); + if (moduleName != null) { + myMap.put(pathElement, moduleName); + } + return this; + } + + @Override + public ModulePath create() { + if (myPath.isEmpty()) { + return EMPTY; + } + final Collection files = Collections.unmodifiableCollection(myPath); + return new ModulePath() { + @Override + public Collection getPath() { + return files; + } + + @Override + public String getModuleName(File pathElement) { + return myMap.get(pathElement); + } + }; + } + }; + } + +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index 26b5d7fb7705..06390151f640 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -27,14 +27,10 @@ import org.jetbrains.jps.PathUtils; import org.jetbrains.jps.ProjectPaths; import org.jetbrains.jps.api.GlobalOptions; import org.jetbrains.jps.backwardRefs.JavaBackwardReferenceIndexWriter; -import org.jetbrains.jps.builders.BuildRootIndex; -import org.jetbrains.jps.builders.DirtyFilesHolder; -import org.jetbrains.jps.builders.FileProcessor; +import org.jetbrains.jps.builders.*; import org.jetbrains.jps.builders.impl.DirtyFilesHolderBase; -import org.jetbrains.jps.builders.java.JavaBuilderExtension; -import org.jetbrains.jps.builders.java.JavaBuilderUtil; -import org.jetbrains.jps.builders.java.JavaCompilingTool; -import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor; +import org.jetbrains.jps.builders.impl.TargetOutputIndexImpl; +import org.jetbrains.jps.builders.java.*; import org.jetbrains.jps.builders.logging.ProjectBuilderLogger; import org.jetbrains.jps.builders.storage.BuildDataCorruptedException; import org.jetbrains.jps.cmdline.ProjectDescriptor; @@ -59,7 +55,8 @@ import org.jetbrains.jps.model.serialization.PathMacroUtil; import org.jetbrains.jps.service.JpsServiceManager; import org.jetbrains.jps.service.SharedThreadPool; -import javax.tools.*; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; import java.io.File; import java.io.FileFilter; import java.io.IOException; @@ -70,6 +67,7 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.Executor; import java.util.concurrent.Future; import java.util.function.BiConsumer; +import java.util.function.Function; import java.util.stream.Collectors; import static com.intellij.openapi.util.Pair.pair; @@ -147,7 +145,7 @@ public class JavaBuilder extends ModuleLevelBuilder { if (LOG.isDebugEnabled()) { LOG.debug("Java compiler ID: " + compilerId); } - MODULE_PATH_SPLITTER.set(context, new ModulePathSplitter()); + MODULE_PATH_SPLITTER.set(context, new ModulePathSplitter(new ExplodedModuleNameFinder(context))); JavaCompilingTool compilingTool = JavaBuilderUtil.findCompilingTool(compilerId); COMPILING_TOOL.set(context, compilingTool); COMPILER_USAGE_STATISTICS.set(context, new ConcurrentHashMap<>()); @@ -443,23 +441,27 @@ public class JavaBuilder extends ModuleLevelBuilder { } Collection classPath = originalClassPath; - Collection modulePath = Collections.emptyList(); + ModulePath modulePath = ModulePath.EMPTY; Collection upgradeModulePath = Collections.emptyList(); if (moduleInfoFile != null) { // has modules + final ModulePathSplitter splitter = MODULE_PATH_SPLITTER.get(context); + final Pair> pair = splitter.splitPath( + moduleInfoFile, outs.keySet(), ProjectPaths.getCompilationModulePath(chunk, false) + ); final boolean useModulePathOnly = Boolean.parseBoolean(System.getProperty(USE_MODULE_PATH_ONLY_OPTION))/*compilerConfig.useModulePathOnly()*/; if (useModulePathOnly) { // in Java 9, named modules are not allowed to read classes from the classpath // moreover, the compiler requires all transitive dependencies to be on the module path - modulePath = ProjectPaths.getCompilationModulePath(chunk, false); + ModulePath.Builder mpBuilder = ModulePath.newBuilder(); + for (File file : ProjectPaths.getCompilationModulePath(chunk, false)) { + mpBuilder.add(pair.first.getModuleName(file), file); + } + modulePath = mpBuilder.create(); classPath = Collections.emptyList(); } else { // placing only explicitly referenced modules into the module path and the rest of deps to classpath - final ModulePathSplitter splitter = MODULE_PATH_SPLITTER.get(context); - final Pair, Collection> pair = splitter.splitPath( - moduleInfoFile, outs.keySet(), ProjectPaths.getCompilationModulePath(chunk, false) - ); modulePath = pair.first; classPath = pair.second; } @@ -1247,6 +1249,29 @@ public class JavaBuilder extends ModuleLevelBuilder { } } + private static class ExplodedModuleNameFinder implements Function { + private final TargetOutputIndex myOutsIndex; + + ExplodedModuleNameFinder(CompileContext context) { + final BuildTargetIndex targetIndex = context.getProjectDescriptor().getBuildTargetIndex(); + final List javaModuleTargets = new ArrayList<>(); + for (JavaModuleBuildTargetType type : JavaModuleBuildTargetType.ALL_TYPES) { + javaModuleTargets.addAll(targetIndex.getAllTargets(type)); + } + myOutsIndex = new TargetOutputIndexImpl(javaModuleTargets, context); + } + + @Override + public String apply(File outputDir) { + for (BuildTarget target : myOutsIndex.getTargetsByOutputFile(outputDir)) { + if (target instanceof ModuleBasedTarget) { + return ((ModuleBasedTarget)target).getModule().getName().trim(); + } + } + return ModulePathSplitter.DEFAULT_MODULE_NAME_SEARCH.apply(outputDir); + } + } + private class ClassProcessingConsumer implements OutputFileConsumer { private final CompileContext myContext; private final OutputFileConsumer myDelegateOutputFileSink; diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/ModulePathSplitter.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/ModulePathSplitter.java index 8745a2572a97..2d827bc3bbea 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/ModulePathSplitter.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/ModulePathSplitter.java @@ -11,19 +11,27 @@ import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.javac.JpsJavacFileManager; +import org.jetbrains.jps.javac.ModulePath; +import java.io.BufferedInputStream; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.lang.reflect.Method; import java.nio.file.Path; import java.util.*; +import java.util.function.Function; +import java.util.jar.Attributes; +import java.util.jar.Manifest; +import java.util.regex.Pattern; /** * @author Eugene Zhuravlev * Date: 26-Sep-19 */ public class ModulePathSplitter { - private final Map myCache = Collections.synchronizedMap(new THashMap<>(FileUtil.FILE_HASHING_STRATEGY)); + private static final Attributes.Name AUTOMATIC_MODULE_NAME = new Attributes.Name("Automatic-Module-Name"); private static final Method myModuleFinderCreateMethod; private static final Method myFindAll; private static final Method myGetDescriptor; @@ -60,22 +68,72 @@ public class ModulePathSplitter { myDescriptorRequires = descriptorRequires; } + // derives module name from filename + public static final Function DEFAULT_MODULE_NAME_SEARCH = file -> { + final String fName = file.getName(); + final int dotIndex = fName.lastIndexOf('.'); // drop extension + return dotIndex >= 0? fName.substring(0, dotIndex) : fName; + }; + + @NotNull + private final Function myModuleNameSearch; + public ModulePathSplitter() { + this(DEFAULT_MODULE_NAME_SEARCH); + } + + public ModulePathSplitter(@NotNull Function moduleNameSearch) { + myModuleNameSearch = moduleNameSearch; } - public Pair, Collection> splitPath(File chunkModuleInfo, Set chunkOutputs, Collection path) { + public Pair> splitPath(File chunkModuleInfo, Set chunkOutputs, Collection path) { if (myModuleFinderCreateMethod == null) { // the module API is not available - return Pair.create(path, Collections.emptyList()); + return Pair.create(ModulePath.create(path), Collections.emptyList()); } - final List modulePath = new ArrayList<>(); + final ModulePath.Builder mpBuilder = ModulePath.newBuilder(); final List classpath = new ArrayList<>(); final Set allRequired = collectRequired(chunkModuleInfo, JpsJavacFileManager.filter(path, file -> !chunkOutputs.contains(file))); for (File file : path) { - (chunkOutputs.contains(file) || allRequired.contains(getModuleInfo(file).name) ? modulePath : classpath).add(file); + if (chunkOutputs.contains(file)) { + mpBuilder.add(null, file); + } + else { + final ModuleInfo info = getModuleInfo(file); + if (allRequired.contains(info.name)) { + // storing only names for automatic modules in "exploded" form. + // for all other kinds of roots module-name is correctly determined by javac itself + mpBuilder.add(info.isAutomaticExploded? info.name : null, file); + } + else { + classpath.add(file); + } + } } - return Pair.create(Collections.unmodifiableList(modulePath), Collections.unmodifiableList(classpath)); + return Pair.create(mpBuilder.create(), Collections.unmodifiableList(classpath)); + } + + private static final Pattern NON_ALPHANUM = Pattern.compile("[^A-Za-z0-9]"); + private static final Pattern REPEATING_DOTS = Pattern.compile("(\\.)(\\1)+"); + + private static String normalizeModuleName(String fName) { + if (fName != null) { + // replace non-alphanumeric + fName = NON_ALPHANUM.matcher(fName).replaceAll("."); + // collapse repeating dots + fName = REPEATING_DOTS.matcher(fName).replaceAll("."); + // drop leading and trailing dots + final int len = fName.length(); + if (len > 0) { + final int start = fName.startsWith(".") ? 1 : 0; + final int end = fName.endsWith(".") ? len - 1 : len; + if (start > 0 || end < len) { + fName = fName.substring(start, end); + } + } + } + return fName; } private Set collectRequired(File chunkModuleInfo, Iterable path) { @@ -104,21 +162,30 @@ public class ModulePathSplitter { try { Object mf = myModuleFinderCreateMethod.invoke(null, (Object)new Path[]{f.toPath()}); // ModuleFinder.of(f.toPath()); - for (Object moduleRef : (Set)myFindAll.invoke(mf)) { // mf.findAll() - final Object descriptor = myGetDescriptor.invoke(moduleRef); // moduleRef.descriptor() - final String moduleName = (String)myDescriptorName.invoke(descriptor); // descriptor.name(); - final Set requires = (Set)myDescriptorRequires.invoke(descriptor); //descriptor.requires(); - if (requires.isEmpty()) { - info = new ModuleInfo(moduleName); - } - else { - final Set req = new HashSet<>(); - for (Object require : requires) { - req.add((String)myRequiresName.invoke(require)/*require.name()*/); + final Set moduleRefs = (Set)myFindAll.invoke(mf); // mf.findAll() + if (!moduleRefs.isEmpty()) { + for (Object moduleRef : moduleRefs) { + final Object descriptor = myGetDescriptor.invoke(moduleRef); // moduleRef.descriptor() + final String moduleName = (String)myDescriptorName.invoke(descriptor); // descriptor.name(); + final Set requires = (Set)myDescriptorRequires.invoke(descriptor); //descriptor.requires(); + if (requires.isEmpty()) { + info = new ModuleInfo(moduleName, false); } - info = new ModuleInfo(moduleName, req); + else { + final Set req = new HashSet<>(); + for (Object require : requires) { + req.add((String)myRequiresName.invoke(require)/*require.name()*/); + } + info = new ModuleInfo(moduleName, req); + } + break; + } + } + else { + final String explodedModuleName = deriveAutomaticModuleName(f); + if (explodedModuleName != null) { + info = new ModuleInfo(explodedModuleName, true); } - break; } } catch (Throwable ignored) { @@ -127,21 +194,45 @@ public class ModulePathSplitter { return info; } - private static final class ModuleInfo { - static final ModuleInfo EMPTY = new ModuleInfo(null, Collections.emptyList()); + private String deriveAutomaticModuleName(File dir) { + if (dir.isDirectory()) { + try { + final BufferedInputStream is = new BufferedInputStream(new FileInputStream(new File(dir, "META-INF/MANIFEST.MF"))); + try { + final String name = new Manifest(is).getMainAttributes().getValue(AUTOMATIC_MODULE_NAME); + return name != null ? name : normalizeModuleName(myModuleNameSearch.apply(dir)); + } + finally { + is.close(); + } + } + catch (FileNotFoundException e) { + return normalizeModuleName(myModuleNameSearch.apply(dir)); // inferring the module name from the dir + } + catch (Throwable ignored) { + } + } + return null; + } + private static final class ModuleInfo { + static final ModuleInfo EMPTY = new ModuleInfo(null, false); @Nullable final String name; @NotNull final Collection requires; + private final boolean isAutomaticExploded; - ModuleInfo(String name) { - this(name, Collections.emptyList()); + ModuleInfo(@Nullable String name, boolean isAutomaticExploded) { + this.name = name; + this.requires = Collections.emptyList(); + this.isAutomaticExploded = isAutomaticExploded; } ModuleInfo(@Nullable String name, @NotNull Collection requires) { this.name = name; this.requires = Collections.unmodifiableCollection(requires); + this.isAutomaticExploded = false; } } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/CompilationPaths.java b/jps/jps-builders/src/org/jetbrains/jps/javac/CompilationPaths.java index 4d2d9b7c7dd8..be396067026a 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/CompilationPaths.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/CompilationPaths.java @@ -16,18 +16,18 @@ public class CompilationPaths { private final Collection myPlatformClasspath; private final Collection myClasspath; private final Collection myUpgradeModulePath; - private final Collection myModulePath; + private final ModulePath myModulePath; private final Collection mySourcePath; public CompilationPaths(Collection platformClasspath, Collection classpath, Collection upgradeModulePath, - Collection modulePath, + ModulePath modulePath, Collection sourcePath) { myPlatformClasspath = constCollection(platformClasspath); myClasspath = constCollection(classpath); myUpgradeModulePath = constCollection(upgradeModulePath); - myModulePath = constCollection(modulePath); + myModulePath = modulePath; mySourcePath = constCollection(sourcePath); } @@ -51,7 +51,7 @@ public class CompilationPaths { } @NotNull - public Collection getModulePath() { + public ModulePath getModulePath() { return myModulePath; } @@ -60,66 +60,12 @@ public class CompilationPaths { return mySourcePath; } - public interface Builder { - CompilationPaths create(); - - Builder setPlatformClasspath(Collection path); - Builder setClasspath(Collection path); - Builder setUpgradeModulePath(Collection path); - Builder setModulePath(Collection path); - Builder setSourcePath(Collection path); - } - public static CompilationPaths create(@Nullable Collection platformCp, @Nullable Collection cp, @Nullable Collection upgradeModCp, - @Nullable Collection modulePath, + @NotNull ModulePath modulePath, @Nullable Collection sourcePath) { return new CompilationPaths(platformCp, cp, upgradeModCp, modulePath, sourcePath); } - public static Builder builder() { - return new Builder() { - private Collection mySourcePath; - private Collection myModulePath; - private Collection myUpgradeModulePath; - private Collection myClasspath; - private Collection myPlatformCp; - - @Override - public CompilationPaths create() { - return CompilationPaths.create(myPlatformCp, myClasspath, myUpgradeModulePath, myModulePath, mySourcePath); - } - - @Override - public Builder setPlatformClasspath(Collection path) { - myPlatformCp = path; - return this; - } - - @Override - public Builder setClasspath(Collection path) { - myClasspath = path; - return this; - } - - @Override - public Builder setUpgradeModulePath(Collection path) { - myUpgradeModulePath = path; - return this; - } - - @Override - public Builder setModulePath(Collection path) { - myModulePath = path; - return this; - } - - @Override - public Builder setSourcePath(Collection path) { - mySourcePath = path; - return this; - } - }; - } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacManager.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacManager.java index 775e29d9768a..72190b1210f0 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacManager.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacManager.java @@ -31,7 +31,7 @@ import org.jetbrains.jps.builders.java.JavaCompilingTool; import org.jetbrains.jps.cmdline.ClasspathBootstrap; import org.jetbrains.jps.incremental.GlobalContextKey; -import javax.tools.*; +import javax.tools.Diagnostic; import java.io.File; import java.net.InetAddress; import java.net.UnknownHostException; @@ -135,7 +135,7 @@ public class ExternalJavacManager extends ProcessAdapter { CanceledStatus cancelStatus) { return forkJavac( javaHome, heapSize, vmOptions, options, - CompilationPaths.create(platformCp, classpath, upgradeModulePath, modulePath, sourcePath), + CompilationPaths.create(platformCp, classpath, upgradeModulePath, ModulePath.create(modulePath), sourcePath), files, outs, diagnosticSink, outputSink, compilingTool, cancelStatus, false ).get(); } diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/Java9Test.java b/jps/jps-builders/testSrc/org/jetbrains/ether/Java9Test.java index 51616e7ec70d..80bdcf4576dc 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/Java9Test.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/Java9Test.java @@ -1,6 +1,7 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.ether; +import com.intellij.openapi.projectRoots.JavaSdkVersion; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SystemInfo; import org.jetbrains.jps.ModuleChunk; @@ -10,8 +11,10 @@ import org.jetbrains.jps.builders.CompileScopeTestBuilder; import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType; import org.jetbrains.jps.incremental.ModuleBuildTarget; import org.jetbrains.jps.incremental.java.ModulePathSplitter; +import org.jetbrains.jps.javac.ModulePath; import org.jetbrains.jps.model.JpsModuleRootModificationUtil; import org.jetbrains.jps.model.java.JpsJavaDependencyScope; +import org.jetbrains.jps.model.java.JpsJavaExtensionService; import org.jetbrains.jps.model.library.JpsLibrary; import org.jetbrains.jps.model.module.JpsModule; @@ -31,8 +34,11 @@ public class Java9Test extends IncrementalTestCase { @Override protected boolean shouldRunTest() { - if (!SystemInfo.IS_AT_LEAST_JAVA9) { - System.out.println("Test '" + getTestName(false) + "' skipped because it requires at least java 9 runtime"); + // java9 is not supported anymore and javac9 contains some problems that are already fixed in java10+ + // It is expected that for JPMS-related features javac10 or better will be used + final JavaSdkVersion sdkVersion = JavaSdkVersion.fromVersionString(SystemInfo.JAVA_VERSION); + if (sdkVersion == null || !sdkVersion.isAtLeast(JavaSdkVersion.JDK_10)) { + System.out.println("Test '" + getTestName(false) + "' skipped because it requires at least java 10 runtime"); return false; } return super.shouldRunTest(); @@ -137,17 +143,41 @@ public class Java9Test extends IncrementalTestCase { final ModulePathSplitter splitter = new ModulePathSplitter(); final Collection dependencies = ProjectPaths.getCompilationModulePath(new ModuleChunk(Collections.singleton(target)), false); - final Pair, Collection> split = splitter.splitPath(moduleInfoPath, Collections.singleton(outputDir), dependencies); - final Collection modulePath = split.first; + final Pair> split = splitter.splitPath(moduleInfoPath, Collections.singleton(outputDir), dependencies); + final ModulePath modulePath = split.first; final Collection classpath = split.second; - assertEquals(4, modulePath.size()); - assertTrue(modulePath.contains(outputDir)); - assertTrue(modulePath.contains(new File(libDir, "module_lib_1.jar"))); - assertTrue(modulePath.contains(new File(libDir, "module_lib_2.jar"))); - assertTrue(modulePath.contains(new File(libDir, "module_lib_util.jar"))); + final Collection modPath = modulePath.getPath(); + assertEquals(4, modPath.size()); + assertTrue(modPath.contains(outputDir)); + assertTrue(modPath.contains(new File(libDir, "module_lib_1.jar"))); + assertTrue(modPath.contains(new File(libDir, "module_lib_2.jar"))); + assertTrue(modPath.contains(new File(libDir, "module_lib_util.jar"))); assertEquals(1, classpath.size()); assertTrue(classpath.contains(new File(libDir, "module_lib_3.jar"))); } + + + public void testExplodedAutoModule() { + setupInitialProject(); + final Map modules = setupModules(); + assertEquals(2, modules.size()); + assertTrue(modules.containsKey("A")); + assertTrue(modules.containsKey("B")); + + doBuild(CompileScopeTestBuilder.rebuild().allModules()).assertSuccessful(); + } + + public void testExplodedAutoModuleWithManifest() { + setupInitialProject(); + final Map modules = setupModules(); + JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(myProject).addResourcePattern("*.MF"); + + assertEquals(2, modules.size()); + assertTrue(modules.containsKey("A")); + assertTrue(modules.containsKey("B")); + + doBuild(CompileScopeTestBuilder.rebuild().allModules()).assertSuccessful(); + } }