[java-intentions] Qualify a method call with an outer class name: fixes after review

IJ-CR-21030
IDEA-255881

GitOrigin-RevId: 8e6b0c6acb9505e75356c4c23c80c5c66870cd41
This commit is contained in:
Andrey.Cherkasov
2022-02-19 05:57:41 +00:00
committed by intellij-monorepo-bot
parent 092977bccf
commit f0000950e6
25 changed files with 93 additions and 56 deletions
@@ -613,14 +613,4 @@ public abstract class QuickFixFactory {
*/
public abstract @NotNull IntentionAction createRemoveRedundantLambdaParameterTypesFix(@NotNull PsiLambdaExpression lambdaExpression,
@IntentionName String message);
/**
* Creates a fix that qualify a reference expression with a qualifier having given text
*
* @param expression reference expression to qualify
* @param qualifierText qualifier text
* @return a new fix
*/
public abstract @NotNull IntentionAction createQualifyWithFix(@NotNull PsiReferenceExpression expression, @NotNull String qualifierText);
}
@@ -3,6 +3,7 @@ package com.intellij.codeInsight.daemon.impl.analysis;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.impl.quickfix.QualifyMethodCallFix;
import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction;
import com.intellij.codeInsight.daemon.impl.quickfix.ReplaceAssignmentFromVoidWithStatementIntentionAction;
import com.intellij.codeInsight.daemon.impl.quickfix.ReplaceGetClassWithClassLiteralFix;
@@ -19,11 +20,13 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.controlFlow.*;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.util.*;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ObjectUtils;
import com.siyeh.ig.callMatcher.CallMatcher;
import com.siyeh.ig.psiutils.ExpressionUtils;
import com.siyeh.ig.psiutils.SwitchUtils;
import com.siyeh.ig.psiutils.VariableAccessUtils;
import org.jetbrains.annotations.NotNull;
@@ -467,4 +470,23 @@ public final class HighlightFixUtil {
return true;
});
}
public static void registerQualifyMethodCallFix(CandidateInfo @NotNull [] methodCandidates,
@NotNull PsiMethodCallExpression methodCall,
@NotNull PsiExpressionList exprList,
@Nullable HighlightInfo highlightInfo) {
for (CandidateInfo methodCandidate : methodCandidates) {
PsiMethod method = (PsiMethod)methodCandidate.getElement();
if (methodCandidate.isAccessible() && PsiUtil.isApplicable(method, methodCandidate.getSubstitutor(), exprList)) {
final PsiModifierListOwner staticParentElement = PsiUtil.getEnclosingStaticElement(methodCall, null);
boolean isMethodStatic = method.hasModifierProperty(PsiModifier.STATIC);
if (staticParentElement == null || isMethodStatic) {
PsiExpression qualifier = ExpressionUtils.getEffectiveQualifier(methodCall.getMethodExpression(), method);
if (qualifier == null) continue;
IntentionAction fix = new QualifyMethodCallFix(methodCall, qualifier.getText());
QuickFixAction.registerQuickFixAction(highlightInfo, HighlightMethodUtil.getFixRange(methodCall), fix);
}
}
}
}
}
@@ -427,7 +427,7 @@ public final class HighlightMethodUtil {
highlightInfo = createIncompatibleCallHighlightInfo(holder, list, candidateInfo);
if (highlightInfo != null) {
registerQualifyWithFixes(resolveHelper.getReferencedMethodCandidates(methodCall, false), methodCall, list, highlightInfo);
HighlightFixUtil.registerQualifyMethodCallFix(resolveHelper.getReferencedMethodCandidates(methodCall, false), methodCall, list, highlightInfo);
registerMethodCallIntentions(highlightInfo, methodCall, list, resolveHelper);
registerMethodReturnFixAction(highlightInfo, candidateInfo, methodCall);
registerTargetTypeFixesBasedOnApplicabilityInference(methodCall, candidateInfo, resolvedMethod, highlightInfo);
@@ -982,33 +982,6 @@ public final class HighlightMethodUtil {
registerChangeParameterClassFix(methodCall, list, highlightInfo, fixRange);
}
private static void registerQualifyWithFixes(CandidateInfo @NotNull [] methodCandidates,
@NotNull PsiMethodCallExpression methodCall,
@NotNull PsiExpressionList exprList,
@Nullable HighlightInfo highlightInfo) {
for (CandidateInfo methodCandidate : methodCandidates) {
PsiMethod method = (PsiMethod)methodCandidate.getElement();
if (methodCandidate.isAccessible() && PsiUtil.isApplicable(method, methodCandidate.getSubstitutor(), exprList)) {
PsiClass aClass = method.getContainingClass();
if (aClass == null) continue;
String className = aClass.getName();
if (className == null) continue;
final PsiModifierListOwner staticParentElement = PsiUtil.getEnclosingStaticElement(methodCall, null);
boolean isMethodStatic = method.hasModifierProperty(PsiModifier.STATIC);
if (staticParentElement == null || isMethodStatic) {
if (isMethodStatic || PsiTreeUtil.isContextAncestor(aClass, methodCall, false)) {
String qualifierText = className;
if (!isMethodStatic) {
qualifierText += ".this";
}
IntentionAction fix = QUICK_FIX_FACTORY.createQualifyWithFix(methodCall.getMethodExpression(), qualifierText);
QuickFixAction.registerQuickFixAction(highlightInfo, getFixRange(methodCall), fix);
}
}
}
}
}
private static void registerMethodAccessLevelIntentions(CandidateInfo @NotNull [] methodCandidates,
@NotNull PsiMethodCallExpression methodCall,
@NotNull PsiExpressionList exprList,
@@ -5,19 +5,16 @@ import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReferenceExpression;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class QualifyWith extends LocalQuickFixAndIntentionActionOnPsiElement {
public class QualifyMethodCallFix extends LocalQuickFixAndIntentionActionOnPsiElement {
private final String myQualifierText;
public QualifyWith(@NotNull PsiReferenceExpression expression,
@NotNull String qualifierText) {
super(expression);
public QualifyMethodCallFix(@NotNull PsiMethodCallExpression call,
@NotNull String qualifierText) {
super(call);
myQualifierText = qualifierText;
}
@@ -39,7 +36,7 @@ public class QualifyWith extends LocalQuickFixAndIntentionActionOnPsiElement {
@Nullable Editor editor,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
PsiReferenceExpression expression = (PsiReferenceExpression)startElement;
PsiReferenceExpression expression = ((PsiMethodCallExpression)startElement).getMethodExpression();
expression.setQualifierExpression(JavaPsiFacade.getElementFactory(project).createExpressionFromText(myQualifierText, null));
}
}
@@ -1174,9 +1174,4 @@ public final class QuickFixFactoryImpl extends QuickFixFactory {
return myMessage;
}
}
@Override
public @NotNull IntentionAction createQualifyWithFix(@NotNull PsiReferenceExpression expression, @NotNull String qualifierText) {
return new QualifyWith(expression, qualifierText);
}
}
@@ -0,0 +1,18 @@
// "Qualify the call with 'A.this'" "true"
class Base {
String name() {
return "";
}
}
class A extends Base {
class B {
String name(String key) {
return A.this.name();
}
}
public String name() {
return "";
}
}
@@ -0,0 +1,14 @@
// "Qualify the call with 'A.this'" "true"
class Base {
String name() {
return "";
}
}
class A extends Base {
class B {
String name(String key) {
return A.this.name();
}
}
}
@@ -1,4 +1,4 @@
// "Qualify the call with 'Base.this'" "false"
// "Qualify the call with 'A.this'" "true"
class Base {
String name() {
return "";
@@ -0,0 +1,14 @@
// "Qualify the call with 'A.this'" "true"
class Base {
String name() {
return "";
}
}
class A extends Base {
class B {
String name(String key) {
return name(<caret>);
}
}
}
@@ -3,11 +3,11 @@ package com.intellij.java.codeInsight.daemon.quickFix;
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase;
public class QualifyWithTest extends LightQuickFixParameterizedTestCase {
public class QualifyMethodCallFixTest extends LightQuickFixParameterizedTestCase {
@Override
protected String getBasePath() {
return "/codeInsight/daemonCodeAnalyzer/quickFix/qualifyWith";
return "/codeInsight/daemonCodeAnalyzer/quickFix/qualifyMethodCall";
}
}
@@ -994,6 +994,19 @@ public final class ExpressionUtils {
// Reference resolves to non-member: probably variable/parameter/etc.
return null;
}
return getEffectiveQualifier(ref, member);
}
/**
* Returns an effective qualifier for a reference that resolves to a member of a Java class. If qualifier is not
* specified, then tries to construct it e.g. creating a corresponding {@link PsiThisExpression}.
*
* @param ref a reference expression to get an effective qualifier for
* @param member a member the reference is resolved to
* @return a qualifier or created (non-physical) {@link PsiThisExpression}.
* May return null if reference points to member of anonymous class referred from inner class
*/
public static PsiExpression getEffectiveQualifier(@NotNull PsiReferenceExpression ref, @NotNull PsiMember member) {
PsiElementFactory factory = JavaPsiFacade.getElementFactory(ref.getProject());
PsiClass memberClass = member.getContainingClass();
if (memberClass != null) {
@@ -1014,7 +1027,8 @@ public final class ExpressionUtils {
if (thisQualifier == null) {
if (PsiUtil.isLocalClass(containingClass)) {
thisQualifier = containingClass.getName();
} else {
}
else {
// Cannot qualify anonymous class
return null;
}