replace 'boolean forCompletion' parameter in PsiResolveHelper with ParameterTypeInferencePolicy class

This commit is contained in:
Dmitry Jemerov
2011-10-17 16:14:48 +02:00
parent 984a7bdb3c
commit 9435ad7311
17 changed files with 317 additions and 133 deletions
@@ -17,6 +17,8 @@ package com.intellij.codeInsight;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.CompletionParameterTypeInferencePolicy;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nullable;
@@ -159,13 +161,14 @@ public class ExpectedTypeUtil {
}
@Nullable
public static PsiSubstitutor inferSubstitutor(final PsiMethod method, final PsiMethodCallExpression callExpr, final boolean forCompletion) {
public static PsiSubstitutor inferSubstitutor(final PsiMethod method, final PsiMethodCallExpression callExpr, boolean forCompletion) {
final PsiResolveHelper helper = JavaPsiFacade.getInstance(method.getProject()).getResolveHelper();
final PsiParameter[] parameters = method.getParameterList().getParameters();
PsiExpression[] args = callExpr.getArgumentList().getExpressions();
PsiSubstitutor result = PsiSubstitutor.EMPTY;
for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(method.getContainingClass())) {
PsiType type = helper.inferTypeForMethodTypeParameter(typeParameter, parameters, args, PsiSubstitutor.EMPTY, callExpr.getParent(), forCompletion);
PsiType type = helper.inferTypeForMethodTypeParameter(typeParameter, parameters, args, PsiSubstitutor.EMPTY, callExpr.getParent(),
forCompletion ? CompletionParameterTypeInferencePolicy.INSTANCE : DefaultParameterTypeInferencePolicy.INSTANCE);
if (PsiType.NULL.equals(type)) return null;
result = result.put(typeParameter, type);
}
@@ -22,6 +22,9 @@ import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.impl.source.jsp.jspJava.JspMethodCall;
import com.intellij.psi.impl.source.resolve.CompletionParameterTypeInferencePolicy;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.search.GlobalSearchScope;
@@ -915,13 +918,15 @@ public class ExpectedTypesProvider {
leftArgs = null;
}
ParameterTypeInferencePolicy policy = forCompletion ? CompletionParameterTypeInferencePolicy.INSTANCE : DefaultParameterTypeInferencePolicy.INSTANCE;
Set<ExpectedTypeInfo> array = new LinkedHashSet<ExpectedTypeInfo>();
for (CandidateInfo candidateInfo : methodCandidates) {
PsiMethod method = (PsiMethod)candidateInfo.getElement();
PsiSubstitutor substitutor;
if (candidateInfo instanceof MethodCandidateInfo) {
final MethodCandidateInfo info = (MethodCandidateInfo)candidateInfo;
substitutor = info.inferTypeArguments(forCompletion);
substitutor = info.inferTypeArguments(policy);
if (!info.isStaticsScopeCorrect() && method != null && !method.hasModifierProperty(PsiModifier.STATIC)) continue;
}
else {
@@ -930,7 +935,7 @@ public class ExpectedTypesProvider {
inferMethodCallArgumentTypes(argument, forCompletion, args, index, method, substitutor, array);
if (leftArgs != null && candidateInfo instanceof MethodCandidateInfo) {
substitutor = ((MethodCandidateInfo)candidateInfo).inferTypeArguments(forCompletion, leftArgs);
substitutor = ((MethodCandidateInfo)candidateInfo).inferTypeArguments(policy, leftArgs);
inferMethodCallArgumentTypes(argument, forCompletion, leftArgs, index, method, substitutor, array);
}
}
@@ -26,6 +26,7 @@ import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.search.PsiSearchHelper;
import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.typeMigration.TypeMigrationLabeler;
@@ -104,7 +105,8 @@ public class VariableTypeFromCallFix implements IntentionAction {
if (varClass != null) {
final PsiSubstitutor psiSubstitutor = resolveHelper.inferTypeArguments(varClass.getTypeParameters(),
parameters,
expressions, PsiSubstitutor.EMPTY, resolved, false);
expressions, PsiSubstitutor.EMPTY, resolved,
DefaultParameterTypeInferencePolicy.INSTANCE);
final PsiClassType appropriateVarType = JavaPsiFacade.getElementFactory(expression.getProject()).createType(varClass, psiSubstitutor);
if (!varType.equals(appropriateVarType)) {
QuickFixAction.registerQuickFixAction(highlightInfo, new VariableTypeFromCallFix(appropriateVarType, (PsiVariable) resolved));
@@ -23,6 +23,7 @@ import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.lang.parameterInfo.*;
import com.intellij.openapi.project.DumbAware;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.CompletionParameterTypeInferencePolicy;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.tree.IElementType;
@@ -125,7 +126,7 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc
for (int i = 0; i < candidates.length; i++) {
CandidateInfo candidate = (CandidateInfo)candidates[i];
PsiMethod method = (PsiMethod)candidate.getElement();
PsiSubstitutor substitutor = candidate instanceof MethodCandidateInfo && ((MethodCandidateInfo)candidate).isInferencePossible() ? ((MethodCandidateInfo)candidate).inferTypeArguments(true) : candidate.getSubstitutor();
PsiSubstitutor substitutor = getCandidateInfoSubstitutor(candidate);
assert substitutor != null;
if (!method.isValid() || !substitutor.isValid()) {
@@ -193,6 +194,12 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc
}
}
private static PsiSubstitutor getCandidateInfoSubstitutor(CandidateInfo candidate) {
return candidate instanceof MethodCandidateInfo && ((MethodCandidateInfo)candidate).isInferencePossible()
? ((MethodCandidateInfo)candidate).inferTypeArguments(CompletionParameterTypeInferencePolicy.INSTANCE)
: candidate.getSubstitutor();
}
private static boolean isAssignableParametersBeforeGivenIndex(final PsiParameter[] parms,
final PsiExpression[] args,
int length,
@@ -408,7 +415,7 @@ public class MethodParameterInfoHandler implements ParameterInfoHandlerWithTabAc
public void updateUI(final Object p, final ParameterInfoUIContext context) {
if (p instanceof CandidateInfo) {
CandidateInfo info = (CandidateInfo)p;
updateMethodPresentation((PsiMethod)info.getElement(), info instanceof MethodCandidateInfo && ((MethodCandidateInfo)info).isInferencePossible() ? ((MethodCandidateInfo)info).inferTypeArguments(true) : info.getSubstitutor(), context);
updateMethodPresentation((PsiMethod)info.getElement(), getCandidateInfoSubstitutor(info), context);
}
else {
updateMethodPresentation((PsiMethod)p, null, context);
@@ -20,6 +20,7 @@ import com.intellij.codeInspection.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
@@ -102,11 +103,12 @@ public class RedundantTypeArgsInspection extends GenericsInspectionToolBase {
PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(expression.getProject()).getResolveHelper();
for (int i = 0; i < typeParameters.length; i++) {
PsiTypeParameter typeParameter = typeParameters[i];
final PsiType inferedType = resolveHelper.inferTypeForMethodTypeParameter(typeParameter, parameters,
final PsiType inferredType = resolveHelper.inferTypeForMethodTypeParameter(typeParameter, parameters,
argumentList.getExpressions(),
resolveResult.getSubstitutor(), expression, false);
if (!typeArguments[i].equals(inferedType)) return;
if (PsiUtil.resolveClassInType(method.getReturnType()) == typeParameter && PsiPrimitiveType.getUnboxedType(inferedType) != null) return;
resolveResult.getSubstitutor(), expression,
DefaultParameterTypeInferencePolicy.INSTANCE);
if (!typeArguments[i].equals(inferredType)) return;
if (PsiUtil.resolveClassInType(method.getReturnType()) == typeParameter && PsiPrimitiveType.getUnboxedType(inferredType) != null) return;
}
final PsiCallExpression copy = (PsiCallExpression)expression.copy(); //see IDEADEV-8174
@@ -0,0 +1,129 @@
/*
* Copyright 2000-2011 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.source.resolve;
import com.intellij.codeInsight.ExpectedTypeInfo;
import com.intellij.codeInsight.ExpectedTypesProvider;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.scope.MethodProcessorSetupFailedException;
import com.intellij.psi.scope.processor.MethodCandidatesProcessor;
import com.intellij.psi.scope.util.PsiScopesUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ArrayUtil;
import java.util.Arrays;
import java.util.List;
/**
* @author yole
*/
public class CompletionParameterTypeInferencePolicy extends ParameterTypeInferencePolicy {
public static final CompletionParameterTypeInferencePolicy INSTANCE = new CompletionParameterTypeInferencePolicy();
private CompletionParameterTypeInferencePolicy() {
}
@Override
public Pair<PsiType, ConstraintType> inferTypeConstraintFromCallContext(PsiCallExpression innerMethodCall,
PsiExpressionList expressionList,
PsiCallExpression contextCall,
PsiTypeParameter typeParameter) {
final MethodCandidatesProcessor processor = new MethodCandidatesProcessor(contextCall);
try {
//can't call resolve() since it obtains full substitution, that may result in infinite recursion
PsiScopesUtil.setupAndRunProcessor(processor, contextCall, false);
PsiExpression[] expressions = expressionList.getExpressions();
int i = ArrayUtil.find(expressions, innerMethodCall);
assert i >= 0;
final JavaResolveResult[] results = processor.getResult();
PsiMethod owner = (PsiMethod)typeParameter.getOwner();
if (owner == null) return null;
final PsiType innerReturnType = owner.getReturnType();
for (final JavaResolveResult result : results) {
final PsiSubstitutor substitutor;
if (result instanceof MethodCandidateInfo) {
List<PsiExpression> leftArgs = Arrays.asList(expressions).subList(0, i);
substitutor = ((MethodCandidateInfo)result).inferTypeArguments(this, leftArgs.toArray(new PsiExpression[leftArgs.size()]));
} else {
substitutor = result.getSubstitutor();
}
final PsiElement element = result.getElement();
if (element instanceof PsiMethod) {
final PsiMethod method = (PsiMethod)element;
final PsiParameter[] parameters = method.getParameterList().getParameters();
PsiParameter parameter = null;
if (parameters.length > i) {
parameter = parameters[i];
}
else if (method.isVarArgs()) {
parameter = parameters[parameters.length - 1];
}
if (parameter != null) {
final PsiParameter finalParameter = parameter;
PsiType type = PsiResolveHelperImpl.ourGuard.doPreventingRecursion(innerMethodCall, true, new Computable<PsiType>() {
@Override
public PsiType compute() {
return substitutor.substitute(finalParameter.getType());
}
});
final Pair<PsiType, ConstraintType> constraint =
PsiResolveHelperImpl.getSubstitutionForTypeParameterConstraint(typeParameter, innerReturnType, type, false,
PsiUtil.getLanguageLevel(innerMethodCall));
if (constraint != null) return constraint;
}
}
}
}
catch (MethodProcessorSetupFailedException ev) {
return null;
}
return null;
}
@Override
public PsiType getDefaultExpectedType(PsiCallExpression methodCall) {
ExpectedTypeInfo[] expectedTypes = ExpectedTypesProvider.getExpectedTypes(methodCall, true);
if (expectedTypes.length > 0) {
return expectedTypes[0].getType();
}
return PsiType.NULL;
}
@Override
public Pair<PsiType, ConstraintType> getInferredTypeWithNoConstraint(PsiManager psiManager, PsiType superType) {
if (!(superType instanceof PsiWildcardType)) {
return new Pair<PsiType, ConstraintType>(PsiWildcardType.createExtends(psiManager, superType), ConstraintType.EQUALS);
}
else {
return new Pair<PsiType, ConstraintType>(superType, ConstraintType.SUBTYPE);
}
}
@Override
public PsiType adjustInferredType(PsiManager manager, PsiType guess, ConstraintType constraintType) {
if (guess != null && !(guess instanceof PsiWildcardType)) {
if (constraintType == ConstraintType.SUPERTYPE) return PsiWildcardType.createExtends(manager, guess);
else if (constraintType == ConstraintType.SUBTYPE) return PsiWildcardType.createSuper(manager, guess);
}
return guess;
}
}
@@ -15,16 +15,12 @@
*/
package com.intellij.psi.impl.source.resolve;
import com.intellij.codeInsight.ExpectedTypeInfo;
import com.intellij.codeInsight.ExpectedTypesProvider;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.RecursionGuard;
import com.intellij.openapi.util.RecursionManager;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.scope.MethodProcessorSetupFailedException;
import com.intellij.psi.scope.processor.MethodCandidatesProcessor;
import com.intellij.psi.scope.processor.MethodResolverProcessor;
@@ -38,11 +34,8 @@ import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
public class PsiResolveHelperImpl implements PsiResolveHelper {
private static final RecursionGuard ourGuard = RecursionManager.createGuard("typeArgInference");
static final RecursionGuard ourGuard = RecursionManager.createGuard("typeArgInference");
private final PsiManager myManager;
public PsiResolveHelperImpl(PsiManager manager) {
@@ -146,7 +139,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
PsiExpression[] arguments,
PsiSubstitutor partialSubstitutor,
PsiElement parent,
final boolean forCompletion) {
final ParameterTypeInferencePolicy policy) {
PsiWildcardType wildcardToCapture = null;
PsiType lowerBound = PsiType.NULL;
PsiType upperBound = PsiType.NULL;
@@ -218,7 +211,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
if (parent != null) {
final Pair<PsiType, ConstraintType> constraint =
inferMethodTypeParameterFromParent(typeParameter, partialSubstitutor, parent, forCompletion);
inferMethodTypeParameterFromParent(typeParameter, partialSubstitutor, parent, policy);
if (constraint != null) {
if (constraint.getSecond() != ConstraintType.SUBTYPE) {
return constraint;
@@ -245,10 +238,10 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
@NotNull PsiExpression[] arguments,
@NotNull PsiSubstitutor partialSubstitutor,
PsiElement parent,
final boolean forCompletion) {
final ParameterTypeInferencePolicy policy) {
final Pair<PsiType, ConstraintType> constraint =
inferTypeForMethodTypeParameterInner(typeParameter, parameters, arguments, partialSubstitutor, parent, forCompletion);
inferTypeForMethodTypeParameterInner(typeParameter, parameters, arguments, partialSubstitutor, parent, policy);
if (constraint == null) return PsiType.NULL;
return constraint.getFirst();
}
@@ -259,13 +252,13 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
@NotNull PsiExpression[] arguments,
@NotNull PsiSubstitutor partialSubstitutor,
@NotNull PsiElement parent,
boolean forCompletion) {
ParameterTypeInferencePolicy policy) {
PsiType[] substitutions = new PsiType[typeParameters.length];
//noinspection unchecked
Pair<PsiType, ConstraintType>[] constraints = new Pair[typeParameters.length];
for (int i = 0; i < typeParameters.length; i++) {
final Pair<PsiType, ConstraintType> constraint =
inferTypeForMethodTypeParameterInner(typeParameters[i], parameters, arguments, partialSubstitutor, null, forCompletion);
inferTypeForMethodTypeParameterInner(typeParameters[i], parameters, arguments, partialSubstitutor, null, policy);
constraints[i] = constraint;
if (constraint != null && constraint.getSecond() != ConstraintType.SUBTYPE) {
substitutions[i] = constraint.getFirst();
@@ -319,10 +312,10 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
Pair<PsiType, ConstraintType> constraint = constraints[i];
if (substitution == null) {
if (constraint == null) {
constraint = inferMethodTypeParameterFromParent(typeParameter, partialSubstitutor, parent, forCompletion);
constraint = inferMethodTypeParameterFromParent(typeParameter, partialSubstitutor, parent, policy);
} else if (constraint.getSecond() == ConstraintType.SUBTYPE) {
Pair<PsiType, ConstraintType> otherConstraint =
inferMethodTypeParameterFromParent(typeParameter, partialSubstitutor, parent, forCompletion);
inferMethodTypeParameterFromParent(typeParameter, partialSubstitutor, parent, policy);
if (otherConstraint != null) {
if (otherConstraint.getSecond() == ConstraintType.EQUALS || otherConstraint.getSecond() == ConstraintType.SUPERTYPE) constraint = otherConstraint;
}
@@ -405,14 +398,14 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
}
private static Pair<PsiType, ConstraintType> inferMethodTypeParameterFromParent(final PsiTypeParameter typeParameter,
PsiSubstitutor substitutor,
PsiElement parent,
final boolean forCompletion) {
PsiSubstitutor substitutor,
PsiElement parent,
final ParameterTypeInferencePolicy policy) {
PsiTypeParameterListOwner owner = typeParameter.getOwner();
Pair<PsiType, ConstraintType> substitution = null;
if (owner instanceof PsiMethod && parent instanceof PsiCallExpression) {
PsiCallExpression methodCall = (PsiCallExpression)parent;
substitution = inferMethodTypeParameterFromParent(skipParenthesizedExprUp(methodCall.getParent()), methodCall, typeParameter, substitutor, forCompletion);
substitution = inferMethodTypeParameterFromParent(skipParenthesizedExprUp(methodCall.getParent()), methodCall, typeParameter, substitutor, policy);
}
return substitution;
}
@@ -428,7 +421,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
}
@Nullable
private static Pair<PsiType, ConstraintType> getSubstitutionForTypeParameterConstraint(PsiTypeParameter typeParam,
public static Pair<PsiType, ConstraintType> getSubstitutionForTypeParameterConstraint(PsiTypeParameter typeParam,
PsiType param,
PsiType arg,
boolean isContraVariantPosition,
@@ -493,12 +486,6 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
return PsiIntersectionType.createIntersection(types);
}
private enum ConstraintType {
EQUALS,
SUBTYPE,
SUPERTYPE
}
//represents the result of failed type inference: in case we failed inferring from parameters, do not perform inference from context
private static final Pair<PsiType, ConstraintType> FAILED_INFERENCE = new Pair<PsiType, ConstraintType>(PsiType.NULL, ConstraintType.EQUALS);
@@ -614,7 +601,7 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
PsiCallExpression methodCall,
final PsiTypeParameter typeParameter,
PsiSubstitutor substitutor,
final boolean forCompletion) {
ParameterTypeInferencePolicy policy) {
Pair<PsiType, ConstraintType> constraint = null;
PsiType expectedType = null;
@@ -634,10 +621,11 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
expectedType = method.getReturnType();
}
}
else if (parent instanceof PsiExpressionList && forCompletion) {
else if (parent instanceof PsiExpressionList) {
final PsiElement pParent = parent.getParent();
if (pParent instanceof PsiCallExpression && parent.equals(((PsiCallExpression)pParent).getArgumentList())) {
constraint = inferTypeForCompletionFromCallContext(methodCall, (PsiExpressionList)parent, (PsiCallExpression)pParent, typeParameter);
constraint = policy.inferTypeConstraintFromCallContext(methodCall, (PsiExpressionList)parent, (PsiCallExpression)pParent,
typeParameter);
}
}
@@ -645,17 +633,8 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
final GlobalSearchScope scope = parent.getResolveScope();
PsiType returnType = null;
if (constraint == null) {
if (forCompletion && expectedType == null) {
ExpectedTypeInfo[] expectedTypes = ExpectedTypesProvider.getExpectedTypes(methodCall, true);
if (expectedTypes.length > 0) {
expectedType = expectedTypes[0].getType();
}
}
if (expectedType == null) {
expectedType = forCompletion ?
PsiType.NULL :
PsiType.getJavaLangObject(manager, scope);
expectedType = policy.getDefaultExpectedType(methodCall);
}
returnType = ((PsiMethod)typeParameter.getOwner()).getReturnType();
@@ -686,19 +665,11 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
PsiType superType = finalSubstitutor.substitute(superTypes[0]);
if (superType == null) superType = PsiType.getJavaLangObject(manager, scope);
if (superType == null) return null;
if (forCompletion && !(superType instanceof PsiWildcardType)) {
result = new Pair<PsiType, ConstraintType>(PsiWildcardType.createExtends(manager, superType), ConstraintType.EQUALS);
}
else {
result = new Pair<PsiType, ConstraintType>(superType, ConstraintType.SUBTYPE);
}
return policy.getInferredTypeWithNoConstraint(manager, superType);
}
else {
PsiType guess = constraint.getFirst();
if (forCompletion && guess != null && !(guess instanceof PsiWildcardType)) {
if (constraint.getSecond() == ConstraintType.SUPERTYPE) guess = PsiWildcardType.createExtends(manager, guess);
else if (constraint.getSecond() == ConstraintType.SUBTYPE) guess = PsiWildcardType.createSuper(manager, guess);
}
guess = policy.adjustInferredType(manager, guess, constraint.getSecond());
//The following code is the result of deep thought, do not shit it out before discussing with [ven]
if (returnType instanceof PsiClassType && typeParameter.equals(((PsiClassType)returnType).resolve())) {
@@ -737,64 +708,4 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
}
return parent;
}
@Nullable
private static Pair<PsiType, ConstraintType> inferTypeForCompletionFromCallContext(@NotNull final PsiCallExpression innerMethodCall,
final PsiExpressionList expressionList,
final PsiCallExpression contextCall,
final PsiTypeParameter typeParameter) {
final MethodCandidatesProcessor processor = new MethodCandidatesProcessor(contextCall);
try {
//can't call resolve() since it obtains full substitution, that may result in infinite recursion
PsiScopesUtil.setupAndRunProcessor(processor, contextCall, false);
PsiExpression[] expressions = expressionList.getExpressions();
int i = ArrayUtil.find(expressions, innerMethodCall);
assert i >= 0;
final JavaResolveResult[] results = processor.getResult();
PsiMethod owner = (PsiMethod)typeParameter.getOwner();
if (owner == null) return null;
final PsiType innerReturnType = owner.getReturnType();
for (final JavaResolveResult result : results) {
final PsiSubstitutor substitutor;
if (result instanceof MethodCandidateInfo) {
List<PsiExpression> leftArgs = Arrays.asList(expressions).subList(0, i);
substitutor = ((MethodCandidateInfo)result).inferTypeArguments(true, leftArgs.toArray(new PsiExpression[leftArgs.size()]));
} else {
substitutor = result.getSubstitutor();
}
final PsiElement element = result.getElement();
if (element instanceof PsiMethod) {
final PsiMethod method = (PsiMethod)element;
final PsiParameter[] parameters = method.getParameterList().getParameters();
PsiParameter parameter = null;
if (parameters.length > i) {
parameter = parameters[i];
}
else if (method.isVarArgs()) {
parameter = parameters[parameters.length - 1];
}
if (parameter != null) {
final PsiParameter finalParameter = parameter;
PsiType type = ourGuard.doPreventingRecursion(innerMethodCall, true, new Computable<PsiType>() {
@Override
public PsiType compute() {
return substitutor.substitute(finalParameter.getType());
}
});
final Pair<PsiType, ConstraintType> constraint =
getSubstitutionForTypeParameterConstraint(typeParameter, innerReturnType, type, false,
PsiUtil.getLanguageLevel(innerMethodCall));
if (constraint != null) return constraint;
}
}
}
}
catch (MethodProcessorSetupFailedException ev) {
return null;
}
return null;
}
}
@@ -35,6 +35,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.controlFlow.ControlFlowUtil;
import com.intellij.psi.impl.source.PsiImmediateClassType;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PropertyUtil;
@@ -451,7 +452,8 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor {
for (final PsiTypeParameter typeParameter : methodTypeParameters) {
final PsiType type = resolveHelper.inferTypeForMethodTypeParameter(typeParameter, getMethod().getParameterList().getParameters(),
methodCallExpression.getArgumentList().getExpressions(),
PsiSubstitutor.EMPTY, methodCallExpression, false);
PsiSubstitutor.EMPTY, methodCallExpression,
DefaultParameterTypeInferencePolicy.INSTANCE);
if (type == null || PsiType.NULL.equals(type)) {
return "";
}
@@ -25,6 +25,7 @@ import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.impl.PsiDiamondTypeUtil;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
@@ -120,7 +121,8 @@ public class JavaIntroduceParameterMethodUsagesProcessor implements IntroducePar
final Project project = method.getProject();
final PsiSubstitutor psiSubstitutor = JavaPsiFacade.getInstance(project).getResolveHelper()
.inferTypeArguments(method.getTypeParameters(), method.getParameterList().getParameters(),
argList.getExpressions(), PsiSubstitutor.EMPTY, callExpression, false);
argList.getExpressions(), PsiSubstitutor.EMPTY, callExpression,
DefaultParameterTypeInferencePolicy.INSTANCE);
RefactoringUtil.replaceMovedMemberTypeParameters(initializer, PsiUtil.typeParametersIterable(method), psiSubstitutor,
JavaPsiFacade.getElementFactory(project));
}
@@ -45,6 +45,7 @@ import com.intellij.openapi.wm.WindowManager;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.*;
import com.intellij.psi.impl.PsiDiamondTypeUtil;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.impl.source.tree.java.ReplaceExpressionUtil;
import com.intellij.psi.util.*;
import com.intellij.refactoring.*;
@@ -390,7 +391,8 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase impleme
final PsiExpression[] args = parent.getArgumentList().getExpressions();
final PsiSubstitutor psiSubstitutor =
JavaPsiFacade.getInstance(parent.getProject()).getResolveHelper().inferTypeArguments(psiMethod.getTypeParameters(), parameters,
args, PsiSubstitutor.EMPTY, parent, false);
args, PsiSubstitutor.EMPTY, parent,
DefaultParameterTypeInferencePolicy.INSTANCE);
if (startOffset < args[parameters.length - 1].getTextOffset()) return null;
@@ -21,6 +21,7 @@ import com.intellij.openapi.util.Comparing;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiSubstitutorImpl;
import com.intellij.psi.impl.source.DummyHolder;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.MethodReferencesSearch;
import com.intellij.psi.search.searches.OverridingMethodsSearch;
@@ -309,7 +310,8 @@ public class SliceUtil {
PsiTypeParameter[] typeParameters = substitutor.getSubstitutionMap().keySet().toArray(new PsiTypeParameter[0]);
PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(project).getResolveHelper();
substitutor = resolveHelper.inferTypeArguments(typeParameters, actualParameters, expressions, parentSubstitutor, argumentList, false);
substitutor = resolveHelper.inferTypeArguments(typeParameters, actualParameters, expressions, parentSubstitutor, argumentList,
DefaultParameterTypeInferencePolicy.INSTANCE);
}
substitutor = removeRawMappingsLeftFromResolve(substitutor);
@@ -0,0 +1,22 @@
/*
* Copyright 2000-2011 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;
public enum ConstraintType {
EQUALS,
SUBTYPE,
SUPERTYPE
}
@@ -18,6 +18,7 @@ package com.intellij.psi;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy;
import com.intellij.psi.infos.CandidateInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -122,7 +123,7 @@ public interface PsiResolveHelper {
@NotNull PsiExpression[] arguments,
@NotNull PsiSubstitutor partialSubstitutor,
@Nullable PsiElement parent,
final boolean forCompletion);
final ParameterTypeInferencePolicy policy);
@NotNull
PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters,
@@ -130,7 +131,7 @@ public interface PsiResolveHelper {
@NotNull PsiExpression[] arguments,
@NotNull PsiSubstitutor partialSubstitutor,
@NotNull PsiElement parent,
final boolean forCompletion);
final ParameterTypeInferencePolicy policy);
@NotNull
PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters,
@@ -0,0 +1,54 @@
/*
* Copyright 2000-2011 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.source.resolve;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import org.jetbrains.annotations.Nullable;
/**
* @author yole
*/
public class DefaultParameterTypeInferencePolicy extends ParameterTypeInferencePolicy {
public static final DefaultParameterTypeInferencePolicy INSTANCE = new DefaultParameterTypeInferencePolicy();
private DefaultParameterTypeInferencePolicy() {
}
@Nullable
@Override
public Pair<PsiType, ConstraintType> inferTypeConstraintFromCallContext(PsiCallExpression innerMethodCall,
PsiExpressionList parent,
PsiCallExpression contextCall,
PsiTypeParameter typeParameter) {
return null;
}
@Override
public PsiType getDefaultExpectedType(PsiCallExpression methodCall) {
return PsiType.getJavaLangObject(methodCall.getManager(), methodCall.getResolveScope());
}
@Override
public Pair<PsiType, ConstraintType> getInferredTypeWithNoConstraint(PsiManager manager, PsiType superType) {
return new Pair<PsiType, ConstraintType>(superType, ConstraintType.SUBTYPE);
}
@Override
public PsiType adjustInferredType(PsiManager manager, PsiType guess, ConstraintType constraintType) {
return guess;
}
}
@@ -0,0 +1,37 @@
/*
* Copyright 2000-2011 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.source.resolve;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import org.jetbrains.annotations.Nullable;
/**
* @author yole
*/
public abstract class ParameterTypeInferencePolicy {
@Nullable
public abstract Pair<PsiType, ConstraintType> inferTypeConstraintFromCallContext(PsiCallExpression innerMethodCall,
PsiExpressionList parent,
PsiCallExpression contextCall,
PsiTypeParameter typeParameter);
public abstract PsiType getDefaultExpectedType(PsiCallExpression methodCall);
public abstract Pair<PsiType, ConstraintType> getInferredTypeWithNoConstraint(PsiManager manager, PsiType superType);
public abstract PsiType adjustInferredType(PsiManager manager, PsiType guess, ConstraintType second);
}
@@ -17,6 +17,8 @@ package com.intellij.psi.infos;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.Nullable;
@@ -84,7 +86,7 @@ public class MethodCandidateInfo extends CandidateInfo{
PsiSubstitutor incompleteSubstitutor = super.getSubstitutor();
PsiMethod method = getElement();
if (myTypeArguments == null) {
myCalcedSubstitutor = inferTypeArguments(false);
myCalcedSubstitutor = inferTypeArguments(DefaultParameterTypeInferencePolicy.INSTANCE);
}
else {
PsiTypeParameter[] typeParams = method.getTypeParameters();
@@ -114,13 +116,13 @@ public class MethodCandidateInfo extends CandidateInfo{
return (PsiMethod)super.getElement();
}
public PsiSubstitutor inferTypeArguments(final boolean forCompletion) {
return inferTypeArguments(forCompletion, myArgumentList instanceof PsiExpressionList
public PsiSubstitutor inferTypeArguments(final ParameterTypeInferencePolicy policy) {
return inferTypeArguments(policy, myArgumentList instanceof PsiExpressionList
? ((PsiExpressionList)myArgumentList).getExpressions()
: PsiExpression.EMPTY_ARRAY);
}
public PsiSubstitutor inferTypeArguments(final boolean forCompletion, final PsiExpression[] arguments) {
public PsiSubstitutor inferTypeArguments(final ParameterTypeInferencePolicy policy, final PsiExpression[] arguments) {
PsiMethod method = getElement();
PsiTypeParameter[] typeParameters = method.getTypeParameters();
@@ -133,7 +135,7 @@ public class MethodCandidateInfo extends CandidateInfo{
}
return javaPsiFacade.getResolveHelper().inferTypeArguments(typeParameters, method.getParameterList().getParameters(), arguments, mySubstitutor,
myArgumentList.getParent(), forCompletion);
myArgumentList.getParent(), policy);
}
public boolean isInferencePossible() {
@@ -20,6 +20,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
@@ -243,7 +244,7 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
final PsiExpressionList argumentList = expression.getArgumentList();
final PsiExpression[] expressions = argumentList.getExpressions();
return resolveHelper
.inferTypeArguments(staticFactoryMethod.getTypeParameters(), parameters, expressions, PsiSubstitutor.EMPTY, parent, false);
.inferTypeArguments(staticFactoryMethod.getTypeParameters(), parameters, expressions, PsiSubstitutor.EMPTY, parent, DefaultParameterTypeInferencePolicy.INSTANCE);
}
public static boolean hasDefaultConstructor(@NotNull final PsiClass psiClass) {