From 1e7810d41c7c84d3412692f87543d07de834c0e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pap=20L=C5=91rinc?= Date: Wed, 2 Mar 2016 18:54:47 +0200 Subject: [PATCH] Fixed `ResultOfAssignmentUsed` inspection, when it's not in method --- ...roovyResultOfAssignmentUsedInspection.java | 29 ++++- .../plugins/groovy/lang/psi/util/PsiUtil.java | 11 +- .../lang/highlighting/GrInspectionTest.groovy | 4 +- .../GrResultOfAssignmentUsedTest.groovy | 102 ++++++++++++++++++ .../lang/highlighting/GrUnusedDefTest.groovy | 53 ++++----- .../ResultOfAssignmentUsed.groovy | 2 +- .../highlighting/UnusedDefsForArgs.groovy | 2 +- .../testdata/highlighting/UnusedInc.groovy | 2 +- 8 files changed, 165 insertions(+), 40 deletions(-) create mode 100644 plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrResultOfAssignmentUsedTest.groovy diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyResultOfAssignmentUsedInspection.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyResultOfAssignmentUsedInspection.java index efdd32fb904b..e90c7d99a020 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyResultOfAssignmentUsedInspection.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyResultOfAssignmentUsedInspection.java @@ -15,15 +15,33 @@ */ package org.jetbrains.plugins.groovy.codeInspection.assignment; +import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.codeInspection.BaseInspection; import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; +import javax.swing.*; + public class GroovyResultOfAssignmentUsedInspection extends BaseInspection { + /** + * @noinspection PublicField, WeakerAccess + */ + public boolean inspectClosures = false; + + @Override + @Nullable + public JComponent createOptionsPanel() { + final MultipleCheckboxOptionsPanel optionsPanel = new MultipleCheckboxOptionsPanel(this); + optionsPanel.addCheckbox("Inspect anonymous closures", "inspectClosures"); + return optionsPanel; + } @Override @Nls @@ -51,14 +69,21 @@ public class GroovyResultOfAssignmentUsedInspection extends BaseInspection { return new Visitor(); } - private static class Visitor extends BaseInspectionVisitor { + private class Visitor extends BaseInspectionVisitor { @Override public void visitAssignmentExpression(GrAssignmentExpression grAssignmentExpression) { super.visitAssignmentExpression(grAssignmentExpression); - if (PsiUtil.isExpressionUsed(grAssignmentExpression)) { + if (isConfusingAssignmentUsage(grAssignmentExpression)) { registerError(grAssignmentExpression); } } + + private boolean isConfusingAssignmentUsage(PsiElement expr) { + PsiElement parent = expr.getParent(); + return !(parent instanceof GroovyFile) && + (inspectClosures || !(parent instanceof GrClosableBlock)) && + PsiUtil.isExpressionUsed(expr); + } } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java index 4f845706ec24..6a3262ef3adf 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java @@ -65,6 +65,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnState import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrThrowStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrCaseSection; import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrForInClause; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrTraditionalForClause; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty; @@ -1169,9 +1170,17 @@ public class PsiUtil { parent instanceof GrAssertStatement || parent instanceof GrThrowStatement || parent instanceof GrSwitchStatement || - parent instanceof GrVariable) { + parent instanceof GrVariable || + parent instanceof GrReferenceExpression || + parent instanceof GrWhileStatement) { return true; } + + if (parent instanceof GrTraditionalForClause) { + GrTraditionalForClause forClause = (GrTraditionalForClause)parent; + return expr == forClause.getCondition(); + } + return isReturnStatement(expr); } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrInspectionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrInspectionTest.groovy index d294dbf5c047..e232b54e8720 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrInspectionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrInspectionTest.groovy @@ -50,11 +50,11 @@ class GrInspectionTest extends GrHighlightingTestBase { public void testResolveMetaClass() { doTest(new GroovyAccessibilityInspection()) } - public void testResultOfAssignmentUsed() { doTest(new GroovyResultOfAssignmentUsedInspection()) } + public void testResultOfAssignmentUsed() { doTest(new GroovyResultOfAssignmentUsedInspection(inspectClosures: true)) } public void testSuppressions() { doTest(new GrUnresolvedAccessInspection(), new GroovyUntypedAccessInspection()) } - public void testInnerClassConstructorThis() { doTest(true, true, true, new GroovyResultOfAssignmentUsedInspection()) } + public void testInnerClassConstructorThis() { doTest(true, true, true, new GroovyResultOfAssignmentUsedInspection(inspectClosures: true)) } public void testUnnecessaryReturnInSwitch() { doTest(new GroovyUnnecessaryReturnInspection()) } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrResultOfAssignmentUsedTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrResultOfAssignmentUsedTest.groovy new file mode 100644 index 000000000000..cd094170d668 --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrResultOfAssignmentUsedTest.groovy @@ -0,0 +1,102 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.highlighting + +import com.intellij.codeInspection.InspectionProfileEntry +import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyResultOfAssignmentUsedInspection + +class GrResultOfAssignmentUsedTest extends GrHighlightingTestBase { + final inspection = new GroovyResultOfAssignmentUsedInspection() + + @Override + InspectionProfileEntry[] getCustomInspections() { [inspection] } + + final warnStart = '' + final warnEnd = '' + + void testUsedVar() { + testHighlighting """ + def foo(a) { + if ((${warnStart}a = 5${warnEnd}) || a) { + ${warnStart}a = 4${warnEnd} + } + } + + def foo2(a) { + def b = 'b' + if (!a) { + println b + b = 5 + } + return 0 // make b = 5 not a return statement + } + + def bar(a) { + print ((${warnStart}a = 5${warnEnd})?:a) + } + + def a(b) { + if (2 && (${warnStart}b = 5${warnEnd})) { + b + } + } + """ + } + + void testResultOfAssignmentUsedInspection() { + testHighlighting """ + if ((${warnStart}a = b${warnEnd}) == null) { + } + """ + + testHighlighting """ + while (${warnStart}a = b${warnEnd}) { + } + """ + + testHighlighting """ + for (i = 0; ${warnStart}a = b${warnEnd}; i++) { + } + """ + + testHighlighting """ + System.out.println(${warnStart}a = b${warnEnd}) + """ + + testHighlighting """ + (${warnStart}a = b${warnEnd}).each {} + """ + } + + void testInspectClosuresOption_isTrue() { + inspection.inspectClosures = true + testHighlighting 'a = 1 ' + testHighlighting "a(0, { ${warnStart}b = 1${warnEnd} }, 2)" + testHighlighting "def a = { ${warnStart}b = 1${warnEnd} }" + testHighlighting "a(0, ${warnStart}b = 1${warnEnd}, 2)" + testHighlighting "def a() { ${warnStart}b = 1${warnEnd} }" + inspection.inspectClosures = false + } + + void testInspectClosuresOption_isFalse() { + inspection.inspectClosures = false + testHighlighting 'a = 1 ' + testHighlighting 'a(0, { b = 1 }, 2)' + testHighlighting "def a = { b = 1 }" + testHighlighting "a(0, ${warnStart}b = 1${warnEnd}, 2)" + testHighlighting "def a() { ${warnStart}b = 1${warnEnd} }" + } +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrUnusedDefTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrUnusedDefTest.groovy index 462045b9a785..ee3d798e6c68 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrUnusedDefTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrUnusedDefTest.groovy @@ -18,7 +18,6 @@ package org.jetbrains.plugins.groovy.lang.highlighting import com.intellij.codeInspection.InspectionProfileEntry import com.intellij.codeInspection.deadCode.UnusedDeclarationInspectionBase import org.jetbrains.plugins.groovy.codeInspection.GroovyUnusedDeclarationInspection -import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyResultOfAssignmentUsedInspection import org.jetbrains.plugins.groovy.codeInspection.confusing.GrUnusedIncDecInspection import org.jetbrains.plugins.groovy.codeInspection.unusedDef.UnusedDefInspection @@ -28,7 +27,10 @@ import org.jetbrains.plugins.groovy.codeInspection.unusedDef.UnusedDefInspection class GrUnusedDefTest extends GrHighlightingTestBase { @Override InspectionProfileEntry[] getCustomInspections() { - return [new UnusedDefInspection(), new GrUnusedIncDecInspection(), new GroovyUnusedDeclarationInspection(), new UnusedDeclarationInspectionBase(true), new GroovyResultOfAssignmentUsedInspection()] as InspectionProfileEntry[] + [new UnusedDefInspection(), + new GrUnusedIncDecInspection(), + new GroovyUnusedDeclarationInspection(), + new UnusedDeclarationInspectionBase(true)] } public void testUnusedVariable() { doTest() } @@ -39,13 +41,13 @@ class GrUnusedDefTest extends GrHighlightingTestBase { public void testDefinitionUsedInSwitchCase() { doTest() } - public void testUnusedDefinitionForMethodMissing() { doTest()} + public void testUnusedDefinitionForMethodMissing() { doTest() } public void testPrefixIncrementCfa() { doTest() } public void testIfIncrementElseReturn() { doTest() } - public void testSwitchControlFlow() { doTest()} + public void testSwitchControlFlow() { doTest() } public void testUsageInInjection() { doTest() } @@ -62,7 +64,7 @@ class GrUnusedDefTest extends GrHighlightingTestBase { public void testGloballyUnusedSymbols() { doTest() } public void testGloballyUnusedInnerMethods() { - myFixture.addClass 'package junit.framework public class TestCase {}' + myFixture.addClass 'package junit.framework; public class TestCase {}' doTest() } @@ -82,33 +84,21 @@ class Foo { } void testUsedVar() { - testHighlighting('''\ -def foo(xxx) { - if ((xxx = 5) || xxx) { - xxx=4 - } -} + testHighlighting ''' + def foo(xxx) { + if ((xxx = 5) || xxx) { + xxx=4 + } + } -def foxo(doo) { - def xxx = 'asdf' - if (!doo) { - println xxx - xxx=5 - } -} - -def bar(xxx) { - print ((xxx=5)?:xxx) -} - -def a(xxx) { - if (2 && (xxx=5)) { - xxx - } - else { - } -} -''') + def foxo(doo) { + def xxx = 'asdf' + if (!doo) { + println xxx + xxx=5 + } + } + ''' } void testFallthroughInSwitch() { @@ -134,5 +124,4 @@ def f2(String foo, int mode) { def abc ''') } - } diff --git a/plugins/groovy/testdata/highlighting/ResultOfAssignmentUsed.groovy b/plugins/groovy/testdata/highlighting/ResultOfAssignmentUsed.groovy index d47a197deec4..cb5fb5b198a9 100644 --- a/plugins/groovy/testdata/highlighting/ResultOfAssignmentUsed.groovy +++ b/plugins/groovy/testdata/highlighting/ResultOfAssignmentUsed.groovy @@ -1,7 +1,7 @@ public class AssResult { public void context(boolean b, String ps) { String vs = 'prefix' - if (b) vs += ps // warning + if (b) vs += ps // no warning if (b) { vs += ps } // no warning print vs = 4 println ps diff --git a/plugins/groovy/testdata/highlighting/UnusedDefsForArgs.groovy b/plugins/groovy/testdata/highlighting/UnusedDefsForArgs.groovy index c77f21708083..6c4a1ae35984 100644 --- a/plugins/groovy/testdata/highlighting/UnusedDefsForArgs.groovy +++ b/plugins/groovy/testdata/highlighting/UnusedDefsForArgs.groovy @@ -1 +1 @@ -args = [] \ No newline at end of file +args = [] \ No newline at end of file diff --git a/plugins/groovy/testdata/highlighting/UnusedInc.groovy b/plugins/groovy/testdata/highlighting/UnusedInc.groovy index f5bee8453032..190915f47a33 100644 --- a/plugins/groovy/testdata/highlighting/UnusedInc.groovy +++ b/plugins/groovy/testdata/highlighting/UnusedInc.groovy @@ -4,4 +4,4 @@ print (a++) def b = 3 b++ - b = 3 \ No newline at end of file + b = 3 \ No newline at end of file