Introduce "Delegate to 'var' property" inspection #KT-26724 Fixed

This commit is contained in:
Toshiaki Kameyama
2018-09-13 12:08:21 +03:00
committed by Mikhail Glukhikh
parent 17d740a373
commit 0fcd1a2072
12 changed files with 147 additions and 0 deletions
@@ -417,3 +417,12 @@ fun returnExpressionVisitor(block: (KtReturnExpression) -> Unit) =
block(returnExpression)
}
}
fun delegatedSuperTypeEntry(block: (KtDelegatedSuperTypeEntry) -> Unit) =
object : KtVisitorVoid() {
override fun visitDelegatedSuperTypeEntry(delegatedSuperTypeEntry: KtDelegatedSuperTypeEntry) {
super.visitDelegatedSuperTypeEntry(delegatedSuperTypeEntry)
block(delegatedSuperTypeEntry)
}
}
@@ -0,0 +1,6 @@
<html>
<body>
This inspection reports delegation to <b>var</b> property.
In fact, only starting value of <b>var</b> property is used for delegation so it's not recommended to do so.
</body>
</html>
+9
View File
@@ -3084,6 +3084,15 @@
language="kotlin"
/>
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.DelegationToVarPropertyInspection"
displayName="Delegating to 'var' property"
groupPath="Kotlin"
groupName="Probable bugs"
enabledByDefault="true"
level="WARNING"
language="kotlin"
/>
<referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/>
<fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.*
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.idea.quickfix.ChangeVariableMutabilityFix
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.delegatedSuperTypeEntry
class DelegationToVarPropertyInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) =
delegatedSuperTypeEntry(fun(delegatedSuperTypeEntry) {
val parameter = delegatedSuperTypeEntry.delegateExpression?.mainReference?.resolve() as? KtParameter ?: return
if (parameter.valOrVarKeyword?.node?.elementType != KtTokens.VAR_KEYWORD) return
holder.registerProblem(
parameter,
"Delegating to 'var' property does not take its changes into account",
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
IntentionWrapper(ChangeVariableMutabilityFix(parameter, false), parameter.containingFile),
RemoveVarKeyword()
)
})
}
private class RemoveVarKeyword : LocalQuickFix {
override fun getName() = "Remove var"
override fun getFamilyName() = name
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
(descriptor.psiElement as? KtParameter)?.valOrVarKeyword?.delete()
}
}
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.inspections.DelegationToVarPropertyInspection
@@ -0,0 +1,9 @@
// PROBLEM: none
interface A {
fun foo()
}
class B : A {
override fun foo() {
}
}
class C(<caret>b: B) : A by b
@@ -0,0 +1,8 @@
// PROBLEM: none
interface A {
fun foo()
}
class B : A {
override fun foo() {}
}
class C(<caret>val b: B) : A by b
@@ -0,0 +1,8 @@
// FIX: Change to val
interface A {
fun foo()
}
class B : A {
override fun foo() {}
}
class C(<caret>var b: B) : A by b
@@ -0,0 +1,8 @@
// FIX: Change to val
interface A {
fun foo()
}
class B : A {
override fun foo() {}
}
class C(val b: B) : A by b
@@ -0,0 +1,8 @@
// FIX: Remove var
interface A {
fun foo()
}
class B : A {
override fun foo() {}
}
class C(var b: B<caret>) : A by b
@@ -0,0 +1,8 @@
// FIX: Remove var
interface A {
fun foo()
}
class B : A {
override fun foo() {}
}
class C(b: B) : A by b
@@ -2115,6 +2115,39 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
}
}
@TestMetadata("idea/testData/inspectionsLocal/delegationToVarProperty")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DelegationToVarProperty extends AbstractLocalInspectionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInDelegationToVarProperty() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/delegationToVarProperty"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
}
@TestMetadata("parameter.kt")
public void testParameter() throws Exception {
runTest("idea/testData/inspectionsLocal/delegationToVarProperty/parameter.kt");
}
@TestMetadata("valParameter.kt")
public void testValParameter() throws Exception {
runTest("idea/testData/inspectionsLocal/delegationToVarProperty/valParameter.kt");
}
@TestMetadata("varParameter.kt")
public void testVarParameter() throws Exception {
runTest("idea/testData/inspectionsLocal/delegationToVarProperty/varParameter.kt");
}
@TestMetadata("varParameter2.kt")
public void testVarParameter2() throws Exception {
runTest("idea/testData/inspectionsLocal/delegationToVarProperty/varParameter2.kt");
}
}
@TestMetadata("idea/testData/inspectionsLocal/deprecatedCallableAddReplaceWith")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)