mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
incremental compilation: ensure javac always resolves dependencies within same module against sources and not classes compiled on previous steps (IDEA-108215)
This commit is contained in:
+10
@@ -0,0 +1,10 @@
|
||||
Cleaning output files:
|
||||
out/production/RecompileTwinDependencies/package1/A.class
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/RecompileTwinDependencies/package1/C.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/package2/A.java
|
||||
src/package2/C.java
|
||||
End of files
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com;
|
||||
|
||||
import package1.*;
|
||||
import package2.*;
|
||||
|
||||
public class B {
|
||||
public A get() { // resolves to "public package1.A get();" or "public package2.A get();" depending on where A is
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
package package1;
|
||||
|
||||
public class A { // resolves to "class package1.A"
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package package1;
|
||||
|
||||
import com.B;
|
||||
|
||||
public class C {
|
||||
{
|
||||
new B().get(); // resolves to invoking of "com/B.get:()Lpackage1/A;"
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package package1;
|
||||
|
||||
// Dummy class for non-empty package
|
||||
public class Dummy {
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
package package2;
|
||||
|
||||
public class A { // resolves to "class package2.A"
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package package2;
|
||||
|
||||
import com.B;
|
||||
|
||||
public class C {
|
||||
{
|
||||
new B().get(); // should be resolved to "com/B.get:()Lpackage2/A;"
|
||||
// but package2/C.java is first compiled when B.class still contains "public package1.A get();"
|
||||
// and compiler returns an error
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package package2;
|
||||
|
||||
// Dummy class for non-empty package
|
||||
public class Dummy {
|
||||
}
|
||||
@@ -935,7 +935,21 @@ public class IncProjectBuilder {
|
||||
final SourceToOutputMapping sourceToOutputStorage = context.getProjectDescriptor().dataManager.getSourceToOutputMap(target);
|
||||
final ProjectBuilderLogger logger = context.getLoggingManager().getProjectBuilderLogger();
|
||||
// actually delete outputs associated with removed paths
|
||||
for (String deletedSource : deletedPaths) {
|
||||
final Collection<String> pathsForIteration;
|
||||
if (Utils.IS_TEST_MODE) {
|
||||
// ensure predictable order in test logs
|
||||
pathsForIteration = new ArrayList<String>(deletedPaths);
|
||||
Collections.sort((List<String>)pathsForIteration, new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
return o1.compareTo(o2);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
pathsForIteration = deletedPaths;
|
||||
}
|
||||
for (String deletedSource : pathsForIteration) {
|
||||
// deleting outputs corresponding to non-existing source
|
||||
final Collection<String> outputs = sourceToOutputStorage.getOutputs(deletedSource);
|
||||
|
||||
|
||||
@@ -72,15 +72,24 @@ public class BuildFSState extends FSState {
|
||||
return super.getSourcesToRecompile(context, target);
|
||||
}
|
||||
|
||||
//public boolean isMarkedForRecompilation(BuildRootDescriptor rd, File file) {
|
||||
// final Map<BuildRootDescriptor, Set<File>> recompile = getDelta(rd.getTarget()).getSourcesToRecompile();
|
||||
// //noinspection SynchronizationOnLocalVariableOrMethodParameter
|
||||
// synchronized (recompile) {
|
||||
// final Set<File> files = recompile.get(rd);
|
||||
// return files != null && files.contains(file);
|
||||
// }
|
||||
//}
|
||||
public boolean isMarkedForRecompilation(@Nullable CompileContext context, BuildRootDescriptor rd, File file) {
|
||||
FilesDelta delta = getRoundDelta(LAST_ROUND_DELTA_KEY, context);
|
||||
if (delta == null) {
|
||||
delta = getDelta(rd.getTarget());
|
||||
}
|
||||
|
||||
final Map<BuildRootDescriptor, Set<File>> recompile = delta.getSourcesToRecompile();
|
||||
//noinspection SynchronizationOnLocalVariableOrMethodParameter
|
||||
synchronized (recompile) {
|
||||
final Set<File> files = recompile.get(rd);
|
||||
return files != null && files.contains(file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: marked file will well be visible as "dirty" only on the next compilation round!
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public boolean markDirty(@Nullable CompileContext context, File file, final BuildRootDescriptor rd, @Nullable Timestamps tsStorage, boolean saveEventStamp) throws IOException {
|
||||
final FilesDelta roundDelta = getRoundDelta(CURRENT_ROUND_DELTA_KEY, context);
|
||||
|
||||
@@ -50,14 +50,15 @@ import org.jetbrains.jps.incremental.messages.ProgressMessage;
|
||||
import org.jetbrains.jps.javac.*;
|
||||
import org.jetbrains.jps.model.JpsDummyElement;
|
||||
import org.jetbrains.jps.model.JpsProject;
|
||||
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
|
||||
import org.jetbrains.jps.model.java.JpsJavaSdkType;
|
||||
import org.jetbrains.jps.model.java.LanguageLevel;
|
||||
import org.jetbrains.jps.model.JpsSimpleElement;
|
||||
import org.jetbrains.jps.model.java.*;
|
||||
import org.jetbrains.jps.model.java.compiler.*;
|
||||
import org.jetbrains.jps.model.library.sdk.JpsSdk;
|
||||
import org.jetbrains.jps.model.module.JpsModule;
|
||||
import org.jetbrains.jps.model.module.JpsModuleType;
|
||||
import org.jetbrains.jps.model.module.JpsTypedModuleSourceRoot;
|
||||
import org.jetbrains.jps.service.JpsServiceManager;
|
||||
import org.jetbrains.jps.util.JpsPathUtil;
|
||||
|
||||
import javax.tools.*;
|
||||
import java.io.*;
|
||||
@@ -247,6 +248,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
exitCode = ExitCode.OK;
|
||||
|
||||
final Set<File> srcPath = new HashSet<File>();
|
||||
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)) {
|
||||
@@ -301,6 +303,14 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
private static void collectSourceRoots(ModuleChunk chunk, Set<File> srcPath, final JavaSourceRootType rootType) {
|
||||
for (JpsModule module : chunk.getModules()) {
|
||||
for (JpsTypedModuleSourceRoot<JpsSimpleElement<JavaSourceRootProperties>> root : module.getSourceRoots(rootType)) {
|
||||
srcPath.add(JpsPathUtil.urlToFile(root.getUrl()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean compileJava(
|
||||
final CompileContext context,
|
||||
ModuleChunk chunk,
|
||||
|
||||
@@ -40,7 +40,7 @@ public class JavacMain {
|
||||
"-d", "-classpath", "-cp", "-bootclasspath"
|
||||
));
|
||||
private static final Set<String> FILTERED_SINGLE_OPTIONS = new HashSet<String>(Arrays.<String>asList(
|
||||
/*javac options*/ "-verbose", "-proc:only", "-implicit:class", "-implicit:none",
|
||||
/*javac options*/ "-verbose", "-proc:only", "-implicit:class", "-implicit:none", "-Xprefer:newer", "-Xprefer:source",
|
||||
/*eclipse options*/"-noExit"
|
||||
));
|
||||
|
||||
@@ -211,6 +211,7 @@ public class JavacMain {
|
||||
private static Collection<String> prepareOptions(final Collection<String> options, boolean usingJavac) {
|
||||
final List<String> result = new ArrayList<String>();
|
||||
if (usingJavac) {
|
||||
result.add("-Xprefer:source");
|
||||
result.add("-implicit:class"); // the option supported by javac only
|
||||
}
|
||||
else { // is Eclipse
|
||||
|
||||
@@ -52,4 +52,8 @@ public class MarkDirtyTest extends IncrementalTestCase {
|
||||
JpsModuleRootModificationUtil.addDependency(util, lib);
|
||||
doTestBuild(1).assertSuccessful();
|
||||
}
|
||||
|
||||
public void testRecompileTwinDependencies() {
|
||||
doTest().assertSuccessful();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user