From b0575f2530f0b2cd7ecec716350ceca16fa37dfe Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 7 Jun 2023 12:12:02 +0300 Subject: [PATCH] Update Ktlint to v0.49.1 (#1683) - supported changes from KtLint 0.49.0 - supported changes from KtLint 0.49.1 - removed dependency to ktlint fat jar - supported functionality `(cannot be auto-corrected)` only on ktlint level --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Nariman Abdullin --- .../kotlin/org/cqfn/diktat/api/DiktatError.kt | 39 ++++------- diktat-cli/build.gradle.kts | 1 + diktat-gradle-plugin/build.gradle.kts | 7 +- .../plugin/gradle/DiktatJavaExecTaskTest.kt | 6 +- diktat-ktlint-engine/build.gradle.kts | 17 ++--- .../ktlint/DiktatBaselineFactoryImpl.kt | 10 +-- .../org/cqfn/diktat/ktlint/DiktatErrorImpl.kt | 36 ---------- .../ktlint/DiktatProcessorFactoryImpl.kt | 11 ++-- .../ktlint/DiktatReporterFactoryImpl.kt | 15 ++--- .../cqfn/diktat/ktlint/DiktatReporterImpl.kt | 15 ++--- .../cqfn/diktat/ktlint/KtLintRuleWrapper.kt | 64 ++++++++++-------- .../org/cqfn/diktat/ktlint/KtLintUtils.kt | 66 +++++++++++++++++-- .../diktat/ktlint/KtLintRuleWrapperTest.kt | 16 ++--- .../ruleset/rules/chapter3/DebugPrintRule.kt | 4 +- .../pinterest/ktlint/core/KtLintTestUtils.kt | 7 ++ .../org/cqfn/diktat/util/LintTestBase.kt | 6 +- diktat-ruleset/build.gradle.kts | 2 + ...V2Spi.kt => DiktatRuleSetProviderV3Spi.kt} | 22 +++---- ...int.cli.ruleset.core.api.RuleSetProviderV3 | 1 + ...om.pinterest.ktlint.core.RuleSetProviderV2 | 1 - .../pinterest/ktlint/core/KtLintTestUtils.kt | 7 ++ .../ruleset/smoke/DiktatSaveSmokeTest.kt | 2 +- .../diktat/ruleset/smoke/DiktatSmokeTest.kt | 2 +- .../ruleset/smoke/DiktatSmokeTestBase.kt | 27 +------- gradle/libs.versions.toml | 18 +++-- 25 files changed, 203 insertions(+), 199 deletions(-) delete mode 100644 diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatErrorImpl.kt create mode 100644 diktat-rules/src/test/kotlin/com/pinterest/ktlint/core/KtLintTestUtils.kt rename diktat-ruleset/src/main/kotlin/org/cqfn/diktat/ruleset/rules/{DiktatRuleSetProviderV2Spi.kt => DiktatRuleSetProviderV3Spi.kt} (52%) create mode 100644 diktat-ruleset/src/main/resources/META-INF/services/com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3 delete mode 100644 diktat-ruleset/src/main/resources/META-INF/services/com.pinterest.ktlint.core.RuleSetProviderV2 create mode 100644 diktat-ruleset/src/test/kotlin/com/pinterest/ktlint/core/KtLintTestUtils.kt diff --git a/diktat-api/src/main/kotlin/org/cqfn/diktat/api/DiktatError.kt b/diktat-api/src/main/kotlin/org/cqfn/diktat/api/DiktatError.kt index 3d4aac4758..56b20c90a5 100644 --- a/diktat-api/src/main/kotlin/org/cqfn/diktat/api/DiktatError.kt +++ b/diktat-api/src/main/kotlin/org/cqfn/diktat/api/DiktatError.kt @@ -2,30 +2,17 @@ package org.cqfn.diktat.api /** * Error found by `diktat` + * + * @property line line number (one-based) + * @property col column number (one-based) + * @property ruleId rule id + * @property detail error message + * @property canBeAutoCorrected true if the found error can be fixed */ -interface DiktatError { - /** - * @return line number (one-based) - */ - fun getLine(): Int - - /** - * @return column number (one-based) - */ - fun getCol(): Int - - /** - * @return rule id - */ - fun getRuleId(): String - - /** - * @return error message - */ - fun getDetail(): String - - /** - * @return true if the found error can be fixed - */ - fun canBeAutoCorrected(): Boolean -} +data class DiktatError( + val line: Int, + val col: Int, + val ruleId: String, + val detail: String, + val canBeAutoCorrected: Boolean = false, +) diff --git a/diktat-cli/build.gradle.kts b/diktat-cli/build.gradle.kts index 55ae4320c2..386acfcf02 100644 --- a/diktat-cli/build.gradle.kts +++ b/diktat-cli/build.gradle.kts @@ -17,6 +17,7 @@ dependencies { implementation(projects.diktatKtlintEngine) implementation(projects.diktatRules) implementation(libs.kotlinx.cli) + implementation(libs.kotlin.logging) implementation(libs.log4j2.core) implementation(libs.log4j2.slf4j2) diff --git a/diktat-gradle-plugin/build.gradle.kts b/diktat-gradle-plugin/build.gradle.kts index 71d6d82c26..b54a7ca102 100644 --- a/diktat-gradle-plugin/build.gradle.kts +++ b/diktat-gradle-plugin/build.gradle.kts @@ -20,9 +20,10 @@ dependencies { implementation(libs.kotlinx.serialization.json) testImplementation(libs.junit.jupiter.api) testRuntimeOnly(libs.junit.jupiter.engine) - testImplementation(libs.ktlint.reporter.json) - testImplementation(libs.ktlint.reporter.plain) - testImplementation(libs.ktlint.reporter.sarif) + testImplementation(libs.ktlint.cli.reporter) + testImplementation(libs.ktlint.cli.reporter.json) + testImplementation(libs.ktlint.cli.reporter.plain) + testImplementation(libs.ktlint.cli.reporter.sarif) } tasks.withType { diff --git a/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskTest.kt b/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskTest.kt index 3f4cc58595..d8a3f087e1 100644 --- a/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskTest.kt +++ b/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskTest.kt @@ -2,9 +2,9 @@ package org.cqfn.diktat.plugin.gradle import org.cqfn.diktat.ktlint.DiktatReporterImpl.Companion.unwrap import org.cqfn.diktat.plugin.gradle.tasks.DiktatCheckTask -import com.pinterest.ktlint.reporter.json.JsonReporter -import com.pinterest.ktlint.reporter.plain.PlainReporter -import com.pinterest.ktlint.reporter.sarif.SarifReporter +import com.pinterest.ktlint.cli.reporter.json.JsonReporter +import com.pinterest.ktlint.cli.reporter.plain.PlainReporter +import com.pinterest.ktlint.cli.reporter.sarif.SarifReporter import org.gradle.api.Project import org.gradle.testfixtures.ProjectBuilder diff --git a/diktat-ktlint-engine/build.gradle.kts b/diktat-ktlint-engine/build.gradle.kts index 7c1ea93453..6aa53bf2ac 100644 --- a/diktat-ktlint-engine/build.gradle.kts +++ b/diktat-ktlint-engine/build.gradle.kts @@ -11,14 +11,15 @@ project.description = "This module builds diktat-api implementation using ktlint dependencies { api(projects.diktatApi) implementation(projects.diktatCommon) - // a temporary solution to avoid a lot of changes in diktat-rules - api(libs.ktlint.core) - implementation(libs.ktlint.reporter.baseline) - implementation(libs.ktlint.reporter.checkstyle) - implementation(libs.ktlint.reporter.html) - implementation(libs.ktlint.reporter.json) - implementation(libs.ktlint.reporter.plain) - implementation(libs.ktlint.reporter.sarif) + implementation(libs.ktlint.core) + implementation(libs.ktlint.cli.reporter) + implementation(libs.ktlint.rule.engine) + implementation(libs.ktlint.cli.reporter.baseline) + implementation(libs.ktlint.cli.reporter.checkstyle) + implementation(libs.ktlint.cli.reporter.html) + implementation(libs.ktlint.cli.reporter.json) + implementation(libs.ktlint.cli.reporter.plain) + implementation(libs.ktlint.cli.reporter.sarif) testImplementation(libs.log4j2.slf4j2) testImplementation(libs.junit.jupiter) diff --git a/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatBaselineFactoryImpl.kt b/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatBaselineFactoryImpl.kt index d3fb2cedc1..e7d33321fd 100644 --- a/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatBaselineFactoryImpl.kt +++ b/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatBaselineFactoryImpl.kt @@ -4,13 +4,15 @@ import org.cqfn.diktat.api.DiktatBaseline import org.cqfn.diktat.api.DiktatBaselineFactory import org.cqfn.diktat.api.DiktatProcessorListener import org.cqfn.diktat.api.DiktatProcessorListener.Companion.closeAfterAllAsProcessorListener -import org.cqfn.diktat.ktlint.DiktatErrorImpl.Companion.wrap import org.cqfn.diktat.ktlint.DiktatReporterImpl.Companion.wrap -import com.pinterest.ktlint.core.api.Baseline -import com.pinterest.ktlint.core.api.loadBaseline -import com.pinterest.ktlint.reporter.baseline.BaselineReporter + +import com.pinterest.ktlint.cli.reporter.baseline.Baseline +import com.pinterest.ktlint.cli.reporter.baseline.BaselineReporter +import com.pinterest.ktlint.cli.reporter.baseline.loadBaseline + import java.io.PrintStream import java.nio.file.Path + import kotlin.io.path.absolutePathString import kotlin.io.path.outputStream diff --git a/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatErrorImpl.kt b/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatErrorImpl.kt deleted file mode 100644 index 83075ba93c..0000000000 --- a/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatErrorImpl.kt +++ /dev/null @@ -1,36 +0,0 @@ -package org.cqfn.diktat.ktlint - -import org.cqfn.diktat.api.DiktatError -import com.pinterest.ktlint.core.LintError - -/** - * Wrapper for KtLint error - * - * @property lintError - */ -data class DiktatErrorImpl( - private val lintError: LintError -) : DiktatError { - override fun getLine(): Int = lintError.line - - override fun getCol(): Int = lintError.col - - override fun getRuleId(): String = lintError.ruleId - - override fun getDetail(): String = lintError.detail - - override fun canBeAutoCorrected(): Boolean = lintError.canBeAutoCorrected - - companion object { - /** - * @return [DiktatError] from KtLint [LintError] - */ - fun LintError.wrap(): DiktatError = DiktatErrorImpl(this) - - /** - * @return KtLint [LintError] from [DiktatError] or exception - */ - fun DiktatError.unwrap(): LintError = (this as? DiktatErrorImpl)?.lintError - ?: error("Unsupported wrapper of ${DiktatError::class.java.simpleName}: ${this::class.java.canonicalName}") - } -} diff --git a/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatProcessorFactoryImpl.kt b/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatProcessorFactoryImpl.kt index 8a3dc4e53f..9f237b3947 100644 --- a/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatProcessorFactoryImpl.kt +++ b/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatProcessorFactoryImpl.kt @@ -4,11 +4,10 @@ import org.cqfn.diktat.DiktatProcessor import org.cqfn.diktat.DiktatProcessorFactory import org.cqfn.diktat.api.DiktatCallback import org.cqfn.diktat.api.DiktatRuleSet -import org.cqfn.diktat.ktlint.DiktatErrorImpl.Companion.wrap import org.cqfn.diktat.ktlint.KtLintRuleWrapper.Companion.toKtLint -import com.pinterest.ktlint.core.Code -import com.pinterest.ktlint.core.KtLintRuleEngine -import com.pinterest.ktlint.core.LintError +import com.pinterest.ktlint.rule.engine.api.Code +import com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine +import com.pinterest.ktlint.rule.engine.api.LintError import java.nio.file.Path private typealias FormatCallback = (LintError, Boolean) -> Unit @@ -45,9 +44,9 @@ class DiktatProcessorFactoryImpl : DiktatProcessorFactory { companion object { private fun DiktatRuleSet.toKtLintEngine(): KtLintRuleEngine = KtLintRuleEngine(ruleProviders = toKtLint()) - private fun Path.toKtLint(): Code = Code.CodeFile(this.toFile()) + private fun Path.toKtLint(): Code = Code.fromFile(this.toFile()) - private fun String.toKtLint(isScript: Boolean): Code = Code.CodeSnippet(this, isScript) + private fun String.toKtLint(isScript: Boolean): Code = Code.fromSnippet(this, isScript) private fun DiktatCallback.toKtLintForFormat(): FormatCallback = { error, isCorrected -> this(error.wrap(), isCorrected) diff --git a/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatReporterFactoryImpl.kt b/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatReporterFactoryImpl.kt index a47f2cec8b..5ed4e141d4 100644 --- a/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatReporterFactoryImpl.kt +++ b/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatReporterFactoryImpl.kt @@ -3,13 +3,12 @@ package org.cqfn.diktat.ktlint import org.cqfn.diktat.api.DiktatReporter import org.cqfn.diktat.api.DiktatReporterFactory import org.cqfn.diktat.ktlint.DiktatReporterImpl.Companion.wrap -import com.pinterest.ktlint.core.ReporterProvider -import com.pinterest.ktlint.reporter.checkstyle.CheckStyleReporterProvider -import com.pinterest.ktlint.reporter.html.HtmlReporterProvider -import com.pinterest.ktlint.reporter.json.JsonReporterProvider -import com.pinterest.ktlint.reporter.plain.Color -import com.pinterest.ktlint.reporter.plain.PlainReporterProvider -import com.pinterest.ktlint.reporter.sarif.SarifReporterProvider +import com.pinterest.ktlint.cli.reporter.checkstyle.CheckStyleReporterProvider +import com.pinterest.ktlint.cli.reporter.html.HtmlReporterProvider +import com.pinterest.ktlint.cli.reporter.json.JsonReporterProvider +import com.pinterest.ktlint.cli.reporter.plain.Color +import com.pinterest.ktlint.cli.reporter.plain.PlainReporterProvider +import com.pinterest.ktlint.cli.reporter.sarif.SarifReporterProvider import java.io.OutputStream import java.io.PrintStream import java.nio.file.Path @@ -22,7 +21,7 @@ class DiktatReporterFactoryImpl : DiktatReporterFactory { private val plainReporterProvider = PlainReporterProvider() /** - * All [ReporterProvider] which __KtLint__ provides + * All reporters which __KtLint__ provides */ private val reporterProviders = setOf( plainReporterProvider, diff --git a/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatReporterImpl.kt b/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatReporterImpl.kt index 84c85fc08e..eba6905830 100644 --- a/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatReporterImpl.kt +++ b/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/DiktatReporterImpl.kt @@ -2,15 +2,14 @@ package org.cqfn.diktat.ktlint import org.cqfn.diktat.api.DiktatError import org.cqfn.diktat.api.DiktatReporter -import org.cqfn.diktat.ktlint.DiktatErrorImpl.Companion.unwrap -import com.pinterest.ktlint.core.Reporter +import com.pinterest.ktlint.cli.reporter.core.api.ReporterV2 import java.nio.file.Path /** * [DiktatReporter] using __KtLint__ */ class DiktatReporterImpl( - private val ktLintReporter: Reporter, + private val ktLintReporter: ReporterV2, private val sourceRootDir: Path, ) : DiktatReporter { override fun beforeAll(files: Collection): Unit = ktLintReporter.beforeAll() @@ -19,21 +18,21 @@ class DiktatReporterImpl( file: Path, error: DiktatError, isCorrected: Boolean, - ): Unit = ktLintReporter.onLintError(file.relativePathStringTo(sourceRootDir), error.unwrap(), isCorrected) + ): Unit = ktLintReporter.onLintError(file.relativePathStringTo(sourceRootDir), error.toKtLintForCli()) override fun after(file: Path): Unit = ktLintReporter.after(file.relativePathStringTo(sourceRootDir)) override fun afterAll(): Unit = ktLintReporter.afterAll() companion object { /** * @param sourceRootDir - * @return [DiktatReporter] which wraps __KtLint__'s [Reporter] + * @return [DiktatReporter] which wraps __KtLint__'s [ReporterV2] */ - fun Reporter.wrap(sourceRootDir: Path): DiktatReporter = DiktatReporterImpl(this, sourceRootDir) + fun ReporterV2.wrap(sourceRootDir: Path): DiktatReporter = DiktatReporterImpl(this, sourceRootDir) /** - * @return __KtLint__'s [Reporter] + * @return __KtLint__'s [ReporterV2] */ - fun DiktatReporter.unwrap(): Reporter = (this as? DiktatReporterImpl)?.ktLintReporter + fun DiktatReporter.unwrap(): ReporterV2 = (this as? DiktatReporterImpl)?.ktLintReporter ?: error("Unsupported wrapper of ${DiktatReporter::class.java.simpleName}: ${this::class.java.canonicalName}") } } diff --git a/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/KtLintRuleWrapper.kt b/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/KtLintRuleWrapper.kt index e7435e13d8..2f4560e334 100644 --- a/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/KtLintRuleWrapper.kt +++ b/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/KtLintRuleWrapper.kt @@ -3,8 +3,10 @@ package org.cqfn.diktat.ktlint import org.cqfn.diktat.api.DiktatRule import org.cqfn.diktat.api.DiktatRuleSet import org.cqfn.diktat.common.config.rules.DIKTAT_RULE_SET_ID -import com.pinterest.ktlint.core.Rule -import com.pinterest.ktlint.core.RuleProvider +import com.pinterest.ktlint.rule.engine.core.api.Rule +import com.pinterest.ktlint.rule.engine.core.api.Rule.VisitorModifier.RunAfterRule.Mode +import com.pinterest.ktlint.rule.engine.core.api.RuleId +import com.pinterest.ktlint.rule.engine.core.api.RuleProvider import org.jetbrains.kotlin.com.intellij.lang.ASTNode private typealias EmitType = (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit @@ -15,20 +17,32 @@ private typealias EmitType = (offset: Int, errorMessage: String, canBeAutoCorrec */ class KtLintRuleWrapper( val rule: DiktatRule, - prevRule: KtLintRuleWrapper? = null, + prevRuleId: RuleId? = null, ) : Rule( - id = rule.id.qualifiedWithRuleSetId(DIKTAT_RULE_SET_ID), - visitorModifiers = createVisitorModifiers(rule, prevRule), + ruleId = rule.id.toRuleId(DIKTAT_RULE_SET_ID), + about = about, + visitorModifiers = createVisitorModifiers(rule, prevRuleId), ) { override fun beforeVisitChildNodes( node: ASTNode, autoCorrect: Boolean, emit: EmitType, - ) = rule.invoke(node, autoCorrect, emit) + ) = rule.invoke(node, autoCorrect) { offset, errorMessage, canBeAutoCorrected -> + emit.invoke(offset, errorMessage.correctErrorDetail(canBeAutoCorrected), canBeAutoCorrected) + } companion object { - private fun Sequence.wrapRules(): Sequence = runningFold(null as KtLintRuleWrapper?) { prevRule, diktatRule -> - KtLintRuleWrapper(diktatRule, prevRule) + private val about: About = About( + maintainer = "Diktat", + repositoryUrl = "https://github.com/saveourtool/diktat", + issueTrackerUrl = "https://github.com/saveourtool/diktat/issues", + ) + + private fun Sequence.wrapRulesToProviders(): Sequence = runningFold(null as RuleProvider?) { prevRuleProvider, diktatRule -> + val prevRuleId = prevRuleProvider?.ruleId?.value?.toRuleId(DIKTAT_RULE_SET_ID) + RuleProvider( + provider = { KtLintRuleWrapper(diktatRule, prevRuleId) }, + ) }.filterNotNull() /** @@ -36,36 +50,28 @@ class KtLintRuleWrapper( */ fun DiktatRuleSet.toKtLint(): Set = rules .asSequence() - .wrapRules() - .map { it.asProvider() } + .wrapRulesToProviders() .toSet() private fun createVisitorModifiers( rule: DiktatRule, - prevRule: KtLintRuleWrapper?, - ): Set = prevRule?.id?.qualifiedWithRuleSetId(DIKTAT_RULE_SET_ID) - ?.let { previousRuleId -> - val ruleId = rule.id.qualifiedWithRuleSetId(DIKTAT_RULE_SET_ID) - require(ruleId != previousRuleId) { - "PrevRule has same ID as rule: $ruleId" - } - setOf( - VisitorModifier.RunAfterRule( - ruleId = previousRuleId, - loadOnlyWhenOtherRuleIsLoaded = false, - runOnlyWhenOtherRuleIsEnabled = false - ) + prevRuleId: RuleId?, + ): Set = prevRuleId?.run { + val ruleId = rule.id.toRuleId(DIKTAT_RULE_SET_ID) + require(ruleId != prevRuleId) { + "PrevRule has same ID as rule: $ruleId" + } + setOf( + VisitorModifier.RunAfterRule( + ruleId = prevRuleId, + mode = Mode.REGARDLESS_WHETHER_RUN_AFTER_RULE_IS_LOADED_OR_DISABLED ) - } ?: emptySet() + ) + } ?: emptySet() /** * @return a rule to which a logic is delegated */ internal fun Rule.unwrap(): DiktatRule = (this as? KtLintRuleWrapper)?.rule ?: error("Provided rule ${javaClass.simpleName} is not wrapped by diktat") - - /** - * @return wraps [Rule] to [RuleProvider] - */ - internal fun Rule.asProvider(): RuleProvider = RuleProvider { this } } } diff --git a/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/KtLintUtils.kt b/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/KtLintUtils.kt index 9e554bdcd5..926c28e2c5 100644 --- a/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/KtLintUtils.kt +++ b/diktat-ktlint-engine/src/main/kotlin/org/cqfn/diktat/ktlint/KtLintUtils.kt @@ -5,27 +5,83 @@ package org.cqfn.diktat.ktlint import org.cqfn.diktat.api.DiktatCallback +import org.cqfn.diktat.api.DiktatError import org.cqfn.diktat.api.DiktatRuleSet import org.cqfn.diktat.common.config.rules.DIKTAT_RULE_SET_ID -import com.pinterest.ktlint.core.LintError + +import com.pinterest.ktlint.cli.reporter.core.api.KtlintCliError +import com.pinterest.ktlint.rule.engine.api.LintError +import com.pinterest.ktlint.rule.engine.core.api.RuleId import org.intellij.lang.annotations.Language + import java.nio.file.Path + import kotlin.io.path.invariantSeparatorsPathString import kotlin.io.path.relativeTo +private const val CANNOT_BE_AUTOCORRECTED_SUFFIX = " (cannot be auto-corrected)" + /** * Makes sure this _rule id_ is qualified with a _rule set id_. * * @param ruleSetId the _rule set id_; defaults to [DIKTAT_RULE_SET_ID]. - * @return the fully-qualified _rule id_ in the form of `ruleSetId:ruleId`. + * @return the fully-qualified _rule id_ in the form of `ruleSetId:ruleId` as __KtLint__'s [RuleId]. * @see DIKTAT_RULE_SET_ID * @since 1.2.4 */ -fun String.qualifiedWithRuleSetId(ruleSetId: String = DIKTAT_RULE_SET_ID): String = +fun String.toRuleId(ruleSetId: String = DIKTAT_RULE_SET_ID): RuleId = when { - this.contains(':') -> this - else -> "$ruleSetId:$this" + this.contains(':') -> RuleId(this) + else -> RuleId("$ruleSetId:$this") + } + +/** + * @return [DiktatError] from KtLint's [LintError] + */ +fun LintError.wrap(): DiktatError = DiktatError( + line = this@wrap.line, + col = this@wrap.col, + ruleId = this@wrap.ruleId.value, + detail = this@wrap.detail.removeSuffix(CANNOT_BE_AUTOCORRECTED_SUFFIX), + canBeAutoCorrected = this@wrap.canBeAutoCorrected, +) + +/** + * @return [DiktatError] from KtLint's [KtlintCliError] + */ +fun KtlintCliError.wrap(): DiktatError = DiktatError( + line = this@wrap.line, + col = this@wrap.col, + ruleId = this@wrap.ruleId, + detail = this@wrap.detail.removeSuffix(CANNOT_BE_AUTOCORRECTED_SUFFIX), + canBeAutoCorrected = this@wrap.status == KtlintCliError.Status.LINT_CAN_BE_AUTOCORRECTED, +) + +/** + * @return KtLint [LintError] from [DiktatError] or exception + */ +fun DiktatError.toKtLintForCli(): KtlintCliError = KtlintCliError( + line = this@toKtLintForCli.line, + col = this@toKtLintForCli.col, + ruleId = this@toKtLintForCli.ruleId, + detail = this@toKtLintForCli.detail.correctErrorDetail(this@toKtLintForCli.canBeAutoCorrected), + status = if (this@toKtLintForCli.canBeAutoCorrected) { + KtlintCliError.Status.LINT_CAN_BE_AUTOCORRECTED + } else { + KtlintCliError.Status.LINT_CAN_NOT_BE_AUTOCORRECTED } +) + +/** + * @receiver [DiktatError.detail] + * @param canBeAutoCorrected [DiktatError.canBeAutoCorrected] + * @return input string with [CANNOT_BE_AUTOCORRECTED_SUFFIX] if it's required + */ +fun String.correctErrorDetail(canBeAutoCorrected: Boolean): String = if (canBeAutoCorrected) { + this +} else { + "$this$CANNOT_BE_AUTOCORRECTED_SUFFIX" +} /** * @param sourceRootDir diff --git a/diktat-ktlint-engine/src/test/kotlin/org/cqfn/diktat/ktlint/KtLintRuleWrapperTest.kt b/diktat-ktlint-engine/src/test/kotlin/org/cqfn/diktat/ktlint/KtLintRuleWrapperTest.kt index 343e64d25a..a7bb79a772 100644 --- a/diktat-ktlint-engine/src/test/kotlin/org/cqfn/diktat/ktlint/KtLintRuleWrapperTest.kt +++ b/diktat-ktlint-engine/src/test/kotlin/org/cqfn/diktat/ktlint/KtLintRuleWrapperTest.kt @@ -1,14 +1,14 @@ package org.cqfn.diktat.ktlint -import com.pinterest.ktlint.core.Code -import com.pinterest.ktlint.core.KtLintRuleEngine import org.cqfn.diktat.api.DiktatErrorEmitter import org.cqfn.diktat.api.DiktatRule import org.cqfn.diktat.api.DiktatRuleSet import org.cqfn.diktat.ktlint.KtLintRuleWrapper.Companion.toKtLint import org.cqfn.diktat.ktlint.KtLintRuleWrapper.Companion.unwrap -import com.pinterest.ktlint.core.Rule -import com.pinterest.ktlint.core.RuleProvider +import com.pinterest.ktlint.rule.engine.api.Code +import com.pinterest.ktlint.rule.engine.api.KtLintRuleEngine +import com.pinterest.ktlint.rule.engine.core.api.Rule +import com.pinterest.ktlint.rule.engine.core.api.RuleProvider import org.assertj.core.api.Assertions.assertThat import org.intellij.lang.annotations.Language import org.jetbrains.kotlin.com.intellij.lang.ASTNode @@ -46,7 +46,7 @@ class KtLintRuleWrapperTest { } .first() .let { - Assertions.assertEquals(rule1.id.qualifiedWithRuleSetId(), it.ruleId, + Assertions.assertEquals(rule1.id.toRuleId(), it.ruleId, "Invalid ruleId in Rule.VisitorModifier.RunAfterRule") } } @@ -77,8 +77,8 @@ class KtLintRuleWrapperTest { * Make sure OrderedRuleSet preserves the order. */ val ruleProviders = DiktatRuleSet(rules).toKtLint() - assertThat(ruleProviders.map(RuleProvider::createNewRuleInstance).map(Rule::id)) - .containsExactlyElementsOf(rules.map(DiktatRule::id).map { it.qualifiedWithRuleSetId() }) + assertThat(ruleProviders.map(RuleProvider::createNewRuleInstance).map(Rule::ruleId)) + .containsExactlyElementsOf(rules.map(DiktatRule::id).map { it.toRuleId() }) @Language("kotlin") val code = "fun foo() { }" @@ -86,7 +86,7 @@ class KtLintRuleWrapperTest { KtLintRuleEngine( ruleProviders = ruleProviders ).lint( - code = Code.CodeSnippet( + code = Code.fromSnippet( content = code ) ) diff --git a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/DebugPrintRule.kt b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/DebugPrintRule.kt index 9f0bf0fc2a..03ec93a3d2 100644 --- a/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/DebugPrintRule.kt +++ b/diktat-rules/src/main/kotlin/org/cqfn/diktat/ruleset/rules/chapter3/DebugPrintRule.kt @@ -34,7 +34,7 @@ class DebugPrintRule(configRules: List) : DiktatRule( valueArgumentList?.getChildren(TokenSet.create(KtNodeTypes.VALUE_ARGUMENT))?.size?.let { it <= 1 } == true && node.findChildByType(KtNodeTypes.LAMBDA_ARGUMENT) == null) { Warnings.DEBUG_PRINT.warn( - configRules, emitWarn, isFixMode, + configRules, emitWarn, autoCorrected = false, "found $referenceExpression()", node.startOffset, node, ) } @@ -57,7 +57,7 @@ class DebugPrintRule(configRules: List) : DiktatRule( ?.text if (logMethod in setOf("error", "info", "log", "warn")) { Warnings.DEBUG_PRINT.warn( - configRules, emitWarn, isFixMode, + configRules, emitWarn, autoCorrected = false, "found console.$logMethod()", node.startOffset, node, ) } diff --git a/diktat-rules/src/test/kotlin/com/pinterest/ktlint/core/KtLintTestUtils.kt b/diktat-rules/src/test/kotlin/com/pinterest/ktlint/core/KtLintTestUtils.kt new file mode 100644 index 0000000000..d75f745318 --- /dev/null +++ b/diktat-rules/src/test/kotlin/com/pinterest/ktlint/core/KtLintTestUtils.kt @@ -0,0 +1,7 @@ +/** + * This class contains util methods for KtLint + */ + +package com.pinterest.ktlint.core + +typealias LintError = org.cqfn.diktat.api.DiktatError diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/LintTestBase.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/LintTestBase.kt index 8a1346bbe6..e702fab592 100644 --- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/LintTestBase.kt +++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/LintTestBase.kt @@ -2,12 +2,10 @@ package org.cqfn.diktat.util import org.cqfn.diktat.api.DiktatCallback import org.cqfn.diktat.common.config.rules.RulesConfig -import org.cqfn.diktat.ktlint.DiktatErrorImpl.Companion.unwrap import org.cqfn.diktat.ktlint.lint import org.cqfn.diktat.ruleset.rules.DiktatRule import org.cqfn.diktat.util.DiktatRuleSetProviderTest.Companion.diktatRuleSetForTest import com.pinterest.ktlint.core.LintError -import com.pinterest.ktlint.core.Rule import org.assertj.core.api.Assertions.assertThat import org.intellij.lang.annotations.Language import java.nio.file.Path @@ -17,7 +15,7 @@ import kotlin.io.path.writeText /** * Base class for testing rules without fixing code. - * @property ruleSupplier mapping of list of [RulesConfig] into a [Rule] + * @property ruleSupplier mapping of list of [RulesConfig] into a [DiktatRule] * @property rulesConfigList optional custom rules config */ open class LintTestBase(private val ruleSupplier: (rulesConfigList: List) -> DiktatRule, @@ -166,7 +164,7 @@ open class LintTestBase(private val ruleSupplier: (rulesConfigList: List.collector(): DiktatCallback = DiktatCallback { error, _ -> - this += error.unwrap() + this += error } } } diff --git a/diktat-ruleset/build.gradle.kts b/diktat-ruleset/build.gradle.kts index 193a1c84e6..6770ce227f 100644 --- a/diktat-ruleset/build.gradle.kts +++ b/diktat-ruleset/build.gradle.kts @@ -28,6 +28,8 @@ dependencies { exclude("org.jetbrains.kotlin", "kotlin-stdlib") exclude("org.jetbrains.kotlin", "kotlin-compiler-embeddable") } + implementation(libs.ktlint.cli.ruleset.core) + implementation(libs.ktlint.logger) testImplementation(projects.diktatTestFramework) testImplementation(projects.diktatKtlintEngine) testImplementation(libs.log4j2.slf4j2) diff --git a/diktat-ruleset/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProviderV2Spi.kt b/diktat-ruleset/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProviderV3Spi.kt similarity index 52% rename from diktat-ruleset/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProviderV2Spi.kt rename to diktat-ruleset/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProviderV3Spi.kt index 7d4d5b8129..72e9ceace3 100644 --- a/diktat-ruleset/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProviderV2Spi.kt +++ b/diktat-ruleset/src/main/kotlin/org/cqfn/diktat/ruleset/rules/DiktatRuleSetProviderV3Spi.kt @@ -2,31 +2,25 @@ package org.cqfn.diktat.ruleset.rules import org.cqfn.diktat.common.config.rules.DIKTAT_RULE_SET_ID import org.cqfn.diktat.ktlint.KtLintRuleWrapper.Companion.toKtLint -import com.pinterest.ktlint.core.RuleProvider -import com.pinterest.ktlint.core.RuleSetProviderV2 -import com.pinterest.ktlint.core.initKtLintKLogger +import com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3 +import com.pinterest.ktlint.logger.api.initKtLintKLogger +import com.pinterest.ktlint.rule.engine.core.api.RuleProvider +import com.pinterest.ktlint.rule.engine.core.api.RuleSetId import mu.KotlinLogging import org.slf4j.Logger /** - * [RuleSetProviderV2] that provides diKTat ruleset. + * [RuleSetProviderV3] that provides diKTat ruleset. * * By default, it is expected to have `diktat-analysis.yml` configuration in the root folder where 'ktlint' is run * otherwise it will use default configuration where some rules are disabled. * - * This class is registered in [resources/META-INF/services/com.pinterest.ktlint.core.RuleSetProviderV2] + * This class is registered in [resources/META-INF/services/com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3] * * The no-argument constructor is used by the Java SPI interface. */ -class DiktatRuleSetProviderV2Spi : RuleSetProviderV2( - id = DIKTAT_RULE_SET_ID, - about = About( - maintainer = "Diktat", - description = "Strict coding standard for Kotlin and a custom set of rules for detecting code smells, code style issues, and bugs", - license = "https://github.com/saveourtool/diktat/blob/master/LICENSE", - repositoryUrl = "https://github.com/saveourtool/diktat", - issueTrackerUrl = "https://github.com/saveourtool/diktat/issues", - ), +class DiktatRuleSetProviderV3Spi : RuleSetProviderV3( + id = RuleSetId(DIKTAT_RULE_SET_ID), ) { init { // Need to init KtLint logger to set log level from CLI diff --git a/diktat-ruleset/src/main/resources/META-INF/services/com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3 b/diktat-ruleset/src/main/resources/META-INF/services/com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3 new file mode 100644 index 0000000000..6b4fbaf014 --- /dev/null +++ b/diktat-ruleset/src/main/resources/META-INF/services/com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3 @@ -0,0 +1 @@ +org.cqfn.diktat.ruleset.rules.DiktatRuleSetProviderV3Spi diff --git a/diktat-ruleset/src/main/resources/META-INF/services/com.pinterest.ktlint.core.RuleSetProviderV2 b/diktat-ruleset/src/main/resources/META-INF/services/com.pinterest.ktlint.core.RuleSetProviderV2 deleted file mode 100644 index 143ed2e22b..0000000000 --- a/diktat-ruleset/src/main/resources/META-INF/services/com.pinterest.ktlint.core.RuleSetProviderV2 +++ /dev/null @@ -1 +0,0 @@ -org.cqfn.diktat.ruleset.rules.DiktatRuleSetProviderV2Spi diff --git a/diktat-ruleset/src/test/kotlin/com/pinterest/ktlint/core/KtLintTestUtils.kt b/diktat-ruleset/src/test/kotlin/com/pinterest/ktlint/core/KtLintTestUtils.kt new file mode 100644 index 0000000000..d75f745318 --- /dev/null +++ b/diktat-ruleset/src/test/kotlin/com/pinterest/ktlint/core/KtLintTestUtils.kt @@ -0,0 +1,7 @@ +/** + * This class contains util methods for KtLint + */ + +package com.pinterest.ktlint.core + +typealias LintError = org.cqfn.diktat.api.DiktatError diff --git a/diktat-ruleset/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSaveSmokeTest.kt b/diktat-ruleset/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSaveSmokeTest.kt index 95129883e0..8fa9d767c5 100644 --- a/diktat-ruleset/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSaveSmokeTest.kt +++ b/diktat-ruleset/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSaveSmokeTest.kt @@ -40,7 +40,7 @@ class DiktatSaveSmokeTest : DiktatSmokeTestBase() { } // do nothing, we can't check unfixed lint errors here - override fun doAssertUnfixedLintErrors(diktatErrorConsumer: (List) -> Unit) = Unit + override fun assertUnfixedLintErrors(diktatErrorConsumer: (List) -> Unit) = Unit /** * @param testPath path to file with code that will be transformed by formatter, relative to [TestComparatorUnit.resourceFilePath] diff --git a/diktat-ruleset/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt b/diktat-ruleset/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt index b70d814bb0..4924dea0bc 100644 --- a/diktat-ruleset/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt +++ b/diktat-ruleset/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTest.kt @@ -34,7 +34,7 @@ class DiktatSmokeTest : DiktatSmokeTestBase() { unfixedLintErrors.clear() } - override fun doAssertUnfixedLintErrors(diktatErrorConsumer: (List) -> Unit) { + override fun assertUnfixedLintErrors(diktatErrorConsumer: (List) -> Unit) { diktatErrorConsumer(unfixedLintErrors) } diff --git a/diktat-ruleset/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTestBase.kt b/diktat-ruleset/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTestBase.kt index 6787c56072..bec5f859cf 100644 --- a/diktat-ruleset/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTestBase.kt +++ b/diktat-ruleset/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSmokeTestBase.kt @@ -7,6 +7,7 @@ package org.cqfn.diktat.ruleset.smoke import org.cqfn.diktat.api.DiktatError +import com.pinterest.ktlint.core.LintError import org.cqfn.diktat.common.config.rules.DIKTAT_COMMON import org.cqfn.diktat.common.config.rules.DIKTAT_RULE_SET_ID import org.cqfn.diktat.common.config.rules.RulesConfig @@ -369,12 +370,7 @@ abstract class DiktatSmokeTestBase { test: String, ) - abstract fun doAssertUnfixedLintErrors(diktatErrorConsumer: (List) -> Unit) - - - private fun assertUnfixedLintErrors(lintErrorsConsumer: (List) -> Unit) = doAssertUnfixedLintErrors { diktatErrors -> - lintErrorsConsumer.invoke(diktatErrors.map(::LintError)) - } + abstract fun assertUnfixedLintErrors(diktatErrorConsumer: (List) -> Unit) companion object { private const val DEFAULT_CONFIG_PATH = "../diktat-analysis.yml" @@ -410,24 +406,5 @@ abstract class DiktatSmokeTestBase { it.toPath().deleteIfExistsSilently() } } - - /** - * A wrapper for DiktatError to be able to compare them - */ - private data class LintError( - val line: Int, - val col: Int, - val ruleId: String, - val detail: String, - var canBeAutoCorrected: Boolean = false, - ) { - constructor(diktatError: DiktatError) : this( - line = diktatError.getLine(), - col = diktatError.getCol(), - ruleId = diktatError.getRuleId(), - detail = diktatError.getDetail(), - canBeAutoCorrected = diktatError.canBeAutoCorrected(), - ) - } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 24ad3fa6bf..b12ba38f9d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ kotlin = "1.8.21" kotlin-ksp = "1.8.21-1.0.11" serialization = "1.5.1" -ktlint = "0.48.2" +ktlint = "0.49.1" junit = "5.9.3" junit-platfrom = "1.9.3" guava = "32.0.0-jre" @@ -107,12 +107,16 @@ kotlin-multiplatform-diff = { module = "io.github.petertrr:kotlin-multiplatform- # ktlint & detekt ktlint-core = { module = "com.pinterest.ktlint:ktlint-core", version.ref = "ktlint" } -ktlint-reporter-baseline = { module = "com.pinterest.ktlint:ktlint-reporter-baseline", version.ref = "ktlint" } -ktlint-reporter-checkstyle = { module = "com.pinterest.ktlint:ktlint-reporter-checkstyle", version.ref = "ktlint" } -ktlint-reporter-html = { module = "com.pinterest.ktlint:ktlint-reporter-html", version.ref = "ktlint" } -ktlint-reporter-json = { module = "com.pinterest.ktlint:ktlint-reporter-json", version.ref = "ktlint" } -ktlint-reporter-plain = { module = "com.pinterest.ktlint:ktlint-reporter-plain", version.ref = "ktlint" } -ktlint-reporter-sarif = { module = "com.pinterest.ktlint:ktlint-reporter-sarif", version.ref = "ktlint" } +ktlint-rule-engine = { module = "com.pinterest.ktlint:ktlint-rule-engine", version.ref = "ktlint" } +ktlint-logger = { module = "com.pinterest.ktlint:ktlint-logger", version.ref = "ktlint" } +ktlint-cli-reporter = { module = "com.pinterest.ktlint:ktlint-cli-reporter", version.ref = "ktlint" } +ktlint-cli-ruleset-core = { module = "com.pinterest.ktlint:ktlint-cli-ruleset-core", version.ref = "ktlint" } +ktlint-cli-reporter-baseline = { module = "com.pinterest.ktlint:ktlint-reporter-baseline", version.ref = "ktlint" } +ktlint-cli-reporter-checkstyle = { module = "com.pinterest.ktlint:ktlint-reporter-checkstyle", version.ref = "ktlint" } +ktlint-cli-reporter-html = { module = "com.pinterest.ktlint:ktlint-reporter-html", version.ref = "ktlint" } +ktlint-cli-reporter-json = { module = "com.pinterest.ktlint:ktlint-reporter-json", version.ref = "ktlint" } +ktlint-cli-reporter-plain = { module = "com.pinterest.ktlint:ktlint-reporter-plain", version.ref = "ktlint" } +ktlint-cli-reporter-sarif = { module = "com.pinterest.ktlint:ktlint-reporter-sarif", version.ref = "ktlint" } sarif4k = { module = "io.github.detekt.sarif4k:sarif4k", version.ref = "sarif4k" } sarif4k-jvm = { module = "io.github.detekt.sarif4k:sarif4k-jvm", version.ref = "sarif4k" }