QuickFix: change type of constructor parameter to match value argument in invocation

This commit is contained in:
Wojciech Lopata
2013-05-16 00:43:26 +02:00
parent c6a378f4fb
commit 2a97617880
8 changed files with 47 additions and 24 deletions
@@ -64,6 +64,7 @@ remove.function.return.type=Remove explicitly specified return type in ''{0}'' f
remove.no.name.function.return.type=Remove explicitly specified function return type
change.element.type=Change ''{0}'' type to ''{1}''
change.function.parameter.type=Change parameter ''{0}'' type of function ''{1}'' to ''{2}''
change.primary.constructor.parameter.type=Change parameter ''{0}'' type of primary constructor of class ''{1}'' to ''{2}''
change.type=Change type from ''{0}'' to ''{1}''
change.type.family=Change Type
add.parameters.to.function=Add parameter{0} to function ''{1}''
@@ -74,12 +74,12 @@ public class ChangeFunctionLiteralReturnTypeFix extends JetIntentionAction<JetFu
return;
}
JetParameter correspondingParameter = QuickFixUtil.getFunctionParameterCorrespondingToFunctionLiteralPassedOutsideArgumentList(element);
JetParameter correspondingParameter = QuickFixUtil.getParameterCorrespondingToFunctionLiteralPassedOutsideArgumentList(element);
if (correspondingParameter != null) {
JetTypeReference correspondingParameterTypeRef = correspondingParameter.getTypeReference();
JetType parameterType = context.get(BindingContext.TYPE, correspondingParameterTypeRef);
if (parameterType != null && !JetTypeChecker.INSTANCE.isSubtypeOf(eventualFunctionLiteralType, parameterType)) {
appropriateQuickFix = new ChangeFunctionParameterTypeFix(correspondingParameter, eventualFunctionLiteralType);
appropriateQuickFix = new ChangeParameterTypeFix(correspondingParameter, eventualFunctionLiteralType);
}
return;
}
@@ -28,27 +28,31 @@ import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.plugin.JetBundle;
import org.jetbrains.jet.renderer.DescriptorRenderer;
public class ChangeFunctionParameterTypeFix extends JetIntentionAction<JetParameter> {
public class ChangeParameterTypeFix extends JetIntentionAction<JetParameter> {
private final String renderedType;
private final String containingFunctionName;
private final String containingDeclarationName;
private final boolean isPrimaryConstructorParameter;
public ChangeFunctionParameterTypeFix(@NotNull JetParameter element, @NotNull JetType type) {
public ChangeParameterTypeFix(@NotNull JetParameter element, @NotNull JetType type) {
super(element);
renderedType = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(type);
JetFunction function = PsiTreeUtil.getParentOfType(element, JetFunction.class);
FqName functionFQName = function == null ? null : JetPsiUtil.getFQName(function);
containingFunctionName = functionFQName == null ? null : functionFQName.getFqName();
JetNamedDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetNamedDeclaration.class);
isPrimaryConstructorParameter = declaration instanceof JetClass;
FqName declarationFQName = declaration == null ? null : JetPsiUtil.getFQName(declaration);
containingDeclarationName = declarationFQName == null ? null : declarationFQName.asString();
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return super.isAvailable(project, editor, file) && containingFunctionName != null;
return super.isAvailable(project, editor, file) && containingDeclarationName != null;
}
@NotNull
@Override
public String getText() {
return JetBundle.message("change.function.parameter.type", element.getName(), containingFunctionName, renderedType);
return isPrimaryConstructorParameter ?
JetBundle.message("change.primary.constructor.parameter.type", element.getName(), containingDeclarationName, renderedType) :
JetBundle.message("change.function.parameter.type", element.getName(), containingDeclarationName, renderedType);
}
@NotNull
@@ -89,7 +89,7 @@ public class QuickFixFactoryForTypeMismatchError implements JetIntentionActionsF
PsiElement declaration = BindingContextUtils.descriptorToDeclaration(context, resolvedCall.getResultingDescriptor());
if (declaration instanceof JetFunction) {
JetParameter binaryOperatorParameter = ((JetFunction) declaration).getValueParameterList().getParameters().get(0);
actions.add(new ChangeFunctionParameterTypeFix(binaryOperatorParameter, expressionType));
actions.add(new ChangeParameterTypeFix(binaryOperatorParameter, expressionType));
}
}
}
@@ -113,20 +113,20 @@ public class QuickFixFactoryForTypeMismatchError implements JetIntentionActionsF
QuickFixUtil.getParentElementOfType(diagnostic, JetFunctionLiteralExpression.class);
if (functionLiteralExpression != null && functionLiteralExpression.getBodyExpression() == expression) {
JetParameter correspondingParameter =
QuickFixUtil.getFunctionParameterCorrespondingToFunctionLiteralPassedOutsideArgumentList(functionLiteralExpression);
QuickFixUtil.getParameterCorrespondingToFunctionLiteralPassedOutsideArgumentList(functionLiteralExpression);
JetType functionLiteralExpressionType = context.get(BindingContext.EXPRESSION_TYPE, functionLiteralExpression);
if (correspondingParameter != null && functionLiteralExpressionType != null) {
actions.add(new ChangeFunctionParameterTypeFix(correspondingParameter, functionLiteralExpressionType));
actions.add(new ChangeParameterTypeFix(correspondingParameter, functionLiteralExpressionType));
}
}
// 2) When an argument is passed inside value argument list:
else {
JetValueArgument valueArgument = QuickFixUtil.getParentElementOfType(diagnostic, JetValueArgument.class);
if (valueArgument != null && valueArgument.getArgumentExpression() == expression) {
JetParameter correspondingParameter = QuickFixUtil.getFunctionParameterCorrespondingToValueArgumentPassedInCall(valueArgument);
if (valueArgument != null && QuickFixUtil.canEvaluateTo(valueArgument.getArgumentExpression(), expression)) {
JetParameter correspondingParameter = QuickFixUtil.getParameterCorrespondingToValueArgumentPassedInCall(valueArgument);
JetType valueArgumentType = context.get(BindingContext.EXPRESSION_TYPE, valueArgument.getArgumentExpression());
if (correspondingParameter != null && valueArgumentType != null) {
actions.add(new ChangeFunctionParameterTypeFix(correspondingParameter, valueArgumentType));
actions.add(new ChangeParameterTypeFix(correspondingParameter, valueArgumentType));
}
}
}
@@ -95,30 +95,33 @@ public class QuickFixUtil {
}
@Nullable
public static JetParameterList getParameterListOfCalledFunction(@NotNull JetCallExpression callExpression) {
public static JetParameterList getParameterListOfCallee(@NotNull JetCallExpression callExpression) {
BindingContext context = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) callExpression.getContainingFile()).getBindingContext();
ResolvedCall<? extends CallableDescriptor> resolvedCall = context.get(BindingContext.RESOLVED_CALL, callExpression.getCalleeExpression());
if (resolvedCall == null) return null;
PsiElement functionDeclaration = BindingContextUtils.descriptorToDeclaration(context, resolvedCall.getCandidateDescriptor());
if (functionDeclaration instanceof JetFunction) {
return ((JetFunction) functionDeclaration).getValueParameterList();
PsiElement declaration = BindingContextUtils.descriptorToDeclaration(context, resolvedCall.getCandidateDescriptor());
if (declaration instanceof JetFunction) {
return ((JetFunction) declaration).getValueParameterList();
}
if (declaration instanceof JetClass) {
return ((JetClass) declaration).getPrimaryConstructorParameterList();
}
return null;
}
@Nullable
public static JetParameter getFunctionParameterCorrespondingToFunctionLiteralPassedOutsideArgumentList(@NotNull JetFunctionLiteralExpression functionLiteralExpression) {
public static JetParameter getParameterCorrespondingToFunctionLiteralPassedOutsideArgumentList(@NotNull JetFunctionLiteralExpression functionLiteralExpression) {
if (!(functionLiteralExpression.getParent() instanceof JetCallExpression)) {
return null;
}
JetCallExpression callExpression = (JetCallExpression) functionLiteralExpression.getParent();
JetParameterList parameterList = getParameterListOfCalledFunction(callExpression);
JetParameterList parameterList = getParameterListOfCallee(callExpression);
if (parameterList == null) return null;
return parameterList.getParameters().get(parameterList.getParameters().size() - 1);
}
@Nullable
public static JetParameter getFunctionParameterCorrespondingToValueArgumentPassedInCall(@NotNull JetValueArgument valueArgument) {
public static JetParameter getParameterCorrespondingToValueArgumentPassedInCall(@NotNull JetValueArgument valueArgument) {
if (!(valueArgument.getParent() instanceof JetValueArgumentList)) {
return null;
}
@@ -127,7 +130,7 @@ public class QuickFixUtil {
return null;
}
JetCallExpression callExpression = (JetCallExpression) valueArgumentList.getParent();
JetParameterList parameterList = getParameterListOfCalledFunction(callExpression);
JetParameterList parameterList = getParameterListOfCallee(callExpression);
if (parameterList == null) return null;
int position = valueArgumentList.getArguments().indexOf(valueArgument);
if (position == -1) return null;
@@ -0,0 +1,5 @@
// "Change parameter 'a' type of primary constructor of class 'B' to 'String'" "true"
class B(val a: String)
fun foo() {
B(if (true) ""<caret> else "")
}
@@ -0,0 +1,5 @@
// "Change parameter 'a' type of primary constructor of class 'B' to 'String'" "true"
class B(val a: Int)
fun foo() {
B(if (true) ""<caret> else "")
}
@@ -1476,6 +1476,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest("idea/testData/quickfix/typeMismatch/parameterTypeMismatch/beforeChangeFunctionParameterType5.kt");
}
@TestMetadata("beforeChangePrimaryConstructorParameterType.kt")
public void testChangePrimaryConstructorParameterType() throws Exception {
doTest("idea/testData/quickfix/typeMismatch/parameterTypeMismatch/beforeChangePrimaryConstructorParameterType.kt");
}
}
@TestMetadata("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression")