From 87558b71f8f639ba51191b642a4c7eb65d1a11a6 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Sat, 15 Jun 2013 18:18:03 +0400 Subject: [PATCH] compile implicitly loaded sources from temp roots only (need this for groovy mixed compilation support); otherwise for all implicitly loaded classes instrumented bytecode will be overwritten (e.g. FormsInstrumentation will suffer) --- .../markDirty/recompileTwinDependencies.log | 6 ++++ .../proto/javac_remote_proto.proto | 1 + .../jetbrains/jps/cmdline/BuildRunner.java | 2 +- .../jps/incremental/IncProjectBuilder.java | 13 +++---- .../jps/incremental/java/JavaBuilder.java | 34 +++++++++++++++++-- .../jps/javac/DiagnosticOutputConsumer.java | 2 ++ .../org/jetbrains/jps/javac/JavacMain.java | 26 +++++++++----- .../jetbrains/jps/javac/JavacProtoUtil.java | 11 ++++++ .../jetbrains/jps/javac/JavacRemoteProto.java | 9 +++++ .../org/jetbrains/jps/javac/JavacServer.java | 5 +++ .../jps/javac/JavacServerResponseHandler.java | 7 ++++ .../jps/builders/JpsBuildTestCase.java | 2 +- 12 files changed, 96 insertions(+), 22 deletions(-) diff --git a/java/java-tests/testData/compileServer/incremental/markDirty/recompileTwinDependencies.log b/java/java-tests/testData/compileServer/incremental/markDirty/recompileTwinDependencies.log index 4badc88cf13a..1c40adc4f7fb 100644 --- a/java/java-tests/testData/compileServer/incremental/markDirty/recompileTwinDependencies.log +++ b/java/java-tests/testData/compileServer/incremental/markDirty/recompileTwinDependencies.log @@ -8,3 +8,9 @@ Compiling files: src/package2/A.java src/package2/C.java End of files +Cleaning output files: +out/production/RecompileTwinDependencies/com/B.class +End of files +Compiling files: +src/com/B.java +End of files diff --git a/jps/jps-builders/proto/javac_remote_proto.proto b/jps/jps-builders/proto/javac_remote_proto.proto index c9991c036046..63d4d2ed402e 100644 --- a/jps/jps-builders/proto/javac_remote_proto.proto +++ b/jps/jps-builders/proto/javac_remote_proto.proto @@ -50,6 +50,7 @@ message Message { CLASS_DATA = 3; BUILD_COMPLETED = 4; REQUEST_ACK = 5; + SRC_FILE_LOADED = 6; } message CompileMessage { diff --git a/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildRunner.java b/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildRunner.java index 7fe98f331a26..a0e2c3428571 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildRunner.java +++ b/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildRunner.java @@ -121,7 +121,7 @@ public class BuildRunner { for (int attempt = 0; attempt < 2; attempt++) { final boolean forceClean = myForceCleanCaches && myFilePaths.isEmpty(); final CompileScope compileScope = createCompilationScope(pd, scopes, myFilePaths, forceClean, includeDependenciesToScope); - final IncProjectBuilder builder = new IncProjectBuilder(pd, BuilderRegistry.getInstance(), myBuilderParams, cs, constantSearch); + final IncProjectBuilder builder = new IncProjectBuilder(pd, BuilderRegistry.getInstance(), myBuilderParams, cs, constantSearch, Utils.IS_TEST_MODE); builder.addMessageHandler(msgHandler); try { switch (buildType) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index b9bf4e5564ec..df783e75f3cb 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -105,6 +105,7 @@ public class IncProjectBuilder { } } }; + private final boolean myIsTestMode; private volatile float myTargetsProcessed = 0.0f; private final float myTotalTargetsWork; @@ -112,7 +113,7 @@ public class IncProjectBuilder { private final List myAsyncTasks = Collections.synchronizedList(new ArrayList()); public IncProjectBuilder(ProjectDescriptor pd, BuilderRegistry builderRegistry, Map builderParams, CanceledStatus cs, - @Nullable Callbacks.ConstantAffectionResolver constantSearch) { + @Nullable Callbacks.ConstantAffectionResolver constantSearch, final boolean isTestMode) { myProjectDescriptor = pd; myBuilderRegistry = builderRegistry; myBuilderParams = builderParams; @@ -120,6 +121,7 @@ public class IncProjectBuilder { myConstantSearch = constantSearch; myTotalTargetsWork = pd.getBuildTargetIndex().getAllTargets().size(); myTotalModuleLevelBuilderCount = builderRegistry.getModuleLevelBuilderCount(); + myIsTestMode = isTestMode; } public void addMessageHandler(MessageHandler handler) { @@ -936,15 +938,10 @@ public class IncProjectBuilder { final ProjectBuilderLogger logger = context.getLoggingManager().getProjectBuilderLogger(); // actually delete outputs associated with removed paths final Collection pathsForIteration; - if (Utils.IS_TEST_MODE) { + if (myIsTestMode) { // ensure predictable order in test logs pathsForIteration = new ArrayList(deletedPaths); - Collections.sort((List)pathsForIteration, new Comparator() { - @Override - public int compare(String o1, String o2) { - return o1.compareTo(o2); - } - }); + Collections.sort((List)pathsForIteration); } else { pathsForIteration = deletedPaths; 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 d3a654a47327..c0273f993347 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 @@ -233,7 +233,6 @@ public class JavaBuilder extends ModuleLevelBuilder { final Collection platformCp = ProjectPaths.getPlatformCompilationClasspath(chunk, false/*context.isProjectRebuild()*/); // begin compilation round - final DiagnosticSink diagnosticSink = new DiagnosticSink(context); final Mappings delta = pd.dataManager.getMappings().createDelta(); final Callbacks.Backend mappingsCallback = delta.getCallback(); final OutputFilesSink outputSink = new OutputFilesSink(context, outputConsumer, mappingsCallback, chunk.getName()); @@ -248,14 +247,22 @@ public class JavaBuilder extends ModuleLevelBuilder { exitCode = ExitCode.OK; final Set srcPath = new HashSet(); + Set tempRoots = null; + collectSourceRoots(chunk, srcPath, chunk.containsTests()? JavaSourceRootType.TEST_SOURCE : JavaSourceRootType.SOURCE); final BuildRootIndex index = pd.getBuildRootIndex(); + for (ModuleBuildTarget target : chunk.getTargets()) { for (JavaSourceRootDescriptor rd : index.getTempTargetRoots(target, context)) { + if (tempRoots == null) { + tempRoots = new THashSet(FileUtil.FILE_HASHING_STRATEGY); + } srcPath.add(rd.root); + tempRoots.add(rd.root); } } - + final DiagnosticSink diagnosticSink = new DiagnosticSink(context, tempRoots == null? Collections.emptySet() : tempRoots); + final String chunkName = chunk.getName(); context.processMessage(new ProgressMessage("Parsing java... [" + chunkName + "]")); @@ -277,6 +284,13 @@ public class JavaBuilder extends ModuleLevelBuilder { } } compiledOk = compileJava(context, chunk, files, classpath, platformCp, srcPath, diagnosticSink, outputSink); + if (compiledOk) { + final Collection loadedTempFiles = diagnosticSink.getLoadedTempSources(); + if (!loadedTempFiles.isEmpty()) { + // compile all implicitly loaded sources from temporary roots + compiledOk = compileJava(context, chunk, loadedTempFiles, classpath, platformCp, tempRoots, new DiagnosticSink(context, Collections.emptySet()), outputSink); + } + } } context.checkCanceled(); @@ -782,11 +796,25 @@ public class JavaBuilder extends ModuleLevelBuilder { private class DiagnosticSink implements DiagnosticOutputConsumer { private final CompileContext myContext; + private final Set myTempRoots; private volatile int myErrorCount = 0; private volatile int myWarningCount = 0; + private final Set myLoadedTempSources = new THashSet(FileUtil.FILE_HASHING_STRATEGY); - public DiagnosticSink(CompileContext context) { + public DiagnosticSink(CompileContext context, Set tempRoots) { myContext = context; + myTempRoots = tempRoots; + } + + @Override + public void javaFileLoaded(File file) { + if (JpsPathUtil.isUnder(myTempRoots, file)) { + myLoadedTempSources.add(file); + } + } + + public Collection getLoadedTempSources() { + return myLoadedTempSources; } public void registerImports(final String className, final Collection imports, final Collection staticImports) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/DiagnosticOutputConsumer.java b/jps/jps-builders/src/org/jetbrains/jps/javac/DiagnosticOutputConsumer.java index ee4269248c14..b24a8325bb65 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/DiagnosticOutputConsumer.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/DiagnosticOutputConsumer.java @@ -16,6 +16,7 @@ package org.jetbrains.jps.javac; import javax.tools.*; +import java.io.File; import java.util.Collection; /** @@ -25,4 +26,5 @@ import java.util.Collection; public interface DiagnosticOutputConsumer extends DiagnosticListener { void outputLineAvailable(String line); void registerImports(String className, Collection imports, Collection staticImports); + void javaFileLoaded(File file); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacMain.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacMain.java index 33e04756db22..5e6c820ff79a 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacMain.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacMain.java @@ -50,7 +50,7 @@ public class JavacMain { Collection platformClasspath, Collection sourcePath, Map> outputDirToRoots, - final DiagnosticOutputConsumer outConsumer, + final DiagnosticOutputConsumer diagnosticConsumer, final OutputFileConsumer outputSink, CanceledStatus canceledStatus, boolean useEclipseCompiler) { JavaCompiler compiler = null; @@ -60,7 +60,7 @@ public class JavacMain { break; } if (compiler == null) { - outConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, "Eclipse Batch Compiler was not found in classpath")); + diagnosticConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, "Eclipse Batch Compiler was not found in classpath")); return false; } } @@ -69,7 +69,7 @@ public class JavacMain { if (compiler == null) { compiler = ToolProvider.getSystemJavaCompiler(); if (compiler == null) { - outConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, "System Java Compiler was not found in classpath")); + diagnosticConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, "System Java Compiler was not found in classpath")); return false; } nowUsingJavac = true; @@ -83,8 +83,16 @@ public class JavacMain { } final List transformers = getSourceTransformers(); + transformers.add(new JavaSourceTransformer() { + // dummy transformer to notify about sources that were accessed during compilation + @Override + public CharSequence transform(File sourceFile, CharSequence content) throws TransformError { + diagnosticConsumer.javaFileLoaded(sourceFile); + return content; + } + }); - final JavacFileManager fileManager = new JavacFileManager(new ContextImpl(compiler, outConsumer, outputSink, canceledStatus, nowUsingJavac), transformers); + final JavacFileManager fileManager = new JavacFileManager(new ContextImpl(compiler, diagnosticConsumer, outputSink, canceledStatus, nowUsingJavac), transformers); fileManager.handleOption("-bootclasspath", Collections.singleton("").iterator()); // this will clear cached stuff fileManager.handleOption("-extdirs", Collections.singleton("").iterator()); // this will clear cached stuff @@ -136,7 +144,7 @@ public class JavacMain { final LineOutputWriter out = new LineOutputWriter() { protected void lineAvailable(String line) { if (nowUsingJavac) { - outConsumer.outputLineAvailable(line); + diagnosticConsumer.outputLineAvailable(line); } else { // todo: filter too verbose eclipse output? @@ -154,7 +162,7 @@ public class JavacMain { } final JavaCompiler.CompilationTask task = compiler.getTask( - out, fileManager, outConsumer, _options, null, fileManager.getJavaFileObjectsFromFiles(sources) + out, fileManager, diagnosticConsumer, _options, null, fileManager.getJavaFileObjectsFromFiles(sources) ); //if (!IS_VM_6_VERSION) { //todo! @@ -166,10 +174,10 @@ public class JavacMain { return task.call(); } catch(IllegalArgumentException e) { - outConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, e.getMessage())); + diagnosticConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, e.getMessage())); } catch (CompilationCanceledException ignored) { - outConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.OTHER, "Compilation was canceled")); + diagnosticConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.OTHER, "Compilation was canceled")); } finally { fileManager.close(); @@ -212,7 +220,7 @@ public class JavacMain { final List result = new ArrayList(); if (usingJavac) { result.add("-Xprefer:source"); - result.add("-implicit:class"); // the option supported by javac only + result.add("-implicit:none"); // the option supported by javac only } else { // is Eclipse result.add("-noExit"); diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacProtoUtil.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacProtoUtil.java index 23d0756b8274..7feb5b896401 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacProtoUtil.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacProtoUtil.java @@ -101,6 +101,17 @@ public class JavacProtoUtil { return builder.build(); } + public static JavacRemoteProto.Message.Response createSourceFileLoadedResponse(File srcFile) { + + final JavacRemoteProto.Message.Response.OutputObject outObjMsg = JavacRemoteProto.Message.Response.OutputObject.newBuilder() + .setKind(convertKind(JavaFileObject.Kind.SOURCE)).setFilePath(FileUtil.toSystemIndependentName(srcFile.getPath())).build(); + + final JavacRemoteProto.Message.Response.Builder builder = JavacRemoteProto.Message.Response.newBuilder(); + builder.setResponseType(JavacRemoteProto.Message.Response.Type.SRC_FILE_LOADED).setOutputObject(outObjMsg); + + return builder.build(); + } + public static JavacRemoteProto.Message.Response createClassDataResponse(String className, Collection imports, Collection staticImports) { final JavacRemoteProto.Message.Response.ClassData.Builder msgBuilder = JavacRemoteProto.Message.Response.ClassData.newBuilder(); msgBuilder.setClassName(className); diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacRemoteProto.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacRemoteProto.java index 87317f2758a6..e16704d6a629 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacRemoteProto.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacRemoteProto.java @@ -3694,6 +3694,10 @@ public final class JavacRemoteProto { * REQUEST_ACK = 5; */ REQUEST_ACK(4, 5), + /** + * SRC_FILE_LOADED = 6; + */ + SRC_FILE_LOADED(5, 6), ; /** @@ -3716,6 +3720,10 @@ public final class JavacRemoteProto { * REQUEST_ACK = 5; */ public static final int REQUEST_ACK_VALUE = 5; + /** + * SRC_FILE_LOADED = 6; + */ + public static final int SRC_FILE_LOADED_VALUE = 6; public final int getNumber() { return value; } @@ -3727,6 +3735,7 @@ public final class JavacRemoteProto { case 3: return CLASS_DATA; case 4: return BUILD_COMPLETED; case 5: return REQUEST_ACK; + case 6: return SRC_FILE_LOADED; default: return null; } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java index 359e151fd333..76a6fe9b46d5 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java @@ -127,6 +127,11 @@ public class JavacServer { Map> outs, final CanceledStatus canceledStatus) { final DiagnosticOutputConsumer diagnostic = new DiagnosticOutputConsumer() { + @Override + public void javaFileLoaded(File file) { + Channels.write(ctx.getChannel(), JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createSourceFileLoadedResponse(file))); + } + public void outputLineAvailable(String line) { Channels.write(ctx.getChannel(), JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createStdOutputResponse(line))); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerResponseHandler.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerResponseHandler.java index a9d2173f29f1..6f06bcae29b6 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerResponseHandler.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerResponseHandler.java @@ -99,6 +99,13 @@ public class JavacServerResponseHandler implements ProtobufResponseHandler{ myOutputSink.save(fileObject); return false; } + + if (responseType == JavacRemoteProto.Message.Response.Type.SRC_FILE_LOADED) { + final JavacRemoteProto.Message.Response.OutputObject outputObject = response.getOutputObject(); + final File file = new File(outputObject.getFilePath()); + myDiagnosticSink.javaFileLoaded(file); + return false; + } if (responseType == JavacRemoteProto.Message.Response.Type.CLASS_DATA) { final JavacRemoteProto.Message.Response.ClassData data = response.getClassData(); diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java index 5e353c9315c8..6241b04e84d2 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java @@ -290,7 +290,7 @@ public abstract class JpsBuildTestCase extends UsefulTestCase { } protected BuildResult doBuild(final ProjectDescriptor descriptor, CompileScopeTestBuilder scopeBuilder) { - IncProjectBuilder builder = new IncProjectBuilder(descriptor, BuilderRegistry.getInstance(), myBuildParams, CanceledStatus.NULL, null); + IncProjectBuilder builder = new IncProjectBuilder(descriptor, BuilderRegistry.getInstance(), myBuildParams, CanceledStatus.NULL, null, true); BuildResult result = new BuildResult(); builder.addMessageHandler(result); try {