Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copyright as code #740

Merged
merged 14 commits into from
Feb 2, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ typealias EmitType = ((offset: Int, errorMessage: String, canBeAutoCorrected: Bo

typealias ListOfList = MutableList<MutableList<ASTNode>>

typealias ListOfPairs = MutableList<Pair<ASTNode, String>>

/**
* This class represent individual inspections of diktat code style.
* A [Warnings] entry contains rule name, warning message and is used in code check.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -52,26 +53,35 @@ class CommentsRule(private val configRules: List<RulesConfig>) : 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) ->
Expand All @@ -80,7 +90,8 @@ class CommentsRule(private val configRules: List<RulesConfig>) : 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)
petertrr marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand All @@ -90,7 +101,7 @@ class CommentsRule(private val configRules: List<RulesConfig>) : 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<Pair<Int, String>> {
private fun getOffsetsToTextBlocksFromEolComments(node: ASTNode, errorNodesWithText: ListOfPairs): List<Pair<Int, String>> {
val comments = node
.findAllNodesWithSpecificType(EOL_COMMENT)
.filter { !it.text.contains(eolCommentStart) || isCodeAfterCommentStart(it.text) }
Expand All @@ -109,6 +120,7 @@ class CommentsRule(private val configRules: List<RulesConfig>) : 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 {
Expand Down Expand Up @@ -139,6 +151,7 @@ class CommentsRule(private val configRules: List<RulesConfig>) : 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()
}
Expand Down
2 changes: 1 addition & 1 deletion diktat-rules/src/main/resources/diktat-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
|}
Expand All @@ -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)
petertrr marked this conversation as resolved.
Show resolved Hide resolved
)
""".trimMargin())
}

@Test
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
petertrr marked this conversation as resolved.
Show resolved Hide resolved
*/
// 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`() {
petertrr marked this conversation as resolved.
Show resolved Hide resolved
lintMethod(
"""
@Suppress("UnsafeCallOnNullableType", "COMMENTED_OUT_CODE")
private fun handleProperty(property: KtProperty) {

/*
x = 1
*/
}

@Suppress("COMMENTED_OUT_CODE")
class A {
// val x = 10
}
""".trimMargin()
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
)
}

Expand Down