From 308e4f7daf95ee06dc0087c35ef230c59fcd2b0e Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 5 Oct 2020 12:49:26 +0200 Subject: [PATCH] java overload resolution: reuse computed getSubstitutor(false); use cache for method references GitOrigin-RevId: abd73c52013d4924fa66fabdfa67bcba597279f5 --- .../psi/infos/MethodCandidateInfo.java | 18 ++++++++++++---- .../tree/java/MethodReferenceResolver.java | 21 ++++++++++++------- .../JavaMethodsConflictResolver.java | 19 +++++++++++------ 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java b/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java index b5f42b3b51e4..a5417cc2843e 100644 --- a/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java +++ b/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java @@ -20,8 +20,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Arrays; +import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.Supplier; import java.util.stream.Collectors; /** @@ -107,9 +109,17 @@ public class MethodCandidateInfo extends CandidateInfo{ @ApplicabilityLevelConstant public int getPertinentApplicabilityLevel() { + return getPertinentApplicabilityLevel(null); + } + + /** + * @param map reuse substitutor from conflict resolver cache when available + */ + @ApplicabilityLevelConstant + public int getPertinentApplicabilityLevel(@Nullable Map map) { int result = myPertinentApplicabilityLevel; if (result == 0) { - myPertinentApplicabilityLevel = result = getPertinentApplicabilityLevelInner(); + myPertinentApplicabilityLevel = result = getPertinentApplicabilityLevelInner(() -> map != null ? map.get(this) : getSubstitutor(false)); } return result; } @@ -118,7 +128,7 @@ public class MethodCandidateInfo extends CandidateInfo{ * 15.12.2.2 Identify Matching Arity Methods Applicable by Strict Invocation */ @ApplicabilityLevelConstant - private int getPertinentApplicabilityLevelInner() { + private int getPertinentApplicabilityLevelInner(Supplier substitutorSupplier) { if (myArgumentList == null || !myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { return getApplicabilityLevel(); } @@ -127,7 +137,7 @@ public class MethodCandidateInfo extends CandidateInfo{ if (isToInferApplicability()) { //ensure applicability check is performed - getSubstitutor(false); + substitutorSupplier.get(); //already performed checks, so if inference failed, error message should be saved if (myApplicabilityError || isPotentiallyCompatible() != ThreeState.YES) { @@ -136,7 +146,7 @@ public class MethodCandidateInfo extends CandidateInfo{ return isVarargs() ? ApplicabilityLevel.VARARGS : ApplicabilityLevel.FIXED_ARITY; } - final PsiSubstitutor substitutor = getSubstitutor(false); + final PsiSubstitutor substitutor = substitutorSupplier.get(); final Computable computable = () -> computeWithKnownTargetType(() -> { //arg types are calculated here without additional constraints: //non-pertinent to applicability arguments of arguments would be skipped diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodReferenceResolver.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodReferenceResolver.java index acf99e37bb4f..b3ae159f24ca 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodReferenceResolver.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/MethodReferenceResolver.java @@ -19,11 +19,13 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.SmartList; +import com.intellij.util.containers.FactoryMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Objects; public class MethodReferenceResolver implements ResolveCache.PolyVariantContextResolver { @@ -208,7 +210,8 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR } @Override - protected int getPertinentApplicabilityLevel(@NotNull MethodCandidateInfo conflict) { + protected int getPertinentApplicabilityLevel(@NotNull MethodCandidateInfo conflict, + Map map) { return conflict.isVarargs() ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY; } @@ -219,8 +222,9 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR if (conflicts.isEmpty()) return null; if (conflicts.size() == 1) return conflicts.get(0); + final Map map = FactoryMap.create(key -> key.getSubstitutor(false)); - checkSameSignatures(conflicts); + checkSameSignatures(conflicts, map); if (conflicts.size() == 1) return conflicts.get(0); checkAccessStaticLevels(conflicts, true); @@ -254,12 +258,12 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR } } - CandidateInfo candidateInfo = resolveConflicts(firstCandidates, secondCandidates, MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY); + CandidateInfo candidateInfo = resolveConflicts(firstCandidates, secondCandidates, map, MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY); if (candidateInfo != null) { return candidateInfo; } - candidateInfo = resolveConflicts(firstCandidates, secondCandidates, MethodCandidateInfo.ApplicabilityLevel.VARARGS); + candidateInfo = resolveConflicts(firstCandidates, secondCandidates, map, MethodCandidateInfo.ApplicabilityLevel.VARARGS); if (candidateInfo != null) { return candidateInfo; } @@ -346,12 +350,15 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR } } - private CandidateInfo resolveConflicts(@NotNull List firstCandidates, @NotNull List secondCandidates, int applicabilityLevel) { + private CandidateInfo resolveConflicts(@NotNull List firstCandidates, + @NotNull List secondCandidates, + Map map, + int applicabilityLevel) { int firstApplicability = checkApplicability(firstCandidates); - checkSpecifics(firstCandidates, applicabilityLevel); + checkSpecifics(firstCandidates, applicabilityLevel, map, 0); int secondApplicability = checkApplicability(secondCandidates); - checkSpecifics(secondCandidates, applicabilityLevel, null, 1); + checkSpecifics(secondCandidates, applicabilityLevel, map, 1); if (firstApplicability < secondApplicability) { return secondCandidates.size() == 1 ? secondCandidates.get(0) : null; diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java index 00da5b2c8fd4..096e2772a8fa 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java @@ -81,7 +81,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ if (conflicts.size() == 1) return conflicts.get(0); } - final int applicabilityLevel = checkApplicability(conflicts); + final int applicabilityLevel = checkApplicability(conflicts, map); if (conflicts.size() == 1) return conflicts.get(0); // makes no sense to do further checks, because if no one candidate matches by parameters count @@ -186,7 +186,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ checkSameSignatures(conflicts, null); } - private void checkSameSignatures(@NotNull List conflicts, Map map) { + protected void checkSameSignatures(@NotNull List conflicts, Map map) { // candidates should go in order of class hierarchy traversal // in order for this to work Map signatures = new THashMap<>(conflicts.size()); @@ -364,11 +364,17 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ @MethodCandidateInfo.ApplicabilityLevelConstant public int checkApplicability(@NotNull List conflicts) { + return checkApplicability(conflicts, null); + } + + @MethodCandidateInfo.ApplicabilityLevelConstant + public int checkApplicability(@NotNull List conflicts, + Map map) { @MethodCandidateInfo.ApplicabilityLevelConstant int maxApplicabilityLevel = 0; boolean toFilter = false; for (CandidateInfo conflict : conflicts) { ProgressManager.checkCanceled(); - @MethodCandidateInfo.ApplicabilityLevelConstant final int level = getPertinentApplicabilityLevel((MethodCandidateInfo)conflict); + @MethodCandidateInfo.ApplicabilityLevelConstant final int level = getPertinentApplicabilityLevel((MethodCandidateInfo)conflict, map); if (maxApplicabilityLevel > 0 && maxApplicabilityLevel != level) { toFilter = true; } @@ -381,7 +387,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ for (Iterator iterator = conflicts.iterator(); iterator.hasNext();) { ProgressManager.checkCanceled(); CandidateInfo info = iterator.next(); - final int level = getPertinentApplicabilityLevel((MethodCandidateInfo)info); + final int level = getPertinentApplicabilityLevel((MethodCandidateInfo)info, map); if (level < maxApplicabilityLevel) { iterator.remove(); } @@ -391,8 +397,9 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ return maxApplicabilityLevel; } - protected int getPertinentApplicabilityLevel(@NotNull MethodCandidateInfo conflict) { - return conflict.getPertinentApplicabilityLevel(); + protected int getPertinentApplicabilityLevel(@NotNull MethodCandidateInfo conflict, + Map map) { + return conflict.getPertinentApplicabilityLevel(map); } private static int getCheckAccessLevel(@NotNull MethodCandidateInfo method){