mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 21:11:28 +07:00
[java] add cast fix when multiple arguments require fix simultaneously (IDEA-271993)
GitOrigin-RevId: 2f6dc7ed7341c851b56a80a9b6404678ac0da0b9
This commit is contained in:
committed by
intellij-monorepo-bot
parent
612d647e64
commit
f803857dc1
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.codeInsight.daemon.impl.quickfix;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
@@ -62,18 +62,19 @@ public abstract class ArgumentFixerActionFactory {
|
||||
|
||||
try {
|
||||
PsiType expectedTypeByParent = PsiTypesUtil.getExpectedTypeByParent(call);
|
||||
for (int i = 0; i < expressions.length; i++) {
|
||||
PsiExpression expression = expressions[i];
|
||||
PsiType exprType = expression.getType();
|
||||
Set<String> suggestedCasts = new HashSet<>();
|
||||
// find to which type we can cast this param to get valid method call
|
||||
for (CandidateInfo candidate : methodCandidates) {
|
||||
PsiMethod method = (PsiMethod)candidate.getElement();
|
||||
PsiSubstitutor substitutor = candidate.getSubstitutor();
|
||||
Map<Integer, Set<String>> suggestedCasts = new HashMap<>();
|
||||
// find to which type we can cast this param to get valid method call
|
||||
for (CandidateInfo candidate : methodCandidates) {
|
||||
PsiMethod method = (PsiMethod)candidate.getElement();
|
||||
PsiSubstitutor substitutor = candidate.getSubstitutor();
|
||||
Map<Integer, PsiType> potentialCasts = new HashMap<>();
|
||||
for (int i = 0; i < expressions.length; i++) {
|
||||
PsiExpression expression = expressions[i];
|
||||
PsiType exprType = expression.getType();
|
||||
PsiType originalParameterType = PsiTypesUtil.getParameterType(method.getParameterList().getParameters(), i, true);
|
||||
PsiType parameterType = substitutor.substitute(originalParameterType);
|
||||
if (!PsiTypesUtil.isDenotableType(parameterType, call)) continue;
|
||||
if (suggestedCasts.contains(parameterType.getCanonicalText())) continue;
|
||||
if (suggestedCasts.computeIfAbsent(i, __ -> new HashSet<>()).contains(parameterType.getCanonicalText())) continue;
|
||||
if (TypeConversionUtil.isPrimitiveAndNotNull(exprType) && parameterType instanceof PsiClassType) {
|
||||
PsiType unboxedParameterType = PsiPrimitiveType.getUnboxedType(parameterType);
|
||||
if (unboxedParameterType != null) {
|
||||
@@ -82,21 +83,28 @@ public abstract class ArgumentFixerActionFactory {
|
||||
}
|
||||
// strict compare since even widening cast may help
|
||||
if (Comparing.equal(exprType, parameterType)) continue;
|
||||
PsiCall newCall = LambdaUtil.copyTopLevelCall(call); //copy with expected type
|
||||
potentialCasts.put(i, parameterType);
|
||||
}
|
||||
|
||||
if (!potentialCasts.isEmpty()) {
|
||||
PsiCall newCall = LambdaUtil.copyTopLevelCall(call);
|
||||
if (newCall == null) continue;
|
||||
PsiExpression modifiedExpression = getModifiedArgument(expression, parameterType);
|
||||
if (modifiedExpression == null) continue;
|
||||
PsiExpressionList argumentList = newCall.getArgumentList();
|
||||
if (argumentList == null) continue;
|
||||
argumentList.getExpressions()[i].replace(modifiedExpression);
|
||||
JavaResolveResult resolveResult = newCall.resolveMethodGenerics();
|
||||
if (resolveResult.getElement() != null && resolveResult.isValidResult()) {
|
||||
if (expectedTypeByParent != null && newCall instanceof PsiCallExpression) {
|
||||
PsiType type = ((PsiCallExpression)newCall).getType();
|
||||
if (type != null && !TypeConversionUtil.isAssignable(expectedTypeByParent, type)) continue;
|
||||
for (Map.Entry<Integer, PsiType> entry : potentialCasts.entrySet()) {
|
||||
replaceWithCast(expressions, newCall, entry);
|
||||
}
|
||||
|
||||
doCheckNewCall(expectedTypeByParent, newCall, () -> {
|
||||
for (Iterator<Map.Entry<Integer, PsiType>> iterator = potentialCasts.entrySet().iterator(); iterator.hasNext(); ) {
|
||||
Map.Entry<Integer, PsiType> entry = iterator.next();
|
||||
registerCastIntention(highlightInfo, fixRange, list, suggestedCasts, entry);
|
||||
iterator.remove();
|
||||
}
|
||||
suggestedCasts.add(parameterType.getCanonicalText());
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, createFix(list, i, parameterType));
|
||||
});
|
||||
|
||||
for (Map.Entry<Integer, PsiType> entry : potentialCasts.entrySet()) {
|
||||
PsiCall callWithSingleCast = LambdaUtil.copyTopLevelCall(call);
|
||||
if (callWithSingleCast == null || replaceWithCast(expressions, callWithSingleCast, entry)) continue;
|
||||
doCheckNewCall(expectedTypeByParent, callWithSingleCast, () -> registerCastIntention(highlightInfo, fixRange, list, suggestedCasts, entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,6 +114,37 @@ public abstract class ArgumentFixerActionFactory {
|
||||
}
|
||||
}
|
||||
|
||||
private static void doCheckNewCall(PsiType expectedTypeByParent, PsiCall callWithSingleCast, Runnable registerIntentions) {
|
||||
JavaResolveResult resolveResult = callWithSingleCast.resolveMethodGenerics();
|
||||
if (resolveResult.getElement() != null && resolveResult.isValidResult()) {
|
||||
if (expectedTypeByParent != null && callWithSingleCast instanceof PsiCallExpression) {
|
||||
PsiType type = ((PsiCallExpression)callWithSingleCast).getType();
|
||||
if (type != null && !TypeConversionUtil.isAssignable(expectedTypeByParent, type)) return;
|
||||
}
|
||||
registerIntentions.run();
|
||||
}
|
||||
}
|
||||
|
||||
private void registerCastIntention(HighlightInfo highlightInfo,
|
||||
TextRange fixRange,
|
||||
PsiExpressionList list,
|
||||
Map<Integer, Set<String>> suggestedCasts,
|
||||
Map.Entry<Integer, PsiType> entry) {
|
||||
suggestedCasts.get(entry.getKey()).add(entry.getValue().getCanonicalText());
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, createFix(list, entry.getKey(), entry.getValue()));
|
||||
}
|
||||
|
||||
private boolean replaceWithCast(PsiExpression[] expressions, PsiCall newCall, Map.Entry<Integer, PsiType> entry) {
|
||||
Integer i = entry.getKey();
|
||||
PsiType parameterType = entry.getValue();
|
||||
PsiExpression modifiedExpression = getModifiedArgument(expressions[i], parameterType);
|
||||
if (modifiedExpression == null) return true;
|
||||
PsiExpressionList argumentList = newCall.getArgumentList();
|
||||
if (argumentList == null) return true;
|
||||
argumentList.getExpressions()[i].replace(modifiedExpression);
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract boolean areTypesConvertible(@NotNull PsiType exprType, @NotNull PsiType parameterType, @NotNull PsiElement context);
|
||||
|
||||
public abstract IntentionAction createFix(PsiExpressionList list, int i, PsiType parameterType);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// "Cast 1st parameter to 'char'" "true"
|
||||
class a {
|
||||
private void test() {}
|
||||
private void test(int i) {}
|
||||
private void test(String s) {}
|
||||
private void test(Object o) {}
|
||||
private void test(char c,char f) {}
|
||||
private void test(int c, char f) {}
|
||||
|
||||
void f() {
|
||||
test((char) 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Cast 1st parameter to 'java.lang.Throwable'" "true"
|
||||
class a {
|
||||
void f(Throwable a, Throwable b) {}
|
||||
void g() {
|
||||
Exception e=null;
|
||||
Object o = null;
|
||||
f((Throwable) e,o);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Cast 1st parameter to 'char'" "false"
|
||||
// "Cast 1st parameter to 'char'" "true"
|
||||
class a {
|
||||
private void test() {}
|
||||
private void test(int i) {}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Cast 1st parameter to 'java.lang.Throwable'" "false"
|
||||
// "Cast 1st parameter to 'java.lang.Throwable'" "true"
|
||||
class a {
|
||||
void f(Throwable a, Throwable b) {}
|
||||
void g() {
|
||||
|
||||
Reference in New Issue
Block a user