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 57d5e9cd55..48347021b6 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 @@ -10,6 +10,8 @@ typealias EmitType = ((offset: Int, errorMessage: String, canBeAutoCorrected: Bo typealias ListOfList = MutableList> +typealias ListOfPairs = MutableList> + /** * This class represent individual inspections of diktat code style. * A [Warnings] entry contains rule name, warning message and is used in code check. diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/CommentsRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/CommentsRule.kt index f169fed02a..d3413646c0 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/CommentsRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter2/comments/CommentsRule.kt @@ -2,6 +2,7 @@ package org.cqfn.diktat.ruleset.rules.chapter2.comments import org.cqfn.diktat.common.config.rules.RulesConfig import org.cqfn.diktat.ruleset.constants.EmitType +import org.cqfn.diktat.ruleset.constants.ListOfPairs import org.cqfn.diktat.ruleset.constants.Warnings.COMMENTED_OUT_CODE import org.cqfn.diktat.ruleset.utils.findAllNodesWithSpecificType @@ -52,26 +53,35 @@ class CommentsRule(private val configRules: List) : Rule("comments" * with '// ' with whitespace, while automatic commenting in, e.g., IDEA creates slashes in the beginning of the line * */ + @Suppress("UnsafeCallOnNullableType", "TOO_LONG_FUNCTION") private fun checkCommentedCode(node: ASTNode) { - val eolCommentsOffsetToText = getOffsetsToTextBlocksFromEolComments(node) + val errorNodesWithText: ListOfPairs = mutableListOf() + val eolCommentsOffsetToText = getOffsetsToTextBlocksFromEolComments(node, errorNodesWithText) val blockCommentsOffsetToText = node .findAllNodesWithSpecificType(BLOCK_COMMENT) - .map { it.startOffset to it.text.trim().removeSurrounding("/*", "*/") } - + .map { + errorNodesWithText.add(it to it.text.trim().removeSurrounding("/*", "*/")) + it.startOffset to it.text.trim().removeSurrounding("/*", "*/") + } (eolCommentsOffsetToText + blockCommentsOffsetToText) .flatMap { (offset, text) -> val (singleLines, blockLines) = text.lines().partition { it.contains(importOrPackage) } val block = if (blockLines.isNotEmpty()) listOf(blockLines.joinToString("\n")) else emptyList() - (singleLines + block).map { offset to it } + (singleLines + block).map { + offset to it + } } - .map { (offset, text) -> + .mapNotNull { (offset, text) -> when { text.contains(importKeyword) -> offset to ktPsiFactory.createImportDirective(ImportPath.fromString(text.substringAfter("$importKeyword "))).node text.contains(packageKeyword) -> offset to ktPsiFactory.createPackageDirective(FqName(text.substringAfter("$packageKeyword "))).node - else -> + else -> if (text.contains(requirePartOfCode)) { offset to ktPsiFactory.createBlockCodeFragment(text, null).node + } else { + null + } } } .filter { (_, parsedNode) -> @@ -80,7 +90,8 @@ class CommentsRule(private val configRules: List) : Rule("comments" .isEmpty() } .forEach { (offset, parsedNode) -> - COMMENTED_OUT_CODE.warn(configRules, emitWarn, isFixMode, parsedNode.text.substringBefore("\n").trim(), offset, parsedNode) + COMMENTED_OUT_CODE.warn(configRules, emitWarn, isFixMode, parsedNode.text.substringBefore("\n").trim(), offset, + errorNodesWithText.find { it.second == parsedNode.text }?.first ?: parsedNode) } } @@ -90,7 +101,7 @@ class CommentsRule(private val configRules: List) : Rule("comments" * Splitting back into lines, if necessary, will be done outside of this method, for both text from EOL and block. * fixme: in this case offset is lost for lines which will be split once more */ - private fun getOffsetsToTextBlocksFromEolComments(node: ASTNode): List> { + private fun getOffsetsToTextBlocksFromEolComments(node: ASTNode, errorNodesWithText: ListOfPairs): List> { val comments = node .findAllNodesWithSpecificType(EOL_COMMENT) .filter { !it.text.contains(eolCommentStart) || isCodeAfterCommentStart(it.text) } @@ -109,6 +120,7 @@ class CommentsRule(private val configRules: List) : Rule("comments" acc } .map { list -> + list.forEach { errorNodesWithText.add(it to it.text.removePrefix("//")) } list.first().startOffset to list.joinToString("\n") { it.text.removePrefix("//") } } } else { @@ -139,6 +151,7 @@ class CommentsRule(private val configRules: List) : Rule("comments" private val importOrPackageRegex = """^(import|package)?\s+([a-zA-Z.])+;*$""".toRegex() private val functionRegex = """^(public|private|protected)*\s*(override|abstract|actual|expect)*\s?fun\s+\w+(\(.*\))?(\s*:\s*\w+)?\s*[{=]${'$'}""".toRegex() private val rightBraceRegex = """^\s*}$""".toRegex() + private val requirePartOfCode = """val |var |=|(\{((.|\n)*)\})""".toRegex() private val codeFileStartCases = listOf(classRegex, importOrPackageRegex, functionRegex, rightBraceRegex) private val eolCommentStart = """// \S""".toRegex() } diff --git a/diktat-rules/src/main/resources/diktat-analysis.yml b/diktat-rules/src/main/resources/diktat-analysis.yml index e304559596..e950b05411 100644 --- a/diktat-rules/src/main/resources/diktat-analysis.yml +++ b/diktat-rules/src/main/resources/diktat-analysis.yml @@ -131,7 +131,7 @@ - name: HEADER_MISSING_OR_WRONG_COPYRIGHT enabled: true configuration: - isCopyrightMandatory: true + isCopyrightMandatory: false copyrightText: 'Copyright (c) Your Company Name Here. 2010-2021' # Checks that header kdoc is located before package directive - name: HEADER_NOT_BEFORE_PACKAGE diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/comments/CommentedCodeTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/comments/CommentedCodeTest.kt index 05517afc0c..b35327d1bd 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/comments/CommentedCodeTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/comments/CommentedCodeTest.kt @@ -52,6 +52,7 @@ class CommentedCodeTest : LintTestBase(::CommentsRule) { |fun foo(a: Int): Int { | /* println(a + 42) | println("This is a test string") + | val b = a*10 | */ | return 0 |} @@ -72,9 +73,7 @@ class CommentedCodeTest : LintTestBase(::CommentsRule) { |// println("This is a test string") | return 0 |} - """.trimMargin(), - LintError(4, 1, ruleId, "${COMMENTED_OUT_CODE.warnText()} println(a + 42)", false) - ) + """.trimMargin()) } @Test @@ -179,8 +178,7 @@ class CommentedCodeTest : LintTestBase(::CommentsRule) { lintMethod( """ |// class Test: Exception() - """.trimMargin(), - LintError(1, 1, ruleId, "${COMMENTED_OUT_CODE.warnText()} class Test: Exception()", false)) + """.trimMargin()) } @Test @@ -199,8 +197,7 @@ class CommentedCodeTest : LintTestBase(::CommentsRule) { lintMethod( """ |// internal sealed class Test: Exception() - """.trimMargin(), - LintError(1, 1, ruleId, "${COMMENTED_OUT_CODE.warnText()} internal sealed class Test: Exception()", false)) + """.trimMargin()) } @Test @@ -293,4 +290,57 @@ class CommentedCodeTest : LintTestBase(::CommentsRule) { | */ """.trimMargin()) } + + @Test + @Tag(WarningNames.COMMENTED_OUT_CODE) + fun `should not trigger on Copyright and another comment`() { + lintMethod( + """ + /* + Copyright (c) Your Company Name Here. 2010-2021 + */ + + package org.cqfn.diktat + + /* + x = 2 + 4 + 1 + */ + // x = 2+4 + + // if true make this + + /* + class A { + + fun foo() + + } + + */ + """.trimMargin(), + LintError(7, 13, ruleId, "${COMMENTED_OUT_CODE.warnText()} ", false), + LintError(14, 13, ruleId, "${COMMENTED_OUT_CODE.warnText()} ", false) + ) + } + + @Test + @Tag(WarningNames.COMMENTED_OUT_CODE) + fun `should not trigger with suppress`() { + lintMethod( + """ + @Suppress("UnsafeCallOnNullableType", "COMMENTED_OUT_CODE") + private fun handleProperty(property: KtProperty) { + + /* + x = 1 + */ + } + + @Suppress("COMMENTED_OUT_CODE") + class A { + // val x = 10 + } + """.trimMargin() + ) + } } diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt index 8affcfdbe7..ba81e98b34 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt @@ -160,8 +160,7 @@ class DiktatSmokeTest : FixTestBase("test/smoke/src/main/kotlin", fun `smoke test #2`() { fixAndCompare("Example2Expected.kt", "Example2Test.kt") unfixedLintErrors.assertEquals( - LintError(1, 1, "$DIKTAT_RULE_SET_ID:header-comment", "${HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE.warnText()} there are 2 declared classes and/or objects", false), - LintError(12, 26, "$DIKTAT_RULE_SET_ID:comments", "${Warnings.COMMENTED_OUT_CODE.warnText()} private class Test : RuntimeException()", false) + LintError(1, 1, "$DIKTAT_RULE_SET_ID:header-comment", "${HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE.warnText()} there are 2 declared classes and/or objects", false) ) }