mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
use stub hierarchy in DirectClassInheritorsSearch
This commit is contained in:
@@ -15,14 +15,17 @@
|
||||
*/
|
||||
package com.intellij.psi.stubsHierarchy.impl;
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileWithId;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.search.DelegatingGlobalSearchScope;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.stubsHierarchy.ClassHierarchy;
|
||||
import com.intellij.psi.stubsHierarchy.SmartClassAnchor;
|
||||
import com.intellij.psi.stubsHierarchy.impl.Symbol.ClassSymbol;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.indexing.FileBasedIndex;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import gnu.trove.TIntStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
@@ -32,6 +35,7 @@ import java.util.*;
|
||||
*/
|
||||
public class SingleClassHierarchy extends ClassHierarchy {
|
||||
private final BitSet myCoveredFiles;
|
||||
private final BitSet myAmbiguousSupers;
|
||||
private final List<StubClassAnchor> myCoveredClasses;
|
||||
private final StubClassAnchor[] myClassAnchors;
|
||||
private final StubClassAnchor[] myClassAnchorsByFileIds;
|
||||
@@ -42,10 +46,23 @@ public class SingleClassHierarchy extends ClassHierarchy {
|
||||
myCoveredFiles = calcCoveredFiles(classSymbols);
|
||||
myClassAnchors = ContainerUtil.map2Array(classSymbols, StubClassAnchor.class, symbol -> symbol.myClassAnchor);
|
||||
myClassAnchorsByFileIds = mkByFileId(myClassAnchors);
|
||||
excludeUncoveredFiles(classSymbols);
|
||||
connectSubTypes(classSymbols);
|
||||
myAmbiguousSupers = calcAmbiguousSupers(classSymbols);
|
||||
myCoveredClasses = Collections.unmodifiableList(ContainerUtil.filter(myClassAnchors, this::isCovered));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static BitSet calcAmbiguousSupers(ClassSymbol[] classSymbols) {
|
||||
BitSet ambiguousSupers = new BitSet();
|
||||
for (ClassSymbol symbol : classSymbols) {
|
||||
if (!symbol.isHierarchyIncomplete() && symbol.hasAmbiguousSupers()) {
|
||||
ambiguousSupers.set(symbol.myClassAnchor.myId);
|
||||
}
|
||||
}
|
||||
return ambiguousSupers;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static BitSet calcCoveredFiles(ClassSymbol[] classSymbols) {
|
||||
BitSet problematicFiles = new BitSet();
|
||||
@@ -79,6 +96,10 @@ public class SingleClassHierarchy extends ClassHierarchy {
|
||||
@NotNull
|
||||
@Override
|
||||
public SmartClassAnchor[] getDirectSubtypeCandidates(@NotNull PsiClass psiClass) {
|
||||
PsiElement original = psiClass.getOriginalElement();
|
||||
if (original instanceof PsiClass) {
|
||||
psiClass = (PsiClass)original;
|
||||
}
|
||||
int fileId = Math.abs(FileBasedIndex.getFileId(psiClass.getContainingFile().getVirtualFile()));
|
||||
SmartClassAnchor anchor = forPsiClass(fileId, psiClass);
|
||||
return anchor == null ? StubClassAnchor.EMPTY_ARRAY : getDirectSubtypeCandidates(anchor);
|
||||
@@ -101,39 +122,28 @@ public class SingleClassHierarchy extends ClassHierarchy {
|
||||
return result;
|
||||
}
|
||||
|
||||
public StubClassAnchor[] getAllSubtypes(PsiClass base) {
|
||||
int fileId = Math.abs(FileBasedIndex.getFileId(base.getContainingFile().getVirtualFile()));
|
||||
@Override
|
||||
public boolean hasAmbiguousSupers(@NotNull SmartClassAnchor anchor) {
|
||||
return myAmbiguousSupers.get(((StubClassAnchor)anchor).myId);
|
||||
}
|
||||
|
||||
TIntHashSet resultIds = new TIntHashSet();
|
||||
TIntHashSet processed = new TIntHashSet();
|
||||
TIntStack queue = new TIntStack();
|
||||
|
||||
StubClassAnchor baseAnchor = forPsiClass(fileId, base);
|
||||
if (baseAnchor == null) {
|
||||
return StubClassAnchor.EMPTY_ARRAY;
|
||||
@NotNull
|
||||
@Override
|
||||
public GlobalSearchScope restrictToUncovered(@NotNull GlobalSearchScope scope) {
|
||||
if (myCoveredClasses.isEmpty()) {
|
||||
return scope;
|
||||
}
|
||||
|
||||
queue.push(baseAnchor.myId);
|
||||
while (queue.size() > 0) {
|
||||
int id = queue.pop();
|
||||
if (processed.add(id)) {
|
||||
int start = subtypeStart(id);
|
||||
int end = subtypeEnd(id);
|
||||
for (int i = start; i < end; i++) {
|
||||
int subtypeId = mySubtypes[i];
|
||||
resultIds.add(subtypeId);
|
||||
if (!processed.contains(subtypeId)) {
|
||||
queue.push(subtypeId);
|
||||
}
|
||||
return new DelegatingGlobalSearchScope(scope, this) {
|
||||
@Override
|
||||
public boolean contains(@NotNull VirtualFile file) {
|
||||
if (file instanceof VirtualFileWithId && myCoveredFiles.get(((VirtualFileWithId)file).getId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return super.contains(file);
|
||||
}
|
||||
}
|
||||
int[] allIds = resultIds.toArray();
|
||||
StubClassAnchor[] result = new StubClassAnchor[allIds.length];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = myClassAnchors[allIds[i]];
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
private static StubClassAnchor[] mkByFileId(final StubClassAnchor[] classAnchors) {
|
||||
@@ -154,8 +164,6 @@ public class SingleClassHierarchy extends ClassHierarchy {
|
||||
}
|
||||
|
||||
private void connectSubTypes(ClassSymbol[] classSymbols) {
|
||||
excludeUncoveredFiles(classSymbols);
|
||||
|
||||
int[] sizes = calculateSizes(classSymbols);
|
||||
|
||||
int[] starts = new int[classSymbols.length];
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.intellij.psi.stubsHierarchy.impl;
|
||||
import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree;
|
||||
import com.intellij.psi.stubsHierarchy.stubs.UnitInfo;
|
||||
import com.intellij.util.BitUtil;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Comparator;
|
||||
@@ -159,6 +160,20 @@ public abstract class Symbol {
|
||||
boolean isHierarchyIncomplete() {
|
||||
return myHierarchyIncomplete;
|
||||
}
|
||||
|
||||
boolean hasAmbiguousSupers() {
|
||||
ClassSymbol[] superClasses = rawSuperClasses();
|
||||
if (superClasses.length < 2) return false;
|
||||
|
||||
TIntHashSet superNames = new TIntHashSet();
|
||||
for (ClassSymbol symbol : superClasses) {
|
||||
if (!superNames.add(symbol.myShortName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-1
@@ -17,6 +17,7 @@ package com.intellij.psi.impl.search;
|
||||
|
||||
import com.intellij.concurrency.JobLauncher;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.progress.ProgressIndicatorProvider;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -175,7 +176,7 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor<PsiClass, Dir
|
||||
@NotNull PsiClass baseClass,
|
||||
@NotNull String baseClassName,
|
||||
@NotNull SearchScope useScope) {
|
||||
GlobalSearchScope globalUseScope = ApplicationManager.getApplication().runReadAction((Computable<GlobalSearchScope>)()-> toGlobal(useScope, project));
|
||||
GlobalSearchScope globalUseScope = ReadAction.compute(() -> StubHierarchyInheritorSearcher.restrictScope(toGlobal(useScope, project)));
|
||||
Collection<PsiReferenceList> candidates =
|
||||
MethodUsagesSearcher.resolveInReadAction(project, () -> JavaSuperClassNameOccurenceIndex.getInstance().get(baseClassName, project, globalUseScope));
|
||||
|
||||
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi.impl.search;
|
||||
|
||||
import com.intellij.openapi.application.QueryExecutorBase;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.PsiSearchScopeUtil;
|
||||
import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
|
||||
import com.intellij.psi.stubsHierarchy.ClassHierarchy;
|
||||
import com.intellij.psi.stubsHierarchy.HierarchyService;
|
||||
import com.intellij.psi.stubsHierarchy.SmartClassAnchor;
|
||||
import com.intellij.util.Processor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class StubHierarchyInheritorSearcher extends QueryExecutorBase<PsiClass, DirectClassInheritorsSearch.SearchParameters> {
|
||||
public StubHierarchyInheritorSearcher() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
private static boolean isSearching() {
|
||||
return Registry.is("java.use.stub.hierarchy.in.inheritor.search");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static GlobalSearchScope restrictScope(@NotNull GlobalSearchScope scope) {
|
||||
if (!isSearching()) return scope;
|
||||
|
||||
Project project = scope.getProject();
|
||||
return project == null ? scope : HierarchyService.getHierarchy(project).restrictToUncovered(scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processQuery(@NotNull DirectClassInheritorsSearch.SearchParameters queryParameters, @NotNull Processor<PsiClass> consumer) {
|
||||
if (!(queryParameters.getScope() instanceof GlobalSearchScope) || !isSearching()) return;
|
||||
|
||||
PsiClass base = queryParameters.getClassToProcess();
|
||||
GlobalSearchScope scope = (GlobalSearchScope)queryParameters.getScope();
|
||||
ClassHierarchy hierarchy = HierarchyService.getHierarchy(base.getProject());
|
||||
for (SmartClassAnchor anchor : hierarchy.getDirectSubtypeCandidates(base)) {
|
||||
if (!processCandidate(consumer, base, scope, hierarchy, anchor)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean processCandidate(Processor<PsiClass> consumer,
|
||||
PsiClass base,
|
||||
GlobalSearchScope scope,
|
||||
ClassHierarchy hierarchy, SmartClassAnchor anchor) {
|
||||
VirtualFile file = anchor.retrieveFile();
|
||||
if (!scope.contains(file)) return true;
|
||||
|
||||
PsiClass candidate = anchor.retrieveClass(base.getProject());
|
||||
if (!PsiSearchScopeUtil.isInScope(candidate.getResolveScope(), base)) return true;
|
||||
|
||||
if (hierarchy.hasAmbiguousSupers(anchor) && !candidate.isInheritor(base, false)) return true;
|
||||
|
||||
return consumer.process(candidate);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.intellij.psi.stubsHierarchy;
|
||||
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
@@ -41,4 +42,15 @@ public abstract class ClassHierarchy {
|
||||
|
||||
@NotNull
|
||||
public abstract SmartClassAnchor[] getDirectSubtypeCandidates(@NotNull SmartClassAnchor anchor);
|
||||
|
||||
/**
|
||||
* @return whether stub hierarchy resolver couldn't determine the super class exactly because there were several possible candidates
|
||||
*/
|
||||
public abstract boolean hasAmbiguousSupers(@NotNull SmartClassAnchor anchor);
|
||||
|
||||
/**
|
||||
* @return the given scope restricted to the files not covered by this hierarchy, to use usual PSI/resolve-based inheritor search in it
|
||||
*/
|
||||
@NotNull
|
||||
public abstract GlobalSearchScope restrictToUncovered(@NotNull GlobalSearchScope scope);
|
||||
}
|
||||
|
||||
@@ -312,7 +312,11 @@ java.annotations.inference.nullable.method.transitivity=true
|
||||
java.annotations.inference.nullable.method.transitivity.description=Restart is required; if a method result is a call to a @Nullable method, reports the caller as @Nullable as well
|
||||
|
||||
java.hierarchy.service=false
|
||||
java.hierarchy.service.description=Restart is required; calculate class hierarchy in background
|
||||
java.hierarchy.service.description=Enable special indexing for quick JVM class hierarchy calculation
|
||||
java.hierarchy.service.restartRequired=true
|
||||
|
||||
java.use.stub.hierarchy.in.inheritor.search=false
|
||||
java.use.stub.hierarchy.in.inheritor.search.description=Use stub hierarchy (enabled by java.hierarchy.service key) in inheritor searches
|
||||
|
||||
java.max.package.name.length=1000
|
||||
java.max.package.name.length.description=An upper length limit on string that the IDE considers worth checking for being package names
|
||||
|
||||
+3
-1
@@ -20,6 +20,7 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.search.StubHierarchyInheritorSearcher;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
|
||||
@@ -74,7 +75,8 @@ public class GroovyDirectInheritorsSearcher implements QueryExecutor<PsiClass, D
|
||||
@Override
|
||||
public List<PsiClass> compute() {
|
||||
if (!clazz.isValid()) return Collections.emptyList();
|
||||
return getDerivingClassCandidates(clazz, (GlobalSearchScope)scope, queryParameters.includeAnonymous());
|
||||
GlobalSearchScope restrictedScope = StubHierarchyInheritorSearcher.restrictScope((GlobalSearchScope)scope);
|
||||
return getDerivingClassCandidates(clazz, restrictedScope, queryParameters.includeAnonymous());
|
||||
}
|
||||
});
|
||||
for (final PsiClass candidate : candidates) {
|
||||
|
||||
@@ -353,6 +353,7 @@
|
||||
<annotatedElementsSearch implementation="com.intellij.psi.impl.search.AnnotatedElementsSearcher"/>
|
||||
<annotatedPackagesSearch implementation="com.intellij.psi.impl.search.AnnotatedPackagesSearcher"/>
|
||||
<directClassInheritorsSearch implementation="com.intellij.psi.impl.search.JavaDirectInheritorsSearcher"/>
|
||||
<directClassInheritorsSearch implementation="com.intellij.psi.impl.search.StubHierarchyInheritorSearcher"/>
|
||||
<classInheritorsSearch implementation="com.intellij.psi.impl.search.JavaClassInheritorsSearcher"/>
|
||||
<overridingMethodsSearch implementation="com.intellij.psi.impl.search.JavaOverridingMethodsSearcher"/>
|
||||
<allOverridingMethodsSearch implementation="com.intellij.psi.impl.search.JavaAllOverridingMethodsSearcher"/>
|
||||
|
||||
Reference in New Issue
Block a user