[functional expressions search] check method equality when applicable (IDEA-276298)

otherwise unrelated lambdas/method references may land in results when intermediate inheritors contain default methods

GitOrigin-RevId: aa5baae37ff676ca477ca41d82b782c42d5fda6c
This commit is contained in:
Anna Kozlova
2021-08-18 13:50:45 +02:00
committed by intellij-monorepo-bot
parent d43848c086
commit f33a1f5426
6 changed files with 62 additions and 33 deletions

View File

@@ -25,10 +25,7 @@ import com.intellij.psi.search.searches.FunctionalExpressionSearch;
import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.search.searches.OverridingMethodsSearch;
import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.PsiUtilCore; import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.ArrayUtil; import com.intellij.util.*;
import com.intellij.util.CommonProcessors;
import com.intellij.util.Function;
import com.intellij.util.NullableFunction;
import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -253,10 +250,7 @@ public class MarkerType {
GlobalSearchScope scope = GlobalSearchScope.allScope(PsiUtilCore.getProjectInReadAction(method)); GlobalSearchScope scope = GlobalSearchScope.allScope(PsiUtilCore.getProjectInReadAction(method));
OverridingMethodsSearch.search(method, scope,true).forEach(new PsiElementProcessorAdapter<>(collectProcessor)); OverridingMethodsSearch.search(method, scope,true).forEach(new PsiElementProcessorAdapter<>(collectProcessor));
if (isAbstract && collectProcessor.getCollection().size() < 2) { if (isAbstract && collectProcessor.getCollection().size() < 2) {
final PsiClass aClass = ReadAction.compute(method::getContainingClass); FunctionalExpressionSearch.search(method).forEach(new PsiElementProcessorAdapter<>(collectExprProcessor));
if (aClass != null) {
FunctionalExpressionSearch.search(aClass).forEach(new PsiElementProcessorAdapter<>(collectExprProcessor));
}
} }
}, JavaAnalysisBundle.message("searching.for.overriding.methods"), true, method.getProject(), (JComponent)e.getComponent())) { }, JavaAnalysisBundle.message("searching.for.overriding.methods"), true, method.getProject(), (JComponent)e.getComponent())) {
return; return;
@@ -353,8 +347,10 @@ public class MarkerType {
super(project, title, createComparatorWrapper((Comparator)renderer.getComparator())); super(project, title, createComparatorWrapper((Comparator)renderer.getComparator()));
} }
void collectFunctionalInheritors(@NotNull ProgressIndicator indicator, PsiClass psiClass) { void collectFunctionalInheritors(@NotNull ProgressIndicator indicator, PsiMember member) {
FunctionalExpressionSearch.search(psiClass).forEach(expr -> { Query<PsiFunctionalExpression> search = member instanceof PsiClass ? FunctionalExpressionSearch.search((PsiClass)member)
: FunctionalExpressionSearch.search((PsiMethod)member);
search.forEach(expr -> {
if (!updateComponent(expr)) { if (!updateComponent(expr)) {
indicator.cancel(); indicator.cancel();
} }
@@ -449,9 +445,7 @@ public class MarkerType {
return super.process(psiMethod); return super.process(psiMethod);
} }
}); });
if (ReadAction.compute(() -> myMethod.hasModifierProperty(PsiModifier.ABSTRACT))) { collectFunctionalInheritors(indicator, myMethod);
collectFunctionalInheritors(indicator, ReadAction.compute(myMethod::getContainingClass));
}
} }
} }
} }

View File

