Skip to content

Commit

Permalink
New Rule COMMENTS_BY_KDOC was implemented (#1350)
Browse files Browse the repository at this point in the history
* New Rule COMMENTS_BY_KDOC was implemented

### What's done:

* New Rule COMMENTS_BY_KDOC was added to check if code block contains kdoc comments
* and fix it by converting to block comment
* tests and docs were added
* Closes: #828
  • Loading branch information
icemachined authored Jun 14, 2022
1 parent 65335c7 commit 48f0c3d
Show file tree
Hide file tree
Showing 17 changed files with 529 additions and 2,282 deletions.
3 changes: 3 additions & 0 deletions diktat-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@
# Checks that underscore is correctly used to split package naming
- name: INCORRECT_PACKAGE_SEPARATOR
enabled: true
# Checks that code block doesn't contain kdoc comments
- name: COMMENTED_BY_KDOC
enabled: true
# Checks that there is no @deprecated tag in kdoc
- name: KDOC_NO_DEPRECATED_TAG
enabled: true
Expand Down
2 changes: 2 additions & 0 deletions diktat-rules/src/main/kotlin/generated/WarningNames.kt
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ public object WarningNames {

public const val COMMENTED_OUT_CODE: String = "COMMENTED_OUT_CODE"

public const val COMMENTED_BY_KDOC: String = "COMMENTED_BY_KDOC"

public const val WRONG_NEWLINES_AROUND_KDOC: String = "WRONG_NEWLINES_AROUND_KDOC"

public const val FIRST_COMMENT_NO_BLANK_LINE: String = "FIRST_COMMENT_NO_BLANK_LINE"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ enum class Warnings(
HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE(false, "2.2.1", "files that contain multiple or no classes should contain description of what is inside of this file"),
HEADER_NOT_BEFORE_PACKAGE(true, "2.2.1", "header KDoc should be placed before package and imports"),
COMMENTED_OUT_CODE(false, "2.4.2", "you should not comment out code, use VCS to save it in history and delete this block"),
COMMENTED_BY_KDOC(true, "2.1.1", "you should not comment inside code blocks using kdoc syntax"),
WRONG_NEWLINES_AROUND_KDOC(true, "2.4.1", "there should be a blank line above the kDoc and there should not be no blank lines after kDoc"),
FIRST_COMMENT_NO_BLANK_LINE(true, "2.4.1", "there should not be any blank lines before first comment"),
COMMENT_WHITE_SPACE(true, "2.4.1", "there should be a white space between code and comment also between code start token and comment text"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.cqfn.diktat.ruleset.rules.DiktatRule
import org.cqfn.diktat.ruleset.utils.*

import com.pinterest.ktlint.core.ast.ElementType
import com.pinterest.ktlint.core.ast.ElementType.BLOCK
import com.pinterest.ktlint.core.ast.ElementType.BLOCK_COMMENT
import com.pinterest.ktlint.core.ast.ElementType.CLASS
import com.pinterest.ktlint.core.ast.ElementType.CLASS_BODY
Expand All @@ -35,6 +36,7 @@ import com.pinterest.ktlint.core.ast.parent
import com.pinterest.ktlint.core.ast.prevSibling
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiCommentImpl
import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl
import org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet
import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
Expand Down Expand Up @@ -67,13 +69,30 @@ class KdocComments(configRules: List<RulesConfig>) : DiktatRule(
CLASS -> checkClassElements(node)
VALUE_PARAMETER -> checkValueParameter(node)
PRIMARY_CONSTRUCTOR -> checkParameterList(node.findChildByType(VALUE_PARAMETER_LIST))
BLOCK -> checkKdocPresent(node)
else -> {
// this is a generated else block
}
}
}
}

private fun checkKdocPresent(node: ASTNode) {
node.findChildrenMatching { it.elementType == KDOC }.forEach {
warnKdocInsideBlock(it)
}
}

private fun warnKdocInsideBlock(kdocNode: ASTNode) {
Warnings.COMMENTED_BY_KDOC.warnAndFix(
configRules, emitWarn, isFixMode,
"Redundant asterisk in block comment: \\**", kdocNode.startOffset, kdocNode
) {
kdocNode.treeParent.addChild(PsiCommentImpl(BLOCK_COMMENT, kdocNode.text.replace("/**", "/*")), kdocNode)
kdocNode.treeParent.removeChild(kdocNode)
}
}

private fun checkParameterList(node: ASTNode?) {
val kdocBeforeClass = node
?.parent({ it.elementType == CLASS })
Expand Down Expand Up @@ -299,10 +318,11 @@ class KdocComments(configRules: List<RulesConfig>) : DiktatRule(
}
}

private fun checkTopLevelDoc(node: ASTNode) =
private fun checkTopLevelDoc(node: ASTNode) {
// checking that all top level class declarations and functions have kDoc
(node.getAllChildrenWithType(CLASS) + node.getAllChildrenWithType(FUN))
return (node.getAllChildrenWithType(CLASS) + node.getAllChildrenWithType(FUN))
.forEach { checkDoc(it, MISSING_KDOC_TOP_LEVEL) }
}

/**
* raises warning if protected, public or internal code element does not have a Kdoc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class ExtensionFunctionsSameNameRule(configRules: List<RulesConfig>) : DiktatRul
listOf(EXTENSION_FUNCTION_SAME_SIGNATURE)
) {
override fun logic(node: ASTNode) {
/**
/*
* 1) Collect all classes that extend other classes (collect related classes)
* 2) Collect all extension functions with same signature
* 3) Check if classes of functions are related
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -845,9 +845,9 @@ private fun ASTNode.findOffsetByLine(line: Int, positionByOffset: (Int) -> Pair<
val currentOffset = this.startOffset

var forwardDirection = true

// We additionaly consider the offset and line for current node in aim to speed up the search
// and not start any time from beginning of file, if possible
//
// If current line is closer to the requested line, start search from it
// otherwise search from the beginning of file
var lineOffset = if (line < currentLine) {
Expand Down
3 changes: 3 additions & 0 deletions diktat-rules/src/main/resources/diktat-analysis-huawei.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@
# Checks that underscore is correctly used to split package naming
- name: INCORRECT_PACKAGE_SEPARATOR
enabled: true
# Checks that code block doesn't contain kdoc comments
- name: COMMENTED_BY_KDOC
enabled: true
# Checks that there is no @deprecated tag in kdoc
- name: KDOC_NO_DEPRECATED_TAG
enabled: true
Expand Down
3 changes: 3 additions & 0 deletions diktat-rules/src/main/resources/diktat-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@
# Checks that underscore is correctly used to split package naming
- name: INCORRECT_PACKAGE_SEPARATOR
enabled: true
# Checks that code block doesn't contain kdoc comments
- name: COMMENTED_BY_KDOC
enabled: true
# Checks that there is no @deprecated tag in kdoc
- name: KDOC_NO_DEPRECATED_TAG
enabled: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import org.junit.jupiter.api.Tag
import org.junit.jupiter.api.Test

class KdocCommentsFixTest : FixTestBase("test/paragraph2/kdoc/", ::KdocComments) {
@Test
@Tag(WarningNames.COMMENTED_BY_KDOC)
fun `check fix code block with kdoc comment`() {
fixAndCompare("KdocBlockCommentExpected.kt", "KdocBlockCommentTest.kt")
}

@Test
@Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY)
fun `check fix with class kdoc`() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.cqfn.diktat.ruleset.chapter2

import org.cqfn.diktat.ruleset.constants.Warnings
import org.cqfn.diktat.ruleset.constants.Warnings.KDOC_EXTRA_PROPERTY
import org.cqfn.diktat.ruleset.constants.Warnings.KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER
import org.cqfn.diktat.ruleset.constants.Warnings.KDOC_NO_CONSTRUCTOR_PROPERTY
Expand All @@ -19,6 +20,42 @@ import org.junit.jupiter.api.Test
class KdocCommentsWarnTest : LintTestBase(::KdocComments) {
private val ruleId: String = "$DIKTAT_RULE_SET_ID:${KdocComments.NAME_ID}"

@Test
@Tag(WarningNames.COMMENTED_BY_KDOC)
fun `Should warn if kdoc comment is inside code block`() {
val code =
"""
|package org.cqfn.diktat.example
|
|/**
| * right place for kdoc
| */
|class Example {
|/**
| * right place for kdoc
| */
| fun doGood(){
| /**
| * wrong place for kdoc
| */
| 1+2
| /**
| * right place for kdoc
| */
| fun prettyPrint(level: Int = 0, maxLevel: Int = -1): String {
| return "test"
| }
| }
|}
""".trimMargin()
lintMethod(
code,
LintError(
11, 9, ruleId, "${Warnings.COMMENTED_BY_KDOC.warnText()} Redundant asterisk in block comment: \\**", true
)
)
}

@Test
@Tag(WarningNames.MISSING_KDOC_TOP_LEVEL)
fun `all public classes should be documented with KDoc`() {
Expand All @@ -39,7 +76,8 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) {
}
""".trimIndent()
lintMethod(code,
lintMethod(
code,
LintError(1, 1, ruleId, "${MISSING_KDOC_TOP_LEVEL.warnText()} SomeGoodName"),
LintError(6, 1, ruleId, "${MISSING_KDOC_TOP_LEVEL.warnText()} SomeOtherGoodName"),
LintError(9, 1, ruleId, "${MISSING_KDOC_TOP_LEVEL.warnText()} SomeNewGoodName"),
Expand All @@ -55,8 +93,10 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) {
internal class SomeGoodName {
}
""".trimIndent()
lintMethod(code, LintError(
1, 1, ruleId, "${MISSING_KDOC_TOP_LEVEL.warnText()} SomeGoodName")
lintMethod(
code, LintError(
1, 1, ruleId, "${MISSING_KDOC_TOP_LEVEL.warnText()} SomeGoodName"
)
)
}

Expand All @@ -71,10 +111,11 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) {
internal fun someGoodNameNew(): String {
return " ";
}
fun main() {}
""".trimIndent()
lintMethod(code,
lintMethod(
code,
LintError(1, 1, ruleId, "${MISSING_KDOC_TOP_LEVEL.warnText()} someGoodName"),
LintError(4, 1, ruleId, "${MISSING_KDOC_TOP_LEVEL.warnText()} someGoodNameNew")
)
Expand Down Expand Up @@ -124,11 +165,12 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) {
private class InternalClass {
}
public fun main() {}
}
""".trimIndent()
lintMethod(code,
lintMethod(
code,
LintError(5, 5, ruleId, "${MISSING_KDOC_CLASS_ELEMENTS.warnText()} variable"),
LintError(7, 5, ruleId, "${MISSING_KDOC_CLASS_ELEMENTS.warnText()} perfectFunction"),
LintError(13, 5, ruleId, "${MISSING_KDOC_CLASS_ELEMENTS.warnText()} InternalClass")
Expand Down Expand Up @@ -158,11 +200,12 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) {
private class InternalClass {
}
public fun main() {}
}
""".trimIndent()
lintMethod(code,
lintMethod(
code,
LintError(5, 5, ruleId, "${MISSING_KDOC_CLASS_ELEMENTS.warnText()} variable"),
LintError(8, 5, ruleId, "${MISSING_KDOC_CLASS_ELEMENTS.warnText()} perfectFunction"),
LintError(14, 5, ruleId, "${MISSING_KDOC_CLASS_ELEMENTS.warnText()} InternalClass")
Expand Down Expand Up @@ -193,7 +236,8 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) {
private class InternalClass {
}
}
""".trimIndent())
""".trimIndent()
)
}

@Test
Expand Down Expand Up @@ -374,7 +418,7 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) {
| * some descriptions
| * @return fdv
| */
|
|
| val name: String,
| anotherName: String,
| OneMoreName: String
Expand All @@ -398,7 +442,7 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) {
| * sdcjkh
| * @property name text2
| */
| val name: String,
| val name: String,
| ) {
|}
""".trimMargin(),
Expand All @@ -415,7 +459,7 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) {
| * text
| */
|class Example (
| private val name: String,
| private val name: String,
| ) {
|}
""".trimMargin()
Expand All @@ -432,7 +476,7 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) {
| * @property
| */
|class Example (
| val name: String,
| val name: String,
| ) {
|}
""".trimMargin(),
Expand All @@ -447,7 +491,7 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) {
lintMethod(
"""
|class Example (
| val name: String,
| val name: String,
| private val surname: String
| ) {
|}
Expand All @@ -467,7 +511,7 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) {
| * @property kek
| */
|class Example (
| val name: String,
| val name: String,
| private val surname: String
| ) {
|}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package test.paragraph2.kdoc

/**
* Converts this AST node and all its children to pretty string representation
*/
@Suppress("AVOID_NESTED_FUNCTIONS")
fun Example.prettyPrint(level: Int = 0, maxLevel: Int = -1): String {
/**
* AST operates with \n only, so we need to build the whole string representation and then change line separator
*/
fun Example.doPrettyPrint(level: Int, maxLevel: Int): String {
return "test" + level + maxLevel
}
return doPrettyPrint(level, maxLevel).replace("\n", System.lineSeparator())
}

/**
* right place for kdoc
*/
class Example {
/**
* right place for kdoc
*/
fun doGood() {
/*
* wrong place for kdoc
*/
/*
* right place for block comment
*/
// right place for eol comment
1 + 2
/**
* Converts this AST node and all its children to pretty string representation
*/
fun Example.prettyPrint(level: Int = 0, maxLevel: Int = -1): String {
return "test"
}
}
}
Loading

0 comments on commit 48f0c3d

Please sign in to comment.