From cb5d04d3fbdf12e3f2a69362cef062c03508d45d Mon Sep 17 00:00:00 2001 From: kentr0w Date: Mon, 26 Oct 2020 16:07:29 +0300 Subject: [PATCH 01/11] rule 6.1.5 ### What's done: Implemented rule 6.1.5 --- diktat-analysis.yml | 4 ++ .../src/main/kotlin/generated/WarningNames.kt | 2 + .../cqfn/diktat/ruleset/constants/Warnings.kt | 1 + .../ruleset/rules/DiktatRuleSetProvider.kt | 1 + .../diktat/ruleset/rules/UselessOverride.kt | 63 +++++++++++++++++++ .../main/resources/diktat-analysis-huawei.yml | 4 ++ .../src/main/resources/diktat-analysis.yml | 4 ++ .../chapter6/UselessOverrideFixTest.kt | 16 +++++ .../chapter6/UselessOverrideWarnTest.kt | 61 ++++++++++++++++++ .../UselessOverrideExpected.kt | 23 +++++++ .../useless-override/UselessOverrideTest.kt | 37 +++++++++++ info/available-rules.md | 3 +- 12 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt create mode 100644 diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideFixTest.kt create mode 100644 diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideWarnTest.kt create mode 100644 diktat-rules/src/test/resources/test/paragraph6/useless-override/UselessOverrideExpected.kt create mode 100644 diktat-rules/src/test/resources/test/paragraph6/useless-override/UselessOverrideTest.kt diff --git a/diktat-analysis.yml b/diktat-analysis.yml index b6e7b717df..63d1c9809c 100644 --- a/diktat-analysis.yml +++ b/diktat-analysis.yml @@ -331,5 +331,9 @@ configuration: {} # Checks that never use the name of a variable in the custom getter or setter - name: WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR + enabled: true + configuration: {} +# Checks that override function is useful +- name: USELESS_OVERRIDE enabled: true configuration: {} \ No newline at end of file diff --git a/diktat-rules/src/main/kotlin/generated/WarningNames.kt b/diktat-rules/src/main/kotlin/generated/WarningNames.kt index 1ca16e251a..3e224a16e2 100644 --- a/diktat-rules/src/main/kotlin/generated/WarningNames.kt +++ b/diktat-rules/src/main/kotlin/generated/WarningNames.kt @@ -196,4 +196,6 @@ public object WarningNames { public const val WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR: String = "WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR" + + public const val USELESS_OVERRIDE: String = "USELESS_OVERRIDE" } diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/Warnings.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/Warnings.kt index 22ca2beaea..239c234516 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/Warnings.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/Warnings.kt @@ -119,6 +119,7 @@ enum class Warnings(private val canBeAutoCorrected: Boolean, private val warn: S // ======== chapter 6 ======== USE_DATA_CLASS(false, "this class can be converted to a data class"), WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR(false, "Use `field` keyword instead of property name inside property accessors"), + USELESS_OVERRIDE(true,"override method doesn't differ from super"), ; /** diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt index 7aef04bfb9..5b65460061 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt @@ -55,6 +55,7 @@ class DiktatRuleSetProvider(private val diktatConfigFile: String = "diktat-analy ::FileSize, ::DataClassesRule, ::IdentifierNaming, + ::UselessOverride, ::LocalVariablesRule, ::ClassLikeStructuresOrderRule, ::BracesInConditionalsAndLoopsRule, diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt new file mode 100644 index 0000000000..eaaf07e174 --- /dev/null +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt @@ -0,0 +1,63 @@ +package org.cqfn.diktat.ruleset.rules + +import com.pinterest.ktlint.core.Rule +import com.pinterest.ktlint.core.ast.ElementType.BLOCK +import com.pinterest.ktlint.core.ast.ElementType.BLOCK_COMMENT +import com.pinterest.ktlint.core.ast.ElementType.DOT_QUALIFIED_EXPRESSION +import com.pinterest.ktlint.core.ast.ElementType.EOL_COMMENT +import com.pinterest.ktlint.core.ast.ElementType.EQ +import com.pinterest.ktlint.core.ast.ElementType.FUN +import com.pinterest.ktlint.core.ast.ElementType.IDENTIFIER +import com.pinterest.ktlint.core.ast.ElementType.KDOC +import com.pinterest.ktlint.core.ast.ElementType.LBRACE +import com.pinterest.ktlint.core.ast.ElementType.MODIFIER_LIST +import com.pinterest.ktlint.core.ast.ElementType.OVERRIDE_KEYWORD +import com.pinterest.ktlint.core.ast.ElementType.RBRACE +import com.pinterest.ktlint.core.ast.ElementType.SUPER_EXPRESSION +import com.pinterest.ktlint.core.ast.ElementType.WHITE_SPACE +import org.cqfn.diktat.common.config.rules.RulesConfig +import org.cqfn.diktat.ruleset.constants.Warnings.USELESS_OVERRIDE +import org.jetbrains.kotlin.com.intellij.lang.ASTNode +import org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet +import org.jetbrains.kotlin.psi.psiUtil.siblings + +/** + * rule 6.1.5 + * Explicit supertype qualification should not be used if there is not clash between called methods + */ +class UselessOverride(private val configRules: List) : Rule("useless-override") { + + companion object { + private val USELESS_CHILDREN_OVERRIDE_FUNCTION = listOf(WHITE_SPACE, LBRACE, + RBRACE, DOT_QUALIFIED_EXPRESSION, KDOC, EOL_COMMENT, BLOCK_COMMENT) + } + + private lateinit var emitWarn: ((offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) + private var isFixMode: Boolean = false + + override fun visit(node: ASTNode, + autoCorrect: Boolean, + emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) { + emitWarn = emit + isFixMode = autoCorrect + + if(node.elementType == FUN) + checkFun(node) + } + + private fun checkFun(node: ASTNode) { + if (node.getChildren(TokenSet.create(MODIFIER_LIST)).any { it.elementType == OVERRIDE_KEYWORD }) + return + val functionBody = (node.findChildByType(BLOCK)?.getChildren(null)?.toList() ?: node.findChildByType(EQ)!!.siblings(true).toList()) + if (USELESS_CHILDREN_OVERRIDE_FUNCTION.containsAll(functionBody.map { it.elementType })) { + if (functionBody.find { it.elementType == DOT_QUALIFIED_EXPRESSION }?.findChildByType(SUPER_EXPRESSION) != null) { + USELESS_OVERRIDE.warnAndFix(configRules, emitWarn, isFixMode, node.findChildByType(IDENTIFIER)!!.text, node.startOffset, node) { + val parentNode = node.treeParent + if (node.treeNext != null && node.treeNext.elementType == WHITE_SPACE) + parentNode.removeChild(node.treeNext) + parentNode.removeChild(node) + } + } + } + } +} \ No newline at end of file diff --git a/diktat-rules/src/main/resources/diktat-analysis-huawei.yml b/diktat-rules/src/main/resources/diktat-analysis-huawei.yml index 19a9c80ed5..13978ad195 100644 --- a/diktat-rules/src/main/resources/diktat-analysis-huawei.yml +++ b/diktat-rules/src/main/resources/diktat-analysis-huawei.yml @@ -330,5 +330,9 @@ configuration: {} # Checks that never use the name of a variable in the custom getter or setter - name: WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR + enabled: true + configuration: {} +# Checks that override function is useful +- name: USELESS_OVERRIDE enabled: true configuration: {} \ No newline at end of file diff --git a/diktat-rules/src/main/resources/diktat-analysis.yml b/diktat-rules/src/main/resources/diktat-analysis.yml index b314f395c2..3b1d7e5eef 100644 --- a/diktat-rules/src/main/resources/diktat-analysis.yml +++ b/diktat-rules/src/main/resources/diktat-analysis.yml @@ -332,5 +332,9 @@ configuration: {} # Checks that never use the name of a variable in the custom getter or setter - name: WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR + enabled: true + configuration: {} +# Checks that override function is useful +- name: USELESS_OVERRIDE enabled: true configuration: {} \ No newline at end of file diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideFixTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideFixTest.kt new file mode 100644 index 0000000000..6cb32baee1 --- /dev/null +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideFixTest.kt @@ -0,0 +1,16 @@ +package org.cqfn.diktat.ruleset.chapter6 + +import generated.WarningNames +import org.cqfn.diktat.util.FixTestBase +import org.cqfn.diktat.ruleset.rules.UselessOverride +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Test + +class UselessOverrideFixTest : FixTestBase("test/paragraph6/useless-override", ::UselessOverride) { + + @Test + @Tag(WarningNames.USELESS_OVERRIDE) + fun `fix nested functions`() { + fixAndCompare("UselessOverrideExpected.kt", "UselessOverrideTest.kt") + } +} \ No newline at end of file diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideWarnTest.kt new file mode 100644 index 0000000000..a426ee4ab2 --- /dev/null +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideWarnTest.kt @@ -0,0 +1,61 @@ +package org.cqfn.diktat.ruleset.chapter6 + +import com.pinterest.ktlint.core.LintError +import generated.WarningNames +import org.cqfn.diktat.ruleset.constants.Warnings.USELESS_OVERRIDE +import org.cqfn.diktat.ruleset.rules.DIKTAT_RULE_SET_ID +import org.cqfn.diktat.ruleset.rules.UselessOverride +import org.cqfn.diktat.util.LintTestBase +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Test + +class UselessOverrideWarnTest: LintTestBase(::UselessOverride) { + + private val ruleId = "$DIKTAT_RULE_SET_ID:useless-override" + + @Test + @Tag(WarningNames.USELESS_OVERRIDE) + fun `check simple wrong examples`() { + lintMethod( + """ + open class Rectangle { + open fun draw() { /* ... */ } + } + + class Square() : Rectangle() { + override fun draw() { + /** + * + * hehe + */ + super.draw() + } + } + + class Square2() : Rectangle() { + override fun draw() { + //hehe + /* + hehe + */ + super.draw() + } + } + + class Square2() : Rectangle() { + override fun draw() { + val q = super.draw() + } + } + + class A: Runnable { + override fun run() { + + } + } + """.trimMargin(), + LintError(6,25, ruleId, "${USELESS_OVERRIDE.warnText()} draw", true), + LintError(16,25, ruleId, "${USELESS_OVERRIDE.warnText()} draw", true) + ) + } +} diff --git a/diktat-rules/src/test/resources/test/paragraph6/useless-override/UselessOverrideExpected.kt b/diktat-rules/src/test/resources/test/paragraph6/useless-override/UselessOverrideExpected.kt new file mode 100644 index 0000000000..b44b2bb5ac --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph6/useless-override/UselessOverrideExpected.kt @@ -0,0 +1,23 @@ +package test.paragraph6 + +open class Rectangle { + open fun draw() { /* ... */ } +} + +class Square() : Rectangle() { + } + +class Square2() : Rectangle() { + } + +class Square2() : Rectangle() { + override fun draw() { + val q = super.draw() + } +} + +class A: Runnable { + override fun run() { + + } +} diff --git a/diktat-rules/src/test/resources/test/paragraph6/useless-override/UselessOverrideTest.kt b/diktat-rules/src/test/resources/test/paragraph6/useless-override/UselessOverrideTest.kt new file mode 100644 index 0000000000..679a641295 --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph6/useless-override/UselessOverrideTest.kt @@ -0,0 +1,37 @@ +package test.paragraph6 + +open class Rectangle { + open fun draw() { /* ... */ } +} + +class Square() : Rectangle() { + override fun draw() { + /** + * + * hehe + */ + super.draw() + } +} + +class Square2() : Rectangle() { + override fun draw() { + //hehe + /* + hehe + */ + super.draw() + } +} + +class Square2() : Rectangle() { + override fun draw() { + val q = super.draw() + } +} + +class A: Runnable { + override fun run() { + + } +} diff --git a/info/available-rules.md b/info/available-rules.md index 0ce1e8cdcd..22e605436a 100644 --- a/info/available-rules.md +++ b/info/available-rules.md @@ -91,5 +91,6 @@ | 5 | 5.2.1 | LAMBDA_IS_NOT_LAST_PARAMETER | Checks that lambda inside function parameters isn't in the end | no | - | | 5 | 5.2.2 | TOO_MANY_PARAMETERS | Check: if function contains more parameters than allowed | no | maxParameterListSize | | 5 | 5.2.3 | WRONG_OVERLOADING_FUNCTION_ARGUMENTS | Check: function has overloading instead use default arguments | no | -| -| 6 | 6.1.2 | USE_DATA_CLASS | Check: if class can be made as data class | no | - | yes | +| 6 | 6.1.2 | USE_DATA_CLASS | Check: if class can be made as data class | no | - | yes |\ +| 6 | 6.1.5 | USELESS_OVERRIDE | Check: if override function can be removed | yes| - | | | 6 | 6.1.9 | WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR | Check: used the name of a variable in the custom getter or setter | no | - | \ No newline at end of file From 9e6e47d762590439b315fa0894bd644973fa6f9c Mon Sep 17 00:00:00 2001 From: kentr0w Date: Mon, 26 Oct 2020 16:12:09 +0300 Subject: [PATCH 02/11] rule 6.1.5 ### What's done: Added empty line --- .../kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt index eaaf07e174..c1f6c6df56 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt @@ -60,4 +60,4 @@ class UselessOverride(private val configRules: List) : Rule("useles } } } -} \ No newline at end of file +} From cba7548e73e80239a99f4481c8571c62a382ad04 Mon Sep 17 00:00:00 2001 From: kentr0w Date: Mon, 26 Oct 2020 16:12:37 +0300 Subject: [PATCH 03/11] rule 6.1.5 ### What's done: Added empty line --- .../org/cqfn/diktat/ruleset/chapter6/UselessOverrideFixTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideFixTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideFixTest.kt index 6cb32baee1..58bb7b244e 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideFixTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideFixTest.kt @@ -13,4 +13,4 @@ class UselessOverrideFixTest : FixTestBase("test/paragraph6/useless-override", : fun `fix nested functions`() { fixAndCompare("UselessOverrideExpected.kt", "UselessOverrideTest.kt") } -} \ No newline at end of file +} From aa3c00268393a68e1f1c117974a1c9e819225057 Mon Sep 17 00:00:00 2001 From: kentr0w Date: Mon, 26 Oct 2020 16:19:26 +0300 Subject: [PATCH 04/11] rule 6.1.5 ### What's done: added suppress --- .../main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt index c1f6c6df56..dd9c30e4fa 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt @@ -45,6 +45,7 @@ class UselessOverride(private val configRules: List) : Rule("useles checkFun(node) } + @Suppress("UnsafeCallOnNullableType") private fun checkFun(node: ASTNode) { if (node.getChildren(TokenSet.create(MODIFIER_LIST)).any { it.elementType == OVERRIDE_KEYWORD }) return From 75450ad3f634c96e79959f40144c0bb77dafbbd1 Mon Sep 17 00:00:00 2001 From: kentr0w Date: Fri, 30 Oct 2020 02:48:16 +0300 Subject: [PATCH 05/11] rule 6.1.5 ### What's done: Changed rule's logic. --- .../diktat/ruleset/rules/UselessOverride.kt | 106 +++++++++++++----- .../chapter6/UselessOverrideFixTest.kt | 6 + .../chapter6/UselessOverrideWarnTest.kt | 23 ++++ .../SeveravalSyperTypesExpected.kt | 28 +++++ .../SeveravalSyperTypesTest.kt | 28 +++++ 5 files changed, 162 insertions(+), 29 deletions(-) create mode 100644 diktat-rules/src/test/resources/test/paragraph6/useless-override/SeveravalSyperTypesExpected.kt create mode 100644 diktat-rules/src/test/resources/test/paragraph6/useless-override/SeveravalSyperTypesTest.kt diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt index dd9c30e4fa..300ab2483f 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt @@ -1,24 +1,25 @@ package org.cqfn.diktat.ruleset.rules import com.pinterest.ktlint.core.Rule -import com.pinterest.ktlint.core.ast.ElementType.BLOCK -import com.pinterest.ktlint.core.ast.ElementType.BLOCK_COMMENT +import com.pinterest.ktlint.core.ast.ElementType.CALL_EXPRESSION +import com.pinterest.ktlint.core.ast.ElementType.CLASS +import com.pinterest.ktlint.core.ast.ElementType.CLASS_BODY +import com.pinterest.ktlint.core.ast.ElementType.CLASS_KEYWORD import com.pinterest.ktlint.core.ast.ElementType.DOT_QUALIFIED_EXPRESSION -import com.pinterest.ktlint.core.ast.ElementType.EOL_COMMENT -import com.pinterest.ktlint.core.ast.ElementType.EQ +import com.pinterest.ktlint.core.ast.ElementType.FILE import com.pinterest.ktlint.core.ast.ElementType.FUN import com.pinterest.ktlint.core.ast.ElementType.IDENTIFIER -import com.pinterest.ktlint.core.ast.ElementType.KDOC -import com.pinterest.ktlint.core.ast.ElementType.LBRACE -import com.pinterest.ktlint.core.ast.ElementType.MODIFIER_LIST -import com.pinterest.ktlint.core.ast.ElementType.OVERRIDE_KEYWORD -import com.pinterest.ktlint.core.ast.ElementType.RBRACE +import com.pinterest.ktlint.core.ast.ElementType.OPEN_KEYWORD +import com.pinterest.ktlint.core.ast.ElementType.REFERENCE_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.SUPER_EXPRESSION -import com.pinterest.ktlint.core.ast.ElementType.WHITE_SPACE +import com.pinterest.ktlint.core.ast.ElementType.SUPER_TYPE_CALL_ENTRY +import com.pinterest.ktlint.core.ast.ElementType.SUPER_TYPE_ENTRY +import com.pinterest.ktlint.core.ast.ElementType.TYPE_REFERENCE +import com.pinterest.ktlint.core.ast.parent import org.cqfn.diktat.common.config.rules.RulesConfig -import org.cqfn.diktat.ruleset.constants.Warnings.USELESS_OVERRIDE +import org.cqfn.diktat.ruleset.constants.Warnings.* +import org.cqfn.diktat.ruleset.utils.* import org.jetbrains.kotlin.com.intellij.lang.ASTNode -import org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet import org.jetbrains.kotlin.psi.psiUtil.siblings /** @@ -28,8 +29,7 @@ import org.jetbrains.kotlin.psi.psiUtil.siblings class UselessOverride(private val configRules: List) : Rule("useless-override") { companion object { - private val USELESS_CHILDREN_OVERRIDE_FUNCTION = listOf(WHITE_SPACE, LBRACE, - RBRACE, DOT_QUALIFIED_EXPRESSION, KDOC, EOL_COMMENT, BLOCK_COMMENT) + private val SUPER_TYPE = listOf(SUPER_TYPE_CALL_ENTRY, SUPER_TYPE_ENTRY) } private lateinit var emitWarn: ((offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) @@ -41,24 +41,72 @@ class UselessOverride(private val configRules: List) : Rule("useles emitWarn = emit isFixMode = autoCorrect - if(node.elementType == FUN) - checkFun(node) + if (node.elementType == CLASS) + checkClass(node) + } + + private fun checkClass(node: ASTNode) { + println(node.prettyPrint()) + val superNodes = node.findAllNodesWithCondition({ it.elementType in SUPER_TYPE }).ifEmpty { return } + val overrideNodes = node.findAllNodesWithSpecificType(DOT_QUALIFIED_EXPRESSION) + .mapNotNull { findFunWithSuper(it) }.ifEmpty { return } + if (superNodes.size == 1) + overrideNodes.map { removeSupertype(it.first) } + else + handleManyImpl(superNodes, overrideNodes) + } + + private fun handleManyImpl(superNodes: List, overrideNodes: List>) { + val q = findAllSupers(superNodes, overrideNodes.map { it.second.text })?.filter { it.value == 1 }?.map { it.key } ?: return + overrideNodes.filter { + it.second.text in q + }.map { + removeSupertype(it.first) + } } @Suppress("UnsafeCallOnNullableType") - private fun checkFun(node: ASTNode) { - if (node.getChildren(TokenSet.create(MODIFIER_LIST)).any { it.elementType == OVERRIDE_KEYWORD }) - return - val functionBody = (node.findChildByType(BLOCK)?.getChildren(null)?.toList() ?: node.findChildByType(EQ)!!.siblings(true).toList()) - if (USELESS_CHILDREN_OVERRIDE_FUNCTION.containsAll(functionBody.map { it.elementType })) { - if (functionBody.find { it.elementType == DOT_QUALIFIED_EXPRESSION }?.findChildByType(SUPER_EXPRESSION) != null) { - USELESS_OVERRIDE.warnAndFix(configRules, emitWarn, isFixMode, node.findChildByType(IDENTIFIER)!!.text, node.startOffset, node) { - val parentNode = node.treeParent - if (node.treeNext != null && node.treeNext.elementType == WHITE_SPACE) - parentNode.removeChild(node.treeNext) - parentNode.removeChild(node) - } + private fun removeSupertype(node: ASTNode) { + USELESS_OVERRIDE.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) { + val startNode = node.parent({ it.elementType == SUPER_EXPRESSION })!!.findChildByType(REFERENCE_EXPRESSION)!! + val lastNode = startNode.siblings(true).last() + startNode.treeParent.removeRange(startNode.treeNext, lastNode) + startNode.treeParent.removeChild(lastNode) + } + } + + @Suppress("UnsafeCallOnNullableType") + private fun findFunWithSuper(node: ASTNode): Pair? { + return Pair( + node.findChildByType(SUPER_EXPRESSION) + ?.findChildByType(TYPE_REFERENCE) + ?.findAllNodesWithSpecificType(IDENTIFIER) + ?.first() ?: return null, + node.findChildByType(CALL_EXPRESSION) + ?.findAllNodesWithSpecificType(IDENTIFIER) + ?.first() ?: return null) + } + + private fun findAllSupers(superTypeList: List, methodsName: List): MutableMap? { + val fileNode = superTypeList.first().parent({ it.elementType == FILE })!! + val superNodesIdentifier = superTypeList.map { it.findAllNodesWithSpecificType(IDENTIFIER).first().text } + val superNodes = fileNode.findAllNodesWithCondition({ superClass -> + superClass.elementType == CLASS && + superClass.getIdentifierName()!!.text in superNodesIdentifier + }).mapNotNull { it.findChildByType(CLASS_BODY) } + if (superNodes.size != superTypeList.size) + return null + val functionNameResult = mutableMapOf() + superNodes.forEach { classBody -> + val overrideFunctions = classBody.findAllNodesWithSpecificType(FUN) + .filter { + (if (classBody.treeParent.hasChildOfType(CLASS_KEYWORD)) it.hasChildOfType(OPEN_KEYWORD) else true) && + it.getIdentifierName()!!.text in methodsName + } + overrideFunctions.forEach { + functionNameResult[it.getIdentifierName()!!.text]?.plus(1) ?: functionNameResult.put(it.getIdentifierName()!!.text, 1) } } + return functionNameResult } -} +} \ No newline at end of file diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideFixTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideFixTest.kt index 58bb7b244e..69fab6489a 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideFixTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideFixTest.kt @@ -13,4 +13,10 @@ class UselessOverrideFixTest : FixTestBase("test/paragraph6/useless-override", : fun `fix nested functions`() { fixAndCompare("UselessOverrideExpected.kt", "UselessOverrideTest.kt") } + + @Test + @Tag(WarningNames.USELESS_OVERRIDE) + fun `fix nestedd functions`() { + fixAndCompare("SeveravalSyperTypesExpected.kt", "SeveravalSyperTypesTest.kt") + } } diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideWarnTest.kt index a426ee4ab2..583cb6d020 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideWarnTest.kt @@ -58,4 +58,27 @@ class UselessOverrideWarnTest: LintTestBase(::UselessOverride) { LintError(16,25, ruleId, "${USELESS_OVERRIDE.warnText()} draw", true) ) } + + @Test + @Tag(WarningNames.USELESS_OVERRIDE) + fun `check simple wronfg examples`() { + lintMethod( + """ + open class Rectangle { + open fun draw() { /* ... */ } + } + + class Square2() : Rectangle(), Keke { + override fun draw() { + super.draw() + super.draw() + } + + private fun goo() {} + + private fun goo() {} + } + """.trimMargin() + ) + } } diff --git a/diktat-rules/src/test/resources/test/paragraph6/useless-override/SeveravalSyperTypesExpected.kt b/diktat-rules/src/test/resources/test/paragraph6/useless-override/SeveravalSyperTypesExpected.kt new file mode 100644 index 0000000000..d6a17c35b0 --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph6/useless-override/SeveravalSyperTypesExpected.kt @@ -0,0 +1,28 @@ +package test.paragraph6.`useless-override` + +open class A { + open fun foo(){} +} + +interface C { + fun foo(){} + fun goo(){} +} + +class B: A(){ + override fun foo() { + super.foo() + } +} + +class D: A(), C { + override fun foo() { + super.foo() + super.foo() + super.goo() + } + + private fun qwe(){ + val q = super.goo() + } +} diff --git a/diktat-rules/src/test/resources/test/paragraph6/useless-override/SeveravalSyperTypesTest.kt b/diktat-rules/src/test/resources/test/paragraph6/useless-override/SeveravalSyperTypesTest.kt new file mode 100644 index 0000000000..da8d5501a4 --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph6/useless-override/SeveravalSyperTypesTest.kt @@ -0,0 +1,28 @@ +package test.paragraph6.`useless-override` + +open class A { + open fun foo(){} +} + +interface C { + fun foo(){} + fun goo(){} +} + +class B: A(){ + override fun foo() { + super.foo() + } +} + +class D: A(), C { + override fun foo() { + super.foo() + super.foo() + super.goo() + } + + private fun qwe(){ + val q = super.goo() + } +} From b796ffb761f4918c30b0579cfba79567e87f3d73 Mon Sep 17 00:00:00 2001 From: kentr0w Date: Fri, 30 Oct 2020 12:29:34 +0300 Subject: [PATCH 06/11] rule 6.1.5 ### What's done: Changed rule's logic. --- .../ruleset/rules/DiktatRuleSetProvider.kt | 2 +- ...UselessOverride.kt => UselessSupertype.kt} | 51 ++++++++++++++----- ...eFixTest.kt => UselessSupertypeFixTest.kt} | 10 ++-- ...arnTest.kt => UselessSupertypeWarnTest.kt} | 31 ++++++----- ...pected.kt => SeveralSuperTypesExpected.kt} | 0 ...rTypesTest.kt => SeveralSuperTypesTest.kt} | 0 .../UselessOverrideExpected.kt | 14 +++++ 7 files changed, 76 insertions(+), 32 deletions(-) rename diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/{UselessOverride.kt => UselessSupertype.kt} (71%) rename diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/{UselessOverrideFixTest.kt => UselessSupertypeFixTest.kt} (54%) rename diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/{UselessOverrideWarnTest.kt => UselessSupertypeWarnTest.kt} (71%) rename diktat-rules/src/test/resources/test/paragraph6/useless-override/{SeveravalSyperTypesExpected.kt => SeveralSuperTypesExpected.kt} (100%) rename diktat-rules/src/test/resources/test/paragraph6/useless-override/{SeveravalSyperTypesTest.kt => SeveralSuperTypesTest.kt} (100%) diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt index 5b65460061..31d4712437 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt @@ -55,7 +55,7 @@ class DiktatRuleSetProvider(private val diktatConfigFile: String = "diktat-analy ::FileSize, ::DataClassesRule, ::IdentifierNaming, - ::UselessOverride, + ::UselessSupertype, ::LocalVariablesRule, ::ClassLikeStructuresOrderRule, ::BracesInConditionalsAndLoopsRule, diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessSupertype.kt similarity index 71% rename from diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt rename to diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessSupertype.kt index 300ab2483f..da437176d5 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessOverride.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessSupertype.kt @@ -9,6 +9,7 @@ import com.pinterest.ktlint.core.ast.ElementType.DOT_QUALIFIED_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.FILE import com.pinterest.ktlint.core.ast.ElementType.FUN import com.pinterest.ktlint.core.ast.ElementType.IDENTIFIER +import com.pinterest.ktlint.core.ast.ElementType.MODIFIER_LIST import com.pinterest.ktlint.core.ast.ElementType.OPEN_KEYWORD import com.pinterest.ktlint.core.ast.ElementType.REFERENCE_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.SUPER_EXPRESSION @@ -17,7 +18,7 @@ import com.pinterest.ktlint.core.ast.ElementType.SUPER_TYPE_ENTRY import com.pinterest.ktlint.core.ast.ElementType.TYPE_REFERENCE import com.pinterest.ktlint.core.ast.parent import org.cqfn.diktat.common.config.rules.RulesConfig -import org.cqfn.diktat.ruleset.constants.Warnings.* +import org.cqfn.diktat.ruleset.constants.Warnings.USELESS_OVERRIDE import org.cqfn.diktat.ruleset.utils.* import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.psi.psiUtil.siblings @@ -26,7 +27,7 @@ import org.jetbrains.kotlin.psi.psiUtil.siblings * rule 6.1.5 * Explicit supertype qualification should not be used if there is not clash between called methods */ -class UselessOverride(private val configRules: List) : Rule("useless-override") { +class UselessSupertype(private val configRules: List) : Rule("useless-override") { companion object { private val SUPER_TYPE = listOf(SUPER_TYPE_CALL_ENTRY, SUPER_TYPE_ENTRY) @@ -46,7 +47,6 @@ class UselessOverride(private val configRules: List) : Rule("useles } private fun checkClass(node: ASTNode) { - println(node.prettyPrint()) val superNodes = node.findAllNodesWithCondition({ it.elementType in SUPER_TYPE }).ifEmpty { return } val overrideNodes = node.findAllNodesWithSpecificType(DOT_QUALIFIED_EXPRESSION) .mapNotNull { findFunWithSuper(it) }.ifEmpty { return } @@ -57,12 +57,14 @@ class UselessOverride(private val configRules: List) : Rule("useles } private fun handleManyImpl(superNodes: List, overrideNodes: List>) { - val q = findAllSupers(superNodes, overrideNodes.map { it.second.text })?.filter { it.value == 1 }?.map { it.key } ?: return - overrideNodes.filter { - it.second.text in q - }.map { - removeSupertype(it.first) - } + val uselessSuperType = findAllSupers(superNodes, overrideNodes.map { it.second.text })?.filter { it.value == 1 }?.map { it.key } + ?: return + overrideNodes + .filter { + it.second.text in uselessSuperType + }.map { + removeSupertype(it.first) + } } @Suppress("UnsafeCallOnNullableType") @@ -75,6 +77,14 @@ class UselessOverride(private val configRules: List) : Rule("useles } } + /** + * Method finds pair of identifier supertype and method name else return null + * example: super.foo() -> return Pair(A, foo) + * super.foo() -> null + * @param node - node of type DOT_QUALIFIED_EXPRESSION + * + * @return pair of identifier + */ @Suppress("UnsafeCallOnNullableType") private fun findFunWithSuper(node: ASTNode): Pair? { return Pair( @@ -87,6 +97,16 @@ class UselessOverride(private val configRules: List) : Rule("useles ?.first() ?: return null) } + /** + * The method looks in the same file for all super interfaces or a class, in each it looks for methods + * that can be overridden and creates a map with a key - the name of the method and value - the number of times it meets + * + * @param superTypeList - list of identifiers super classes + * @param methodsName - name of overrides methods + * + * @return map name of method and the number of times it meets + */ + @Suppress("UnsafeCallOnNullableType") private fun findAllSupers(superTypeList: List, methodsName: List): MutableMap? { val fileNode = superTypeList.first().parent({ it.elementType == FILE })!! val superNodesIdentifier = superTypeList.map { it.findAllNodesWithSpecificType(IDENTIFIER).first().text } @@ -96,17 +116,20 @@ class UselessOverride(private val configRules: List) : Rule("useles }).mapNotNull { it.findChildByType(CLASS_BODY) } if (superNodes.size != superTypeList.size) return null - val functionNameResult = mutableMapOf() + val functionNameMap = mutableMapOf() superNodes.forEach { classBody -> val overrideFunctions = classBody.findAllNodesWithSpecificType(FUN) .filter { - (if (classBody.treeParent.hasChildOfType(CLASS_KEYWORD)) it.hasChildOfType(OPEN_KEYWORD) else true) && + (if (classBody.treeParent.hasChildOfType(CLASS_KEYWORD)) it.findChildByType(MODIFIER_LIST)!!.hasChildOfType(OPEN_KEYWORD) else true) && it.getIdentifierName()!!.text in methodsName } overrideFunctions.forEach { - functionNameResult[it.getIdentifierName()!!.text]?.plus(1) ?: functionNameResult.put(it.getIdentifierName()!!.text, 1) + if (functionNameMap.containsKey(it.getIdentifierName()!!.text)) + functionNameMap[it.getIdentifierName()!!.text] = functionNameMap[it.getIdentifierName()!!.text]!! + 1 + else + functionNameMap[it.getIdentifierName()!!.text] = 1 } } - return functionNameResult + return functionNameMap } -} \ No newline at end of file +} diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideFixTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessSupertypeFixTest.kt similarity index 54% rename from diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideFixTest.kt rename to diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessSupertypeFixTest.kt index 69fab6489a..3f8d2fccff 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideFixTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessSupertypeFixTest.kt @@ -2,21 +2,21 @@ package org.cqfn.diktat.ruleset.chapter6 import generated.WarningNames import org.cqfn.diktat.util.FixTestBase -import org.cqfn.diktat.ruleset.rules.UselessOverride +import org.cqfn.diktat.ruleset.rules.UselessSupertype import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test -class UselessOverrideFixTest : FixTestBase("test/paragraph6/useless-override", ::UselessOverride) { +class UselessSupertypeFixTest : FixTestBase("test/paragraph6/useless-override", ::UselessSupertype) { @Test @Tag(WarningNames.USELESS_OVERRIDE) - fun `fix nested functions`() { + fun `fix example with one super`() { fixAndCompare("UselessOverrideExpected.kt", "UselessOverrideTest.kt") } @Test @Tag(WarningNames.USELESS_OVERRIDE) - fun `fix nestedd functions`() { - fixAndCompare("SeveravalSyperTypesExpected.kt", "SeveravalSyperTypesTest.kt") + fun `fix several super`() { + fixAndCompare("SeveralSuperTypesExpected.kt", "SeveralSuperTypesTest.kt") } } diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessSupertypeWarnTest.kt similarity index 71% rename from diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideWarnTest.kt rename to diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessSupertypeWarnTest.kt index 583cb6d020..7972462fb4 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessOverrideWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessSupertypeWarnTest.kt @@ -4,18 +4,18 @@ import com.pinterest.ktlint.core.LintError import generated.WarningNames import org.cqfn.diktat.ruleset.constants.Warnings.USELESS_OVERRIDE import org.cqfn.diktat.ruleset.rules.DIKTAT_RULE_SET_ID -import org.cqfn.diktat.ruleset.rules.UselessOverride +import org.cqfn.diktat.ruleset.rules.UselessSupertype import org.cqfn.diktat.util.LintTestBase import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test -class UselessOverrideWarnTest: LintTestBase(::UselessOverride) { +class UselessSupertypeWarnTest: LintTestBase(::UselessSupertype) { private val ruleId = "$DIKTAT_RULE_SET_ID:useless-override" @Test @Tag(WarningNames.USELESS_OVERRIDE) - fun `check simple wrong examples`() { + fun `check simple wrong example`() { lintMethod( """ open class Rectangle { @@ -54,31 +54,38 @@ class UselessOverrideWarnTest: LintTestBase(::UselessOverride) { } } """.trimMargin(), - LintError(6,25, ruleId, "${USELESS_OVERRIDE.warnText()} draw", true), - LintError(16,25, ruleId, "${USELESS_OVERRIDE.warnText()} draw", true) + LintError(11,35, ruleId, "${USELESS_OVERRIDE.warnText()} Rectangle", true), + LintError(21,35, ruleId, "${USELESS_OVERRIDE.warnText()} Rectangle", true) ) } @Test @Tag(WarningNames.USELESS_OVERRIDE) - fun `check simple wronfg examples`() { + fun `check example with two super`() { lintMethod( """ open class Rectangle { open fun draw() { /* ... */ } } - class Square2() : Rectangle(), Keke { + interface KK { + fun draw() {} + fun kk() {} + } + + class Square2() : Rectangle(), KK { override fun draw() { super.draw() - super.draw() + super.draw() } - private fun goo() {} - - private fun goo() {} + private fun goo() { + super.kk() + } + } - """.trimMargin() + """.trimMargin(), + LintError(17,35, ruleId, "${USELESS_OVERRIDE.warnText()} KK", true) ) } } diff --git a/diktat-rules/src/test/resources/test/paragraph6/useless-override/SeveravalSyperTypesExpected.kt b/diktat-rules/src/test/resources/test/paragraph6/useless-override/SeveralSuperTypesExpected.kt similarity index 100% rename from diktat-rules/src/test/resources/test/paragraph6/useless-override/SeveravalSyperTypesExpected.kt rename to diktat-rules/src/test/resources/test/paragraph6/useless-override/SeveralSuperTypesExpected.kt diff --git a/diktat-rules/src/test/resources/test/paragraph6/useless-override/SeveravalSyperTypesTest.kt b/diktat-rules/src/test/resources/test/paragraph6/useless-override/SeveralSuperTypesTest.kt similarity index 100% rename from diktat-rules/src/test/resources/test/paragraph6/useless-override/SeveravalSyperTypesTest.kt rename to diktat-rules/src/test/resources/test/paragraph6/useless-override/SeveralSuperTypesTest.kt diff --git a/diktat-rules/src/test/resources/test/paragraph6/useless-override/UselessOverrideExpected.kt b/diktat-rules/src/test/resources/test/paragraph6/useless-override/UselessOverrideExpected.kt index b44b2bb5ac..5d50b2da29 100644 --- a/diktat-rules/src/test/resources/test/paragraph6/useless-override/UselessOverrideExpected.kt +++ b/diktat-rules/src/test/resources/test/paragraph6/useless-override/UselessOverrideExpected.kt @@ -5,10 +5,24 @@ open class Rectangle { } class Square() : Rectangle() { + override fun draw() { + /** + * + * hehe + */ + super.draw() } +} class Square2() : Rectangle() { + override fun draw() { + //hehe + /* + hehe + */ + super.draw() } +} class Square2() : Rectangle() { override fun draw() { From 23c1e02e9e25a689cdc94ffe896cfaa0b00bec33 Mon Sep 17 00:00:00 2001 From: kentr0w Date: Fri, 30 Oct 2020 23:11:37 +0300 Subject: [PATCH 07/11] Rule 6.1.5 ### What's done: Fixed after review --- .../cqfn/diktat/ruleset/constants/Warnings.kt | 2 +- .../diktat/ruleset/rules/UselessSupertype.kt | 32 +++++++++++-------- .../chapter6/UselessSupertypeWarnTest.kt | 8 ++--- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/Warnings.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/Warnings.kt index 6ed9431902..5c6ff4f368 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/Warnings.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/constants/Warnings.kt @@ -121,7 +121,7 @@ enum class Warnings(private val canBeAutoCorrected: Boolean, private val warn: S WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR(false, "Use `field` keyword instead of property name inside property accessors"), MULTIPLE_INIT_BLOCKS(true, "Avoid using multiple `init` blocks, this logic can be moved to constructors or properties declarations"), CLASS_SHOULD_NOT_BE_ABSTRACT(true, "class should not be abstract, because it has no abstract functions"), - USELESS_OVERRIDE(true,"override method doesn't differ from super"), + USELESS_SUPERTYPE(true,"unnecessary supertype specification"), ; /** diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessSupertype.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessSupertype.kt index da437176d5..371b8d422b 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessSupertype.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessSupertype.kt @@ -15,10 +15,11 @@ import com.pinterest.ktlint.core.ast.ElementType.REFERENCE_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.SUPER_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.SUPER_TYPE_CALL_ENTRY import com.pinterest.ktlint.core.ast.ElementType.SUPER_TYPE_ENTRY +import com.pinterest.ktlint.core.ast.ElementType.SUPER_TYPE_LIST import com.pinterest.ktlint.core.ast.ElementType.TYPE_REFERENCE import com.pinterest.ktlint.core.ast.parent import org.cqfn.diktat.common.config.rules.RulesConfig -import org.cqfn.diktat.ruleset.constants.Warnings.USELESS_OVERRIDE +import org.cqfn.diktat.ruleset.constants.Warnings.USELESS_SUPERTYPE import org.cqfn.diktat.ruleset.utils.* import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.psi.psiUtil.siblings @@ -26,6 +27,7 @@ import org.jetbrains.kotlin.psi.psiUtil.siblings /** * rule 6.1.5 * Explicit supertype qualification should not be used if there is not clash between called methods + * fixme can't fix supertypes that are defined in other files. */ class UselessSupertype(private val configRules: List) : Rule("useless-override") { @@ -47,13 +49,14 @@ class UselessSupertype(private val configRules: List) : Rule("usele } private fun checkClass(node: ASTNode) { - val superNodes = node.findAllNodesWithCondition({ it.elementType in SUPER_TYPE }).ifEmpty { return } - val overrideNodes = node.findAllNodesWithSpecificType(DOT_QUALIFIED_EXPRESSION) + val superNodes = node.findChildByType(SUPER_TYPE_LIST)?.findAllNodesWithCondition({ it.elementType in SUPER_TYPE })?.takeIf { it.isNotEmpty() } ?: return + val qualifiedSuperCalls = node.findAllNodesWithSpecificType(DOT_QUALIFIED_EXPRESSION) .mapNotNull { findFunWithSuper(it) }.ifEmpty { return } - if (superNodes.size == 1) - overrideNodes.map { removeSupertype(it.first) } - else - handleManyImpl(superNodes, overrideNodes) + if (superNodes.size == 1) { + qualifiedSuperCalls.map { removeSupertype(it.first) } + } else { + handleManyImpl(superNodes, qualifiedSuperCalls) + } } private fun handleManyImpl(superNodes: List, overrideNodes: List>) { @@ -69,7 +72,7 @@ class UselessSupertype(private val configRules: List) : Rule("usele @Suppress("UnsafeCallOnNullableType") private fun removeSupertype(node: ASTNode) { - USELESS_OVERRIDE.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) { + USELESS_SUPERTYPE.warnAndFix(configRules, emitWarn, isFixMode, node.text, node.startOffset, node) { val startNode = node.parent({ it.elementType == SUPER_EXPRESSION })!!.findChildByType(REFERENCE_EXPRESSION)!! val lastNode = startNode.siblings(true).last() startNode.treeParent.removeRange(startNode.treeNext, lastNode) @@ -91,10 +94,10 @@ class UselessSupertype(private val configRules: List) : Rule("usele node.findChildByType(SUPER_EXPRESSION) ?.findChildByType(TYPE_REFERENCE) ?.findAllNodesWithSpecificType(IDENTIFIER) - ?.first() ?: return null, + ?.firstOrNull() ?: return null, node.findChildByType(CALL_EXPRESSION) ?.findAllNodesWithSpecificType(IDENTIFIER) - ?.first() ?: return null) + ?.firstOrNull() ?: return null) } /** @@ -107,7 +110,7 @@ class UselessSupertype(private val configRules: List) : Rule("usele * @return map name of method and the number of times it meets */ @Suppress("UnsafeCallOnNullableType") - private fun findAllSupers(superTypeList: List, methodsName: List): MutableMap? { + private fun findAllSupers(superTypeList: List, methodsName: List): Map? { val fileNode = superTypeList.first().parent({ it.elementType == FILE })!! val superNodesIdentifier = superTypeList.map { it.findAllNodesWithSpecificType(IDENTIFIER).first().text } val superNodes = fileNode.findAllNodesWithCondition({ superClass -> @@ -124,12 +127,13 @@ class UselessSupertype(private val configRules: List) : Rule("usele it.getIdentifierName()!!.text in methodsName } overrideFunctions.forEach { - if (functionNameMap.containsKey(it.getIdentifierName()!!.text)) + functionNameMap[it.getIdentifierName()!!.text] = functionNameMap.getOrDefault(it.getIdentifierName()!!.text, 0) + 1 + /*if (functionNameMap.containsKey(it.getIdentifierName()!!.text)) functionNameMap[it.getIdentifierName()!!.text] = functionNameMap[it.getIdentifierName()!!.text]!! + 1 else - functionNameMap[it.getIdentifierName()!!.text] = 1 + functionNameMap[it.getIdentifierName()!!.text] = 1*/ } } - return functionNameMap + return functionNameMap.toMap() } } diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessSupertypeWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessSupertypeWarnTest.kt index 7972462fb4..ebc5e7baae 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessSupertypeWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessSupertypeWarnTest.kt @@ -2,7 +2,7 @@ package org.cqfn.diktat.ruleset.chapter6 import com.pinterest.ktlint.core.LintError import generated.WarningNames -import org.cqfn.diktat.ruleset.constants.Warnings.USELESS_OVERRIDE +import org.cqfn.diktat.ruleset.constants.Warnings.USELESS_SUPERTYPE import org.cqfn.diktat.ruleset.rules.DIKTAT_RULE_SET_ID import org.cqfn.diktat.ruleset.rules.UselessSupertype import org.cqfn.diktat.util.LintTestBase @@ -54,8 +54,8 @@ class UselessSupertypeWarnTest: LintTestBase(::UselessSupertype) { } } """.trimMargin(), - LintError(11,35, ruleId, "${USELESS_OVERRIDE.warnText()} Rectangle", true), - LintError(21,35, ruleId, "${USELESS_OVERRIDE.warnText()} Rectangle", true) + LintError(11,35, ruleId, "${USELESS_SUPERTYPE.warnText()} Rectangle", true), + LintError(21,35, ruleId, "${USELESS_SUPERTYPE.warnText()} Rectangle", true) ) } @@ -85,7 +85,7 @@ class UselessSupertypeWarnTest: LintTestBase(::UselessSupertype) { } """.trimMargin(), - LintError(17,35, ruleId, "${USELESS_OVERRIDE.warnText()} KK", true) + LintError(17,35, ruleId, "${USELESS_SUPERTYPE.warnText()} KK", true) ) } } From 0c9c03af1e25149cda2d59ebe9f4887d68ec8f8c Mon Sep 17 00:00:00 2001 From: kentr0w Date: Sat, 31 Oct 2020 00:39:24 +0300 Subject: [PATCH 08/11] Rule 6.1.5 ### What's done: Fixed after review --- diktat-rules/src/main/kotlin/generated/WarningNames.kt | 2 +- .../cqfn/diktat/ruleset/chapter6/UselessSupertypeFixTest.kt | 4 ++-- .../cqfn/diktat/ruleset/chapter6/UselessSupertypeWarnTest.kt | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/diktat-rules/src/main/kotlin/generated/WarningNames.kt b/diktat-rules/src/main/kotlin/generated/WarningNames.kt index 85e0a54780..add3f04c35 100644 --- a/diktat-rules/src/main/kotlin/generated/WarningNames.kt +++ b/diktat-rules/src/main/kotlin/generated/WarningNames.kt @@ -201,5 +201,5 @@ public object WarningNames { public const val CLASS_SHOULD_NOT_BE_ABSTRACT: String = "CLASS_SHOULD_NOT_BE_ABSTRACT" - public const val USELESS_OVERRIDE: String = "USELESS_OVERRIDE" + public const val USELESS_SUPERTYPE: String = "USELESS_SUPERTYPE" } diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessSupertypeFixTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessSupertypeFixTest.kt index 3f8d2fccff..e150924323 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessSupertypeFixTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessSupertypeFixTest.kt @@ -9,13 +9,13 @@ import org.junit.jupiter.api.Test class UselessSupertypeFixTest : FixTestBase("test/paragraph6/useless-override", ::UselessSupertype) { @Test - @Tag(WarningNames.USELESS_OVERRIDE) + @Tag(WarningNames.USELESS_SUPERTYPE) fun `fix example with one super`() { fixAndCompare("UselessOverrideExpected.kt", "UselessOverrideTest.kt") } @Test - @Tag(WarningNames.USELESS_OVERRIDE) + @Tag(WarningNames.USELESS_SUPERTYPE) fun `fix several super`() { fixAndCompare("SeveralSuperTypesExpected.kt", "SeveralSuperTypesTest.kt") } diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessSupertypeWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessSupertypeWarnTest.kt index ebc5e7baae..4af8fda272 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessSupertypeWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/UselessSupertypeWarnTest.kt @@ -14,7 +14,7 @@ class UselessSupertypeWarnTest: LintTestBase(::UselessSupertype) { private val ruleId = "$DIKTAT_RULE_SET_ID:useless-override" @Test - @Tag(WarningNames.USELESS_OVERRIDE) + @Tag(WarningNames.USELESS_SUPERTYPE) fun `check simple wrong example`() { lintMethod( """ @@ -60,7 +60,7 @@ class UselessSupertypeWarnTest: LintTestBase(::UselessSupertype) { } @Test - @Tag(WarningNames.USELESS_OVERRIDE) + @Tag(WarningNames.USELESS_SUPERTYPE) fun `check example with two super`() { lintMethod( """ From 99e8c57bc1efda35966fb6825ade1fef94018af0 Mon Sep 17 00:00:00 2001 From: kentr0w Date: Sat, 31 Oct 2020 01:17:39 +0300 Subject: [PATCH 09/11] Rule 6.1.5 ### What's done: Fixed after review --- diktat-analysis.yml | 2 +- diktat-rules/src/main/resources/diktat-analysis-huawei.yml | 2 +- diktat-rules/src/main/resources/diktat-analysis.yml | 2 +- info/available-rules.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/diktat-analysis.yml b/diktat-analysis.yml index 645fc07b97..941db5c4d4 100644 --- a/diktat-analysis.yml +++ b/diktat-analysis.yml @@ -342,6 +342,6 @@ enabled: true configuration: {} # Checks that override function is useful -- name: USELESS_OVERRIDE +- name: USELESS_SUPERTYPE enabled: true configuration: {} \ No newline at end of file diff --git a/diktat-rules/src/main/resources/diktat-analysis-huawei.yml b/diktat-rules/src/main/resources/diktat-analysis-huawei.yml index fdffb798ed..215e24fa81 100644 --- a/diktat-rules/src/main/resources/diktat-analysis-huawei.yml +++ b/diktat-rules/src/main/resources/diktat-analysis-huawei.yml @@ -341,6 +341,6 @@ enabled: true configuration: {} # Checks that override function is useful -- name: USELESS_OVERRIDE +- name: USELESS_SUPERTYPE enabled: true configuration: {} \ No newline at end of file diff --git a/diktat-rules/src/main/resources/diktat-analysis.yml b/diktat-rules/src/main/resources/diktat-analysis.yml index 797e833cfb..1f5350843d 100644 --- a/diktat-rules/src/main/resources/diktat-analysis.yml +++ b/diktat-rules/src/main/resources/diktat-analysis.yml @@ -343,6 +343,6 @@ enabled: true configuration: {} # Checks that override function is useful -- name: USELESS_OVERRIDE +- name: USELESS_SUPERTYPE enabled: true configuration: {} \ No newline at end of file diff --git a/info/available-rules.md b/info/available-rules.md index f1a27f898a..83a42945c3 100644 --- a/info/available-rules.md +++ b/info/available-rules.md @@ -93,6 +93,6 @@ | 5 | 5.2.3 | WRONG_OVERLOADING_FUNCTION_ARGUMENTS | Check: function has overloading instead use default arguments | no | -| | 6 | 6.1.2 | USE_DATA_CLASS | Check: if class can be made as data class | no | - | yes | | 6 | 6.1.4 | MULTIPLE_INIT_BLOCKS | Checks that classes have only one init block | yes | no | - | -| 6 | 6.1.5 | USELESS_OVERRIDE | Check: if override function can be removed | yes| - | | +| 6 | 6.1.5 | USELESS_SUPERTYPE | Check: if override function can be removed | yes| - | | | 6 | 6.1.6 | CLASS_SHOULD_NOT_BE_ABSTRACT | Checks: if abstract class has any abstract method. If not, warns that class should not be abstract
Fix: deletes abstract modifier | yes | - | - | | 6 | 6.1.9 | WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR | Check: used the name of a variable in the custom getter or setter | no | - | \ No newline at end of file From 5d9f2c095584533dc0e117fe122964d99e0080a9 Mon Sep 17 00:00:00 2001 From: kentr0w Date: Mon, 9 Nov 2020 18:52:20 +0300 Subject: [PATCH 10/11] Rule 6.1.5 ### What's done: Fixed after review --- diktat-analysis.yml | 2 +- .../cqfn/diktat/ruleset/rules/UselessSupertype.kt | 15 +++++++-------- .../src/main/resources/diktat-analysis-huawei.yml | 2 +- .../src/main/resources/diktat-analysis.yml | 2 +- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/diktat-analysis.yml b/diktat-analysis.yml index ce2a23da30..5f391a5611 100644 --- a/diktat-analysis.yml +++ b/diktat-analysis.yml @@ -350,7 +350,7 @@ - name: CLASS_SHOULD_NOT_BE_ABSTRACT enabled: true configuration: {} -# Checks that override function is useful +# Checks explicit supertype qualification - name: USELESS_SUPERTYPE enabled: true configuration: {} \ No newline at end of file diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessSupertype.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessSupertype.kt index 371b8d422b..cb5a5e47aa 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessSupertype.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/UselessSupertype.kt @@ -19,6 +19,7 @@ import com.pinterest.ktlint.core.ast.ElementType.SUPER_TYPE_LIST import com.pinterest.ktlint.core.ast.ElementType.TYPE_REFERENCE import com.pinterest.ktlint.core.ast.parent import org.cqfn.diktat.common.config.rules.RulesConfig +import org.cqfn.diktat.ruleset.constants.EmitType import org.cqfn.diktat.ruleset.constants.Warnings.USELESS_SUPERTYPE import org.cqfn.diktat.ruleset.utils.* import org.jetbrains.kotlin.com.intellij.lang.ASTNode @@ -35,7 +36,7 @@ class UselessSupertype(private val configRules: List) : Rule("usele private val SUPER_TYPE = listOf(SUPER_TYPE_CALL_ENTRY, SUPER_TYPE_ENTRY) } - private lateinit var emitWarn: ((offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) + private lateinit var emitWarn: EmitType private var isFixMode: Boolean = false override fun visit(node: ASTNode, @@ -60,7 +61,9 @@ class UselessSupertype(private val configRules: List) : Rule("usele } private fun handleManyImpl(superNodes: List, overrideNodes: List>) { - val uselessSuperType = findAllSupers(superNodes, overrideNodes.map { it.second.text })?.filter { it.value == 1 }?.map { it.key } + val uselessSuperType = findAllSupers(superNodes, overrideNodes.map { it.second.text }) + ?.filter { it.value == 1 } // filtering methods whose names occur only once + ?.map { it.key } // take their names ?: return overrideNodes .filter { @@ -119,7 +122,7 @@ class UselessSupertype(private val configRules: List) : Rule("usele }).mapNotNull { it.findChildByType(CLASS_BODY) } if (superNodes.size != superTypeList.size) return null - val functionNameMap = mutableMapOf() + val functionNameMap = hashMapOf() superNodes.forEach { classBody -> val overrideFunctions = classBody.findAllNodesWithSpecificType(FUN) .filter { @@ -127,11 +130,7 @@ class UselessSupertype(private val configRules: List) : Rule("usele it.getIdentifierName()!!.text in methodsName } overrideFunctions.forEach { - functionNameMap[it.getIdentifierName()!!.text] = functionNameMap.getOrDefault(it.getIdentifierName()!!.text, 0) + 1 - /*if (functionNameMap.containsKey(it.getIdentifierName()!!.text)) - functionNameMap[it.getIdentifierName()!!.text] = functionNameMap[it.getIdentifierName()!!.text]!! + 1 - else - functionNameMap[it.getIdentifierName()!!.text] = 1*/ + functionNameMap.compute(it.getIdentifierName()!!.text) { _, oldValue -> (oldValue ?: 0) + 1} } } return functionNameMap.toMap() diff --git a/diktat-rules/src/main/resources/diktat-analysis-huawei.yml b/diktat-rules/src/main/resources/diktat-analysis-huawei.yml index f5ecfd7504..c27edaaa0e 100644 --- a/diktat-rules/src/main/resources/diktat-analysis-huawei.yml +++ b/diktat-rules/src/main/resources/diktat-analysis-huawei.yml @@ -349,7 +349,7 @@ - name: CLASS_SHOULD_NOT_BE_ABSTRACT enabled: true configuration: {} -# Checks that override function is useful +# Checks explicit supertype qualification - name: USELESS_SUPERTYPE enabled: true configuration: {} \ No newline at end of file diff --git a/diktat-rules/src/main/resources/diktat-analysis.yml b/diktat-rules/src/main/resources/diktat-analysis.yml index 36a0d98a32..7a48e1c631 100644 --- a/diktat-rules/src/main/resources/diktat-analysis.yml +++ b/diktat-rules/src/main/resources/diktat-analysis.yml @@ -351,7 +351,7 @@ - name: CLASS_SHOULD_NOT_BE_ABSTRACT enabled: true configuration: {} -# Checks that override function is useful +# Checks explicit supertype qualification - name: USELESS_SUPERTYPE enabled: true configuration: {} \ No newline at end of file From 4f24942527f03a92e0a6421b09ce15c66eab2af6 Mon Sep 17 00:00:00 2001 From: kentr0w Date: Fri, 13 Nov 2020 13:15:06 +0300 Subject: [PATCH 11/11] Rule 6.1.5 ### What's done: Fixed after review --- .../org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt index 6302dc312f..0af2490bf9 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProvider.kt @@ -65,7 +65,6 @@ class DiktatRuleSetProvider(private val diktatConfigFile: String = "diktat-analy ::IdentifierNaming, // code structure ::UselessSupertype, - ::LocalVariablesRule, ::ClassLikeStructuresOrderRule, ::WhenMustHaveElseRule, ::BracesInConditionalsAndLoopsRule, @@ -78,6 +77,7 @@ class DiktatRuleSetProvider(private val diktatConfigFile: String = "diktat-analy // other rules ::StringTemplateFormatRule, ::DataClassesRule, + ::LocalVariablesRule, ::SmartCastRule, ::PropertyAccessorFields, ::AbstractClassesRule,