From 4ce5115d22599933dc37ffdf276f1eb08501f5f0 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Sat, 30 Mar 2019 16:47:27 +0100 Subject: [PATCH] IG: add option to ignore methods which return the type of the enclosing class (IDEA-93333) for "Chained method calls" inspection --- .../siyeh/InspectionGadgetsBundle.properties | 2 +- .../ig/style/ChainedMethodCallInspection.java | 56 ++++++++++++++----- .../igtest/bugs/ChainedMethodInspection.java | 19 ------- .../ChainedMethodCall.java | 22 ++++++++ .../ChainedMethodCallInspectionTest.java | 22 ++++++++ 5 files changed, 86 insertions(+), 35 deletions(-) delete mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ChainedMethodInspection.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/style/chained_method_call/ChainedMethodCall.java create mode 100644 plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/ChainedMethodCallInspectionTest.java diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties index d3dd36ee138d..ecb0250d4b75 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1292,7 +1292,7 @@ literal.as.arg.to.string.equals.problem.descriptor=Literal #ref is literal.as.arg.to.string.equals.flip.quickfix=Flip ''{0}()'' c.style.array.declaration.replace.quickfix=Replace with Java-style array declaration chained.method.call.ignore.option=Ignore chained method calls in field initializers -chained.method.call.ignore.this.super.option=Ignore chained method calls in 'this()' and 'super()' calls +chained.method.call.ignore.self.types.option=Ignore calls to methods returning the same type as their enclosing class introduce.variable.quickfix=Introduce variable introduce.variable.may.change.semantics.quickfix=Introduce variable (may change semantics) flip.comparison.quickfix=Flip comparison diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/ChainedMethodCallInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/ChainedMethodCallInspection.java index 73795d618855..54803e41a129 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/style/ChainedMethodCallInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/ChainedMethodCallInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2016 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2019 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package com.siyeh.ig.style; import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.JavaPsiConstructorUtil; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; @@ -25,6 +26,7 @@ import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.fixes.IntroduceVariableFix; import com.siyeh.ig.psiutils.ParenthesesUtils; +import org.jdom.Element; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -32,14 +34,24 @@ import javax.swing.*; public class ChainedMethodCallInspection extends BaseInspection { @SuppressWarnings("PublicField") public boolean m_ignoreFieldInitializations = true; + + @SuppressWarnings({"PublicField", "unused"}) + public boolean m_ignoreThisSuperCalls = true; // keep for compatibility + @SuppressWarnings("PublicField") - public boolean m_ignoreThisSuperCalls = true; + public boolean ignoreSelfTypes = true; + + @Override + public void writeSettings(@NotNull Element node) { + defaultWriteSettings(node, "ignoreSelfTypes"); + writeBooleanOption(node, "ignoreSelfTypes", true); + } @Override public JComponent createOptionsPanel() { final MultipleCheckboxOptionsPanel panel = new MultipleCheckboxOptionsPanel(this); panel.addCheckbox(InspectionGadgetsBundle.message("chained.method.call.ignore.option"), "m_ignoreFieldInitializations"); - panel.addCheckbox(InspectionGadgetsBundle.message("chained.method.call.ignore.this.super.option"), "m_ignoreThisSuperCalls"); + panel.addCheckbox(InspectionGadgetsBundle.message("chained.method.call.ignore.self.types.option"), "ignoreSelfTypes"); return panel; } @@ -76,11 +88,11 @@ public class ChainedMethodCallInspection extends BaseInspection { public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) { super.visitMethodCallExpression(expression); final PsiReferenceExpression reference = expression.getMethodExpression(); - final PsiExpression qualifier = reference.getQualifierExpression(); + final PsiExpression qualifier = ParenthesesUtils.stripParentheses(reference.getQualifierExpression()); if (qualifier == null) { return; } - if (!isCallExpression(qualifier)) { + if (!(qualifier instanceof PsiCallExpression)) { return; } if (m_ignoreFieldInitializations) { @@ -89,21 +101,35 @@ public class ChainedMethodCallInspection extends BaseInspection { return; } } - if (m_ignoreThisSuperCalls) { - final PsiExpressionList expressionList = PsiTreeUtil.getParentOfType(expression, PsiExpressionList.class); - if (expressionList != null) { - final PsiElement parent = expressionList.getParent(); - if (JavaPsiConstructorUtil.isConstructorCall(parent)) { + final PsiExpressionList expressionList = PsiTreeUtil.getParentOfType(expression, PsiExpressionList.class); + if (expressionList != null) { + final PsiElement parent = expressionList.getParent(); + if (JavaPsiConstructorUtil.isConstructorCall(parent)) { + return; + } + } + if (ignoreSelfTypes) { + if (qualifier instanceof PsiMethodCallExpression) { + final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)qualifier; + final PsiMethod qualifierMethod = methodCallExpression.resolveMethod(); + if (qualifierMethod == null) { + return; + } + PsiClass containingClass = qualifierMethod.getContainingClass(); + PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(qualifierMethod.getReturnType()); + if (containingClass == null || containingClass.equals(aClass)) { + return; + } + } + else { + PsiClass callClass = PsiUtil.resolveClassInClassTypeOnly(expression.getType()); + PsiClass qualifierClass = PsiUtil.resolveClassInClassTypeOnly(qualifier.getType()); + if (qualifierClass == null || qualifierClass.equals(callClass)) { return; } } } registerMethodCallError(expression); } - - private boolean isCallExpression(PsiExpression expression) { - expression = ParenthesesUtils.stripParentheses(expression); - return expression instanceof PsiMethodCallExpression || expression instanceof PsiNewExpression; - } } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ChainedMethodInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ChainedMethodInspection.java deleted file mode 100644 index 584be27c5304..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ChainedMethodInspection.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.siyeh.igtest.bugs; - -public class ChainedMethodInspection{ - private ChainedMethodInspection baz = foo().bar(); - public void baz(){ - foo().bar(); - (foo()).bar(); - } - - public ChainedMethodInspection foo() - { - return this; - } - - public ChainedMethodInspection bar() - { - return this; - } -} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/chained_method_call/ChainedMethodCall.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/chained_method_call/ChainedMethodCall.java new file mode 100644 index 000000000000..be1b3906ab37 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/chained_method_call/ChainedMethodCall.java @@ -0,0 +1,22 @@ +package com.siyeh.igtest.bugs; + +public class ChainedMethodCall { + private X baz = new X().foo().bar(); + public void baz(){ + new X().foo().bar(); + (new X().foo()).bar(); + String s = new StringBuilder().append("x: ").append(new X()).append("y: ").append(new Y()).toString(); + } + + class X { + public Y foo() { + return new Y(); + } + } + + class Y { + public X bar() { + return new X(); + } + } +} diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/ChainedMethodCallInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/ChainedMethodCallInspectionTest.java new file mode 100644 index 000000000000..dc6b29eddb9f --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/ChainedMethodCallInspectionTest.java @@ -0,0 +1,22 @@ +// Copyright 2000-2019 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. +package com.siyeh.ig.style; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class ChainedMethodCallInspectionTest extends LightInspectionTestCase { + + public void testChainedMethodCall() { + doTest(); + } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new ChainedMethodCallInspection(); + } +}