call static on subclass: warn on method references (IDEA-187321)

This commit is contained in:
Anna Kozlova
2018-03-07 08:02:40 +01:00
parent 75a7ae68e3
commit 25ea060e3c
4 changed files with 80 additions and 19 deletions
@@ -19,6 +19,7 @@ import com.intellij.codeInspection.CleanupLocalInspectionTool;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.util.ObjectUtils;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
@@ -67,13 +68,26 @@ public class StaticCallOnSubclassInspection extends BaseInspection implements Cl
@Override
public void doFix(Project project, ProblemDescriptor descriptor) {
final PsiIdentifier name = (PsiIdentifier)descriptor.getPsiElement();
final PsiReferenceExpression expression = (PsiReferenceExpression)name.getParent();
final PsiIdentifier name = ObjectUtils.tryCast(descriptor.getPsiElement(), PsiIdentifier.class);
if (name == null) return;
final PsiReferenceExpression expression = ObjectUtils.tryCast(name.getParent(), PsiReferenceExpression.class);
if (expression == null) {
return;
}
final PsiMethodCallExpression call = (PsiMethodCallExpression)expression.getParent();
final String methodName = expression.getReferenceName();
if (expression instanceof PsiMethodReferenceExpression) {
PsiElement resolve = expression.resolve();
if (resolve instanceof PsiMethod) {
PsiClass containingClass = ((PsiMethod)resolve).getContainingClass();
if (containingClass != null) {
PsiExpression qualifierExpression = expression.getQualifierExpression();
if (qualifierExpression instanceof PsiReferenceExpression) {
((PsiReferenceExpression)qualifierExpression).bindToElement(containingClass);
}
}
}
return;
}
final PsiMethodCallExpression call = ObjectUtils.tryCast(expression.getParent(), PsiMethodCallExpression.class);
if (call == null) {
return;
}
@@ -90,6 +104,7 @@ public class StaticCallOnSubclassInspection extends BaseInspection implements Cl
CommentTracker commentTracker = new CommentTracker();
final String argText = commentTracker.text(argumentList);
final String typeArgText = commentTracker.text(call.getTypeArgumentList());
final String methodName = expression.getReferenceName();
PsiReplacementUtil.replaceExpressionAndShorten(call, containingClassName + '.' + typeArgText + methodName + argText, commentTracker);
}
}
@@ -99,26 +114,39 @@ public class StaticCallOnSubclassInspection extends BaseInspection implements Cl
return new StaticCallOnSubclassVisitor();
}
private static class StaticCallOnSubclassVisitor
extends BaseInspectionVisitor {
private static class StaticCallOnSubclassVisitor extends BaseInspectionVisitor {
@Override
public void visitMethodCallExpression(
@NotNull PsiMethodCallExpression call) {
public void visitMethodCallExpression(@NotNull PsiMethodCallExpression call) {
super.visitMethodCallExpression(call);
final PsiReferenceExpression methodExpression =
call.getMethodExpression();
final PsiElement qualifier = methodExpression.getQualifier();
if (!(qualifier instanceof PsiReferenceExpression)) {
return;
}
final PsiMethod method = call.resolveMethod();
final PsiReferenceExpression methodExpression = call.getMethodExpression();
final PsiMethod method = call.resolveMethod();
if (method == null) {
return;
}
checkCallOnSubclass(method, methodExpression);
}
@Override
public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) {
super.visitMethodReferenceExpression(expression);
if (PsiMethodReferenceUtil.isStaticallyReferenced(expression)) {
PsiElement resolve = expression.resolve();
if (resolve instanceof PsiMethod) {
checkCallOnSubclass((PsiMethod)resolve, expression);
}
}
}
private void checkCallOnSubclass(@NotNull PsiMethod method, PsiReferenceExpression methodExpression) {
if (!method.hasModifierProperty(PsiModifier.STATIC)) {
return;
}
PsiExpression qualifier = methodExpression.getQualifierExpression();
if (!(qualifier instanceof PsiReferenceExpression)) {
return;
}
final PsiElement referent = ((PsiReference)qualifier).resolve();
if (!(referent instanceof PsiClass)) {
return;
@@ -131,11 +159,15 @@ public class StaticCallOnSubclassInspection extends BaseInspection implements Cl
if (declaringClass.equals(referencedClass)) {
return;
}
final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(call.getProject()).getResolveHelper();
if (!resolveHelper.isAccessible(declaringClass, call, null)) {
final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(methodExpression.getProject()).getResolveHelper();
if (!resolveHelper.isAccessible(declaringClass, methodExpression, null)) {
return;
}
registerMethodCallError(call, declaringClass, referencedClass);
PsiElement referenceNameElement = methodExpression.getReferenceNameElement();
if (referenceNameElement == null) {
return;
}
registerError(referenceNameElement, declaringClass, referencedClass);
}
}
}
@@ -0,0 +1,13 @@
class I {
static <Z> void FOO() {
}
}
class A extends I {
{
Runnable r = I/*c2*/::<String>FOO;
}
}
@@ -0,0 +1,13 @@
class I {
static <Z> void FOO() {
}
}
class A extends I {
{
Runnable r = A/*c2*/::<String>F<caret>OO;
}
}
@@ -17,7 +17,6 @@ package com.siyeh.ig.fixes.bugs;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.IGQuickFixesTestCase;
import com.siyeh.ig.bugs.CastConflictsWithInstanceofInspection;
import com.siyeh.ig.bugs.StaticCallOnSubclassInspection;
public class StaticCallOnSubclassTest extends IGQuickFixesTestCase {
@@ -31,6 +30,10 @@ public class StaticCallOnSubclassTest extends IGQuickFixesTestCase {
doTest("preserveTypeArgs", InspectionGadgetsBundle.message("static.method.via.subclass.rationalize.quickfix"));
}
public void testMethodReference() {
doTest("methodRef", InspectionGadgetsBundle.message("static.method.via.subclass.rationalize.quickfix"));
}
@Override
protected String getRelativePath() {
return "bugs/staticCallOnSubclass";