From 71c81d4354aa8b20a7c73312491793010cefafb3 Mon Sep 17 00:00:00 2001 From: Alexander Drugakov Date: Mon, 16 Oct 2023 13:04:50 +0300 Subject: [PATCH] Fixed KdocComments (#1754) ### What's done: - Changed warning `KDOC_NO_CONSTRUCTOR_PROPERTY` to `KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT` in some cases when property or parameter has comment before. - Added check is warning `KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT` fixable for case when property or parameter has any tags in KDoc-comment before. If it has = non-fixed. - Added configuration for `@param` tags creation: `isParamTagsForParameters` and `isParamTagsForPrivateProperties`. - Added fixed warnings `KDOC_NO_CONSTRUCTOR_PROPERTY` and `KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT` for cases when configuration options are on, and then `private` properties and parameters must have `@param` tags in class-KDoc. Additionally added logic for replacing incorrect tag with correct one regardless of whether configuration is enabled or not. - Added non-fixed warning `KDOC_EXTRA_PROPERTY` for redundant `@param` tags in class-KDoc. - Reworked fix tests. Added tests for cases when `@property` or `@param` tag exist in class-KDoc. - Added new warning tests. It's part of #1737 --- diktat-analysis.yml | 3 + .../com/saveourtool/diktat/DiktatRunner.kt | 2 +- .../saveourtool/diktat/DiktatRunnerFactory.kt | 6 + .../diktat/cli/DiktatProperties.kt | 3 + .../diktat/common/cli/CliArgument.kt | 9 +- .../generation/EnumNamesSymbolProcessor.kt | 2 + .../diktat/plugin/gradle/DiktatExtension.kt | 2 + .../plugin/gradle/tasks/DiktatTaskBase.kt | 2 + .../diktat/ktlint/DiktatReporterImpl.kt | 3 + .../diktat/ruleset/constants/Warnings.kt | 2 + .../diktat/ruleset/rules/DiktatRule.kt | 2 +- .../rules/chapter2/kdoc/KdocComments.kt | 516 +++++++++++++----- .../chapter3/MultipleModifiersSequence.kt | 2 +- .../rules/chapter3/files/TopLevelOrderRule.kt | 7 + .../main/resources/diktat-analysis-huawei.yml | 3 + .../src/main/resources/diktat-analysis.yml | 3 + .../ruleset/chapter2/KdocCommentsFixTest.kt | 19 +- .../ruleset/chapter2/KdocCommentsWarnTest.kt | 208 +++++-- .../kdoc/ConstructorCommentExpected.kt | 314 ++++++++++- .../kdoc/ConstructorCommentNewlineExpected.kt | 19 +- .../kdoc/ConstructorCommentNewlineTest.kt | 11 +- .../kdoc/ConstructorCommentNoKDocExpected.kt | 253 +++++++-- .../kdoc/ConstructorCommentNoKDocTest.kt | 241 +++++++- .../ConstructorCommentPropertiesExpected.kt | 261 +++++++++ .../kdoc/ConstructorCommentPropertiesTest.kt | 289 ++++++++++ .../paragraph2/kdoc/ConstructorCommentTest.kt | 321 ++++++++++- .../framework/common/LocalCommandExecutor.kt | 3 + .../framework/config/TestArgumentsReader.kt | 2 +- .../framework/processing/FileComparator.kt | 4 + .../processing/TestComparatorUnit.kt | 4 +- .../processing/TestProcessingFactory.kt | 2 + info/available-rules.md | 262 ++++----- 32 files changed, 2346 insertions(+), 434 deletions(-) create mode 100644 diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentPropertiesExpected.kt create mode 100644 diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentPropertiesTest.kt diff --git a/diktat-analysis.yml b/diktat-analysis.yml index 523c1d222b..86c7026405 100644 --- a/diktat-analysis.yml +++ b/diktat-analysis.yml @@ -450,6 +450,9 @@ # Checks that property in constructor doesn't contain comment - name: KDOC_NO_CONSTRUCTOR_PROPERTY enabled: true + configuration: + isParamTagsForParameters: false # create param tags for parameters without val or var + isParamTagsForPrivateProperties: false # create param tags for private properties # Checks that property in KDoc present in class - name: KDOC_EXTRA_PROPERTY enabled: true diff --git a/diktat-api/src/main/kotlin/com/saveourtool/diktat/DiktatRunner.kt b/diktat-api/src/main/kotlin/com/saveourtool/diktat/DiktatRunner.kt index b3f5d6181c..de2503758c 100644 --- a/diktat-api/src/main/kotlin/com/saveourtool/diktat/DiktatRunner.kt +++ b/diktat-api/src/main/kotlin/com/saveourtool/diktat/DiktatRunner.kt @@ -15,9 +15,9 @@ private typealias RunAction = (DiktatProcessor, DiktatProcessorListener) -> Unit /** * A runner for diktat on bunch of files using baseline and reporter * + * @param diktatBaselineGenerator * @property diktatProcessor * @property diktatBaseline - * @property diktatBaselineGenerator * @property diktatReporter */ data class DiktatRunner( diff --git a/diktat-api/src/main/kotlin/com/saveourtool/diktat/DiktatRunnerFactory.kt b/diktat-api/src/main/kotlin/com/saveourtool/diktat/DiktatRunnerFactory.kt index 81e0d3cd0c..bb3a946451 100644 --- a/diktat-api/src/main/kotlin/com/saveourtool/diktat/DiktatRunnerFactory.kt +++ b/diktat-api/src/main/kotlin/com/saveourtool/diktat/DiktatRunnerFactory.kt @@ -5,7 +5,9 @@ import com.saveourtool.diktat.api.DiktatBaselineFactory import com.saveourtool.diktat.api.DiktatProcessorListener import com.saveourtool.diktat.api.DiktatReporter import com.saveourtool.diktat.api.DiktatReporterFactory +import com.saveourtool.diktat.api.DiktatRuleConfig import com.saveourtool.diktat.api.DiktatRuleConfigReader +import com.saveourtool.diktat.api.DiktatRuleSet import com.saveourtool.diktat.api.DiktatRuleSetFactory import java.io.OutputStream import java.nio.file.Path @@ -13,6 +15,10 @@ import java.nio.file.Path /** * A factory to create [DiktatRunner] * + * @param diktatRuleConfigReader a reader for [DiktatRuleConfig] + * @param diktatRuleSetFactory a factory for [DiktatRuleSet] + * @param diktatProcessorFactory a factory for [DiktatProcessor] + * @param diktatBaselineFactory a factory for [DiktatBaseline] * @property diktatReporterFactory a factory for [DiktatReporter] */ class DiktatRunnerFactory( diff --git a/diktat-cli/src/main/kotlin/com/saveourtool/diktat/cli/DiktatProperties.kt b/diktat-cli/src/main/kotlin/com/saveourtool/diktat/cli/DiktatProperties.kt index 562895e618..ad388681bb 100644 --- a/diktat-cli/src/main/kotlin/com/saveourtool/diktat/cli/DiktatProperties.kt +++ b/diktat-cli/src/main/kotlin/com/saveourtool/diktat/cli/DiktatProperties.kt @@ -26,6 +26,9 @@ import kotlinx.cli.default import kotlinx.cli.vararg /** + * @param groupByFileInPlain + * @param colorNameInPlain + * @param logLevel * @property config path to `diktat-analysis.yml` * @property mode mode of `diktat` * @property reporterProviderId diff --git a/diktat-common/src/main/kotlin/com/saveourtool/diktat/common/cli/CliArgument.kt b/diktat-common/src/main/kotlin/com/saveourtool/diktat/common/cli/CliArgument.kt index a24be0a986..319455e313 100644 --- a/diktat-common/src/main/kotlin/com/saveourtool/diktat/common/cli/CliArgument.kt +++ b/diktat-common/src/main/kotlin/com/saveourtool/diktat/common/cli/CliArgument.kt @@ -7,9 +7,12 @@ import kotlinx.serialization.Serializable /** * This class is used to serialize/deserialize json representation * that is used to store command line arguments - * @property shortName short argument representation like -h - * @property longName long argument representation like --help - * @property hasArgs indicates if option should have explicit argument + * + * @param shortName short argument representation like -h + * @param helpDescr + * @param longName long argument representation like --help + * @param hasArgs indicates if option should have explicit argument + * @param isRequired */ @Serializable data class CliArgument( diff --git a/diktat-dev-ksp/src/main/kotlin/com/saveourtool/diktat/ruleset/generation/EnumNamesSymbolProcessor.kt b/diktat-dev-ksp/src/main/kotlin/com/saveourtool/diktat/ruleset/generation/EnumNamesSymbolProcessor.kt index 5ed5e7bd0e..cd046dcead 100644 --- a/diktat-dev-ksp/src/main/kotlin/com/saveourtool/diktat/ruleset/generation/EnumNamesSymbolProcessor.kt +++ b/diktat-dev-ksp/src/main/kotlin/com/saveourtool/diktat/ruleset/generation/EnumNamesSymbolProcessor.kt @@ -11,6 +11,8 @@ import com.google.devtools.ksp.symbol.KSClassDeclaration /** * [SymbolProcessor] to generate a class with contacts for names from provided enum + * + * @param codeGenerator */ class EnumNamesSymbolProcessor( private val codeGenerator: CodeGenerator, diff --git a/diktat-gradle-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/gradle/DiktatExtension.kt b/diktat-gradle-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/gradle/DiktatExtension.kt index e8ba234a88..a51ed2152f 100644 --- a/diktat-gradle-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/gradle/DiktatExtension.kt +++ b/diktat-gradle-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/gradle/DiktatExtension.kt @@ -9,6 +9,8 @@ import java.io.File /** * An extension to configure diktat in build.gradle(.kts) file + * + * @param patternSet */ open class DiktatExtension( private val patternSet: PatternSet diff --git a/diktat-gradle-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/gradle/tasks/DiktatTaskBase.kt b/diktat-gradle-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/gradle/tasks/DiktatTaskBase.kt index 2eb33a1905..dd2e7d9e74 100644 --- a/diktat-gradle-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/gradle/tasks/DiktatTaskBase.kt +++ b/diktat-gradle-plugin/src/main/kotlin/com/saveourtool/diktat/plugin/gradle/tasks/DiktatTaskBase.kt @@ -32,6 +32,8 @@ import java.nio.file.Path /** * A base task to run `diktat` + * + * @param inputs * @property extension */ @Suppress("WRONG_NEWLINES", "Deprecation") diff --git a/diktat-ktlint-engine/src/main/kotlin/com/saveourtool/diktat/ktlint/DiktatReporterImpl.kt b/diktat-ktlint-engine/src/main/kotlin/com/saveourtool/diktat/ktlint/DiktatReporterImpl.kt index dcca2964ef..6db144afe5 100644 --- a/diktat-ktlint-engine/src/main/kotlin/com/saveourtool/diktat/ktlint/DiktatReporterImpl.kt +++ b/diktat-ktlint-engine/src/main/kotlin/com/saveourtool/diktat/ktlint/DiktatReporterImpl.kt @@ -8,6 +8,9 @@ import java.nio.file.Path /** * [DiktatReporter] using __KtLint__ + * + * @param ktLintReporter + * @param sourceRootDir */ class DiktatReporterImpl( private val ktLintReporter: ReporterV2, diff --git a/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/constants/Warnings.kt b/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/constants/Warnings.kt index cba87df812..602f861225 100644 --- a/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/constants/Warnings.kt +++ b/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/constants/Warnings.kt @@ -11,6 +11,8 @@ import org.jetbrains.kotlin.com.intellij.lang.ASTNode /** * This class represent individual inspections of diktat code style. * A [Warnings] entry contains rule name, warning message and is used in code check. + * + * @param warn description of the inspection * @property canBeAutoCorrected whether this inspection can automatically fix the code. Should be public to be able to use it in docs generator. * @property ruleId number of the inspection according to [diktat code style](https://github.com/saveourtool/diktat/blob/master/info/guide/diktat-coding-convention.md) */ diff --git a/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/DiktatRule.kt b/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/DiktatRule.kt index c71470bcc0..8edd933d7c 100644 --- a/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/DiktatRule.kt +++ b/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/DiktatRule.kt @@ -14,9 +14,9 @@ private typealias DiktatRuleApi = com.saveourtool.diktat.api.DiktatRule /** * This is a wrapper around _KtLint_ `com.pinterest.ktlint.core.Rule`. * + * @param inspections warnings that are used in the rule's code * @property id id of the rule * @property configRules all rules from configuration - * @property inspections warnings that are used in the rule's code */ @Suppress("TooGenericExceptionCaught") abstract class DiktatRule( diff --git a/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter2/kdoc/KdocComments.kt b/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter2/kdoc/KdocComments.kt index f6c0969c22..39e38b6531 100644 --- a/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter2/kdoc/KdocComments.kt +++ b/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter2/kdoc/KdocComments.kt @@ -1,8 +1,11 @@ package com.saveourtool.diktat.ruleset.rules.chapter2.kdoc +import com.saveourtool.diktat.common.config.rules.RuleConfiguration import com.saveourtool.diktat.common.config.rules.RulesConfig import com.saveourtool.diktat.common.config.rules.getCommonConfiguration +import com.saveourtool.diktat.common.config.rules.getRuleConfig import com.saveourtool.diktat.ruleset.constants.Warnings +import com.saveourtool.diktat.ruleset.constants.Warnings.COMMENTED_BY_KDOC import com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_DUPLICATE_PROPERTY import com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_EXTRA_PROPERTY import com.saveourtool.diktat.ruleset.constants.Warnings.KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER @@ -20,6 +23,7 @@ import org.jetbrains.kotlin.KtNodeTypes.FUN import org.jetbrains.kotlin.KtNodeTypes.MODIFIER_LIST import org.jetbrains.kotlin.KtNodeTypes.PRIMARY_CONSTRUCTOR import org.jetbrains.kotlin.KtNodeTypes.PROPERTY +import org.jetbrains.kotlin.KtNodeTypes.TYPE_REFERENCE import org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER import org.jetbrains.kotlin.KtNodeTypes.VALUE_PARAMETER_LIST import org.jetbrains.kotlin.com.intellij.lang.ASTNode @@ -29,7 +33,9 @@ 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.lexer.KDocTokens import org.jetbrains.kotlin.kdoc.lexer.KDocTokens.KDOC +import org.jetbrains.kotlin.kdoc.parser.KDocElementTypes import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag +import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens.BLOCK_COMMENT import org.jetbrains.kotlin.lexer.KtTokens.EOL_COMMENT @@ -37,7 +43,6 @@ import org.jetbrains.kotlin.lexer.KtTokens.IDENTIFIER import org.jetbrains.kotlin.lexer.KtTokens.VAL_KEYWORD import org.jetbrains.kotlin.lexer.KtTokens.VAR_KEYWORD import org.jetbrains.kotlin.lexer.KtTokens.WHITE_SPACE -import org.jetbrains.kotlin.psi.KtParameterList import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.psi.psiUtil.siblings import org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType @@ -46,23 +51,27 @@ import org.jetbrains.kotlin.psi.stubs.elements.KtFileElementType * This rule checks the following features in KDocs: * 1) All top-level (file level) functions and classes with public or internal access should have KDoc * 2) All internal elements in class like class, property or function should be documented with KDoc - * 3) All properties declared in the primary constructor are documented using `@property` tag in class KDoc + * 3) All non-private properties declared in the primary constructor are documented using `@property` tag in class KDoc */ class KdocComments(configRules: List) : DiktatRule( NAME_ID, configRules, listOf(KDOC_EXTRA_PROPERTY, KDOC_NO_CONSTRUCTOR_PROPERTY, KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT, MISSING_KDOC_CLASS_ELEMENTS, MISSING_KDOC_TOP_LEVEL, - KDOC_DUPLICATE_PROPERTY + KDOC_DUPLICATE_PROPERTY, COMMENTED_BY_KDOC ) ) { - private val config by lazy { configRules.getCommonConfiguration() } + private val configuration by lazy { + KdocCommentsConfiguration(configRules.getRuleConfig(KDOC_NO_CONSTRUCTOR_PROPERTY)?.configuration ?: emptyMap()) + } /** * @param node */ override fun logic(node: ASTNode) { val filePath = node.getFilePath() + val config = configRules.getCommonConfiguration() + if (!node.hasTestAnnotation() && !isLocatedInTest(filePath.splitPathToDirs(), config.testAnchors)) { when (node.elementType) { KtFileElementType.INSTANCE -> checkTopLevelDoc(node) @@ -84,7 +93,7 @@ class KdocComments(configRules: List) : DiktatRule( } private fun warnKdocInsideBlock(kdocNode: ASTNode) { - Warnings.COMMENTED_BY_KDOC.warnAndFix( + COMMENTED_BY_KDOC.warnAndFix( configRules, emitWarn, isFixMode, "Redundant asterisk in block comment: \\**", kdocNode.startOffset, kdocNode ) { @@ -98,25 +107,26 @@ class KdocComments(configRules: List) : DiktatRule( ?.parent { it.elementType == CLASS } ?.findChildByType(KDOC) ?: return - val propertiesInKdoc = kdocBeforeClass + val parametersInKdoc = 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 } + .filter { it.knownTag == KDocKnownTag.PROPERTY || it.knownTag == KDocKnownTag.PARAM } + + val parametersInConstructor = node + .findChildrenMatching { it.elementType == VALUE_PARAMETER } + .mapNotNull { it.findChildByType(IDENTIFIER)?.text } + + parametersInKdoc + .filterNot { it.getSubjectName() == null || it.getSubjectName() in parametersInConstructor } .forEach { KDOC_EXTRA_PROPERTY.warn(configRules, emitWarn, it.text, it.node.startOffset, node) } } @Suppress("UnsafeCallOnNullableType", "ComplexMethod") private fun checkValueParameter(valueParameterNode: ASTNode) { if (valueParameterNode.parents().none { it.elementType == PRIMARY_CONSTRUCTOR } || - !valueParameterNode.hasChildOfType(VAL_KEYWORD) && - !valueParameterNode.hasChildOfType(VAR_KEYWORD) - ) { + valueParameterNode.parents().any { it.elementType == TYPE_REFERENCE }) { return } + val prevComment = if (valueParameterNode.siblings(forward = false) .takeWhile { it.elementType != EOL_COMMENT && it.elementType != BLOCK_COMMENT } .all { it.elementType == WHITE_SPACE } @@ -128,68 +138,151 @@ class KdocComments(configRules: List) : DiktatRule( } else { null } + val kdocBeforeClass = valueParameterNode.parent { it.elementType == CLASS }!!.findChildByType(KDOC) + val isParamTagNeeded = (!valueParameterNode.hasChildOfType(VAL_KEYWORD) && !valueParameterNode.hasChildOfType(VAR_KEYWORD)) || + !valueParameterNode.getFirstChildWithType(MODIFIER_LIST).isAccessibleOutside() prevComment?.let { kdocBeforeClass?.let { - checkKdocBeforeClass(valueParameterNode, kdocBeforeClass, prevComment) + checkKdocBeforeClass(valueParameterNode, kdocBeforeClass, prevComment, isParamTagNeeded) } - ?: createKdocWithProperty(valueParameterNode, prevComment) + ?: createKdocWithProperty(valueParameterNode, prevComment, isParamTagNeeded) } ?: kdocBeforeClass?.let { - checkBasicKdocBeforeClass(valueParameterNode, kdocBeforeClass) + checkBasicKdocBeforeClass(valueParameterNode, kdocBeforeClass, isParamTagNeeded) } - ?: createKdocBasicKdoc(valueParameterNode) + ?: createKdocBasicKdoc(valueParameterNode, isParamTagNeeded) } - @Suppress("UnsafeCallOnNullableType") - private fun checkBasicKdocBeforeClass(node: ASTNode, kdocBeforeClass: ASTNode) { - val propertyInClassKdoc = kdocBeforeClass + @Suppress("UnsafeCallOnNullableType", "ComplexMethod") + private fun checkBasicKdocBeforeClass( + node: ASTNode, + kdocBeforeClass: ASTNode, + isParamTagNeeded: Boolean + ) { + val parameterName = node.findChildByType(IDENTIFIER)!!.text + val parameterTagInClassKdoc = kdocBeforeClass .kDocTags() - .firstOrNull { it.knownTag == KDocKnownTag.PROPERTY && it.getSubjectName() == node.findChildByType(IDENTIFIER)!!.text } - if (propertyInClassKdoc == null && node.getFirstChildWithType(MODIFIER_LIST).isAccessibleOutside()) { - KDOC_NO_CONSTRUCTOR_PROPERTY.warnAndFix(configRules, emitWarn, isFixMode, - "add <${node.findChildByType(IDENTIFIER)!!.text}> to KDoc", node.startOffset, node) { - insertTextInKdoc(kdocBeforeClass, " * @property ${node.findChildByType(IDENTIFIER)!!.text}\n") + .firstOrNull { (it.knownTag == KDocKnownTag.PARAM || it.knownTag == KDocKnownTag.PROPERTY) && it.getSubjectName() == parameterName } + + parameterTagInClassKdoc?.let { + val correctTag = if (isParamTagNeeded) KDocKnownTag.PARAM else KDocKnownTag.PROPERTY + + if (parameterTagInClassKdoc.knownTag != correctTag) { + val warningText = if (isParamTagNeeded) { + "change `@property` tag to `@param` tag for <$parameterName> to KDoc" + } else { + "change `@param` tag to `@property` tag for <$parameterName> to KDoc" + } + + KDOC_NO_CONSTRUCTOR_PROPERTY.warnAndFix(configRules, emitWarn, isFixMode, warningText, node.startOffset, node) { + val isFirstTagInKdoc = parameterTagInClassKdoc.node == kdocBeforeClass.kDocTags().first().node + replaceWrongTagInClassKdoc(kdocBeforeClass, parameterName, isParamTagNeeded, isFirstTagInKdoc) + } + } + } ?: run { + val isParameter = !node.hasChildOfType(VAL_KEYWORD) && !node.hasChildOfType(VAR_KEYWORD) + val isPrivateProperty = !node.getFirstChildWithType(MODIFIER_LIST).isAccessibleOutside() + + if (!isParamTagNeeded || (isParameter && configuration.isParamTagsForParameters) || (isPrivateProperty && configuration.isParamTagsForPrivateProperties)) { + val warningText = if (isParamTagNeeded) "add param <$parameterName> to KDoc" else "add property <$parameterName> to KDoc" + + KDOC_NO_CONSTRUCTOR_PROPERTY.warnAndFix(configRules, emitWarn, isFixMode, warningText, node.startOffset, node) { + val newKdocText = if (isParamTagNeeded) "* @param $parameterName\n " else "* @property $parameterName\n " + insertTextInKdoc(kdocBeforeClass, checkOneNewLineAfterKdocClassDescription(kdocBeforeClass, newKdocText, false)) + } } } } + private fun replaceWrongTagInClassKdoc( + kdocBeforeClass: ASTNode, + parameterName: String, + isParamTagNeeded: Boolean, + isFirstTagInKdoc: Boolean + ) { + val wrongTagText = if (isParamTagNeeded) "* @property $parameterName" else "* @param $parameterName" + val replaceText = if (isParamTagNeeded) "* @param $parameterName" else "* @property $parameterName" + + changeTagInKdoc(kdocBeforeClass, wrongTagText, checkOneNewLineAfterKdocClassDescription(kdocBeforeClass, replaceText, isFirstTagInKdoc)) + } + + @Suppress("UnsafeCallOnNullableType") + private fun changeTagInKdoc( + kdocBeforeClass: ASTNode, + wrongTagText: String, + correctTagText: String + ) { + val allKdocText = kdocBeforeClass.text + val newKdocText = allKdocText.replaceFirst(wrongTagText, correctTagText) + kdocBeforeClass.treeParent.replaceChild(kdocBeforeClass, KotlinParser().createNode(newKdocText).findChildByType(KDOC)!!) + } + @Suppress("UnsafeCallOnNullableType") + private fun checkOneNewLineAfterKdocClassDescription( + kdocBeforeClass: ASTNode, + newKdocText: String, + isFirstTagInKdoc: Boolean + ): String { + val firstDescriptionSection = kdocBeforeClass + .findChildrenMatching { it.elementType == KDocElementTypes.KDOC_SECTION } + .firstOrNull() + val lastTextInDescription = firstDescriptionSection + ?.findChildrenMatching { it.elementType == KDocTokens.TEXT || it.elementType == KDocTokens.CODE_BLOCK_TEXT || it.elementType == KDocTokens.MARKDOWN_LINK } + ?.lastOrNull { it.text.trim().isNotEmpty() } + + val isHasDescription = lastTextInDescription != null + + return newKdocText.let {text -> + if (isHasDescription && (kdocBeforeClass.kDocTags().isEmpty() || isFirstTagInKdoc)) { + // if we have any existing tags and current is first of them, we need to save last three nodes which are KDOC_LEADING_ASTERISK and two WHITE_SPACE around it + // this is necessary so that first tag is on new line immediately after description + val beforeChild = if (isFirstTagInKdoc) firstDescriptionSection!!.lastChildNode.treePrev.treePrev.treePrev else firstDescriptionSection!!.lastChildNode + + // remove all KDOC_LEADING_ASTERISK and WHITE_SPACE between last text in description and end of description + firstDescriptionSection + .findChildrenMatching { + firstDescriptionSection.isChildAfterAnother(it, lastTextInDescription!!) && + (firstDescriptionSection.isChildBeforeAnother(it, beforeChild) || it == beforeChild) + } + .forEach { firstDescriptionSection.removeChild(it) } + + "*\n $text" + } else { + text + } + } + } + private fun checkKdocBeforeClass( node: ASTNode, kdocBeforeClass: ASTNode, - prevComment: ASTNode + prevComment: ASTNode, + isParamTagNeeded: Boolean ) { - val propertyInClassKdoc = kdocBeforeClass - .kDocTags() - .firstOrNull { it.knownTag == KDocKnownTag.PROPERTY && it.getSubjectName() == node.findChildByType(IDENTIFIER)!!.text } - ?.node - val propertyInLocalKdoc = if (prevComment.elementType == KDOC) { - prevComment - .kDocTags() - .firstOrNull { it.knownTag == KDocKnownTag.PROPERTY && it.getSubjectName() == node.findChildByType(IDENTIFIER)!!.text } - ?.node - } else { - null - } if (prevComment.elementType == KDOC || prevComment.elementType == BLOCK_COMMENT) { - // there is a documentation before property that we can extract, and there is class KDoc, where we can move it to - handleKdocAndBlock(node, prevComment, kdocBeforeClass, propertyInClassKdoc, propertyInLocalKdoc) + // there is a documentation before property or parameter that we can extract, and there is class KDoc, where we can move it to + handleKdocAndBlock(node, kdocBeforeClass, prevComment, isParamTagNeeded) } else { - KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnAndFix(configRules, emitWarn, isFixMode, node.findChildByType(IDENTIFIER)!!.text, prevComment.startOffset, node) { - handleCommentBefore(node, kdocBeforeClass, prevComment, propertyInClassKdoc) - } + handleCommentBefore(node, kdocBeforeClass, prevComment, isParamTagNeeded) } } @Suppress("UnsafeCallOnNullableType") - private fun createKdocBasicKdoc(node: ASTNode) { - if (node.getFirstChildWithType(MODIFIER_LIST).isAccessibleOutside() && !node.isOverridden()) { - KDOC_NO_CONSTRUCTOR_PROPERTY.warnAndFix(configRules, emitWarn, isFixMode, - "add <${node.findChildByType(IDENTIFIER)!!.text}> to KDoc", node.startOffset, node) { - val newKdoc = KotlinParser().createNode("/**\n * @property ${node.findChildByType(IDENTIFIER)!!.text}\n */") + private fun createKdocBasicKdoc(node: ASTNode, isParamTagNeeded: Boolean) { + val isParameter = !node.hasChildOfType(VAL_KEYWORD) && !node.hasChildOfType(VAR_KEYWORD) + val isPrivateProperty = !node.getFirstChildWithType(MODIFIER_LIST).isAccessibleOutside() + + if (!isParamTagNeeded || (isParameter && configuration.isParamTagsForParameters) || (isPrivateProperty && configuration.isParamTagsForPrivateProperties)) { + val parameterName = node.findChildByType(IDENTIFIER)!!.text + val warningText = if (isParamTagNeeded) "add param <$parameterName> to KDoc" else "add property <$parameterName> to KDoc" + + KDOC_NO_CONSTRUCTOR_PROPERTY.warnAndFix(configRules, emitWarn, isFixMode, warningText, node.startOffset, node) { val classNode = node.parent { it.elementType == CLASS }!! + val newKdocText = if (isParamTagNeeded) "/**\n * @param $parameterName\n */" else "/**\n * @property $parameterName\n */" + val newKdoc = KotlinParser().createNode(newKdocText) + classNode.addChild(PsiWhiteSpaceImpl("\n"), classNode.firstChildNode) classNode.addChild(newKdoc.findChildByType(KDOC)!!, classNode.firstChildNode) } @@ -197,84 +290,229 @@ class KdocComments(configRules: List) : DiktatRule( } @Suppress("UnsafeCallOnNullableType") - private fun createKdocWithProperty(valueParameterNode: ASTNode, prevComment: ASTNode) { - KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnAndFix(configRules, emitWarn, isFixMode, prevComment.text, prevComment.startOffset, valueParameterNode) { - val classNode = valueParameterNode.parent { it.elementType == CLASS }!! - val newKdocText = if (prevComment.elementType == KDOC) { - prevComment.text - } else if (prevComment.elementType == EOL_COMMENT) { - "/**\n * @property ${valueParameterNode.findChildByType(IDENTIFIER)!!.text} ${prevComment.text.removePrefix("//")}\n */" - } else { - "/**\n * @property ${valueParameterNode.findChildByType(IDENTIFIER)!!.text}${prevComment.text.removePrefix("/*").removeSuffix("*/")} */" + private fun createKdocWithProperty( + node: ASTNode, + prevComment: ASTNode, + isParamTagNeeded: Boolean + ) { + val isParameter = !node.hasChildOfType(VAL_KEYWORD) && !node.hasChildOfType(VAR_KEYWORD) + val isPrivateProperty = !node.getFirstChildWithType(MODIFIER_LIST).isAccessibleOutside() + + if (!isParamTagNeeded || (isParameter && configuration.isParamTagsForParameters) || (isPrivateProperty && configuration.isParamTagsForPrivateProperties)) { + val parameterName = node.findChildByType(IDENTIFIER)!!.text + val classNode = node.parent { it.elementType == CLASS }!! + + // if property or parameter is documented with KDoc, which has a tag inside, then it can contain some additional more + // complicated structure, that will be hard to move automatically + val isHasTagsInConstructorKdoc = prevComment.elementType == KDOC && prevComment.kDocTags().isNotEmpty() + val isFixable = !isHasTagsInConstructorKdoc + val warningText = if (isParamTagNeeded) "add comment for param <$parameterName> to KDoc" else "add comment for property <$parameterName> to KDoc" + + KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnOnlyOrWarnAndFix(configRules, emitWarn, warningText, prevComment.startOffset, node, isFixable, isFixMode) { + val newKdocText = createClassKdocTextFromComment(prevComment, parameterName, isParamTagNeeded) + val newKdoc = KotlinParser().createNode(newKdocText).findChildByType(KDOC)!! + + classNode.addChild(PsiWhiteSpaceImpl("\n"), classNode.firstChildNode) + classNode.addChild(newKdoc, classNode.firstChildNode) + node.removeWithWhiteSpace(prevComment) } - val newKdoc = KotlinParser().createNode(newKdocText).findChildByType(KDOC)!! - classNode.addChild(PsiWhiteSpaceImpl("\n"), classNode.firstChildNode) - classNode.addChild(newKdoc, classNode.firstChildNode) - valueParameterNode.removeWithWhiteSpace(prevComment) } } - @Suppress("UnsafeCallOnNullableType") + private fun createClassKdocTextFromComment( + prevComment: ASTNode, + parameterName: String, + isParamTagNeeded: Boolean + ) = when (prevComment.elementType) { + KDOC -> if (isParamTagNeeded) { + "/**\n * @param $parameterName${createClassKdocTextFromKdocComment(prevComment)}\n */" + } else { + "/**\n * @property $parameterName${createClassKdocTextFromKdocComment(prevComment)}\n */" + } + EOL_COMMENT -> if (isParamTagNeeded) { + "/**\n * @param $parameterName ${createClassKdocTextFromEolComment(prevComment)}\n */" + } else { + "/**\n * @property $parameterName ${createClassKdocTextFromEolComment(prevComment)}\n */" + } + else -> if (isParamTagNeeded) { + "/**\n * @param $parameterName${createClassKdocTextFromBlockComment(prevComment)}\n */" + } else { + "/**\n * @property $parameterName${createClassKdocTextFromBlockComment(prevComment)}\n */" + } + } + + private fun createClassKdocTextFromKdocComment(prevComment: ASTNode) = + prevComment.text + .removePrefix("/**") + .removeSuffix("*/") + .replace("\n( )*\\*( )*".toRegex(), "\n * ") + .trimStart(' ') + .trimEnd(' ', '\n') + .let { if (!it.startsWith("\n")) " $it" else it } + + private fun createClassKdocTextFromEolComment(prevComment: ASTNode) = + prevComment.text + .removePrefix("//") + .trimStart(' ') + .trimEnd(' ', '\n') + + private fun createClassKdocTextFromBlockComment(prevComment: ASTNode) = + prevComment.text + .removePrefix("/*") + .removeSuffix("*/") + .replace("\n( )*\\*( )*".toRegex(), "\n * ") + .trimStart(' ') + .trimEnd(' ', '\n') + .let { if (!it.startsWith("\n")) " $it" else it } + + @Suppress( + "UnsafeCallOnNullableType", + "TOO_LONG_FUNCTION", + "ComplexMethod" + ) private fun handleKdocAndBlock( node: ASTNode, - prevComment: ASTNode, kdocBeforeClass: ASTNode, - propertyInClassKdoc: ASTNode?, - propertyInLocalKdoc: ASTNode? + prevComment: ASTNode, + isParamTagNeeded: Boolean ) { - val kdocText = if (prevComment.elementType == KDOC) { - prevComment.text - .removePrefix("/**") - .removeSuffix("*/") - .trim('\n', ' ') + val parameterName = node.findChildByType(IDENTIFIER)!!.text + val parameterTagInClassKdoc = kdocBeforeClass + .kDocTags() + .firstOrNull { (it.knownTag == KDocKnownTag.PARAM || it.knownTag == KDocKnownTag.PROPERTY) && it.getSubjectName() == parameterName } + val parameterInClassKdoc = parameterTagInClassKdoc?.node + + val commentText = if (prevComment.elementType == KDOC) { + createClassKdocTextFromKdocComment(prevComment) } else { - prevComment.text - .removePrefix("/*") - .removeSuffix("*/") - .trim('\n', ' ') + createClassKdocTextFromBlockComment(prevComment) } - // if property is documented with KDoc, which has a property tag inside, then it can contain some additional more complicated - // structure, that will be hard to move automatically - val isFixable = propertyInLocalKdoc == null - KDOC_NO_CONSTRUCTOR_PROPERTY.warnOnlyOrWarnAndFix(configRules, emitWarn, prevComment.text, prevComment.startOffset, node, shouldBeAutoCorrected = isFixable, isFixMode) { - propertyInClassKdoc?.let { + + // if property or parameter is documented with KDoc, which has a tag inside, then it can contain some additional more + // complicated structure, that will be hard to move automatically + val isHasTagsInConstructorKdoc = prevComment.elementType == KDOC && prevComment.kDocTags().isNotEmpty() + val isFixable = !isHasTagsInConstructorKdoc + + val (isHasWrongTag, warningText) = checkWrongTagAndMakeWarningText(parameterTagInClassKdoc, parameterName, isParamTagNeeded) + val isFirstTagInKdoc = parameterTagInClassKdoc?.node != null && parameterTagInClassKdoc.node == kdocBeforeClass.kDocTags().first().node + + parameterInClassKdoc?.let { + KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnOnlyOrWarnAndFix(configRules, emitWarn, warningText, prevComment.startOffset, node, isFixable, isFixMode) { // local docs should be appended to docs in class - appendKdocTagContent(propertyInClassKdoc, "\n$kdocText") - } - ?: insertTextInKdoc(kdocBeforeClass, " * @property ${node.findChildByType(IDENTIFIER)!!.text} ${kdocText.removePrefix("*")}\n") + appendKdocTagContent(parameterInClassKdoc, commentText) - node.removeWithWhiteSpace(prevComment) + if (isHasWrongTag) { + replaceWrongTagInClassKdoc(kdocBeforeClass, parameterName, isParamTagNeeded, isFirstTagInKdoc) + } + + node.removeWithWhiteSpace(prevComment) + } } + ?: run { + val isParameter = !node.hasChildOfType(VAL_KEYWORD) && !node.hasChildOfType(VAR_KEYWORD) + val isPrivateProperty = !node.getFirstChildWithType(MODIFIER_LIST).isAccessibleOutside() + + if (!isParamTagNeeded || (isParameter && configuration.isParamTagsForParameters) || (isPrivateProperty && configuration.isParamTagsForPrivateProperties)) { + KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnOnlyOrWarnAndFix(configRules, emitWarn, warningText, prevComment.startOffset, node, isFixable, isFixMode) { + val newKdocText = if (isParamTagNeeded) "* @param $parameterName$commentText\n " else "* @property $parameterName$commentText\n " + insertTextInKdoc(kdocBeforeClass, checkOneNewLineAfterKdocClassDescription(kdocBeforeClass, newKdocText, isFirstTagInKdoc)) + + node.removeWithWhiteSpace(prevComment) + } + } + } } - @Suppress("UnsafeCallOnNullableType") + @Suppress( + "UnsafeCallOnNullableType", + "TOO_LONG_FUNCTION", + "ComplexMethod" + ) private fun handleCommentBefore( node: ASTNode, kdocBeforeClass: ASTNode, prevComment: ASTNode, - propertyInClassKdoc: ASTNode? + isParamTagNeeded: Boolean ) { - propertyInClassKdoc?.let { - if (propertyInClassKdoc.hasChildOfType(KDocTokens.TEXT)) { - val kdocText = propertyInClassKdoc.findChildByType(KDocTokens.TEXT)!! - (kdocText as LeafPsiElement).rawReplaceWithText("${kdocText.text} ${prevComment.text}") - } else { - propertyInClassKdoc.addChild(LeafPsiElement(KDocTokens.TEXT, prevComment.text), null) + val parameterName = node.findChildByType(IDENTIFIER)!!.text + val parameterTagInClassKdoc = kdocBeforeClass + .kDocTags() + .firstOrNull { (it.knownTag == KDocKnownTag.PARAM || it.knownTag == KDocKnownTag.PROPERTY) && it.getSubjectName() == parameterName } + val parameterInClassKdoc = parameterTagInClassKdoc?.node + + val (isHasWrongTag, warningText) = checkWrongTagAndMakeWarningText(parameterTagInClassKdoc, parameterName, isParamTagNeeded) + val isFirstTagInKdoc = parameterTagInClassKdoc?.node != null && parameterTagInClassKdoc.node == kdocBeforeClass.kDocTags().first().node + + parameterInClassKdoc?.let { + KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnAndFix(configRules, emitWarn, isFixMode, warningText, prevComment.startOffset, node) { + if (parameterInClassKdoc.hasChildOfType(KDocTokens.TEXT)) { + val newKdocText = parameterInClassKdoc + .findChildrenMatching { it.elementType == KDocTokens.TEXT || it.elementType == KDocTokens.CODE_BLOCK_TEXT } + .lastOrNull() + (newKdocText as LeafPsiElement).rawReplaceWithText("${newKdocText.text}\n * ${createClassKdocTextFromEolComment(prevComment)}") + } else { + parameterInClassKdoc.addChild(LeafPsiElement(KDocTokens.TEXT, " ${createClassKdocTextFromEolComment(prevComment)}"), null) + } + + if (isHasWrongTag) { + replaceWrongTagInClassKdoc(kdocBeforeClass, parameterName, isParamTagNeeded, isFirstTagInKdoc) + } + + node.treeParent.removeChildMergingSurroundingWhitespaces(prevComment.treePrev, prevComment, prevComment.treeNext) } } ?: run { - insertTextInKdoc(kdocBeforeClass, "* @property ${node.findChildByType(IDENTIFIER)!!.text} ${prevComment.text.removeRange(0, 2)}\n") + val isParameter = !node.hasChildOfType(VAL_KEYWORD) && !node.hasChildOfType(VAR_KEYWORD) + val isPrivateProperty = !node.getFirstChildWithType(MODIFIER_LIST).isAccessibleOutside() + + if (!isParamTagNeeded || (isParameter && configuration.isParamTagsForParameters) || (isPrivateProperty && configuration.isParamTagsForPrivateProperties)) { + KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnAndFix(configRules, emitWarn, isFixMode, warningText, prevComment.startOffset, node) { + val newKdocText = if (isParamTagNeeded) { + "* @param $parameterName ${createClassKdocTextFromEolComment(prevComment)}\n " + } else { + "* @property $parameterName ${createClassKdocTextFromEolComment(prevComment)}\n " + } + + insertTextInKdoc(kdocBeforeClass, checkOneNewLineAfterKdocClassDescription(kdocBeforeClass, newKdocText, isFirstTagInKdoc)) + + node.treeParent.removeChildMergingSurroundingWhitespaces(prevComment.treePrev, prevComment, prevComment.treeNext) + } + } } - node.treeParent.removeChildMergingSurroundingWhitespaces(prevComment) + } + + private fun checkWrongTagAndMakeWarningText( + parameterTagInClassKdoc: KDocTag?, + parameterName: String, + isParamTagNeeded: Boolean + ): Pair { + val correctTag = if (isParamTagNeeded) KDocKnownTag.PARAM else KDocKnownTag.PROPERTY + val isHasWrongTag = parameterTagInClassKdoc != null && parameterTagInClassKdoc.knownTag != correctTag + val warningText = if (isHasWrongTag) { + if (isParamTagNeeded) { + "change `@property` tag to `@param` tag for <$parameterName> and add comment to KDoc" + } else { + "change `@param` tag to `@property` tag for <$parameterName> and add comment to KDoc" + } + } else { + if (isParamTagNeeded) { + "add comment for param <$parameterName> to KDoc" + } else { + "add comment for property <$parameterName> to KDoc" + } + } + + return Pair(isHasWrongTag, warningText) } private fun checkDuplicateProperties(kdoc: ASTNode) { - val propertiesAndParams = kdoc.kDocTags() + val propertiesAndParams = kdoc + .kDocTags() .filter { it.knownTag == KDocKnownTag.PROPERTY || it.knownTag == KDocKnownTag.PARAM } val traversedNodes: MutableSet = mutableSetOf() - propertiesAndParams.forEach { property -> - if (!traversedNodes.add(property.getSubjectName())) { - KDOC_DUPLICATE_PROPERTY.warn(configRules, emitWarn, property.text, property.node.startOffset, kdoc) + propertiesAndParams.forEach { parameter -> + if (!traversedNodes.add(parameter.getSubjectName())) { + KDOC_DUPLICATE_PROPERTY.warn(configRules, emitWarn, parameter.text, parameter.node.startOffset, kdoc) } } } @@ -291,19 +529,15 @@ class KdocComments(configRules: List) : DiktatRule( * Append [content] to [kdocTagNode], e.g. * (`@property foo bar`, "baz") -> `@property foo bar baz` */ - private fun appendKdocTagContent( - kdocTagNode: ASTNode, content: String, - ) { - kdocTagNode.findChildByType(KDocTokens.TEXT)?.let { - kdocTagNode.replaceChild( - it, - LeafPsiElement(KDocTokens.TEXT, "${it.text}$content"), - ) - } - ?: kdocTagNode.addChild( - LeafPsiElement(KDocTokens.TEXT, content), - null, - ) + private fun appendKdocTagContent(kdocTagNode: ASTNode, content: String) { + kdocTagNode.findChildrenMatching { it.elementType == KDocTokens.TEXT || it.elementType == KDocTokens.CODE_BLOCK_TEXT } + .lastOrNull() + ?.let { + kdocTagNode.replaceChild( + it, + LeafPsiElement(KDocTokens.TEXT, "${it.text}$content"), + ) + } ?: kdocTagNode.addChild(LeafPsiElement(KDocTokens.TEXT, content), null) } private fun checkClassElements(node: ASTNode) { @@ -319,13 +553,15 @@ class KdocComments(configRules: List) : DiktatRule( } .forEach { classElement -> if (classElement.elementType == PROPERTY) { - // we check if property declared in class body is also documented in class header via `@property` tag + // we check if property declared in class body is also documented in class header via + // `@property` tag val classKdoc = node.getFirstChildWithType(KDOC) val propertyInClassKdoc = classKdoc?.kDocTags()?.find { it.knownTag == KDocKnownTag.PROPERTY && it.getSubjectName() == classElement.getIdentifierName()?.text } propertyInClassKdoc?.let { - // if property is documented as `@property`, then we suggest to move docs to the declaration inside the class body + // if property is documented as `@property`, then we suggest to move docs to the + // declaration inside the class body KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER.warn(configRules, emitWarn, classElement.text, classElement.startOffset, classElement) return } @@ -365,6 +601,21 @@ class KdocComments(configRules: List) : DiktatRule( private fun isTopLevelFunctionStandard(node: ASTNode): Boolean = node.elementType == FUN && node.isStandardMethod() + /** + * [RuleConfiguration] for param tags creation + */ + private class KdocCommentsConfiguration(config: Map) : RuleConfiguration(config) { + /** + * Create param tags for parameters without val or var + */ + val isParamTagsForParameters = config["isParamTagsForParameters"]?.toBoolean() ?: true + + /** + * Create param tags for private properties + */ + val isParamTagsForPrivateProperties = config["isParamTagsForPrivateProperties"]?.toBoolean() ?: true + } + companion object { const val NAME_ID = "kdoc-comments" private val statementsToDocument = TokenSet.create(CLASS, FUN, PROPERTY) @@ -372,14 +623,10 @@ class KdocComments(configRules: List) : DiktatRule( } private fun ASTNode.removeWithWhiteSpace(prevComment: ASTNode) { - if (prevComment.elementType == KDOC) { - if (prevComment.treeNext.elementType == WHITE_SPACE) { - removeChild(prevComment.treeNext) - } - removeChild(prevComment) - } else { - removeChildMergingSurroundingWhitespaces(prevComment) - } + removeChildMergingSurroundingWhitespaces( + if (prevComment.elementType == KDOC) prevComment.treeParent.treePrev else prevComment.treePrev, + prevComment, prevComment.treeNext + ) } /** @@ -387,18 +634,21 @@ private fun ASTNode.removeWithWhiteSpace(prevComment: ASTNode) { * preserving only a single newline if present (i.e. leaving no empty lines after merging). In any case, [child] is removed * from the tree. */ -private fun ASTNode.removeChildMergingSurroundingWhitespaces(child: ASTNode) { - with(child) { - if (treeNext?.elementType == WHITE_SPACE && treePrev?.elementType == WHITE_SPACE) { - val mergedText = (treePrev.text + treeNext.text) - val mergedSpace = if (mergedText.contains('\n')) { - '\n' + mergedText.substringAfterLast('\n') - } else { - mergedText - } - treeParent.replaceWhiteSpaceText(treePrev, mergedSpace) +private fun ASTNode.removeChildMergingSurroundingWhitespaces( + prevWhiteSpaces: ASTNode, + child: ASTNode, + nextWhitespaces: ASTNode +) { + if (nextWhitespaces.elementType == WHITE_SPACE && prevWhiteSpaces.elementType == WHITE_SPACE) { + val mergedText = (prevWhiteSpaces.text + nextWhitespaces.text) + val mergedSpace = if (mergedText.contains('\n')) { + '\n' + mergedText.substringAfterLast('\n') + } else { + mergedText } - treeParent.removeChild(treeNext) + + child.treeParent.removeChild(prevWhiteSpaces) + child.treeParent.replaceWhiteSpaceText(nextWhitespaces, mergedSpace) } removeChild(child) } diff --git a/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/MultipleModifiersSequence.kt b/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/MultipleModifiersSequence.kt index 0bc32d5e34..8f232febe5 100644 --- a/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/MultipleModifiersSequence.kt +++ b/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/MultipleModifiersSequence.kt @@ -17,7 +17,7 @@ import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.psiUtil.children /** - * @property configRules + * @param configRules */ class MultipleModifiersSequence(configRules: List) : DiktatRule( NAME_ID, diff --git a/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/files/TopLevelOrderRule.kt b/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/files/TopLevelOrderRule.kt index 93b36e9df3..1d8cebd241 100644 --- a/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/files/TopLevelOrderRule.kt +++ b/diktat-rules/src/main/kotlin/com/saveourtool/diktat/ruleset/rules/chapter3/files/TopLevelOrderRule.kt @@ -81,6 +81,8 @@ class TopLevelOrderRule(configRules: List) : DiktatRule( /** * Class containing different groups of properties in file + * + * @param properties */ private data class Properties(private val properties: List) : Elements { override fun sortElements(): MutableList { @@ -94,6 +96,11 @@ class TopLevelOrderRule(configRules: List) : DiktatRule( /** * Class containing different children in file + * + * @param properties + * @param typealiases + * @param functions + * @param classes */ private data class Blocks( private val properties: List, diff --git a/diktat-rules/src/main/resources/diktat-analysis-huawei.yml b/diktat-rules/src/main/resources/diktat-analysis-huawei.yml index d7f8718fed..8cf7c46b02 100644 --- a/diktat-rules/src/main/resources/diktat-analysis-huawei.yml +++ b/diktat-rules/src/main/resources/diktat-analysis-huawei.yml @@ -449,6 +449,9 @@ # Checks that property in constructor doesn't contains comment - name: KDOC_NO_CONSTRUCTOR_PROPERTY enabled: true + configuration: + isParamTagsForParameters: false # create param tags for parameters without val or var + isParamTagsForPrivateProperties: false # create param tags for private properties # Checks that property in KDoc present in class - name: KDOC_EXTRA_PROPERTY enabled: true diff --git a/diktat-rules/src/main/resources/diktat-analysis.yml b/diktat-rules/src/main/resources/diktat-analysis.yml index 2f276637c6..60c483d7a0 100644 --- a/diktat-rules/src/main/resources/diktat-analysis.yml +++ b/diktat-rules/src/main/resources/diktat-analysis.yml @@ -436,6 +436,9 @@ # Checks that property in constructor doesn't contain comment - name: KDOC_NO_CONSTRUCTOR_PROPERTY enabled: true + configuration: + isParamTagsForParameters: true # create param tags for parameters without val or var + isParamTagsForPrivateProperties: true # create param tags for private properties # Checks that the long lambda has parameters - name: TOO_MANY_LINES_IN_LAMBDA enabled: true diff --git a/diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocCommentsFixTest.kt b/diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocCommentsFixTest.kt index 464080e338..3922c3440b 100644 --- a/diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocCommentsFixTest.kt +++ b/diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocCommentsFixTest.kt @@ -4,8 +4,8 @@ import com.saveourtool.diktat.ruleset.rules.chapter2.kdoc.KdocComments import com.saveourtool.diktat.util.FixTestBase import generated.WarningNames -import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Tags import org.junit.jupiter.api.Test class KdocCommentsFixTest : FixTestBase("test/paragraph2/kdoc/", ::KdocComments) { @@ -16,20 +16,25 @@ class KdocCommentsFixTest : FixTestBase("test/paragraph2/kdoc/", ::KdocComments) } @Test - @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY) + @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY), Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT), Tag(WarningNames.MISSING_KDOC_TOP_LEVEL)) + fun `check fix without class kdoc`() { + fixAndCompare("ConstructorCommentNoKDocExpected.kt", "ConstructorCommentNoKDocTest.kt") + } + + @Test + @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY), Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT)) fun `check fix with class kdoc`() { fixAndCompare("ConstructorCommentExpected.kt", "ConstructorCommentTest.kt") } - @Disabled("https://github.com/saveourtool/diktat/issues/1737") @Test - @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY) - fun `check fix without class kdoc`() { - fixAndCompare("ConstructorCommentNoKDocExpected.kt", "ConstructorCommentNoKDocTest.kt") + @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY), Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT)) + fun `check fix with properties in class kdoc`() { + fixAndCompare("ConstructorCommentPropertiesExpected.kt", "ConstructorCommentPropertiesTest.kt") } @Test - @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY) + @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY), Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT)) fun `should preserve newlines when moving comments from value parameters`() { fixAndCompare("ConstructorCommentNewlineExpected.kt", "ConstructorCommentNewlineTest.kt") } diff --git a/diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocCommentsWarnTest.kt b/diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocCommentsWarnTest.kt index 261d88d580..a0bbcbe865 100644 --- a/diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocCommentsWarnTest.kt +++ b/diktat-rules/src/test/kotlin/com/saveourtool/diktat/ruleset/chapter2/KdocCommentsWarnTest.kt @@ -296,7 +296,7 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) { } @Test - @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT) + @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT), Tag(WarningNames.KDOC_EXTRA_PROPERTY)) fun `check simple primary constructor with comment`() { lintMethod( """ @@ -311,25 +311,27 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) { |) { |} """.trimMargin(), - DiktatError(7, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} name", true) + DiktatError(3, 4, ruleId, "${KDOC_EXTRA_PROPERTY.warnText()} @param adsf", false), + DiktatError(7, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} add comment for property to KDoc", true) ) } @Test @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY) - fun `shouldn't trigger on override parameter`() { + fun `should trigger on override parameter`() { lintMethod( """ |@Suppress("MISSING_KDOC_TOP_LEVEL") |public class Example ( | override val serializersModule: SerializersModule = EmptySerializersModule |) - """.trimMargin() + """.trimMargin(), + DiktatError(3, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add property to KDoc", true) ) } @Test - @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY) + @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT) fun `shouldn't trigger because not primary constructor`() { lintMethod( """ @@ -342,7 +344,7 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) { | // name | name: String, | anotherName: String, - | OneMoreName: String + | oneMoreName: String | ) |} """.trimMargin() @@ -350,7 +352,7 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) { } @Test - @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT) + @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT), Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY)) fun `check constructor with comment`() { lintMethod( """ @@ -361,16 +363,18 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) { | //some descriptions | val name: String, | anotherName: String, - | OneMoreName: String + | oneMoreName: String | ) { |} """.trimMargin(), - DiktatError(5, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} name", true) + DiktatError(5, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} add comment for property to KDoc", true), + DiktatError(7, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param to KDoc", true), + DiktatError(8, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param to KDoc", true) ) } @Test - @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY) + @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT), Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY)) fun `check constructor with block comment`() { lintMethod( """ @@ -380,17 +384,19 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) { |class Example ( | /*some descriptions*/val name: String, | anotherName: String, - | OneMoreName: String + | private val oneMoreName: String | ) { |} """.trimMargin(), - DiktatError(5, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} /*some descriptions*/", true) + DiktatError(5, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} add comment for property to KDoc", true), + DiktatError(6, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param to KDoc", true), + DiktatError(7, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param to KDoc", true) ) } @Test - @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY) - fun `check not property`() { + @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT), Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY)) + fun `check not property but params`() { lintMethod( """ |/** @@ -398,17 +404,20 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) { | */ |class Example ( | //some descriptions - | name: String, + | private val name: String, | anotherName: String, - | OneMoreName: String + | private val oneMoreName: String | ) { |} - """.trimMargin() + """.trimMargin(), + DiktatError(5, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} add comment for param to KDoc", true), + DiktatError(7, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param to KDoc", true), + DiktatError(8, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param to KDoc", true) ) } @Test - @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY) + @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT), Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY)) fun `check constructor with kdoc`() { lintMethod( """ @@ -418,53 +427,60 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) { |class Example ( | /** | * some descriptions - | * @return fdv | */ - | | val name: String, | anotherName: String, - | OneMoreName: String + | private val oneMoreName: String | ) { |} """.trimMargin(), - DiktatError(5, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} /**...", true) + DiktatError(5, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} add comment for property to KDoc", true), + DiktatError(9, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param to KDoc", true), + DiktatError(10, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param to KDoc", true) ) } @Test - @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY) - fun `shouldn't fix`() { + @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT) + fun `shouldn't fix because KDoc comment and property tag inside`() { lintMethod( """ |/** - | * @property name text + | * @return some | */ |class Example ( | /** | * sdcjkh | * @property name text2 + | * fdfdfd | */ | val name: String, | ) { |} """.trimMargin(), - DiktatError(5, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} /**...", false) + DiktatError(5, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} add comment for property to KDoc", false) ) } @Test - @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY) - fun `shouldn't trigger`() { + @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT) + fun `shouldn't fix because KDoc comment and any tag inside`() { lintMethod( """ |/** - | * text + | * @return some | */ |class Example ( - | private val name: String, + | /** + | * sdcjkh + | * @return name text2 + | * fdfdfd + | */ + | val name: String, | ) { |} - """.trimMargin() + """.trimMargin(), + DiktatError(5, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} add comment for property to KDoc", false) ) } @@ -475,7 +491,6 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) { """ |/** | * @property Name text - | * @property | */ |class Example ( | val name: String, @@ -483,42 +498,147 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) { |} """.trimMargin(), DiktatError(2, 4, ruleId, "${KDOC_EXTRA_PROPERTY.warnText()} @property Name text", false), - DiktatError(6, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add to KDoc", true) + DiktatError(5, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add property to KDoc", true) ) } @Test - @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY), Tag(WarningNames.MISSING_KDOC_TOP_LEVEL)) - fun `no property kdoc and class`() { + @Tag(WarningNames.KDOC_EXTRA_PROPERTY) + fun `extra property in kdoc`() { + lintMethod( + """ + |/** + | * @property name bla + | * @property kek + | */ + |class Example ( + | val name: String + | ) { + |} + """.trimMargin(), + DiktatError(3, 4, ruleId, "${KDOC_EXTRA_PROPERTY.warnText()} @property kek", false) + ) + } + + @Test + @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY) + fun `change property to param in kdoc for private parameter`() { lintMethod( """ + |/** + | * @property name abc + | */ + |class Example ( + | private val name: String, + | ) { + |} + """.trimMargin(), + DiktatError(5, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} change `@property` tag to `@param` tag for to KDoc", true) + ) + } + + @Test + @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY) + fun `change param to property in kdoc for property`() { + lintMethod( + """ + |/** + | * @param name abc + | */ |class Example ( | val name: String, - | private val surname: String | ) { |} """.trimMargin(), - DiktatError(1, 1, ruleId, "${MISSING_KDOC_TOP_LEVEL.warnText()} Example"), - DiktatError(2, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add to KDoc", true) + DiktatError(5, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} change `@param` tag to `@property` tag for to KDoc", true), ) } @Test - @Tag(WarningNames.KDOC_EXTRA_PROPERTY) - fun `extra property in kdoc`() { + @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT) + fun `change param to property in kdoc for property with single comment`() { lintMethod( """ |/** - | * @property name bla - | * @property kek + | * @param name abc | */ + |class Example ( + | //some descriptions + | val name: String, + | ) { + |} + """.trimMargin(), + DiktatError(5, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} change `@param` tag to `@property` tag for and add comment to KDoc", true), + ) + } + + @Test + @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT) + fun `change param to property in kdoc for property with block comment`() { + lintMethod( + """ + |/** + | * @param name abc + | */ + |class Example ( + | /*some descriptions*/ + | val name: String, + | ) { + |} + """.trimMargin(), + DiktatError(5, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} change `@param` tag to `@property` tag for and add comment to KDoc", true), + ) + } + + @Test + @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT) + fun `comment on private parameter`() { + lintMethod( + """ + |/** + | * abc + | */ + |class Example ( + | // single-line comment + | private val name: String, + | ) { + |} + """.trimMargin(), + DiktatError(5, 4, ruleId,"${KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT.warnText()} add comment for param to KDoc", true) + ) + } + + @Test + @Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY) + fun `should trigger on private parameter`() { + lintMethod( + """ + |/** + | * text + | */ + |class Example ( + | private val name: String, + | ) { + |} + """.trimMargin(), + DiktatError(5, 4, ruleId,"${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param to KDoc", true) + ) + } + + @Test + @Tags(Tag(WarningNames.KDOC_NO_CONSTRUCTOR_PROPERTY), Tag(WarningNames.MISSING_KDOC_TOP_LEVEL)) + fun `no property kdoc and class`() { + lintMethod( + """ |class Example ( | val name: String, | private val surname: String | ) { |} """.trimMargin(), - DiktatError(3, 4, ruleId, "${KDOC_EXTRA_PROPERTY.warnText()} @property kek", false) + DiktatError(1, 1, ruleId, "${MISSING_KDOC_TOP_LEVEL.warnText()} Example"), + DiktatError(2, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add property to KDoc", true), + DiktatError(3, 4, ruleId, "${KDOC_NO_CONSTRUCTOR_PROPERTY.warnText()} add param to KDoc", true) ) } @@ -602,7 +722,7 @@ class KdocCommentsWarnTest : LintTestBase(::KdocComments) { |/** | * Test class | */ - |class example(f: String) { + |class example { | |} """.trimMargin() diff --git a/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentExpected.kt b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentExpected.kt index 2e19ea6258..5cfd52ac29 100644 --- a/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentExpected.kt +++ b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentExpected.kt @@ -1,27 +1,307 @@ package test.paragraph2.kdoc /** - * @property name another text -* some text + * kdoc + * class + * comment + * + * @param name */ -class A ( - var name: String -){} +class A constructor( + name: String +) {} /** - * @property name another text + * kdoc + * class + * comment + * + * @param name single-line comment */ -class A ( - /** - * @property name some text - */ - val name: String -){} +class A constructor( + name: String +) {} /** - * @property name another text -* text + * kdoc + * class + * comment + * + * @param name + * block + * comment */ -class A ( - val name: String -){} +class A constructor( + name: String +) {} + +/** + * kdoc + * class + * comment + * + * @param name + * kdoc property + * comment + */ +class A constructor( + name: String +) {} + +/** + * kdoc + * class + * comment + */ +class A constructor( + /** + * @property name property + * comment + */ + name: String +) {} + +/** + * kdoc + * class + * comment + * + * @property name + */ +class A constructor( + val name: String +) {} + +/** + * kdoc + * class + * comment + * + * @property name single-line comment + */ +class A constructor( + val name: String +) {} + +/** + * kdoc + * class + * comment + * + * @property name + * block + * comment + */ +class A constructor( + val name: String +) {} + +/** + * kdoc + * class + * comment + * + * @property name + * kdoc property + * comment + */ +class A constructor( + val name: String +) {} + +/** + * kdoc + * class + * comment + */ +class A constructor( + /** + * @property name property + * comment + */ + val name: String +) {} + +/** + * kdoc + * class + * comment + * + * @param name + */ +class A constructor( + private val name: String +) {} + +/** + * kdoc + * class + * comment + * + * @param name single-line comment + */ +class A constructor( + private val name: String +) {} + +/** + * kdoc + * class + * comment + * + * @param name + * block + * comment + */ +class A constructor( + private val name: String +) {} + +/** + * kdoc + * class + * comment + * + * @param name + * kdoc property + * comment + */ +class A constructor( + private val name: String +) {} + +/** + * kdoc + * class + * comment + */ +class A constructor( + /** + * @property name property + * comment + */ + private val name: String +) {} + +/** + * kdoc + * class + * comment + * + * @property openName single-line comment + * @property openLastName + * block + * comment + * @property openBirthDate + * kdoc property + * comment + */ +open class B constructor( + open val openName: String, + open val openLastName: String, + open val openBirthDate: String, + /** + * @property openAddr property + * comment + */ + open val openAddr: String +) {} + +/** + * kdoc + * class + * comment + * + * @param privateName single-line comment + * @property protectedName single-line comment + * @property internalName single-line comment + * @property openName single-line comment + * @property name single-line comment + * @param paramName single-line comment + * @param privateLastName + * block + * comment + * @property protectedLastName + * block + * comment + * @property internalLastName + * block + * comment + * @property openLastName + * block + * comment + * @property lastName + * block + * comment + * @param paramLastName + * block + * comment + * @param privateBirthDate + * kdoc property + * comment + * @property protectedBirthDate + * kdoc property + * comment + * @property internalBirthDate + * kdoc property + * comment + * @property openBirthDate + * kdoc property + * comment + * @property birthDate + * kdoc property + * comment + * @param paramBirthDate + * kdoc property + * comment + */ +class A constructor( + private val privateName: String, + protected val protectedName: String, + internal val internalName: String, + override val openName: String, + val name: String, + paramName: String, + private val privateLastName: String, + protected val protectedLastName: String, + internal val internalLastName: String, + override val openLastName: String, + val lastName: String, + paramLastName: String, + private val privateBirthDate: String, + protected val protectedBirthDate: String, + internal val internalBirthDate: String, + override val openBirthDate: String, + val birthDate: String, + paramBirthDate: String, + /** + * @property privateAddr property + * comment + */ + private val privateAddr: String, + /** + * @property protectedAddr property + * comment + */ + protected val protectedAddr: String, + /** + * @property internalAddr property + * comment + */ + internal val internalAddr: String, + /** + * @property openAddr property + * comment + */ + override val openAddr: String, + /** + * @property addr property + * comment + */ + val addr: String, + /** + * @property paramAddr property + * comment + */ + paramAddr: String, +) : B() {} diff --git a/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNewlineExpected.kt b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNewlineExpected.kt index 64e5156d99..3c68fe82c6 100644 --- a/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNewlineExpected.kt +++ b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNewlineExpected.kt @@ -2,8 +2,8 @@ package test.paragraph2.kdoc /** * @property param1 - * @property param2 first comment -*/ + * @property param2 first comment + */ class Example( val param1: String, val param2: String, // second comment @@ -11,9 +11,18 @@ class Example( /** * @property param1 - * @property param2 first comment -*/ + * @property param2 first comment + */ class Example( val param1: String, val param2: String, /* second comment */ -) \ No newline at end of file +) + +/** + * @property param1 + * @property param2 first comment + */ +class Example( + val param1: String, + val param2: String, /** second comment */ +) diff --git a/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNewlineTest.kt b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNewlineTest.kt index 5984676a5a..dc73713a69 100644 --- a/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNewlineTest.kt +++ b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNewlineTest.kt @@ -1,11 +1,16 @@ package test.paragraph2.kdoc class Example( - val param1: String, // first comment + val param1: String, // first comment val param2: String, // second comment ) class Example( - val param1: String, /* first comment */ + val param1: String, /* first comment */ val param2: String, /* second comment */ -) \ No newline at end of file +) + +class Example( + val param1: String, /** first comment */ + val param2: String, /** second comment */ +) diff --git a/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNoKDocExpected.kt b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNoKDocExpected.kt index 4743bc6509..0ec40f52e2 100644 --- a/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNoKDocExpected.kt +++ b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNoKDocExpected.kt @@ -1,53 +1,236 @@ package test.paragraph2.kdoc /** - * @property name comment + * @param name */ class A constructor( - val name: String -){} + name: String +) {} /** - * hello - */ + * @param name single-line comment + */ class A constructor( - val name: String -){} + name: String +) {} /** - * text - */ + * @param name + * block + * comment + */ class A constructor( - @param:JsonProperty("shortName") private val shortName: String -){} + name: String +) {} /** - * @property lastName + * @param name + * kdoc property + * comment */ class A constructor( - private var name: String, - val lastName: String -){} + name: String +) {} + +class A constructor( + /** + * @property name property + * comment + */ + name: String +) {} /** * @property name - * hello - */ -class A constructor( - val name: String -){} - -class Example(private val foo: Int) - -/** - * @property g - * @property e - * @property s -*/ -class Example constructor( - val g: String, - private var q: String, - @param:JsonProperty("shortName") private val shortName: String, - val e: String, - protected val s: String -){} + */ +class A constructor( + val name: String +) {} + +/** + * @property name single-line comment + */ +class A constructor( + val name: String +) {} + +/** + * @property name + * block + * comment + */ +class A constructor( + val name: String +) {} + +/** + * @property name + * kdoc property + * comment + */ +class A constructor( + val name: String +) {} + +class A constructor( + /** + * @property name property + * comment + */ + val name: String +) {} + +/** + * @param name + */ +class A constructor( + private val name: String +) {} + +/** + * @param name single-line comment + */ +class A constructor( + private val name: String +) {} + +/** + * @param name + * block + * comment + */ +class A constructor( + private val name: String +) {} + +/** + * @param name + * kdoc property + * comment + */ +class A constructor( + private val name: String +) {} + +class A constructor( + /** + * @property name property + * comment + */ + private val name: String +) {} + +/** + * @property openName single-line comment + * @property openLastName + * block + * comment + * @property openBirthDate + * kdoc property + * comment + */ +open class B constructor( + open val openName: String, + open val openLastName: String, + open val openBirthDate: String, + /** + * @property openAddr property + * comment + */ + open val openAddr: String +) {} + +/** + * @param privateName single-line comment + * @property protectedName single-line comment + * @property internalName single-line comment + * @property openName single-line comment + * @property name single-line comment + * @param paramName single-line comment + * @param privateLastName + * block + * comment + * @property protectedLastName + * block + * comment + * @property internalLastName + * block + * comment + * @property openLastName + * block + * comment + * @property lastName + * block + * comment + * @param paramLastName + * block + * comment + * @param privateBirthDate + * kdoc property + * comment + * @property protectedBirthDate + * kdoc property + * comment + * @property internalBirthDate + * kdoc property + * comment + * @property openBirthDate + * kdoc property + * comment + * @property birthDate + * kdoc property + * comment + * @param paramBirthDate + * kdoc property + * comment + */ +class A constructor( + private val privateName: String, + protected val protectedName: String, + internal val internalName: String, + override val openName: String, + val name: String, + paramName: String, + private val privateLastName: String, + protected val protectedLastName: String, + internal val internalLastName: String, + override val openLastName: String, + val lastName: String, + paramLastName: String, + private val privateBirthDate: String, + protected val protectedBirthDate: String, + internal val internalBirthDate: String, + override val openBirthDate: String, + val birthDate: String, + paramBirthDate: String, + /** + * @property privateAddr property + * comment + */ + private val privateAddr: String, + /** + * @property protectedAddr property + * comment + */ + protected val protectedAddr: String, + /** + * @property internalAddr property + * comment + */ + internal val internalAddr: String, + /** + * @property openAddr property + * comment + */ + override val openAddr: String, + /** + * @property addr property + * comment + */ + val addr: String, + /** + * @property paramAddr property + * comment + */ + paramAddr: String, +) : B() {} diff --git a/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNoKDocTest.kt b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNoKDocTest.kt index 26e317b8bb..e38f74aab5 100644 --- a/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNoKDocTest.kt +++ b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentNoKDocTest.kt @@ -1,42 +1,225 @@ package test.paragraph2.kdoc class A constructor( - //comment - val name: String -){} + name: String +) {} class A constructor( - /** - * hello - */ - val name: String -){} + //single-line comment + name: String +) {} class A constructor( - /** - * text - */ - @param:JsonProperty("shortName") private val shortName: String -){} + /* + * block + * comment + */ + name: String +) {} class A constructor( - private var name: String, - val lastName: String -){} + /** + * kdoc property + * comment + */ + name: String +) {} class A constructor( - /* - * hello - */ - val name: String -){} + /** + * @property name property + * comment + */ + name: String +) {} -class Example(private val foo: Int) +class A constructor( + val name: String +) {} + +class A constructor( + //single-line comment + val name: String +) {} + +class A constructor( + /* + * block + * comment + */ + val name: String +) {} + +class A constructor( + /** + * kdoc property + * comment + */ + val name: String +) {} + +class A constructor( + /** + * @property name property + * comment + */ + val name: String +) {} + +class A constructor( + private val name: String +) {} -class Example constructor( - val g: String, - private var q: String, - @param:JsonProperty("shortName") private val shortName: String, - val e: String, - protected val s: String -){} +class A constructor( + //single-line comment + private val name: String +) {} + +class A constructor( + /* + * block + * comment + */ + private val name: String +) {} + +class A constructor( + /** + * kdoc property + * comment + */ + private val name: String +) {} + +class A constructor( + /** + * @property name property + * comment + */ + private val name: String +) {} + +open class B constructor( + //single-line comment + open val openName: String, + /* + * block + * comment + */ + open val openLastName: String, + /** + * kdoc property + * comment + */ + open val openBirthDate: String, + /** + * @property openAddr property + * comment + */ + open val openAddr: String +) {} + +class A constructor( + //single-line comment + private val privateName: String, + //single-line comment + protected val protectedName: String, + //single-line comment + internal val internalName: String, + //single-line comment + override val openName: String, + //single-line comment + val name: String, + //single-line comment + paramName: String, + /* + * block + * comment + */ + private val privateLastName: String, + /* + * block + * comment + */ + protected val protectedLastName: String, + /* + * block + * comment + */ + internal val internalLastName: String, + /* + * block + * comment + */ + override val openLastName: String, + /* + * block + * comment + */ + val lastName: String, + /* + * block + * comment + */ + paramLastName: String, + /** + * kdoc property + * comment + */ + private val privateBirthDate: String, + /** + * kdoc property + * comment + */ + protected val protectedBirthDate: String, + /** + * kdoc property + * comment + */ + internal val internalBirthDate: String, + /** + * kdoc property + * comment + */ + override val openBirthDate: String, + /** + * kdoc property + * comment + */ + val birthDate: String, + /** + * kdoc property + * comment + */ + paramBirthDate: String, + /** + * @property privateAddr property + * comment + */ + private val privateAddr: String, + /** + * @property protectedAddr property + * comment + */ + protected val protectedAddr: String, + /** + * @property internalAddr property + * comment + */ + internal val internalAddr: String, + /** + * @property openAddr property + * comment + */ + override val openAddr: String, + /** + * @property addr property + * comment + */ + val addr: String, + /** + * @property paramAddr property + * comment + */ + paramAddr: String, +) : B() {} diff --git a/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentPropertiesExpected.kt b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentPropertiesExpected.kt new file mode 100644 index 0000000000..58a5ce9626 --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentPropertiesExpected.kt @@ -0,0 +1,261 @@ +package test.paragraph2.kdoc + +/** + * @param name property info + */ +class A constructor( + name: String +) {} + +/** + * @param name property info + * single-line comment + */ +class A constructor( + name: String +) {} + +/** + * @param name property info + * block + * comment + */ +class A constructor( + name: String +) {} + +/** + * @param name property info + * kdoc property + * comment + */ +class A constructor( + name: String +) {} + +/** + * @param name property info + */ +class A constructor( + /** + * @property name property + * comment + */ + name: String +) {} + +/** + * @property name property info + */ +class A constructor( + val name: String +) {} + +/** + * @property name property info + * single-line comment + */ +class A constructor( + val name: String +) {} + +/** + * @property name property info + * block + * comment + */ +class A constructor( + val name: String +) {} + +/** + * @property name property info + * kdoc property + * comment + */ +class A constructor( + val name: String +) {} + +/** + * @property name property info + */ +class A constructor( + /** + * @property name property + * comment + */ + val name: String +) {} + +/** + * @param name property info + */ +class A constructor( + private val name: String +) {} + +/** + * @param name property info + * single-line comment + */ +class A constructor( + private val name: String +) {} + +/** + * @param name property info + * block + * comment + */ +class A constructor( + private val name: String +) {} + +/** + * @param name property info + * kdoc property + * comment + */ +class A constructor( + private val name: String +) {} + +/** + * @property name property info + */ +class A constructor( + /** + * @property name property + * comment + */ + private val name: String +) {} + +/** + * @property openName open property info + * single-line comment + * @property openLastName + * open last property + * info + * block + * comment + * @property openAddr + * property + * info + * @property openBirthDate + * kdoc property + * comment + */ +open class B constructor( + open val openName: String, + open val openLastName: String, + open val openBirthDate: String, + /** + * @property openAddr property + * comment + */ + open val openAddr: String +) {} + +/** + * @property internalName internal + * property info + * single-line comment + * @property openName override + * property info + * single-line comment + * @param privateLastName private + * property info + * block + * comment + * @property openAddr override + * property info + * @param privateName single-line comment + * @property protectedName single-line comment + * @property name single-line comment + * @param paramName single-line comment + * @property protectedLastName + * block + * comment + * @property internalLastName + * block + * comment + * @property openLastName + * block + * comment + * @property lastName + * block + * comment + * @param paramLastName + * block + * comment + * @param privateBirthDate + * kdoc property + * comment + * @property protectedBirthDate + * kdoc property + * comment + * @property internalBirthDate + * kdoc property + * comment + * @property openBirthDate + * kdoc property + * comment + * @property birthDate + * kdoc property + * comment + * @param paramBirthDate + * kdoc property + * comment + */ +class A constructor( + private val privateName: String, + protected val protectedName: String, + internal val internalName: String, + override val openName: String, + val name: String, + paramName: String, + private val privateLastName: String, + protected val protectedLastName: String, + internal val internalLastName: String, + override val openLastName: String, + val lastName: String, + paramLastName: String, + private val privateBirthDate: String, + protected val protectedBirthDate: String, + internal val internalBirthDate: String, + override val openBirthDate: String, + val birthDate: String, + paramBirthDate: String, + /** + * @property privateAddr property + * comment + */ + private val privateAddr: String, + /** + * @property protectedAddr property + * comment + */ + protected val protectedAddr: String, + /** + * @property internalAddr property + * comment + */ + internal val internalAddr: String, + /** + * @property openAddr property + * comment + */ + override val openAddr: String, + /** + * @property addr property + * comment + */ + val addr: String, + /** + * @property paramAddr property + * comment + */ + paramAddr: String, +) : B() {} diff --git a/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentPropertiesTest.kt b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentPropertiesTest.kt new file mode 100644 index 0000000000..28b2c70b50 --- /dev/null +++ b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentPropertiesTest.kt @@ -0,0 +1,289 @@ +package test.paragraph2.kdoc + +/** + * @param name property info + */ +class A constructor( + name: String +) {} + +/** + * @param name property info + */ +class A constructor( + //single-line comment + name: String +) {} + +/** + * @param name property info + */ +class A constructor( + /* + * block + * comment + */ + name: String +) {} + +/** + * @param name property info + */ +class A constructor( + /** + * kdoc property + * comment + */ + name: String +) {} + +/** + * @param name property info + */ +class A constructor( + /** + * @property name property + * comment + */ + name: String +) {} + +/** + * @property name property info + */ +class A constructor( + val name: String +) {} + +/** + * @property name property info + */ +class A constructor( + //single-line comment + val name: String +) {} + +/** + * @property name property info + */ +class A constructor( + /* + * block + * comment + */ + val name: String +) {} + +/** + * @property name property info + */ +class A constructor( + /** + * kdoc property + * comment + */ + val name: String +) {} + +/** + * @property name property info + */ +class A constructor( + /** + * @property name property + * comment + */ + val name: String +) {} + +/** + * @property name property info + */ +class A constructor( + private val name: String +) {} + +/** + * @property name property info + */ +class A constructor( + //single-line comment + private val name: String +) {} + +/** + * @property name property info + */ +class A constructor( + /* + * block + * comment + */ + private val name: String +) {} + +/** + * @property name property info + */ +class A constructor( + /** + * kdoc property + * comment + */ + private val name: String +) {} + +/** + * @property name property info + */ +class A constructor( + /** + * @property name property + * comment + */ + private val name: String +) {} + +/** + * @property openName open property info + * @param openLastName + * open last property + * info + * @property openAddr + * property + * info + */ +open class B constructor( + //single-line comment + open val openName: String, + /* + * block + * comment + */ + open val openLastName: String, + /** + * kdoc property + * comment + */ + open val openBirthDate: String, + /** + * @property openAddr property + * comment + */ + open val openAddr: String +) {} + +/** + * @property internalName internal + * property info + * @param openName override + * property info + * @property privateLastName private + * property info + * @property openAddr override + * property info + */ +class A constructor( + //single-line comment + private val privateName: String, + //single-line comment + protected val protectedName: String, + //single-line comment + internal val internalName: String, + //single-line comment + override val openName: String, + //single-line comment + val name: String, + //single-line comment + paramName: String, + /* + * block + * comment + */ + private val privateLastName: String, + /* + * block + * comment + */ + protected val protectedLastName: String, + /* + * block + * comment + */ + internal val internalLastName: String, + /* + * block + * comment + */ + override val openLastName: String, + /* + * block + * comment + */ + val lastName: String, + /* + * block + * comment + */ + paramLastName: String, + /** + * kdoc property + * comment + */ + private val privateBirthDate: String, + /** + * kdoc property + * comment + */ + protected val protectedBirthDate: String, + /** + * kdoc property + * comment + */ + internal val internalBirthDate: String, + /** + * kdoc property + * comment + */ + override val openBirthDate: String, + /** + * kdoc property + * comment + */ + val birthDate: String, + /** + * kdoc property + * comment + */ + paramBirthDate: String, + /** + * @property privateAddr property + * comment + */ + private val privateAddr: String, + /** + * @property protectedAddr property + * comment + */ + protected val protectedAddr: String, + /** + * @property internalAddr property + * comment + */ + internal val internalAddr: String, + /** + * @property openAddr property + * comment + */ + override val openAddr: String, + /** + * @property addr property + * comment + */ + val addr: String, + /** + * @property paramAddr property + * comment + */ + paramAddr: String, +) : B() {} diff --git a/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentTest.kt b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentTest.kt index 562189c413..04c6ff97b0 100644 --- a/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentTest.kt +++ b/diktat-rules/src/test/resources/test/paragraph2/kdoc/ConstructorCommentTest.kt @@ -1,31 +1,310 @@ package test.paragraph2.kdoc /** - * @property name another text + * kdoc + * class + * comment */ -class A ( - /** - * some text - */ - var name: String -){} +class A constructor( + name: String +) {} /** - * @property name another text + * kdoc + * class + * comment */ -class A ( - /** - * @property name some text - */ - val name: String -){} +class A constructor( + //single-line comment + name: String +) {} /** - * @property name another text + * kdoc + * class + * comment */ -class A ( - /* - * text - */ - val name: String -){} +class A constructor( + /* + * block + * comment + */ + name: String +) {} + +/** + * kdoc + * class + * comment + */ +class A constructor( + /** + * kdoc property + * comment + */ + name: String +) {} + +/** + * kdoc + * class + * comment + */ +class A constructor( + /** + * @property name property + * comment + */ + name: String +) {} + +/** + * kdoc + * class + * comment + */ +class A constructor( + val name: String +) {} + +/** + * kdoc + * class + * comment + */ +class A constructor( + //single-line comment + val name: String +) {} + +/** + * kdoc + * class + * comment + */ +class A constructor( + /* + * block + * comment + */ + val name: String +) {} + +/** + * kdoc + * class + * comment + */ +class A constructor( + /** + * kdoc property + * comment + */ + val name: String +) {} + +/** + * kdoc + * class + * comment + */ +class A constructor( + /** + * @property name property + * comment + */ + val name: String +) {} + +/** + * kdoc + * class + * comment + */ +class A constructor( + private val name: String +) {} + +/** + * kdoc + * class + * comment + */ +class A constructor( + //single-line comment + private val name: String +) {} + +/** + * kdoc + * class + * comment + */ +class A constructor( + /* + * block + * comment + */ + private val name: String +) {} + +/** + * kdoc + * class + * comment + */ +class A constructor( + /** + * kdoc property + * comment + */ + private val name: String +) {} + +/** + * kdoc + * class + * comment + */ +class A constructor( + /** + * @property name property + * comment + */ + private val name: String +) {} + +/** + * kdoc + * class + * comment + */ +open class B constructor( + //single-line comment + open val openName: String, + /* + * block + * comment + */ + open val openLastName: String, + /** + * kdoc property + * comment + */ + open val openBirthDate: String, + /** + * @property openAddr property + * comment + */ + open val openAddr: String +) {} + +/** + * kdoc + * class + * comment + */ +class A constructor( + //single-line comment + private val privateName: String, + //single-line comment + protected val protectedName: String, + //single-line comment + internal val internalName: String, + //single-line comment + override val openName: String, + //single-line comment + val name: String, + //single-line comment + paramName: String, + /* + * block + * comment + */ + private val privateLastName: String, + /* + * block + * comment + */ + protected val protectedLastName: String, + /* + * block + * comment + */ + internal val internalLastName: String, + /* + * block + * comment + */ + override val openLastName: String, + /* + * block + * comment + */ + val lastName: String, + /* + * block + * comment + */ + paramLastName: String, + /** + * kdoc property + * comment + */ + private val privateBirthDate: String, + /** + * kdoc property + * comment + */ + protected val protectedBirthDate: String, + /** + * kdoc property + * comment + */ + internal val internalBirthDate: String, + /** + * kdoc property + * comment + */ + override val openBirthDate: String, + /** + * kdoc property + * comment + */ + val birthDate: String, + /** + * kdoc property + * comment + */ + paramBirthDate: String, + /** + * @property privateAddr property + * comment + */ + private val privateAddr: String, + /** + * @property protectedAddr property + * comment + */ + protected val protectedAddr: String, + /** + * @property internalAddr property + * comment + */ + internal val internalAddr: String, + /** + * @property openAddr property + * comment + */ + override val openAddr: String, + /** + * @property addr property + * comment + */ + val addr: String, + /** + * @property paramAddr property + * comment + */ + paramAddr: String, +) : B() {} diff --git a/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/common/LocalCommandExecutor.kt b/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/common/LocalCommandExecutor.kt index d6b44584f4..de4e611930 100644 --- a/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/common/LocalCommandExecutor.kt +++ b/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/common/LocalCommandExecutor.kt @@ -14,6 +14,9 @@ import kotlinx.coroutines.runBlocking /** * Class that wraps shell [command] and can execute it + * + * @param command + * @param ioDispatcher */ class LocalCommandExecutor internal constructor( private val command: String, diff --git a/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/config/TestArgumentsReader.kt b/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/config/TestArgumentsReader.kt index e9035f28c5..11a7353d84 100644 --- a/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/config/TestArgumentsReader.kt +++ b/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/config/TestArgumentsReader.kt @@ -22,8 +22,8 @@ import kotlinx.serialization.json.decodeFromStream /** * Class that gives access to properties of a test * + * @param args CLI arguments * @param classLoader [ClassLoader] which is used to load properties file - * @property args CLI arguments * @property properties properties from properties file */ class TestArgumentsReader( diff --git a/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/processing/FileComparator.kt b/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/processing/FileComparator.kt index 4e229f7641..adb05288ed 100644 --- a/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/processing/FileComparator.kt +++ b/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/processing/FileComparator.kt @@ -11,6 +11,10 @@ import java.io.File /** * A class that is capable of comparing files content + * + * @param fileName + * @param expectedResult + * @param actualResult */ class FileComparator( private val fileName: String, diff --git a/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/processing/TestComparatorUnit.kt b/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/processing/TestComparatorUnit.kt index 85d82fb64e..8731fb2033 100644 --- a/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/processing/TestComparatorUnit.kt +++ b/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/processing/TestComparatorUnit.kt @@ -10,9 +10,9 @@ import kotlin.io.path.name /** * Class that can apply transformation to an input file and then compare with expected result and output difference. * - * @property resourceFilePath only used when the files are loaded as resources, + * @param resourceFilePath only used when the files are loaded as resources, * via [compareFilesFromResources]. - * @property function a transformation that will be applied to the file + * @param function a transformation that will be applied to the file */ @Suppress("ForbiddenComment", "TYPE_ALIAS") class TestComparatorUnit( diff --git a/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/processing/TestProcessingFactory.kt b/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/processing/TestProcessingFactory.kt index 9396ce8a77..679771240e 100644 --- a/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/processing/TestProcessingFactory.kt +++ b/diktat-test-framework/src/main/kotlin/com/saveourtool/diktat/test/framework/processing/TestProcessingFactory.kt @@ -17,6 +17,8 @@ import kotlin.system.exitProcess /** * A class that runs tests based on configuration + * + * @param argReader */ @Suppress("ForbiddenComment") class TestProcessingFactory(private val argReader: TestArgumentsReader) { diff --git a/info/available-rules.md b/info/available-rules.md index 4cfa76d5bb..75887c41b0 100644 --- a/info/available-rules.md +++ b/info/available-rules.md @@ -1,132 +1,132 @@ -| Chap | Standard | Rule name | Description | Fix | Config | FixMe | -|------|----------|-------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| 1 | 1.1.1 | CONFUSING_IDENTIFIER_NAMING | Check: warns if the identifier has an inappropriate name (see table of [rule 1.2 part 6](guide/diktat-coding-convention.md#-111-identifiers-naming-conventions)). | no | no | no | -| 1 | 1.1.1 | BACKTICKS_PROHIBITED | Check: warns if backticks (``) are used in the identifier name, except in the case when it is a test method (marked with `@Test` annotation). | no | no | - | | -| 1 | 1.1.1 | VARIABLE_NAME_INCORRECT | Check: warns if a variable name consists of only a single character; the only exceptions are industry-standard fixed names, such as {`i`, `j`}.
Fix: No fix is available, since it is the responsibility of a human to choose a meaningful identifier name. | no | no | Recursively update usages of this class in the projectMake exceptions configurable. | -| 1 | 1.1.1 | EXCEPTION_SUFFIX | Check: warns if a class that extends any `Exception` class does not have an "Exception" suffix.
Fix: adding the "Exception" suffix to the class name. | yes | no | Need to add tests for this. | -| 1 | 1.1.1 | IDENTIFIER_LENGTH | Check: identifier length should be in the [2,64] range , except for industry-standard names, such as {`i`, `j`} and 'e' for catching exceptions.
Fix: Fix: no fix is available, since only a human can choose a meaningful identifier name, depending on the context. | no | no | May be make this rule configurable (length) | -| 1 | 1.1.1 | FILE_NAME_INCORRECT | Check: warns if a file name does not have a `.kt`/`.kts` extension.
Fix: no | no | no | Extensions should be configurable; it can be autofixed. | -| 1 | 1.1.1 | GENERIC_NAME | Check: warns if the name of a [_generic type parameter_](https://kotlinlang.org/docs/generics.html) (e.g. `T`) consists of more than a single capital letter. The capital letter can be followed by numbers, though (e.g. `T12`).
Fix: | yes | no | Recursively update usages of this identifier in the project. | -| 1 | 1.1.1 | VARIABLE_HAS_PREFIX | Check: warns if the name of a variable has a [Hungarian notation](https://en.wikipedia.org/wiki/Hungarian_notation) specific prefix (like `mVariable` or `M_VARIABLE`), which is considered a bad code style (_Android_ is the only exception).
Fix: none is available, as only a human can choose a meaningful name, depending on a particular context. | no | no | | -| 1 | 1.2.1 | PACKAGE_NAME_MISSING | Check: warns if a package declaration is missing in the file.
Fix: automatically adds a package directive with the name that starts from the domain name (example - com.huawei) and contains the real directory. | yes | no | Recursively fix all imports in the project.
Fix the directory where the code is stored.
Make this check isolated from the domain name addition. | -| 1 | 1.2.1 | PACKAGE_NAME_INCORRECT_CASE | Check: warns if a package name is incorrect (non-lower) case.
Fix: automatically update the case in package name. | yes | no | Recursively update all imports in the project. | -| 1 | 1.2.1 | PACKAGE_NAME_INCORRECT_PREFIX | Check: warns if a package name does not start with the company's domain.
Fix: automatically update the prefix in the package name. | yes | no | Fix the directory where the code is stored.
Recursively update all imports in the project. | -| 1 | 1.2.1 | PACKAGE_NAME_INCORRECT_SYMBOLS | Check: warns if a package name has incorrect symbols, such as underscore or non-ASCII letters/digits. Exception: underscores that are used for differentiating of keywords in a name.
Fix: no fix currently available; will be suggested later. | no | no | Add autofix for at least converting underscore to a dot or replacing itFix the directory where the code is stored. Cover autofix with tests. | -| 1 | 1.2.1 | PACKAGE_NAME_INCORRECT_PATH | Check: warns if the path for a file does not match with a package name.
Fix: replacing the incorrect package name with the name constructed from a path to the file. | yes | no | Make this check isolated from domain name creation. Recursively update all imports in the project. Fix the directory where the code is stored. Add a test mechanism to test checker. | -| 1 | 1.2.1 | INCORRECT_PACKAGE_SEPARATOR | Check: warns if the underscore is incorrectly used in package naming to split name parts.
Fix: fixing all nodes in AST and the package name to remove all underscores. | no | no | Recursively update usages of this class in the project. | -| 1 | 1.3.1 | CLASS_NAME_INCORRECT | Check: warns if the Class/Enum/Interface name does not match the Pascal case ("([A-Z][a-z0-9]+)+").
Fix: fixing the case. If it is some fixed case (like Snake or Camel) - with word saving; if not - will restore PascalCase as is. | yes | no | Recursively update usages of this class in the projectCheck and find the better way of converting the identifier to PascalCaseNeed to add checks using natural language processing and check that the class name contains only nouns. | -| 1 | 1.3.1 | OBJECT_NAME_INCORRECT | Check: warns if the object does not match the Pascal case ("([A-Z][a-z0-9]+)+").
Fix: fixing the case in the same way as for the classes. | yes | no | Recursively update usages of this class in the project. | -| 1 | 1.3.1 | ENUM_VALUE | Check: verifies if the enum value is in UPPER_SNAKE_CASE or in PascalCase depending on the configuration. UPPER_SNAKE_CASE is the default configuration, but can be changed by 'enumStyle' config.
Fix: automatically converting the enum case to a properly selected case | yes | enumStyle: snakeCase, pascalCase | Recursively update usages of this identifier in the project. | -| 1 | 1.3.1 | TYPEALIAS_NAME_INCORRECT_CASE | Check: typealias name should be in pascalCase.
Fix: | yes | no | Recursively update usages of this typealias in the project. | -| 1 | 1.4.1 | FUNCTION_NAME_INCORRECT_CASE | Check: function/method name should be in lowerCamelCase.
Fix: | yes | no | Recursively update usages of this function in the project. | -| 1 | 1.5.1 | CONSTANT_UPPERCASE | Check: warns if CONSTANT (treated as const val from companion object or class level) is not in UPPER_SNAKE_CASE.
Fix: name is changed to UPPER_SNAKE_CASE. | yes | no | Recursively update usages of this identifier in the project. | -| 1 | 1.6.1 | VARIABLE_NAME_INCORRECT_FORMAT | Check: warns if the name of a variable is not in lowerCamelCase or contains non-ASCII letters.
Fix: fixing the case format to lowerCamelCase. | | no | - | -| 1 | 1.6.2 | FUNCTION_BOOLEAN_PREFIX | Check: functions/methods that return boolean should have a special prefix, such as "is/should/etc."
Fix: | yes | no | Recursively update usages of this function in the project. Aggressive fix - what if the new name will not be valid? | -| 2 | 2.1.1 | MISSING_KDOC_TOP_LEVEL | Check: warns at a file level internal or public class or if the function has a missing KDoc.
Fix: no | no | no | Support extension for setters/getters. Support extension for method "override". | -| 2 | 2.1.1 | KDOC_EXTRA_PROPERTY | Check: warn if there is a property in KDoc that is not present in the class. | no | no | - | -| 2 | 2.1.1 | KDOC_DUPLICATE_PROPERTY | Check: warn if there's a property in KDoc which is already present. | no | no | - | -| 2 | 2.1.1 | MISSING_KDOC_CLASS_ELEMENTS | Check: warns if accessible internal elements (protected, public, internal) in a class are not documented.
Fix: no | no | no | Maybe exception cases for setters and getters are needed; no sense in adding KDoc to them. | -| 2 | 2.1.1 | MISSING_KDOC_ON_FUNCTION | Check: warns if accessible function doesn't have KDoc.
Fix: adds KDoc template if it is not empty. | yes | no | | -| 2 | 2.1.1 | KDOC_NO_CONSTRUCTOR_PROPERTY | Check: warns if there is no property tag inside KDoc before the constructor. | yes | no | | -| 2 | 2.1.1 | KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER | Check: warns if the property is declared in a class body but documented with a property tag inside KDoc before the constructor. | yes | no | | -| 2 | 2.1.1 | KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT | Check: warns if there is a comment before the property in the constructor. | yes | no | | -| 2 | 2.1.1 | COMMENTED_BY_KDOC | Check: warns if there is a kdoc comment in the code block. | yes | no | replace "/**" to "/*" | -| 2 | 2.1.2 | KDOC_WITHOUT_PARAM_TAG | Check: warns if an accessible method has parameters and they are not documented in KDoc.
Fix: If accessible method has no KDoc, the KDoc template is added. | yes | no | Should also make a separate fix, even if there is already some Kdoc in place. | -| 2 | 2.1.2 | KDOC_WITHOUT_RETURN_TAG | Check: warns if the accessible method has an explicit return type. Then it is not documented in KDoc.
Fix: If the accessible method has no KDoc, the KDoc template is added. | yes | no | Should also make separate fix, even if there is already some Kdoc in place. | -| 2 | 2.1.2 | KDOC_WITHOUT_THROWS_TAG | Check: warns if the accessible method has the throw keyword and it is not documented in KDoc.
Fix: if the accessible method has no KDoc, KDoc template is added. | yes | no | Should also make separate fix, even if there is already some Kdoc in place. | -| 2 | 2.1.3 | KDOC_EMPTY_KDOC | Check: warns if the KDoc is empty.
Fix: no | no | no | | -| 2 | 2.1.3 | KDOC_WRONG_SPACES_AFTER_TAG | Check: warns if there is more than one space after the KDoc tag.
Fix: removes redundant spaces. | yes | no | | -| 2 | 2.1.3 | KDOC_WRONG_TAGS_ORDER | Check: warns if the basic KDoc tags are not ordered properly.
Fix: reorders tags (`@receiver`, `@param`, `@property`, `@return`, `@throws` or `@exception`, `@constructor`). | yes | no | Ensure basic tags are at the end of KDoc. | -| 2 | 2.1.3 | KDOC_NEWLINES_BEFORE_BASIC_TAGS | Check: warns if the block of tags (@param, @return, @throws) is not separated from the previous part of KDoc by exactly one empty line.
Fix: adds an empty line or removes a redundant one. | yes | no | | -| 2 | 2.1.3 | KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS | Check: if there is a newline of an empty KDoc line (with a leading asterisk) between `@param`, `@return`, `@throws` tags.
Fix: removes the line. | yes | no | | -| 2 | 2.1.3 | KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS | Check: warns if special tags `@apiNote`, `@implNote`, `@implSpec` don't have exactly one empty line after.
Fix: removes redundant lines or adds one. | yes | no | Handle empty lines without a leading asterisk. | -| 2 | 2.1.3 | KDOC_NO_DEPRECATED_TAG | Check: warns if `@deprecated` is used in KDoc.
Fix: adds `@Deprecated` annotation with a message; removes the tag. | yes | no | The `replaceWith` field in the annotation can also be filled with a meaningful value. | -| 2 | 2.2.1 | KDOC_NO_EMPTY_TAGS | Check: warns if the KDoc tags have an empty content. | no | no | | -| 2 | 2.2.1 | KDOC_CONTAINS_DATE_OR_AUTHOR | Check: warns if the KDoc header contains the `@author` tag.
Also warns if the `@since` tag is present but contains anything but version (e.g.: a date). | no | no | Detect the author by other patterns (e.g. 'created by' etc.) | -| 2 | 2.2.1 | HEADER_WRONG_FORMAT | Checks: warns if there is no newline after the KDoc header.
Fix: adds a newline | yes | no | Check if the header is on the very top of the file. It is hard to determine when it is not. | -| 2 | 2.2.1 | HEADER_MISSING_OR_WRONG_COPYRIGHT | Checks: copyright exists on top of the file and is properly formatted (as a block comment).
Fix: adds copyright if it is missing and required. | yes | isCopyrightMandatory, copyrightText (sets the copyright pattern for your project, you also can use `;@currYear;` the key word in your text in aim to indicate the current year, instead of explicitly specifying). | | -| 2 | 2.2.1 | WRONG_COPYRIGHT_YEAR | Checks: copyright has a valid year.
Fix: makes the year valid. | yes | no | - | -| 2 | 2.2.1 | HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE | Check: warns if a file with zero or >1 classes doesn't have a KDoc header. | no | no | | -| 2 | 2.2.1 | HEADER_NOT_BEFORE_PACKAGE | Check: warns if a KDoc file header is located not before a package directive.
Fix: moves this KDoc | yes | no | | -| 2 | 2.3.1 | KDOC_TRIVIAL_KDOC_ON_FUNCTION | Check: warns if KDoc contains a single line with words 'return', 'get' or 'set'. | no | no | | -| 2 | 2.4.1 | COMMENT_WHITE_SPACE | Check: warns if there is no space between // and comment, and if there is no space between the code and the comment
.Fix: adds a white space. | yes | maxSpaces | - | -| 2 | 2.4.1 | WRONG_NEWLINES_AROUND_KDOC | Check: warns if there is no new line above and under the comment. Exception on the first comment.
Fix: adds a new line. | yes | no | - | -| 2 | 2.4.1 | FIRST_COMMENT_NO_BLANK_LINE | Check: warns if there is a new line before the first comment.
Fix: deletes a new line. | yes | no | - | -| 2 | 2.4.1 | IF_ELSE_COMMENTS | Check: warns if there is a comment outside of the else block.
Fix: adds the comment to the first line in else block. | yes | no | - | -| 2 | 2.4.2 | COMMENTED_OUT_CODE | Check: warns if the commented code is detected (when uncommented, can be parsed). | no | no | Offset is lost when the joined EOL comments are split again. | -| 3 | 3.1.1 | FILE_IS_TOO_LONG | Check: warns if the file has too many lines.
Fix: no | no | maxSize | - | -| 1 | 3.1.2 | FILE_NAME_MATCH_CLASS | Check: warns
Fix: no | no | no | Probably, it can be agressively autofixed. | -| 3 | 3.1.2 | FILE_CONTAINS_ONLY_COMMENTS | Check: warns if the file contains only comments, imports, and package directive. | no | no | - | -| 3 | 3.1.2 | FILE_INCORRECT_BLOCKS_ORDER | Check: warns if the general order of code parts is wrong.
Fix: rearranges parts of code. | yes | no | handle other elements that could be present before the package directive (other comments). | -| 3 | 3.1.2 | FILE_NO_BLANK_LINE_BETWEEN_BLOCKS | Check: warns if there is not exactly one blank line between the code parts.
Fix: leaves a single empty line. | yes | no | - | -| 3 | 3.1.2 | FILE_UNORDERED_IMPORTS | Check: warns if the imports are not sorted alphabetically, or there are empty lines among them.
Fix: reorders imports. | yes | no | - | -| 3 | 3.1.2 | FILE_WILDCARD_IMPORTS | Check: warns if the wildcard imports are used except the cases when they are allowed. | no | allowedWildcards | - | -| 3 | 3.1.2 | UNUSED_IMPORT | Check: warns if an import is not used. | no | deleteUnusedImport | - | -| 3 | 3.1.4 | WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES | Check: warns if the declaration part of a class, such as a code structure (class, interface, etc.) is not in the proper order.
Fix: restores the order according to the code style guide. | yes | no | - | -| 3 | 3.1.4 | BLANK_LINE_BETWEEN_PROPERTIES | Check: warns if properties with comments are not separated by a blank line.
Fix: fixes the number of blank lines. | yes | no | - | -| 3 | 3.1.4 | WRONG_DECLARATIONS_ORDER | Check: if the order of enum values or constant properties inside the companion is not correct. | yes | no | - | -| 3 | 3.1.5 | TOP_LEVEL_ORDER | Check: warns if the top level order is incorrect. | yes | no | - | -| 3 | 3.2.1 | NO_BRACES_IN_CONDITIONALS_AND_LOOPS | Check: warns if braces are not used in `if`, `else`, `when`, `for`, `do`, and `while` statements. Exception: single line if statement (ternary operator).
Fix: adds missing braces. | yes | no | - | -| 3 | 3.2.2 | BRACES_BLOCK_STRUCTURE_ERROR | Check: warns if non-empty code blocks with braces do not follow the K&R style (1TBS or OTBS style). | yes | openBraceNewline closeBraceNewline | - | -| 3 | 3.3.1 | WRONG_INDENTATION | Check: warns if an indentation is incorrect.
Fix: corrects the indentation.

Basic cases are covered currently. | yes | extendedIndentOfParameters
alignedParameters
extendedIndentForExpressionBodies
extendedIndentAfterOperators
extendedIndentBeforeDot
indentationSize | - | -| 3 | 3.4.1 | EMPTY_BLOCK_STRUCTURE_ERROR | Check: warns if an empty block exists or if its style is incorrect. | yes | allowEmptyBlocks styleEmptyBlockWithNewline | - | -| 3 | 3.5.1 | LONG_LINE | Check: warns if the length doesn't exceed the specified length. | no | lineLength | Handle json method in KDoc. | -| 3 | 3.6.1 | MORE_THAN_ONE_STATEMENT_PER_LINE | Check: warns if there is more than one statement per line. | yes | no | - | -| 3 | 3.6.2 | REDUNDANT_SEMICOLON | Check: warns if semicolons are used at the end of a line.
Fix: removes the semicolon. | yes | no | - | -| 3 | 3.6.2 | WRONG_NEWLINES | Check: warns if line breaks do not follow the code style guide.
Fix: fixes incorrect line breaks. | yes | no | - | -| 3 | 3.6.2 | COMPLEX_EXPRESSION | Check: warns if a long dot-qualified expression is used in a condition or as an argument. | no | no | - | -| 3 | 3.6.2 | TRAILING_COMMA | Check: warns if a trailing comma is missing. | yes | valueArgument valueParameter indices whenConditions collectionLiteral typeArgument typeParameter destructuringDeclaration | - | -| 3 | 3.7.1 | TOO_MANY_BLANK_LINES | Check: warns if blank lines are used or placed incorrectly.
Fix: removes redundant blank lines. | yes | no | | -| 3 | 3.8.1 | WRONG_WHITESPACE | Check: warns if the usage of horizontal spaces violates the code style guide.
Fix: fixes incorrect whitespaces. | yes | no | - | -| 3 | 3.8.1 | TOO_MANY_CONSECUTIVE_SPACES | Check: warns if there are too many consecutive spaces in a line. Exception: in an enum if there is a configured and single eol comment.
Fix: squeezes spaces to 1. | yes | maxSpaces saveInitialFormattingForEnums | - | -| 3 | 3.9.1 | ENUMS_SEPARATED | Check: warns if an enum structure is incorrect: the enum entries should be separated by a comma and a line break, and the last entry should have a semicolon in the end. | yes | no | Replace variable to enum if it possible. | -| 3 | 3.10.2 | LOCAL_VARIABLE_EARLY_DECLARATION | Check: warns if a local variable is declared not immediately before its usage.
Fix (not implemented yet): moves the variable declaration. | no | no | add auto fix | -| 3 | 3.11.1 | WHEN_WITHOUT_ELSE | Check: warns if a `when` statement does not have `else` in the end.
Fix: adds `else` when a statement doesn't have it. | yes | no | - | If a `when` statement of the enum or sealed type contains all values of the enum, there is no need to have the "else" branch. | -| 3 | 3.12.1 | ANNOTATION_NEW_LINE | Check: warns if an annotation is not on a new single line. | yes | no | - | -| 3 | 3.12.2 | PREVIEW_ANNOTATION | Check: warns if method, annotated with `@Preview` is not private or has no `Preview` suffix. | yes | no | - | -| 3 | 3.14.1 | WRONG_MULTIPLE_MODIFIERS_ORDER | Check: warns if the multiple modifiers in the sequence are in the wrong order. Value identifier supported in Kotlin 1.5 | yes | no | - | -| 3 | 3.14.2 | LONG_NUMERICAL_VALUES_SEPARATED | Check: warns if the value of the integer or float constant is too big. | no | maxNumberLength maxBlockLength | - | +| Chap | Standard | Rule name | Description | Fix | Config | FixMe | +|------|----------|-------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 1 | 1.1.1 | CONFUSING_IDENTIFIER_NAMING | Check: warns if the identifier has an inappropriate name (see table of [rule 1.2 part 6](guide/diktat-coding-convention.md#-111-identifiers-naming-conventions)). | no | no | no | +| 1 | 1.1.1 | BACKTICKS_PROHIBITED | Check: warns if backticks (``) are used in the identifier name, except in the case when it is a test method (marked with `@Test` annotation). | no | no | - | | +| 1 | 1.1.1 | VARIABLE_NAME_INCORRECT | Check: warns if a variable name consists of only a single character; the only exceptions are industry-standard fixed names, such as {`i`, `j`}.
Fix: No fix is available, since it is the responsibility of a human to choose a meaningful identifier name. | no | no | Recursively update usages of this class in the projectMake exceptions configurable. | +| 1 | 1.1.1 | EXCEPTION_SUFFIX | Check: warns if a class that extends any `Exception` class does not have an "Exception" suffix.
Fix: adding the "Exception" suffix to the class name. | yes | no | Need to add tests for this. | +| 1 | 1.1.1 | IDENTIFIER_LENGTH | Check: identifier length should be in the [2,64] range , except for industry-standard names, such as {`i`, `j`} and 'e' for catching exceptions.
Fix: Fix: no fix is available, since only a human can choose a meaningful identifier name, depending on the context. | no | no | May be make this rule configurable (length) | +| 1 | 1.1.1 | FILE_NAME_INCORRECT | Check: warns if a file name does not have a `.kt`/`.kts` extension.
Fix: no | no | no | Extensions should be configurable; it can be autofixed. | +| 1 | 1.1.1 | GENERIC_NAME | Check: warns if the name of a [_generic type parameter_](https://kotlinlang.org/docs/generics.html) (e.g. `T`) consists of more than a single capital letter. The capital letter can be followed by numbers, though (e.g. `T12`).
Fix: | yes | no | Recursively update usages of this identifier in the project. | +| 1 | 1.1.1 | VARIABLE_HAS_PREFIX | Check: warns if the name of a variable has a [Hungarian notation](https://en.wikipedia.org/wiki/Hungarian_notation) specific prefix (like `mVariable` or `M_VARIABLE`), which is considered a bad code style (_Android_ is the only exception).
Fix: none is available, as only a human can choose a meaningful name, depending on a particular context. | no | no | | +| 1 | 1.2.1 | PACKAGE_NAME_MISSING | Check: warns if a package declaration is missing in the file.
Fix: automatically adds a package directive with the name that starts from the domain name (example - com.huawei) and contains the real directory. | yes | no | Recursively fix all imports in the project.
Fix the directory where the code is stored.
Make this check isolated from the domain name addition. | +| 1 | 1.2.1 | PACKAGE_NAME_INCORRECT_CASE | Check: warns if a package name is incorrect (non-lower) case.
Fix: automatically update the case in package name. | yes | no | Recursively update all imports in the project. | +| 1 | 1.2.1 | PACKAGE_NAME_INCORRECT_PREFIX | Check: warns if a package name does not start with the company's domain.
Fix: automatically update the prefix in the package name. | yes | no | Fix the directory where the code is stored.
Recursively update all imports in the project. | +| 1 | 1.2.1 | PACKAGE_NAME_INCORRECT_SYMBOLS | Check: warns if a package name has incorrect symbols, such as underscore or non-ASCII letters/digits. Exception: underscores that are used for differentiating of keywords in a name.
Fix: no fix currently available; will be suggested later. | no | no | Add autofix for at least converting underscore to a dot or replacing itFix the directory where the code is stored. Cover autofix with tests. | +| 1 | 1.2.1 | PACKAGE_NAME_INCORRECT_PATH | Check: warns if the path for a file does not match with a package name.
Fix: replacing the incorrect package name with the name constructed from a path to the file. | yes | no | Make this check isolated from domain name creation. Recursively update all imports in the project. Fix the directory where the code is stored. Add a test mechanism to test checker. | +| 1 | 1.2.1 | INCORRECT_PACKAGE_SEPARATOR | Check: warns if the underscore is incorrectly used in package naming to split name parts.
Fix: fixing all nodes in AST and the package name to remove all underscores. | no | no | Recursively update usages of this class in the project. | +| 1 | 1.3.1 | CLASS_NAME_INCORRECT | Check: warns if the Class/Enum/Interface name does not match the Pascal case ("([A-Z][a-z0-9]+)+").
Fix: fixing the case. If it is some fixed case (like Snake or Camel) - with word saving; if not - will restore PascalCase as is. | yes | no | Recursively update usages of this class in the projectCheck and find the better way of converting the identifier to PascalCaseNeed to add checks using natural language processing and check that the class name contains only nouns. | +| 1 | 1.3.1 | OBJECT_NAME_INCORRECT | Check: warns if the object does not match the Pascal case ("([A-Z][a-z0-9]+)+").
Fix: fixing the case in the same way as for the classes. | yes | no | Recursively update usages of this class in the project. | +| 1 | 1.3.1 | ENUM_VALUE | Check: verifies if the enum value is in UPPER_SNAKE_CASE or in PascalCase depending on the configuration. UPPER_SNAKE_CASE is the default configuration, but can be changed by 'enumStyle' config.
Fix: automatically converting the enum case to a properly selected case | yes | enumStyle: snakeCase, pascalCase | Recursively update usages of this identifier in the project. | +| 1 | 1.3.1 | TYPEALIAS_NAME_INCORRECT_CASE | Check: typealias name should be in pascalCase.
Fix: | yes | no | Recursively update usages of this typealias in the project. | +| 1 | 1.4.1 | FUNCTION_NAME_INCORRECT_CASE | Check: function/method name should be in lowerCamelCase.
Fix: | yes | no | Recursively update usages of this function in the project. | +| 1 | 1.5.1 | CONSTANT_UPPERCASE | Check: warns if CONSTANT (treated as const val from companion object or class level) is not in UPPER_SNAKE_CASE.
Fix: name is changed to UPPER_SNAKE_CASE. | yes | no | Recursively update usages of this identifier in the project. | +| 1 | 1.6.1 | VARIABLE_NAME_INCORRECT_FORMAT | Check: warns if the name of a variable is not in lowerCamelCase or contains non-ASCII letters.
Fix: fixing the case format to lowerCamelCase. | | no | - | +| 1 | 1.6.2 | FUNCTION_BOOLEAN_PREFIX | Check: functions/methods that return boolean should have a special prefix, such as "is/should/etc."
Fix: | yes | no | Recursively update usages of this function in the project. Aggressive fix - what if the new name will not be valid? | +| 2 | 2.1.1 | MISSING_KDOC_TOP_LEVEL | Check: warns at a file level internal or public class or if the function has a missing KDoc.
Fix: no | no | no | Support extension for setters/getters. Support extension for method "override". | +| 2 | 2.1.1 | KDOC_EXTRA_PROPERTY | Check: warn if there is a property in KDoc that is not present in the class. | no | no | - | +| 2 | 2.1.1 | KDOC_DUPLICATE_PROPERTY | Check: warn if there's a property in KDoc which is already present. | no | no | - | +| 2 | 2.1.1 | MISSING_KDOC_CLASS_ELEMENTS | Check: warns if accessible internal elements (protected, public, internal) in a class are not documented.
Fix: no | no | no | Maybe exception cases for setters and getters are needed; no sense in adding KDoc to them. | +| 2 | 2.1.1 | MISSING_KDOC_ON_FUNCTION | Check: warns if accessible function doesn't have KDoc.
Fix: adds KDoc template if it is not empty. | yes | no | | +| 2 | 2.1.1 | KDOC_NO_CONSTRUCTOR_PROPERTY | Check: warns if there is no property tag inside KDoc before the constructor. | yes | isParamTagsForParameters, isParamTagsForPrivateProperties | | +| 2 | 2.1.1 | KDOC_NO_CLASS_BODY_PROPERTIES_IN_HEADER | Check: warns if the property is declared in a class body but documented with a property tag inside KDoc before the constructor. | yes | no | | +| 2 | 2.1.1 | KDOC_NO_CONSTRUCTOR_PROPERTY_WITH_COMMENT | Check: warns if there is a comment before the property in the constructor. | yes | no | | +| 2 | 2.1.1 | COMMENTED_BY_KDOC | Check: warns if there is a kdoc comment in the code block. | yes | no | replace "/**" to "/*" | +| 2 | 2.1.2 | KDOC_WITHOUT_PARAM_TAG | Check: warns if an accessible method has parameters and they are not documented in KDoc.
Fix: If accessible method has no KDoc, the KDoc template is added. | yes | no | Should also make a separate fix, even if there is already some Kdoc in place. | +| 2 | 2.1.2 | KDOC_WITHOUT_RETURN_TAG | Check: warns if the accessible method has an explicit return type. Then it is not documented in KDoc.
Fix: If the accessible method has no KDoc, the KDoc template is added. | yes | no | Should also make separate fix, even if there is already some Kdoc in place. | +| 2 | 2.1.2 | KDOC_WITHOUT_THROWS_TAG | Check: warns if the accessible method has the throw keyword and it is not documented in KDoc.
Fix: if the accessible method has no KDoc, KDoc template is added. | yes | no | Should also make separate fix, even if there is already some Kdoc in place. | +| 2 | 2.1.3 | KDOC_EMPTY_KDOC | Check: warns if the KDoc is empty.
Fix: no | no | no | | +| 2 | 2.1.3 | KDOC_WRONG_SPACES_AFTER_TAG | Check: warns if there is more than one space after the KDoc tag.
Fix: removes redundant spaces. | yes | no | | +| 2 | 2.1.3 | KDOC_WRONG_TAGS_ORDER | Check: warns if the basic KDoc tags are not ordered properly.
Fix: reorders tags (`@receiver`, `@param`, `@property`, `@return`, `@throws` or `@exception`, `@constructor`). | yes | no | Ensure basic tags are at the end of KDoc. | +| 2 | 2.1.3 | KDOC_NEWLINES_BEFORE_BASIC_TAGS | Check: warns if the block of tags (@param, @return, @throws) is not separated from the previous part of KDoc by exactly one empty line.
Fix: adds an empty line or removes a redundant one. | yes | no | | +| 2 | 2.1.3 | KDOC_NO_NEWLINES_BETWEEN_BASIC_TAGS | Check: if there is a newline of an empty KDoc line (with a leading asterisk) between `@param`, `@return`, `@throws` tags.
Fix: removes the line. | yes | no | | +| 2 | 2.1.3 | KDOC_NO_NEWLINE_AFTER_SPECIAL_TAGS | Check: warns if special tags `@apiNote`, `@implNote`, `@implSpec` don't have exactly one empty line after.
Fix: removes redundant lines or adds one. | yes | no | Handle empty lines without a leading asterisk. | +| 2 | 2.1.3 | KDOC_NO_DEPRECATED_TAG | Check: warns if `@deprecated` is used in KDoc.
Fix: adds `@Deprecated` annotation with a message; removes the tag. | yes | no | The `replaceWith` field in the annotation can also be filled with a meaningful value. | +| 2 | 2.2.1 | KDOC_NO_EMPTY_TAGS | Check: warns if the KDoc tags have an empty content. | no | no | | +| 2 | 2.2.1 | KDOC_CONTAINS_DATE_OR_AUTHOR | Check: warns if the KDoc header contains the `@author` tag.
Also warns if the `@since` tag is present but contains anything but version (e.g.: a date). | no | no | Detect the author by other patterns (e.g. 'created by' etc.) | +| 2 | 2.2.1 | HEADER_WRONG_FORMAT | Checks: warns if there is no newline after the KDoc header.
Fix: adds a newline | yes | no | Check if the header is on the very top of the file. It is hard to determine when it is not. | +| 2 | 2.2.1 | HEADER_MISSING_OR_WRONG_COPYRIGHT | Checks: copyright exists on top of the file and is properly formatted (as a block comment).
Fix: adds copyright if it is missing and required. | yes | isCopyrightMandatory, copyrightText (sets the copyright pattern for your project, you also can use `;@currYear;` the key word in your text in aim to indicate the current year, instead of explicitly specifying). | | +| 2 | 2.2.1 | WRONG_COPYRIGHT_YEAR | Checks: copyright has a valid year.
Fix: makes the year valid. | yes | no | - | +| 2 | 2.2.1 | HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE | Check: warns if a file with zero or >1 classes doesn't have a KDoc header. | no | no | | +| 2 | 2.2.1 | HEADER_NOT_BEFORE_PACKAGE | Check: warns if a KDoc file header is located not before a package directive.
Fix: moves this KDoc | yes | no | | +| 2 | 2.3.1 | KDOC_TRIVIAL_KDOC_ON_FUNCTION | Check: warns if KDoc contains a single line with words 'return', 'get' or 'set'. | no | no | | +| 2 | 2.4.1 | COMMENT_WHITE_SPACE | Check: warns if there is no space between // and comment, and if there is no space between the code and the comment
.Fix: adds a white space. | yes | maxSpaces | - | +| 2 | 2.4.1 | WRONG_NEWLINES_AROUND_KDOC | Check: warns if there is no new line above and under the comment. Exception on the first comment.
Fix: adds a new line. | yes | no | - | +| 2 | 2.4.1 | FIRST_COMMENT_NO_BLANK_LINE | Check: warns if there is a new line before the first comment.
Fix: deletes a new line. | yes | no | - | +| 2 | 2.4.1 | IF_ELSE_COMMENTS | Check: warns if there is a comment outside of the else block.
Fix: adds the comment to the first line in else block. | yes | no | - | +| 2 | 2.4.2 | COMMENTED_OUT_CODE | Check: warns if the commented code is detected (when uncommented, can be parsed). | no | no | Offset is lost when the joined EOL comments are split again. | +| 3 | 3.1.1 | FILE_IS_TOO_LONG | Check: warns if the file has too many lines.
Fix: no | no | maxSize | - | +| 1 | 3.1.2 | FILE_NAME_MATCH_CLASS | Check: warns
Fix: no | no | no | Probably, it can be agressively autofixed. | +| 3 | 3.1.2 | FILE_CONTAINS_ONLY_COMMENTS | Check: warns if the file contains only comments, imports, and package directive. | no | no | - | +| 3 | 3.1.2 | FILE_INCORRECT_BLOCKS_ORDER | Check: warns if the general order of code parts is wrong.
Fix: rearranges parts of code. | yes | no | handle other elements that could be present before the package directive (other comments). | +| 3 | 3.1.2 | FILE_NO_BLANK_LINE_BETWEEN_BLOCKS | Check: warns if there is not exactly one blank line between the code parts.
Fix: leaves a single empty line. | yes | no | - | +| 3 | 3.1.2 | FILE_UNORDERED_IMPORTS | Check: warns if the imports are not sorted alphabetically, or there are empty lines among them.
Fix: reorders imports. | yes | no | - | +| 3 | 3.1.2 | FILE_WILDCARD_IMPORTS | Check: warns if the wildcard imports are used except the cases when they are allowed. | no | allowedWildcards | - | +| 3 | 3.1.2 | UNUSED_IMPORT | Check: warns if an import is not used. | no | deleteUnusedImport | - | +| 3 | 3.1.4 | WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES | Check: warns if the declaration part of a class, such as a code structure (class, interface, etc.) is not in the proper order.
Fix: restores the order according to the code style guide. | yes | no | - | +| 3 | 3.1.4 | BLANK_LINE_BETWEEN_PROPERTIES | Check: warns if properties with comments are not separated by a blank line.
Fix: fixes the number of blank lines. | yes | no | - | +| 3 | 3.1.4 | WRONG_DECLARATIONS_ORDER | Check: if the order of enum values or constant properties inside the companion is not correct. | yes | no | - | +| 3 | 3.1.5 | TOP_LEVEL_ORDER | Check: warns if the top level order is incorrect. | yes | no | - | +| 3 | 3.2.1 | NO_BRACES_IN_CONDITIONALS_AND_LOOPS | Check: warns if braces are not used in `if`, `else`, `when`, `for`, `do`, and `while` statements. Exception: single line if statement (ternary operator).
Fix: adds missing braces. | yes | no | - | +| 3 | 3.2.2 | BRACES_BLOCK_STRUCTURE_ERROR | Check: warns if non-empty code blocks with braces do not follow the K&R style (1TBS or OTBS style). | yes | openBraceNewline closeBraceNewline | - | +| 3 | 3.3.1 | WRONG_INDENTATION | Check: warns if an indentation is incorrect.
Fix: corrects the indentation.

Basic cases are covered currently. | yes | extendedIndentOfParameters
alignedParameters
extendedIndentForExpressionBodies
extendedIndentAfterOperators
extendedIndentBeforeDot
indentationSize | - | +| 3 | 3.4.1 | EMPTY_BLOCK_STRUCTURE_ERROR | Check: warns if an empty block exists or if its style is incorrect. | yes | allowEmptyBlocks styleEmptyBlockWithNewline | - | +| 3 | 3.5.1 | LONG_LINE | Check: warns if the length doesn't exceed the specified length. | no | lineLength | Handle json method in KDoc. | +| 3 | 3.6.1 | MORE_THAN_ONE_STATEMENT_PER_LINE | Check: warns if there is more than one statement per line. | yes | no | - | +| 3 | 3.6.2 | REDUNDANT_SEMICOLON | Check: warns if semicolons are used at the end of a line.
Fix: removes the semicolon. | yes | no | - | +| 3 | 3.6.2 | WRONG_NEWLINES | Check: warns if line breaks do not follow the code style guide.
Fix: fixes incorrect line breaks. | yes | no | - | +| 3 | 3.6.2 | COMPLEX_EXPRESSION | Check: warns if a long dot-qualified expression is used in a condition or as an argument. | no | no | - | +| 3 | 3.6.2 | TRAILING_COMMA | Check: warns if a trailing comma is missing. | yes | valueArgument valueParameter indices whenConditions collectionLiteral typeArgument typeParameter destructuringDeclaration | - | +| 3 | 3.7.1 | TOO_MANY_BLANK_LINES | Check: warns if blank lines are used or placed incorrectly.
Fix: removes redundant blank lines. | yes | no | | +| 3 | 3.8.1 | WRONG_WHITESPACE | Check: warns if the usage of horizontal spaces violates the code style guide.
Fix: fixes incorrect whitespaces. | yes | no | - | +| 3 | 3.8.1 | TOO_MANY_CONSECUTIVE_SPACES | Check: warns if there are too many consecutive spaces in a line. Exception: in an enum if there is a configured and single eol comment.
Fix: squeezes spaces to 1. | yes | maxSpaces saveInitialFormattingForEnums | - | +| 3 | 3.9.1 | ENUMS_SEPARATED | Check: warns if an enum structure is incorrect: the enum entries should be separated by a comma and a line break, and the last entry should have a semicolon in the end. | yes | no | Replace variable to enum if it possible. | +| 3 | 3.10.2 | LOCAL_VARIABLE_EARLY_DECLARATION | Check: warns if a local variable is declared not immediately before its usage.
Fix (not implemented yet): moves the variable declaration. | no | no | add auto fix | +| 3 | 3.11.1 | WHEN_WITHOUT_ELSE | Check: warns if a `when` statement does not have `else` in the end.
Fix: adds `else` when a statement doesn't have it. | yes | no | - | If a `when` statement of the enum or sealed type contains all values of the enum, there is no need to have the "else" branch. | +| 3 | 3.12.1 | ANNOTATION_NEW_LINE | Check: warns if an annotation is not on a new single line. | yes | no | - | +| 3 | 3.12.2 | PREVIEW_ANNOTATION | Check: warns if method, annotated with `@Preview` is not private or has no `Preview` suffix. | yes | no | - | +| 3 | 3.14.1 | WRONG_MULTIPLE_MODIFIERS_ORDER | Check: warns if the multiple modifiers in the sequence are in the wrong order. Value identifier supported in Kotlin 1.5 | yes | no | - | +| 3 | 3.14.2 | LONG_NUMERICAL_VALUES_SEPARATED | Check: warns if the value of the integer or float constant is too big. | no | maxNumberLength maxBlockLength | - | | 3 | 3.14.3 | MAGIC_NUMBER | Check: warns if there are magic numbers in the code. | no | ignoreNumbers, ignoreHashCodeFunction, ignorePropertyDeclaration, ignoreLocalVariableDeclaration, ignoreConstantDeclaration, ignoreCompanionObjectPropertyDeclaration, ignoreEnums, ignoreRanges, ignoreExtensionFunctions | no | -| 3 | 3.15.1 | STRING_CONCATENATION | Check: warns if the concatenation of strings is used in a single line. | yes | no | - | -| 3 | 3.15.2 | STRING_TEMPLATE_CURLY_BRACES | Check: warns if there are redundant curly braces in the string template.
Fix: deletes the curly braces. | yes | no | + | -| 3 | 3.15.2 | STRING_TEMPLATE_QUOTES | Check: warns if there are redundant quotes in the string template.
Fix: deletes the quotes and $ symbol. | yes | no | + | -| 3 | 3.16.1 | COLLAPSE_IF_STATEMENTS | Check: warns if there are redundant nested if-statements, which could be collapsed into a single statement by concatenating their conditions. | yes | no | - | -| 3 | 3.16.2 | COMPLEX_BOOLEAN_EXPRESSION | Check: warns if the boolean expression is complex and can be simplified.
Fix: replaces the boolean expression with a simpler one. | yes | no | + | -| 3 | 3.17.1 | CONVENTIONAL_RANGE | Check: warns if it is possible to replace the range with `until` or replace the `rangeTo` function with a range.
Fix: replace range with `until` or replace the `rangeTo` function with a range. | yes | no | - | -| 3 | 3.18.1 | DEBUG_PRINT | Check: warns if there is a printing to console (assumption that it's a debug logging). | no | no | - | -| 4 | 4.1.1 | FLOAT_IN_ACCURATE_CALCULATIONS | Checks that floating-point values are not used in the arithmetic expressions.
Fix: no | no | no | Current implementation detects only floating-point constants. | -| 4 | 4.1.3 | SAY_NO_TO_VAR | Check: warns if the `var` modifier is used for a local variable (not in a class or at file level), and this var is not used in accumulators. | no | no | no | several fixmes related to the search mechanism (VariablesSearch) and fixme for checking reassinment of this var | -| 4 | 4.2.1 | SMART_CAST_NEEDED | Check: warns if the casting can be omitted.
Fix: Deletes casting. | yes | no | - | | -| 4 | 4.2.2 | TYPE_ALIAS | Check: if the type reference of a property is longer than expected. | yes | typeReferenceLength | - | | -| 4 | 4.3.1 | NULLABLE_PROPERTY_TYPE | Check: warns if an immutable property is initialized with null, or if the immutable property can have non-nullable type instead of nullable.
Fix: suggests the initial value instead of null or changes in the immutable property type. | yes | no | - | -| 4 | 4.3.2 | GENERIC_VARIABLE_WRONG_DECLARATION | Check: warns if variables of generic types don't have an explicit type declaration.
Fix: fixes only the variables that have a generic declaration on both sides. | yes | no | + | -| 4 | 4.3.3 | AVOID_NULL_CHECKS | Check: warns if the null-check is used explicitly (for example: if (a == null)). | yes | no | Fix if\else conditions on null. | -| 5 | 5.1.1 | TOO_LONG_FUNCTION | Check: warns if the length of a function is too long. | no | maxFunctionLength isIncludeHeader | | -| 5 | 5.1.2 | NESTED_BLOCK | Warns if a function has more nested blocks than expected. | no | maxNestedBlockQuantit | | -| 5 | 5.1.3 | AVOID_NESTED_FUNCTIONS | Check: Warns if there are nested functions.
Fix: declare the function in the outer scope. | yes | no | + | -| 5 | 5.1.4 | INVERSE_FUNCTION_PREFERRED | Check: Warns if a function call with "!" can be rewritten to the inverse function (!isEmpty() -> isNotEmpty()).
Fix: Rewrites the function call. | yes | - | - | -| 5 | 5.2.1 | LAMBDA_IS_NOT_LAST_PARAMETER | Checks that the lambda inside function parameters block is not at the end. | no | no | | -| 5 | 5.2.2 | TOO_MANY_PARAMETERS | Check: Warns if a function contains more parameters than allowed. | no | maxParameterListSize | | -| 5 | 5.2.3 | WRONG_OVERLOADING_FUNCTION_ARGUMENTS | Check: Warns if a function has overloading instead of using default arguments. | no | no | | -| 5 | 5.2.4 | RUN_BLOCKING_INSIDE_ASYNC | Check: Warns if the runBlocking is used inside the async block code. | no | no | - | -| 5 | 5.2.5 | TOO_MANY_LINES_IN_LAMBDA | Checks that the long lambda has parameters. | no | maxLambdaLength | | -| 5 | 5.2.6 | CUSTOM_LABEL | Check: Warns if using an unnecessary custom label. | no | no | - | -| 5 | 5.2.7 | PARAMETER_NAME_IN_OUTER_LAMBDA | Check: warns if the outer lambda uses an implicit parameter `it`. | no | no | - | -| 6 | 6.1.1 | SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY | Check: warns if there is only one secondary constructor in a class.
Fix: converts it to a primary constructor. | yes | no | Support the more complicated logic of the constructor conversion. | -| 6 | 6.1.2 | USE_DATA_CLASS | Check: if the class can be made as a data class. | no | no | yes | -| 6 | 6.1.3 | EMPTY_PRIMARY_CONSTRUCTOR | Check: warns if there is an empty primary constructor. | yes | no | yes | -| 6 | 6.1.4 | MULTIPLE_INIT_BLOCKS | Checks that the classes have only one init block. | yes | no | - | -| 6 | 6.1.5 | USELESS_SUPERTYPE | Checks if the override function can be removed. | yes | no | | -| 6 | 6.1.6 | CLASS_SHOULD_NOT_BE_ABSTRACT | Checks if the abstract class has any abstract method. If not, it warns that the class must not be abstract.
Fix: deletes the abstract modifier. | yes | no | - | -| 6 | 6.1.7 | NO_CORRESPONDING_PROPERTY | Checks: warns if with using "backing property" scheme, the name of a real and a back property are the same. | no | no | - | -| 6 | 6.1.8 | CUSTOM_GETTERS_SETTERS | Check that no custom getters and setters are used for the properties. | no | no | - | -| 6 | 6.1.9 | WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR | Checks if the name of a variable is used in the custom getter or setter. | no | no | | -| 6 | 6.1.10 | TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED | Checks if there are trivial getters or setters.
Fix: Delete the trivial getter or setter. | yes | no | - | -| 6 | 6.1.11 | COMPACT_OBJECT_INITIALIZATION | Checks if the class instantiation can be wrapped in `apply` for better readability. | | no | | -| 6 | 6.1.12 | INLINE_CLASS_CAN_BE_USED | Check: warns if the class can be transferred to the inline class. | no | no | yes | -| 6 | 6.2.2 | EXTENSION_FUNCTION_SAME_SIGNATURE | Checks if an extension function has the same signature as another extension function, and their classes are related. | no | no | + | -| 6 | 6.2.3 | EXTENSION_FUNCTION_WITH_CLASS | Check: if the file contains a class, then it can not have extension functions for the same class. | no | no | - | -| 6 | 6.2.4 | USE_LAST_INDEX | Check: change a property length - 1 to the property lastIndex. | no | no | - | -| 6 | 6.4.1 | AVOID_USING_UTILITY_CLASS | Checks if there is a class/object that can be replaced with the extension function. | no | no | - | -| 6 | 6.4.2 | OBJECT_IS_PREFERRED | Check: if class is stateless, then it is preferred to use `object.` | yes | no | + | -| 6 | 6.5.1 | RUN_IN_SCRIPT | Checks : if the kts script contains other functions except the run code. | yes | no | - | +| 3 | 3.15.1 | STRING_CONCATENATION | Check: warns if the concatenation of strings is used in a single line. | yes | no | - | +| 3 | 3.15.2 | STRING_TEMPLATE_CURLY_BRACES | Check: warns if there are redundant curly braces in the string template.
Fix: deletes the curly braces. | yes | no | + | +| 3 | 3.15.2 | STRING_TEMPLATE_QUOTES | Check: warns if there are redundant quotes in the string template.
Fix: deletes the quotes and $ symbol. | yes | no | + | +| 3 | 3.16.1 | COLLAPSE_IF_STATEMENTS | Check: warns if there are redundant nested if-statements, which could be collapsed into a single statement by concatenating their conditions. | yes | no | - | +| 3 | 3.16.2 | COMPLEX_BOOLEAN_EXPRESSION | Check: warns if the boolean expression is complex and can be simplified.
Fix: replaces the boolean expression with a simpler one. | yes | no | + | +| 3 | 3.17.1 | CONVENTIONAL_RANGE | Check: warns if it is possible to replace the range with `until` or replace the `rangeTo` function with a range.
Fix: replace range with `until` or replace the `rangeTo` function with a range. | yes | no | - | +| 3 | 3.18.1 | DEBUG_PRINT | Check: warns if there is a printing to console (assumption that it's a debug logging). | no | no | - | +| 4 | 4.1.1 | FLOAT_IN_ACCURATE_CALCULATIONS | Checks that floating-point values are not used in the arithmetic expressions.
Fix: no | no | no | Current implementation detects only floating-point constants. | +| 4 | 4.1.3 | SAY_NO_TO_VAR | Check: warns if the `var` modifier is used for a local variable (not in a class or at file level), and this var is not used in accumulators. | no | no | no | several fixmes related to the search mechanism (VariablesSearch) and fixme for checking reassinment of this var | +| 4 | 4.2.1 | SMART_CAST_NEEDED | Check: warns if the casting can be omitted.
Fix: Deletes casting. | yes | no | - | | +| 4 | 4.2.2 | TYPE_ALIAS | Check: if the type reference of a property is longer than expected. | yes | typeReferenceLength | - | | +| 4 | 4.3.1 | NULLABLE_PROPERTY_TYPE | Check: warns if an immutable property is initialized with null, or if the immutable property can have non-nullable type instead of nullable.
Fix: suggests the initial value instead of null or changes in the immutable property type. | yes | no | - | +| 4 | 4.3.2 | GENERIC_VARIABLE_WRONG_DECLARATION | Check: warns if variables of generic types don't have an explicit type declaration.
Fix: fixes only the variables that have a generic declaration on both sides. | yes | no | + | +| 4 | 4.3.3 | AVOID_NULL_CHECKS | Check: warns if the null-check is used explicitly (for example: if (a == null)). | yes | no | Fix if\else conditions on null. | +| 5 | 5.1.1 | TOO_LONG_FUNCTION | Check: warns if the length of a function is too long. | no | maxFunctionLength isIncludeHeader | | +| 5 | 5.1.2 | NESTED_BLOCK | Warns if a function has more nested blocks than expected. | no | maxNestedBlockQuantit | | +| 5 | 5.1.3 | AVOID_NESTED_FUNCTIONS | Check: Warns if there are nested functions.
Fix: declare the function in the outer scope. | yes | no | + | +| 5 | 5.1.4 | INVERSE_FUNCTION_PREFERRED | Check: Warns if a function call with "!" can be rewritten to the inverse function (!isEmpty() -> isNotEmpty()).
Fix: Rewrites the function call. | yes | - | - | +| 5 | 5.2.1 | LAMBDA_IS_NOT_LAST_PARAMETER | Checks that the lambda inside function parameters block is not at the end. | no | no | | +| 5 | 5.2.2 | TOO_MANY_PARAMETERS | Check: Warns if a function contains more parameters than allowed. | no | maxParameterListSize | | +| 5 | 5.2.3 | WRONG_OVERLOADING_FUNCTION_ARGUMENTS | Check: Warns if a function has overloading instead of using default arguments. | no | no | | +| 5 | 5.2.4 | RUN_BLOCKING_INSIDE_ASYNC | Check: Warns if the runBlocking is used inside the async block code. | no | no | - | +| 5 | 5.2.5 | TOO_MANY_LINES_IN_LAMBDA | Checks that the long lambda has parameters. | no | maxLambdaLength | | +| 5 | 5.2.6 | CUSTOM_LABEL | Check: Warns if using an unnecessary custom label. | no | no | - | +| 5 | 5.2.7 | PARAMETER_NAME_IN_OUTER_LAMBDA | Check: warns if the outer lambda uses an implicit parameter `it`. | no | no | - | +| 6 | 6.1.1 | SINGLE_CONSTRUCTOR_SHOULD_BE_PRIMARY | Check: warns if there is only one secondary constructor in a class.
Fix: converts it to a primary constructor. | yes | no | Support the more complicated logic of the constructor conversion. | +| 6 | 6.1.2 | USE_DATA_CLASS | Check: if the class can be made as a data class. | no | no | yes | +| 6 | 6.1.3 | EMPTY_PRIMARY_CONSTRUCTOR | Check: warns if there is an empty primary constructor. | yes | no | yes | +| 6 | 6.1.4 | MULTIPLE_INIT_BLOCKS | Checks that the classes have only one init block. | yes | no | - | +| 6 | 6.1.5 | USELESS_SUPERTYPE | Checks if the override function can be removed. | yes | no | | +| 6 | 6.1.6 | CLASS_SHOULD_NOT_BE_ABSTRACT | Checks if the abstract class has any abstract method. If not, it warns that the class must not be abstract.
Fix: deletes the abstract modifier. | yes | no | - | +| 6 | 6.1.7 | NO_CORRESPONDING_PROPERTY | Checks: warns if with using "backing property" scheme, the name of a real and a back property are the same. | no | no | - | +| 6 | 6.1.8 | CUSTOM_GETTERS_SETTERS | Check that no custom getters and setters are used for the properties. | no | no | - | +| 6 | 6.1.9 | WRONG_NAME_OF_VARIABLE_INSIDE_ACCESSOR | Checks if the name of a variable is used in the custom getter or setter. | no | no | | +| 6 | 6.1.10 | TRIVIAL_ACCESSORS_ARE_NOT_RECOMMENDED | Checks if there are trivial getters or setters.
Fix: Delete the trivial getter or setter. | yes | no | - | +| 6 | 6.1.11 | COMPACT_OBJECT_INITIALIZATION | Checks if the class instantiation can be wrapped in `apply` for better readability. | | no | | +| 6 | 6.1.12 | INLINE_CLASS_CAN_BE_USED | Check: warns if the class can be transferred to the inline class. | no | no | yes | +| 6 | 6.2.2 | EXTENSION_FUNCTION_SAME_SIGNATURE | Checks if an extension function has the same signature as another extension function, and their classes are related. | no | no | + | +| 6 | 6.2.3 | EXTENSION_FUNCTION_WITH_CLASS | Check: if the file contains a class, then it can not have extension functions for the same class. | no | no | - | +| 6 | 6.2.4 | USE_LAST_INDEX | Check: change a property length - 1 to the property lastIndex. | no | no | - | +| 6 | 6.4.1 | AVOID_USING_UTILITY_CLASS | Checks if there is a class/object that can be replaced with the extension function. | no | no | - | +| 6 | 6.4.2 | OBJECT_IS_PREFERRED | Check: if class is stateless, then it is preferred to use `object.` | yes | no | + | +| 6 | 6.5.1 | RUN_IN_SCRIPT | Checks : if the kts script contains other functions except the run code. | yes | no | - |