mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
more efficient use of indices in stub hierarchy
This commit is contained in:
@@ -19,13 +19,11 @@ import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressIndicatorProvider;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.openapi.vfs.VirtualFileWithId;
|
||||
import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
|
||||
import com.intellij.psi.search.DelegatingGlobalSearchScope;
|
||||
import com.intellij.psi.search.EverythingGlobalScope;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.stubsHierarchy.HierarchyService;
|
||||
import com.intellij.psi.util.CachedValue;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
@@ -33,17 +31,18 @@ import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.psi.util.PsiModificationTracker;
|
||||
import com.intellij.util.CachedValueBase;
|
||||
import com.intellij.util.indexing.FileBasedIndex;
|
||||
import com.intellij.util.indexing.FileBasedIndexImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
public class HierarchyServiceImpl extends HierarchyService {
|
||||
private static final SingleClassHierarchy EMPTY_HIERARCHY = new SingleClassHierarchy(Symbol.ClassSymbol.EMPTY_ARRAY);
|
||||
private final Project myProject;
|
||||
private final ProjectFileIndex myFileIndex;
|
||||
private final CachedValue<SingleClassHierarchy> myHierarchy;
|
||||
|
||||
public HierarchyServiceImpl(Project project) {
|
||||
myProject = project;
|
||||
myFileIndex = ProjectFileIndex.SERVICE.getInstance(project);
|
||||
myHierarchy = CachedValuesManager.getManager(project).createCachedValue(
|
||||
() -> CachedValueProvider.Result.create(buildHierarchy(), PsiModificationTracker.MODIFICATION_COUNT),
|
||||
false);
|
||||
@@ -69,38 +68,56 @@ public class HierarchyServiceImpl extends HierarchyService {
|
||||
private SingleClassHierarchy buildHierarchy() {
|
||||
Symbols symbols = new Symbols();
|
||||
StubEnter stubEnter = new StubEnter(symbols);
|
||||
IdSets idSets = IdSets.getIdSets(myProject);
|
||||
|
||||
loadUnits(false, symbols.myNameEnvironment, stubEnter);
|
||||
loadUnits(idSets.libraryFiles, StubHierarchyIndex.BINARY_FILES, symbols.myNameEnvironment, stubEnter);
|
||||
stubEnter.connect1();
|
||||
|
||||
loadUnits(true, symbols.myNameEnvironment, stubEnter);
|
||||
loadUnits(idSets.sourceFiles, StubHierarchyIndex.SOURCE_FILES, symbols.myNameEnvironment, stubEnter);
|
||||
stubEnter.connect2();
|
||||
|
||||
return symbols.createHierarchy();
|
||||
}
|
||||
|
||||
private void loadUnits(boolean sourceMode, NameEnvironment names, StubEnter stubEnter) {
|
||||
GlobalSearchScope scope = new DelegatingGlobalSearchScope(new EverythingGlobalScope(myProject)) {
|
||||
@Override
|
||||
public boolean contains(@NotNull VirtualFile file) {
|
||||
return sourceMode ? myFileIndex.isInSourceContent(file) : myFileIndex.isInLibraryClasses(file);
|
||||
}
|
||||
};
|
||||
private void loadUnits(BitSet files, int indexKey, NameEnvironment names, StubEnter stubEnter) {
|
||||
ProgressIndicator indicator = ProgressIndicatorProvider.getGlobalProgressIndicator();
|
||||
FileBasedIndex index = FileBasedIndex.getInstance();
|
||||
for (String packageName : index.getAllKeys(StubHierarchyIndex.INDEX_ID, myProject)) {
|
||||
QualifiedName pkg = StringUtil.isEmpty(packageName) ? null : names.fromString(packageName, true);
|
||||
index.processValues(StubHierarchyIndex.INDEX_ID, packageName, null, new FileBasedIndex.ValueProcessor<IndexTree.Unit>() {
|
||||
int count = 0;
|
||||
|
||||
@Override
|
||||
public boolean process(VirtualFile file, IndexTree.Unit unit) {
|
||||
if (indicator != null && ++count % 128 == 0) indicator.checkCanceled();
|
||||
stubEnter.unitEnter(Translator.internNames(names, unit, ((VirtualFileWithId)file).getId(), pkg));
|
||||
return true;
|
||||
FileBasedIndexImpl index = (FileBasedIndexImpl)FileBasedIndex.getInstance();
|
||||
index.processAllValues(StubHierarchyIndex.INDEX_ID, indexKey, myProject, new FileBasedIndexImpl.IdValueProcessor<IndexTree.Unit>() {
|
||||
int count = 0;
|
||||
@Override
|
||||
public boolean process(int fileId, IndexTree.Unit unit) {
|
||||
if (indicator != null && ++count % 128 == 0) indicator.checkCanceled();
|
||||
if (files.get(fileId)) {
|
||||
QualifiedName pkg = StringUtil.isEmpty(unit.myPackageId) ? null : names.fromString(unit.myPackageId, true);
|
||||
stubEnter.unitEnter(Translator.internNames(names, unit, fileId, pkg));
|
||||
}
|
||||
}, scope);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static class IdSets {
|
||||
final BitSet sourceFiles = new BitSet();
|
||||
final BitSet libraryFiles = new BitSet();
|
||||
|
||||
static IdSets getIdSets(@NotNull Project project) {
|
||||
return CachedValuesManager.getManager(project).getCachedValue(project, () -> {
|
||||
IdSets answer = new IdSets();
|
||||
ProjectFileIndex index = ProjectFileIndex.SERVICE.getInstance(project);
|
||||
FileBasedIndex.getInstance().iterateIndexableFiles(file -> {
|
||||
if (!file.isDirectory() && file instanceof VirtualFileWithId) {
|
||||
if (index.isInSourceContent(file)) {
|
||||
answer.sourceFiles.set(((VirtualFileWithId) file).getId());
|
||||
}
|
||||
else if (index.isInLibraryClasses(file)) {
|
||||
answer.libraryFiles.set(((VirtualFileWithId) file).getId());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}, project, ProgressIndicatorProvider.getGlobalProgressIndicator());
|
||||
return CachedValueProvider.Result.create(answer, ProjectRootManager.getInstance(project), VirtualFileManager.VFS_STRUCTURE_MODIFICATIONS);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.intellij.psi.stubsHierarchy.impl;
|
||||
import com.intellij.ide.highlighter.JavaClassFileType;
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiModifier;
|
||||
import com.intellij.psi.PsiNameHelper;
|
||||
@@ -39,7 +38,10 @@ import com.intellij.util.indexing.FileContent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class JavaStubIndexer extends StubHierarchyIndexer {
|
||||
|
||||
@@ -61,7 +63,7 @@ public class JavaStubIndexer extends StubHierarchyIndexer {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<Pair<String, Unit>> indexFile(@NotNull FileContent content) {
|
||||
public Unit indexFile(@NotNull FileContent content) {
|
||||
Stub stubTree = StubTreeBuilder.buildStubTree(content);
|
||||
if (!(stubTree instanceof PsiJavaFileStub)) return null;
|
||||
|
||||
@@ -87,7 +89,7 @@ public class JavaStubIndexer extends StubHierarchyIndexer {
|
||||
ClassDecl[] classes = classList.isEmpty() ? ClassDecl.EMPTY_ARRAY : classList.toArray(new ClassDecl[classList.size()]);
|
||||
Import[] imports = importList.isEmpty() ? Import.EMPTY_ARRAY : importList.toArray(new Import[importList.size()]);
|
||||
byte type = javaFileStub.isCompiled() ? IndexTree.BYTECODE : IndexTree.JAVA;
|
||||
return Collections.singletonList(Pair.create(javaFileStub.getPackageName(), new Unit(type, imports, classes)));
|
||||
return new Unit(javaFileStub.getPackageName(), type, imports, classes);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -18,47 +18,42 @@ package com.intellij.psi.stubsHierarchy.impl;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
|
||||
import com.intellij.psi.impl.java.stubs.index.JavaUnitDescriptor;
|
||||
import com.intellij.psi.stubsHierarchy.StubHierarchyIndexer;
|
||||
import com.intellij.util.indexing.*;
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.EnumeratorStringDescriptor;
|
||||
import com.intellij.util.io.EnumeratorIntegerDescriptor;
|
||||
import com.intellij.util.io.KeyDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class StubHierarchyIndex extends FileBasedIndexExtension<String, IndexTree.Unit> implements PsiDependentIndex {
|
||||
static final ID<String, IndexTree.Unit> INDEX_ID = ID.create("jvm.hierarchy");
|
||||
public class StubHierarchyIndex extends FileBasedIndexExtension<Integer, IndexTree.Unit> implements PsiDependentIndex {
|
||||
public static final int BINARY_FILES = 0;
|
||||
public static final int SOURCE_FILES = 1;
|
||||
static final ID<Integer, IndexTree.Unit> INDEX_ID = ID.create("jvm.hierarchy");
|
||||
private static final StubHierarchyIndexer[] ourIndexers = StubHierarchyIndexer.EP_NAME.getExtensions();
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ID<String, IndexTree.Unit> getName() {
|
||||
public ID<Integer, IndexTree.Unit> getName() {
|
||||
return INDEX_ID;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DataIndexer<String, IndexTree.Unit, FileContent> getIndexer() {
|
||||
public DataIndexer<Integer, IndexTree.Unit, FileContent> getIndexer() {
|
||||
return inputData -> {
|
||||
for (StubHierarchyIndexer indexer : ourIndexers) {
|
||||
List<Pair<String, IndexTree.Unit>> pairs = indexer.handlesFile(inputData.getFile()) ? indexer.indexFile(inputData) : null;
|
||||
if (pairs != null && !pairs.isEmpty()) {
|
||||
Map<String, IndexTree.Unit> answer = new HashMap<>();
|
||||
for (Pair<String, IndexTree.Unit> entry : pairs) {
|
||||
if (entry.second.myDecls.length > 0) {
|
||||
answer.put(StringUtil.notNullize(entry.first), entry.second);
|
||||
}
|
||||
}
|
||||
return answer;
|
||||
IndexTree.Unit unit = indexer.handlesFile(inputData.getFile()) ? indexer.indexFile(inputData) : null;
|
||||
if (unit != null && unit.myDecls.length > 0) {
|
||||
return Collections.singletonMap(inputData.getFile().getFileType().isBinary() ? BINARY_FILES : SOURCE_FILES, unit);
|
||||
}
|
||||
}
|
||||
return Collections.emptyMap();
|
||||
@@ -67,8 +62,8 @@ public class StubHierarchyIndex extends FileBasedIndexExtension<String, IndexTre
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public KeyDescriptor<String> getKeyDescriptor() {
|
||||
return EnumeratorStringDescriptor.INSTANCE;
|
||||
public KeyDescriptor<Integer> getKeyDescriptor() {
|
||||
return EnumeratorIntegerDescriptor.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -79,7 +74,7 @@ public class StubHierarchyIndex extends FileBasedIndexExtension<String, IndexTre
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return IndexTree.STUB_HIERARCHY_ENABLED ? 2 + Arrays.stream(ourIndexers).mapToInt(StubHierarchyIndexer::getVersion).sum() : 0;
|
||||
return IndexTree.STUB_HIERARCHY_ENABLED ? 3 + Arrays.stream(ourIndexers).mapToInt(StubHierarchyIndexer::getVersion).sum() : 0;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
Reference in New Issue
Block a user