mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 21:11:28 +07:00
[java-intentions] AddTypeArgumentsConditionalFix: report the branch
After changes in highlighting, it's not possible anymore to attach a fix to the range. In general, it's good, because the user may have no idea that the fix is available at a specific offset. So instead, we allow invoking the fix at the whole error range but indicate which branch will be updated. Also: parentheses supported; fix all option added, minor touch-ups GitOrigin-RevId: d756252cd1d3c061f52bdb70d62bed3bedcb69e3
This commit is contained in:
committed by
intellij-monorepo-bot
parent
19b4123fe6
commit
07960b2159
@@ -1,4 +1,6 @@
|
||||
add.explicit.type.arguments=Add explicit type arguments
|
||||
add.explicit.type.arguments.then=Add explicit type arguments to then-branch call
|
||||
add.explicit.type.arguments.else=Add explicit type arguments to else-branch call
|
||||
|
||||
change.type.arguments=Change type arguments
|
||||
change.type.arguments.to.0=Change type arguments to <{0}>
|
||||
|
||||
@@ -5,27 +5,24 @@ import com.intellij.codeInsight.intention.CommonIntentionAction;
|
||||
import com.intellij.codeInsight.intention.PriorityAction;
|
||||
import com.intellij.java.analysis.JavaAnalysisBundle;
|
||||
import com.intellij.modcommand.*;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class AddTypeArgumentsConditionalFix extends PsiUpdateModCommandAction<PsiMethodCallExpression> {
|
||||
private static final Logger LOG = Logger.getInstance(AddTypeArgumentsConditionalFix.class);
|
||||
private final @NotNull PsiSubstitutor mySubstitutor;
|
||||
|
||||
private final PsiSubstitutor mySubstitutor;
|
||||
private final PsiMethod myMethod;
|
||||
|
||||
public AddTypeArgumentsConditionalFix(PsiSubstitutor substitutor, PsiMethodCallExpression expression, PsiMethod method) {
|
||||
private AddTypeArgumentsConditionalFix(@NotNull PsiSubstitutor substitutor, @NotNull PsiMethodCallExpression expression) {
|
||||
super(expression);
|
||||
mySubstitutor = substitutor;
|
||||
myMethod = method;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -34,17 +31,27 @@ public class AddTypeArgumentsConditionalFix extends PsiUpdateModCommandAction<Ps
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiMethodCallExpression element) {
|
||||
if (!mySubstitutor.isValid() || !myMethod.isValid()) return null;
|
||||
return Presentation.of(getFamilyName()).withPriority(PriorityAction.Priority.HIGH);
|
||||
protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiMethodCallExpression call) {
|
||||
if (!mySubstitutor.isValid()) return null;
|
||||
String name = getFamilyName();
|
||||
if (PsiUtil.skipParenthesizedExprUp(call.getParent()) instanceof PsiConditionalExpression conditional) {
|
||||
if (PsiTreeUtil.isAncestor(conditional.getThenExpression(), call, false)) {
|
||||
name = JavaAnalysisBundle.message("add.explicit.type.arguments.then");
|
||||
} else if (PsiTreeUtil.isAncestor(conditional.getElseExpression(), call, false)) {
|
||||
name = JavaAnalysisBundle.message("add.explicit.type.arguments.else");
|
||||
}
|
||||
}
|
||||
return Presentation.of(name).withPriority(PriorityAction.Priority.HIGH)
|
||||
.withFixAllOption(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invoke(@NotNull ActionContext context, @NotNull PsiMethodCallExpression call, @NotNull ModPsiUpdater updater) {
|
||||
final PsiTypeParameter[] typeParameters = myMethod.getTypeParameters();
|
||||
PsiMethod method = call.resolveMethod();
|
||||
if (method == null) return;
|
||||
final PsiTypeParameter[] typeParameters = method.getTypeParameters();
|
||||
final String typeArguments = "<" + StringUtil.join(typeParameters, parameter -> {
|
||||
final PsiType substituteTypeParam = mySubstitutor.substitute(parameter);
|
||||
LOG.assertTrue(substituteTypeParam != null);
|
||||
final PsiType substituteTypeParam = Objects.requireNonNull(mySubstitutor.substitute(parameter));
|
||||
return GenericsUtil.eliminateWildcards(substituteTypeParam).getCanonicalText();
|
||||
}, ", ") + ">";
|
||||
final PsiExpression expression = call.getMethodExpression().getQualifierExpression();
|
||||
@@ -53,9 +60,9 @@ public class AddTypeArgumentsConditionalFix extends PsiUpdateModCommandAction<Ps
|
||||
withTypeArgsText = expression.getText();
|
||||
}
|
||||
else {
|
||||
if (isInStaticContext(call, null) || myMethod.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
final PsiClass aClass = myMethod.getContainingClass();
|
||||
LOG.assertTrue(aClass != null);
|
||||
if (isInStaticContext(call, null) || method.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
final PsiClass aClass = method.getContainingClass();
|
||||
if (aClass == null) return;
|
||||
withTypeArgsText = aClass.getQualifiedName();
|
||||
}
|
||||
else {
|
||||
@@ -73,47 +80,47 @@ public class AddTypeArgumentsConditionalFix extends PsiUpdateModCommandAction<Ps
|
||||
}
|
||||
|
||||
public static void register(@NotNull Consumer<? super CommonIntentionAction> highlightInfo, @Nullable PsiExpression expression, @NotNull PsiType lType) {
|
||||
if (lType != PsiTypes.nullType() && expression instanceof PsiConditionalExpression) {
|
||||
final PsiExpression thenExpression = ((PsiConditionalExpression)expression).getThenExpression();
|
||||
final PsiExpression elseExpression = ((PsiConditionalExpression)expression).getElseExpression();
|
||||
if (lType != PsiTypes.nullType() && expression instanceof PsiConditionalExpression conditional) {
|
||||
PsiExpression thenExpression = PsiUtil.skipParenthesizedExprDown(conditional.getThenExpression());
|
||||
PsiExpression elseExpression = PsiUtil.skipParenthesizedExprDown(conditional.getElseExpression());
|
||||
if (thenExpression != null && elseExpression != null) {
|
||||
final PsiType thenType = thenExpression.getType();
|
||||
final PsiType elseType = elseExpression.getType();
|
||||
PsiType thenType = thenExpression.getType();
|
||||
PsiType elseType = elseExpression.getType();
|
||||
if (thenType != null && elseType != null) {
|
||||
final boolean thenAssignable = TypeConversionUtil.isAssignable(lType, thenType);
|
||||
final boolean elseAssignable = TypeConversionUtil.isAssignable(lType, elseType);
|
||||
if (!thenAssignable && thenExpression instanceof PsiMethodCallExpression) {
|
||||
inferTypeArgs(highlightInfo, lType, thenExpression);
|
||||
boolean thenAssignable = TypeConversionUtil.isAssignable(lType, thenType);
|
||||
boolean elseAssignable = TypeConversionUtil.isAssignable(lType, elseType);
|
||||
if (!thenAssignable && thenExpression instanceof PsiMethodCallExpression call) {
|
||||
inferTypeArgs(highlightInfo, lType, call);
|
||||
}
|
||||
if (!elseAssignable && elseExpression instanceof PsiMethodCallExpression) {
|
||||
inferTypeArgs(highlightInfo, lType, elseExpression);
|
||||
if (!elseAssignable && elseExpression instanceof PsiMethodCallExpression call) {
|
||||
inferTypeArgs(highlightInfo, lType, call);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void inferTypeArgs(Consumer<? super ModCommandAction> fixConsumer, PsiType lType, PsiExpression expression) {
|
||||
final JavaResolveResult result = ((PsiMethodCallExpression)expression).resolveMethodGenerics();
|
||||
final PsiMethod method = (PsiMethod)result.getElement();
|
||||
private static void inferTypeArgs(@NotNull Consumer<? super ModCommandAction> fixConsumer,
|
||||
@NotNull PsiType lType,
|
||||
@NotNull PsiMethodCallExpression call) {
|
||||
PsiMethod method = call.resolveMethod();
|
||||
if (method != null) {
|
||||
final PsiType returnType = method.getReturnType();
|
||||
final PsiClass aClass = method.getContainingClass();
|
||||
PsiType returnType = method.getReturnType();
|
||||
PsiClass aClass = method.getContainingClass();
|
||||
if (returnType != null && aClass != null && aClass.getQualifiedName() != null) {
|
||||
final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(method.getProject());
|
||||
final PsiDeclarationStatement variableDeclarationStatement =
|
||||
javaPsiFacade.getElementFactory().createVariableDeclarationStatement("xxx", lType, expression, expression);
|
||||
final PsiExpression initializer =
|
||||
((PsiLocalVariable)variableDeclarationStatement.getDeclaredElements()[0]).getInitializer();
|
||||
LOG.assertTrue(initializer != null);
|
||||
JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(method.getProject());
|
||||
PsiDeclarationStatement variableDeclarationStatement =
|
||||
javaPsiFacade.getElementFactory().createVariableDeclarationStatement("xxx", lType, call, call);
|
||||
PsiExpression initializer =
|
||||
Objects.requireNonNull(((PsiLocalVariable)variableDeclarationStatement.getDeclaredElements()[0]).getInitializer());
|
||||
|
||||
final PsiSubstitutor substitutor = javaPsiFacade.getResolveHelper()
|
||||
PsiSubstitutor substitutor = javaPsiFacade.getResolveHelper()
|
||||
.inferTypeArguments(method.getTypeParameters(), method.getParameterList().getParameters(),
|
||||
((PsiMethodCallExpression)expression).getArgumentList().getExpressions(), PsiSubstitutor.EMPTY,
|
||||
call.getArgumentList().getExpressions(), PsiSubstitutor.EMPTY,
|
||||
initializer, DefaultParameterTypeInferencePolicy.INSTANCE);
|
||||
PsiType substitutedType = substitutor.substitute(returnType);
|
||||
if (substitutedType != null && TypeConversionUtil.isAssignable(lType, substitutedType)) {
|
||||
fixConsumer.accept(new AddTypeArgumentsConditionalFix(substitutor, (PsiMethodCallExpression)expression, method));
|
||||
fixConsumer.accept(new AddTypeArgumentsConditionalFix(substitutor, call));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Add explicit type arguments" "true-preview"
|
||||
// "Add explicit type arguments to then-branch call" "true-preview"
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Add explicit type arguments" "true-preview"
|
||||
// "Add explicit type arguments to else-branch call" "true-preview"
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Add explicit type arguments" "true-preview"
|
||||
// "Add explicit type arguments to then-branch call" "true-preview"
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Add explicit type arguments" "true-preview"
|
||||
// "Add explicit type arguments to then-branch call" "true-preview"
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// "Add explicit type arguments" "true-preview"
|
||||
// "Add explicit type arguments to then-branch call" "true-preview"
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
<T> List<T> f() { return new ArrayList<T>(); }
|
||||
void someMethod(Test t, boolean b) {
|
||||
List<String> s = b ? t.<String>f() : new ArrayList<String>();
|
||||
List<String> s = b ? (t.<String>f()) : new ArrayList<String>();
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
// "Add explicit type arguments" "true-preview"
|
||||
// "Add explicit type arguments to else-branch call" "true-preview"
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
static <T> List<T> f() { return new ArrayList<T>(); }
|
||||
void someMethod(Test t, boolean b) {
|
||||
List<String> s = b ? t.<String>f() : new ArrayList<String>();
|
||||
List<String> s = b ? new ArrayList<String>() : t.<String>f();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Add explicit type arguments" "true-preview"
|
||||
// "Add explicit type arguments to then-branch call" "true-preview"
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Add explicit type arguments" "true-preview"
|
||||
// "Add explicit type arguments to then-branch call" "true-preview"
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Add explicit type arguments" "true-preview"
|
||||
// "Add explicit type arguments to else-branch call" "true-preview"
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Add explicit type arguments" "true-preview"
|
||||
// "Add explicit type arguments to then-branch call" "true-preview"
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Add explicit type arguments" "true-preview"
|
||||
// "Add explicit type arguments to then-branch call" "true-preview"
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// "Add explicit type arguments" "true-preview"
|
||||
// "Add explicit type arguments to then-branch call" "true-preview"
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
<T> List<T> f() { return new ArrayList<T>(); }
|
||||
void someMethod(Test t, boolean b) {
|
||||
List<String> s = b ? t.f<caret>() : new ArrayList<String>();
|
||||
List<String> s = b ? (t.f<caret>()) : new ArrayList<String>();
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
// "Add explicit type arguments" "true-preview"
|
||||
// "Add explicit type arguments to else-branch call" "true-preview"
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
static <T> List<T> f() { return new ArrayList<T>(); }
|
||||
void someMethod(Test t, boolean b) {
|
||||
List<String> s = b ? t.f<caret>() : new ArrayList<String>();
|
||||
List<String> s = b ? new ArrayList<String>() : t.f<caret>();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Add explicit type arguments" "true-preview"
|
||||
// "Add explicit type arguments to then-branch call" "true-preview"
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
|
||||
Reference in New Issue
Block a user