diff --git a/diktat-analysis.yml b/diktat-analysis.yml index a6a0163678..2010f51806 100644 --- a/diktat-analysis.yml +++ b/diktat-analysis.yml @@ -254,6 +254,9 @@ # Checks that property in constructor doesn't contains comment - name: KDOC_NO_CONSTRUCTOR_PROPERTY enabled: true +# Checks that property in KDoc present in class +- name: KDOC_EXTRA_PROPERTY + enabled: true # Checks that KDoc in constructor has property tag but with comment inside constructor - name: KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT enabled: true diff --git a/diktat-rules/src/main/kotlin/generated/WarningNames.kt b/diktat-rules/src/main/kotlin/generated/WarningNames.kt index a73ff5a170..52735c2a16 100644 --- a/diktat-rules/src/main/kotlin/generated/WarningNames.kt +++ b/diktat-rules/src/main/kotlin/generated/WarningNames.kt @@ -81,6 +81,8 @@ public object WarningNames { public const val KDOC_NO_CONSTRUCTOR_PROPERTY: String = "KDOC_NO_CONSTRUCTOR_PROPERTY" + public const val KDOC_EXTRA_PROPERTY: String = "KDOC_EXTRA_PROPERTY" + public const val KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT: String = "KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT" 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 f1b5c13b65..e0c7f06f0e 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 @@ -65,6 +65,7 @@ enum class Warnings( KDOC_NO_EMPTY_TAGS(false, "2.2.1", "no empty descriptions in tag blocks are allowed"), KDOC_NO_DEPRECATED_TAG(true, "2.1.3", "KDoc doesn't support @deprecated tag, use @Deprecated annotation instead"), KDOC_NO_CONSTRUCTOR_PROPERTY(true, "2.1.1", "all properties from the primary constructor should be documented in a @property tag in KDoc"), + KDOC_EXTRA_PROPERTY(false, "2.1.1", "There is property in KDoc which is not present in the class"), KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT(true, "2.1.1", "replace comment before property with @property tag in class KDoc"), HEADER_WRONG_FORMAT(true, "2.2.1", "file header comments should be properly formatted"), HEADER_MISSING_OR_WRONG_COPYRIGHT(true, "2.2.1", "file header comment must include copyright information inside a block comment"), diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/kdoc/KdocComments.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/kdoc/KdocComments.kt index c10caefd61..07d89af058 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/kdoc/KdocComments.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/kdoc/KdocComments.kt @@ -4,24 +4,12 @@ import org.cqfn.diktat.common.config.rules.RulesConfig import org.cqfn.diktat.common.config.rules.getCommonConfiguration import org.cqfn.diktat.ruleset.constants.EmitType 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_CONSTRUCTOR_PROPERTY import org.cqfn.diktat.ruleset.constants.Warnings.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT import org.cqfn.diktat.ruleset.constants.Warnings.MISSING_KDOC_CLASS_ELEMENTS import org.cqfn.diktat.ruleset.constants.Warnings.MISSING_KDOC_TOP_LEVEL -import org.cqfn.diktat.ruleset.utils.KotlinParser -import org.cqfn.diktat.ruleset.utils.getAllChildrenWithType -import org.cqfn.diktat.ruleset.utils.getFileName -import org.cqfn.diktat.ruleset.utils.getFirstChildWithType -import org.cqfn.diktat.ruleset.utils.getIdentifierName -import org.cqfn.diktat.ruleset.utils.getRootNode -import org.cqfn.diktat.ruleset.utils.hasChildOfType -import org.cqfn.diktat.ruleset.utils.hasTestAnnotation -import org.cqfn.diktat.ruleset.utils.isAccessibleOutside -import org.cqfn.diktat.ruleset.utils.isLocatedInTest -import org.cqfn.diktat.ruleset.utils.isOverridden -import org.cqfn.diktat.ruleset.utils.isStandardMethod -import org.cqfn.diktat.ruleset.utils.kDocTags -import org.cqfn.diktat.ruleset.utils.splitPathToDirs +import org.cqfn.diktat.ruleset.utils.* import com.pinterest.ktlint.core.Rule import com.pinterest.ktlint.core.ast.ElementType.BLOCK_COMMENT @@ -38,6 +26,7 @@ import com.pinterest.ktlint.core.ast.ElementType.MODIFIER_LIST import com.pinterest.ktlint.core.ast.ElementType.PRIMARY_CONSTRUCTOR import com.pinterest.ktlint.core.ast.ElementType.PROPERTY import com.pinterest.ktlint.core.ast.ElementType.VALUE_PARAMETER +import com.pinterest.ktlint.core.ast.ElementType.VALUE_PARAMETER_LIST import com.pinterest.ktlint.core.ast.ElementType.VAL_KEYWORD import com.pinterest.ktlint.core.ast.ElementType.VAR_KEYWORD import com.pinterest.ktlint.core.ast.ElementType.WHITE_SPACE @@ -47,6 +36,7 @@ import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement 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 +import org.jetbrains.kotlin.psi.KtParameterList import org.jetbrains.kotlin.psi.psiUtil.parents /** @@ -79,6 +69,7 @@ class KdocComments(private val configRules: List) : Rule("kdoc-comm FILE -> checkTopLevelDoc(node) CLASS -> checkClassElements(node) VALUE_PARAMETER -> checkValueParameter(node) + PRIMARY_CONSTRUCTOR -> checkParameterList(node.findChildByType(VALUE_PARAMETER_LIST)) else -> { // this is a generated else block } @@ -86,6 +77,21 @@ class KdocComments(private val configRules: List) : Rule("kdoc-comm } } + private fun checkParameterList(node: ASTNode?) { + val kdocBeforeClass = node + ?.parent({ it.elementType == CLASS }) + ?.findChildByType(KDOC) ?: return + val propertiesInKdoc = kdocBeforeClass + .kDocTags() + ?.filter { it.knownTag == KDocKnownTag.PROPERTY} + val propertyNames = (node.psi as KtParameterList) + .parameters + .mapNotNull { it.nameIdentifier?.text } + propertiesInKdoc + ?.filterNot { it.getSubjectName() == null || it.getSubjectName() in propertyNames } + ?.forEach { KDOC_EXTRA_PROPERTY.warn(configRules, emitWarn, isFixMode, it.text, it.node.startOffset, node) } + } + @Suppress("UnsafeCallOnNullableType", "ComplexMethod") private fun checkValueParameter(node: ASTNode) { if (node.parents().none { it.elementType == PRIMARY_CONSTRUCTOR } || diff --git a/diktat-rules/src/main/resources/diktat-analysis-huawei.yml b/diktat-rules/src/main/resources/diktat-analysis-huawei.yml index 562e152463..99342d1c1e 100644 --- a/diktat-rules/src/main/resources/diktat-analysis-huawei.yml +++ b/diktat-rules/src/main/resources/diktat-analysis-huawei.yml @@ -252,6 +252,9 @@ # Checks that property in constructor doesn't contains comment - name: KDOC_NO_CONSTRUCTOR_PROPERTY enabled: true +# Checks that property in KDoc present in class +- name: KDOC_EXTRA_PROPERTY + enabled: true # Checks that KDoc in constructor has property tag but with comment inside constructor - name: KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT enabled: true diff --git a/diktat-rules/src/main/resources/diktat-analysis.yml b/diktat-rules/src/main/resources/diktat-analysis.yml index 9030e614e5..05983b1d53 100644 --- a/diktat-rules/src/main/resources/diktat-analysis.yml +++ b/diktat-rules/src/main/resources/diktat-analysis.yml @@ -254,6 +254,9 @@ # Checks that KDoc in constructor has property tag - name: KDOC_NO_CONSTRUCTOR_PROPERTY enabled: true +# Checks that property in KDoc present in class +- name: KDOC_EXTRA_PROPERTY + enabled: true # Checks that KDoc in constructor has property tag but with comment inside constructor - name: KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT enabled: true diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/KdocCommentsWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/KdocCommentsWarnTest.kt index 106ff33cf1..33f3376a88 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/KdocCommentsWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter2/KdocCommentsWarnTest.kt @@ -1,5 +1,6 @@ package org.cqfn.diktat.ruleset.chapter2 +import org.cqfn.diktat.ruleset.constants.Warnings.KDOC_EXTRA_PROPERTY import org.cqfn.diktat.ruleset.constants.Warnings.KDOC_NO_CONSTRUCTOR_PROPERTY import org.cqfn.diktat.ruleset.constants.Warnings.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT import org.cqfn.diktat.ruleset.constants.Warnings.MISSING_KDOC_CLASS_ELEMENTS @@ -408,19 +409,21 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) { } @Test - @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY) + @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY), Tag(WarningNames.KDOC_EXTRA_PROPERTY)) fun `no property kdoc`() { lintMethod( """ |/** | * @property Name text + | * @property | */ |class Example ( | val name: String, | ) { |} """.trimMargin(), - LintError(5, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add to KDoc", true) + LintError(2, 4, ruleId, "${KDOC_EXTRA_PROPERTY.warnText()} @property Name text", false), + LintError(6, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add to KDoc", true) ) } @@ -439,4 +442,23 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) { LintError(2, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add to KDoc", true) ) } + + @Test + @Tag(WarningNames.KDOC_EXTRA_PROPERTY) + fun `extra property in kdoc`() { + lintMethod( + """ + |/** + | * @property name bla + | * @property kek + | */ + |class Example ( + | val name: String, + | private val surname: String + | ) { + |} + """.trimMargin(), + LintError(3, 4, ruleId, "${KDOC_EXTRA_PROPERTY.warnText()} @property kek", false) + ) + } } diff --git a/info/available-rules.md b/info/available-rules.md index e67aa65cfb..481807504e 100644 --- a/info/available-rules.md +++ b/info/available-rules.md @@ -37,6 +37,7 @@ | 2 | 2.3 | KDOC_NO_EMPTY_TAGS | Check: warns if KDoc tags have empty content | no | || | 2 | 2.3 | KDOC_NO_DEPRECATED_TAG | Check: warns if `@deprecated` is used in KDoc
Fix: adds `@Deprecated` annotation with message, removes tag | yes | |Annotation's `replaceWith` field can be filled too| | 2 | 2.3 | KDOC_NO_CONSTRUCTOR_PROPERTY | Check: warns if there is no property tag inside KDoc before constructor | yes | -| +| 2 | 2.3 | KDOC_EXTRA_PROPERTY | Check: warns if there is property in KDoc which doesn't exist in class | no | - | - | | 2 | 2.3 | KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT | Check: warns if there is comment before property in constructor | yes | -| | 2 | 2.5 | KDOC_TRIVIAL_KDOC_ON_FUNCTION | Check: warns if KDoc contains single line with words 'return', 'get' or 'set' | no | - | | 2 | 2.4 | HEADER_WRONG_FORMAT | Checks: warns if there is no newline after header KDoc
Fix: adds newline | yes | |Check if header is on the very top of file. It's hard to determine when it's not.|