mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
support JPMS module names for exploded automatic modules (IDEA-183692)
GitOrigin-RevId: 29b82f6f8ebce48a71cd1ca74ec70532697e93a7
This commit is contained in:
committed by
intellij-monorepo-bot
parent
075c0d463a
commit
a12101438d
@@ -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<File, Set<File>> 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,
|
||||
|
||||
@@ -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<? extends JavaFileObject> 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<? extends JavaFileObject> 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<? extends FileObject> fileObjects) {
|
||||
Iterable<? extends FileObject> 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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package ppp;
|
||||
|
||||
public class Util {
|
||||
public static void perform() {
|
||||
System.out.println("Util.perform");
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
module B {
|
||||
requires A;
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package qqq;
|
||||
|
||||
import ppp.Util;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
Util.perform();
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
Automatic-Module-Name: custom.a
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package ppp;
|
||||
|
||||
public class Util {
|
||||
public static void perform() {
|
||||
System.out.println("Util.perform");
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
module B {
|
||||
requires custom.a;
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package qqq;
|
||||
|
||||
import ppp.Util;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
Util.perform();
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,7 @@ message Message {
|
||||
repeated OutputGroup output = 7;
|
||||
repeated string module_path = 8;
|
||||
repeated string upgrade_module_path = 9;
|
||||
map<string,string> module_names = 10;
|
||||
}
|
||||
|
||||
message Response {
|
||||
|
||||
@@ -142,7 +142,7 @@ public class ExternalJavacProcess {
|
||||
Collection<? extends File> files,
|
||||
Collection<? extends File> classpath,
|
||||
Collection<? extends File> platformCp,
|
||||
Collection<? extends File> modulePath,
|
||||
ModulePath modulePath,
|
||||
Collection<? extends File> upgradeModulePath,
|
||||
Collection<? extends File> sourcePath,
|
||||
Map<File, Set<File>> outs,
|
||||
@@ -237,7 +237,14 @@ public class ExternalJavacProcess {
|
||||
final List<File> cp = toFiles(request.getClasspathList());
|
||||
final List<File> platformCp = toFiles(request.getPlatformClasspathList());
|
||||
final List<File> srcPath = toFiles(request.getSourcepathList());
|
||||
final List<File> modulePath = toFiles(request.getModulePathList());
|
||||
|
||||
final ModulePath.Builder modulePathBuilder = ModulePath.newBuilder();
|
||||
final Map<String, String> namesMap = request.getModuleNamesMap();
|
||||
for (String path : request.getModulePathList()) {
|
||||
modulePathBuilder.add(namesMap.get(path), new File(path));
|
||||
}
|
||||
final ModulePath modulePath = modulePathBuilder.create();
|
||||
|
||||
final List<File> upgradeModulePath = toFiles(request.getUpgradeModulePathList());
|
||||
|
||||
final Map<File, Set<File>> outs = new HashMap<File, Set<File>>();
|
||||
|
||||
@@ -40,7 +40,7 @@ public class JavacMain {
|
||||
final Collection<? extends File> sources,
|
||||
Collection<? extends File> classpath,
|
||||
Collection<? extends File> platformClasspath,
|
||||
Collection<? extends File> modulePath,
|
||||
ModulePath modulePath,
|
||||
Collection<? extends File> upgradeModulePath,
|
||||
Collection<? extends File> sourcePath,
|
||||
final Map<File, Set<File>> 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<File>() {
|
||||
setLocation(fileManager, "ANNOTATION_PROCESSOR_MODULE_PATH", JpsJavacFileManager.filter(modulePath.getPath(), new BooleanFunction<File>() {
|
||||
@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();
|
||||
|
||||
@@ -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<? extends File> files,
|
||||
Collection<? extends File> classpath,
|
||||
Collection<? extends File> platformCp,
|
||||
Collection<? extends File> modulePath,
|
||||
ModulePath modulePath,
|
||||
Collection<? extends File> upgradeModulePath,
|
||||
Collection<? extends File> sourcePath,
|
||||
Map<File, Set<File>> 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()));
|
||||
|
||||
@@ -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);
|
||||
|
||||
/**
|
||||
* <code>map<string, string> module_names = 10;</code>
|
||||
*/
|
||||
int getModuleNamesCount();
|
||||
/**
|
||||
* <code>map<string, string> module_names = 10;</code>
|
||||
*/
|
||||
boolean containsModuleNames(
|
||||
java.lang.String key);
|
||||
/**
|
||||
* Use {@link #getModuleNamesMap()} instead.
|
||||
*/
|
||||
@java.lang.Deprecated
|
||||
java.util.Map<java.lang.String, java.lang.String>
|
||||
getModuleNames();
|
||||
/**
|
||||
* <code>map<string, string> module_names = 10;</code>
|
||||
*/
|
||||
java.util.Map<java.lang.String, java.lang.String>
|
||||
getModuleNamesMap();
|
||||
/**
|
||||
* <code>map<string, string> module_names = 10;</code>
|
||||
*/
|
||||
|
||||
java.lang.String getModuleNamesOrDefault(
|
||||
java.lang.String key,
|
||||
java.lang.String defaultValue);
|
||||
/**
|
||||
* <code>map<string, string> module_names = 10;</code>
|
||||
*/
|
||||
|
||||
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
|
||||
.<java.lang.String, java.lang.String>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<java.lang.String, java.lang.String>
|
||||
internalGetModuleNames() {
|
||||
return moduleNames_;
|
||||
}
|
||||
private com.google.protobuf.MapFieldLite<java.lang.String, java.lang.String>
|
||||
internalGetMutableModuleNames() {
|
||||
if (!moduleNames_.isMutable()) {
|
||||
moduleNames_ = moduleNames_.mutableCopy();
|
||||
}
|
||||
return moduleNames_;
|
||||
}
|
||||
|
||||
public int getModuleNamesCount() {
|
||||
return internalGetModuleNames().size();
|
||||
}
|
||||
/**
|
||||
* <code>map<string, string> module_names = 10;</code>
|
||||
*/
|
||||
|
||||
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<java.lang.String, java.lang.String> getModuleNames() {
|
||||
return getModuleNamesMap();
|
||||
}
|
||||
/**
|
||||
* <code>map<string, string> module_names = 10;</code>
|
||||
*/
|
||||
|
||||
public java.util.Map<java.lang.String, java.lang.String> getModuleNamesMap() {
|
||||
return java.util.Collections.unmodifiableMap(
|
||||
internalGetModuleNames());
|
||||
}
|
||||
/**
|
||||
* <code>map<string, string> module_names = 10;</code>
|
||||
*/
|
||||
|
||||
public java.lang.String getModuleNamesOrDefault(
|
||||
java.lang.String key,
|
||||
java.lang.String defaultValue) {
|
||||
if (key == null) { throw new java.lang.NullPointerException(); }
|
||||
java.util.Map<java.lang.String, java.lang.String> map =
|
||||
internalGetModuleNames();
|
||||
return map.containsKey(key) ? map.get(key) : defaultValue;
|
||||
}
|
||||
/**
|
||||
* <code>map<string, string> module_names = 10;</code>
|
||||
*/
|
||||
|
||||
public java.lang.String getModuleNamesOrThrow(
|
||||
java.lang.String key) {
|
||||
if (key == null) { throw new java.lang.NullPointerException(); }
|
||||
java.util.Map<java.lang.String, java.lang.String> map =
|
||||
internalGetModuleNames();
|
||||
if (!map.containsKey(key)) {
|
||||
throw new java.lang.IllegalArgumentException();
|
||||
}
|
||||
return map.get(key);
|
||||
}
|
||||
/**
|
||||
* <code>map<string, string> module_names = 10;</code>
|
||||
*/
|
||||
private java.util.Map<java.lang.String, java.lang.String>
|
||||
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<java.lang.String, java.lang.String> 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<java.lang.String, java.lang.String> 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();
|
||||
}
|
||||
/**
|
||||
* <code>map<string, string> module_names = 10;</code>
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
/**
|
||||
* <code>map<string, string> module_names = 10;</code>
|
||||
*/
|
||||
|
||||
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<java.lang.String, java.lang.String> getModuleNames() {
|
||||
return getModuleNamesMap();
|
||||
}
|
||||
/**
|
||||
* <code>map<string, string> module_names = 10;</code>
|
||||
*/
|
||||
public java.util.Map<java.lang.String, java.lang.String> getModuleNamesMap() {
|
||||
return java.util.Collections.unmodifiableMap(
|
||||
instance.getModuleNamesMap());
|
||||
}
|
||||
/**
|
||||
* <code>map<string, string> module_names = 10;</code>
|
||||
*/
|
||||
|
||||
public java.lang.String getModuleNamesOrDefault(
|
||||
java.lang.String key,
|
||||
java.lang.String defaultValue) {
|
||||
if (key == null) { throw new java.lang.NullPointerException(); }
|
||||
java.util.Map<java.lang.String, java.lang.String> map =
|
||||
instance.getModuleNamesMap();
|
||||
return map.containsKey(key) ? map.get(key) : defaultValue;
|
||||
}
|
||||
/**
|
||||
* <code>map<string, string> module_names = 10;</code>
|
||||
*/
|
||||
|
||||
public java.lang.String getModuleNamesOrThrow(
|
||||
java.lang.String key) {
|
||||
if (key == null) { throw new java.lang.NullPointerException(); }
|
||||
java.util.Map<java.lang.String, java.lang.String> map =
|
||||
instance.getModuleNamesMap();
|
||||
if (!map.containsKey(key)) {
|
||||
throw new java.lang.IllegalArgumentException();
|
||||
}
|
||||
return map.get(key);
|
||||
}
|
||||
/**
|
||||
* <code>map<string, string> module_names = 10;</code>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
/**
|
||||
* <code>map<string, string> module_names = 10;</code>
|
||||
*/
|
||||
public Builder putAllModuleNames(
|
||||
java.util.Map<java.lang.String, java.lang.String> 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) {
|
||||
|
||||
@@ -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<StandardJavaF
|
||||
return new File(s);
|
||||
}
|
||||
};
|
||||
private static final Method ourContainsMethod;
|
||||
static {
|
||||
Method method = null;
|
||||
try {
|
||||
method = JavaFileManager.class.getDeclaredMethod("contains", Location.class, FileObject.class);
|
||||
}
|
||||
catch (Throwable ignored) {
|
||||
}
|
||||
ourContainsMethod = method;
|
||||
}
|
||||
|
||||
|
||||
private Map<File, Set<File>> myOutputsMap = Collections.emptyMap();
|
||||
@Nullable
|
||||
private String myEncodingName;
|
||||
@@ -82,6 +73,12 @@ public class JpsJavacFileManager extends ForwardingJavaFileManager<StandardJavaF
|
||||
myJavacBefore9 = javacBefore9;
|
||||
mySourceTransformers = transformers;
|
||||
myContext = new Context() {
|
||||
@Nullable
|
||||
@Override
|
||||
public String getExplodedAutomaticModuleName(File pathElement) {
|
||||
return context.getExplodedAutomaticModuleName(pathElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCanceled() {
|
||||
return context.isCanceled();
|
||||
@@ -267,6 +264,9 @@ public class JpsJavacFileManager extends ForwardingJavaFileManager<StandardJavaF
|
||||
}
|
||||
|
||||
public interface Context {
|
||||
@Nullable
|
||||
String getExplodedAutomaticModuleName(File pathElement);
|
||||
|
||||
boolean isCanceled();
|
||||
|
||||
@NotNull
|
||||
@@ -333,6 +333,9 @@ public class JpsJavacFileManager extends ForwardingJavaFileManager<StandardJavaF
|
||||
@Override
|
||||
public void setLocation(Location location, Iterable<? extends File> 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<StandardJavaF
|
||||
}
|
||||
|
||||
// this method overrides corresponding API method since javac 9
|
||||
public boolean contains(Location location, FileObject fo) {
|
||||
public boolean contains(Location location, FileObject fo) throws IOException {
|
||||
if (fo instanceof JpsFileObject) {
|
||||
return location.equals(((JpsFileObject)fo).getLocation());
|
||||
}
|
||||
if (ourContainsMethod == null) {
|
||||
throw new UnsupportedOperationException("Operation is not supported for file objects " + fo.getClass().getName());
|
||||
}
|
||||
// delegate the call further
|
||||
try {
|
||||
return ((Boolean)ourContainsMethod.invoke(getStdManager(), location, fo)).booleanValue();
|
||||
}
|
||||
catch (Throwable e) {
|
||||
throw new UnsupportedOperationException(e);
|
||||
}
|
||||
return myContainsCall.callDefaultImpl(getStdManager(), "file object " + fo.getClass().getName(), location, fo);
|
||||
}
|
||||
private final DelegateCallHandler<JavaFileManager, Boolean> myContainsCall = new DelegateCallHandler<JavaFileManager, Boolean>(
|
||||
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<StandardJavaF
|
||||
myOutputsMap = outputDirToSrcRoots;
|
||||
}
|
||||
|
||||
private final DelegateCallHandler<StandardJavaFileManager, Void> mySetLocationForModuleCall = new DelegateCallHandler<StandardJavaFileManager, Void>(
|
||||
StandardJavaFileManager.class, "setLocationForModule", Location.class, String.class, Collection.class
|
||||
);
|
||||
private final DelegateCallHandler<File, Object> myToPathCall = new DelegateCallHandler<File, Object>(File.class, "toPath");
|
||||
|
||||
private void initExplodedModuleNames(final Location modulePathLocation, Iterable<? extends File> 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<T, R> {
|
||||
private final Method myMethod;
|
||||
private final String myUnsupportedMessage;
|
||||
|
||||
DelegateCallHandler(final Class<? extends T> 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 <T> Iterable<T> merge(final Iterable<? extends T> first, final Iterable<? extends T> second) {
|
||||
return new Iterable<T>() {
|
||||
@Override
|
||||
|
||||
@@ -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<? extends File> 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<? extends File> getPath() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModuleName(File pathElement) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public static ModulePath create(Collection<? extends File> path) {
|
||||
if (path.isEmpty()) {
|
||||
return EMPTY;
|
||||
}
|
||||
final Collection<File> files = Collections.unmodifiableCollection(path);
|
||||
return new ModulePath() {
|
||||
@Override
|
||||
public Collection<? extends File> getPath() {
|
||||
return files;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModuleName(File pathElement) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Builder newBuilder() {
|
||||
return new Builder() {
|
||||
private final Map<File, String> myMap = new THashMap<File, String>();
|
||||
private final Collection<File> myPath = new ArrayList<File>();
|
||||
|
||||
@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<File> files = Collections.unmodifiableCollection(myPath);
|
||||
return new ModulePath() {
|
||||
@Override
|
||||
public Collection<? extends File> getPath() {
|
||||
return files;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModuleName(File pathElement) {
|
||||
return myMap.get(pathElement);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<? extends File> classPath = originalClassPath;
|
||||
Collection<File> modulePath = Collections.emptyList();
|
||||
ModulePath modulePath = ModulePath.EMPTY;
|
||||
Collection<? extends File> upgradeModulePath = Collections.emptyList();
|
||||
|
||||
if (moduleInfoFile != null) { // has modules
|
||||
final ModulePathSplitter splitter = MODULE_PATH_SPLITTER.get(context);
|
||||
final Pair<ModulePath, Collection<File>> 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<File>, Collection<File>> 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<File, String> {
|
||||
private final TargetOutputIndex myOutsIndex;
|
||||
|
||||
ExplodedModuleNameFinder(CompileContext context) {
|
||||
final BuildTargetIndex targetIndex = context.getProjectDescriptor().getBuildTargetIndex();
|
||||
final List<ModuleBuildTarget> 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;
|
||||
|
||||
@@ -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<File, ModuleInfo> 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<File, String> 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<File, String> myModuleNameSearch;
|
||||
|
||||
public ModulePathSplitter() {
|
||||
this(DEFAULT_MODULE_NAME_SEARCH);
|
||||
}
|
||||
|
||||
public ModulePathSplitter(@NotNull Function<File, String> moduleNameSearch) {
|
||||
myModuleNameSearch = moduleNameSearch;
|
||||
}
|
||||
|
||||
public Pair<Collection<File>, Collection<File>> splitPath(File chunkModuleInfo, Set<File> chunkOutputs, Collection<File> path) {
|
||||
public Pair<ModulePath, Collection<File>> splitPath(File chunkModuleInfo, Set<File> chunkOutputs, Collection<File> 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<File> modulePath = new ArrayList<>();
|
||||
final ModulePath.Builder mpBuilder = ModulePath.newBuilder();
|
||||
final List<File> classpath = new ArrayList<>();
|
||||
|
||||
final Set<String> 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<String> collectRequired(File chunkModuleInfo, Iterable<? extends File> 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<String> 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<String> 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<String> 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<String> requires) {
|
||||
this.name = name;
|
||||
this.requires = Collections.unmodifiableCollection(requires);
|
||||
this.isAutomaticExploded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,18 +16,18 @@ public class CompilationPaths {
|
||||
private final Collection<File> myPlatformClasspath;
|
||||
private final Collection<File> myClasspath;
|
||||
private final Collection<File> myUpgradeModulePath;
|
||||
private final Collection<File> myModulePath;
|
||||
private final ModulePath myModulePath;
|
||||
private final Collection<File> mySourcePath;
|
||||
|
||||
public CompilationPaths(Collection<? extends File> platformClasspath,
|
||||
Collection<? extends File> classpath,
|
||||
Collection<? extends File> upgradeModulePath,
|
||||
Collection<? extends File> modulePath,
|
||||
ModulePath modulePath,
|
||||
Collection<? extends File> 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<File> getModulePath() {
|
||||
public ModulePath getModulePath() {
|
||||
return myModulePath;
|
||||
}
|
||||
|
||||
@@ -60,66 +60,12 @@ public class CompilationPaths {
|
||||
return mySourcePath;
|
||||
}
|
||||
|
||||
public interface Builder {
|
||||
CompilationPaths create();
|
||||
|
||||
Builder setPlatformClasspath(Collection<File> path);
|
||||
Builder setClasspath(Collection<File> path);
|
||||
Builder setUpgradeModulePath(Collection<File> path);
|
||||
Builder setModulePath(Collection<File> path);
|
||||
Builder setSourcePath(Collection<File> path);
|
||||
}
|
||||
|
||||
public static CompilationPaths create(@Nullable Collection<? extends File> platformCp,
|
||||
@Nullable Collection<? extends File> cp,
|
||||
@Nullable Collection<? extends File> upgradeModCp,
|
||||
@Nullable Collection<? extends File> modulePath,
|
||||
@NotNull ModulePath modulePath,
|
||||
@Nullable Collection<? extends File> sourcePath) {
|
||||
return new CompilationPaths(platformCp, cp, upgradeModCp, modulePath, sourcePath);
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder() {
|
||||
private Collection<File> mySourcePath;
|
||||
private Collection<File> myModulePath;
|
||||
private Collection<File> myUpgradeModulePath;
|
||||
private Collection<File> myClasspath;
|
||||
private Collection<File> myPlatformCp;
|
||||
|
||||
@Override
|
||||
public CompilationPaths create() {
|
||||
return CompilationPaths.create(myPlatformCp, myClasspath, myUpgradeModulePath, myModulePath, mySourcePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setPlatformClasspath(Collection<File> path) {
|
||||
myPlatformCp = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setClasspath(Collection<File> path) {
|
||||
myClasspath = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setUpgradeModulePath(Collection<File> path) {
|
||||
myUpgradeModulePath = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setModulePath(Collection<File> path) {
|
||||
myModulePath = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setSourcePath(Collection<File> path) {
|
||||
mySourcePath = path;
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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<File> dependencies = ProjectPaths.getCompilationModulePath(new ModuleChunk(Collections.singleton(target)), false);
|
||||
final Pair<Collection<File>, Collection<File>> split = splitter.splitPath(moduleInfoPath, Collections.singleton(outputDir), dependencies);
|
||||
final Collection<File> modulePath = split.first;
|
||||
final Pair<ModulePath, Collection<File>> split = splitter.splitPath(moduleInfoPath, Collections.singleton(outputDir), dependencies);
|
||||
final ModulePath modulePath = split.first;
|
||||
final Collection<File> 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<? extends File> 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<String, JpsModule> 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<String, JpsModule> 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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user