From d2faad61ecdcfc9b88bf4fbd61509823a1066c7c Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Thu, 3 Nov 2016 13:44:39 +0300 Subject: [PATCH] javac ast indices: add scope invalidation multi-module test case --- .../CompilerReferenceServiceImpl.java | 38 ++++++----- .../backwardRefs/DirtyModulesHolder.java | 18 ++++- .../completion/AbstractCompilerAwareTest.java | 16 ++++- .../MethodChainsCompletionTest.java | 1 + .../CompilerReferencesMultiModuleTest.kt | 66 +++++++++++++++++++ .../compiler/CompilerReferencesTest.java | 6 ++ .../compiler/CompilerReferencesTestBase.java | 2 +- 7 files changed, 126 insertions(+), 21 deletions(-) create mode 100644 java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesMultiModuleTest.kt 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 625a8eefd9dd..8a5095086a08 100644 --- a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceImpl.java @@ -327,22 +327,6 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple } } - @TestOnly - @Nullable - public Set getReferentFiles(@NotNull PsiElement element) { - FileBasedIndex fileIndex = FileBasedIndex.getInstance(); - final TIntHashSet ids = getReferentFileIds(element); - if (ids == null) return null; - Set fileSet = new THashSet<>(); - ids.forEach(id -> { - final VirtualFile vFile = fileIndex.findFileById(myProject, id); - assert vFile != null; - fileSet.add(vFile); - return true; - }); - return fileSet; - } - ProjectFileIndex getFileIndex() { return myProjectFileIndex; } @@ -450,4 +434,26 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple return 31 * mySearchType.hashCode() + mySearchFileType.hashCode(); } } + + @TestOnly + @Nullable + public Set getReferentFiles(@NotNull PsiElement element) { + FileBasedIndex fileIndex = FileBasedIndex.getInstance(); + final TIntHashSet ids = getReferentFileIds(element); + if (ids == null) return null; + Set fileSet = new THashSet<>(); + ids.forEach(id -> { + final VirtualFile vFile = fileIndex.findFileById(myProject, id); + assert vFile != null; + fileSet.add(vFile); + return true; + }); + return fileSet; + } + + @TestOnly + @NotNull + public DirtyModulesHolder getDirtyModulesHolder() { + return myDirtyModulesHolder; + } } diff --git a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/DirtyModulesHolder.java b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/DirtyModulesHolder.java index 6e2a801d746e..85ee4332c3bd 100644 --- a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/DirtyModulesHolder.java +++ b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/DirtyModulesHolder.java @@ -31,11 +31,12 @@ import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.TestOnly; import java.util.Collections; import java.util.Set; -class DirtyModulesHolder extends UserDataHolderBase { +public class DirtyModulesHolder extends UserDataHolderBase { private final CompilerReferenceServiceImpl myService; private final FileDocumentManager myFileDocManager; private final PsiDocumentManager myPsiDocManager; @@ -82,6 +83,11 @@ class DirtyModulesHolder extends UserDataHolderBase { } private GlobalSearchScope calculateDirtyModules() { + return getAllDirtyModules().stream().map(Module::getModuleWithDependentsScope).reduce(GlobalSearchScope.EMPTY_SCOPE, (s1, s2) -> s1.union(s2)); + } + + @NotNull + private Set getAllDirtyModules() { final Set dirtyModules = new THashSet<>(myVFSChangedModules); for (Document document : myFileDocManager.getUnsavedDocuments()) { final Module m = getModuleForSourceContentFile(myFileDocManager.getFile(document)); @@ -91,7 +97,7 @@ class DirtyModulesHolder extends UserDataHolderBase { final Module m = getModuleForSourceContentFile(ObjectUtils.notNull(myPsiDocManager.getPsiFile(document)).getVirtualFile()); if (m != null) dirtyModules.add(m); } - return dirtyModules.stream().map(Module::getModuleWithDependentsScope).reduce(GlobalSearchScope.EMPTY_SCOPE, (s1, s2) -> s1.union(s2)); + return dirtyModules; } boolean contains(VirtualFile file) { @@ -162,4 +168,12 @@ class DirtyModulesHolder extends UserDataHolderBase { } return null; } + + @TestOnly + @NotNull + public Set getAllDirtyModulesForTest() { + synchronized (myLock) { + return getAllDirtyModules(); + } + } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/AbstractCompilerAwareTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/AbstractCompilerAwareTest.java index 6fbfa5224a0c..440fd38186fa 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/AbstractCompilerAwareTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/AbstractCompilerAwareTest.java @@ -17,9 +17,11 @@ package com.intellij.codeInsight.completion; import com.intellij.openapi.compiler.CompilerMessage; import com.intellij.openapi.compiler.CompilerMessageCategory; +import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.util.io.FileUtil; import com.intellij.testFramework.CompilerTester; import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; +import com.intellij.util.containers.ContainerUtil; import java.io.File; import java.io.IOException; @@ -33,13 +35,23 @@ public abstract class AbstractCompilerAwareTest extends JavaCodeInsightFixtureTe @Override protected void setUp() throws Exception { super.setUp(); - myCompilerTester = new CompilerTester(myModule); + } + + protected void installCompiler() { + try { + myCompilerTester = new CompilerTester(getProject(), ContainerUtil.list(ModuleManager.getInstance(getProject()).getModules())); + } + catch (Exception e) { + fail(e.getMessage()); + } } @Override protected void tearDown() throws Exception { try { - myCompilerTester.tearDown(); + if (myCompilerTester != null) { + myCompilerTester.tearDown(); + } } finally { myCompilerTester = null; diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/MethodChainsCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/MethodChainsCompletionTest.java index abd9af52ce38..683f06a1d9cc 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/MethodChainsCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/MethodChainsCompletionTest.java @@ -41,6 +41,7 @@ public class MethodChainsCompletionTest extends AbstractCompilerAwareTest { @Override protected void setUp() throws Exception { super.setUp(); + installCompiler(); ClassFilesIndexFeature.METHOD_CHAINS_COMPLETION.enable(); } diff --git a/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesMultiModuleTest.kt b/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesMultiModuleTest.kt new file mode 100644 index 000000000000..996389340c20 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesMultiModuleTest.kt @@ -0,0 +1,66 @@ +/* + * 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 + +import com.intellij.compiler.backwardRefs.CompilerReferenceServiceImpl +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.module.JavaModuleType +import com.intellij.openapi.module.Module +import com.intellij.openapi.roots.ModuleRootModificationUtil +import com.intellij.testFramework.PsiTestUtil + +class CompilerReferencesMultiModuleTest : CompilerReferencesTestBase() { + private var moduleA: Module? = null + private var moduleB: Module? = null + + override fun setUp() { + super.setUp() + addTwoModules() + installCompiler() + } + + fun testNoChanges() { + myFixture.addFileToProject("BaseClass.java", "public interface BaseClass{}") + myFixture.addFileToProject("A/ClassA.java", "public class ClassA implements BaseClass{}") + myFixture.addFileToProject("B/ClassB.java", "public class ClassB implements BaseClass{}") + rebuildProject() + assertEmpty(dirtyModules()) + } + + fun testLeafModuleTyping() { + myFixture.addFileToProject("BaseClass.java", "public interface BaseClass{}") + val classA = myFixture.addFileToProject("A/ClassA.java", "public class ClassA implements BaseClass{}") + myFixture.addFileToProject("B/ClassB.java", "public class ClassB implements BaseClass{}") + rebuildProject() + myFixture.openFileInEditor(classA.virtualFile) + myFixture.type("/*typing in module A*/") + assertEquals("A", assertOneElement(dirtyModules()).name) + FileDocumentManager.getInstance().saveAllDocuments() + assertEquals("A", assertOneElement(dirtyModules()).name) + } + + private fun addTwoModules() { + moduleA = PsiTestUtil.addModule(project, JavaModuleType.getModuleType(), "A", myFixture.tempDirFixture.findOrCreateDir("A")) + moduleB = PsiTestUtil.addModule(project, JavaModuleType.getModuleType(), "B", myFixture.tempDirFixture.findOrCreateDir("B")) + ModuleRootModificationUtil.addDependency(moduleA!!, myModule) + ModuleRootModificationUtil.addDependency(moduleB!!, myModule) + } + + private fun dirtyModules() = + (CompilerReferenceService.getInstance(project) as CompilerReferenceServiceImpl) + .dirtyModulesHolder + .allDirtyModulesForTest +} diff --git a/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesTest.java b/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesTest.java index e89d1f37be4f..69747e4c4810 100644 --- a/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesTest.java +++ b/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesTest.java @@ -40,6 +40,12 @@ public class CompilerReferencesTest extends CompilerReferencesTestBase { return JavaTestUtil.getJavaTestDataPath() + "/compiler/bytecodeReferences/"; } + @Override + public void setUp() throws Exception { + super.setUp(); + installCompiler(); + } + public void testIsNotReady() { myFixture.configureByFile(getName() + "/Foo.java"); assertNull(getReferentFilesForElementUnderCaret()); diff --git a/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesTestBase.java b/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesTestBase.java index 865da07caae7..0fd0bde00891 100644 --- a/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesTestBase.java +++ b/java/java-tests/testSrc/com/intellij/compiler/CompilerReferencesTestBase.java @@ -17,7 +17,7 @@ package com.intellij.compiler; import com.intellij.codeInsight.completion.AbstractCompilerAwareTest; -abstract class CompilerReferencesTestBase extends AbstractCompilerAwareTest { +public abstract class CompilerReferencesTestBase extends AbstractCompilerAwareTest { private boolean myDefaultEnableState; @Override