Skip to content

Commit

Permalink
Add rule to migrate away from ktlint-disable directives (#2068)
Browse files Browse the repository at this point in the history
* Add rule to migrate ktlint-disable directives from comments to @Suppress or @SuppressWarnings annotations

Note that the SuppressionLocatorBuilder never ignore this rule as otherwise the suppression hint to ignore *all* rules would also ignore the rule which has to migrate this suppression hint.

Closes #1947

* Fix max line length for markdown files

* Fix wildcard imports settings

* Improve trace logging by printing a lint error directly when it is emitted

The reports print the lint violations in which they occur in the source code. This is not necessarily the order in which they are detected and fixed. For debugging some type of problems, the latter order is important.

* Add "libs.logback" as runtime only dependency so that logging is visible in unit tests
  • Loading branch information
paul-dingemans committed Jun 27, 2023
1 parent ef4afbe commit 4f6ed15
Show file tree
Hide file tree
Showing 48 changed files with 2,540 additions and 368 deletions.
6 changes: 6 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ root = true
[*]
indent_style = space
indent_size = 2
max_line_length = 140

end_of_line = lf
charset = utf-8
Expand All @@ -26,8 +27,13 @@ ktlint_experimental = enabled
# Don't allow any wildcard imports
ij_kotlin_packages_to_use_import_on_demand = unset

# Prevent wildcard imports
ij_kotlin_name_count_to_use_star_import = 99
ij_kotlin_name_count_to_use_star_import_for_members = 99

[*.md]
trim_trailing_whitespace = false
max_line_length = unset

[gradle/verification-metadata.xml]
indent_size = 3
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ This project adheres to [Semantic Versioning](https://semver.org/).

## Unreleased

### Deprecation of ktlint-enable and ktlint-disable directives

The `ktlint-disable` and `ktlint-enable` directives are no longer supported. Ktlint rules can now only be suppressed using the `@Suppress` or `@SuppressWarnings` annotations. A new rule, `internal:ktlint-suppression`, is provided to replace the directives with annotations.

API consumers do not need to provide this rule, but it does no harm when done.

The `internal:ktlint-suppression` rule can not be disabled via the `.editorconfig` nor via `@Suppress` or `@SuppressWarnings` annotations.

### Custom Rule Providers need to prepare for Kotlin 1.9

In Kotlin 1.9 the extension points of the embedded kotlin compiler will change. Ktlint only uses the `org.jetbrains.kotlin.com.intellij.treeCopyHandler` extension point. This extension is not yet supported in 1.9, neither is it documented ([#KT-58704](https://youtrack.jetbrains.com/issue/KT-58704/Support-and-document-extension-point-org.jetbrains.kotlin.com.intellij.treeCopyHandler)). Without this extension point it might happen that your custom rules will throw exceptions during runtime. See [#1981](https://github.com/pinterest/ktlint/issues/1981).
Expand Down Expand Up @@ -32,6 +40,7 @@ At this point in time, it is not yet decided what the next steps will be. Ktlint
* Add new experimental rule `statement-wrapping` which ensures function, class, or other blocks statement body doesn't start or end at starting or ending braces of the block ([#1938](https://github.com/pinterest/ktlint/issues/1938))
* Add new experimental rule `blank-line-before-declaration`. This rule requires a blank line before class, function or property declarations ([#1939](https://github.com/pinterest/ktlint/issues/1939))
* Wrap multiple statements on same line `wrapping` ([#1078](https://github.com/pinterest/ktlint/issues/1078))
* Add new rule `ktlint-suppression` to replace the `ktlint-disable` and `ktlint-enable` directives with annotations. This rule can not be disabled via the `.editorconfig` ([#1947](https://github.com/pinterest/ktlint/issues/1947))
* Inform user about using `--format` option of KtLint CLI when finding a violation that can be autocorrected ([#1071](https://github.com/pinterest/ktlint/issues/1071))

### Removed
Expand Down
49 changes: 4 additions & 45 deletions documentation/snapshot/docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,17 @@ See [adding a custom rule set](../api/custom-rule-set/) for more information.
!!! tip
Suppressing a `ktlint` violation is meant primarily as an escape latch for the rare cases when **ktlint** is not able to produce the correct result. Please report any such instances using [GitHub Issues](https://github.com/pinterest/ktlint/issues)).

To disable a specific rule you'll need the rule identifier which is displayed at the end of the lint error.
To disable a specific rule you'll need the fully qualified rule identifier. This identifier is displayed at the end of the lint error. In case your code was autocorrected, you need to revert the code and run the `lint` task instead of the `format` to find the rule identifier.

An error can be suppressed using:
As of Ktlint 0.50, an error can only be suppressed using @Suppress or @SuppressWarnings annotations

* EOL comments
* Block comments
* @Suppress annotations

=== "[:material-heart:](#) Suppress annotation"
=== "[:material-heart:](#) Allowed"

```kotlin
// Suppressing all rules for the entire file
@file:Suppress("ktlint")

// Suppress a single rule (with id 'rule-id', defined in rule set with id 'rule-set-id') from the annotated construct
// Suppress a single rule (with id 'rule-id', defined in rule set with id 'rule-set-id') in the scope of the annotated construct
@Suppress("ktlint:rule-set-id:rule-id")
class Foo {}

Expand All @@ -69,43 +65,6 @@ An error can be suppressed using:
@Suppress("ktlint")
import foo.*
```
=== "[:material-heart:](#) EOL comments"

```kotlin
// Suppress a single rule for the commented line
import foo.* // ktlint-disable standard_no-wildcard-imports

// Suppress multiple rules for the commented line
import foo.* // ktlint-disable standard_no-wildcard-imports standard_other-rule-id

// Suppress all rules for the commented line
import foo.* // ktlint-disable
```

=== "[:material-heart-off-outline:](#) Block comments"

```kotlin
// Suppress a single rule for all code between the start and end tag
/* ktlint-disable standard_no-wildcard-imports */
import foo.*
/* ktlint-disable standard_no-wildcard-imports */

// Suppress multiple rules for all code between the start and end tag
/* ktlint-disable standard_no-wildcard-imports standard_no-wildcard-imports */
import foo.*
/* ktlint-enable standard_no-wildcard-imports standard_no-wildcard-imports */

// Suppress all rules for all code between the start and end tag
/* ktlint-disable */
import foo.*
/* ktlint-enable */
```

!!! important
When using the block comments, the `ktlint-enable` directive needs to specify the exact same rule-id's and in the same order as the `ktlint-disable` directive.

!!! warning
From a consistency perspective seen, it might be best to **not** mix the (EOL/Block) comment style with the annotation style in the same project.

## How do I globally disable a rule without `.editorconfig`?

Expand Down
4 changes: 0 additions & 4 deletions documentation/snapshot/docs/rules/experimental.md
Original file line number Diff line number Diff line change
Expand Up @@ -465,10 +465,6 @@ A single line block comment should be replaced with an EOL comment when possible
*/
val foo = "foo" // Some comment
val foo = { /* no-op */ }

/* ktlint-disable foo-rule-id bar-rule-id */
val foo = "foo"
/* ktlint-enable foo-rule-id bar-rule-id */
```
=== "[:material-heart-off-outline:](#) Disallowed"

Expand Down
48 changes: 48 additions & 0 deletions documentation/snapshot/docs/rules/standard.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,54 @@ Indentation formatting - respects `.editorconfig` `indent_size` with no continua

Rule id: `indent` (`standard` rule set)

## Ktlint-suppression rule

The `ktlint-disable` and `ktlint-enable` directives are no longer supported as of ktlint version `0.50.0`. This rule migrates the directives to Suppress or SuppressWarnings annotations.

Identifiers in the @Suppress and @SuppressWarnings annotations to suppress ktlint rules are checked for validity and autocorrected when possible.

=== "[:material-heart:](#) Ktlint"

```kotlin
@file:Suppress("ktlint:standard:no-wildcard-imports")

class FooBar {
@Suppress("ktlint:standard:max-line-length")
val foo = "some longggggggggggggggggggg text"

fun bar() =
@Suppress("ktlint:standard:no-multi-spaces")
listOf(
"1 One",
"10 Ten",
"100 Hundred",
)
}
```
=== "[:material-heart-off-outline:](#) Disallowed"

```kotlin
/* ktlint-disable standard:no-wildcard-imports */

class FooBar {
val foo = "some longggggggggggggggggggg text" // ktlint-disable standard:max-line-length

fun bar() =
listOf(
/* ktlint-disable standard:no-multi-spaces */
"1 One",
"10 Ten",
"100 Hundred",
/* ktlint-enable standard:no-multi-spaces */
)
}
```

Rule id: `ktlint-suppression` (`standard` rule set)

!!! note
This rule can not be disabled in the `.editorconfig`.

## Max line length

Ensures that lines do not exceed the given length of `.editorconfig` property `max_line_length` (see [EditorConfig](../configuration-ktlint/) section for more). This rule does not apply in a number of situations. For example, in the case a line exceeds the maximum line length due to a comment that disables ktlint rules then that comment is being ignored when validating the length of the line. The `.editorconfig` property `ktlint_ignore_back_ticked_identifier` can be set to ignore identifiers which are enclosed in backticks, which for example is very useful when you want to allow longer names for unit tests.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,29 @@ class CheckStyleReporterTest {
val reporter = CheckStyleReporter(PrintStream(out, true))
reporter.onLintError(
"/one-fixed-and-one-not.kt",
@Suppress("ktlint:argument-list-wrapping")
@Suppress("ktlint:standard:argument-list-wrapping")
KtlintCliError(1, 1, "rule-1", "<\"&'>", LINT_CAN_BE_AUTOCORRECTED),
)
reporter.onLintError(
"/one-fixed-and-one-not.kt",
@Suppress("ktlint:argument-list-wrapping")
@Suppress("ktlint:standard:argument-list-wrapping")
KtlintCliError(2, 1, "rule-2", "And if you see my friend", FORMAT_IS_AUTOCORRECTED),
)

reporter.onLintError(
"/two-not-fixed.kt",
@Suppress("ktlint:argument-list-wrapping")
@Suppress("ktlint:standard:argument-list-wrapping")
KtlintCliError(1, 10, "rule-1", "I thought I would again", LINT_CAN_BE_AUTOCORRECTED),
)
reporter.onLintError(
"/two-not-fixed.kt",
@Suppress("ktlint:argument-list-wrapping")
@Suppress("ktlint:standard:argument-list-wrapping")
KtlintCliError(2, 20, "rule-2", "A single thin straight line", LINT_CAN_BE_AUTOCORRECTED),
)

reporter.onLintError(
"/all-corrected.kt",
@Suppress("ktlint:argument-list-wrapping")
@Suppress("ktlint:standard:argument-list-wrapping")
KtlintCliError(1, 1, "rule-1", "I thought we had more time", FORMAT_IS_AUTOCORRECTED),
)
reporter.afterAll()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,15 @@ class FormatReporterTest {
}

companion object {
@Suppress("ktlint:argument-list-wrapping", "ktlint:max-line-length")
@Suppress("ktlint:standard:argument-list-wrapping", "ktlint:standard:max-line-length")
val SOME_LINT_ERROR_CAN_BE_AUTOCORRECTED =
KtlintCliError(1, 1, "some-rule", "This error can be autocorrected", LINT_CAN_BE_AUTOCORRECTED)

@Suppress("ktlint:argument-list-wrapping", "ktlint:max-line-length")
@Suppress("ktlint:standard:argument-list-wrapping", "ktlint:standard:max-line-length")
val SOME_LINT_ERROR_CAN_NOT_BE_AUTOCORRECTED =
KtlintCliError(1, 1, "rule-1", "This error can *not* be autocorrected", LINT_CAN_NOT_BE_AUTOCORRECTED)

@Suppress("ktlint:argument-list-wrapping", "ktlint:max-line-length")
@Suppress("ktlint:standard:argument-list-wrapping", "ktlint:standard:max-line-length")
val SOME_FORMAT_ERROR_IS_AUTOCORRECTED =
KtlintCliError(1, 1, "rule-1", "This error can *not* be autocorrected", FORMAT_IS_AUTOCORRECTED)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,13 @@ class HtmlReporterTest {
val out = ByteArrayOutputStream()
val reporter = HtmlReporter(PrintStream(out, true))

@Suppress("ktlint:argument-list-wrapping", "ktlint:max-line-length")
@Suppress("ktlint:standard:argument-list-wrapping", "ktlint:standard:max-line-length")
reporter.onLintError(
"/file1.kt",
KtlintCliError(1, 1, "rule-1", "Error message contains a generic type like List<Int> (cannot be auto-corrected)", LINT_CAN_BE_AUTOCORRECTED),
)

@Suppress("ktlint:argument-list-wrapping", "ktlint:max-line-length")
@Suppress("ktlint:standard:argument-list-wrapping", "ktlint:standard:max-line-length")
reporter.onLintError(
"/file1.kt",
KtlintCliError(2, 1, "rule-2", "Error message contains special html symbols like a<b>c\"d'e&f (cannot be auto-corrected)", LINT_CAN_BE_AUTOCORRECTED),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,29 @@ class JsonReporterTest {
val reporter = JsonReporter(PrintStream(out, true))
reporter.onLintError(
"/one-fixed-and-one-not.kt",
@Suppress("ktlint:argument-list-wrapping")
@Suppress("ktlint:standard:argument-list-wrapping")
KtlintCliError(1, 1, "rule-1", "<\"&'>", LINT_CAN_BE_AUTOCORRECTED),
)
reporter.onLintError(
"/one-fixed-and-one-not.kt",
@Suppress("ktlint:argument-list-wrapping")
@Suppress("ktlint:standard:argument-list-wrapping")
KtlintCliError(2, 1, "rule-2", "And if you see my friend", FORMAT_IS_AUTOCORRECTED),
)

reporter.onLintError(
"/two-not-fixed.kt",
@Suppress("ktlint:argument-list-wrapping")
@Suppress("ktlint:standard:argument-list-wrapping")
KtlintCliError(1, 10, "rule-1", "I thought I would again", LINT_CAN_BE_AUTOCORRECTED),
)
reporter.onLintError(
"/two-not-fixed.kt",
@Suppress("ktlint:argument-list-wrapping")
@Suppress("ktlint:standard:argument-list-wrapping")
KtlintCliError(2, 20, "rule-2", "A single thin straight line", LINT_CAN_BE_AUTOCORRECTED),
)

reporter.onLintError(
"/all-corrected.kt",
@Suppress("ktlint:argument-list-wrapping")
@Suppress("ktlint:standard:argument-list-wrapping")
KtlintCliError(1, 1, "rule-1", "I thought we had more time", FORMAT_IS_AUTOCORRECTED),
)
reporter.afterAll()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,29 @@ class PlainSummaryReporterTest {
).apply {
onLintError(
"file-1.kt",
@Suppress("ktlint:argument-list-wrapping")
@Suppress("ktlint:standard:argument-list-wrapping")
KtlintCliError(1, 1, "rule-1", "description-error-at-position-1:1 (cannot be auto-corrected)", LINT_CAN_BE_AUTOCORRECTED),
)
onLintError(
"file-1.kt",
@Suppress("ktlint:argument-list-wrapping")
@Suppress("ktlint:standard:argument-list-wrapping")
KtlintCliError(2, 1, "rule-2", "description-error-at-position-2:1", FORMAT_IS_AUTOCORRECTED),
)

onLintError(
"file-2.kt",
@Suppress("ktlint:argument-list-wrapping")
@Suppress("ktlint:standard:argument-list-wrapping")
KtlintCliError(1, 10, "rule-1", "description-error-at-position-1:10 (cannot be auto-corrected)", LINT_CAN_BE_AUTOCORRECTED),
)
onLintError(
"file-2.kt",
@Suppress("ktlint:argument-list-wrapping")
@Suppress("ktlint:standard:argument-list-wrapping")
KtlintCliError(2, 20, "rule-2", "description-error-at-position-2:20 (cannot be auto-corrected)", LINT_CAN_BE_AUTOCORRECTED),
)

onLintError(
"file-3.kt",
@Suppress("ktlint:argument-list-wrapping")
@Suppress("ktlint:standard:argument-list-wrapping")
KtlintCliError(1, 1, "rule-1", "description-error-at-position-1:1", FORMAT_IS_AUTOCORRECTED),
)

Expand Down Expand Up @@ -72,17 +72,17 @@ class PlainSummaryReporterTest {
val reporter = PlainSummaryReporter(PrintStream(out, true))
reporter.onLintError(
"file-1.kt",
@Suppress("ktlint:argument-list-wrapping", "ktlint:max-line-length")
@Suppress("ktlint:standard:argument-list-wrapping", "ktlint:standard:max-line-length")
KtlintCliError(18, 51, "", "Not a valid Kotlin file (18:51 unexpected tokens (use ';' to separate expressions on the same line)) (cannot be auto-corrected) ()", KOTLIN_PARSE_EXCEPTION),
)
reporter.onLintError(
"file-2.kt",
@Suppress("ktlint:argument-list-wrapping", "ktlint:max-line-length")
@Suppress("ktlint:standard:argument-list-wrapping", "ktlint:standard:max-line-length")
KtlintCliError(18, 51, "", "Not a valid Kotlin file (18:51 unexpected tokens (use ';' to separate expressions on the same line)) (cannot be auto-corrected) ()", KOTLIN_PARSE_EXCEPTION),
)
reporter.onLintError(
"file-3.kt",
@Suppress("ktlint:argument-list-wrapping")
@Suppress("ktlint:standard:argument-list-wrapping")
KtlintCliError(18, 51, "", "Something else", LINT_CAN_BE_AUTOCORRECTED),
)
reporter.afterAll()
Expand Down
Loading

0 comments on commit 4f6ed15

Please sign in to comment.