blob: e2a70d8dfadaa5ab6006ed8d93d3bc0f78150c9c [file] [log] [blame]
/*
* Copyright 2000-2010 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.
*/
/*
* User: anna
* Date: 10-Jun-2010
*/
package com.intellij.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil;
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;
import com.intellij.refactoring.typeMigration.TypeMigrationProcessor;
import com.intellij.refactoring.typeMigration.TypeMigrationRules;
import com.intellij.usageView.UsageViewUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class VariableTypeFromCallFix implements IntentionAction {
private final PsiType myExpressionType;
private final PsiVariable myVar;
private VariableTypeFromCallFix(@NotNull PsiClassType type, @NotNull PsiVariable var) {
myExpressionType = type;
myVar = var;
}
@Override
@NotNull
public String getText() {
return QuickFixBundle.message("fix.variable.type.text",
UsageViewUtil.getType(myVar),
myVar.getName(),
myExpressionType.getCanonicalText());
}
@Override
@NotNull
public String getFamilyName() {
return QuickFixBundle.message("fix.variable.type.family");
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return true;
}
@Override
public void invoke(@NotNull final Project project, final Editor editor, PsiFile file) throws IncorrectOperationException {
final TypeMigrationRules rules = new TypeMigrationRules(TypeMigrationLabeler.getElementType(myVar));
rules.setMigrationRootType(myExpressionType);
rules.setBoundScope(PsiSearchHelper.SERVICE.getInstance(project).getUseScope(myVar));
TypeMigrationProcessor.runHighlightingTypeMigration(project, editor, rules, myVar);
}
@Override
public boolean startInWriteAction() {
return true;
}
@NotNull
public static List<IntentionAction> getQuickFixActions(@NotNull PsiMethodCallExpression methodCall,
@NotNull PsiExpressionList list) {
final JavaResolveResult result = methodCall.getMethodExpression().advancedResolve(false);
PsiMethod method = (PsiMethod) result.getElement();
final PsiSubstitutor substitutor = result.getSubstitutor();
PsiExpression[] expressions = list.getExpressions();
if (method == null || method.getParameterList().getParametersCount() != expressions.length) return Collections.emptyList();
final PsiParameter[] parameters = method.getParameterList().getParameters();
List<IntentionAction> actions = new ArrayList<IntentionAction>();
for (int i = 0; i < expressions.length; i++) {
final PsiExpression expression = expressions[i];
PsiType expressionType = expression.getType();
if (expressionType instanceof PsiPrimitiveType) {
expressionType = ((PsiPrimitiveType)expressionType).getBoxedType(expression);
}
if (expressionType == null) continue;
final PsiParameter parameter = parameters[i];
final PsiType formalParamType = parameter.getType();
final PsiType parameterType = substitutor.substitute(formalParamType);
if (parameterType.isAssignableFrom(expressionType)) continue;
final PsiExpression qualifierExpression = methodCall.getMethodExpression().getQualifierExpression();
if (qualifierExpression instanceof PsiReferenceExpression) {
final PsiElement resolved = ((PsiReferenceExpression)qualifierExpression).resolve();
if (resolved instanceof PsiVariable) {
final PsiType varType = ((PsiVariable)resolved).getType();
final PsiClass varClass = PsiUtil.resolveClassInType(varType);
final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(expression.getProject()).getResolveHelper();
if (varClass != null) {
final PsiSubstitutor psiSubstitutor = resolveHelper.inferTypeArguments(varClass.getTypeParameters(),
parameters,
expressions, PsiSubstitutor.EMPTY, resolved,
DefaultParameterTypeInferencePolicy.INSTANCE);
final PsiClassType appropriateVarType = JavaPsiFacade.getElementFactory(expression.getProject()).createType(varClass, psiSubstitutor);
if (!varType.equals(appropriateVarType)) {
actions.add(new VariableTypeFromCallFix(appropriateVarType, (PsiVariable)resolved));
}
break;
}
}
}
actions.addAll(getParameterTypeChangeFixes(method, expression, parameterType));
}
return actions;
}
private static List<IntentionAction> getParameterTypeChangeFixes(@NotNull PsiMethod method,
@NotNull PsiExpression expression,
PsiType parameterType) {
if (!(expression instanceof PsiReferenceExpression)) {
return Collections.emptyList();
}
List<IntentionAction> result = new ArrayList<IntentionAction>();
final PsiManager manager = method.getManager();
if (manager.isInProject(method)) {
final PsiMethod[] superMethods = method.findDeepestSuperMethods();
for (PsiMethod superMethod : superMethods) {
if (!manager.isInProject(superMethod)) return Collections.emptyList();
}
final PsiElement resolve = ((PsiReferenceExpression)expression).resolve();
if (resolve instanceof PsiVariable) {
result.addAll(HighlightUtil.getChangeVariableTypeFixes((PsiVariable)resolve, parameterType));
}
}
return result;
}
}