From 09edb261d3aae959bdf908349b7e9a4b8aab5cee Mon Sep 17 00:00:00 2001 From: Daria Pleshkova <81246075+diphtongue@users.noreply.github.com> Date: Thu, 7 Dec 2023 17:47:17 +0300 Subject: [PATCH] Fixed false positive `MISSING_KDOC_ON_FUNCTION` on local function (function inside another function) (#1848) ### What's done: - Fixed false positive `MISSING_KDOC_ON_FUNCTION` on local function (function inside another function) - Added warning tests Closes #1773 --- .../rules/chapter1/IdentifierNaming.kt | 1 + .../rules/chapter2/kdoc/KdocMethods.kt | 21 +++- .../ruleset/chapter2/KdocMethodsTest.kt | 99 +++++++++++++++++++ 3 files changed, 119 insertions(+), 2 deletions(-) diff --git a/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter1/IdentifierNaming.kt b/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter1/IdentifierNaming.kt index 08dec56835..24fe0cfcba 100644 --- a/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter1/IdentifierNaming.kt +++ b/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter1/IdentifierNaming.kt @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.KtNodeTypes.DESTRUCTURING_DECLARATION import org.jetbrains.kotlin.KtNodeTypes.DESTRUCTURING_DECLARATION_ENTRY import org.jetbrains.kotlin.KtNodeTypes.FUNCTION_TYPE import org.jetbrains.kotlin.KtNodeTypes.OBJECT_DECLARATION +import org.jetbrains.kotlin.KtNodeTypes.PROPERTY import org.jetbrains.kotlin.KtNodeTypes.REFERENCE_EXPRESSION import org.jetbrains.kotlin.KtNodeTypes.TYPE_PARAMETER import org.jetbrains.kotlin.KtNodeTypes.TYPE_REFERENCE diff --git a/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter2/kdoc/KdocMethods.kt b/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter2/kdoc/KdocMethods.kt index 68b614c3d8..3e8d96494e 100644 --- a/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter2/kdoc/KdocMethods.kt +++ b/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter2/kdoc/KdocMethods.kt @@ -98,7 +98,22 @@ class KdocMethods(configRules: List) : DiktatRule( } } - @Suppress("UnsafeCallOnNullableType", "AVOID_NULL_CHECKS") + private fun hasFunParent(node: ASTNode): Boolean { + var parent = node.treeParent + while (parent != null) { + if (parent.elementType == FUN) { + return true + } + parent = parent.treeParent + } + return false + } + + @Suppress( + "UnsafeCallOnNullableType", + "AVOID_NULL_CHECKS", + "CyclomaticComplexMethod" + ) private fun checkSignatureDescription(node: ASTNode) { val kdoc = node.getFirstChildWithType(KDOC) val kdocTags = kdoc?.kDocTags() @@ -119,7 +134,9 @@ class KdocMethods(configRules: List) : DiktatRule( val anyTagFailed = paramCheckFailed || returnCheckFailed || throwsCheckFailed // if no tag failed, we have too little information to suggest KDoc - it would just be empty - if (kdoc == null && anyTagFailed) { + if (kdoc == null && hasFunParent(node)) { + return + } else if (kdoc == null && anyTagFailed) { addKdocTemplate(node, name, missingParameters, explicitlyThrownExceptions, returnCheckFailed) } else if (kdoc == null && !isReferenceExpressionWithSameName(node)) { MISSING_KDOC_ON_FUNCTION.warn(configRules, emitWarn, name, node.startOffset, node) diff --git a/diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocMethodsTest.kt b/diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocMethodsTest.kt index aba16246fc..94c439e65d 100644 --- a/diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocMethodsTest.kt +++ b/diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocMethodsTest.kt @@ -425,4 +425,103 @@ class KdocMethodsTest : LintTestBase(::KdocMethods) { DiktatError(2, 1, ruleId, "${MISSING_KDOC_ON_FUNCTION.warnText()} writeToConsoleEx", true), ) } + + @Test + @Tag(WarningNames.MISSING_KDOC_ON_FUNCTION) + fun `KDoc shouldn't trigger on local functions`() { + lintMethod( + """ + |fun printHelloAndBye() { + | fun printHello() { + | print("Hello") + | } + | printHello() + | val ab = 5 + | ab?.let { + | fun printBye() { + | print("Bye") + | } + | printBye() + | } + |} + """.trimMargin(), + DiktatError(1, 1, ruleId, "${MISSING_KDOC_ON_FUNCTION.warnText()} printHelloAndBye", false), + ) + } + + @Test + @Tag(WarningNames.MISSING_KDOC_ON_FUNCTION) + fun `KDoc shouldn't trigger on functions with KDoc`() { + lintMethod( + """ + |/** + | * prints "Hello" and "Bye" + | */ + |fun printHelloAndBye() { + | fun printHello() { + | print("Hello") + | } + | printHello() + | val ab = 5 + | ab?.let { + | fun printBye() { + | print("Bye") + | } + | printBye() + | } + |} + """.trimMargin(), + ) + } + + @Test + @Tag(WarningNames.MISSING_KDOC_ON_FUNCTION) + fun `KDoc shouldn't trigger on nested local functions`() { + lintMethod( + """ + |fun printHelloAndBye() { + | fun printHello() { + | print("Hello") + | fun printBye() { + | print("Bye") + | } + | fun printDots() { + | print("...") + | } + | printBye() + | printDots() + | } + | printHello() + |} + """.trimMargin(), + DiktatError(1, 1, ruleId, "${MISSING_KDOC_ON_FUNCTION.warnText()} printHelloAndBye", false), + ) + } + + @Test + @Tag(WarningNames.MISSING_KDOC_ON_FUNCTION) + fun `KDoc shouldn't trigger on local functions with KDoc`() { + lintMethod( + """ + |fun printHelloAndBye() { + | fun printHello() { + | print("Hello") + | } + | printHello() + | val ab = 5 + | ab?.let { + | /** + | * prints "Bye" + | */ + | fun printBye() { + | print("Bye") + | } + | printBye() + | } + |} + """.trimMargin(), + DiktatError(1, 1, ruleId, "${MISSING_KDOC_ON_FUNCTION.warnText()} printHelloAndBye", false), + ) + } + }