From e81eee4cc1f31b2aaab8b15c38c26ab91f198531 Mon Sep 17 00:00:00 2001 From: Dennis Cornwell Date: Sun, 29 Jul 2018 23:35:23 +0300 Subject: [PATCH] Introduce inspection for determining if a forEach parameter is unused #KT-22068 Fixed --- .../ForEachParameterNotUsed.html | 5 ++ idea/src/META-INF/plugin.xml | 9 +++ idea/src/META-INF/plugin.xml.173 | 9 +++ idea/src/META-INF/plugin.xml.181 | 9 +++ idea/src/META-INF/plugin.xml.183 | 9 +++ idea/src/META-INF/plugin.xml.as31 | 9 +++ idea/src/META-INF/plugin.xml.as32 | 9 +++ idea/src/META-INF/plugin.xml.as33 | 9 +++ .../ForEachParameterNotUsedInspection.kt | 67 +++++++++++++++++++ .../correctReference.kt | 10 +++ .../inspectionData/expected.xml | 34 ++++++++++ .../inspectionData/inspections.test | 2 + .../forEachParameterNotUsed/test.kt | 11 +++ .../codeInsight/InspectionTestGenerated.java | 5 ++ 14 files changed, 197 insertions(+) create mode 100644 idea/resources/inspectionDescriptions/ForEachParameterNotUsed.html create mode 100644 idea/src/org/jetbrains/kotlin/idea/inspections/ForEachParameterNotUsedInspection.kt create mode 100644 idea/testData/inspections/forEachParameterNotUsed/correctReference.kt create mode 100644 idea/testData/inspections/forEachParameterNotUsed/inspectionData/expected.xml create mode 100644 idea/testData/inspections/forEachParameterNotUsed/inspectionData/inspections.test create mode 100644 idea/testData/inspections/forEachParameterNotUsed/test.kt diff --git a/idea/resources/inspectionDescriptions/ForEachParameterNotUsed.html b/idea/resources/inspectionDescriptions/ForEachParameterNotUsed.html new file mode 100644 index 00000000000..280af78a53e --- /dev/null +++ b/idea/resources/inspectionDescriptions/ForEachParameterNotUsed.html @@ -0,0 +1,5 @@ + + +This inspection guards against useless forEach loops by identifying when the iterable's values are not used. + + \ No newline at end of file diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 77000e98e68..195f4b81acd 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -2924,6 +2924,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + + + + + + + + + + + + + { + val lambda = it.lambdaArguments.singleOrNull()?.getLambdaExpression() ?: return@callExpressionVisitor + val descriptor = lambda.analyze()[BindingContext.FUNCTION, lambda.functionLiteral] ?: return@callExpressionVisitor + val iterableParameter = descriptor.valueParameters.singleOrNull() ?: return@callExpressionVisitor + + if (lambda.bodyExpression?.usesDescriptor(iterableParameter) != true && it.calleeExpression != null) { + holder.registerProblem( + it.calleeExpression!!, + "Loop parameter '${iterableParameter.getThisLabelName()}' is unused", + ProblemHighlightType.GENERIC_ERROR_OR_WARNING + ) + } + } + } + } + } + + private fun KtBlockExpression.usesDescriptor(descriptor: VariableDescriptor): Boolean { + var used = false + acceptChildren(object : KtVisitorVoid() { + override fun visitKtElement(element: KtElement) { + if (!used) { + if (element.children.isNotEmpty()) { + element.acceptChildren(this) + } else { + val bindingContext = element.analyze() + val resolvedCall = element.getResolvedCall(bindingContext) ?: return + + used = resolvedCall.candidateDescriptor == descriptor + } + } + } + }) + return used + } +} \ No newline at end of file diff --git a/idea/testData/inspections/forEachParameterNotUsed/correctReference.kt b/idea/testData/inspections/forEachParameterNotUsed/correctReference.kt new file mode 100644 index 00000000000..e0f667413d9 --- /dev/null +++ b/idea/testData/inspections/forEachParameterNotUsed/correctReference.kt @@ -0,0 +1,10 @@ +fun test() { + val items = sequenceOf() + items.forEach { + ForEachable().forEach {} + } +} + +class ForEachable { + fun forEach(action: (ForEachable) -> Unit) {} +} \ No newline at end of file diff --git a/idea/testData/inspections/forEachParameterNotUsed/inspectionData/expected.xml b/idea/testData/inspections/forEachParameterNotUsed/inspectionData/expected.xml new file mode 100644 index 00000000000..4d2af48e66b --- /dev/null +++ b/idea/testData/inspections/forEachParameterNotUsed/inspectionData/expected.xml @@ -0,0 +1,34 @@ + + + test.kt + 3 + light_idea_test_case + + Iterated elements are not used in forEach + Loop parameter 'it' is unused + + + test.kt + 4 + light_idea_test_case + + Iterated elements are not used in forEach + Loop parameter 'item' is unused + + + test.kt + 7 + light_idea_test_case + + Iterated elements are not used in forEach + Loop parameter 'it' is unused + + + correctReference.kt + 3 + light_idea_test_case + + Iterated elements are not used in forEach + Loop parameter 'it' is unused + + \ No newline at end of file diff --git a/idea/testData/inspections/forEachParameterNotUsed/inspectionData/inspections.test b/idea/testData/inspections/forEachParameterNotUsed/inspectionData/inspections.test new file mode 100644 index 00000000000..ca92ab2769f --- /dev/null +++ b/idea/testData/inspections/forEachParameterNotUsed/inspectionData/inspections.test @@ -0,0 +1,2 @@ +// INSPECTION_CLASS: org.jetbrains.kotlin.idea.inspections.ForEachParameterNotUsedInspection +// WITH_RUNTIME diff --git a/idea/testData/inspections/forEachParameterNotUsed/test.kt b/idea/testData/inspections/forEachParameterNotUsed/test.kt new file mode 100644 index 00000000000..25ec0a23f80 --- /dev/null +++ b/idea/testData/inspections/forEachParameterNotUsed/test.kt @@ -0,0 +1,11 @@ +fun test() { + val items = listOf() + items.forEach { } + items.forEach { item -> } + items.forEach { doSomething(it) } + items.forEach { item -> doSomething(item) } + items.forEach { items.forEach { doSomething(it) } } + items.forEach { items.forEach { thing -> doSomething(it); doSomething(thing) } } +} + +fun doSomething(item: Any) {} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java index ba3901559e2..669d0ea338f 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java @@ -169,6 +169,11 @@ public class InspectionTestGenerated extends AbstractInspectionTest { runTest("idea/testData/inspections/equalsAndHashCode/inspectionData/inspections.test"); } + @TestMetadata("forEachParameterNotUsed/inspectionData/inspections.test") + public void testForEachParameterNotUsed_inspectionData_Inspections_test() throws Exception { + runTest("idea/testData/inspections/forEachParameterNotUsed/inspectionData/inspections.test"); + } + @TestMetadata("gradleWrongPluginVersion/inspectionData/inspections.test") public void testGradleWrongPluginVersion_inspectionData_Inspections_test() throws Exception { runTest("idea/testData/inspections/gradleWrongPluginVersion/inspectionData/inspections.test");