An anti-bikeshedding Kotlin linter with built-in formatter
no-semi
(#1733)standard:filename
rule whenever Ktlint CLI is run with option --stdin
(#1742)--log-level
is specified. Throw exception when an invalid value is passed. (#1749)experimental
rule set are disabled by default. (#1747)1.8.0
and Kotlin version to 1.8.0
.The indent
rule has been rewritten from scratch. Solving problems in the old algorithm was very difficult. With the new algorithm this becomes a lot easier. Although the new implementation of the rule has been compared against several open source projects containing over 400,000 lines of code, it is still likely that new issues will be discovered. Please report your indentation issues so that these can be fixed as well.
.editorconfig
property to disable rulesIn the previous release (0.47.x), the .editorconfig
property disabled_rules
was deprecated and replaced with ktlint_disabled_rules
. This latter property has now been deprecated as well in favour of a more flexible and better maintainable solution. Rule and rule sets can now be enabled/disabled with a separate property per rule (set). Please read deprecation of (ktlint_)disable_rules property for more information.
The KtLint CLI has not been changed. Although you can still use parameter --experimental
to enable KtLint's Experimental rule set, you might want to set .editorconfig
property ktlint_experimental = enabled
instead.
If you are not an API consumer or Rule Set provider then you can skip this section.
Classes below have been relocated:
com.pinterest.ktlint.core.api.UsesEditorConfigProperties.EditorConfigProperty
has been replaced with com.pinterest.ktlint.core.api.editorconfig.EditorConfigProperty
.com.pinterest.ktlint.core.KtLintParseException
has been replaced with com.pinterest.ktlint.core.api.KtLintParseException
.com.pinterest.ktlint.core.RuleExecutionException
has been replaced with com.pinterest.ktlint.core.api.KtLintRuleException
.com.pinterest.ktlint.reporter.format.internal.Color
has been moved to com.pinterest.ktlint.reporter.format.Color
.com.pinterest.ktlint.reporter.plain.internal.Color
has been moved to com.pinterest.ktlint.reporter.plain.Color
.lint
and format
This is the last release that supports the ExperimentalParams
to invoke the lint
and format
functions of KtLint. The ExperimentalParams
contains a mix of configuration settings which are not dependent on the file/code which is to be processed. Other parameters in that class describe the code/file to be processed but can be configured inconsistently (for example a file with name "foo.kt" could be marked as a Kotlin Script file).
The static object KtLint
is deprecated and replaced by class KtLintRuleEngine
which is configured with KtLintRuleEngineConfiguration
. The instance of the KtLintRuleEngine
is intended to be reused for scanning all files in a project and should not be recreated per file.
Both lint
and format
are simplified and can now be called for a code block or for an entire file.
import java.io.File
// Define a reusable instance of the KtLint Rule Engine
val ktLintRuleEngine = KtLintRuleEngine(
// Define configuration
)
// Process a collection of files
val files: Set<File> // Collect files in a convenient way
files.forEach(file in files) {
ktLintRuleEngine.lint(file) {
// Handle lint violations
}
}
// or process a code sample for a given filepath
ktLintRuleEngine.lint(
code = "code to be linted",
filePath = Path("/path/to/source/file")
) {
// Handle lint violations
}
.editorconfig
sThe list of .editorconfig
files which will be accessed by KtLint when linting or formatting a given path can now be retrieved with the new API KtLint.editorConfigFilePaths(path: Path): List<Path>
.
This API can be called with either a file or a directory. It's intended usage is that it is called once with the root directory of a project before actually linting or formatting files of that project. When called with a directory path, all .editorconfig
files in the directory or any of its subdirectories (except hidden directories) are returned. In case the given directory does not contain an .editorconfig
file or if it does not contain the root=true
setting, the parent directories are scanned as well until a root .editorconfig
file is found.
Calling this API with a file path results in the .editorconfig
files that will be accessed when processing that specific file. In case the directory in which the file resides does not contain an .editorconfig
file or if it does not contain the root=true
setting, the parent directories are scanned until a root .editorconfig
file is found.
Constant KtLint.FILE_PATH_USER_DATA_KEY
is deprecated and will be removed in KtLint version 0.49.0. The file name will be passed correctly to the node with element type FILE and can be retrieved as follows:
if (node.isRoot()) {
val fileName = (node.psi as? KtFile)?.name
...
}
wrapping
(#1643)stdin
with the --patterns-from-stdin
command line options/flags (#1606)indent
rule and new experimental rule context-receiver-wrapping
(#1672)class-naming
), functions (function-naming
) and properties (property-naming
) (#44)plain-summary
which prints a summary the number of violation which have been autocorrected or could not be autocorrected, both split by rule..editorconfig
when running CLI with options --stdin
and --editorconfig
(#1651)trailing-comma-on-call-site
(#1642)ktlint_disabled_rules
to exposed editorConfigProperties
(#1671)trailing-comma-on-declaration-site
and trailing-comma-on-call-site
(#1676)function-signature
(#1690)1.8.0-RC
and Kotlin version to 1.7.21
.true
unless the android codestyle
is enabled. Note that KtLint from a consistency viewpoint enforces the trailing comma on call site while default IntelliJ IDEA formatting only allows the trailing comma but leaves it up to the developer's discretion. (#1670)true
unless the android codestyle
is enabled. Note that KtLint from a consistency viewpoint enforces the trailing comma on declaration site while default IntelliJ IDEA formatting only allows the trailing comma but leaves it up to the developer's discretion. (#1669)--debug
, --trace
, --verbose
and -v
are replaced with --log-level=<level>
or the short version `-l=--log-level=none
or -l=none
(#1652)indent
rule. Solving problems in the old algorithm was very difficult. With the new algorithm this becomes a lot easier. Although the new implementation of the rule has been compared against several open source projects containing over 400,000 lines of code, it is still likely that new issues will be discovered. Please report your indentation issues so that these can be fixed as well. (#1682, #1321, #1200, #1562, #1563, #1639)indent
rule. Solving problems in the old algorithm was very difficult. With the new algorithm this becomes a lot easier. Although the new implementation of the rule has been compared against several open source projects containing over 400,000 lines of code, it is still likely that new issues will be discovered. Please report your indentation issues so that these can be fixed as well. (#1682, #1321, #1200, #1562, #1563, #1639, #1688)java 19
, remove support for running tests on java 18
.io.github.detekt.sarif4k:sarif4k
version to 0.2.0
(#1701).trailing-comma-on-call-site
, trailing-comma-on-declaration-site
) (#1602)--disabled-rules
(#1599)@file:Suppress
on all toplevel declarations (#1623)If you are not an API consumer nor a RuleSet provider, then you can safely skip this section. Otherwise, please read below carefully and upgrade your usage of ktlint. In this and coming releases, we are changing and adapting important parts of our API in order to increase maintainability and flexibility for future changes. Please avoid skipping a releases as that will make it harder to migrate.
Up until ktlint 0.46 the Rule class provided only one life cycle hook. This "visit" hook was called in a depth-first-approach on all nodes in the file. A rule like the IndentationRule used the RunOnRootOnly visitor modifier to call this lifecycle hook for the root node only in combination with an alternative way of traversing the ASTNodes. Downside of this approach was that suppression of the rule on blocks inside a file was not possible (#631). More generically, this applied to all rules, applying alternative traversals of the AST.
The Rule class now offers new life cycle hooks:
Optionally, a rule can stop the traversal of the remainder of the AST whenever the goal of the rule has been achieved. See KDoc on Rule class for more information.
The "visit" life cycle hook will be removed in Ktlint 0.48. In KtLint 0.47 the "visit" life cycle hook will be called only when hook "beforeVisitChildNodes" is not overridden. It is recommended to migrate to the new lifecycle hooks in KtLint 0.47. Please create an issue, in case you need additional assistence to implement the new life cycle hooks in your rules.
The KtLint engine needs a more fine-grained control on the instantiation of new Rule instances. Currently, a new instance of a rule can be created only once per file. However, when formatting files the same rule instance is reused for a second processing iteration in case a Lint violation has been autocorrected. By re-using the same rule instance, state of that rule might leak from the first to the second processing iteration.
Providers of custom rule sets have to migrate the custom rule set JAR file. The current RuleSetProvider interface which is implemented in the custom rule set is deprecated and marked for removal in KtLint 0.48. Custom rule sets using the old RuleSetProvider interface will not be run in KtLint 0.48 or above.
For now, it is advised to implement the new RuleSetProviderV2 interface without removing the old RuleSetProvider interface. In this way, KtLint 0.47 and above use the RuleSetProviderV2 interface and ignore the old RuleSetProvider interface completely. KtLint 0.46 and below only use the old RuleSetProvider interface.
Adding the new interface is straight forward, as can be seen below:
// Current implementation
public class CustomRuleSetProvider : RuleSetProvider {
override fun get(): RuleSet = RuleSet(
"custom",
CustomRule1(),
CustomRule2(),
)
}
// New implementation
public class CustomRuleSetProvider :
RuleSetProviderV2(CUSTOM_RULE_SET_ID),
RuleSetProvider {
override fun get(): RuleSet =
RuleSet(
CUSTOM_RULE_SET_ID,
CustomRule1(),
CustomRule2()
)
override fun getRuleProviders(): Set<RuleProvider> =
setOf(
RuleProvider { CustomRule1() },
RuleProvider { CustomRule2() }
)
private companion object {
const val CUSTOM_RULE_SET_ID = custom"
}
}
Also note that file 'resource/META-INF/services/com.pinterest.ktlint.core.RuleSetProviderV2' needs to be added. In case your custom rule set provider implements both RuleSetProvider and RuleSetProviderV2, the resource directory contains files for both implementation. The content of those files is identical as the interfaces are implemented on the same class.
Once above has been implemented, rules no longer have to clean up their internal state as the KtLint rule engine can request a new instance of the Rule at any time it suspects that the internal state of the Rule is tampered with (e.g. as soon as the Rule instance is used for traversing the AST).
The KtLint engine needs a more fine-grained control on the instantiation of new Rule instances. Currently, a new instance of a rule can be created only once per file. However, when formatting files the same rule instance is reused for a second processing iteration in case a Lint violation has been autocorrected. By re-using the same rule instance, state of that rule might leak from the first to the second processing iteration.
The ExperimentalParams parameter which is used to invoke "KtLint.lint" and "KtLint.format" contains a new parameter "ruleProviders" which will replace the "ruleSets" parameter in KtLint 0.48. Exactly one of those parameters should be a non-empty set. It is preferred that API consumers migrate to using "ruleProviders".
// Old style using "ruleSets"
KtLint.format(
KtLint.ExperimentalParams(
...
ruleSets = listOf(
RuleSet(
"custom",
CustomRule1(),
CustomRule2()
)
),
...
)
)
// New style using "ruleProviders"
KtLint.format(
KtLint.ExperimentalParams(
...
ruleProviders = setOf(
RuleProvider { CustomRule1() },
RuleProvider { CustomRule2() }
),
cb = { _, _ -> }
)
)
Once above has been implemented, rules no longer have to clean up their internal state as the KtLint rule engine can request a new instance of the Rule at any time it suspects that the internal state of the Rule is tampered with (e.g. as soon as the Rule instance is used for traversing the AST).
The callback function provided as parameter to the format function is now called for all errors regardless whether the error has been autocorrected. Existing consumers of the format function should now explicitly check the autocorrected
flag in the callback result and handle it appropriately (in most case this will be ignoring the callback results for which autocorrected
has value true
).
Class com.pinterest.ktlint.core.internal.CurrentBaseline
has been replaced with com.pinterest.ktlint.core.api.Baseline
.
Noteworthy changes:
baselineRules
(nullable) is replaced with `lintErrorsPerFile (non-nullable).baselineGenerationNeeded
(boolean) is replaced with status
(type Baseline.Status
).The utility functions provided via com.pinterest.ktlint.core.internal.CurrentBaseline
are moved to the new class. One new method List<LintError>.doesNotContain(lintError: LintError)
is added.
The .editorconfig
property disabled_rules
(api property DefaultEditorConfigProperties.disabledRulesProperty
) has been deprecated and will be removed in a future version. Use ktlint_disabled_rules
(api property DefaultEditorConfigProperties.ktlintDisabledRulesProperty
) instead as it more clearly identifies that ktlint is the owner of the property. This property is to be renamed in .editorconfig
files and ExperimentalParams.editorConfigOverride
.
Although, Ktlint 0.47.0 falls back on property disabled_rules
whenever ktlint_disabled_rules
is not found, this result in a warning message being printed.
Parameter "ExperimentalParams.editorConfigPath" is deprecated in favor of the new parameter "ExperimentalParams.editorConfigDefaults". When used in the old implementation this resulted in ignoring all ".editorconfig" files on the path to the file. The new implementation uses properties from the "editorConfigDefaults"parameter only when no ".editorconfig" files on the path to the file supplies this property for the filepath.
API consumers can easily create the EditConfigDefaults by calling "EditConfigDefaults.load(path)" or creating it programmatically.
.editorconfig
fileSome API Consumers keep a long-running instance of the KtLint engine alive. In case an .editorconfig
file is changed, which was already loaded into the internal cache of the KtLint engine this change would not be taken into account by KtLint. One way to deal with this, was to clear the entire KtLint cache after each change in an .editorconfig
file.
Now, the API consumer can reload an .editorconfig
. If the .editorconfig
with given path is actually found in the cached, it will be replaced with the new value directly. If the file is not yet loaded in the cache, loading will be deferred until the file is actually requested again.
Example:
KtLint.reloadEditorConfigFile("/some/path/to/.editorconfig")
Several methods for which it is unlikely that they are used by API consumers have been marked for removal from the public API in KtLint 0.48.0. Please create an issue in case you have a valid business case to keep such methods in the public API.
format
reporter. This reporter prints a one-line-summary of the formatting status per file. (#621).filename
(#1521).indent
) #631
enum-entry-name-case
, filename
) (#1530).ktlint
cli on default kotlin extensions only when an (existing) path to a directory is given. (#917).format
function for all errors including errors that are autocorrected (#1491)function-signature
(#1527)multiline-if-else
(#1560)multiline-if-else
(#828)ktlint_code_style
(#1559)trailing-comma
(#1542)trailing-comma
into trailing-comma-on-call-site
and trailing-comma-on-declaration-site
(#1555)wrapping
(#1578)format
function for all errors including errors that are autocorrected (#1491)annotation
(#1574).editorconfig
property disabled_rules
to ktlint_disabled_rules
(#701)1.7.20-beta
and Kotlin version to 1.7.10
.7.5.1
versionMinor release to address some regressions introduced in 0.46.0
-Xuse-k2
as it forces API Consumers to compile their projects with this same flag (#1506).indent
(#1510)The rules below are promoted from the experimental
ruleset to the standard
ruleset.
annotation
annotation-spacing
argument-list-wrapping
double-colon-spacing
enum-entry-name-case
multiline-if-else
no-empty-first-line-in-method-block
package-name
trailing-comma
spacing-around-angle-brackets
spacing-between-declarations-with-annotations
spacing-between-declarations-with-comments
unary-op-spacing
Note that as a result of moving the rules that the prefix experimental:
has to be removed from all references to this rule. Check references in:
.editorconfig
setting disabled_rules
.VisitorModifier.RunAfterRule
.If your project did not run with the experimental
ruleset enabled before, you might expect new lint violations to be reported. Please note that rules can be disabled via the the .editorconfig
in case you do not want the rules to be applied on your project.
If you are not an API user nor a RuleSet provider, then you can safely skip this section. Otherwise, please read below carefully and upgrade your usage of ktlint. In this and coming releases, we are changing and adapting important parts of our API in order to increase maintainability and flexibility for future changes. Please avoid skipping a releases as that will make it harder to migrate.
The lint and formatting changes no longer accept parameters of type Params
but only ExperimentalParams
. Also, the VisitorProvider parameter has been removed. Because of this, your integration with KtLint breaks. Based on feedback with ktlint 0.45.x, we now prefer to break at compile time instead of trying to keep the interface backwards compatible. Please raise an issue, in case you help to convert to the new API.
The interface UsesEditorConfigProperties
provides method getEditorConfigValue
to retrieve a named .editorconfig
property for a given ASTNode. When implementing this interface, the value editorConfigProperties
needs to be overridden. Previously it was not checked whether a retrieved property was actually recorded in this list. Now, retrieval of unregistered properties results in an exception.
Property Ktlint.DISABLED
has been removed. The property value can now be retrieved as follows:
astNode
.getEditorConfigValue(DefaultEditorConfigProperties.disabledRulesProperty)
.split(",")
and be supplied via the ExperimentalParams
as follows:
ExperimentalParams(
...
editorConfigOverride = EditorConfigOverride.from(
DefaultEditorConfigProperties.disabledRulesProperty to "some-rule-id,experimental:some-other-rule-id"
)
...
)
Property Ktlint.ANDROID_USER_DATA_KEY
has been removed. The property value can now be retrieved as follows:
astNode
.getEditorConfigValue(DefaultEditorConfigProperties.codeStyleProperty)
and be supplied via the ExperimentalParams
as follows:
ExperimentalParams(
...
editorConfigOverride = EditorConfigOverride.from(
DefaultEditorConfigProperties.codeStyleProperty to "android"
)
...
)
This property defaults to the official
Kotlin code style when not set.
An AssertJ style API for testing KtLint rules (#1444) has been added. Usage of this API is encouraged in favor of using the old RuleExtension API. For more information, see KtLintAssertThat API
spacing-between-function-name-and-opening-parenthesis
) (#1341)parameter-list-spacing
) (#1341)function-return-type-spacing
) (#1341)nullable-type-spacing
) (#1341)type-parameter-list-spacing
) (#1435)function-start-of-body-spacing
) (#1341)@Suppress
(more information) (#765)function-signature
) (#1341)no-consecutive-blank-lines
to new rule (no-blank-lines-in-chained-method-calls
) (#1248)wrapping
(#1457)indent
(#1340)indent
) and a newline in the expression in a for-statement should not force to wrap it wrapping
(#1350)indent
(#1335).editorconfig
setting indentSize
is set to value tab
then return the default tab width as value for indentSize
(#1485)@file:Suppress(...)
(#1029)1.7.0
and Kotlin version to 1.7.0
.7.1.2
release4.6.3
releasefilename
(#1004)annotation
, annotation-spacing
, argument-list-wrapping
, double-colon-spacing
, enum-entry-name-case
, multiline-if-else
, no-empty-first-line-in-method-block
, package-name
, traling-comma
, spacing-around-angle-brackets
, spacing-between-declarations-with-annotations
, spacing-between-declarations-with-comments
, unary-op-spacing
(#1481)--android
can be omitted when the .editorconfig
property ktlint_code_style = android
is defined1.6.20
and Kotlin version to 1.6.20
.Minor release to fix a breaking issue with ktlint
API consumers
If you are not an API user nor a RuleSet provider, then you can safely skip this section. Otherwise, please read below carefully and upgrade your usage of ktlint. In this and coming releases, we are changing and adapting important parts of our API in order to increase maintainability and flexibility for future changes. Please avoid skipping a releases as that will make it harder to migrate.
This section is applicable when providing rules that depend on one or more values of ".editorconfig" properties. Property values should no longer be retrieved via EditConfig or directly via userData[EDITOR_CONFIG_USER_DATA_KEY]
. Property values should now only be retrieved using method ASTNode.getEditorConfigValue(editorConfigProperty)
of interface UsesEditorConfigProperties
which is provided in this release. Starting from next release after the current release, the EditConfig and/or userData[EDITOR_CONFIG_USER_DATA_KEY]
may be removed without further notice which will break your API or rule. To prevent disruption of your end user, you should migrate a.s.a.p.
function-type-reference-spacing
) (#1341)type-parameter-list-spacing
) (#1366)discouraged-comment-location
) (#1365)fun-keyword-spacing
) (#1362)experimental:block-comment-initial-star-alignment
(#297).editorconfig
property ij_kotlin_packages_to_use_import_on_demand
(no-wildcard-imports
) (#1272)comment-wrapping
) (#1403)kdoc-wrapping
) (#1403)type-parameter-list-spacing
) (#1366)no-multi-spaces
) (#1394)indent
) (#1375)no-unused-imports
) (#1277), (#1393), (#1256)indent
rule to the new rule wrapping
(as part of the standard
ruleset). In case you currently have disabled the indent
rule, you may want to reconsider whether this is still necessary or that you also want to disable the new wrapping
rule to keep the status quo. Both rules can be run independent of each other. (#835)Please welcome paul-dingemans as an official maintainer of ktlint!
trailing-comma
) (#1280)no-trailing-spaces
) (#1270)no-unused-imports
) (#1282)indent
) (#1222)trailing-comma
) (#1312)indent
) (#1210)indent
) (#1262)no-trailing-spaces
) (#1334)parameter-list-wrapping
) (#1255)indent
) (#1330)parameter-list-wrapping
, argument-list-wrapping
) (#897, #1045, #1119, #1255, #1267, #1319, #1320, #1337
parameter-list-wrapping
) (#1255)1.6.0
release1.6.0
release7.1.1
release7.4
version