From de8b0ef27a3c855f8cbc71050a38b0d41e4c254c Mon Sep 17 00:00:00 2001 From: Nariman Abdullin Date: Thu, 16 Jun 2022 12:09:46 +0300 Subject: [PATCH 1/4] Fix for UNUSED_IMPORT in KDoc ### What's done: - supported KDOC_MARKDOWN_LINK as references --- .../rules/chapter3/files/FileStructureRule.kt | 39 +++++--- .../ruleset/chapter3/FileStructureRuleTest.kt | 89 +++++++++++++++++-- 2 files changed, 110 insertions(+), 18 deletions(-) diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/FileStructureRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/FileStructureRule.kt index 1e522cc81a..aec77f17a6 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/FileStructureRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/FileStructureRule.kt @@ -19,6 +19,7 @@ import org.cqfn.diktat.ruleset.utils.handleIncorrectOrder import org.cqfn.diktat.ruleset.utils.ignoreImports import org.cqfn.diktat.ruleset.utils.moveChildBefore import org.cqfn.diktat.ruleset.utils.operatorMap +import org.cqfn.diktat.ruleset.utils.removePrefix import com.pinterest.ktlint.core.ast.ElementType.BLOCK_COMMENT import com.pinterest.ktlint.core.ast.ElementType.EOL_COMMENT @@ -27,6 +28,7 @@ import com.pinterest.ktlint.core.ast.ElementType.FILE_ANNOTATION_LIST import com.pinterest.ktlint.core.ast.ElementType.IMPORT_DIRECTIVE import com.pinterest.ktlint.core.ast.ElementType.IMPORT_LIST import com.pinterest.ktlint.core.ast.ElementType.KDOC +import com.pinterest.ktlint.core.ast.ElementType.KDOC_MARKDOWN_LINK import com.pinterest.ktlint.core.ast.ElementType.OPERATION_REFERENCE import com.pinterest.ktlint.core.ast.ElementType.PACKAGE_DIRECTIVE import com.pinterest.ktlint.core.ast.ElementType.REFERENCE_EXPRESSION @@ -73,9 +75,8 @@ class FileStructureRule(configRules: List) : DiktatRule( .mapValues { (_, value) -> value.map { it.split(PACKAGE_SEPARATOR).map(Name::identifier) } } - private val refSet: MutableSet = mutableSetOf() private var packageName = "" - + /** * There are groups of methods, which should be excluded from usage check without type resolution. * `componentN` is a method for N-th component in destructuring declarations. @@ -226,7 +227,7 @@ class FileStructureRule(configRules: List) : DiktatRule( private fun checkUnusedImport( node: ASTNode ) { - findAllReferences(node) + val refSet = findAllReferences(node) packageName = (node.findChildByType(PACKAGE_DIRECTIVE)?.psi as KtPackageDirective).qualifiedName node.findChildByType(IMPORT_LIST) ?.getChildren(TokenSet.create(IMPORT_DIRECTIVE)) @@ -264,24 +265,36 @@ class FileStructureRule(configRules: List) : DiktatRule( ) { ktImportDirective.delete() } } - private fun findAllReferences(node: ASTNode) { - node.findAllDescendantsWithSpecificType(OPERATION_REFERENCE).forEach { ref -> - if (!ref.isPartOf(IMPORT_DIRECTIVE)) { + private fun findAllReferences(node: ASTNode): Set { + val referencesFromOperations = node.findAllDescendantsWithSpecificType(OPERATION_REFERENCE) + .filterNot { it.isPartOf(IMPORT_DIRECTIVE) } + .flatMap { ref -> val references = operatorMap.filterValues { ref.text in it } if (references.isNotEmpty()) { - references.keys.forEach { key -> refSet.add(key) } + references.keys } else { // this is needed to check infix functions that relate to operation reference - refSet.add(ref.text) + setOf(ref.text) } } - } - node.findAllDescendantsWithSpecificType(REFERENCE_EXPRESSION).forEach { - if (!it.isPartOf(IMPORT_DIRECTIVE)) { + val referencesFromExpressions = node.findAllDescendantsWithSpecificType(REFERENCE_EXPRESSION) + .filterNot { it.isPartOf(IMPORT_DIRECTIVE) } + .map { // the importedName method removes the quotes, but the node.text method does not - refSet.add(it.text.replace("`", "")) + it.text.replace("`", "") } - } + val referencesFromKDocs = node.findAllDescendantsWithSpecificType(KDOC) + .flatMap { it.findAllDescendantsWithSpecificType(KDOC_MARKDOWN_LINK) } + .map { it.text.removePrefix("[").removeSuffix("]") } + .flatMap { + if (it.contains(".")) { + // support cases with reference to method + listOf(it, it.substringBeforeLast(".")) + } else { + listOf(it) + } + } + return (referencesFromOperations + referencesFromExpressions + referencesFromKDocs).toSet() } private fun rearrangeImports( diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/FileStructureRuleTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/FileStructureRuleTest.kt index b5abea6c91..14e934eff7 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/FileStructureRuleTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter3/FileStructureRuleTest.kt @@ -79,7 +79,7 @@ class FileStructureRuleTest : LintTestBase(::FileStructureRule) { |import org.junit.Test |import org.cqfn.diktat.Foo | - |class Example { + |class Example { |val x: Test = null |val y: Foo = null |} @@ -273,7 +273,7 @@ class FileStructureRuleTest : LintTestBase(::FileStructureRule) { | |import org.cqfn.diktat.example.Foo | - |class Example { + |class Example { |} """.trimMargin(), LintError(1, 1, ruleId, "${Warnings.UNUSED_IMPORT.warnText()} org.cqfn.diktat.example.Foo - unused import", true) @@ -289,7 +289,7 @@ class FileStructureRuleTest : LintTestBase(::FileStructureRule) { | |import org.cqfn.diktat.Foo | - |class Example { + |class Example { |} """.trimMargin(), LintError(1, 1, ruleId, "${Warnings.UNUSED_IMPORT.warnText()} org.cqfn.diktat.Foo - unused import", true) @@ -305,7 +305,7 @@ class FileStructureRuleTest : LintTestBase(::FileStructureRule) { | |import org.cqfn.diktat.Foo | - |class Example { + |class Example { |val x: Foo = null |} """.trimMargin(), @@ -321,7 +321,7 @@ class FileStructureRuleTest : LintTestBase(::FileStructureRule) { | |import kotlin.io.path.div | - |class Example { + |class Example { |val pom = kotlin.io.path.createTempFile().toFile() |val x = listOf(pom.parentFile.toPath() / "src/main/kotlin/exclusion") |} @@ -482,4 +482,83 @@ class FileStructureRuleTest : LintTestBase(::FileStructureRule) { LintError(1, 1, ruleId, "${Warnings.UNUSED_IMPORT.warnText()} tasks.getValue - unused import", true) ) } + + @Test + @Tag(WarningNames.UNUSED_IMPORT) + fun `import in KDoc #1`() { + lintMethod( + """ + |import java.io.IOException + | + |interface BluetoothApi { + | + | /** + | * Send array of bytes to bluetooth output stream. + | * This call is asynchronous. + | * + | * Note that this operation can still throw an [IOException] if the remote device silently + | * closes the connection so the pipe gets broken. + | * + | * @param bytes data to send + | * @return true if success, false if there was an error or device has been disconnected + | */ + | fun trySend(bytes: ByteArray): Boolean + |} + """.trimMargin(), + ) + } + + @Test + @Tag(WarningNames.UNUSED_IMPORT) + fun `import in KDoc #2`() { + lintMethod( + """ + |import java.io.IOException + |import java.io.IOException as IOE + |import java.io.UncheckedIOException + |import java.io.UncheckedIOException as UIOE + | + |interface BluetoothApi { + | /** + | * @see IOException + | * @see [UncheckedIOException] + | * @see IOE + | * @see [UIOE] + | */ + | fun trySend(bytes: ByteArray): Boolean + |} + """.trimMargin(), + ) + } + + @Test + @Tag(WarningNames.UNUSED_IMPORT) + fun `import in KDoc #3`() { + lintMethod( + """ + |package com.example + | + |import com.example.Library1 as Lib1 + |import com.example.Library1.doSmth as doSmthElse1 + |import com.example.Library2 as Lib2 + |import com.example.Library2.doSmth as doSmthElse2 + | + |object Library1 { + | fun doSmth(): Unit = TODO() + |} + | + |object Library2 { + | fun doSmth(): Unit = TODO() + |} + | + |/** + | * @see Lib1.doSmth + | * @see doSmthElse1 + | * @see [Lib2.doSmth] + | * @see [doSmthElse2] + | */ + |class Client + """.trimMargin(), + ) + } } From b45160bb91502439cfb748bf7f4943882a89c88b Mon Sep 17 00:00:00 2001 From: Nariman Abdullin Date: Thu, 16 Jun 2022 13:59:58 +0300 Subject: [PATCH 2/4] fixed camelCase issue with variable name --- .../diktat/ruleset/rules/chapter3/files/FileStructureRule.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/FileStructureRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/FileStructureRule.kt index aec77f17a6..6b0c3fa470 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/FileStructureRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/FileStructureRule.kt @@ -19,7 +19,6 @@ import org.cqfn.diktat.ruleset.utils.handleIncorrectOrder import org.cqfn.diktat.ruleset.utils.ignoreImports import org.cqfn.diktat.ruleset.utils.moveChildBefore import org.cqfn.diktat.ruleset.utils.operatorMap -import org.cqfn.diktat.ruleset.utils.removePrefix import com.pinterest.ktlint.core.ast.ElementType.BLOCK_COMMENT import com.pinterest.ktlint.core.ast.ElementType.EOL_COMMENT @@ -283,7 +282,7 @@ class FileStructureRule(configRules: List) : DiktatRule( // the importedName method removes the quotes, but the node.text method does not it.text.replace("`", "") } - val referencesFromKDocs = node.findAllDescendantsWithSpecificType(KDOC) + val referencesFromKdocs = node.findAllDescendantsWithSpecificType(KDOC) .flatMap { it.findAllDescendantsWithSpecificType(KDOC_MARKDOWN_LINK) } .map { it.text.removePrefix("[").removeSuffix("]") } .flatMap { @@ -294,7 +293,7 @@ class FileStructureRule(configRules: List) : DiktatRule( listOf(it) } } - return (referencesFromOperations + referencesFromExpressions + referencesFromKDocs).toSet() + return (referencesFromOperations + referencesFromExpressions + referencesFromKdocs).toSet() } private fun rearrangeImports( From 47781a4e88ba5da463c8c201676b5b75bc233419 Mon Sep 17 00:00:00 2001 From: Nariman Abdullin Date: Thu, 16 Jun 2022 14:11:31 +0300 Subject: [PATCH 3/4] fixed UNUSED_IMPORT in project --- .../diktat/ruleset/chapter5/AvoidNestedFunctionsWarnTest.kt | 1 - .../chapter5/ParameterNameInOuterLambdaRuleWarnTest.kt | 1 - .../org/cqfn/diktat/ruleset/utils/AstNodeUtilsTest.kt | 6 ++---- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter5/AvoidNestedFunctionsWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter5/AvoidNestedFunctionsWarnTest.kt index 4635395199..4cf0b0ca81 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter5/AvoidNestedFunctionsWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter5/AvoidNestedFunctionsWarnTest.kt @@ -6,7 +6,6 @@ import org.cqfn.diktat.ruleset.rules.chapter5.AvoidNestedFunctionsRule import org.cqfn.diktat.util.LintTestBase import com.pinterest.ktlint.core.LintError -import generated.WarningNames import generated.WarningNames.AVOID_NESTED_FUNCTIONS import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter5/ParameterNameInOuterLambdaRuleWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter5/ParameterNameInOuterLambdaRuleWarnTest.kt index 5bd632d61e..c71028e8e1 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter5/ParameterNameInOuterLambdaRuleWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter5/ParameterNameInOuterLambdaRuleWarnTest.kt @@ -4,7 +4,6 @@ import org.cqfn.diktat.common.config.rules.RulesConfig import org.cqfn.diktat.ruleset.constants.Warnings import org.cqfn.diktat.ruleset.rules.DIKTAT_RULE_SET_ID import org.cqfn.diktat.ruleset.rules.chapter5.ParameterNameInOuterLambdaRule -import org.cqfn.diktat.ruleset.rules.chapter6.classes.AbstractClassesRule import org.cqfn.diktat.util.LintTestBase import com.pinterest.ktlint.core.LintError diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtilsTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtilsTest.kt index f8897e7bd9..5a89060d28 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtilsTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/AstNodeUtilsTest.kt @@ -14,7 +14,6 @@ import com.pinterest.ktlint.core.Rule import com.pinterest.ktlint.core.RuleSet import com.pinterest.ktlint.core.api.FeatureInAlphaState import com.pinterest.ktlint.core.ast.ElementType -import com.pinterest.ktlint.core.ast.ElementType.BLOCK import com.pinterest.ktlint.core.ast.ElementType.CLASS import com.pinterest.ktlint.core.ast.ElementType.CLASS_BODY import com.pinterest.ktlint.core.ast.ElementType.EOL_COMMENT @@ -23,7 +22,6 @@ 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.INTEGER_CONSTANT -import com.pinterest.ktlint.core.ast.ElementType.LAMBDA_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.MODIFIER_LIST import com.pinterest.ktlint.core.ast.ElementType.PROPERTY import com.pinterest.ktlint.core.ast.ElementType.TYPE_REFERENCE @@ -129,7 +127,7 @@ class AstNodeUtilsTest { fun `test getTypeParameterList`() { val code = """ class Array(val size: Int) { - + } """.trimIndent() applyToCode(code, 1) { node, counter -> @@ -408,7 +406,7 @@ class AstNodeUtilsTest { fun `test isNodeFromFileLevel - node isn't from file level`() { val code = """ val x = 2 - + """.trimIndent() applyToCode(code, 8) { node, counter -> if (node.elementType != FILE) { From eb4902c5151bc1f66408618d7df492b8b9af0f4a Mon Sep 17 00:00:00 2001 From: Nariman Abdullin Date: Thu, 16 Jun 2022 19:20:51 +0300 Subject: [PATCH 4/4] fixed unused import --- .../cqfn/diktat/ruleset/rules/chapter3/files/IndentationRule.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/IndentationRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/IndentationRule.kt index 0ba1b38fe9..30bab7fc64 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/IndentationRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/files/IndentationRule.kt @@ -33,7 +33,6 @@ import com.pinterest.ktlint.core.ast.ElementType.LONG_STRING_TEMPLATE_ENTRY import com.pinterest.ktlint.core.ast.ElementType.LONG_TEMPLATE_ENTRY_END import com.pinterest.ktlint.core.ast.ElementType.LONG_TEMPLATE_ENTRY_START import com.pinterest.ktlint.core.ast.ElementType.LPAR -import com.pinterest.ktlint.core.ast.ElementType.OPEN_QUOTE import com.pinterest.ktlint.core.ast.ElementType.RBRACE import com.pinterest.ktlint.core.ast.ElementType.RBRACKET import com.pinterest.ktlint.core.ast.ElementType.RPAR