Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Differentiate between correctable and non-correctable KtLint rules #5324

Merged
merged 2 commits into from Sep 24, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -7,6 +7,7 @@ import com.pinterest.ktlint.core.api.DefaultEditorConfigProperties.codeStyleSetP
import com.pinterest.ktlint.core.api.UsesEditorConfigProperties
import io.github.detekt.psi.fileName
import io.github.detekt.psi.toFilePath
import io.gitlab.arturbosch.detekt.api.CodeSmell
import io.gitlab.arturbosch.detekt.api.Config
import io.gitlab.arturbosch.detekt.api.CorrectableCodeSmell
import io.gitlab.arturbosch.detekt.api.Debt
Expand Down Expand Up @@ -47,6 +48,9 @@ abstract class FormattingRule(config: Config) : Rule(config) {
private var positionByOffset: (offset: Int) -> Pair<Int, Int> by SingleAssign()
private var root: KtFile by SingleAssign()

// KtLint has rules which prompts the user to manually correct issues e.g. Filename and PackageName.
protected open fun canBeCorrectedByKtLint(message: String): Boolean = true
arturbosch marked this conversation as resolved.
Show resolved Hide resolved

protected fun issueFor(description: String) =
Issue(javaClass.simpleName, Severity.Style, description, Debt.FIVE_MINS)

Expand Down Expand Up @@ -102,7 +106,12 @@ abstract class FormattingRule(config: Config) : Rule(config) {
?.plus(".")
.orEmpty()
val entity = Entity("", "$packageName${root.fileName}:$line", location, root)
report(CorrectableCodeSmell(issue, entity, message, autoCorrectEnabled = autoCorrect))

if (canBeCorrectedByKtLint(message)) {
report(CorrectableCodeSmell(issue, entity, message, autoCorrectEnabled = autoCorrect))
} else {
report(CodeSmell(issue, entity, message))
}
}
}

Expand Down
Expand Up @@ -15,4 +15,6 @@ class EnumEntryNameCase(config: Config) : FormattingRule(config) {

override val wrapping = EnumEntryNameCaseRule()
override val issue = issueFor("Reports enum entries with names that don't meet standard conventions.")

override fun canBeCorrectedByKtLint(message: String): Boolean = false
}
Expand Up @@ -16,4 +16,6 @@ class Filename(config: Config) : FormattingRule(config) {

override val wrapping = FilenameRule()
override val issue = issueFor("Checks if top level class matches the filename")

override fun canBeCorrectedByKtLint(message: String): Boolean = false
}
Expand Up @@ -24,6 +24,8 @@ class ImportOrdering(config: Config) : FormattingRule(config) {
@Configuration("the import ordering layout")
private val layout: String by configWithAndroidVariants(IDEA_PATTERN, ASCII_PATTERN)

override fun canBeCorrectedByKtLint(message: String): Boolean = "no autocorrection" !in message

override fun overrideEditorConfigProperties(): Map<UsesEditorConfigProperties.EditorConfigProperty<*>, String> =
mapOf(ImportOrderingRule.ideaImportsLayoutProperty to layout)

Expand Down
Expand Up @@ -30,6 +30,8 @@ class Indentation(config: Config) : FormattingRule(config) {
@Suppress("UnusedPrivateMember")
private val continuationIndentSize by config(4)

override fun canBeCorrectedByKtLint(message: String): Boolean = "not contain both tab(s) and space(s)" !in message

override fun overrideEditorConfigProperties(): Map<UsesEditorConfigProperties.EditorConfigProperty<*>, String> =
mapOf(
DefaultEditorConfigProperties.indentSizeProperty to indentSize.toString(),
Expand Down
Expand Up @@ -32,6 +32,8 @@ class MaximumLineLength(config: Config) : FormattingRule(config) {
@Configuration("ignore back ticked identifier")
private val ignoreBackTickedIdentifier by config(false)

override fun canBeCorrectedByKtLint(message: String): Boolean = false

override fun overrideEditorConfigProperties(): Map<UsesEditorConfigProperties.EditorConfigProperty<*>, String> =
mapOf(
MaxLineLengthRule.ignoreBackTickedIdentifierProperty to ignoreBackTickedIdentifier.toString(),
Expand Down
Expand Up @@ -20,6 +20,8 @@ class NoWildcardImports(config: Config) : FormattingRule(config) {
@Configuration("Defines allowed wildcard imports")
private val packagesToUseImportOnDemandProperty by config(ALLOWED_WILDCARD_IMPORTS)

override fun canBeCorrectedByKtLint(message: String): Boolean = false

override fun overrideEditorConfigProperties(): Map<UsesEditorConfigProperties.EditorConfigProperty<*>, String> =
mapOf(
NoWildcardImportsRule.packagesToUseImportOnDemandProperty to packagesToUseImportOnDemandProperty
Expand Down
Expand Up @@ -16,4 +16,6 @@ class PackageName(config: Config) : FormattingRule(config) {

override val wrapping = PackageNameRule()
override val issue = issueFor("Checks package name is formatted correctly")

override fun canBeCorrectedByKtLint(message: String): Boolean = false
}
@@ -0,0 +1,56 @@
package io.gitlab.arturbosch.detekt.formatting

import io.gitlab.arturbosch.detekt.api.CodeSmell
import io.gitlab.arturbosch.detekt.api.Config
import io.gitlab.arturbosch.detekt.formatting.wrappers.EnumEntryNameCase
import io.gitlab.arturbosch.detekt.formatting.wrappers.Filename
import io.gitlab.arturbosch.detekt.formatting.wrappers.ImportOrdering
import io.gitlab.arturbosch.detekt.formatting.wrappers.Indentation
import io.gitlab.arturbosch.detekt.formatting.wrappers.MaximumLineLength
import io.gitlab.arturbosch.detekt.formatting.wrappers.NoWildcardImports
import io.gitlab.arturbosch.detekt.formatting.wrappers.PackageName
import io.gitlab.arturbosch.detekt.test.assertThat
import org.junit.jupiter.api.DynamicTest
import org.junit.jupiter.api.TestFactory

class RulesWhichCantBeCorrectedSpec {

@TestFactory
fun `verify findings of these rules are not correctable`(): Iterable<DynamicTest> {
val commonCode = """
package under_score
import xyz.wrong_order
/*comment in between*/
import java.io.*
class NotTheFilename
class MaximumLeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeth
enum class Enum {
violation_triggering_name
}
""".trimIndent()

val multilineQuote = "${'"'}${'"'}${'"'}"
val indentationCode = """
val foo = $multilineQuote
line1
${'\t'}line2
$multilineQuote.trimIndent()
""".trimIndent()

return listOf(
Filename(Config.empty) to commonCode,
PackageName(Config.empty) to commonCode,
NoWildcardImports(Config.empty) to commonCode,
MaximumLineLength(Config.empty) to commonCode,
EnumEntryNameCase(Config.empty) to commonCode,
ImportOrdering(Config.empty) to commonCode,
Indentation(Config.empty) to indentationCode,
).map { (rule, code) ->
DynamicTest.dynamicTest("${rule.ruleId} should not return correctable code smell") {
assertThat(rule.lint(code, "non_pascal_case.kt"))
.isNotEmpty
.hasExactlyElementsOfTypes(CodeSmell::class.java)
}
}
}
}