mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
ExpectedTypesProvider: allow to finish when at most specified number of candidates are found
Fixes IDEA-207951 Ide freeze on showing parameter info
This commit is contained in:
@@ -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<ExpectedTypeInfo> 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<ExpectedTypeInfo> array = new LinkedHashSet<>();
|
||||
Set<ExpectedTypeInfo> 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<PsiSubstitutor> 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
|
||||
|
||||
+2
-5
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user