IJ-CR-126040 [java-highlighting] S IDEA-338688 Change variable type intention produces compile error

- allow changing input parameters

GitOrigin-RevId: 3fad3ac051e314f6858c91ed177b9df22ccef15e
This commit is contained in:
Mikhail Pyltsin
2024-03-08 17:26:30 +01:00
committed by intellij-monorepo-bot
parent f6af686f4d
commit ba48f05c21
5 changed files with 48 additions and 24 deletions

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.daemon.impl.quickfix;
@@ -12,7 +12,6 @@ import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.search.PsiSearchHelper;
import com.intellij.psi.util.JavaElementKind;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.CommonJavaRefactoringUtil;
@@ -90,7 +89,7 @@ public final class VariableTypeFromCallFix implements IntentionAction {
final PsiType parameterType = substitutor.substitute(formalParamType);
if (parameterType.isAssignableFrom(expressionType)) continue;
final PsiExpression qualifierExpression = methodCall.getMethodExpression().getQualifierExpression();
final PsiExpression qualifierExpression = PsiUtil.skipParenthesizedExprDown(methodCall.getMethodExpression().getQualifierExpression());
if (qualifierExpression instanceof PsiReferenceExpression) {
final PsiElement resolved = ((PsiReferenceExpression)qualifierExpression).resolve();
if (resolved instanceof PsiVariable) {
@@ -99,7 +98,7 @@ public final class VariableTypeFromCallFix implements IntentionAction {
final Project project = expression.getProject();
final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(project).getResolveHelper();
if (varClass != null) {
final PsiSubstitutor psiSubstitutor = resolveHelper.inferTypeArguments(varClass.getTypeParameters(),
PsiSubstitutor psiSubstitutor = resolveHelper.inferTypeArguments(varClass.getTypeParameters(),
parameters,
expressions, PsiSubstitutor.EMPTY, resolved,
DefaultParameterTypeInferencePolicy.INSTANCE);
@@ -107,18 +106,27 @@ public final class VariableTypeFromCallFix implements IntentionAction {
t -> t != null && t.equalsToText(CommonClassNames.JAVA_LANG_VOID))) {
continue;
}
final PsiType appropriateVarType = GenericsUtil.getVariableTypeByExpressionType(
PsiType appropriateVarType = GenericsUtil.getVariableTypeByExpressionType(
JavaPsiFacade.getElementFactory(project).createType(varClass, psiSubstitutor));
if (!varType.equals(appropriateVarType)) {
PsiMethodCallExpression methodCallCopy = (PsiMethodCallExpression)methodCall.copy();
PsiElement castedQualifier =
AddTypeCastFix.addTypeCast(project, methodCallCopy.getMethodExpression().getQualifierExpression(), appropriateVarType);
PsiMethodCallExpression castedMethodCallCopy = PsiTreeUtil.getParentOfType(castedQualifier, PsiMethodCallExpression.class);
//only qualifier is considered, so it is necessary to check that it doesn't change a return type of the whole method,
AddTypeCastFix.addTypeCast(project, methodCallCopy.getMethodExpression().getQualifierExpression(), appropriateVarType);
//it is necessary to check that it doesn't change a return type of the whole method,
//otherwise it can lead to broken code
if (castedMethodCallCopy != null && castedMethodCallCopy.getType() != null &&
!castedMethodCallCopy.getType().equals(methodCall.getType())) {
continue;
if (methodCallCopy.getType() != null && !methodCallCopy.getType().equals(methodCall.getType())) {
PsiMethod resolvedMethod = methodCall.resolveMethod();
if(resolvedMethod ==null) continue;
PsiType returnMethodType = resolvedMethod.getReturnType();
if (!(PsiUtil.resolveClassInClassTypeOnly(returnMethodType) instanceof PsiTypeParameter returnTypeParameter)) {
continue;
}
PsiType oldReturnType = methodCall.getType();
psiSubstitutor = psiSubstitutor.put(returnTypeParameter, oldReturnType);
appropriateVarType = GenericsUtil.getVariableTypeByExpressionType(
JavaPsiFacade.getElementFactory(project).createType(varClass, psiSubstitutor));
if (varType.equals(appropriateVarType)) {
continue;
}
}
actions.add(new VariableTypeFromCallFix(appropriateVarType, (PsiVariable)resolved));
break;

View File

@@ -0,0 +1,13 @@
// "Change variable 'f' type to 'Function<Foo, String>'" "true"
class Test {
enum Foo { FOO }
public static void main(String[] args) {
Function<Foo, String> f = s -> s;
System.out.println((f).apply(Foo.FOO).toUpperCase());
}
interface Function<T, R> {
R apply(T t);
}
}

View File

@@ -0,0 +1,13 @@
// "Change variable 'f' type to 'Function<Foo, String>'" "true"
class Test {
enum Foo { FOO }
public static void main(String[] args) {
Function<String, String> f = s -> s;
System.out.println((f).apply(<caret>Foo.FOO).toUpperCase());
}
interface Function<T, R> {
R apply(T t);
}
}

View File

@@ -1,10 +0,0 @@
// "Change field 'f' type to 'Function<Foo, Object>'" "false"
class Test {
enum Foo { FOO }
public static void main(String[] args) {
Function<String, String> f = s -> s;
// does not compile because apply expects a string
System.out.println(f.apply(<caret>Foo.FOO).toUpperCase());
}
}

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.daemon.impl.quickfix;
@@ -14,7 +14,7 @@ public class VariableTypeFromCallTest extends LightQuickFixParameterizedTestCase
@Override
protected LanguageLevel getLanguageLevel() {
return LanguageLevel.JDK_1_7;
return LanguageLevel.JDK_1_8;
}
}