Introduce "Unused result of data class copy" inspection

#KT-34121 Fixed
This commit is contained in:
Toshiaki Kameyama
2019-12-11 12:00:55 +09:00
committed by klunnii
parent ae6d89b100
commit bc580d2fd9
10 changed files with 126 additions and 1 deletions
@@ -2216,4 +2216,5 @@ hints.codevision.inheritors.format={0, choice, 1#1 Inheritor|2#{0,number} Inheri
hints.codevision.inheritors.to_many.format={0,number}+ Inheritors
hints.codevision.overrides.format={0, choice, 1#1 Override|2#{0,number} Overrides}
hints.codevision.overrides.to_many.format={0,number}+ Overrides
hints.codevision.settings=Settings...
hints.codevision.settings=Settings...
inspection.unused.result.of.data.class.copy=Unused result of data class copy
+8
View File
@@ -2563,6 +2563,14 @@
language="kotlin"
key="inspection.simplifiable.scope.function.display.name" bundle="messages.KotlinBundle"/>
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.UnusedDataClassCopyResultInspection"
groupPath="Kotlin"
groupName="Probable bugs"
enabledByDefault="true"
level="WARNING"
language="kotlin"
key="inspection.unused.result.of.data.class.copy" bundle="messages.KotlinBundle"/>
</extensions>
</idea-plugin>
@@ -0,0 +1,5 @@
<html>
<body>
This inspection reports unused result of data class copy function call.
</body>
</html>
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInspection.ProblemsHolder
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.psi.callExpressionVisitor
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
class UnusedDataClassCopyResultInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = callExpressionVisitor(fun(call) {
val callee = call.calleeExpression ?: return
if (callee.text != "copy") return
val context = call.analyze(BodyResolveMode.PARTIAL_WITH_CFA)
val descriptor = call.getResolvedCall(context)?.resultingDescriptor ?: return
val receiver = descriptor.dispatchReceiverParameter ?: descriptor.extensionReceiverParameter ?: return
if ((receiver.value as? ImplicitClassReceiver)?.classDescriptor?.isData != true) return
if (call.getQualifiedExpressionForSelectorOrThis().isUsedAsExpression(context)) return
holder.registerProblem(callee, KotlinBundle.message("inspection.unused.result.of.data.class.copy"))
})
}
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.inspections.UnusedDataClassCopyResultInspection
@@ -0,0 +1,11 @@
// FIX: none
// WITH_RUNTIME
fun main() {
val o = Foo("")
o.<caret>copy(prop = "New")
bar(o)
}
data class Foo(val prop: String)
fun bar(foo: Foo) {}
@@ -0,0 +1,13 @@
// FIX: none
// WITH_RUNTIME
fun main() {
val o = Foo("")
o.run {
<caret>copy(prop = "New")
bar(o)
}
}
data class Foo(val prop: String)
fun bar(foo: Foo) {}
@@ -0,0 +1,11 @@
// PROBLEM: none
// WITH_RUNTIME
fun main() {
val o = Foo("")
val o2 = o.<caret>copy(prop = "New")
bar(o2)
}
data class Foo(val prop: String)
fun bar(foo: Foo) {}
@@ -0,0 +1,13 @@
// PROBLEM: none
// WITH_RUNTIME
fun main() {
val o = Foo("")
o.run {
val o2 = <caret>copy(prop = "New")
bar(o2)
}
}
data class Foo(val prop: String)
fun bar(foo: Foo) {}
@@ -14026,6 +14026,39 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
}
}
@TestMetadata("idea/testData/inspectionsLocal/unusedDataClassCopyResult")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class UnusedDataClassCopyResult extends AbstractLocalInspectionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInUnusedDataClassCopyResult() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/inspectionsLocal/unusedDataClassCopyResult"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true);
}
@TestMetadata("basic.kt")
public void testBasic() throws Exception {
runTest("idea/testData/inspectionsLocal/unusedDataClassCopyResult/basic.kt");
}
@TestMetadata("basic2.kt")
public void testBasic2() throws Exception {
runTest("idea/testData/inspectionsLocal/unusedDataClassCopyResult/basic2.kt");
}
@TestMetadata("used.kt")
public void testUsed() throws Exception {
runTest("idea/testData/inspectionsLocal/unusedDataClassCopyResult/used.kt");
}
@TestMetadata("used2.kt")
public void testUsed2() throws Exception {
runTest("idea/testData/inspectionsLocal/unusedDataClassCopyResult/used2.kt");
}
}
@TestMetadata("idea/testData/inspectionsLocal/unusedEquals")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)