diff --git a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceImpl.java b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceImpl.java index 7d6fa3c950d8..18c91aa357c5 100644 --- a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceImpl.java @@ -68,7 +68,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple private final static Logger LOG = Logger.getInstance(CompilerReferenceServiceImpl.class); private final Set myFileTypes; - private final DirtyModulesHolder myDirtyModulesHolder; + private final DirtyScopeHolder myDirtyScopeHolder; private final ProjectFileIndex myProjectFileIndex; private final LongAdder myCompilationCount = new LongAdder(); private final ReentrantReadWriteLock myLock = new ReentrantReadWriteLock(); @@ -82,7 +82,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple myProjectFileIndex = ProjectRootManager.getInstance(project).getFileIndex(); myFileTypes = Stream.of(LanguageLightRefAdapter.INSTANCES).flatMap(a -> a.getFileTypes().stream()).collect(Collectors.toSet()); - myDirtyModulesHolder = new DirtyModulesHolder(this, fileDocumentManager, psiDocumentManager); + myDirtyScopeHolder = new DirtyScopeHolder(this, fileDocumentManager, psiDocumentManager); } @Override @@ -91,7 +91,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple myProject.getMessageBus().connect(myProject).subscribe(BuildManagerListener.TOPIC, new BuildManagerListener() { @Override public void buildStarted(Project project, UUID sessionId, boolean isAutomake) { - myDirtyModulesHolder.compilerActivityStarted(); + myDirtyScopeHolder.compilerActivityStarted(); closeReaderIfNeed(); } }); @@ -127,9 +127,9 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple modulesWithErrors = Collections.emptySet(); } if (modulesWithErrors.contains(null) /*unknown error location*/) { - myDirtyModulesHolder.compilerActivityFinished(Module.EMPTY_ARRAY, compilationModules); + myDirtyScopeHolder.compilerActivityFinished(Module.EMPTY_ARRAY, compilationModules); } else { - myDirtyModulesHolder.compilerActivityFinished(compilationModules, modulesWithErrors.toArray(Module.EMPTY_ARRAY)); + myDirtyScopeHolder.compilerActivityFinished(compilationModules, modulesWithErrors.toArray(Module.EMPTY_ARRAY)); } myCompilationCount.increment(); @@ -139,7 +139,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple } }); - myDirtyModulesHolder.installVFSListener(); + myDirtyScopeHolder.installVFSListener(); if (!ApplicationManager.getApplication().isUnitTestMode()) { ApplicationManager.getApplication().executeOnPooledThread(() -> { @@ -152,12 +152,12 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple }); if (modules == null) return; if (isUpToDate) { - myDirtyModulesHolder.compilerActivityFinished(modules, Module.EMPTY_ARRAY); + myDirtyScopeHolder.compilerActivityFinished(modules, Module.EMPTY_ARRAY); myCompilationCount.increment(); openReaderIfNeed(); } else { - myDirtyModulesHolder.compilerActivityFinished(Module.EMPTY_ARRAY, modules); + myDirtyScopeHolder.compilerActivityFinished(Module.EMPTY_ARRAY, modules); } }); }); @@ -233,7 +233,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple }); if (candidatesPerFile == null) return null; - GlobalSearchScope dirtyScope = myDirtyModulesHolder.getDirtyScope(); + GlobalSearchScope dirtyScope = myDirtyScopeHolder.getDirtyScope(); if (ElementPlace.LIB == ReadAction.compute(() -> ElementPlace.get(aClass.getContainingFile().getVirtualFile(), myProjectFileIndex))) { dirtyScope = dirtyScope.union(LibraryScopeCache.getInstance(myProject).getLibrariesOnlyScope()); } @@ -270,7 +270,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple try { if (myReader == null) return null; try { - return myReader.getDirectInheritors(searchElement, useScope, myDirtyModulesHolder.getDirtyScope(), searchFileType, searchType); + return myReader.getDirectInheritors(searchElement, useScope, myDirtyScopeHolder.getDirtyScope(), searchFileType, searchType); } catch (StorageException e) { throw new RuntimeException(e); @@ -285,7 +285,8 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple TIntHashSet referentFileIds = getReferentFileIds(element); if (referentFileIds == null) return null; - return getScopeRestrictedByFileTypes(new ScopeWithoutReferencesOnCompilation(referentFileIds, myProjectFileIndex).intersectWith(notScope(myDirtyModulesHolder.getDirtyScope())), + return getScopeRestrictedByFileTypes(new ScopeWithoutReferencesOnCompilation(referentFileIds, myProjectFileIndex).intersectWith(notScope( + myDirtyScopeHolder.getDirtyScope())), myFileTypes.toArray(new FileType[myFileTypes.size()])); } @@ -323,7 +324,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple VirtualFile file = PsiUtilCore.getVirtualFile(psiElement); if (file == null) return null; ElementPlace place = ElementPlace.get(file, myProjectFileIndex); - if (place == null || (place == ElementPlace.SRC && myDirtyModulesHolder.contains(file))) { + if (place == null || (place == ElementPlace.SRC && myDirtyScopeHolder.contains(file))) { return null; } final LanguageLightRefAdapter adapter = findAdapterForFileType(file.getFileType()); @@ -500,7 +501,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple @TestOnly @NotNull - public DirtyModulesHolder getDirtyModulesHolder() { - return myDirtyModulesHolder; + public DirtyScopeHolder getDirtyScopeHolder() { + return myDirtyScopeHolder; } } diff --git a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/DirtyModulesHolder.java b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/DirtyScopeHolder.java similarity index 86% rename from java/compiler/impl/src/com/intellij/compiler/backwardRefs/DirtyModulesHolder.java rename to java/compiler/impl/src/com/intellij/compiler/backwardRefs/DirtyScopeHolder.java index f9c1fb95c3a7..9b87cebdf2b8 100644 --- a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/DirtyModulesHolder.java +++ b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/DirtyScopeHolder.java @@ -37,7 +37,7 @@ import org.jetbrains.annotations.TestOnly; import java.util.Collections; import java.util.Set; -public class DirtyModulesHolder extends UserDataHolderBase { +public class DirtyScopeHolder extends UserDataHolderBase { private final CompilerReferenceServiceImpl myService; private final FileDocumentManager myFileDocManager; private final PsiDocumentManager myPsiDocManager; @@ -46,10 +46,11 @@ public class DirtyModulesHolder extends UserDataHolderBase { private final Object myLock = new Object(); private boolean myCompilationPhase; + private volatile GlobalSearchScope myExcludedFilesScope; - public DirtyModulesHolder(@NotNull CompilerReferenceServiceImpl service, - FileDocumentManager fileDocumentManager, - PsiDocumentManager psiDocumentManager){ + public DirtyScopeHolder(@NotNull CompilerReferenceServiceImpl service, + FileDocumentManager fileDocumentManager, + PsiDocumentManager psiDocumentManager){ myService = service; myFileDocManager = fileDocumentManager; myPsiDocManager = psiDocumentManager; @@ -69,6 +70,7 @@ public class DirtyModulesHolder extends UserDataHolderBase { Collections.addAll(myVFSChangedModules, markAsDirty); myVFSChangedModules.addAll(myChangedModulesDuringCompilation); myChangedModulesDuringCompilation.clear(); + myExcludedFilesScope = ExcludedFromCompileFilesUtil.getExcludedFilesScope(myService.getProject(), myService.getFileTypes()); } } @@ -81,13 +83,18 @@ public class DirtyModulesHolder extends UserDataHolderBase { return ReadAction.compute(() -> { if (project.isDisposed()) throw new ProcessCanceledException(); return CachedValuesManager.getManager(project).getCachedValue(this, () -> - CachedValueProvider.Result.create(calculateDirtyModules(), PsiModificationTracker.MODIFICATION_COUNT, VirtualFileManager.getInstance(), myService)); + CachedValueProvider.Result.create(calculateDirtyScope(), PsiModificationTracker.MODIFICATION_COUNT, VirtualFileManager.getInstance(), myService)); }); } } - private GlobalSearchScope calculateDirtyModules() { - return getAllDirtyModules().stream().map(Module::getModuleWithDependentsScope).reduce(GlobalSearchScope.EMPTY_SCOPE, (s1, s2) -> s1.union(s2)); + private GlobalSearchScope calculateDirtyScope() { + final GlobalSearchScope dirtyModuleScope = getAllDirtyModules() + .stream() + .map(Module::getModuleWithDependentsScope) + .reduce(GlobalSearchScope.EMPTY_SCOPE, (s1, s2) -> s1.union(s2)); + + return dirtyModuleScope.union(myExcludedFilesScope); } @NotNull diff --git a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/ExcludedFromCompileFilesUtil.java b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/ExcludedFromCompileFilesUtil.java new file mode 100644 index 000000000000..bb0ba5a3abe8 --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/ExcludedFromCompileFilesUtil.java @@ -0,0 +1,63 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.compiler.backwardRefs; + +import com.intellij.compiler.CompilerConfiguration; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VfsUtilCore; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileWithId; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class ExcludedFromCompileFilesUtil { + static GlobalSearchScope getExcludedFilesScope(@NotNull Project project, @NotNull Set fileTypes) { + final Collection excludedFiles = Stream + .of(CompilerConfiguration.getInstance(project).getExcludedEntriesConfiguration().getExcludeEntryDescriptions()) + .flatMap(description -> { + final VirtualFile file = description.getVirtualFile(); + if (file == null) return Stream.empty(); + if (description.isFile()) { + return Stream.of(file); + } + else if (description.isIncludeSubdirectories()) { + return iterateChildrenRecursively(file); + } + else { + return Stream.of(file.getChildren()); + } + }) + .filter(f -> !f.isDirectory() && f instanceof VirtualFileWithId && fileTypes.contains(f.getFileType())) + .collect(Collectors.toList()); + + return GlobalSearchScope.filesWithoutLibrariesScope(project, excludedFiles); + } + + private static Stream iterateChildrenRecursively(VirtualFile file) { + final Stream.Builder builder = Stream.builder(); + VfsUtilCore.iterateChildrenRecursively(file, null, f -> { + builder.accept(f); + return true; + }); + return builder.build(); + } +} diff --git a/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithExcludedFromCompilationDirectory/Foo.java b/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithExcludedFromCompilationDirectory/Foo.java new file mode 100644 index 000000000000..90b22e24b429 --- /dev/null +++ b/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithExcludedFromCompilationDirectory/Foo.java @@ -0,0 +1,5 @@ +public class Foo { + void m() { + Runnable r = () -> {}; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithExcludedFromCompilationDirectory/excluded/A.java b/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithExcludedFromCompilationDirectory/excluded/A.java new file mode 100644 index 000000000000..3b130e8f8620 --- /dev/null +++ b/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithExcludedFromCompilationDirectory/excluded/A.java @@ -0,0 +1,5 @@ +public class A { + void m() { + Runnable r = () -> {}; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithExcludedFromCompilationDirectory/excluded/child/ShouldFindHere.java b/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithExcludedFromCompilationDirectory/excluded/child/ShouldFindHere.java new file mode 100644 index 000000000000..292c1f0a1030 --- /dev/null +++ b/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithExcludedFromCompilationDirectory/excluded/child/ShouldFindHere.java @@ -0,0 +1,5 @@ +public class ShouldFindHere { + void m() { + Runnable r = () -> {}; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithExcludedFromCompilationFile/Bar.java b/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithExcludedFromCompilationFile/Bar.java new file mode 100644 index 000000000000..04ccbcee51f7 --- /dev/null +++ b/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithExcludedFromCompilationFile/Bar.java @@ -0,0 +1,5 @@ +public class Bar { + void m() { + Runnable r = () -> {}; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithExcludedFromCompilationFile/Foo.java b/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithExcludedFromCompilationFile/Foo.java new file mode 100644 index 000000000000..90b22e24b429 --- /dev/null +++ b/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithExcludedFromCompilationFile/Foo.java @@ -0,0 +1,5 @@ +public class Foo { + void m() { + Runnable r = () -> {}; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithRecursivelyExcludedFromCompilationDirectory/Foo.java b/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithRecursivelyExcludedFromCompilationDirectory/Foo.java new file mode 100644 index 000000000000..90b22e24b429 --- /dev/null +++ b/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithRecursivelyExcludedFromCompilationDirectory/Foo.java @@ -0,0 +1,5 @@ +public class Foo { + void m() { + Runnable r = () -> {}; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithRecursivelyExcludedFromCompilationDirectory/excluded/child/ShouldFindHere.java b/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithRecursivelyExcludedFromCompilationDirectory/excluded/child/ShouldFindHere.java new file mode 100644 index 000000000000..292c1f0a1030 --- /dev/null +++ b/java/java-tests/testData/compiler/compilerReferenceFindUsages/testFindUsagesWithRecursivelyExcludedFromCompilationDirectory/excluded/child/ShouldFindHere.java @@ -0,0 +1,5 @@ +public class ShouldFindHere { + void m() { + Runnable r = () -> {}; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesFindUsagesTest.java b/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesFindUsagesTest.java index 46b1776dd016..1da95f09c42b 100644 --- a/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesFindUsagesTest.java +++ b/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesFindUsagesTest.java @@ -18,12 +18,24 @@ package com.intellij.compiler; import com.intellij.JavaTestUtil; import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase; import com.intellij.lang.injection.InjectedLanguageManager; +import com.intellij.openapi.compiler.options.ExcludeEntryDescription; +import com.intellij.openapi.compiler.options.ExcludesConfiguration; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.LanguageLevelProjectExtension; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.injected.MyTestInjector; +import com.intellij.psi.search.searches.FunctionalExpressionSearch; import com.intellij.psi.search.searches.MethodReferencesSearch; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.testFramework.CompilerTester; +import com.intellij.testFramework.IdeaTestUtil; import com.intellij.testFramework.SkipSlowTestLocally; +import com.intellij.util.Consumer; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; @SkipSlowTestLocally public class CompilerReferencesFindUsagesTest extends DaemonAnalyzerTestCase { @@ -37,6 +49,7 @@ public class CompilerReferencesFindUsagesTest extends DaemonAnalyzerTestCase { CompilerReferenceService.IS_ENABLED_KEY.setValue(true); super.setUp(); myCompilerTester = new CompilerTester(myModule); + LanguageLevelProjectExtension.getInstance(myProject).setLanguageLevel(LanguageLevel.JDK_1_8); } @Override @@ -51,10 +64,16 @@ public class CompilerReferencesFindUsagesTest extends DaemonAnalyzerTestCase { } } + @Override protected String getTestDataPath() { return JavaTestUtil.getJavaTestDataPath() + "/compiler/compilerReferenceFindUsages/"; } + @Override + protected Sdk getTestProjectJdk() { + return IdeaTestUtil.getMockJdk18(); + } + public void testMethodUsageOnGetter() throws Exception { configureByFiles(getName(), getName() + "/Foo.java", getName() + "/FooFactory.java", getName() + "/Bar.java"); PsiMethod methodToSearch = findClass("Foo").findMethodsByName("someMethod", false)[0]; @@ -117,4 +136,40 @@ public class CompilerReferencesFindUsagesTest extends DaemonAnalyzerTestCase { PsiReference reference = assertOneElement(ReferencesSearch.search(classForSearch).findAll()); assertTrue(InjectedLanguageManager.getInstance(getProject()).isInjectedFragment(reference.getElement().getContainingFile())); } + + public void testFindUsagesWithExcludedFromCompilationDirectory() { + doTestRunnableFindUsagesWithExcludesConfiguration(configuration -> { + final VirtualFile dirToExclude = findClass("A").getContainingFile().getVirtualFile().getParent(); + configuration.addExcludeEntryDescription(new ExcludeEntryDescription(dirToExclude, false, false, myProject)); + }, 3, "Foo.java", "excluded/A.java", "excluded/child/ShouldFindHere.java"); + } + + public void testFindUsagesWithRecursivelyExcludedFromCompilationDirectory() { + doTestRunnableFindUsagesWithExcludesConfiguration(configuration -> { + final VirtualFile dirToExclude = findClass("ShouldFindHere").getContainingFile().getVirtualFile().getParent().getParent(); + configuration.addExcludeEntryDescription(new ExcludeEntryDescription(dirToExclude, true, false, myProject)); + }, 2, "Foo.java", "excluded/child/ShouldFindHere.java"); + } + + public void testFindUsagesWithExcludedFromCompilationFile() { + doTestRunnableFindUsagesWithExcludesConfiguration(configuration -> { + final VirtualFile dirToExclude = findClass("Foo").getContainingFile().getVirtualFile(); + configuration.addExcludeEntryDescription(new ExcludeEntryDescription(dirToExclude, false, true, myProject)); + }, 2, "Foo.java", "Bar.java"); + } + + private void doTestRunnableFindUsagesWithExcludesConfiguration(@NotNull Consumer excludesConfigurationPatcher, + int expectedUsagesCount, + String... testFiles) { + final ExcludesConfiguration excludesConfiguration = CompilerConfiguration.getInstance(myProject).getExcludedEntriesConfiguration(); + try { + configureByFiles(getName(), Arrays.stream(testFiles).map(f -> getName() + "/" + f).toArray(String[]::new)); + excludesConfigurationPatcher.consume(excludesConfiguration); + //assertSize(expectedUsagesCount, FunctionalExpressionSearch.search(myJavaFacade.findClass(CommonClassNames.JAVA_LANG_RUNNABLE)).findAll()); + myCompilerTester.rebuild(); + assertSize(expectedUsagesCount, FunctionalExpressionSearch.search(myJavaFacade.findClass(CommonClassNames.JAVA_LANG_RUNNABLE)).findAll()); + } finally { + excludesConfiguration.removeAllExcludeEntryDescriptions(); + } + } } diff --git a/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesMultiModuleTest.kt b/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesMultiModuleTest.kt index 996389340c20..302db5470f4d 100644 --- a/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesMultiModuleTest.kt +++ b/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesMultiModuleTest.kt @@ -61,6 +61,6 @@ class CompilerReferencesMultiModuleTest : CompilerReferencesTestBase() { private fun dirtyModules() = (CompilerReferenceService.getInstance(project) as CompilerReferenceServiceImpl) - .dirtyModulesHolder + .dirtyScopeHolder .allDirtyModulesForTest }