diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java index e1474f8f2e94..90de968a8be6 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java @@ -176,8 +176,8 @@ public class CompileDriver { if (explicitScopes != null) { scopes.addAll(explicitScopes); } - else if (!compileContext.isRebuild() && !CompileScopeUtil.allProjectModulesAffected(compileContext)) { - CompileScopeUtil.addScopesForModules(Arrays.asList(scope.getAffectedModules()), scope.getAffectedUnloadedModules(), scopes, forceBuild); + else if (!compileContext.isRebuild() && (!paths.isEmpty() || !CompileScopeUtil.allProjectModulesAffected(compileContext))) { + CompileScopeUtil.addScopesForSourceSets(scope.getAffectedSourceSets(), scope.getAffectedUnloadedModules(), scopes, forceBuild); } else { scopes.addAll(CmdlineProtoUtil.createAllModulesScopes(forceBuild)); diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileScopeUtil.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileScopeUtil.java index 58fcf194a5af..fa8f37af2977 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileScopeUtil.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileScopeUtil.java @@ -15,6 +15,7 @@ */ package com.intellij.compiler.impl; +import com.intellij.compiler.ModuleSourceSet; import com.intellij.openapi.compiler.CompileScope; import com.intellij.openapi.module.Module; import com.intellij.openapi.util.Key; @@ -68,6 +69,30 @@ public class CompileScopeUtil { } } + public static void addScopesForSourceSets(Collection sets, Collection unloadedModules, List scopes, boolean forceBuild) { + if (!sets.isEmpty() || !unloadedModules.isEmpty()) { + for (ModuleSourceSet set : sets) { + final BuildTargetType targetType = toTargetType(set); + assert targetType != null; + + TargetTypeBuildScope.Builder builder = TargetTypeBuildScope.newBuilder().setTypeId(targetType.getTypeId()).setForceBuild(forceBuild); + builder.addTargetId(set.getModule().getName()); + for (String unloadedModule : unloadedModules) { + builder.addTargetId(unloadedModule); + } + scopes.add(builder.build()); + } + } + } + + private static BuildTargetType toTargetType(ModuleSourceSet set) { + switch (set.getType()) { + case TEST: return JavaModuleBuildTargetType.TEST; + case PRODUCTION: return JavaModuleBuildTargetType.PRODUCTION; + default: return null; + } + } + public static List getBaseScopeForExternalBuild(@NotNull CompileScope scope) { return scope.getUserData(BASE_SCOPE_FOR_EXTERNAL_BUILD); } diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompositeScope.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompositeScope.java index 8278f5be7d46..f9e9dbc8804c 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompositeScope.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompositeScope.java @@ -19,6 +19,7 @@ */ package com.intellij.compiler.impl; +import com.intellij.compiler.ModuleSourceSet; import com.intellij.openapi.compiler.CompileScope; import com.intellij.openapi.compiler.ExportableUserDataHolderBase; import com.intellij.openapi.fileTypes.FileType; @@ -27,6 +28,7 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.SmartHashSet; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; @@ -91,6 +93,15 @@ public class CompositeScope extends ExportableUserDataHolderBase implements Comp return modules.toArray(Module.EMPTY_ARRAY); } + @Override + public Collection getAffectedSourceSets() { + Set sets = new SmartHashSet<>(); + for (CompileScope scope : myScopes) { + sets.addAll(scope.getAffectedSourceSets()); + } + return sets; + } + @NotNull @Override public Collection getAffectedUnloadedModules() { diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/OneProjectItemCompileScope.java b/java/compiler/impl/src/com/intellij/compiler/impl/OneProjectItemCompileScope.java index 267a86a2e0f3..2c830ee14eb7 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/OneProjectItemCompileScope.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/OneProjectItemCompileScope.java @@ -1,12 +1,12 @@ // 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 com.intellij.compiler.impl; +import com.intellij.compiler.ModuleSourceSet; import com.intellij.openapi.compiler.CompileScope; import com.intellij.openapi.compiler.ExportableUserDataHolderBase; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ContentIterator; import com.intellij.openapi.roots.ProjectFileIndex; @@ -17,6 +17,8 @@ import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; public class OneProjectItemCompileScope extends ExportableUserDataHolderBase implements CompileScope{ @@ -58,12 +60,27 @@ public class OneProjectItemCompileScope extends ExportableUserDataHolderBase imp @Override @NotNull public Module[] getAffectedModules() { - final Module module = ModuleUtilCore.findModuleForFile(myFile, myProject); - if (module == null) { + final Collection sets = getAffectedSourceSets(); + if (sets.isEmpty()) { LOG.error("Module is null for file " + myFile.getPresentableUrl()); return Module.EMPTY_ARRAY; } - return new Module[] {module}; + return new Module[] {sets.iterator().next().getModule()}; } + @Override + public Collection getAffectedSourceSets() { + if (myProject.isDefault()) { + return Collections.emptyList(); + } + final ProjectFileIndex index = ProjectFileIndex.getInstance(myProject); + final Module module = index.getModuleForFile(myFile); + if (module == null) { + return Collections.emptyList(); + } + return Collections.singleton(new ModuleSourceSet( + module, + index.isInTestSourceContent(myFile)? ModuleSourceSet.Type.TEST : ModuleSourceSet.Type.PRODUCTION + )); + } } diff --git a/java/compiler/openapi/src/com/intellij/openapi/compiler/CompileScope.java b/java/compiler/openapi/src/com/intellij/openapi/compiler/CompileScope.java index 9c8766e5c5cd..2a7d6d489b83 100644 --- a/java/compiler/openapi/src/com/intellij/openapi/compiler/CompileScope.java +++ b/java/compiler/openapi/src/com/intellij/openapi/compiler/CompileScope.java @@ -15,14 +15,17 @@ */ package com.intellij.openapi.compiler; +import com.intellij.compiler.ModuleSourceSet; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.module.Module; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.SmartList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Collections; +import java.util.List; /** * Interface describing the current compilation scope. @@ -67,4 +70,17 @@ public interface CompileScope extends ExportableUserDataHolder { default Collection getAffectedUnloadedModules() { return Collections.emptyList(); } + + /** + * @return similar to {getAffectedModules}, but is more precise about which kinds of source roots are affected: production and/or tests + */ + default Collection getAffectedSourceSets() { + List sets = new SmartList<>(); + for (Module module : getAffectedModules()) { + for (ModuleSourceSet.Type setType : ModuleSourceSet.Type.values()) { + sets.add(new ModuleSourceSet(module, setType)); + } + } + return sets; + } } diff --git a/java/compiler/tests/com/intellij/compiler/ModuleCompileScopeTest.java b/java/compiler/tests/com/intellij/compiler/ModuleCompileScopeTest.java index 852be9bcdd65..e42adcce7381 100644 --- a/java/compiler/tests/com/intellij/compiler/ModuleCompileScopeTest.java +++ b/java/compiler/tests/com/intellij/compiler/ModuleCompileScopeTest.java @@ -70,7 +70,8 @@ public class ModuleCompileScopeTest extends BaseCompilerTestCase { public void testForceCompileUpToDateFileAndDoNotCompileDependentTestClass() { VirtualFile a = createFile("src/A.java", "class A{ public static void foo(int param) {} }"); - VirtualFile b = createFile("testSrc/B.java", "class B { void bar() {A.foo(10);}}"); + final String bText = "class B { void bar() {A.foo(10);}}"; + VirtualFile b = createFile("testSrc/B.java", bText); Module module = addModule("a", a.getParent(), b.getParent()); make(module); assertOutput(module, fs().file("A.class"), false); @@ -87,7 +88,7 @@ public class ModuleCompileScopeTest extends BaseCompilerTestCase { deleteFile(testClassFile); make(module); assertOutput(module, fs()); - changeFile(b); // touch b + changeFile(b, bText + " "); // touch b compile(true, a); assertOutput(module, fs().file("A.class"), false); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileScopeImpl.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileScopeImpl.java index 111c83ff0a41..698fc373e113 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileScopeImpl.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileScopeImpl.java @@ -65,7 +65,7 @@ public class CompileScopeImpl extends CompileScope { @Override public boolean isWholeTargetAffected(@NotNull BuildTarget target) { - return myFiles.isEmpty() && (myTypes.contains(target.getTargetType()) || myTargets.contains(target) || isAffectedByAssociatedModule(target)); + return (myTypes.contains(target.getTargetType()) || myTargets.contains(target) || isAffectedByAssociatedModule(target)) && !myFiles.containsKey(target); } @Override