Files
openide/java/java-tests/testSrc/com/intellij/util/indexing/IndexTest.groovy
Dmitry Batkovich d5d82af58a remove method unused parameter
GitOrigin-RevId: 44de250731f8fea3938ba70fd2e172d58b8d2d46
2021-03-22 14:20:44 +00:00

1535 lines
68 KiB
Groovy

// Copyright 2000-2020 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.util.indexing
import com.intellij.find.ngrams.TrigramIndex
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.ide.scratch.ScratchRootType
import com.intellij.ide.todo.TodoConfiguration
import com.intellij.java.index.StringIndex
import com.intellij.lang.Language
import com.intellij.lang.LanguageParserDefinitions
import com.intellij.lang.java.JavaLanguage
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.WriteAction
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.command.impl.UndoManagerImpl
import com.intellij.openapi.command.undo.UndoManager
import com.intellij.openapi.diagnostic.DefaultLogger
import com.intellij.openapi.editor.Document
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.fileEditor.FileEditor
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.fileEditor.impl.CurrentEditorProvider
import com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl
import com.intellij.openapi.fileTypes.ExactFileNameMatcher
import com.intellij.openapi.fileTypes.FileTypeManager
import com.intellij.openapi.fileTypes.PlainTextFileType
import com.intellij.openapi.module.StdModuleTypes
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.util.ProgressIndicatorBase
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.DumbServiceImpl
import com.intellij.openapi.roots.ContentIterator
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.RecursionManager
import com.intellij.openapi.util.Ref
import com.intellij.openapi.util.ThrowableComputable
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.io.FileUtilRt
import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.*
import com.intellij.openapi.vfs.newvfs.events.VFileCreateEvent
import com.intellij.openapi.vfs.newvfs.events.VFileDeleteEvent
import com.intellij.openapi.vfs.newvfs.events.VFileEvent
import com.intellij.openapi.vfs.newvfs.events.VFilePropertyChangeEvent
import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry
import com.intellij.pom.java.LanguageLevel
import com.intellij.psi.*
import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.psi.impl.PsiDocumentManagerImpl
import com.intellij.psi.impl.PsiManagerEx
import com.intellij.psi.impl.cache.impl.id.IdIndex
import com.intellij.psi.impl.cache.impl.id.IdIndexEntry
import com.intellij.psi.impl.cache.impl.id.IdIndexImpl
import com.intellij.psi.impl.cache.impl.todo.TodoIndex
import com.intellij.psi.impl.file.impl.FileManagerImpl
import com.intellij.psi.impl.java.JavaFunctionalExpressionIndex
import com.intellij.psi.impl.java.stubs.index.JavaStubIndexKeys
import com.intellij.psi.impl.search.JavaNullMethodArgumentIndex
import com.intellij.psi.impl.source.*
import com.intellij.psi.search.*
import com.intellij.psi.stubs.*
import com.intellij.psi.util.CachedValue
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiModificationTracker
import com.intellij.testFramework.IdeaTestUtil
import com.intellij.testFramework.PlatformTestUtil
import com.intellij.testFramework.PsiTestUtil
import com.intellij.testFramework.SkipSlowTestLocally
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase
import com.intellij.util.*
import com.intellij.util.indexing.events.IndexedFilesListener
import com.intellij.util.indexing.events.VfsEventsMerger
import com.intellij.util.indexing.impl.IndexDebugProperties
import com.intellij.util.indexing.impl.MapIndexStorage
import com.intellij.util.indexing.impl.MapReduceIndex
import com.intellij.util.indexing.impl.UpdatableValueContainer
import com.intellij.util.indexing.impl.forward.IntForwardIndex
import com.intellij.util.indexing.impl.storage.VfsAwareMapIndexStorage
import com.intellij.util.indexing.impl.storage.VfsAwareMapReduceIndex
import com.intellij.util.io.CaseInsensitiveEnumeratorStringDescriptor
import com.intellij.util.io.EnumeratorStringDescriptor
import com.intellij.util.io.PersistentMapBase
import com.intellij.util.ref.GCUtil
import com.intellij.util.ref.GCWatcher
import com.intellij.util.ui.UIUtil
import com.siyeh.ig.JavaOverridingMethodUtil
import groovy.transform.CompileStatic
import org.jetbrains.annotations.NotNull
import org.jetbrains.plugins.groovy.GroovyFileType
import org.jetbrains.plugins.groovy.GroovyLanguage
import java.util.concurrent.CountDownLatch
import static com.intellij.ide.plugins.DynamicPluginsTestUtil.loadExtensionWithText
@SkipSlowTestLocally
class IndexTest extends JavaCodeInsightFixtureTestCase {
@Override
protected void tuneFixture(JavaModuleFixtureBuilder moduleBuilder) throws Exception {
if (getName() == "test indexed state for file without content requiring indices") {
// should add file to test dire as soon as possible
String otherRoot = myFixture.getTempDirPath() + "/otherRoot";
assertTrue(new File(otherRoot).mkdirs());
assertTrue(new File(otherRoot, "intellij.exe").createNewFile());
moduleBuilder.addSourceContentRoot(otherRoot)
}
}
void testUpdate() throws StorageException, IOException {
StringIndex index = createIndex(getTestName(false), new EnumeratorStringDescriptor(), false)
try {
// build index
index.update("com/ppp/a.java", "a b c d")
index.update("com/ppp/b.java", "a b g h")
index.update("com/ppp/c.java", "a z f")
index.update("com/ppp/d.java", "a a u y z")
index.update("com/ppp/e.java", "a n chj e c d")
assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/b.java", "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java")
assertDataEquals(index.getFilesByWord("b"), "com/ppp/a.java", "com/ppp/b.java")
assertDataEquals(index.getFilesByWord("c"), "com/ppp/a.java", "com/ppp/e.java")
assertDataEquals(index.getFilesByWord("d"), "com/ppp/a.java", "com/ppp/e.java")
assertDataEquals(index.getFilesByWord("g"), "com/ppp/b.java")
assertDataEquals(index.getFilesByWord("h"), "com/ppp/b.java")
assertDataEquals(index.getFilesByWord("z"), "com/ppp/c.java", "com/ppp/d.java")
assertDataEquals(index.getFilesByWord("f"), "com/ppp/c.java")
assertDataEquals(index.getFilesByWord("u"), "com/ppp/d.java")
assertDataEquals(index.getFilesByWord("y"), "com/ppp/d.java")
assertDataEquals(index.getFilesByWord("n"), "com/ppp/e.java")
assertDataEquals(index.getFilesByWord("chj"), "com/ppp/e.java")
assertDataEquals(index.getFilesByWord("e"), "com/ppp/e.java")
// update index
index.update("com/ppp/d.java", "a u y z")
assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/b.java", "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java")
index.update("com/ppp/d.java", "u y z")
assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/b.java", "com/ppp/c.java", "com/ppp/e.java")
index.update("com/ppp/d.java", "a a a u y z")
assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/b.java", "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java")
index.update("com/ppp/e.java", "a n chj e c d z")
assertDataEquals(index.getFilesByWord("z"), "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java")
index.update("com/ppp/b.java", null)
assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java")
assertDataEquals(index.getFilesByWord("b"), "com/ppp/a.java")
assertDataEquals(index.getFilesByWord("g"))
assertDataEquals(index.getFilesByWord("h"))
}
finally {
index.dispose()
}
}
void testUpdateWithCustomEqualityPolicy() {
def index = createIndex(getTestName(false), new CaseInsensitiveEnumeratorStringDescriptor(), false)
try {
index.update("a.java", "x")
assertDataEquals(index.getFilesByWord("x"), "a.java")
assertDataEquals(index.getFilesByWord("X"), "a.java")
index.update("b.java", "y")
assertDataEquals(index.getFilesByWord("y"), "b.java")
index.update("c.java", "Y")
assertDataEquals(index.getFilesByWord("y"), "b.java", "c.java")
}
finally {
index.dispose()
}
}
private static StringIndex createIndex(String testName, EnumeratorStringDescriptor keyDescriptor, boolean readOnly) {
final File storageFile = FileUtil.createTempFile("index_test", "storage")
final File metaIndexFile = FileUtil.createTempFile("index_test_inputs", "storage")
final VfsAwareMapIndexStorage indexStorage = new VfsAwareMapIndexStorage(storageFile.toPath(), keyDescriptor, new EnumeratorStringDescriptor(),
16 * 1024, readOnly)
return new StringIndex(testName, indexStorage, metaIndexFile, !readOnly)
}
private static <T> void assertDataEquals(List<T> actual, T... expected) {
assertSameElements(actual, expected)
}
void testCollectedPsiWithChangedDocument() throws IOException {
final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile()
assertNotNull(findClass("Foo"))
PsiFile psiFile = getPsiManager().findFile(vFile)
assertNotNull(psiFile)
Document document = FileDocumentManager.getInstance().getDocument(vFile)
WriteCommandAction.runWriteCommandAction(project) { document.deleteString(0, document.getTextLength()) }
assertNotNull(findClass("Foo"))
PsiClass foo = findClass("Foo")
assertNotNull(foo)
assertTrue(foo.isValid())
assertEquals("class Foo {}", foo.getText())
assertTrue(foo.isValid())
PsiDocumentManager.getInstance(getProject()).commitAllDocuments()
assertNull(findClass("Foo"))
}
void testCollectedPsiWithDocumentChangedCommittedAndChangedAgain() throws IOException {
final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile()
assertNotNull(findClass("Foo"))
PsiFile psiFile = getPsiManager().findFile(vFile)
assertNotNull(psiFile)
Document document = FileDocumentManager.getInstance().getDocument(vFile)
WriteCommandAction.runWriteCommandAction(project) { document.deleteString(0, document.getTextLength()) }
PsiDocumentManager.getInstance(getProject()).commitAllDocuments()
WriteCommandAction.runWriteCommandAction(project) { document.insertString(0, " ") }
PsiClass foo = findClass("Foo")
assertNull(foo)
}
private PsiClass findClass(String name) {
return JavaPsiFacade.getInstance(getProject()).findClass(name, GlobalSearchScope.allScope(getProject()))
}
void testSavedUncommittedDocument() throws IOException {
final VirtualFile vFile = myFixture.addFileToProject("Foo.java", "").getVirtualFile()
assertNull(findClass("Foo"))
PsiFile psiFile = getPsiManager().findFile(vFile)
assertNotNull(psiFile)
long count = getPsiManager().getModificationTracker().getModificationCount()
Document document = FileDocumentManager.getInstance().getDocument(vFile)
WriteCommandAction.runWriteCommandAction(project) { document.insertString(0, "class Foo {}") }
FileDocumentManager.getInstance().saveDocument(document)
assertTrue(count == getPsiManager().getModificationTracker().getModificationCount())
assertNull(findClass("Foo"))
PsiDocumentManager.getInstance(getProject()).commitAllDocuments()
assertNotNull(findClass("Foo"))
assertNotNull(findClass("Foo").getText())
// if Foo exists now, mod count should be different
assertTrue(count != getPsiManager().getModificationTracker().getModificationCount())
}
void testPersistentChangeAffectsDocument() throws IOException {
def psiFile = myFixture.addFileToProject("Foo.java", "class Foo {}")
final VirtualFile vFile = psiFile.getVirtualFile()
def stamp = ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, getProject())
WriteCommandAction.runWriteCommandAction(getProject(), { CodeStyleManager.getInstance(project).reformat(psiFile) })
PostprocessReformattingAspect.getInstance(project).doPostponedFormatting()
WriteCommandAction.runWriteCommandAction(project) { PsiManager.getInstance(project).reloadFromDisk(psiFile) }
assertEquals(stamp, ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, getProject()))
FileContentUtilCore.reparseFiles(Collections.singletonList(vFile))
def provider = PsiManager.getInstance(project).findViewProvider(vFile)
def stubTree = ((PsiFileImpl)provider.getPsi(provider.getBaseLanguage())).getGreenStubTree()
WriteAction.run { VfsUtil.saveText(vFile, "class Bar {}") }
assertNotNull(findClass("Foo"))
}
void testPersistentChangeAffectsUnsavedDocument() throws IOException {
def psiFile = myFixture.addFileToProject("Foo.java", "class Foo {}")
final VirtualFile vFile = psiFile.getVirtualFile()
Document document = FileDocumentManager.getInstance().getDocument(vFile)
WriteCommandAction.runWriteCommandAction(project) { document.insertString(0, "class f {}") }
WriteCommandAction.runWriteCommandAction(project) { PsiManager.getInstance(project).reloadFromDisk(psiFile) }
assertNotNull findClass("Foo")
WriteAction.run { VfsUtil.saveText(vFile, "class x {}") }
WriteCommandAction.runWriteCommandAction(project) { document.insertString(0, "class a {}") }
GCUtil.tryGcSoftlyReachableObjects()
assertNotNull findClass("Foo")
}
void testSkipUnknownFileTypes() throws IOException {
final VirtualFile vFile = myFixture.addFileToProject("Foo.test", "Foo").getVirtualFile()
assertEquals(PlainTextFileType.INSTANCE, vFile.getFileType())
final PsiSearchHelper helper = PsiSearchHelper.getInstance(getProject())
assertOneElement(helper.findFilesWithPlainTextWords("Foo"))
final Document document = FileDocumentManager.getInstance().getDocument(vFile)
//todo should file type be changed silently without events?
//assertEquals(UnknownFileType.INSTANCE, vFile.getFileType());
final PsiFile file = PsiDocumentManager.getInstance(getProject()).getPsiFile(document)
assertInstanceOf(file, PsiPlainTextFile.class)
assertEquals("Foo", file.getText())
assertOneElement(helper.findFilesWithPlainTextWords("Foo"))
WriteCommandAction.runWriteCommandAction(getProject(), new Runnable() {
@Override
void run() {
document.insertString(0, " ")
assertEquals("Foo", file.getText())
assertOneElement(helper.findFilesWithPlainTextWords("Foo"))
FileDocumentManager.getInstance().saveDocument(document)
assertEquals("Foo", file.getText())
assertOneElement(helper.findFilesWithPlainTextWords("Foo"))
PsiDocumentManager.getInstance(getProject()).commitAllDocuments()
assertEquals(" Foo", file.getText())
assertOneElement(helper.findFilesWithPlainTextWords("Foo"))
}
})
}
void testUndoToFileContentForUnsavedCommittedDocument() throws IOException {
final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile()
((VirtualFileSystemEntry)vFile).setModificationStamp(0) // as unchanged file
final Document document = FileDocumentManager.getInstance().getDocument(vFile)
assertTrue(document != null)
assert document.getModificationStamp() == 0
assertNotNull(findClass("Foo"))
WriteCommandAction.runWriteCommandAction(getProject(), new Runnable() {
@Override
void run() {
document.insertString(0, "import Bar;\n")
PsiDocumentManager.getInstance(getProject()).commitAllDocuments()
assertNotNull(findClass("Foo"))
}
})
final UndoManager undoManager = UndoManager.getInstance(getProject())
final FileEditor selectedEditor = FileEditorManager.getInstance(getProject()).openFile(vFile, false)[0]
((UndoManagerImpl)undoManager).setEditorProvider(new CurrentEditorProvider() {
@Override
FileEditor getCurrentEditor() {
return selectedEditor
}
})
assertTrue(undoManager.isUndoAvailable(selectedEditor))
FileDocumentManager.getInstance().saveDocument(document)
undoManager.undo(selectedEditor)
assertNotNull(findClass("Foo"))
}
void "test rename unsaved file"() {
def psiFile = myFixture.addFileToProject("Foo.java", "class Foo {}")
def scope = GlobalSearchScope.allScope(project)
assert !FileDocumentManager.instance.unsavedDocuments
WriteCommandAction.runWriteCommandAction(getProject(), { ((PsiJavaFile)psiFile).importList.add(elementFactory.createImportStatementOnDemand("java.io")) })
GCUtil.tryGcSoftlyReachableObjects()
assert JavaPsiFacade.getInstance(project).findClass("Foo", scope)
assert !((FileManagerImpl)psiManager.fileManager).getCachedDirectory(psiFile.virtualFile.parent)
WriteCommandAction.runWriteCommandAction(getProject(), { assert psiFile.setName("Foo1.java") == psiFile })
assert FileDocumentManager.instance.unsavedDocuments
assert JavaPsiFacade.getInstance(project).findClass("Foo", scope)
}
void "test rename dir with unsaved file"() {
def psiFile = myFixture.addFileToProject("foo/Foo.java", "package pkg; class Foo {}")
def scope = GlobalSearchScope.allScope(project)
assert !FileDocumentManager.instance.unsavedDocuments
WriteCommandAction.runWriteCommandAction(getProject(), { ((PsiJavaFile)psiFile).importList.add(elementFactory.createImportStatementOnDemand("java.io")) })
GCUtil.tryGcSoftlyReachableObjects()
assert JavaPsiFacade.getInstance(project).findClass("pkg.Foo", scope)
def dir = psiFile.virtualFile.parent
assert !((FileManagerImpl)psiManager.fileManager).getCachedDirectory(dir)
WriteAction.run { dir.rename(this, "bar") }
assert FileDocumentManager.instance.unsavedDocuments
assert JavaPsiFacade.getInstance(project).findClass("pkg.Foo", scope)
}
void "test language level change"() {
def psiFile = myFixture.addFileToProject("Foo.java", "class Foo {}")
def scope = GlobalSearchScope.allScope(project)
WriteCommandAction.runWriteCommandAction(getProject(), { psiFile.add(elementFactory.createEnum("SomeEnum")) })
WriteCommandAction.runWriteCommandAction(getProject(), { CodeStyleManager.getInstance(getProject()).reformat(psiFile) })
assert JavaPsiFacade.getInstance(project).findClass("Foo", scope)
def stamp = ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project)
IdeaTestUtil.setModuleLanguageLevel(myFixture.module, LanguageLevel.JDK_1_3)
assert ((PsiJavaFile)psiFile).importList.node
assert stamp != ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project)
}
void "test rename file with indexed associated unsaved document don't lost its data"() {
def level = LanguageLevel.HIGHEST
IdeaTestUtil.setModuleLanguageLevel(myFixture.module, level)
def psiFile = myFixture.addFileToProject("Foo.java", "class Foo {}")
def file = psiFile.virtualFile
def scope = GlobalSearchScope.allScope(project)
PostprocessReformattingAspect.getInstance(getProject()).doPostponedFormatting()
PsiDocumentManager.getInstance(getProject()).commitAllDocuments()
def vp = PsiManager.getInstance(project).findViewProvider(file)
WriteCommandAction.runWriteCommandAction(getProject(), { CodeStyleManager.getInstance(getProject()).reformat(vp.getPsi(vp.baseLanguage)) })
PostprocessReformattingAspect.getInstance(getProject()).doPostponedFormatting()
FileContentUtilCore.reparseFiles(Collections.singletonList(file))
vp = PsiManager.getInstance(project).findViewProvider(file)
((PsiFileImpl)vp.getPsi(vp.baseLanguage)).greenStubTree
PostprocessReformattingAspect.getInstance(getProject()).doPostponedFormatting()
FileContentUtilCore.reparseFiles(Collections.singletonList(file))
PostprocessReformattingAspect.getInstance(getProject()).doPostponedFormatting()
IdeaTestUtil.setModuleLanguageLevel(myFixture.module, level)
assert JavaPsiFacade.getInstance(project).findClass("Foo", scope)
}
void "test language level change2"() {
def psiFile = myFixture.addFileToProject("Foo.java", "class Foo {}")
def vFile = psiFile.virtualFile
def scope = GlobalSearchScope.allScope(project)
WriteCommandAction.runWriteCommandAction(getProject(), { psiFile.add(elementFactory.createEnum("SomeEnum")) })
WriteCommandAction.runWriteCommandAction(getProject(), { CodeStyleManager.getInstance(getProject()).reformat(psiFile) })
PostprocessReformattingAspect.getInstance(getProject()).doPostponedFormatting()
assert JavaPsiFacade.getInstance(project).findClass("Foo", scope)
IdeaTestUtil.setModuleLanguageLevel(myFixture.module, LanguageLevel.JDK_1_3)
assert ((PsiJavaFile)getPsiManager().findFile(vFile)).importList.node
GCUtil.tryGcSoftlyReachableObjects()
assert ((PsiJavaFile)getPsiManager().findFile(vFile)).importList.node
}
void "test unknown file type in stubs"() {
def vFile = myFixture.addFileToProject("Foo.java", "").virtualFile
final Document document = FileDocumentManager.getInstance().getDocument(vFile)
WriteCommandAction.runWriteCommandAction(project) { document.setText("class Foo {}") }
PsiDocumentManager.getInstance(project).commitAllDocuments()
assert findClass("Foo")
WriteAction.run { vFile.rename(null, "Foo1") }
assert !findClass("Foo")
}
void "test uncommitted saved document 2"() {
def file = myFixture.addFileToProject('a.java', 'class Foo {}')
WriteCommandAction.runWriteCommandAction(project) {
assert findClass('Foo')
file.viewProvider.document.text = ''
PsiDocumentManager.getInstance(project).commitAllDocuments()
file.viewProvider.document.text = 'class Foo {}'
FileDocumentManager.instance.saveAllDocuments()
assert !findClass('Foo')
}
}
void "test plain text file type in stubs"() {
def vFile = myFixture.addFileToProject("Foo.java", "class Bar {}").virtualFile
assert findClass("Bar")
final Document document = FileDocumentManager.getInstance().getDocument(vFile)
WriteCommandAction.runWriteCommandAction(project) { document.setText("class Foo {}") }
PsiDocumentManager.getInstance(project).commitAllDocuments()
assert findClass("Foo")
assert !findClass("Bar")
WriteAction.run { vFile.rename(null, "Foo1") }
assert !findClass("Foo")
assert !findClass("Bar")
}
void "test changing a file without psi makes the document committed and updates index"() {
def psiFile = myFixture.addFileToProject("Foo.java", "class Foo {}")
def vFile = psiFile.virtualFile
def scope = GlobalSearchScope.allScope(project)
WriteCommandAction.runWriteCommandAction(project) { FileDocumentManager.instance.getDocument(vFile).text = "import zoo.Zoo; class Foo1 {}" }
assert PsiDocumentManager.getInstance(project).uncommittedDocuments
FileDocumentManager.instance.saveAllDocuments()
PsiDocumentManager.getInstance(project).commitAllDocuments()
//noinspection GroovyUnusedAssignment
psiFile = null
GCWatcher.tracking(((PsiManagerEx)psiManager).fileManager.getCachedPsiFile(vFile)).ensureCollected { UIUtil.dispatchAllInvocationEvents() }
assert !((PsiManagerEx)psiManager).fileManager.getCachedPsiFile(vFile)
WriteAction.run { VfsUtil.saveText(vFile, "class Foo3 {}") }
assert !PsiDocumentManager.getInstance(project).uncommittedDocuments
assert JavaPsiFacade.getInstance(project).findClass("Foo3", scope)
}
void "test rename file invalidates indices in right order"() throws IOException {
GlobalSearchScope scope = GlobalSearchScope.allScope(getProject())
for (def i = 0; i < 100; ++i) {
final VirtualFile file = myFixture.addFileToProject("foo/Foo" + i + ".java", "package foo; class Foo" + i + " {}").getVirtualFile()
assertNotNull(JavaPsiFacade.getInstance(getProject()).findClass("foo.Foo" + i, scope))
WriteCommandAction.runWriteCommandAction(project) { file.rename(this, "Bar" + i + ".java") }
assertNotNull(JavaPsiFacade.getInstance(getProject()).findClass("foo.Foo" + i, scope))
}
}
void "test no index stamp update when no change"() throws IOException {
final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile()
def stamp = FileBasedIndex.instance.getIndexModificationStamp(IdIndex.NAME, project)
assertTrue(((VirtualFileSystemEntry)vFile).isFileIndexed())
WriteAction.run { VfsUtil.saveText(vFile, "Foo class") }
assertTrue(!((VirtualFileSystemEntry)vFile).isFileIndexed())
assertTrue(stamp == FileBasedIndex.instance.getIndexModificationStamp(IdIndex.NAME, project))
assertTrue(((VirtualFileSystemEntry)vFile).isFileIndexed())
WriteAction.run { VfsUtil.saveText(vFile, "class Foo2 {}") }
assertTrue(stamp != FileBasedIndex.instance.getIndexModificationStamp(IdIndex.NAME, project))
final Document document = FileDocumentManager.getInstance().getDocument(vFile)
WriteCommandAction.runWriteCommandAction(project) { document.setText("Foo2 class") }
stamp = FileBasedIndex.instance.getIndexModificationStamp(IdIndex.NAME, project)
WriteCommandAction.runWriteCommandAction(project) { document.setText("class Foo2") }
assertTrue(stamp == FileBasedIndex.instance.getIndexModificationStamp(IdIndex.NAME, project))
WriteCommandAction.runWriteCommandAction(project) { document.setText("Foo3 class") }
PsiDocumentManager.getInstance(project).commitAllDocuments()
assertTrue(stamp != FileBasedIndex.instance.getIndexModificationStamp(IdIndex.NAME, project))
WriteCommandAction.runWriteCommandAction(project) { document.text = "class Foo { Runnable r = ( ) -> {}; }" }
PsiDocumentManager.getInstance(project).commitAllDocuments()
stamp = FileBasedIndex.instance.getIndexModificationStamp(JavaFunctionalExpressionIndex.INDEX_ID, project)
WriteCommandAction.runWriteCommandAction(project) { document.text = "class Foo { Runnable x = () -> { }; }" }
PsiDocumentManager.getInstance(project).commitAllDocuments()
assert stamp == FileBasedIndex.instance.getIndexModificationStamp(JavaFunctionalExpressionIndex.INDEX_ID, project)
}
void "test no index stamp update when no change 2"() throws IOException {
@org.intellij.lang.annotations.Language("JAVA")
def text0 = """
class Main111 {
static void staticMethod(Object o) {
staticMethod(null);
}
}
"""
final VirtualFile vFile = myFixture.configureByText(JavaFileType.INSTANCE, text0).virtualFile
def stamp = FileBasedIndex.instance.getIndexModificationStamp(JavaNullMethodArgumentIndex.INDEX_ID, project)
def data = new JavaNullMethodArgumentIndex.MethodCallData("staticMethod", 0)
def files = FileBasedIndex.instance.getContainingFiles(JavaNullMethodArgumentIndex.INDEX_ID, data, GlobalSearchScope.projectScope(project))
assertTrue(files.size() == 1)
assertEquals(files[0], vFile)
@org.intellij.lang.annotations.Language("JAVA")
def text = """
class Main {
static void staticMethod(Object o) {
staticMethod(null);
}
}
"""
WriteAction.run { VfsUtil.saveText(vFile, text) }
PsiDocumentManager.getInstance(project).commitAllDocuments()
assertTrue(stamp == (FileBasedIndex.instance).getIndexModificationStamp(JavaNullMethodArgumentIndex.INDEX_ID, project))
files = FileBasedIndex.instance.getContainingFiles(JavaNullMethodArgumentIndex.INDEX_ID, data, GlobalSearchScope.projectScope(project))
assertTrue(files.size() == 1)
assertEquals(files[0], vFile)
}
void "test snapshot index in memory state after commit of unsaved document"() throws IOException {
final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile()
def classEntry = new IdIndexEntry("class", true)
FileBasedIndex.ValueProcessor findValueProcessor = { file, value -> file != vFile }
def projectScope = GlobalSearchScope.projectScope(project)
def result = FileBasedIndex.instance.processValues(IdIndexImpl.NAME, classEntry, null, findValueProcessor, projectScope)
assertFalse(result)
final Document document = FileDocumentManager.getInstance().getDocument(vFile)
WriteCommandAction.runWriteCommandAction(project) { document.setText("") }
PsiDocumentManager.getInstance(project).commitAllDocuments()
result = FileBasedIndex.instance.processValues(IdIndexImpl.NAME, classEntry, null, findValueProcessor, projectScope)
assertTrue(result)
}
void "test no stub index stamp update when no change"() throws IOException {
final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile()
def stamp = ((StubIndexImpl)StubIndex.instance).getIndexModificationStamp(JavaStubIndexKeys.CLASS_SHORT_NAMES, project)
WriteAction.run { VfsUtil.saveText(vFile, "class Foo { int foo; }") }
assertTrue(stamp == ((StubIndexImpl)StubIndex.instance).getIndexModificationStamp(JavaStubIndexKeys.CLASS_SHORT_NAMES, project))
WriteAction.run { VfsUtil.saveText(vFile, "class Foo2 { }") }
assertTrue(stamp != ((StubIndexImpl)StubIndex.instance).getIndexModificationStamp(JavaStubIndexKeys.CLASS_SHORT_NAMES, project))
final Document document = FileDocumentManager.getInstance().getDocument(vFile)
WriteCommandAction.runWriteCommandAction(project) { document.setText("class Foo3 {}") }
PsiDocumentManager.getInstance(project).commitAllDocuments()
stamp = ((StubIndexImpl)StubIndex.instance).getIndexModificationStamp(JavaStubIndexKeys.CLASS_SHORT_NAMES, project)
WriteCommandAction.runWriteCommandAction(project) { document.setText("class Foo3 { int foo; }") }
PsiDocumentManager.getInstance(project).commitAllDocuments()
assertTrue(stamp == ((StubIndexImpl)StubIndex.instance).getIndexModificationStamp(JavaStubIndexKeys.CLASS_SHORT_NAMES, project))
WriteCommandAction.runWriteCommandAction(project) { document.setText("class Foo2 { }") }
PsiDocumentManager.getInstance(project).commitAllDocuments()
assertTrue(stamp != ((StubIndexImpl)StubIndex.instance).getIndexModificationStamp(JavaStubIndexKeys.CLASS_SHORT_NAMES, project))
}
void "test internalErrorOfStubProcessingInvalidatesIndex"() throws IOException {
DefaultLogger.disableStderrDumping(testRootDisposable)
final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile()
def clazz = Ref.create(findClass("Foo"))
assert clazz.get() != null
runFindClassStubIndexQueryThatProducesInvalidResult("Foo")
GCWatcher.fromClearedRef(clazz).ensureCollected()
assertNull(findClass("Foo"))
// check invalidation of transient indices state
def document = FileDocumentManager.instance.getDocument(vFile)
WriteCommandAction.runWriteCommandAction(project) { document.setText("class Foo2 {}") }
PsiDocumentManager.getInstance(project).commitDocument(document)
clazz = Ref.create(findClass("Foo2"))
assert clazz.get() != null
runFindClassStubIndexQueryThatProducesInvalidResult("Foo2")
GCWatcher.fromClearedRef(clazz).ensureCollected()
assertNull(findClass("Foo2"))
}
private void runFindClassStubIndexQueryThatProducesInvalidResult(String qName) {
def foundFile = [null]
def key = qName.hashCode()
def searchScope = GlobalSearchScope.allScope(project)
def processor = new Processor<PsiFile>() {
@Override
boolean process(PsiFile file) {
foundFile[0] = file
return false
}
}
try {
StubIndex.instance.
processElements(JavaStubIndexKeys.CLASS_FQN, key, project, searchScope, PsiClass.class, new Processor<PsiClass>() {
@Override
boolean process(PsiClass aClass) {
StubIndex.instance.processElements(JavaStubIndexKeys.CLASS_FQN, key, project, searchScope, PsiFile.class, processor)
return false
}
})
fail("Unexpected")
}
catch (AssertionError ignored) {
// stub mismatch
}
assertTrue(((StubIndexImpl)StubIndex.instance).areAllProblemsProcessedInTheCurrentThread())
try {
StubIndex.instance.processElements(JavaStubIndexKeys.CLASS_FQN, key, project, searchScope, PsiFile.class, processor)
fail("Unexpected")
}
catch (AssertionError ignored) {
// stub mismatch
}
}
void "test do not collect stub tree while holding stub elements"() throws IOException {
final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile()
PsiFileWithStubSupport psiFile = getPsiManager().findFile(vFile) as PsiFileWithStubSupport
assertNotNull(psiFile)
def clazz = findClass("Foo")
assertNotNull(clazz)
def stubTreeHash = psiFile.getStubTree().hashCode()
GCUtil.tryGcSoftlyReachableObjects()
def stubTree = psiFile.getStubTree()
assertNotNull(stubTree)
assertEquals(stubTreeHash, stubTree.hashCode())
}
void "test report using index from other index"() throws IOException {
def className = "Foo"
def vfile = myFixture.addClass("class $className { void bar() {} }").getContainingFile().getVirtualFile()
def scope = GlobalSearchScope.allScope(project)
def foundClass = [false]
def foundMethod = [false]
try {
StubIndex.instance.processElements(
JavaStubIndexKeys.CLASS_SHORT_NAMES, className, project, scope,
PsiClass.class,
new Processor<PsiClass>() {
@Override
boolean process(PsiClass aClass) {
foundClass[0] = true
StubIndex.instance.processElements(
JavaStubIndexKeys.METHODS, "bar", project, scope,
PsiMethod.class,
new Processor<PsiMethod>() {
@Override
boolean process(PsiMethod method) {
foundMethod[0] = true
return true
}
})
return true
}
})
}
catch (e) {
if (!(e instanceof RuntimeException)) throw e
}
assertTrue(foundClass[0])
assertTrue(foundMethod[0]) // allow access stub index processing other index
def foundClassProcessAll = [false]
def foundClassStub = [false]
try {
StubIndex.instance.processAllKeys(
JavaStubIndexKeys.CLASS_SHORT_NAMES, project,
new Processor<String>() {
@Override
boolean process(String aClass) {
if (!className.equals(aClass)) return true
foundClassProcessAll[0] = true
StubIndex.instance.processElements(
JavaStubIndexKeys.CLASS_SHORT_NAMES, aClass, project, scope,
PsiClass.class,
new Processor<PsiClass>() {
@Override
boolean process(PsiClass clazz) {
foundClassStub[0] = true
return true
}
})
return true
}
})
}
catch (e) {
if (!(e instanceof RuntimeException)) throw e
}
assertTrue(foundClassProcessAll[0])
assertTrue(foundClassStub[0])
def foundId = [false]
def foundStub = [false]
try {
FileBasedIndex.instance.
processValues(IdIndex.NAME, new IdIndexEntry("Foo", true), null, new FileBasedIndex.ValueProcessor<Integer>() {
@Override
boolean process(@NotNull VirtualFile file, Integer value) {
foundId[0] = true
FileBasedIndex.instance.processValues(
StubUpdatingIndex.INDEX_ID,
vfile.id,
null,
new FileBasedIndex.ValueProcessor<SerializedStubTree>() {
@Override
boolean process(@NotNull VirtualFile file2, SerializedStubTree value2) {
foundStub[0] = true
return true
}
},
scope
)
return true
}
}, scope)
}
catch (e) {
if (!(e instanceof RuntimeException)) throw e
}
assertTrue(foundId[0])
assertTrue(!foundStub[0])
}
void testNullProjectScope() throws Throwable {
GlobalSearchScope allScope = new EverythingGlobalScope()
// create file to be indexed
final VirtualFile testFile = myFixture.addFileToProject("test.txt", "test").getVirtualFile()
assertNoException(IllegalArgumentException.class, new ThrowableRunnable<Throwable>() {
@Override
void run() throws Throwable {
//force to index new file with null project scope
FileBasedIndex.getInstance().ensureUpToDate(IdIndex.NAME, getProject(), allScope)
}
})
assertNotNull(testFile)
}
class RecordingVfsListener extends IndexedFilesListener {
RecordingVfsListener() {
super()
}
@Override
protected void iterateIndexableFiles(@NotNull VirtualFile file, @NotNull ContentIterator iterator) {
VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor<Void>() {
@Override
boolean visitFile(@NotNull VirtualFile visitedFile) {
iterator.processFile(visitedFile)
return true
}
})
}
String indexingOperation(VirtualFile file) {
Ref<String> operation = new Ref<>()
eventMerger.processChanges(new VfsEventsMerger.VfsEventProcessor() {
@Override
boolean process(@NotNull VfsEventsMerger.ChangeInfo info) {
operation.set(info.toString())
return true
}
})
StringUtil.replace(operation.get(), file.getPath(), file.getName())
}
}
void testIndexedFilesListener() throws Throwable {
def listener = new RecordingVfsListener()
VirtualFileManager.instance.addAsyncFileListener(listener, myFixture.testRootDisposable)
def fileName = "test.txt"
final VirtualFile testFile = myFixture.addFileToProject(fileName, "test").getVirtualFile()
assertEquals("file: $fileName; " +
"operation: UPDATE-REMOVE UPDATE ADD", listener.indexingOperation(testFile))
FileContentUtilCore.reparseFiles(Collections.singletonList(testFile))
assertEquals("file: $fileName; " +
"operation: REMOVE ADD", listener.indexingOperation(testFile))
WriteAction.run { VfsUtil.saveText(testFile, "foo") }
WriteAction.run { VfsUtil.saveText(testFile, "bar") }
assertEquals("file: $fileName; " +
"operation: UPDATE-REMOVE UPDATE", listener.indexingOperation(testFile))
WriteAction.run { VfsUtil.saveText(testFile, "baz") }
WriteAction.run { testFile.delete(null) }
assertEquals("file: $fileName; " +
"operation: REMOVE", listener.indexingOperation(testFile))
}
void "test files inside copied directory are indexed"() {
def facade = JavaPsiFacade.getInstance(project)
def srcFile = myFixture.addFileToProject('foo/bar/A.java', 'class A {}')
assert facade.findClass('A', GlobalSearchScope.moduleScope(module)) != null
def anotherDir = myFixture.tempDirFixture.findOrCreateDir('another')
def anotherModule = PsiTestUtil.addModule(project, StdModuleTypes.JAVA, 'another', anotherDir)
assert !facade.findClass('A', GlobalSearchScope.moduleScope(anotherModule))
WriteAction.run { srcFile.virtualFile.parent.copy(this, anotherDir, 'doo') }
assert facade.findClass('A', GlobalSearchScope.moduleScope(anotherModule)) != null
assert JavaFileElementType.isInSourceContent(myFixture.tempDirFixture.getFile('another/doo/A.java'))
}
void "test requesting nonexisted index fails as expected"() {
ID<?, ?> myId = ID.create("my.id")
try {
FileBasedIndex.instance.getContainingFiles(myId, "null", GlobalSearchScope.allScope(project))
FileBasedIndex.instance.processAllKeys(myId, CommonProcessors.alwaysTrue(), project)
fail()
}
catch (IllegalStateException ignored) {}
}
void "test read-only index access"() {
StringIndex index = createIndex(getTestName(false), new EnumeratorStringDescriptor(), true)
try {
IndexDebugProperties.IS_UNIT_TEST_MODE = false;
assertFalse(index.update("qwe/asd", "some_string"))
def rebuildThrowable = index.getRebuildThrowable()
assertInstanceOf(rebuildThrowable, StorageException.class)
def rebuildCause = rebuildThrowable.getCause()
assertInstanceOf(rebuildCause, IncorrectOperationException.class)
}
finally {
IndexDebugProperties.IS_UNIT_TEST_MODE = true;
index.dispose()
}
}
void "test commit without reparse properly changes index"() {
def srcFile = myFixture.addFileToProject('A.java', 'class A {}')
assert findClass('A') != null
Document document = FileDocumentManager.getInstance().getDocument(srcFile.virtualFile)
WriteCommandAction.runWriteCommandAction(project) { document.replaceString(0, document.getTextLength(), 'class B {}') }
assertNotNull(findClass('A'))
((PsiDocumentManagerImpl)PsiDocumentManager.getInstance(project)).commitDocument(document)
assertNull(findClass("A"))
assertNotNull(findClass("B"))
WriteCommandAction.runWriteCommandAction(project) { document.replaceString(0, document.getTextLength(), 'class C {}') }
assertNotNull(findClass('B'))
FileDocumentManager.getInstance().saveDocument(document)
((PsiDocumentManagerImpl)PsiDocumentManager.getInstance(project)).commitDocument(document)
assertNull(findClass("B"))
assertNotNull(findClass("C"))
}
void "test reload from disk after adding import"() {
def file = myFixture.addFileToProject("Foo.java", "class Foo {}") as PsiJavaFile
WriteCommandAction.runWriteCommandAction(project) { file.importList.add(JavaPsiFacade.getElementFactory(project).createImportStatementOnDemand('java.util')) }
PostprocessReformattingAspect.getInstance(project).doPostponedFormatting()
WriteCommandAction.runWriteCommandAction(project) { psiManager.reloadFromDisk(file) }
assert findClass("Foo")
}
void "test read-only index has read-only storages"() {
def index = createIndex(getTestName(false), new EnumeratorStringDescriptor(), true).getIndex()
try {
MapIndexStorage<String, String> storage = assertInstanceOf(index, MapReduceIndex.class).getStorage()
PersistentMapBase<String, UpdatableValueContainer<String>> map = storage.getIndexMap()
assertTrue(map.getReadOnly())
assertTrue(map.getValueStorage().isReadOnly())
}
finally {
index.dispose()
}
}
@CompileStatic
void "test Vfs Event Processing Performance"() {
def filename = 'A.java'
myFixture.addFileToProject('foo/bar/' + filename, 'class A {}')
PlatformTestUtil.startPerformanceTest("Vfs Event Processing By Index", 1000, {
def files = FilenameIndex.getFilesByName(project, filename, GlobalSearchScope.moduleScope(module))
assert files?.length == 1
VirtualFile file = files[0].virtualFile
def filename2 = 'B.java'
def max = 100000
List<VFileEvent> eventList = new ArrayList<>(max)
def len = max / 2
for (int i = 0; i < len; ++i) {
eventList.add(new VFilePropertyChangeEvent(null, file, VirtualFile.PROP_NAME, filename, filename2, true))
eventList.add(new VFilePropertyChangeEvent(null, file, VirtualFile.PROP_NAME, filename2, filename, true))
eventList.add(new VFileDeleteEvent(null, file, true))
eventList.add(new VFileCreateEvent(null, file.parent, filename, false, null, null, true, null))
}
def applier = ((FileBasedIndexImpl)FileBasedIndex.instance).changedFilesCollector.prepareChange(eventList)
applier.beforeVfsChange()
applier.afterVfsChange()
files = FilenameIndex.getFilesByName(project, filename, GlobalSearchScope.moduleScope(module))
assert files?.length == 1
}).assertTiming()
}
void "test class file in src content isn't returned from index"() {
def runnable = JavaPsiFacade.getInstance(project).findClass(Runnable.name, GlobalSearchScope.allScope(project))
def thread = JavaPsiFacade.getInstance(project).findClass(Thread.name, GlobalSearchScope.allScope(project))
def srcRoot = myFixture.tempDirFixture.getFile("")
WriteCommandAction.runWriteCommandAction(project) { VfsUtil.copy(this, thread.containingFile.virtualFile, srcRoot) }
def projectScope = GlobalSearchScope.projectScope(project)
assert !JavaOverridingMethodUtil.getOverridingMethodsIfCheapEnough(runnable.methods[0], projectScope, { true }).findFirst().present
assert StubIndex.instance.getElements(JavaStubIndexKeys.METHODS, 'run', project, projectScope, PsiMethod).empty
}
void "test text todo indexing checks for cancellation"() {
TodoPattern pattern = new TodoPattern("(x+x+)+y", TodoAttributesUtil.createDefault(), true)
TodoPattern[] oldPatterns = TodoConfiguration.getInstance().getTodoPatterns()
TodoPattern[] newPatterns = [pattern]
TodoConfiguration.getInstance().setTodoPatterns(newPatterns)
FileBasedIndex.instance.ensureUpToDate(TodoIndex.NAME, project, GlobalSearchScope.allScope(project))
myFixture.addFileToProject("Foo.txt", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
try {
final CountDownLatch progressStarted = new CountDownLatch(1)
final ProgressIndicatorBase progressIndicatorBase = new ProgressIndicatorBase()
boolean[] canceled = [false]
ApplicationManager.application.executeOnPooledThread({
progressStarted.await()
TimeoutUtil.sleep(1000)
progressIndicatorBase.cancel()
TimeoutUtil.sleep(500)
assertTrue(canceled[0])
})
ProgressManager.getInstance().runProcess(
{
try {
progressStarted.countDown()
FileBasedIndex.instance.ensureUpToDate(TodoIndex.NAME, project, GlobalSearchScope.allScope(project))
}
catch (ProcessCanceledException ignore) {
canceled[0] = true
}
}, progressIndicatorBase
)
}
finally {
TodoConfiguration.getInstance().setTodoPatterns(oldPatterns)
}
}
void "test stub updating index problem during processAllKeys"() throws IOException {
def className = "Foo"
myFixture.addClass("class $className {}")
def scope = GlobalSearchScope.allScope(project)
def foundClassProcessAll = [false]
def foundClassStub = [false]
try {
StubIndex.instance.processAllKeys(
JavaStubIndexKeys.CLASS_SHORT_NAMES, project,
new Processor<String>() {
@Override
boolean process(String aClass) {
if (!className.equals(aClass)) return true
foundClassProcessAll[0] = true
// adding file will add file to index's dirty set but it should not be processed within current read action
myFixture.addFileToProject("Bar.java", "class Bar { }")
StubIndex.instance.processElements(
JavaStubIndexKeys.CLASS_SHORT_NAMES, aClass, project, scope,
PsiClass.class,
new Processor<PsiClass>() {
@Override
boolean process(PsiClass clazz) {
foundClassStub[0] = true
return true
}
})
return true
}
})
}
catch (e) {
if (!(e instanceof RuntimeException)) throw e
}
assertTrue(foundClassProcessAll[0])
assertTrue(foundClassStub[0]) // allow access stub index processing other index
}
void "test document increases beyond too large limit"() {
String item = createLongSequenceOfCharacterConstants()
def fileText = 'class Bar { char[] item = { ' + item + "};\n }"
def file = myFixture.addFileToProject('foo/Bar.java', fileText).virtualFile
assertNotNull(findClass("Bar"))
Document document = FileDocumentManager.getInstance().getDocument(file)
for (int i = 0; i < 2; ++i) {
WriteCommandAction.runWriteCommandAction(getProject(), { document.replaceString(0, document.textLength, item + item) })
PsiDocumentManager.getInstance(project).commitDocument(document)
assertNull(findClass("Bar"))
WriteCommandAction.runWriteCommandAction(getProject(), { document.replaceString(0, document.textLength, fileText) })
PsiDocumentManager.getInstance(project).commitDocument(document)
assertNotNull(findClass("Bar"))
}
}
private static String createLongSequenceOfCharacterConstants() {
String item = "'c',"
item * (Integer.highestOneBit(FileUtilRt.userFileSizeLimit) / item.length())
}
void "test file increases beyond too large limit"() {
String item = createLongSequenceOfCharacterConstants()
def fileText = 'class Bar { char[] item = { ' + item + "};\n }"
def file = myFixture.addFileToProject('foo/Bar.java', fileText).virtualFile
assertNotNull(findClass("Bar"))
for (int i = 0; i < 2; ++i) {
WriteAction.run { VfsUtil.saveText(file, item + item) }
assertNull(findClass("Bar"))
WriteAction.run { VfsUtil.saveText(file, fileText) }
assertNotNull(findClass("Bar"))
}
}
void "test indexed state for file without content requiring indices"() {
def scope = GlobalSearchScope.allScope(getProject())
FileBasedIndex.instance.ensureUpToDate(FilenameIndex.NAME, project, scope)
def files = FilenameIndex.getFilesByName(getProject(), "intellij.exe", scope)
def file = assertOneElement(files).virtualFile
assertTrue(file.getFileType().isBinary())
assertTrue(((VirtualFileSystemEntry)file).isFileIndexed())
WriteCommandAction.runWriteCommandAction(getProject(), { file.rename(this, 'intellij2.exe') })
FileBasedIndex.instance.ensureUpToDate(FilenameIndex.NAME, project, scope)
assertTrue(((VirtualFileSystemEntry)file).isFileIndexed())
}
void "test IDEA-188028" () {
def file = myFixture.addFileToProject('a.java', 'class Foo {}') as PsiJavaFileImpl
WriteCommandAction.runWriteCommandAction(project) {
def document = file.viewProvider.document
document.setText('')
PsiDocumentManager.getInstance(project).commitAllDocuments()
PsiManager.getInstance(project).reloadFromDisk(file)
document.setText('')
assert !findClass('Foo')
file.virtualFile.rename(this, 'a1.java')
PsiDocumentManager.getInstance(project).commitAllDocuments()
assert !findClass('Foo')
}
}
void "test every directory and file are marked as indexed in open project"() {
VirtualFile foo = myFixture.addFileToProject('src/main/a.java', 'class Foo {}').virtualFile
VirtualFile main = foo.parent
VirtualFile src = main.parent
def scope = GlobalSearchScope.allScope(getProject())
assertEquals(foo, assertOneElement(FilenameIndex.getVirtualFilesByName("a.java", scope)))
assertEquals(main, assertOneElement(FilenameIndex.getVirtualFilesByName( "main", scope)))
assertEquals(src, assertOneElement(FilenameIndex.getVirtualFilesByName( "src", scope)))
// content-less indexes has been passed
// now all directories are indexed
assertFalse(((VirtualFileSystemEntry)foo).isFileIndexed())
assertTrue(((VirtualFileSystemEntry)main).isFileIndexed())
assertTrue(((VirtualFileSystemEntry)src).isFileIndexed())
assert findClass("Foo") // ensure content dependent indexes are passed
assertTrue(((VirtualFileSystemEntry)foo).isFileIndexed())
}
void "test stub updating index stamp"() {
final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile()
def stamp = ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project)
WriteAction.run { VfsUtil.saveText(vFile, "class Foo { void m() {} }") }
assertTrue(stamp != ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project))
stamp = ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project)
WriteAction.run { VfsUtil.saveText(vFile, "class Foo { void m() { int k = 0; } }") }
assertTrue(stamp == ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project))
}
void "test index stamp update on transient data deletion"() {
WriteCommandAction.runWriteCommandAction(project) {
def stamp = ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project)
def file = myFixture.addClass("class Foo {}").getContainingFile()
((PsiJavaFile)file).getImportList().add(JavaPsiFacade.getElementFactory(getProject()).createImportStatementOnDemand("java.io"))
assert findClass("Foo") != null
PsiDocumentManager.getInstance(getProject()).commitAllDocuments()
assertTrue(stamp != ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project))
stamp = ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project)
assert findClass("Foo") != null
PsiDocumentManager.getInstance(getProject()).commitAllDocuments()
assertTrue(stamp == ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project))
stamp = ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project)
PostprocessReformattingAspect.getInstance(getProject()).doPostponedFormatting()
PsiManager.getInstance(getProject()).reloadFromDisk(file)
assertTrue(stamp != ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project))
assert findClass("Foo") != null
PsiDocumentManager.getInstance(getProject()).commitAllDocuments()
assertTrue(stamp != ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project))
stamp = ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project)
findClass("Foo").replace(findClass("Foo").copy())
assert findClass("Foo") != null
assertTrue(stamp == ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project))
}
}
void "test non empty memory storage cleanup advances index modification stamp"() {
def stamp = ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project)
def file = myFixture.addClass("class Foo {}").getContainingFile()
assert findClass("Foo")
assertTrue(stamp != ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project))
stamp = ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project)
WriteCommandAction.runWriteCommandAction(project) { ((PsiJavaFile)file).getImportList().add(JavaPsiFacade.getElementFactory(getProject()).createImportStatementOnDemand("java.io")) }
assert findClass("Foo")
assertTrue(stamp != ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project))
stamp = ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project)
WriteCommandAction.runWriteCommandAction(project) { ((FileDocumentManagerImpl)FileDocumentManager.instance).dropAllUnsavedDocuments() }
assert findClass("Foo")
assertTrue(stamp != ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(StubUpdatingIndex.INDEX_ID, project))
}
void "test index clear increments modification stamp"() {
StringIndex index = createIndex(getTestName(false), new EnumeratorStringDescriptor(), false)
try {
def stamp = index.getModificationStamp()
index.clear();
assertTrue(stamp != index.getModificationStamp())
}
finally {
index.dispose()
}
}
void "test unsaved document is still indexed on dumb mode ignoring access"() {
def file = (PsiJavaFile)myFixture.addFileToProject("Foo.java", "class Foo {}")
def nameIdentifier = file.getClasses()[0].getNameIdentifier()
def project = getProject()
def dumbService = (DumbServiceImpl)DumbService.getInstance(project)
def virtualFile = file.getVirtualFile()
assertTrue(findWordInDumbMode("Foo", virtualFile, false))
assertFalse(findWordInDumbMode("Bar", virtualFile, false))
dumbService.setDumb(true)
try {
assertTrue(findWordInDumbMode("Foo", virtualFile, true))
assertFalse(findWordInDumbMode("Bar", virtualFile, true))
WriteCommandAction.runWriteCommandAction(project) { nameIdentifier.replace(JavaPsiFacade.getElementFactory(project).createIdentifier("Bar")) }
assertTrue(FileDocumentManager.instance.isDocumentUnsaved(PsiDocumentManager.getInstance(project).getDocument(file)))
assertTrue(findWordInDumbMode("Bar", virtualFile, true))
assertFalse(findWordInDumbMode("Foo", virtualFile, true))
}
finally {
dumbService.setDumb(false)
}
assertTrue(findWordInDumbMode("Bar", virtualFile, false))
assertFalse(findWordInDumbMode("Foo", virtualFile, false))
}
void "test change file type association from groovy to java"() {
@org.intellij.lang.annotations.Language("JAVA")
def text = "class Foo { void m() {" +
" String x = 'qwerty';" +
"}}"
def file = myFixture.addFileToProject("Foo.groovy", text)
def virtualFile = file.virtualFile
def idIndexData = getIdIndexData(virtualFile)
assertTrue(idIndexData.containsKey(new IdIndexEntry("Foo", false)))
assertTrue(idIndexData.containsKey(new IdIndexEntry("qwerty", false)))
assertEquals(UsageSearchContext.IN_STRINGS | UsageSearchContext.IN_CODE, idIndexData.get(new IdIndexEntry("qwerty", false)))
assertEquals(GroovyFileType.GROOVY_FILE_TYPE, FileTypeIndex.getIndexedFileType(virtualFile, getProject()))
def stub = StubTreeLoader.getInstance().readFromVFile(getProject(), virtualFile)
assertStubLanguage(GroovyLanguage.INSTANCE, stub)
assertEquals(GroovyLanguage.INSTANCE, file.getLanguage())
assert findClass("Foo")
def matcher = new ExactFileNameMatcher("Foo.groovy")
try {
WriteCommandAction.runWriteCommandAction(project) { FileTypeManager.getInstance().associate(JavaFileType.INSTANCE, matcher) }
assertEquals(JavaFileType.INSTANCE, FileTypeIndex.getIndexedFileType(virtualFile, getProject()))
stub = StubTreeLoader.getInstance().readFromVFile(getProject(), virtualFile)
assertStubLanguage(JavaLanguage.INSTANCE, stub)
idIndexData = getIdIndexData(virtualFile)
assertTrue(idIndexData.containsKey(new IdIndexEntry("Foo", false)))
assertFalse(idIndexData.containsKey(new IdIndexEntry("qwerty", false)))
def javaFooClass = findClass("Foo")
assertEquals(JavaLanguage.INSTANCE, javaFooClass.getLanguage())
}
finally {
WriteCommandAction.runWriteCommandAction(project) { FileTypeManager.getInstance().removeAssociation(JavaFileType.INSTANCE, matcher) }
}
}
void "test composite index with snapshot mappings hash id"() {
def groovyFileId = ((VirtualFileWithId)myFixture.addFileToProject("Foo.groovy", "class Foo {}").virtualFile).getId()
def javaFileId = ((VirtualFileWithId)myFixture.addFileToProject("Foo.java", "class Foo {}").virtualFile).getId()
def fbi = FileBasedIndex.getInstance()
fbi.ensureUpToDate(IdIndex.NAME, getProject(), GlobalSearchScope.allScope(getProject()))
fbi.ensureUpToDate(TrigramIndex.INDEX_ID, getProject(), GlobalSearchScope.allScope(getProject()))
def idIndex = ((FileBasedIndexImpl)fbi).getIndex(IdIndex.NAME)
def trigramIndex = ((FileBasedIndexImpl)fbi).getIndex(TrigramIndex.INDEX_ID)
assertTrue(FileBasedIndex.ourSnapshotMappingsEnabled)
def idIndexForwardIndex = (IntForwardIndex)((VfsAwareMapReduceIndex)idIndex).getForwardIndex()
def trigramIndexForwardIndex = (IntForwardIndex)((VfsAwareMapReduceIndex)trigramIndex).getForwardIndex()
// id index depends on file type
assertFalse(idIndexForwardIndex.getInt(javaFileId) == 0)
assertFalse(idIndexForwardIndex.getInt(groovyFileId) == 0)
assertFalse(idIndexForwardIndex.getInt(groovyFileId) == idIndexForwardIndex.getInt(javaFileId))
// trigram index is not a composite index
assertFalse(trigramIndexForwardIndex.getInt(javaFileId) == 0)
assertFalse(trigramIndexForwardIndex.getInt(groovyFileId) == 0)
// for trigram index the assertion above can be broken by definition of trigram index
// assertFalse(trigramIndexForwardIndex.getInt(groovyFileId) == trigramIndexForwardIndex.getInt(javaFileId))
}
private boolean findWordInDumbMode(String word, VirtualFile file, boolean inDumbMode) {
assertTrue(DumbService.isDumb(getProject()) == inDumbMode)
assertTrue(FileBasedIndex.isIndexAccessDuringDumbModeEnabled())
def wordHash = new IdIndexEntry(word, true)
def scope = GlobalSearchScope.allScope(project)
def fileBasedIndex = FileBasedIndex.instance
boolean found = false
def runnable = {
found = fileBasedIndex.getContainingFiles(IdIndex.NAME, wordHash, scope).contains(file)
}
if (inDumbMode) {
fileBasedIndex.ignoreDumbMode(DumbModeAccessType.RAW_INDEX_DATA_ACCEPTABLE, runnable)
}
else {
runnable.run()
}
return found
}
private static assertStubLanguage(@NotNull Language expectedLanguage, @NotNull ObjectStubTree stub) {
def parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(expectedLanguage)
assertEquals(parserDefinition.getFileNodeType(), stub.getPlainList().get(0).getType())
}
@NotNull
private Map<IdIndexEntry, Integer> getIdIndexData(@NotNull VirtualFile file) {
FileBasedIndex.getInstance().getFileData(IdIndex.NAME, file, getProject())
}
void 'test no caching for index queries with different ignoreDumbMode kinds'() {
RecursionManager.disableMissedCacheAssertions(testRootDisposable)
def clazz = myFixture.addClass('class Foo {}')
assert clazz == myFixture.findClass('Foo')
DumbServiceImpl.getInstance(project).setDumb(true)
def indexQueries = 0
def plainQueries = 0
def stubQuery = CachedValuesManager.getManager(project).createCachedValue {
indexQueries++
CachedValueProvider.Result.create(myFixture.findClass('Foo'), PsiModificationTracker.MODIFICATION_COUNT)
}
def idQuery = CachedValuesManager.getManager(project).createCachedValue {
indexQueries++
GlobalSearchScope fileScope = GlobalSearchScope.fileScope(clazz.containingFile);
IdIndexEntry key = new IdIndexEntry('Foo', true);
def hasId = !FileBasedIndex.instance.getContainingFiles(IdIndex.NAME, key, fileScope).isEmpty()
CachedValueProvider.Result.create(hasId, PsiModificationTracker.MODIFICATION_COUNT)
}
def plainValue = CachedValuesManager.getManager(project).createCachedValue {
plainQueries++
CachedValueProvider.Result.create("x", PsiModificationTracker.MODIFICATION_COUNT)
}
// index queries aren't cached
5.times {
assert clazz == FileBasedIndex.instance.ignoreDumbMode(DumbModeAccessType.RELIABLE_DATA_ONLY, asComputable(stubQuery))
}
assert indexQueries >= 5
indexQueries = 0
assert FileBasedIndex.instance.ignoreDumbMode(DumbModeAccessType.RAW_INDEX_DATA_ACCEPTABLE, asComputable(idQuery))
assert FileBasedIndex.instance.ignoreDumbMode(DumbModeAccessType.RELIABLE_DATA_ONLY, asComputable(idQuery))
assert indexQueries >= 2
// non-index queries should work as usual
3.times {
assert "x" == FileBasedIndex.instance.ignoreDumbMode(DumbModeAccessType.RAW_INDEX_DATA_ACCEPTABLE, asComputable(plainValue))
assert "x" == FileBasedIndex.instance.ignoreDumbMode(DumbModeAccessType.RELIABLE_DATA_ONLY, asComputable(plainValue))
}
assert plainQueries > 0 && plainQueries < 3*2
// cache queries inside single ignoreDumbMode
indexQueries = 0
psiManager.dropPsiCaches()
FileBasedIndex.instance.ignoreDumbMode(DumbModeAccessType.RAW_INDEX_DATA_ACCEPTABLE) {
5.times {assert idQuery.getValue() }
assert indexQueries > 0 && indexQueries < 5
}
indexQueries = 0
psiManager.dropPsiCaches()
FileBasedIndex.instance.ignoreDumbMode(DumbModeAccessType.RELIABLE_DATA_ONLY) {
5.times {assert clazz == stubQuery.getValue() }
assert indexQueries > 0 && indexQueries < 5
}
}
void 'test no caching on write action inside ignoreDumbMode'() {
RecursionManager.disableMissedCacheAssertions(testRootDisposable)
def clazz = myFixture.addClass('class Foo {}')
assert clazz == myFixture.findClass('Foo')
DumbServiceImpl.getInstance(project).setDumb(true)
def stubQuery = CachedValuesManager.getManager(project).createCachedValue {
CachedValueProvider.Result.create(myFixture.javaFacade.findClass('Foo', GlobalSearchScope.allScope(project)),
PsiModificationTracker.MODIFICATION_COUNT)
}
FileBasedIndex.instance.ignoreDumbMode(DumbModeAccessType.RELIABLE_DATA_ONLY) {
assert clazz == stubQuery.getValue()
WriteCommandAction.runWriteCommandAction(project) {
clazz.setName('Bar')
}
assert null == stubQuery.getValue()
}
}
void 'test indexes should be wiped after scratch removal'() {
def file = ScratchRootType.getInstance().createScratchFile(project, "Foo.java", JavaLanguage.INSTANCE, "class Foo {}")
def fileId = ((VirtualFileWithId)file).getId()
def fileBasedIndex = (FileBasedIndexImpl)FileBasedIndex.instance
def trigramId = TrigramIndex.INDEX_ID
fileBasedIndex.ensureUpToDate(trigramId, project, GlobalSearchScope.everythingScope(project))
assertNotEmpty(fileBasedIndex.getIndex(trigramId).getIndexedFileData(fileId).values())
WriteCommandAction.runWriteCommandAction(project) { file.delete(null) }
fileBasedIndex.ensureUpToDate(trigramId, project, GlobalSearchScope.everythingScope(project))
assertEmpty(fileBasedIndex.getIndex(trigramId).getIndexedFileData(fileId).values())
}
void 'test requestReindex'() {
def file = ScratchRootType.getInstance().createScratchFile(project, "Foo.java", JavaLanguage.INSTANCE, "class Foo {}")
def text = "<fileBasedIndex implementation=\"" + CountingFileBasedIndexExtension.class.getName() + "\"/>"
Disposer.register(testRootDisposable, loadExtensionWithText(text, CountingFileBasedIndexExtension.class.classLoader))
FileBasedIndex.getInstance().getFileData(CountingFileBasedIndexExtension.INDEX_ID, file, project)
assertTrue(CountingFileBasedIndexExtension.COUNTER.get() > 0)
CountingFileBasedIndexExtension.COUNTER.set(0)
FileBasedIndex.instance.requestReindex(file)
FileBasedIndex.getInstance().getFileData(CountingFileBasedIndexExtension.INDEX_ID, file, project)
assertTrue(CountingFileBasedIndexExtension.COUNTER.get() > 0)
}
void 'test modified excluded file not present in index'() {
// we don't update excluded file index data, so we should wipe it to be consistent
def file = myFixture.addFileToProject("src/to_be_excluded/A.java", "class A {}").virtualFile
assertNotNull(findClass("A"))
def fileBasedIndex = (FileBasedIndexImpl)FileBasedIndex.instance
def trigramId = TrigramIndex.INDEX_ID
def fileId = ((VirtualFileWithId)file).getId()
fileBasedIndex.ensureUpToDate(trigramId, project, GlobalSearchScope.everythingScope(project))
assertNotEmpty(fileBasedIndex.getIndex(trigramId).getIndexedFileData(fileId).values())
def parentDir = file.parent
PsiTestUtil.addExcludedRoot(myFixture.getModule(), parentDir)
WriteAction.run { VfsUtil.saveText(file, "class B {}") }
fileBasedIndex.ensureUpToDate(trigramId, project, GlobalSearchScope.everythingScope(project))
assertEmpty(fileBasedIndex.getIndex(trigramId).getIndexedFileData(fileId).values())
assertFalse(((VirtualFileSystemEntry)file).isFileIndexed())
}
private static <T> ThrowableComputable<T, RuntimeException> asComputable(CachedValue<T> cachedValue) {
return new ThrowableComputable<T, RuntimeException>() {
@Override
T compute() throws RuntimeException {
return cachedValue.getValue()
}
}
}
}