@@ -92,17 +92,14 @@ public class JavaFindUsagesHandler extends FindUsagesHandler {
} }
} }
final PsiClass aClass = ReadAction.compute(method::getContainingClass); FunctionalExpressionSearch.search(method).forEach(element -> {
if (aClass != null) { if (element instanceof PsiLambdaExpression) {
FunctionalExpressionSearch.search(aClass).forEach(element -> { PsiParameter[] parameters = ((PsiLambdaExpression)element).getParameterList().getParameters();
if (element instanceof PsiLambdaExpression) { if (idx < parameters.length) {
PsiParameter[] parameters = ((PsiLambdaExpression)element).getParameterList().getParameters(); elementsToSearch.add(parameters[idx]);
if (idx < parameters.length) {
elementsToSearch.add(parameters[idx]);
}
} }
}); }
} });
return PsiUtilCore.toPsiElementArray(elementsToSearch); return PsiUtilCore.toPsiElementArray(elementsToSearch);
} }
@@ -122,7 +119,7 @@ public class JavaFindUsagesHandler extends FindUsagesHandler {
ProgressManager pm = ProgressManager.getInstance(); ProgressManager pm = ProgressManager.getInstance();
boolean hasOverriden = pm.runProcessWithProgressSynchronously(() -> boolean hasOverriden = pm.runProcessWithProgressSynchronously(() ->
OverridingMethodsSearch.search(method).findFirst() != null || FunctionalExpressionSearch.search(aClass).findFirst() != null, OverridingMethodsSearch.search(method).findFirst() != null || FunctionalExpressionSearch.search(method).findFirst() != null,
JavaBundle.message("progress.title.detect.overridden.methods"), true, getProject()) == Boolean.TRUE; JavaBundle.message("progress.title.detect.overridden.methods"), true, getProject()) == Boolean.TRUE;
if (hasOverriden && myFactory.getFindVariableOptions().isSearchInOverridingMethods) { if (hasOverriden && myFactory.getFindVariableOptions().isSearchInOverridingMethods) {

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. // Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.psi.search.searches; package com.intellij.psi.search.searches;
import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.application.ReadAction;
@@ -11,21 +11,36 @@ import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.EmptyQuery; import com.intellij.util.EmptyQuery;
import com.intellij.util.Query; import com.intellij.util.Query;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public final class FunctionalExpressionSearch extends ExtensibleQueryFactory<PsiFunctionalExpression, FunctionalExpressionSearch.SearchParameters> { public final class FunctionalExpressionSearch extends ExtensibleQueryFactory<PsiFunctionalExpression, FunctionalExpressionSearch.SearchParameters> {
private static final FunctionalExpressionSearch INSTANCE = new FunctionalExpressionSearch(); private static final FunctionalExpressionSearch INSTANCE = new FunctionalExpressionSearch();
public static class SearchParameters { public static class SearchParameters {
private final PsiClass myElementToSearch; private final PsiClass myElementToSearch;
private final PsiMethod myMethod;
private final SearchScope myScope; private final SearchScope myScope;
private final @NotNull Project myProject; private final @NotNull Project myProject;
public SearchParameters(@NotNull PsiClass aClass, @NotNull SearchScope scope) { public SearchParameters(@NotNull PsiClass aClass,
@NotNull SearchScope scope) {
this(aClass, null, scope);
}
public SearchParameters(@NotNull PsiClass aClass,
@Nullable PsiMethod psiMethod,
@NotNull SearchScope scope) {
myProject = aClass.getProject(); myProject = aClass.getProject();
myElementToSearch = aClass; myElementToSearch = aClass;
myMethod = psiMethod;
myScope = scope; myScope = scope;
} }
@Nullable
public PsiMethod getMethod() {
return myMethod;
}
@NotNull @NotNull
public PsiClass getElementToSearch() { public PsiClass getElementToSearch() {
return myElementToSearch; return myElementToSearch;
@@ -56,10 +71,10 @@ public final class FunctionalExpressionSearch extends ExtensibleQueryFactory<Psi
@NotNull @NotNull
public static Query<PsiFunctionalExpression> search(@NotNull PsiMethod psiMethod, @NotNull SearchScope scope) { public static Query<PsiFunctionalExpression> search(@NotNull PsiMethod psiMethod, @NotNull SearchScope scope) {
return ReadAction.compute(() -> { return ReadAction.compute(() -> {
if (!psiMethod.hasModifierProperty(PsiModifier.STATIC) && !psiMethod.hasModifierProperty(PsiModifier.DEFAULT)) { if (psiMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
PsiClass containingClass = psiMethod.getContainingClass(); PsiClass containingClass = psiMethod.getContainingClass();
if (containingClass != null) { if (containingClass != null) {
return INSTANCE.createUniqueResultsQuery(new SearchParameters(containingClass, scope)); return INSTANCE.createUniqueResultsQuery(new SearchParameters(containingClass, psiMethod, scope));
} }
} }
return EmptyQuery.getEmptyQuery(); return EmptyQuery.getEmptyQuery();

View File

@@ -39,10 +39,7 @@ import com.intellij.psi.search.searches.FunctionalExpressionSearch.SearchParamet
import com.intellij.psi.stubs.StubIndex; import com.intellij.psi.stubs.StubIndex;
import com.intellij.psi.stubs.StubTextInconsistencyException; import com.intellij.psi.stubs.StubTextInconsistencyException;
import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.Processor; import com.intellij.util.Processor;
import com.intellij.util.Processors; import com.intellij.util.Processors;
import com.intellij.util.ThreeState; import com.intellij.util.ThreeState;
@@ -94,6 +91,11 @@ public final class JavaFunctionalExpressionSearcher extends QueryExecutorBase<Ps
PsiMethod saMethod = Objects.requireNonNull(LambdaUtil.getFunctionalInterfaceMethod(samClass)); PsiMethod saMethod = Objects.requireNonNull(LambdaUtil.getFunctionalInterfaceMethod(samClass));
PsiType samType = saMethod.getReturnType(); PsiType samType = saMethod.getReturnType();
if (samType == null) continue; if (samType == null) continue;
if (session.method != null &&
!saMethod.equals(session.method) &&
!MethodSignatureUtil.isSuperMethod(saMethod, session.method)) {
continue;
}
SearchScope scope = psiSearchHelper.getUseScope(samClass).intersectWith(session.scope); SearchScope scope = psiSearchHelper.getUseScope(samClass).intersectWith(session.scope);
descriptors.add(new SamDescriptor(samClass, saMethod, samType, GlobalSearchScopeUtil.toGlobalSearchScope(scope, project))); descriptors.add(new SamDescriptor(samClass, saMethod, samType, GlobalSearchScopeUtil.toGlobalSearchScope(scope, project)));
@@ -461,10 +463,12 @@ public final class JavaFunctionalExpressionSearcher extends QueryExecutorBase<Ps
private final AtomicInteger sureExprsAfterLightCheck = new AtomicInteger(); private final AtomicInteger sureExprsAfterLightCheck = new AtomicInteger();
private final AtomicInteger exprsToHeavyCheck = new AtomicInteger(); private final AtomicInteger exprsToHeavyCheck = new AtomicInteger();
private final Set<VirtualFile> filesLookedInside = ContainerUtil.newConcurrentSet(); private final Set<VirtualFile> filesLookedInside = ContainerUtil.newConcurrentSet();
private final @Nullable PsiMethod method;
public Session(@NotNull SearchParameters parameters, @NotNull Processor<? super PsiFunctionalExpression> consumer) { public Session(@NotNull SearchParameters parameters, @NotNull Processor<? super PsiFunctionalExpression> consumer) {
this.consumer = consumer; this.consumer = consumer;
elementToSearch = parameters.getElementToSearch(); elementToSearch = parameters.getElementToSearch();
method = parameters.getMethod();
project = parameters.getProject(); project = parameters.getProject();
psiManager = PsiManager.getInstance(project); psiManager = PsiManager.getInstance(project);
scope = parameters.getEffectiveSearchScope(); scope = parameters.getEffectiveSearchScope();

View File

@@ -0,0 +1,14 @@
class Clazz {
public static void main(String[] args) {
Child child = x -> System.out.println();
}
}
interface I {
void execute(int i);
}
interface Child extends I {
default void execute(int i) {}
void f(int i);
}

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. // Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.psi.impl.search; package com.intellij.psi.impl.search;
import com.intellij.JavaTestUtil; import com.intellij.JavaTestUtil;
@@ -111,6 +111,11 @@ public class FindFunctionalInterfaceTest extends LightJavaCodeInsightFixtureTest
assertSize(1, FunctionalExpressionSearch.search(findClass("I")).findAll()); assertSize(1, FunctionalExpressionSearch.search(findClass("I")).findAll());
} }
public void testDefaultInHierarchy() {
configure();
assertEmpty(FunctionalExpressionSearch.search(findClass("I").getMethods()[0]).findAll());
}
public void testStreamOfLikeApiWithField() { public void testStreamOfLikeApiWithField() {
myFixture.addClass("class Base { StrType Stream = null; }"); myFixture.addClass("class Base { StrType Stream = null; }");
configure(); configure();