From 2db44a1e7fd5304542bcad70d5c18b96ea6ba919 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Fri, 1 Mar 2019 12:55:33 +0700 Subject: [PATCH] ExpectedTypesProvider: allow to finish when at most specified number of candidates are found Fixes IDEA-207951 Ide freeze on showing parameter info --- .../codeInsight/ExpectedTypesProvider.java | 61 ++++++++++++++----- ...ompletionParameterTypeInferencePolicy.java | 7 +-- 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java index d02c261c650d..32400729e37b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java @@ -104,6 +104,15 @@ public class ExpectedTypesProvider { return new ExpectedTypeInfoImpl(type, kind, defaultType, tailType, calledMethod, expectedName); } + @Nullable + public static ExpectedTypeInfo getSingleExpectedTypeForCompletion(@Nullable PsiExpression expr) { + ExpectedTypeInfo[] expectedTypes = getExpectedTypes(expr, true, ourGlobalScopeClassProvider, false, false, 1); + if (expectedTypes.length > 0) { + return expectedTypes[0]; + } + return null; + } + @NotNull public static ExpectedTypeInfo[] getExpectedTypes(@Nullable PsiExpression expr, boolean forCompletion) { return getExpectedTypes(expr, forCompletion, false, false); @@ -124,6 +133,15 @@ public class ExpectedTypesProvider { @NotNull public static ExpectedTypeInfo[] getExpectedTypes(@Nullable PsiExpression expr, boolean forCompletion, ExpectedClassProvider classProvider, final boolean voidable, boolean usedAfter) { + return getExpectedTypes(expr, forCompletion, classProvider, voidable, usedAfter, Integer.MAX_VALUE); + } + + @NotNull + public static ExpectedTypeInfo[] getExpectedTypes(@Nullable PsiExpression expr, + boolean forCompletion, + ExpectedClassProvider classProvider, + boolean voidable, + boolean usedAfter, int maxCandidates) { if (expr == null) return ExpectedTypeInfo.EMPTY_ARRAY; PsiElement parent = expr.getParent(); PsiFunctionalExpression functionalExpression = extractFunctionalExpression(expr); @@ -141,7 +159,7 @@ public class ExpectedTypesProvider { return result; } } - MyParentVisitor visitor = new MyParentVisitor(expr, forCompletion, classProvider, voidable, usedAfter); + MyParentVisitor visitor = new MyParentVisitor(expr, forCompletion, classProvider, voidable, usedAfter, maxCandidates); if (parent != null) { parent.accept(visitor); } @@ -249,6 +267,7 @@ public class ExpectedTypesProvider { private PsiExpression myExpr; private final boolean myForCompletion; private final boolean myUsedAfter; + private final int myMaxCandidates; private final ExpectedClassProvider myClassProvider; private final boolean myVoidable; final List myResult = ContainerUtil.newArrayList(); @@ -258,16 +277,21 @@ public class ExpectedTypesProvider { boolean forCompletion, ExpectedClassProvider classProvider, boolean voidable, - boolean usedAfter) { + boolean usedAfter, + int maxCandidates) { myExpr = expr; myForCompletion = forCompletion; myClassProvider = classProvider; myVoidable = voidable; myUsedAfter = usedAfter; + myMaxCandidates = maxCandidates; } @NotNull public ExpectedTypeInfo[] getResult() { + if (myResult.size() > myMaxCandidates) { + return myResult.subList(0, myMaxCandidates).toArray(ExpectedTypeInfo.EMPTY_ARRAY); + } return myResult.toArray(ExpectedTypeInfo.EMPTY_ARRAY); } @@ -275,7 +299,8 @@ public class ExpectedTypesProvider { public void visitParenthesizedExpression(PsiParenthesizedExpression expression) { PsiElement parent = expression.getParent(); if (parent != null) { - final MyParentVisitor visitor = new MyParentVisitor(expression, myForCompletion, myClassProvider, myVoidable, myUsedAfter); + final MyParentVisitor visitor = new MyParentVisitor(expression, myForCompletion, myClassProvider, myVoidable, myUsedAfter, + myMaxCandidates); parent.accept(visitor); for (final ExpectedTypeInfo info : visitor.myResult) { myResult.add(createInfoImpl(info.getType(), info.getKind(), info.getDefaultType(), TailTypes.RPARENTH, info.getCalledMethod(), @@ -297,7 +322,7 @@ public class ExpectedTypesProvider { @Override public void visitReferenceExpression(@NotNull PsiReferenceExpression expression) { if (myForCompletion) { - final MyParentVisitor visitor = new MyParentVisitor(expression, true, myClassProvider, myVoidable, myUsedAfter); + final MyParentVisitor visitor = new MyParentVisitor(expression, true, myClassProvider, myVoidable, myUsedAfter, myMaxCandidates); expression.getParent().accept(visitor); myResult.addAll(visitor.myResult); return; @@ -647,8 +672,9 @@ public class ExpectedTypesProvider { if (PsiDiamondType.hasDiamond(newExpr)) { final JavaResolveResult[] candidates = PsiDiamondTypeImpl.collectStaticFactories(newExpr, DuplicateConflictResolver.INSTANCE); if (candidates != null) { - final PsiExpressionList argumentList = newExpr.getArgumentList(); - Collections.addAll(myResult, getExpectedArgumentTypesForMethodCall(ContainerUtil.map(candidates, candidate -> (CandidateInfo)candidate, CandidateInfo.EMPTY_ARRAY), argumentList, myExpr, myForCompletion, + final PsiExpressionList argumentList = Objects.requireNonNull(newExpr.getArgumentList()); + CandidateInfo[] converted = ContainerUtil.map(candidates, candidate -> (CandidateInfo)candidate, CandidateInfo.EMPTY_ARRAY); + Collections.addAll(myResult, getExpectedArgumentTypesForMethodCall(converted, argumentList, myExpr, myForCompletion, newExpr.resolveMethod())); } return; @@ -698,7 +724,7 @@ public class ExpectedTypesProvider { if (op == JavaTokenType.EQEQ || op == JavaTokenType.NE) { ContainerUtil.addIfNotNull(myResult, getEqualsType(anotherExpr)); } - final MyParentVisitor visitor = new MyParentVisitor(expr, true, myClassProvider, myVoidable, myUsedAfter); + final MyParentVisitor visitor = new MyParentVisitor(expr, true, myClassProvider, myVoidable, myUsedAfter, myMaxCandidates); myExpr = (PsiExpression)myExpr.getParent(); expr.getParent().accept(visitor); myResult.addAll(visitor.myResult); @@ -898,7 +924,7 @@ public class ExpectedTypesProvider { } PsiElement parent = expr.getParent(); - MyParentVisitor visitor = new MyParentVisitor(expr, false, myClassProvider, myVoidable, myUsedAfter); + MyParentVisitor visitor = new MyParentVisitor(expr, false, myClassProvider, myVoidable, myUsedAfter, myMaxCandidates); myExpr = (PsiExpression)myExpr.getParent(); parent.accept(visitor); ExpectedTypeInfo[] componentTypeInfo = visitor.getResult(); @@ -926,7 +952,7 @@ public class ExpectedTypesProvider { myResult.add(createInfoImpl(PsiType.BOOLEAN, ExpectedTypeInfo.TYPE_STRICTLY, PsiType.BOOLEAN, TailType.NONE)); } else if (myExpr.equals(expr.getThenExpression())) { - ExpectedTypeInfo[] types = getExpectedTypes(expr, myForCompletion); + ExpectedTypeInfo[] types = getExpectedTypes(expr, myForCompletion, ourGlobalScopeClassProvider, false, false, myMaxCandidates); for (int i = 0; i < types.length; i++) { final ExpectedTypeInfo info = types[i]; types[i] = createInfoImpl(info.getType(), info.getKind(), info.getDefaultType(), TailType.COND_EXPR_COLON, info.getCalledMethod(), @@ -938,7 +964,7 @@ public class ExpectedTypesProvider { if (!myExpr.equals(expr.getElseExpression())) { LOG.error(Arrays.asList(expr.getChildren()) + "; " + myExpr); } - Collections.addAll(myResult, getExpectedTypes(expr, myForCompletion)); + Collections.addAll(myResult, getExpectedTypes(expr, myForCompletion, ourGlobalScopeClassProvider, false, false, myMaxCandidates)); } } @@ -1033,7 +1059,7 @@ public class ExpectedTypesProvider { ParameterTypeInferencePolicy policy = forCompletion ? CompletionParameterTypeInferencePolicy.INSTANCE : DefaultParameterTypeInferencePolicy.INSTANCE; - Set array = new LinkedHashSet<>(); + Set set = new LinkedHashSet<>(); for (CandidateInfo candidateInfo : methodCandidates) { PsiMethod method = (PsiMethod)candidateInfo.getElement(); PsiSubstitutor substitutor; @@ -1051,7 +1077,8 @@ public class ExpectedTypesProvider { if (substitutor == null) { return ExpectedTypeInfo.EMPTY_ARRAY; } - inferMethodCallArgumentTypes(argument, forCompletion, args, index, method, substitutor, array); + inferMethodCallArgumentTypes(argument, forCompletion, args, index, method, substitutor, set); + if (set.size() >= myMaxCandidates) break; if (leftArgs != null && candidateInfo instanceof MethodCandidateInfo) { Computable computable = () -> ((MethodCandidateInfo)candidateInfo).inferSubstitutorFromArgs(policy, leftArgs); @@ -1059,13 +1086,14 @@ public class ExpectedTypesProvider { ? computable.compute() : MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(argumentList, false, computable); if (substitutor != null) { - inferMethodCallArgumentTypes(argument, forCompletion, leftArgs, index, method, substitutor, array); + inferMethodCallArgumentTypes(argument, forCompletion, leftArgs, index, method, substitutor, set); + if (set.size() >= myMaxCandidates) break; } } } // try to find some variants without considering previous argument PRIMITIVE_TYPES - if (forCompletion && array.isEmpty()) { + if (forCompletion && set.isEmpty()) { for (CandidateInfo candidate : methodCandidates) { PsiMethod method = (PsiMethod)candidate.getElement(); PsiSubstitutor substitutor = candidate.getSubstitutor(); @@ -1076,11 +1104,12 @@ public class ExpectedTypesProvider { TailType tailType = getMethodArgumentTailType(argument, index, method, substitutor, params); ExpectedTypeInfoImpl info = createInfoImpl(paramType, ExpectedTypeInfo.TYPE_OR_SUBTYPE, paramType, tailType, method, getPropertyName(param)); - array.add(info); + set.add(info); + if (set.size() >= myMaxCandidates) break; } } - return array.toArray(ExpectedTypeInfo.EMPTY_ARRAY); + return set.toArray(ExpectedTypeInfo.EMPTY_ARRAY); } @NotNull diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/CompletionParameterTypeInferencePolicy.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/CompletionParameterTypeInferencePolicy.java index 6ea0c50889a4..b157e46283ea 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/CompletionParameterTypeInferencePolicy.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/CompletionParameterTypeInferencePolicy.java @@ -31,11 +31,8 @@ public class CompletionParameterTypeInferencePolicy extends ProcessCandidatePara @Override public PsiType getDefaultExpectedType(PsiCallExpression methodCall) { - ExpectedTypeInfo[] expectedTypes = ExpectedTypesProvider.getExpectedTypes(methodCall, true); - if (expectedTypes.length > 0) { - return expectedTypes[0].getType(); - } - return PsiType.NULL; + ExpectedTypeInfo expectedType = ExpectedTypesProvider.getSingleExpectedTypeForCompletion(methodCall); + return expectedType == null ? PsiType.NULL : expectedType.getType(); } @Override