diff --git a/diktat-analysis.yml b/diktat-analysis.yml index 8f48b4030f..970cd8a055 100644 --- a/diktat-analysis.yml +++ b/diktat-analysis.yml @@ -6,6 +6,8 @@ domainName: org.cqfn.diktat # testDirs: test disabledChapters: "" + testDirs: test + kotlinVersion: "1.4.21" # Checks that the Class/Enum/Interface name does not match Pascal case - name: CLASS_NAME_INCORRECT enabled: true diff --git a/diktat-common/src/main/kotlin/org/cqfn/diktat/common/config/rules/RulesConfigReader.kt b/diktat-common/src/main/kotlin/org/cqfn/diktat/common/config/rules/RulesConfigReader.kt index 6c3af44e25..1c34c2a34d 100644 --- a/diktat-common/src/main/kotlin/org/cqfn/diktat/common/config/rules/RulesConfigReader.kt +++ b/diktat-common/src/main/kotlin/org/cqfn/diktat/common/config/rules/RulesConfigReader.kt @@ -5,6 +5,7 @@ package org.cqfn.diktat.common.config.rules import org.cqfn.diktat.common.config.reader.JsonResourceConfigReader +import org.cqfn.diktat.common.config.rules.RulesConfigReader.Companion.log import com.charleskorn.kaml.Yaml import com.charleskorn.kaml.YamlConfiguration @@ -123,6 +124,16 @@ data class CommonConfiguration(private val configuration: Map?) configuration?.get("disabledChapters") } + /** + * Get version of kotlin from configuration + */ + val kotlinVersion: KotlinVersion by lazy { + configuration?.get("kotlinVersion")?.kotlinVersion() ?: run { + log.error("Kotlin version not specified in the configuration file. Will be using ${KotlinVersion.CURRENT} version") + KotlinVersion.CURRENT + } + } + /** * False if configuration has been read from config file, true if defaults are used */ @@ -155,3 +166,20 @@ fun List.isRuleEnabled(rule: Rule): Boolean { val ruleMatched = getRuleConfig(rule) return ruleMatched?.enabled ?: true } + +/** + * Parse string into KotlinVersion + * + * @return KotlinVersion from configuration + */ +fun String.kotlinVersion(): KotlinVersion { + require(this.contains("^(\\d+\\.)(\\d+)\\.?(\\d+)?$".toRegex())) { + "Kotlin version format is incorrect" + } + val versions = this.split(".").map { it.toInt() } + return if (versions.size == 2) { + KotlinVersion(versions[0], versions[1]) + } else { + KotlinVersion(versions[0], versions[1], versions[2]) + } +} diff --git a/diktat-common/src/test/kotlin/org/cqfn/diktat/test/ConfigReaderTest.kt b/diktat-common/src/test/kotlin/org/cqfn/diktat/test/ConfigReaderTest.kt index c27dd630a8..b1b624a80e 100644 --- a/diktat-common/src/test/kotlin/org/cqfn/diktat/test/ConfigReaderTest.kt +++ b/diktat-common/src/test/kotlin/org/cqfn/diktat/test/ConfigReaderTest.kt @@ -1,7 +1,10 @@ package org.cqfn.diktat.test +import org.cqfn.diktat.common.config.rules.DIKTAT_COMMON import org.cqfn.diktat.common.config.rules.RulesConfig import org.cqfn.diktat.common.config.rules.RulesConfigReader +import org.cqfn.diktat.common.config.rules.getCommonConfiguration +import org.cqfn.diktat.common.config.rules.kotlinVersion import org.junit.jupiter.api.Test class ConfigReaderTest { @@ -13,6 +16,19 @@ class ConfigReaderTest { assert(rulesConfigList.any { it.name == "CLASS_NAME_INCORRECT" && it.enabled }) assert(rulesConfigList.find { it.name == "CLASS_NAME_INCORRECT" }?.configuration == emptyMap()) assert(rulesConfigList.find { it.name == "DIKTAT_COMMON" } - ?.configuration == mapOf("domainName" to "org.cqfn.diktat")) + ?.configuration?.get("domainName") == "org.cqfn.diktat") + } + + @Test + fun `testing kotlin version`() { + val rulesConfigList: List? = RulesConfigReader(javaClass.classLoader) + .readResource("src/test/resources/test-rules-config.yml") + val currentKotlinVersion = KotlinVersion.CURRENT + requireNotNull(rulesConfigList) + assert(rulesConfigList.getCommonConfiguration().value.kotlinVersion == currentKotlinVersion) + assert(rulesConfigList.find { it.name == DIKTAT_COMMON } + ?.configuration + ?.get("kotlinVersion") + ?.kotlinVersion() == currentKotlinVersion) } } diff --git a/diktat-common/src/test/resources/test-rules-config.yml b/diktat-common/src/test/resources/test-rules-config.yml index 9219ba23ac..be6c9f20ee 100644 --- a/diktat-common/src/test/resources/test-rules-config.yml +++ b/diktat-common/src/test/resources/test-rules-config.yml @@ -2,6 +2,7 @@ enabled: true configuration: domainName: org.cqfn.diktat + kotlinVersion: 1.4.21 - name: CLASS_NAME_INCORRECT enabled: true - name: CONSTANT_UPPERCASE diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter6/classes/InlineClassesRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter6/classes/InlineClassesRule.kt index e600621a5d..dd254abdb1 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter6/classes/InlineClassesRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter6/classes/InlineClassesRule.kt @@ -1,6 +1,7 @@ package org.cqfn.diktat.ruleset.rules.chapter6.classes import org.cqfn.diktat.common.config.rules.RulesConfig +import org.cqfn.diktat.common.config.rules.getCommonConfiguration import org.cqfn.diktat.ruleset.constants.EmitType import org.cqfn.diktat.ruleset.constants.Warnings.INLINE_CLASS_CAN_BE_USED import org.cqfn.diktat.ruleset.utils.getFirstChildWithType @@ -37,7 +38,8 @@ class InlineClassesRule(private val configRule: List) : Rule("inlin emitWarn = emit isFixMode = autoCorrect - if (node.elementType == CLASS) { + val configuration by configRule.getCommonConfiguration() + if (node.elementType == CLASS && configuration.kotlinVersion >= ktVersion) { handleClasses(node.psi as KtClass) } } @@ -47,9 +49,8 @@ class InlineClassesRule(private val configRule: List) : Rule("inlin if (hasValidProperties(classPsi) && !isExtendingClass(classPsi.node) && classPsi.node.getFirstChildWithType(MODIFIER_LIST)?.getChildren(null)?.all { it.elementType in goodModifiers } != false) { - INLINE_CLASS_CAN_BE_USED.warnAndFix(configRule, emitWarn, isFixMode, "class ${classPsi.name}", classPsi.node.startOffset, classPsi.node) { - // Fixme: since it's an experimental feature we shouldn't do fixer - } + // Fixme: since it's an experimental feature we shouldn't do fixer + INLINE_CLASS_CAN_BE_USED.warn(configRule, emitWarn, isFixMode, "class ${classPsi.name}", classPsi.node.startOffset, classPsi.node) } } @@ -72,6 +73,7 @@ class InlineClassesRule(private val configRule: List) : Rule("inlin ?: false companion object { + val ktVersion = KotlinVersion(1, 3) val goodModifiers = listOf(PUBLIC_KEYWORD, PRIVATE_KEYWORD, FINAL_KEYWORD, PROTECTED_KEYWORD, INTERNAL_KEYWORD) } } diff --git a/diktat-rules/src/main/resources/diktat-analysis-huawei.yml b/diktat-rules/src/main/resources/diktat-analysis-huawei.yml index f9ad192742..851b5ff10e 100644 --- a/diktat-rules/src/main/resources/diktat-analysis-huawei.yml +++ b/diktat-rules/src/main/resources/diktat-analysis-huawei.yml @@ -6,6 +6,8 @@ domainName: com.huawei # testDirs: test disabledChapters: "" + testDirs: test + kotlinVersion: "1.4.21" # Checks that the Class/Enum/Interface name does not match Pascal case - name: CLASS_NAME_INCORRECT enabled: true diff --git a/diktat-rules/src/main/resources/diktat-analysis.yml b/diktat-rules/src/main/resources/diktat-analysis.yml index d88c10efde..e304559596 100644 --- a/diktat-rules/src/main/resources/diktat-analysis.yml +++ b/diktat-rules/src/main/resources/diktat-analysis.yml @@ -5,6 +5,7 @@ domainName: your.name.here testDirs: test disabledChapters: "" + kotlinVersion: "1.4.21" # Checks that the Class/Enum/Interface name does not match Pascal case - name: CLASS_NAME_INCORRECT enabled: true diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/InlineClassesWarnTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/InlineClassesWarnTest.kt index 2a3cf65760..8f31bb3bad 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/InlineClassesWarnTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/chapter6/InlineClassesWarnTest.kt @@ -1,5 +1,7 @@ package org.cqfn.diktat.ruleset.chapter6 +import org.cqfn.diktat.common.config.rules.DIKTAT_COMMON +import org.cqfn.diktat.common.config.rules.RulesConfig import org.cqfn.diktat.ruleset.constants.Warnings.INLINE_CLASS_CAN_BE_USED import org.cqfn.diktat.ruleset.rules.DIKTAT_RULE_SET_ID import org.cqfn.diktat.ruleset.rules.chapter6.classes.InlineClassesRule @@ -12,6 +14,21 @@ import org.junit.jupiter.api.Test class InlineClassesWarnTest : LintTestBase(::InlineClassesRule) { private val ruleId = "$DIKTAT_RULE_SET_ID:inline-classes" + private val rulesConfigListEarlierVersion: List = listOf( + RulesConfig( + DIKTAT_COMMON, true, + mapOf("kotlinVersion" to "1.2.9")) + ) + private val rulesConfigListSameVersion: List = listOf( + RulesConfig( + DIKTAT_COMMON, true, + mapOf("kotlinVersion" to "1.3")) + ) + private val rulesConfigListLateVersion: List = listOf( + RulesConfig( + DIKTAT_COMMON, true, + mapOf("kotlinVersion" to "1.3.1")) + ) @Test @Tag(WarningNames.INLINE_CLASS_CAN_BE_USED) @@ -32,7 +49,7 @@ class InlineClassesWarnTest : LintTestBase(::InlineClassesRule) { | val config = Config() |} """.trimMargin(), - LintError(1, 1, ruleId, "${INLINE_CLASS_CAN_BE_USED.warnText()} class Some", true) + LintError(1, 1, ruleId, "${INLINE_CLASS_CAN_BE_USED.warnText()} class Some", false) ) } @@ -45,7 +62,7 @@ class InlineClassesWarnTest : LintTestBase(::InlineClassesRule) { | val config = Config() |} """.trimMargin(), - LintError(1, 1, ruleId, "${INLINE_CLASS_CAN_BE_USED.warnText()} class Some", true) + LintError(1, 1, ruleId, "${INLINE_CLASS_CAN_BE_USED.warnText()} class Some", false) ) } @@ -70,7 +87,7 @@ class InlineClassesWarnTest : LintTestBase(::InlineClassesRule) { | |} """.trimMargin(), - LintError(1, 1, ruleId, "${INLINE_CLASS_CAN_BE_USED.warnText()} class Some", true) + LintError(1, 1, ruleId, "${INLINE_CLASS_CAN_BE_USED.warnText()} class Some", false) ) } @@ -119,7 +136,7 @@ class InlineClassesWarnTest : LintTestBase(::InlineClassesRule) { | val some = 3 |} """.trimMargin(), - LintError(1, 1, ruleId, "${INLINE_CLASS_CAN_BE_USED.warnText()} class Some", true) + LintError(1, 1, ruleId, "${INLINE_CLASS_CAN_BE_USED.warnText()} class Some", false) ) } @@ -144,7 +161,7 @@ class InlineClassesWarnTest : LintTestBase(::InlineClassesRule) { | |} """.trimMargin(), - LintError(1, 1, ruleId, "${INLINE_CLASS_CAN_BE_USED.warnText()} class LocalCommandExecutor", true) + LintError(1, 1, ruleId, "${INLINE_CLASS_CAN_BE_USED.warnText()} class LocalCommandExecutor", false) ) } @@ -157,7 +174,40 @@ class InlineClassesWarnTest : LintTestBase(::InlineClassesRule) { | |} """.trimMargin(), - LintError(1, 1, ruleId, "${INLINE_CLASS_CAN_BE_USED.warnText()} class LocalCommandExecutor", true) + LintError(1, 1, ruleId, "${INLINE_CLASS_CAN_BE_USED.warnText()} class LocalCommandExecutor", false) + ) + } + + @Test + @Tag(WarningNames.INLINE_CLASS_CAN_BE_USED) + fun `check kotlin version`() { + lintMethod( + """ + |class Some { + | val config = Config() + |} + """.trimMargin(), + LintError(1, 1, ruleId, "${INLINE_CLASS_CAN_BE_USED.warnText()} class Some", false), + rulesConfigList = rulesConfigListLateVersion + ) + + lintMethod( + """ + |class Some { + | val config = Config() + |} + """.trimMargin(), + rulesConfigList = rulesConfigListEarlierVersion + ) + + lintMethod( + """ + |class Some { + | val config = Config() + |} + """.trimMargin(), + LintError(1, 1, ruleId, "${INLINE_CLASS_CAN_BE_USED.warnText()} class Some", false), + rulesConfigList = rulesConfigListSameVersion ) } } diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt index f9fc4f35e9..8affcfdbe7 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt @@ -119,6 +119,10 @@ class DiktatSmokeTest : FixTestBase("test/smoke/src/main/kotlin", | | http://www.apache.org/licenses/LICENSE-2.0 """.trimMargin() + ), + DIKTAT_COMMON to mapOf( + "domainName" to "org.cqfn.diktat", + "kotlinVersion" to "1.3.7" ) ) ) @@ -127,6 +131,10 @@ class DiktatSmokeTest : FixTestBase("test/smoke/src/main/kotlin", Assertions.assertFalse( unfixedLintErrors.contains(LintError(line = 1, col = 1, ruleId = "diktat-ruleset:comments", detail = "${Warnings.COMMENTED_OUT_CODE.warnText()} /*")) ) + + Assertions.assertTrue( + unfixedLintErrors.contains(LintError(1, 1, "diktat-ruleset:inline-classes", "${Warnings.INLINE_CLASS_CAN_BE_USED.warnText()} class Some")) + ) } @Test diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/RulesConfigYamlTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/RulesConfigYamlTest.kt index da18bc44ea..97739f4a31 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/RulesConfigYamlTest.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/utils/RulesConfigYamlTest.kt @@ -1,8 +1,10 @@ package org.cqfn.diktat.ruleset.utils +import org.cqfn.diktat.common.config.rules.DIKTAT_COMMON import org.cqfn.diktat.common.config.rules.RulesConfig import org.cqfn.diktat.common.config.rules.RulesConfigReader import org.cqfn.diktat.common.config.rules.getRuleConfig +import org.cqfn.diktat.common.config.rules.kotlinVersion import org.cqfn.diktat.ruleset.constants.Warnings import com.charleskorn.kaml.Yaml @@ -26,7 +28,7 @@ inline class RulesConfigYamlTest(private val pathMap: Map = compareRulesAndConfig("diktat-analysis.yml") compareRulesAndConfig("diktat-analysis-huawei.yml") val thirdConfig = "${System.getProperty("user.dir")}${File.separator}..${File.separator}diktat-analysis.yml${File.separator}" - compareRulesAndConfig(thirdConfig, "parent/diktat-analysis.yml") + compareRulesAndConfig(thirdConfig, "../diktat-analysis.yml") } @Test @@ -36,6 +38,19 @@ inline class RulesConfigYamlTest(private val pathMap: Map = checkComments("../diktat-analysis.yml") } + @Test + fun `check kotlin version`() { + val currentKotlinVersion = KotlinVersion.CURRENT + pathMap.keys.forEach { path -> + val config = readAllRulesFromConfig(path) + val ktVersion = config.find { it.name == DIKTAT_COMMON } + ?.configuration + ?.get("kotlinVersion") + ?.kotlinVersion() + Assertions.assertEquals(ktVersion, currentKotlinVersion) + } + } + private fun checkComments(configName: String) { val lines = File(configName) .readLines() diff --git a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example5Expected.kt b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example5Expected.kt index e1f8ad1003..73d8187164 100644 --- a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example5Expected.kt +++ b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example5Expected.kt @@ -10,6 +10,6 @@ package org.cqfn.diktat class Some { - + val config = Config() } diff --git a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example5Test.kt b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example5Test.kt index 7396489e1a..d54fe0ad3f 100644 --- a/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example5Test.kt +++ b/diktat-rules/src/test/resources/test/smoke/src/main/kotlin/Example5Test.kt @@ -1,5 +1,5 @@ package org.cqfn.diktat class Some { - + val config = Config() }