mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
search java direct inheritors using javac indices (initial): do not process lots of non-direct inheritors for library classes (IDEA-CR-14364)
This commit is contained in:
@@ -88,17 +88,11 @@ class CompilerReferenceReader {
|
||||
@NotNull GlobalSearchScope searchScope,
|
||||
@NotNull GlobalSearchScope dirtyScope,
|
||||
@NotNull Project project,
|
||||
FileType fileType) {
|
||||
@NotNull FileType fileType) {
|
||||
if (classSearchElementInfo == null) return null;
|
||||
LOG.assertTrue(classSearchElementInfo.searchElements.length == 1);
|
||||
|
||||
CompilerBackwardReferenceIndex.LightDefinition[] candidates =
|
||||
Stream.of(classSearchElementInfo.searchElements)
|
||||
.map(this::asLightUsage)
|
||||
.map(myIndex.getBackwardHierarchyMap()::get)
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
.toArray(CompilerBackwardReferenceIndex.LightDefinition[]::new);
|
||||
|
||||
Collection<CompilerBackwardReferenceIndex.LightDefinition> candidates = myIndex.getBackwardHierarchyMap().get(asLightUsage(classSearchElementInfo.searchElements[0]));
|
||||
if (candidates == null) return Couple.of(Collections.emptyMap(), Collections.emptyMap());
|
||||
|
||||
Set<Class<? extends LightUsage>> suitableClasses = new THashSet<>();
|
||||
@@ -111,7 +105,8 @@ class CompilerReferenceReader {
|
||||
|
||||
final GlobalSearchScope effectiveSearchScope = GlobalSearchScope.notScope(dirtyScope).intersectWith(searchScope);
|
||||
|
||||
Map<VirtualFile, SmartList<String>> candidatesPerFile = Stream.of(candidates)
|
||||
Map<VirtualFile, SmartList<String>> candidatesPerFile = candidates
|
||||
.stream()
|
||||
.filter(def -> suitableClasses.contains(def.getUsage().getClass()))
|
||||
.map(definition -> {
|
||||
final VirtualFile file = findFile(definition.getFileId());
|
||||
|
||||
@@ -25,17 +25,15 @@ import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.roots.impl.LibraryScopeCache;
|
||||
import com.intellij.openapi.util.Couple;
|
||||
import com.intellij.openapi.util.ModificationTracker;
|
||||
import com.intellij.openapi.util.UserDataHolderBase;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiNamedElement;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.psi.util.PsiModificationTracker;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.containers.ConcurrentFactoryMap;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.indexing.FileBasedIndex;
|
||||
@@ -204,9 +202,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
|
||||
@NotNull GlobalSearchScope searchScope,
|
||||
@NotNull ClassResolvingCompilerSearchAdapter<T> inheritorSearchAdapter,
|
||||
@NotNull FileType searchFileType) {
|
||||
if (!isServiceEnabled() ||
|
||||
InjectedLanguageManager.getInstance(myProject).isInjectedFragment(aClass.getContainingFile()) ||
|
||||
!myProjectFileIndex.isInSourceContent(aClass.getContainingFile().getVirtualFile())) return null;
|
||||
if (!isServiceEnabled() || InjectedLanguageManager.getInstance(myProject).isInjectedFragment(aClass.getContainingFile())) return null;
|
||||
|
||||
Couple<Map<VirtualFile, T[]>> directInheritorsAndCandidates =
|
||||
CachedValuesManager.getCachedValue(aClass, () -> CachedValueProvider.Result.create(calculateDirectInheritors(aClass,
|
||||
@@ -217,7 +213,11 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
|
||||
this));
|
||||
|
||||
if (directInheritorsAndCandidates == null) return null;
|
||||
return new CompilerDirectInheritorInfoImpl<>(directInheritorsAndCandidates, myDirtyModulesHolder.getDirtyScope(), searchScope);
|
||||
GlobalSearchScope dirtyScope = myDirtyModulesHolder.getDirtyScope();
|
||||
if (ElementPlace.LIB == ElementPlace.get(aClass.getContainingFile().getVirtualFile(), myProjectFileIndex)) {
|
||||
dirtyScope = dirtyScope.union(LibraryScopeCache.getInstance(myProject).getLibrariesOnlyScope());
|
||||
}
|
||||
return new CompilerDirectInheritorInfoImpl<>(directInheritorsAndCandidates, dirtyScope, searchScope);
|
||||
}
|
||||
|
||||
private boolean isServiceEnabled() {
|
||||
@@ -227,8 +227,8 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
|
||||
private <T extends PsiNamedElement> Couple<Map<VirtualFile, T[]>> calculateDirectInheritors(@NotNull PsiNamedElement aClass,
|
||||
@NotNull ClassResolvingCompilerSearchAdapter<T> searchAdapter,
|
||||
@NotNull GlobalSearchScope useScope,
|
||||
FileType searchFileType) {
|
||||
final CompilerElementInfo searchElementInfo = asCompilerElements(aClass, searchAdapter);
|
||||
@NotNull FileType searchFileType) {
|
||||
final CompilerElementInfo searchElementInfo = asCompilerElements(aClass, searchAdapter, false);
|
||||
synchronized (myLock) {
|
||||
if (myReader == null) return null;
|
||||
return myReader.getDirectInheritors(aClass,
|
||||
@@ -252,7 +252,7 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
|
||||
|
||||
@Nullable
|
||||
private TIntHashSet getReferentFileIds(@NotNull PsiElement element, @NotNull CompilerSearchAdapter adapter) {
|
||||
final CompilerElementInfo compilerElementInfo = asCompilerElements(element, adapter);
|
||||
final CompilerElementInfo compilerElementInfo = asCompilerElements(element, adapter, true);
|
||||
if (compilerElementInfo == null) return null;
|
||||
|
||||
synchronized (myLock) {
|
||||
@@ -268,27 +268,24 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private CompilerElementInfo asCompilerElements(@NotNull PsiElement element, @NotNull CompilerSearchAdapter adapter) {
|
||||
final PsiFile file = element.getContainingFile();
|
||||
if (file == null) return null;
|
||||
final VirtualFile vFile = file.getVirtualFile();
|
||||
if (vFile == null) return null;
|
||||
|
||||
ElementPlace place = ElementPlace.get(vFile, myProjectFileIndex);
|
||||
if (place == null) {
|
||||
private CompilerElementInfo asCompilerElements(@NotNull PsiElement psiElement, @NotNull CompilerSearchAdapter adapter, boolean buildHierarchyForLibraryElements) {
|
||||
VirtualFile file = PsiUtilCore.getVirtualFile(psiElement);
|
||||
ElementPlace place = ElementPlace.get(file, myProjectFileIndex);
|
||||
if (place == null || (place == ElementPlace.SRC && myDirtyModulesHolder.contains(file))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (myDirtyModulesHolder.contains(vFile)) {
|
||||
return null;
|
||||
}
|
||||
if (place == ElementPlace.SRC) {
|
||||
final CompilerElement compilerElement = adapter.asCompilerElement(element);
|
||||
return compilerElement == null ? null : new CompilerElementInfo(place, compilerElement);
|
||||
final CompilerElement compilerElement = adapter.asCompilerElement(psiElement);
|
||||
if (compilerElement == null) return null;
|
||||
if (place == ElementPlace.LIB && buildHierarchyForLibraryElements) {
|
||||
final CompilerElement[] elements = adapter.getHierarchyRestrictedToLibrariesScope(compilerElement, psiElement);
|
||||
final CompilerElement[] fullHierarchy = new CompilerElement[elements.length + 1];
|
||||
fullHierarchy[0] = compilerElement;
|
||||
System.arraycopy(elements, 0, fullHierarchy, 1, elements.length);
|
||||
return new CompilerElementInfo(place, fullHierarchy);
|
||||
}
|
||||
else {
|
||||
final CompilerElement[] elements = adapter.libraryElementAsCompilerElements(element);
|
||||
return elements.length == 0 ? null : new CompilerElementInfo(place, elements);
|
||||
return new CompilerElementInfo(place, compilerElement);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,8 +326,8 @@ public class CompilerReferenceServiceImpl extends CompilerReferenceService imple
|
||||
SRC, LIB;
|
||||
|
||||
private static ElementPlace get(VirtualFile file, ProjectFileIndex index) {
|
||||
return index.isInSourceContent(file) ? SRC :
|
||||
((index.isInLibrarySource(file) || index.isInLibraryClasses(file)) ? LIB : null);
|
||||
if (file == null) return null;
|
||||
return index.isInSourceContent(file) ? SRC : ((index.isInLibrarySource(file) || index.isInLibraryClasses(file)) ? LIB : null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ package com.intellij.compiler;
|
||||
public abstract class CompilerElement {
|
||||
public static final CompilerElement[] EMPTY_ARRAY = new CompilerElement[0];
|
||||
|
||||
public abstract CompilerElement override(String overriderName);
|
||||
|
||||
public static class CompilerMethod extends CompilerElement {
|
||||
private final String myJavacClassName;
|
||||
private final String myJavacMethodName;
|
||||
@@ -40,6 +42,11 @@ public abstract class CompilerElement {
|
||||
public int getJavacParameterCount() {
|
||||
return myJavacParameterCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompilerElement override(String overriderName) {
|
||||
return new CompilerMethod(overriderName, myJavacMethodName, myJavacParameterCount);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CompilerClass extends CompilerElement {
|
||||
@@ -52,6 +59,11 @@ public abstract class CompilerElement {
|
||||
public String getJavacName() {
|
||||
return myJavacName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompilerElement override(String overriderName) {
|
||||
return new CompilerClass(myJavacName);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CompilerField extends CompilerElement {
|
||||
@@ -70,6 +82,11 @@ public abstract class CompilerElement {
|
||||
public String getJavacName() {
|
||||
return myJavacName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompilerElement override(String overriderName) {
|
||||
return new CompilerField(overriderName, myJavacName);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CompilerFunExpr extends CompilerElement {
|
||||
@@ -82,5 +99,10 @@ public abstract class CompilerElement {
|
||||
public String getJavacClassName() {
|
||||
return myJavacClassName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompilerElement override(String overriderName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,5 +27,5 @@ public interface CompilerSearchAdapter {
|
||||
CompilerElement asCompilerElement(@NotNull PsiElement psi);
|
||||
|
||||
@NotNull
|
||||
CompilerElement[] libraryElementAsCompilerElements(@NotNull PsiElement psi);
|
||||
CompilerElement[] getHierarchyRestrictedToLibrariesScope(@NotNull CompilerElement baseLibraryElement, @NotNull PsiElement baseLibraryPsi);
|
||||
}
|
||||
|
||||
+12
-48
@@ -26,18 +26,15 @@ import com.intellij.psi.impl.java.stubs.impl.PsiClassStubImpl;
|
||||
import com.intellij.psi.impl.source.PsiFileImpl;
|
||||
import com.intellij.psi.impl.source.PsiFileWithStubSupport;
|
||||
import com.intellij.psi.search.searches.ClassInheritorsSearch;
|
||||
import com.intellij.psi.stubs.StubBase;
|
||||
import com.intellij.psi.stubs.StubElement;
|
||||
import com.intellij.psi.stubs.StubTree;
|
||||
import com.intellij.psi.util.ClassUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.Processor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class JavaBaseCompilerSearchAdapter implements ClassResolvingCompilerSearchAdapter<PsiClass> {
|
||||
public static final JavaBaseCompilerSearchAdapter INSTANCE = new JavaBaseCompilerSearchAdapter();
|
||||
@@ -82,43 +79,18 @@ public class JavaBaseCompilerSearchAdapter implements ClassResolvingCompilerSear
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CompilerElement[] libraryElementAsCompilerElements(@NotNull PsiElement element) {
|
||||
if (mayBeVisibleOutsideOwnerFile(element)) {
|
||||
if (element instanceof PsiField || element instanceof PsiMethod) {
|
||||
final String name = ((PsiMember)element).getName();
|
||||
|
||||
final Function<String, CompilerElement> builder;
|
||||
if (element instanceof PsiField) {
|
||||
builder = (ownerJvmName) -> new CompilerElement.CompilerField(ownerJvmName, name);
|
||||
}
|
||||
else {
|
||||
final int parametersCount = ((PsiMethod)element).getParameterList().getParametersCount();
|
||||
builder = (ownerJvmName) -> new CompilerElement.CompilerMethod(ownerJvmName, name, parametersCount);
|
||||
}
|
||||
|
||||
final List<CompilerElement> result = new ArrayList<>();
|
||||
inLibrariesHierarchy(((PsiMember)element).getContainingClass(), aClass -> {
|
||||
final String jvmClassName = ClassUtil.getJVMClassName(aClass);
|
||||
if (jvmClassName != null) {
|
||||
result.add(builder.apply(jvmClassName));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return result.toArray(new CompilerElement[result.size()]);
|
||||
}
|
||||
else if (element instanceof PsiClass) {
|
||||
final List<CompilerElement> result = new ArrayList<>();
|
||||
inLibrariesHierarchy((PsiClass)element, aClass -> {
|
||||
final String jvmClassName = ClassUtil.getJVMClassName(aClass);
|
||||
if (jvmClassName != null) {
|
||||
result.add(new CompilerElement.CompilerClass(jvmClassName));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return result.toArray(new CompilerElement[result.size()]);
|
||||
}
|
||||
}
|
||||
return CompilerElement.EMPTY_ARRAY;
|
||||
public CompilerElement[] getHierarchyRestrictedToLibrariesScope(@NotNull CompilerElement baseLibraryElement, @NotNull PsiElement baseLibraryPsi) {
|
||||
final PsiClass baseClass = ObjectUtils.notNull(baseLibraryPsi instanceof PsiClass ? (PsiClass)baseLibraryPsi : ((PsiMember)baseLibraryPsi).getContainingClass());
|
||||
final List<CompilerElement> overridden = new ArrayList<>();
|
||||
Processor<PsiClass> processor = c -> {
|
||||
if (c.hasModifierProperty(PsiModifier.PRIVATE)) return true;
|
||||
String qName = c.getQualifiedName();
|
||||
if (qName == null) return true;
|
||||
overridden.add(baseLibraryElement.override(qName));
|
||||
return true;
|
||||
};
|
||||
ClassInheritorsSearch.search(baseClass, LibraryScopeCache.getInstance(baseClass.getProject()).getLibrariesOnlyScope(), true).forEach(processor);
|
||||
return overridden.toArray(new CompilerElement[overridden.size()]);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -137,14 +109,6 @@ public class JavaBaseCompilerSearchAdapter implements ClassResolvingCompilerSear
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void inLibrariesHierarchy(PsiClass aClass, Processor<PsiClass> processor) {
|
||||
if (aClass != null) {
|
||||
processor.process(aClass);
|
||||
ClassInheritorsSearch.search(aClass, LibraryScopeCache.getInstance(aClass.getProject()).getLibrariesOnlyScope(), true)
|
||||
.forEach(processor);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<PsiClass> retrieveMatchedClasses(VirtualFile file, Project project, Collection<InternalClassMatcher> matchers) {
|
||||
final List<PsiClass> result = new ArrayList<>(matchers.size());
|
||||
PsiFileWithStubSupport psiFile = ObjectUtils.notNull((PsiFileWithStubSupport)PsiManager.getInstance(project).findFile(file));
|
||||
|
||||
+2
-3
@@ -39,8 +39,7 @@ public class JavaFunctionalExpressionCompilerSearchAdapter implements CompilerSe
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CompilerElement[] libraryElementAsCompilerElements(@NotNull PsiElement psi) {
|
||||
final CompilerElement element = asCompilerElement(psi);
|
||||
return element == null ? CompilerElement.EMPTY_ARRAY : new CompilerElement[] {element};
|
||||
public CompilerElement[] getHierarchyRestrictedToLibrariesScope(@NotNull CompilerElement baseLibraryElement, @NotNull PsiElement baseLibraryPsi) {
|
||||
return CompilerElement.EMPTY_ARRAY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import java.util.List;
|
||||
import java.util.AbstractList;
|
||||
|
||||
class Foo {
|
||||
|
||||
interface ListImpl extends List {
|
||||
|
||||
}
|
||||
|
||||
abstract static class AbstractListImpl extends AbstractList {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,10 +20,7 @@ import com.intellij.codeInsight.completion.AbstractCompilerAwareTest;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.PsiAnonymousClass;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiMember;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.testFramework.SkipSlowTestLocally;
|
||||
@@ -101,17 +98,28 @@ public class CompilerReferencesTest extends AbstractCompilerAwareTest {
|
||||
assertEmpty(candidates);
|
||||
}
|
||||
|
||||
public void testHierarchyOfLibClass() {
|
||||
myFixture.configureByFiles(getName() + "/Foo.java");
|
||||
rebuildProject();
|
||||
CompilerReferenceService.CompilerDirectInheritorInfo<PsiClass> directInheritorInfo = getHierarchyFor(myFixture.getJavaFacade().findClass(CommonClassNames.JAVA_UTIL_LIST));
|
||||
PsiClass inheritor = assertOneElement(directInheritorInfo.getDirectInheritors().collect(Collectors.toList()));
|
||||
assertEquals("Foo.ListImpl", inheritor.getQualifiedName());
|
||||
}
|
||||
|
||||
private CompilerReferenceService.CompilerDirectInheritorInfo<PsiClass> getHierarchyUnderForElementCaret() {
|
||||
final PsiElement atCaret = myFixture.getElementAtCaret();
|
||||
assertNotNull(atCaret);
|
||||
final PsiClass classAtCaret = PsiTreeUtil.getParentOfType(atCaret, PsiClass.class, false);
|
||||
assertNotNull(classAtCaret);
|
||||
return getHierarchyFor(classAtCaret);
|
||||
}
|
||||
|
||||
private CompilerReferenceService.CompilerDirectInheritorInfo<PsiClass> getHierarchyFor(PsiClass classAtCaret) {
|
||||
return CompilerReferenceService.getInstance(myFixture.getProject()).getDirectInheritors(classAtCaret,
|
||||
assertInstanceOf(classAtCaret.getUseScope(), GlobalSearchScope.class),
|
||||
assertInstanceOf(classAtCaret.getUseScope(), GlobalSearchScope.class),
|
||||
JavaBaseCompilerSearchAdapter.INSTANCE,
|
||||
StdFileTypes.JAVA);
|
||||
|
||||
}
|
||||
|
||||
private Set<VirtualFile> getReferentFilesForElementUnderCaret(CompilerSearchAdapter adapter) {
|
||||
|
||||
Reference in New Issue
Block a user