cache repeated requests for class inheritors and method overriders to speedup highlighting of heavily subclassed library classes to fix IDEA-152346 Syntax highlighting takes 45 seconds

This commit is contained in:
Alexey Kudravtsev
2016-03-28 14:59:27 +03:00
parent 3425838d56
commit 14e866598a
13 changed files with 669 additions and 198 deletions
@@ -24,10 +24,8 @@ import com.intellij.psi.util.MethodSignature;
import com.intellij.psi.util.MethodSignatureUtil;
import com.intellij.psi.util.PsiSuperMethodUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.containers.FactoryMap;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -66,12 +64,11 @@ public class FindSuperElementsHelper {
}
public static PsiMethod getSiblingInheritedViaSubClass(@NotNull PsiMethod method) {
return Pair.getFirst(getSiblingInheritedViaSubClass(method, createSubClassCache()));
return Pair.getFirst(getSiblingInfoInheritedViaSubClass(method));
}
// returns super method, sub class
public static Pair<PsiMethod, PsiClass> getSiblingInheritedViaSubClass(@NotNull final PsiMethod method,
@NotNull Map<PsiClass, PsiClass> subClassCache) {
public static Pair<PsiMethod, PsiClass> getSiblingInfoInheritedViaSubClass(@NotNull final PsiMethod method) {
if (!method.hasModifierProperty(PsiModifier.PUBLIC)) return null;
if (method.hasModifierProperty(PsiModifier.STATIC)) return null;
final PsiClass containingClass = method.getContainingClass();
@@ -86,55 +83,44 @@ public class FindSuperElementsHelper {
final Ref<Pair<PsiMethod, PsiClass>> result = Ref.create();
ClassInheritorsSearch.search(containingClass, containingClass.getUseScope(), true, true, false).forEach(
inheritor -> {
ProgressManager.checkCanceled();
for (PsiClassType interfaceType : inheritor.getImplementsListTypes()) {
ProgressManager.checkCanceled();
for (PsiClassType interfaceType : inheritor.getImplementsListTypes()) {
PsiClassType.ClassResolveResult resolved = interfaceType.resolveGenerics();
PsiClass anInterface = resolved.getElement();
if (anInterface == null || !checkedInterfaces.add(PsiAnchor.create(anInterface))) continue;
for (PsiMethod superMethod : anInterface.findMethodsByName(method.getName(), true)) {
PsiElement navigationElement = superMethod.getNavigationElement();
if (!(navigationElement instanceof PsiMethod)) continue; // Kotlin
superMethod = (PsiMethod)navigationElement;
ProgressManager.checkCanceled();
PsiClassType.ClassResolveResult resolved = interfaceType.resolveGenerics();
PsiClass anInterface = resolved.getElement();
if (anInterface == null || !checkedInterfaces.add(PsiAnchor.create(anInterface))) continue;
for (PsiMethod superMethod : anInterface.findMethodsByName(method.getName(), true)) {
PsiElement navigationElement = superMethod.getNavigationElement();
if (!(navigationElement instanceof PsiMethod)) continue; // Kotlin
superMethod = (PsiMethod)navigationElement;
ProgressManager.checkCanceled();
PsiClass superInterface = superMethod.getContainingClass();
if (superInterface == null) {
continue;
}
if (containingClass.isInheritor(superInterface, true)) {
// if containingClass implements the superInterface then it's not a sibling inheritance but a pretty boring the usual one
continue;
}
// calculate substitutor of containingClass --> inheritor
PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(containingClass, inheritor, PsiSubstitutor.EMPTY);
// calculate substitutor of inheritor --> superInterface
substitutor = TypeConversionUtil.getSuperClassSubstitutor(superInterface, inheritor, substitutor);
final MethodSignature superSignature = superMethod.getSignature(substitutor);
final MethodSignature derivedSignature = method.getSignature(PsiSubstitutor.EMPTY);
boolean isOverridden = MethodSignatureUtil.isSubsignature(superSignature, derivedSignature);
if (!isOverridden) {
continue;
}
result.set(Pair.create(superMethod, inheritor));
return false;
PsiClass superInterface = superMethod.getContainingClass();
if (superInterface == null) {
continue;
}
if (containingClass.isInheritor(superInterface, true)) {
// if containingClass implements the superInterface then it's not a sibling inheritance but a pretty boring the usual one
continue;
}
// calculate substitutor of containingClass --> inheritor
PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(containingClass, inheritor, PsiSubstitutor.EMPTY);
// calculate substitutor of inheritor --> superInterface
substitutor = TypeConversionUtil.getSuperClassSubstitutor(superInterface, inheritor, substitutor);
final MethodSignature superSignature = superMethod.getSignature(substitutor);
final MethodSignature derivedSignature = method.getSignature(PsiSubstitutor.EMPTY);
boolean isOverridden = MethodSignatureUtil.isSubsignature(superSignature, derivedSignature);
if (!isOverridden) {
continue;
}
result.set(Pair.create(superMethod, inheritor));
return false;
}
return true;
}
return true;
});
return result.get();
}
@NotNull
public static Map<PsiClass, PsiClass> createSubClassCache() {
return new FactoryMap<PsiClass, PsiClass>() {
@Nullable
@Override
protected PsiClass create(PsiClass aClass) {
return ClassInheritorsSearch.search(aClass, false).findFirst();
}
};
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* 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.
@@ -299,7 +299,7 @@ public class CodeInsightUtil {
});
} else {
Query<PsiClass> baseQuery = ClassInheritorsSearch.search(
new ClassInheritorsSearch.SearchParameters(baseClass, scope, true, false, false, matcher::prefixMatches));
new ClassInheritorsSearch.SearchParameters(baseClass, scope, true, true, false, matcher::prefixMatches));
Query<PsiClass> query = new FilteredQuery<>(baseQuery, psiClass -> !(psiClass instanceof PsiTypeParameter));
query.forEach(inheritorsProcessor);
}
@@ -27,12 +27,12 @@ import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.markup.GutterIconRenderer;
import com.intellij.openapi.editor.markup.SeparatorPlacement;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.FindSuperElementsHelper;
import com.intellij.psi.search.searches.AllOverridingMethodsSearch;
import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
import com.intellij.psi.search.searches.FunctionalExpressionSearch;
import com.intellij.psi.search.searches.SuperMethodsSearch;
import com.intellij.psi.util.MethodSignatureBackedByPsiMethod;
@@ -48,7 +48,6 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class JavaLineMarkerProvider extends LineMarkerProviderDescriptor {
@@ -162,7 +161,6 @@ public class JavaLineMarkerProvider extends LineMarkerProviderDescriptor {
@Override
public void collectSlowLineMarkers(@NotNull final List<PsiElement> elements, @NotNull final Collection<LineMarkerInfo> result) {
ApplicationManager.getApplication().assertReadAccessAllowed();
Map<PsiClass, PsiClass> subClassCache = FindSuperElementsHelper.createSubClassCache();
Collection<PsiMethod> methods = new THashSet<>();
//noinspection ForLoopReplaceableByForEach
@@ -178,18 +176,17 @@ public class JavaLineMarkerProvider extends LineMarkerProviderDescriptor {
}
}
else if (parent instanceof PsiClass && !(parent instanceof PsiTypeParameter)) {
collectInheritingClasses((PsiClass)parent, result, subClassCache);
collectInheritingClasses((PsiClass)parent, result);
}
}
if (!methods.isEmpty()) {
collectOverridingMethods(methods, result);
collectSiblingInheritedMethods(methods, result, subClassCache);
collectSiblingInheritedMethods(methods, result);
}
}
private static void collectSiblingInheritedMethods(@NotNull final Collection<PsiMethod> methods,
@NotNull Collection<LineMarkerInfo> result,
@NotNull Map<PsiClass, PsiClass> subClassCache) {
@NotNull Collection<LineMarkerInfo> result) {
for (PsiMethod method : methods) {
ProgressManager.checkCanceled();
PsiClass aClass = method.getContainingClass();
@@ -198,7 +195,7 @@ public class JavaLineMarkerProvider extends LineMarkerProviderDescriptor {
boolean canHaveSiblingSuper = !method.hasModifierProperty(PsiModifier.ABSTRACT) && !method.hasModifierProperty(PsiModifier.STATIC) && method.hasModifierProperty(PsiModifier.PUBLIC)&& !method.hasModifierProperty(PsiModifier.FINAL)&& !method.hasModifierProperty(PsiModifier.NATIVE);
if (!canHaveSiblingSuper) continue;
PsiMethod siblingInheritedViaSubClass = Pair.getFirst(FindSuperElementsHelper.getSiblingInheritedViaSubClass(method, subClassCache));
PsiMethod siblingInheritedViaSubClass = FindSuperElementsHelper.getSiblingInheritedViaSubClass(method);
if (siblingInheritedViaSubClass == null) {
continue;
}
@@ -229,14 +226,13 @@ public class JavaLineMarkerProvider extends LineMarkerProviderDescriptor {
}
protected void collectInheritingClasses(@NotNull PsiClass aClass,
@NotNull Collection<LineMarkerInfo> result,
@NotNull Map<PsiClass, PsiClass> subClassCache) {
@NotNull Collection<LineMarkerInfo> result) {
if (aClass.hasModifierProperty(PsiModifier.FINAL)) {
return;
}
if (CommonClassNames.JAVA_LANG_OBJECT.equals(aClass.getQualifiedName())) return; // It's useless to have overridden markers for object.
PsiClass subClass = subClassCache.get(aClass);
PsiClass subClass = DirectClassInheritorsSearch.search(aClass).findFirst();
if (subClass != null || FunctionalExpressionSearch.search(aClass).findFirst() != null) {
final Icon icon;
if (aClass.isInterface()) {
@@ -160,8 +160,7 @@ public class MarkerType {
}
@Nullable
private static String calculateOverridingSiblingMethodTooltip(@NotNull PsiMethod method) {
Pair<PsiMethod, PsiClass> pair =
FindSuperElementsHelper.getSiblingInheritedViaSubClass(method, FindSuperElementsHelper.createSubClassCache());
Pair<PsiMethod, PsiClass> pair = FindSuperElementsHelper.getSiblingInfoInheritedViaSubClass(method);
if (pair == null) return null;
PsiMethod superMethod = pair.getFirst();
PsiClass subClass = pair.getSecond();
@@ -247,7 +246,7 @@ public class MarkerType {
private static String getOverriddenMethodTooltip(@NotNull PsiMethod method) {
PsiElementProcessor.CollectElementsWithLimit<PsiMethod> processor = new PsiElementProcessor.CollectElementsWithLimit<PsiMethod>(5);
OverridingMethodsSearch.search(method, true).forEach(new PsiElementProcessorAdapter<PsiMethod>(processor));
OverridingMethodsSearch.search(method).forEach(new PsiElementProcessorAdapter<PsiMethod>(processor));
boolean isAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT);
@@ -287,7 +286,7 @@ public class MarkerType {
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
@Override
public void run() {
OverridingMethodsSearch.search(method, true).forEach(new PsiElementProcessorAdapter<PsiMethod>(collectProcessor));
OverridingMethodsSearch.search(method).forEach(new PsiElementProcessorAdapter<PsiMethod>(collectProcessor));
if (isAbstract && collectProcessor.getCollection().size() < 2) {
final PsiClass aClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
@Override
@@ -468,7 +467,7 @@ public class MarkerType {
@Override
public void run(@NotNull final ProgressIndicator indicator) {
super.run(indicator);
OverridingMethodsSearch.search(myMethod, true).forEach(
OverridingMethodsSearch.search(myMethod).forEach(
new CommonProcessors.CollectProcessor<PsiMethod>() {
@Override
public boolean process(PsiMethod psiMethod) {
@@ -56,6 +56,7 @@ public class ClassInheritorsSearch extends ExtensibleQueryFactory<PsiClass, Clas
myScope = scope;
myCheckDeep = checkDeep;
myCheckInheritance = checkInheritance;
assert checkInheritance;
myIncludeAnonymous = includeAnonymous;
myNameCondition = nameCondition;
}
@@ -96,6 +97,32 @@ public class ClassInheritorsSearch extends ExtensibleQueryFactory<PsiClass, Clas
(myIncludeAnonymous ? " (anonymous)":"")+
(myNameCondition == Conditions.<String>alwaysTrue() ? "" : " condition: "+myNameCondition);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SearchParameters that = (SearchParameters)o;
if (myCheckDeep != that.myCheckDeep) return false;
if (myCheckInheritance != that.myCheckInheritance) return false;
if (myIncludeAnonymous != that.myIncludeAnonymous) return false;
if (!myClass.equals(that.myClass)) return false;
if (!myScope.equals(that.myScope)) return false;
return myNameCondition.equals(that.myNameCondition);
}
@Override
public int hashCode() {
int result = myClass.hashCode();
result = 31 * result + myScope.hashCode();
result = 31 * result + (myCheckDeep ? 1 : 0);
result = 31 * result + (myCheckInheritance ? 1 : 0);
result = 31 * result + (myIncludeAnonymous ? 1 : 0);
result = 31 * result + myNameCondition.hashCode();
return result;
}
}
private ClassInheritorsSearch() {}
@@ -0,0 +1,68 @@
/*
* 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.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.impl.AnyPsiChangeListener;
import com.intellij.psi.impl.PsiManagerImpl;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicIntegerArray;
class HighlightingCaches {
public static HighlightingCaches getInstance(Project project) {
return ServiceManager.getService(project, HighlightingCaches.class);
}
private final List<Map<?,?>> allCaches = ContainerUtil.createConcurrentList();
public HighlightingCaches(Project project) {
project.getMessageBus().connect().subscribe(PsiManagerImpl.ANY_PSI_CHANGE_TOPIC, new AnyPsiChangeListener() {
@Override
public void beforePsiChanged(boolean isPhysical) {
if (isPhysical) {
allCaches.forEach(Map::clear);
}
}
@Override
public void afterPsiChanged(boolean isPhysical) {
}
});
}
final Map<PsiClass, Pair<List<PsiClass>, AtomicIntegerArray>> DIRECT_SUB_CLASSES = createCache();
final Map<ClassInheritorsSearch.SearchParameters, Collection<PsiClass>> ALL_SUB_CLASSES = createCache();
final Map<PsiMethod, Collection<PsiMethod>> OVERRIDING_METHODS = createCache();
@NotNull
private <T,V> Map<T,V> createCache() {
ConcurrentMap<T, V> map = ContainerUtil.createConcurrentSoftKeySoftValueMap(10, 0.7f, Runtime.getRuntime().availableProcessors(), ContainerUtil.canonicalStrategy());
allCaches.add(map);
return map;
}
}
@@ -18,7 +18,6 @@ package com.intellij.psi.impl.search;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.QueryExecutorBase;
import com.intellij.openapi.application.ReadActionProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.openapi.progress.ProgressManager;
@@ -33,22 +32,22 @@ import com.intellij.psi.search.searches.AllClassesSearch;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.CommonProcessors;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;
public class JavaClassInheritorsSearcher extends QueryExecutorBase<PsiClass, ClassInheritorsSearch.SearchParameters> {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.search.JavaClassInheritorsSearcher");
@Override
public void processQuery(@NotNull ClassInheritorsSearch.SearchParameters parameters, @NotNull Processor<PsiClass> consumer) {
final PsiClass baseClass = parameters.getClassToProcess();
final SearchScope searchScope = parameters.getScope();
LOG.assertTrue(searchScope != null);
assert parameters.isCheckDeep();
assert parameters.isCheckInheritance();
ProgressIndicator progress = ProgressIndicatorProvider.getGlobalProgressIndicator();
if (progress != null) {
@@ -67,7 +66,6 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase<PsiClass, Cla
progress.popState();
}
}
}
private static boolean processInheritors(@NotNull final ClassInheritorsSearch.SearchParameters parameters,
@@ -79,11 +77,34 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase<PsiClass, Cla
Project project = PsiUtilCore.getProjectInReadAction(baseClass);
if (isJavaLangObject(baseClass)) {
return AllClassesSearch.search(searchScope, project, parameters.getNameCondition()).forEach(aClass -> {
ProgressManager.checkCanceled();
return isJavaLangObject(aClass) || consumer.process(aClass);
ProgressManager.checkCanceled();
return isJavaLangObject(aClass) || consumer.process(aClass);
});
}
Collection<PsiClass> cached = HighlightingCaches.getInstance(project).ALL_SUB_CLASSES.get(parameters);
if (cached == null) {
cached = new ArrayList<>();
boolean success = getAllSubClasses(project, baseClass, parameters, new CommonProcessors.CollectProcessor<>(cached));
assert success;
HighlightingCaches.getInstance(project).ALL_SUB_CLASSES.put(parameters, cached);
}
Processor<PsiClass> readActionedConsumer = ReadActionProcessor.wrapInReadAction(consumer);
for (final PsiClass subClass : cached) {
ProgressManager.checkCanceled();
if (!readActionedConsumer.process(subClass)) {
return false;
}
}
return true;
}
private static boolean getAllSubClasses(@NotNull Project project,
@NotNull PsiClass baseClass,
@NotNull ClassInheritorsSearch.SearchParameters parameters,
@NotNull Processor<PsiClass> consumer) {
SearchScope searchScope = parameters.getScope();
final Ref<PsiClass> currentBase = Ref.create(null);
final Stack<PsiAnchor> stack = new Stack<>();
final Set<PsiAnchor> processed = ContainerUtil.newTroveSet();
@@ -93,7 +114,7 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase<PsiClass, Cla
public boolean processInReadAction(PsiClass candidate) {
ProgressManager.checkCanceled();
if (parameters.isCheckInheritance() || parameters.isCheckDeep() && !(candidate instanceof PsiAnonymousClass)) {
if (parameters.isCheckInheritance() || !(candidate instanceof PsiAnonymousClass)) {
if (!candidate.isInheritor(currentBase.get(), false)) {
return true;
}
@@ -103,25 +124,25 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase<PsiClass, Cla
if (candidate instanceof PsiAnonymousClass) {
return consumer.process(candidate);
}
final String name = candidate.getName();
if (name != null && parameters.getNameCondition().value(name) && !consumer.process(candidate)) {
return false;
}
}
if (parameters.isCheckDeep() && !(candidate instanceof PsiAnonymousClass) && !isFinal(candidate)) {
if (!(candidate instanceof PsiAnonymousClass) && !candidate.hasModifierProperty(PsiModifier.FINAL)) {
stack.push(PsiAnchor.create(candidate));
}
return true;
}
};
ApplicationManager.getApplication().runReadAction(() -> {
stack.push(PsiAnchor.create(baseClass));
stack.push(PsiAnchor.create(baseClass));
});
final GlobalSearchScope projectScope = GlobalSearchScope.allScope(project);
while (!stack.isEmpty()) {
ProgressManager.checkCanceled();
@@ -20,6 +20,7 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
@@ -27,6 +28,7 @@ import com.intellij.psi.impl.java.stubs.index.JavaAnonymousClassBaseRefOccurence
import com.intellij.psi.impl.java.stubs.index.JavaSuperClassNameOccurenceIndex;
import com.intellij.psi.search.EverythingGlobalScope;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiSearchScopeUtil;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.AllClassesSearch;
import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
@@ -34,15 +36,12 @@ import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.Processor;
import com.intellij.util.QueryExecutor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.SmartList;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.atomic.AtomicIntegerArray;
/**
* @author max
@@ -67,94 +66,155 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor<PsiClass, Dir
}
final GlobalSearchScope scope = useScope instanceof GlobalSearchScope ? (GlobalSearchScope)useScope : new EverythingGlobalScope(project);
final String searchKey = ApplicationManager.getApplication().runReadAction((Computable<String>)aClass::getName);
if (StringUtil.isEmpty(searchKey)) {
Pair<List<PsiClass>, AtomicIntegerArray> pair = calculateDirectSubClasses(project, aClass);
List<PsiClass> result = pair.getFirst();
AtomicIntegerArray isInheritorFlag = pair.getSecond();
if (result.isEmpty()) {
return true;
}
Collection<PsiReferenceList> candidates =
MethodUsagesSearcher.resolveInReadAction(project, () -> JavaSuperClassNameOccurenceIndex.getInstance().get(searchKey, project, scope));
Map<String, List<PsiClass>> classes = new HashMap<>();
for (final PsiReferenceList referenceList : candidates) {
final VirtualFile jarFile = getJarFile(aClass);
// iterate by same-FQN groups. For each group process only same-jar subclasses, or all of them if they are all outside the jarFile.
int groupStart = 0;
boolean sameJarClassFound = false;
for (int i = 0; i < result.size(); i++) {
ProgressManager.checkCanceled();
final PsiClass candidate = (PsiClass)ApplicationManager.getApplication().runReadAction((Computable<PsiElement>)referenceList::getParent);
if (!checkInheritance(parameters, aClass, candidate, project)) continue;
String fqn = ApplicationManager.getApplication().runReadAction((Computable<String>)candidate::getQualifiedName);
List<PsiClass> list = classes.get(fqn);
if (list == null) {
list = new ArrayList<>();
classes.put(fqn, list);
}
list.add(candidate);
}
if (!classes.isEmpty()) {
final VirtualFile jarFile = getJarFile(aClass);
for (List<PsiClass> sameNamedClasses : classes.values()) {
ProgressManager.checkCanceled();
if (!processSameNamedClasses(sameNamedClasses, jarFile, consumer)) return false;
}
}
if (parameters.includeAnonymous()) {
Collection<PsiAnonymousClass> anonymousCandidates =
MethodUsagesSearcher.resolveInReadAction(project, () -> JavaAnonymousClassBaseRefOccurenceIndex.getInstance().get(searchKey, project, scope));
for (PsiAnonymousClass candidate : anonymousCandidates) {
ProgressManager.checkCanceled();
if (!checkInheritance(parameters, aClass, candidate, project)) continue;
if (!consumer.process(candidate)) return false;
}
boolean isEnum = ApplicationManager.getApplication().runReadAction((Computable<Boolean>)aClass::isEnum);
if (isEnum) {
// abstract enum can be subclassed in the body
PsiField[] fields = ApplicationManager.getApplication().runReadAction((Computable<PsiField[]>)aClass::getFields);
for (final PsiField field : fields) {
PsiClass subClass = result.get(i);
if (subClass instanceof PsiAnonymousClass) {
// we reached anonymous classes tail, process them all and exit
if (!parameters.includeAnonymous()) {
return true;
}
for (; i < result.size(); i++) {
ProgressManager.checkCanceled();
if (field instanceof PsiEnumConstant) {
PsiEnumConstantInitializer initializingClass =
ApplicationManager.getApplication().runReadAction((Computable<PsiEnumConstantInitializer>)((PsiEnumConstant)field)::getInitializingClass);
if (initializingClass != null) {
if (!consumer.process(initializingClass)) return false;
}
subClass = result.get(i);
if (!checkInheritance(parameters.isCheckInheritance(), aClass, subClass, project, isInheritorFlag, i)) continue;
if (!isInScope(scope, subClass)) continue;
if (!consumer.process(subClass)) return false;
}
return true;
}
if (subClass == PsiUtil.NULL_PSI_CLASS) {
// the end of the same-FQN group. Process only same-jar classes in the group or the whole group if there were none.
if (!sameJarClassFound) {
for (int g=groupStart; g<i; g++) {
ProgressManager.checkCanceled();
subClass = result.get(g);
if (!checkInheritance(parameters.isCheckInheritance(), aClass, subClass, project, isInheritorFlag, g)) continue;
if (!consumer.process(subClass)) return false;
}
}
groupStart = i+1;
sameJarClassFound = false;
}
else {
if (!checkInheritance(parameters.isCheckInheritance(), aClass, subClass, project, isInheritorFlag, i)) continue;
if (!isInScope(scope, subClass)) continue;
VirtualFile currentJarFile = getJarFile(subClass);
boolean fromSameJar = Comparing.equal(currentJarFile, jarFile);
if (fromSameJar) {
sameJarClassFound = true;
if (!consumer.process(subClass)) return false;
}
}
}
return true;
}
private static boolean checkInheritance(@NotNull DirectClassInheritorsSearch.SearchParameters p,
@NotNull PsiClass aClass,
@NotNull PsiClass candidate,
@NotNull Project project) {
return MethodUsagesSearcher.resolveInReadAction(project, () -> !p.isCheckInheritance() || candidate.isInheritor(aClass, false));
private static boolean isInScope(GlobalSearchScope scope, PsiClass subClass) {
return ApplicationManager.getApplication().runReadAction((Computable<Boolean>)() -> PsiSearchScopeUtil.isInScope(scope, subClass));
}
private static boolean processSameNamedClasses(@NotNull List<PsiClass> sameNamedClasses,
@Nullable VirtualFile jarFile,
@NotNull Processor<PsiClass> consumer) {
// if there is a class from the same jar, prefer it
boolean sameJarClassFound = false;
private static final int INHERITANCE_UNKNOWN = 0;
private static final int INHERITANCE_YES = 1;
private static final int INHERITANCE_NO = 2;
if (jarFile != null && sameNamedClasses.size() > 1) {
for (PsiClass sameNamedClass : sameNamedClasses) {
// Returns pair ( list of direct subclasses, array of corresponding isInheritor flags )
// The array initially contains INHERITANCE_UNKNOWN values, then the isInheritor() method result is cached in the array as INHERITANCE_YES or INHERITANCE_NO.
// The list starts with non-anonymous classes, ends with anonymous sub classes
// Regular classes grouped by their FQN. (Because among the same-named subclasses we should return only the same-jar ones, or all of them if there were none)
// The groups are separated with NULL_PSI_CLASS
@NotNull
private static Pair<List<PsiClass>, AtomicIntegerArray> calculateDirectSubClasses(@NotNull Project project, @NotNull PsiClass baseClass) {
Pair<List<PsiClass>, AtomicIntegerArray> cached = HighlightingCaches.getInstance(project).DIRECT_SUB_CLASSES.get(baseClass);
if (cached != null) {
return cached;
}
final String className = ApplicationManager.getApplication().runReadAction((Computable<String>)baseClass::getName);
if (StringUtil.isEmpty(className)) {
return Pair.create(Collections.emptyList(), new AtomicIntegerArray(0));
}
GlobalSearchScope allScope = GlobalSearchScope.allScope(project);
Collection<PsiReferenceList> candidates =
MethodUsagesSearcher.resolveInReadAction(project, () -> JavaSuperClassNameOccurenceIndex.getInstance().get(className, project, allScope));
Map<String, List<PsiClass>> classes = new HashMap<>();
int count = 0;
for (final PsiReferenceList referenceList : candidates) {
ProgressManager.checkCanceled();
final PsiClass candidate = (PsiClass)ApplicationManager.getApplication().runReadAction((Computable<PsiElement>)referenceList::getParent);
String fqn = ApplicationManager.getApplication().runReadAction((Computable<String>)candidate::getQualifiedName);
List<PsiClass> list = classes.get(fqn);
if (list == null) {
list = new SmartList<>();
classes.put(fqn, list);
}
list.add(candidate);
count++;
}
Collection<PsiAnonymousClass> anonymousCandidates =
MethodUsagesSearcher.resolveInReadAction(project, () -> JavaAnonymousClassBaseRefOccurenceIndex.getInstance().get(className, project, allScope));
List<PsiClass> result = new ArrayList<>(count+classes.size()+anonymousCandidates.size()+1);
for (Map.Entry<String, List<PsiClass>> entry : classes.entrySet()) {
result.addAll(entry.getValue());
result.add(PsiUtil.NULL_PSI_CLASS);
}
result.addAll(anonymousCandidates);
boolean isEnum = ApplicationManager.getApplication().runReadAction((Computable<Boolean>)baseClass::isEnum);
if (isEnum) {
// abstract enum can be subclassed in the body
PsiField[] fields = ApplicationManager.getApplication().runReadAction((Computable<PsiField[]>)baseClass::getFields);
for (final PsiField field : fields) {
ProgressManager.checkCanceled();
boolean fromSameJar = Comparing.equal(getJarFile(sameNamedClass), jarFile);
if (fromSameJar) {
sameJarClassFound = true;
if (!consumer.process(sameNamedClass)) return false;
if (field instanceof PsiEnumConstant) {
PsiEnumConstantInitializer initializingClass =
ApplicationManager.getApplication().runReadAction((Computable<PsiEnumConstantInitializer>)((PsiEnumConstant)field)::getInitializingClass);
if (initializingClass != null) {
result.add(initializingClass);
}
}
}
}
return sameJarClassFound || ContainerUtil.process(sameNamedClasses, consumer);
Pair<List<PsiClass>, AtomicIntegerArray> pair = Pair.create(result, new AtomicIntegerArray(result.size()));
HighlightingCaches.getInstance(project).DIRECT_SUB_CLASSES.put(baseClass, pair);
return pair;
}
private static boolean checkInheritance(boolean checkInheritance,
@NotNull PsiClass aClass,
@NotNull PsiClass candidate,
@NotNull Project project,
@NotNull AtomicIntegerArray isInheritorFlags,
int i) {
if (!checkInheritance) return true;
int cachedFlag = isInheritorFlags.get(i);
if (cachedFlag == INHERITANCE_YES) return true;
if (cachedFlag == INHERITANCE_NO) return false;
assert cachedFlag == INHERITANCE_UNKNOWN;
boolean isReallyInherited = MethodUsagesSearcher.resolveInReadAction(project, () -> candidate.isInheritor(aClass, false));
isInheritorFlags.set(i, isReallyInherited ? INHERITANCE_YES : INHERITANCE_NO);
return isReallyInherited;
}
private static VirtualFile getJarFile(@NotNull PsiClass aClass) {
@@ -15,9 +15,14 @@
*/
package com.intellij.psi.impl.search;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiSearchScopeUtil;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.OverridingMethodsSearch;
@@ -29,56 +34,79 @@ import com.intellij.util.QueryExecutor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.LinkedHashSet;
/**
* @author max
*/
public class JavaOverridingMethodsSearcher implements QueryExecutor<PsiMethod, OverridingMethodsSearch.SearchParameters> {
@Override
public boolean execute(@NotNull final OverridingMethodsSearch.SearchParameters p, @NotNull final Processor<PsiMethod> consumer) {
final PsiMethod method = p.getMethod();
final SearchScope scope = p.getScope();
public boolean execute(@NotNull final OverridingMethodsSearch.SearchParameters parameters, @NotNull final Processor<PsiMethod> consumer) {
final PsiMethod method = parameters.getMethod();
final PsiClass parentClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
@Nullable
@Override
public PsiClass compute() {
return method.getContainingClass();
Project project = ApplicationManager.getApplication().runReadAction((Computable<Project>)method::getProject);
Collection<PsiMethod> cached = HighlightingCaches.getInstance(project).OVERRIDING_METHODS.get(method);
if (cached == null) {
cached = compute(method, project);
HighlightingCaches.getInstance(project).OVERRIDING_METHODS.put(method, cached);
}
final SearchScope scope = parameters.getScope();
for (final PsiMethod subMethod : cached) {
ProgressManager.checkCanceled();
if (!ApplicationManager.getApplication().runReadAction((Computable<Boolean>)() -> PsiSearchScopeUtil.isInScope(scope, subMethod))) {
continue;
}
});
assert parentClass != null;
Processor<PsiClass> inheritorsProcessor = new Processor<PsiClass>() {
@Override
public boolean process(final PsiClass inheritor) {
PsiMethod found = ApplicationManager.getApplication().runReadAction(new Computable<PsiMethod>() {
@Override
@Nullable
public PsiMethod compute() {
return findOverridingMethod(inheritor, parentClass, method);
}
});
return found == null || consumer.process(found) && p.isCheckDeep();
if (!consumer.process(subMethod) || !parameters.isCheckDeep()) {
return false;
}
}
return true;
}
@NotNull
private static Collection<PsiMethod> compute(@NotNull PsiMethod method, @NotNull Project project) {
Collection<PsiMethod> result = new LinkedHashSet<>();
Application application = ApplicationManager.getApplication();
final PsiClass containingClass = application.runReadAction((Computable<PsiClass>)method::getContainingClass);
assert containingClass != null;
Processor<PsiClass> inheritorsProcessor = inheritor -> {
PsiMethod found = application.runReadAction((Computable<PsiMethod>)() -> findOverridingMethod(project, inheritor, method, containingClass));
if (found != null) {
result.add(found);
}
return true;
};
return ClassInheritorsSearch.search(parentClass, scope, true).forEach(inheritorsProcessor);
// use wider scope to handle public method defined in package-private class which is subclassed by public class in the same package which is subclassed by public class from another package with redefined method
SearchScope allScope = GlobalSearchScope.allScope(project);
boolean success = ClassInheritorsSearch.search(containingClass, allScope, true).forEach(inheritorsProcessor);
assert success;
return result;
}
@Nullable
private static PsiMethod findOverridingMethod(PsiClass inheritor, @NotNull PsiClass parentClass, PsiMethod method) {
private static PsiMethod findOverridingMethod(@NotNull Project project,
@NotNull PsiClass inheritor,
@NotNull PsiMethod method,
@NotNull PsiClass methodContainingClass) {
String name = method.getName();
if (inheritor.findMethodsByName(name, false).length > 0) {
PsiMethod found = MethodSignatureUtil.findMethodBySuperSignature(inheritor, getSuperSignature(inheritor, parentClass, method), false);
if (found != null && isAcceptable(found, method)) {
PsiMethod found = MethodSignatureUtil.findMethodBySuperSignature(inheritor, getSuperSignature(inheritor, methodContainingClass, method), false);
if (found != null && isAcceptable(project, found, inheritor, method, methodContainingClass)) {
return found;
}
}
if (parentClass.isInterface() && !inheritor.isInterface()) { //check for sibling implementation
if (methodContainingClass.isInterface() && !inheritor.isInterface()) { //check for sibling implementation
final PsiClass superClass = inheritor.getSuperClass();
if (superClass != null && !superClass.isInheritor(parentClass, true) && superClass.findMethodsByName(name, true).length > 0) {
MethodSignature signature = getSuperSignature(inheritor, parentClass, method);
if (superClass != null && !superClass.isInheritor(methodContainingClass, true) && superClass.findMethodsByName(name, true).length > 0) {
MethodSignature signature = getSuperSignature(inheritor, methodContainingClass, method);
PsiMethod derived = MethodSignatureUtil.findMethodInSuperClassBySignatureInDerived(inheritor, superClass, signature, true);
if (derived != null && isAcceptable(derived, method)) {
if (derived != null && isAcceptable(project, derived, inheritor, method, methodContainingClass)) {
return derived;
}
}
@@ -94,10 +122,13 @@ public class JavaOverridingMethodsSearcher implements QueryExecutor<PsiMethod, O
}
private static boolean isAcceptable(final PsiMethod found, final PsiMethod method) {
private static boolean isAcceptable(@NotNull Project project,
@NotNull PsiMethod found,
@NotNull PsiClass foundContainingClass,
@NotNull PsiMethod method,
@NotNull PsiClass methodContainingClass) {
return !found.hasModifierProperty(PsiModifier.STATIC) &&
(!method.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) ||
JavaPsiFacade.getInstance(found.getProject())
.arePackagesTheSame(method.getContainingClass(), found.getContainingClass()));
JavaPsiFacade.getInstance(project).arePackagesTheSame(methodContainingClass, foundContainingClass));
}
}
@@ -16,6 +16,7 @@
package com.intellij.psi.util;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
@@ -23,6 +24,7 @@ import com.intellij.openapi.projectRoots.JavaVersionService;
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
@@ -1280,4 +1282,282 @@ public final class PsiUtil extends PsiUtilCore {
}
}
}
public static class NullPsiClass extends NullPsiElement implements PsiClass {
@Nullable
@Override
public ItemPresentation getPresentation() {
throw createException();
}
@Nullable
@Override
public PsiDocComment getDocComment() {
throw createException();
}
@Override
public boolean hasTypeParameters() {
throw createException();
}
@Nullable
@Override
public PsiModifierList getModifierList() {
throw createException();
}
@Nullable
@Override
public String getName() {
throw createException();
}
@Override
public boolean isDeprecated() {
throw createException();
}
@Nullable
@Override
public PsiTypeParameterList getTypeParameterList() {
throw createException();
}
@Override
public void navigate(boolean requestFocus) {
throw createException();
}
@Override
public boolean canNavigate() {
throw createException();
}
@Override
public boolean hasModifierProperty(@PsiModifier.ModifierConstant @NonNls @NotNull String name) {
throw createException();
}
@NotNull
@Override
public PsiTypeParameter[] getTypeParameters() {
throw createException();
}
@Override
public boolean canNavigateToSource() {
throw createException();
}
@Nullable
@Override
public String getQualifiedName() {
throw createException();
}
@Override
public boolean isInterface() {
throw createException();
}
@Override
public boolean isAnnotationType() {
throw createException();
}
@Override
public boolean isEnum() {
throw createException();
}
@Nullable
@Override
public PsiReferenceList getExtendsList() {
throw createException();
}
@Nullable
@Override
public PsiReferenceList getImplementsList() {
throw createException();
}
@NotNull
@Override
public PsiClassType[] getExtendsListTypes() {
throw createException();
}
@NotNull
@Override
public PsiClassType[] getImplementsListTypes() {
throw createException();
}
@Nullable
@Override
public PsiClass getSuperClass() {
throw createException();
}
@Override
public PsiClass[] getInterfaces() {
throw createException();
}
@NotNull
@Override
public PsiClass[] getSupers() {
throw createException();
}
@NotNull
@Override
public PsiClassType[] getSuperTypes() {
throw createException();
}
@NotNull
@Override
public PsiField[] getFields() {
throw createException();
}
@NotNull
@Override
public PsiMethod[] getMethods() {
throw createException();
}
@NotNull
@Override
public PsiMethod[] getConstructors() {
throw createException();
}
@NotNull
@Override
public PsiClass[] getInnerClasses() {
throw createException();
}
@NotNull
@Override
public PsiClassInitializer[] getInitializers() {
throw createException();
}
@NotNull
@Override
public PsiField[] getAllFields() {
throw createException();
}
@NotNull
@Override
public PsiMethod[] getAllMethods() {
throw createException();
}
@NotNull
@Override
public PsiClass[] getAllInnerClasses() {
throw createException();
}
@Nullable
@Override
public PsiField findFieldByName(@NonNls String name, boolean checkBases) {
throw createException();
}
@Nullable
@Override
public PsiMethod findMethodBySignature(PsiMethod patternMethod, boolean checkBases) {
throw createException();
}
@NotNull
@Override
public PsiMethod[] findMethodsBySignature(PsiMethod patternMethod, boolean checkBases) {
throw createException();
}
@NotNull
@Override
public PsiMethod[] findMethodsByName(@NonNls String name, boolean checkBases) {
throw createException();
}
@NotNull
@Override
public List<Pair<PsiMethod, PsiSubstitutor>> findMethodsAndTheirSubstitutorsByName(@NonNls String name, boolean checkBases) {
throw createException();
}
@NotNull
@Override
public List<Pair<PsiMethod, PsiSubstitutor>> getAllMethodsAndTheirSubstitutors() {
throw createException();
}
@Nullable
@Override
public PsiClass findInnerClassByName(@NonNls String name, boolean checkBases) {
throw createException();
}
@Nullable
@Override
public PsiElement getLBrace() {
throw createException();
}
@Nullable
@Override
public PsiElement getRBrace() {
throw createException();
}
@Nullable
@Override
public PsiIdentifier getNameIdentifier() {
throw createException();
}
@Override
public PsiElement getScope() {
throw createException();
}
@Override
public boolean isInheritor(@NotNull PsiClass baseClass, boolean checkDeep) {
throw createException();
}
@Override
public boolean isInheritorDeep(PsiClass baseClass, @Nullable PsiClass classToByPass) {
throw createException();
}
@Nullable
@Override
public PsiClass getContainingClass() {
throw createException();
}
@NotNull
@Override
public Collection<HierarchicalMethodSignature> getVisibleSignatures() {
throw createException();
}
@Override
public PsiElement setName(@NonNls @NotNull String name) {
throw createException();
}
}
public static final PsiClass NULL_PSI_CLASS = new NullPsiClass();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* 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.
@@ -59,7 +59,7 @@ import java.util.List;
public class PsiUtilCore {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.util.PsiUtilCore");
public static final PsiElement NULL_PSI_ELEMENT = new NullPsiElement();
private static class NullPsiElement implements PsiElement {
protected static class NullPsiElement implements PsiElement {
@Override
@NotNull
public Project getProject() {
@@ -31,7 +31,6 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.FindSuperElementsHelper;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.search.searches.AllOverridingMethodsSearch;
import com.intellij.psi.search.searches.SuperMethodsSearch;
@@ -58,7 +57,10 @@ import org.jetbrains.plugins.groovy.lang.psi.util.GrTraitUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
import javax.swing.*;
import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* @author ilyas
@@ -85,7 +87,7 @@ public class GroovyLineMarkerProvider extends JavaLineMarkerProvider {
final MarkerType type = GroovyMarkerTypes.OVERRIDING_PROPERTY_TYPE;
return new LineMarkerInfo<>(element, element.getTextRange(), icon, Pass.UPDATE_ALL, type.getTooltip(),
type.getNavigationHandler(),
GutterIconRenderer.Alignment.LEFT);
GutterIconRenderer.Alignment.LEFT);
}
}
}
@@ -95,7 +97,7 @@ public class GroovyLineMarkerProvider extends JavaLineMarkerProvider {
final Icon icon = AllIcons.Gutter.OverridingMethod;
final MarkerType type = GroovyMarkerTypes.GR_OVERRIDING_METHOD;
return new LineMarkerInfo<>(element, element.getTextRange(), icon, Pass.UPDATE_ALL, type.getTooltip(),
type.getNavigationHandler(), GutterIconRenderer.Alignment.LEFT);
type.getNavigationHandler(), GutterIconRenderer.Alignment.LEFT);
}
}
//need to draw method separator above docComment
@@ -132,8 +134,8 @@ public class GroovyLineMarkerProvider extends JavaLineMarkerProvider {
}
LineMarkerInfo info =
new LineMarkerInfo<>(element, comment != null ? comment.getTextRange() : element.getTextRange(), null,
Pass.UPDATE_ALL, FunctionUtil.<Object, String>nullConstant(), null,
GutterIconRenderer.Alignment.RIGHT);
Pass.UPDATE_ALL, FunctionUtil.<Object, String>nullConstant(), null,
GutterIconRenderer.Alignment.RIGHT);
EditorColorsScheme scheme = myColorsManager.getGlobalScheme();
info.separatorColor = scheme.getColor(CodeInsightColors.METHOD_SEPARATORS_COLOR);
info.separatorPlacement = SeparatorPlacement.TOP;
@@ -186,7 +188,6 @@ public class GroovyLineMarkerProvider extends JavaLineMarkerProvider {
@Override
public void collectSlowLineMarkers(@NotNull final List<PsiElement> elements, @NotNull final Collection<LineMarkerInfo> result) {
Set<PsiMethod> methods = new HashSet<>();
Map<PsiClass, PsiClass> subClassCache = FindSuperElementsHelper.createSubClassCache();
for (PsiElement element : elements) {
ProgressManager.checkCanceled();
if (element instanceof GrField) {
@@ -202,7 +203,7 @@ public class GroovyLineMarkerProvider extends JavaLineMarkerProvider {
}
}
else if (element instanceof PsiClass && !(element instanceof PsiTypeParameter)) {
collectInheritingClasses((PsiClass)element, result, subClassCache);
collectInheritingClasses((PsiClass)element, result);
}
}
collectOverridingMethods(methods, result);
@@ -244,7 +245,7 @@ public class GroovyLineMarkerProvider extends JavaLineMarkerProvider {
final MarkerType type = element instanceof GrField ? GroovyMarkerTypes.OVERRIDEN_PROPERTY_TYPE
: GroovyMarkerTypes.GR_OVERRIDEN_METHOD;
LineMarkerInfo info = new LineMarkerInfo<>(range, range.getTextRange(), icon, Pass.UPDATE_OVERRIDDEN_MARKERS, type.getTooltip(),
type.getNavigationHandler(), GutterIconRenderer.Alignment.RIGHT);
type.getNavigationHandler(), GutterIconRenderer.Alignment.RIGHT);
result.add(info);
}
}
+2
View File
@@ -446,6 +446,8 @@
serviceImplementation="com.intellij.psi.impl.PsiNameHelperImpl"/>
<projectService serviceInterface="com.intellij.psi.impl.file.impl.JavaFileManager"
serviceImplementation="com.intellij.psi.impl.file.impl.JavaFileManagerImpl"/>
<projectService
serviceImplementation="com.intellij.psi.impl.search.HighlightingCaches"/>
<projectService serviceInterface="com.intellij.codeInsight.guess.GuessManager"
serviceImplementation="com.intellij.codeInsight.guess.impl.GuessManagerImpl"/>
<projectService serviceInterface="com.intellij.psi.impl.source.resolve.JavaResolveCache"