diff --git a/CHANGELOG.md b/CHANGELOG.md index 9350e072a2..72117af4c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -96,6 +96,11 @@ if (node.isRoot()) { * Add missing `ktlint_disabled_rules` to exposed `editorConfigProperties` ([#1671](https://github.com/pinterest/ktlint/issue/1671)) * Do not add a second trailing comma, if the original trailing comma is followed by a KDOC `trailing-comma-on-declaration-site` and `trailing-comma-on-call-site` ([#1676](https://github.com/pinterest/ktlint/issue/1676)) * A function signature preceded by an annotation array should be handled similar as function preceded by a singular annotation `function-signature` ([#1690](https://github.com/pinterest/ktlint/issue/1690)) +* Fix offset of annotation violations +* Fix line offset when blank line found between class and primary constructor +* Remove needless blank line between class followed by EOL, and primary constructor +* Fix offset of unexpected linebreak before assignment +* Remove whitespace before redundant semicolon if the semicolon is followed by whitespace ### Changed * Update Kotlin development version to `1.8.0-RC` and Kotlin version to `1.7.21`. diff --git a/RELEASE_TESTING.MD b/RELEASE_TESTING.MD index c9bd30dd15..c21514ac2e 100644 --- a/RELEASE_TESTING.MD +++ b/RELEASE_TESTING.MD @@ -54,7 +54,10 @@ Before releasing a new version of KtLint, the release candidate is tested on a s ```shell ./exec-in-each-project.sh "git pull" ``` -3. Remove file `baseline.xml` +3. Remove baseline file + ```shell + rm baseline.xml + ``` ## Testing a new release @@ -68,6 +71,8 @@ Pre-requisites: Formatting projects in which ktlint is not used may result in a huge amount of fixes. The main focus of this test is to see what the effects are when upgrading ktlint in a project already formatted with latest released ktlint version. +TODO: After release 0.48, update procedure below as the parameter "--experimental" does not need to be specified anymore when it is stored correctly in the `.editorconfig` file(s). + 1. Format the sample projects with the *latest released* ktlint version: ```shell ktlint -F --experimental --relative # Do not call this command via the "./exec-in-each-project.sh" script. @@ -77,25 +82,53 @@ Formatting projects in which ktlint is not used may result in a huge amount of f ```shell ./exec-in-each-project.sh "git add --all && git commit -m \"Format with ktlint (xx.yy.zz) -F --experimental\"" ``` -3. Create a baseline file with the *latest released* ktlint version: + Repeat step 1 and 2 until no files are changed anymore. +3. Create a new baseline file with the *latest released* ktlint version to ignore all lint violations that could not be autocorrected using the latest ktlint version: ```shell + rm baseline.xml ktlint --experimental --baseline=baseline.xml --relative # Do not call this command via the "./exec-in-each-project.sh" script as we want one combined baseline.xml file for all projects. ``` -4. Rerun previous command. As all violations were stored in file `baseline.xml` it is to be expected that no violations will be reported anymore. However, if violations are reported, this should be investigated and fixed before proceeding as otherwise you might falsely interpret them as caused by changed in the new release. You might want to add some `.editorconfig` configuration to suppress violations which can not be autocorrected. Commit your changes: +4. Check that besides the `baseline.xml` no files are changed (in step 1 and 2 all violations which could be autocorrected have already been committed). Remaining violations which could not be autocorrected are saved in the `baseline.xml` which is stored outside the project directories. ```shell - ./exec-in-each-project.sh "git add --all && git commit -m \"Fix for some reason\"" + ./exec-in-each-project.sh "git status" + ``` + The `baseline.xml` file should only contain errors which can not be autocorrected. +5. Define `.editorconfig` in the integration test directory with content below. Also follow up the instructions mentioned: + ```editorconfig + root = true + [*.{kt,kts}] + # The open source projects that are used for release testing of ktlint contain a few '.editorconfig' files which need to + # be changed: + # 1) Disable the "root = true" property so that each project ultimately falls back on this file. In this way offending + # rules can be easily enabled/disabled for all test projects + # 2) Add specific rules to project below + # graphql + # ktlint_standard_import-ordering = disabled + # ktlint_standard_package-name = disabled + ktlint_standard = enabled + ktlint_standard_filename = disabled + ktlint_standard_no-wildcard-imports = disabled + + ktlint_experimental = enabled + ktlint_experimental_function-naming = disabled + ktlint_experimental_property-naming = disabled ``` - Repeat until no new violations are reported. -5. Lint with *latest development* version: +6. Commit changes: ```shell - ktlint-dev --experimental --baseline=baseline.xml --relative # Do not call this command via the "./exec-in-each-project.sh" script as we want to use the one combined baseline.xml file for all projects. + ./exec-in-each-project.sh "git add --all && git commit -m \"Update .editorconfig to fallback to integration test settings\"" + ``` +7. Lint with *latest development* version: + ```shell + ktlint-dev --baseline=baseline.xml --relative # Do not call this command via the "./exec-in-each-project.sh" script as we want to use the one combined baseline.xml file for all projects. + # or when lots are violations are reported + ktlint-dev --baseline=baseline.xml --relative --reporter=plain-summary # Do not call this command via the "./exec-in-each-project.sh" script as we want to use the one combined baseline.xml file for all projects. ``` Inspect the output roughly (detailed inspection is done when formatting): * Is the amount of logging messages comparable to before? If not, are the changes intended? * Are violations related to rules that have actually been added or changed? -6. Format with *latest development* version: +8. Format with *latest development* version: ```shell - ktlint-dev -F --experimental --baseline=baseline.xml --relative # Do not call this command via the "./exec-in-each-project.sh" script as we want to use the one combined baseline.xml file for all projects. + ktlint-dev -F --baseline=baseline.xml --relative # Do not call this command via the "./exec-in-each-project.sh" script as we want to use the one combined baseline.xml file for all projects. ``` Inspect the output carefully: * If you see an error like below, then this version obviously may *not* be released. It is best to fix this error before continuing with testing and validating! @@ -105,15 +138,15 @@ Formatting projects in which ktlint is not used may result in a huge amount of f * Ideally, no violations are shown. This means that all violations have been autocorrected. * Violations which could not be autocorrected should be validated for correctness but do not block the release as most likely this is intended behavior. * If a violation is shown which is not marked as being "can not be autocorrected" this means that during autocorrect of another violation a new violations has been introduced. This should be fixed before releasing especially when the next format introduces the original violation again which of course would result in an endless loop. -7. Inspect all fixed violations, Of course inspection similar violations tens of times does not make sense. At least check different types of violations a couple of times. Commit changes which do not need to be inspected again: +9. Inspect all fixed violations, Of course inspection similar violations tens of times does not make sense. At least check different types of violations a couple of times. Commit changes which do not need to be inspected again: ```shell ./exec-in-each-project.sh "git add --all && git commit -m \"Fixed with latest development version\"" ``` -8. Rerun lint with *latest development* version: - ```shell - ktlint-dev --experimental --baseline=baseline.xml --relative # Do not call this command via the "./exec-in-each-project.sh" script as we want to use the one combined baseline.xml file for all projects. - ``` - No violations should be expected. +10. Rerun lint with *latest development* version: + ```shell + ktlint-dev --experimental --baseline=baseline.xml --relative # Do not call this command via the "./exec-in-each-project.sh" script as we want to use the one combined baseline.xml file for all projects. + ``` + No violations, except error that can not be autocorrected, should be expected. ## Checking documentation [The documentation for KtLint](https://pinterest.github.io/ktlint/) should be checked for dead links. diff --git a/docs/install/cli.md b/docs/install/cli.md index c088550c07..356eeb3bcc 100644 --- a/docs/install/cli.md +++ b/docs/install/cli.md @@ -60,7 +60,7 @@ When no arguments are specified, the style of all Kotlin files (ending with '.kt ktlint ``` -To validate with the [standard ruleset](../../rules/standard/) and the [experimental rulesset](../../rules/experimental/) run command below: +To validate with the [standard ruleset](../../rules/standard/) and the [experimental ruleset](../../rules/experimental/) run command below: ```shell title="Validation with standard and experimental ruleset" ktlint --experimental diff --git a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/KtLint.kt b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/KtLint.kt index 46fca2d2c2..4b521c7a4a 100644 --- a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/KtLint.kt +++ b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/KtLint.kt @@ -11,6 +11,7 @@ import com.pinterest.ktlint.core.api.EditorConfigOverride import com.pinterest.ktlint.core.api.EditorConfigOverride.Companion.EMPTY_EDITOR_CONFIG_OVERRIDE import com.pinterest.ktlint.core.api.KtLintRuleException import com.pinterest.ktlint.core.api.UsesEditorConfigProperties +import com.pinterest.ktlint.core.api.editorconfig.CODE_STYLE_PROPERTY import com.pinterest.ktlint.core.api.editorconfig.CodeStyleValue import com.pinterest.ktlint.core.api.editorconfig.DEFAULT_EDITOR_CONFIG_PROPERTIES import com.pinterest.ktlint.core.internal.EditorConfigFinder @@ -580,10 +581,10 @@ public class KtLintRuleEngine( public fun generateKotlinEditorConfigSection(filePath: Path): String { val codeStyle = editorConfigOverride - .properties[com.pinterest.ktlint.core.api.editorconfig.CODE_STYLE_PROPERTY] + .properties[CODE_STYLE_PROPERTY] ?.parsed ?.safeAs() - ?: com.pinterest.ktlint.core.api.editorconfig.CODE_STYLE_PROPERTY.defaultValue + ?: CODE_STYLE_PROPERTY.defaultValue val rules = ruleProviders .map { RuleRunner(it) } diff --git a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/api/UsesEditorConfigProperties.kt b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/api/UsesEditorConfigProperties.kt index ecb4bcbfdc..e2e9aaa970 100644 --- a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/api/UsesEditorConfigProperties.kt +++ b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/api/UsesEditorConfigProperties.kt @@ -180,6 +180,7 @@ public object DefaultEditorConfigProperties : UsesEditorConfigProperties { // ReplaceWith is not specified as the property should not be migrated to KTLINT_DISABLED_RULES_PROPERTY but to // the RuleExecution property. ) + @Suppress("ktlint:experimental:property-naming") public val disabledRulesProperty: EditorConfigProperty = DISABLED_RULES_PROPERTY diff --git a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/api/editorconfig/CodeStyleEditorConfigProperty.kt b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/api/editorconfig/CodeStyleEditorConfigProperty.kt index 5cbfcce155..4563078203 100644 --- a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/api/editorconfig/CodeStyleEditorConfigProperty.kt +++ b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/api/editorconfig/CodeStyleEditorConfigProperty.kt @@ -17,7 +17,7 @@ public val CODE_STYLE_PROPERTY: EditorConfigProperty = type = PropertyType.LowerCasingPropertyType( "ktlint_code_style", "The code style ('official' or 'android') to be applied. Defaults to 'official' when not set.", - EnumValueParser(CodeStyleValue::class.java), + SafeEnumValueParser(CodeStyleValue::class.java), CodeStyleValue.values().map { it.name }.toSet(), ), defaultValue = CodeStyleValue.official, diff --git a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/api/editorconfig/RuleExecutionEditorConfigProperty.kt b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/api/editorconfig/RuleExecutionEditorConfigProperty.kt index eb723fef25..2c89025fb2 100644 --- a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/api/editorconfig/RuleExecutionEditorConfigProperty.kt +++ b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/api/editorconfig/RuleExecutionEditorConfigProperty.kt @@ -14,7 +14,7 @@ internal val RULE_EXECUTION_PROPERTY_TYPE = PropertyType.LowerCasingPropertyType( "ktlint_rule_execution", "When enabled, the rule is being executed.", - PropertyType.PropertyValueParser.EnumValueParser(RuleExecution::class.java), + SafeEnumValueParser(RuleExecution::class.java), CodeStyleValue.values().map { it.name }.toSet(), ) diff --git a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/api/editorconfig/SafeEnumValueParser.kt b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/api/editorconfig/SafeEnumValueParser.kt new file mode 100644 index 0000000000..92af2f4e60 --- /dev/null +++ b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/api/editorconfig/SafeEnumValueParser.kt @@ -0,0 +1,49 @@ +package com.pinterest.ktlint.core.api.editorconfig + +import java.util.Locale +import org.ec4j.core.model.PropertyType +import org.ec4j.core.model.PropertyType.PropertyValueParser + +/** + * A [PropertyValueParser] implementation that allows only members of a given [Enum] type. This class is almost + * identical to the original [EnumValueParser] provided by ec4j. Difference is that values are trimmed before trying to + * match the enum values. + * + * As the ec4j project has not provided any new release since version 1.0 (2019-08-01) a custom implementation has been + * added. + * + * @param the type of the value + * + */ +internal class SafeEnumValueParser?>(enumType: Class) : PropertyValueParser { + private val enumType: Class?> + + init { + this.enumType = enumType + } + + override fun parse(name: String?, value: String?): PropertyType.PropertyValue = + if (value == null) { + PropertyType.PropertyValue.invalid(value, "Cannot make enum " + enumType.name + " out of null") + } else { + try { + PropertyType.PropertyValue.valid( + value, + java.lang.Enum.valueOf( + enumType, + value + // In case an EOL comment (separated with a space) is appended after the value then the comment + // itself is removed but not the space. This results in the enum value not being parsed + // correctly. + .trim() + .lowercase(Locale.getDefault()), + ) as T, + ) + } catch (e: IllegalArgumentException) { + PropertyType.PropertyValue.invalid( + value, + "Unexpected parsed \"" + value + "\" for enum " + enumType.name, + ) + } + } +} diff --git a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/EditorConfigGenerator.kt b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/EditorConfigGenerator.kt index b66fa93b58..f9e83ed8bf 100644 --- a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/EditorConfigGenerator.kt +++ b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/EditorConfigGenerator.kt @@ -4,6 +4,7 @@ import com.pinterest.ktlint.core.Rule import com.pinterest.ktlint.core.api.DefaultEditorConfigProperties.writeEditorConfigProperty import com.pinterest.ktlint.core.api.EditorConfigOverride import com.pinterest.ktlint.core.api.UsesEditorConfigProperties +import com.pinterest.ktlint.core.api.editorconfig.CODE_STYLE_PROPERTY import com.pinterest.ktlint.core.api.editorconfig.CodeStyleValue import com.pinterest.ktlint.core.api.editorconfig.DEFAULT_EDITOR_CONFIG_PROPERTIES import com.pinterest.ktlint.core.initKtLintKLogger @@ -41,7 +42,7 @@ internal class EditorConfigGenerator( .load( filePath = filePath, rules = rules, - editorConfigOverride = EditorConfigOverride.from(com.pinterest.ktlint.core.api.editorconfig.CODE_STYLE_PROPERTY to codeStyle.name), + editorConfigOverride = EditorConfigOverride.from(CODE_STYLE_PROPERTY to codeStyle.name), ) val potentialEditorConfigSettings = diff --git a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/EditorConfigLoader.kt b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/EditorConfigLoader.kt index fc4129c4b4..4de0ea59ed 100644 --- a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/EditorConfigLoader.kt +++ b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/EditorConfigLoader.kt @@ -8,6 +8,7 @@ import com.pinterest.ktlint.core.api.EditorConfigOverride.Companion.EMPTY_EDITOR import com.pinterest.ktlint.core.api.EditorConfigProperties import com.pinterest.ktlint.core.api.UsesEditorConfigProperties import com.pinterest.ktlint.core.api.editorconfig.EditorConfigProperty +import com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY import com.pinterest.ktlint.core.initKtLintKLogger import com.pinterest.ktlint.core.internal.ThreadSafeEditorConfigCache.Companion.THREAD_SAFE_EDITOR_CONFIG_CACHE import java.nio.charset.StandardCharsets @@ -58,8 +59,8 @@ public class EditorConfigLoader( .queryProperties(normalizedFilePath.resource()) .properties .also { loaded -> - if (loaded[TAB_WIDTH_PROPERTY_NAME]?.sourceValue == loaded[com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY.name]?.sourceValue && - editorConfigOverride.properties[com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY] != null + if (loaded[TAB_WIDTH_PROPERTY_NAME]?.sourceValue == loaded[INDENT_SIZE_PROPERTY.name]?.sourceValue && + editorConfigOverride.properties[INDENT_SIZE_PROPERTY] != null ) { // The tab_width property can not be overridden via the editorConfigOverride. So if it has been // set to the same value as the indent_size property then keep its value in sync with that @@ -68,7 +69,7 @@ public class EditorConfigLoader( .builder() .name(TAB_WIDTH_PROPERTY_NAME) .type(PropertyType.tab_width) - .value(editorConfigOverride.properties[com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY]?.source) + .value(editorConfigOverride.properties[INDENT_SIZE_PROPERTY]?.source) .build() } editorConfigOverride diff --git a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/VisitorProvider.kt b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/VisitorProvider.kt index 84423e0354..b0fa2a8be8 100644 --- a/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/VisitorProvider.kt +++ b/ktlint-core/src/main/kotlin/com/pinterest/ktlint/core/internal/VisitorProvider.kt @@ -3,7 +3,9 @@ package com.pinterest.ktlint.core.internal import com.pinterest.ktlint.core.Rule import com.pinterest.ktlint.core.api.EditorConfigProperties import com.pinterest.ktlint.core.api.UsesEditorConfigProperties +import com.pinterest.ktlint.core.api.editorconfig.DISABLED_RULES_PROPERTY import com.pinterest.ktlint.core.api.editorconfig.EditorConfigProperty +import com.pinterest.ktlint.core.api.editorconfig.KTLINT_DISABLED_RULES_PROPERTY import com.pinterest.ktlint.core.api.editorconfig.RULE_EXECUTION_PROPERTY_TYPE import com.pinterest.ktlint.core.api.editorconfig.RuleExecution import com.pinterest.ktlint.core.api.editorconfig.createRuleExecutionEditorConfigProperty @@ -29,8 +31,8 @@ internal class VisitorProvider( recreateRuleSorter: Boolean = false, ) : UsesEditorConfigProperties { override val editorConfigProperties: List> = listOf( - com.pinterest.ktlint.core.api.editorconfig.KTLINT_DISABLED_RULES_PROPERTY, - com.pinterest.ktlint.core.api.editorconfig.DISABLED_RULES_PROPERTY, + KTLINT_DISABLED_RULES_PROPERTY, + DISABLED_RULES_PROPERTY, ).plus( ruleRunners.map { createRuleExecutionEditorConfigProperty(toQualifiedRuleId(it.ruleSetId, it.ruleId)) @@ -99,15 +101,15 @@ internal class VisitorProvider( editorConfigProperties.containsKey(ktLintRuleSetExecutionPropertyName(qualifiedRuleId)) -> editorConfigProperties.isRuleEnabled(qualifiedRuleId) - editorConfigProperties.containsKey(com.pinterest.ktlint.core.api.editorconfig.KTLINT_DISABLED_RULES_PROPERTY.name) -> + editorConfigProperties.containsKey(KTLINT_DISABLED_RULES_PROPERTY.name) -> editorConfigProperties.isEnabled( - com.pinterest.ktlint.core.api.editorconfig.KTLINT_DISABLED_RULES_PROPERTY, + KTLINT_DISABLED_RULES_PROPERTY, qualifiedRuleId, ) - editorConfigProperties.containsKey(com.pinterest.ktlint.core.api.editorconfig.DISABLED_RULES_PROPERTY.name) -> + editorConfigProperties.containsKey(DISABLED_RULES_PROPERTY.name) -> editorConfigProperties.isEnabled( - com.pinterest.ktlint.core.api.editorconfig.DISABLED_RULES_PROPERTY, + DISABLED_RULES_PROPERTY, qualifiedRuleId, ) diff --git a/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/DisabledRulesTest.kt b/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/DisabledRulesTest.kt index f1f4864bc8..a0a5d7b248 100644 --- a/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/DisabledRulesTest.kt +++ b/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/DisabledRulesTest.kt @@ -1,6 +1,8 @@ package com.pinterest.ktlint.core import com.pinterest.ktlint.core.api.EditorConfigOverride +import com.pinterest.ktlint.core.api.editorconfig.DISABLED_RULES_PROPERTY +import com.pinterest.ktlint.core.api.editorconfig.KTLINT_DISABLED_RULES_PROPERTY import com.pinterest.ktlint.core.api.editorconfig.RuleExecution import com.pinterest.ktlint.core.api.editorconfig.createRuleExecutionEditorConfigProperty import com.pinterest.ktlint.core.ast.ElementType @@ -50,7 +52,7 @@ class DisabledRulesTest { ruleProviders = setOf( RuleProvider { NoVarRule(ruleId) }, ), - editorConfigOverride = EditorConfigOverride.from(com.pinterest.ktlint.core.api.editorconfig.DISABLED_RULES_PROPERTY to disabledRuleId), + editorConfigOverride = EditorConfigOverride.from(DISABLED_RULES_PROPERTY to disabledRuleId), ).lint("var foo") { e -> add(e) } }, ).isEmpty() @@ -78,7 +80,7 @@ class DisabledRulesTest { ruleProviders = setOf( RuleProvider { NoVarRule(ruleId) }, ), - editorConfigOverride = EditorConfigOverride.from(com.pinterest.ktlint.core.api.editorconfig.KTLINT_DISABLED_RULES_PROPERTY to disabledRuleId), + editorConfigOverride = EditorConfigOverride.from(KTLINT_DISABLED_RULES_PROPERTY to disabledRuleId), ).lint("var foo") { e -> add(e) } }, ).isEmpty() diff --git a/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/VisitorProviderTest.kt b/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/VisitorProviderTest.kt index 8f60356285..83cbe3cc5a 100644 --- a/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/VisitorProviderTest.kt +++ b/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/VisitorProviderTest.kt @@ -1,5 +1,7 @@ package com.pinterest.ktlint.core +import com.pinterest.ktlint.core.api.editorconfig.DISABLED_RULES_PROPERTY +import com.pinterest.ktlint.core.api.editorconfig.KTLINT_DISABLED_RULES_PROPERTY import com.pinterest.ktlint.core.api.editorconfig.RULE_EXECUTION_PROPERTY_TYPE import com.pinterest.ktlint.core.api.editorconfig.RuleExecution import com.pinterest.ktlint.core.internal.RuleRunner @@ -103,7 +105,7 @@ class VisitorProviderTest { } private fun ktlintDisabledRulesEditorConfigProperties(vararg ruleIds: String) = - with(com.pinterest.ktlint.core.api.editorconfig.DISABLED_RULES_PROPERTY) { + with(DISABLED_RULES_PROPERTY) { mapOf( name to Property.builder() @@ -207,7 +209,7 @@ class VisitorProviderTest { } private fun ktlintDisabledRulesEditorConfigProperties(vararg ruleIds: String) = - with(com.pinterest.ktlint.core.api.editorconfig.KTLINT_DISABLED_RULES_PROPERTY) { + with(KTLINT_DISABLED_RULES_PROPERTY) { mapOf( name to Property.builder() diff --git a/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/api/editorconfig/CodeStyleEditorConfigPropertyTest.kt b/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/api/editorconfig/CodeStyleEditorConfigPropertyTest.kt new file mode 100644 index 0000000000..0cd7090a2a --- /dev/null +++ b/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/api/editorconfig/CodeStyleEditorConfigPropertyTest.kt @@ -0,0 +1,30 @@ +package com.pinterest.ktlint.core.api.editorconfig + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.CsvSource + +class CodeStyleEditorConfigPropertyTest { + @ParameterizedTest(name = "Value: [{0}], result: [{1}]") + @CsvSource( + value = [ + "official,official", + " official,official", + "official ,official", + " official ,official", + "android,android", + " android,android", + "android ,android", + " android ,android", + ], + ignoreLeadingAndTrailingWhitespace = false, + ) + fun `Given a code style property`( + value: String, + expectedCodeStyleValue: CodeStyleValue, + ) { + val actual = CODE_STYLE_PROPERTY.type.parse(value) + + assertThat(actual.parsed).isEqualTo(expectedCodeStyleValue) + } +} diff --git a/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/api/editorconfig/RuleExecutionEditorConfigPropertyTest.kt b/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/api/editorconfig/RuleExecutionEditorConfigPropertyTest.kt new file mode 100644 index 0000000000..528d9bc821 --- /dev/null +++ b/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/api/editorconfig/RuleExecutionEditorConfigPropertyTest.kt @@ -0,0 +1,30 @@ +package com.pinterest.ktlint.core.api.editorconfig + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.CsvSource + +class RuleExecutionEditorConfigPropertyTest { + @ParameterizedTest(name = "Value: [{0}], result: [{1}]") + @CsvSource( + value = [ + "enabled,enabled", + " enabled,enabled", + "enabled ,enabled", + " enabled ,enabled", + "disabled,disabled", + " disabled,disabled", + "disabled ,disabled", + " disabled ,disabled", + ], + ignoreLeadingAndTrailingWhitespace = false, + ) + fun `Given a rule execution property for which the value`( + value: String, + expectedRuleExecution: RuleExecution, + ) { + val actual = RULE_EXECUTION_PROPERTY_TYPE.parse(value) + + assertThat(actual.parsed).isEqualTo(expectedRuleExecution) + } +} diff --git a/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/api/editorconfig/SafeEnumValueParserTest.kt b/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/api/editorconfig/SafeEnumValueParserTest.kt new file mode 100644 index 0000000000..15ed04e5fa --- /dev/null +++ b/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/api/editorconfig/SafeEnumValueParserTest.kt @@ -0,0 +1,28 @@ +package com.pinterest.ktlint.core.api.editorconfig + +import org.assertj.core.api.Assertions.assertThat +import org.ec4j.core.model.PropertyType +import org.junit.jupiter.api.Test + +class SafeEnumValueParserTest { + @Test + fun `Given a rule execution property for which the value`() { + val propertyType = + PropertyType.LowerCasingPropertyType( + "some-property-type", + null, + SafeEnumValueParser(SomePropertyType::class.java), + SomePropertyType.values().map { it.name }.toSet(), + ) + + val actual = propertyType.parse(" value2 ") + + assertThat(actual.parsed).isEqualTo(SomePropertyType.value2) + } + + @Suppress("EnumEntryName") + private enum class SomePropertyType { + value1, + value2, + } +} diff --git a/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/internal/EditorConfigGeneratorTest.kt b/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/internal/EditorConfigGeneratorTest.kt index 0d10de5b17..9ad47776f7 100644 --- a/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/internal/EditorConfigGeneratorTest.kt +++ b/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/internal/EditorConfigGeneratorTest.kt @@ -5,7 +5,9 @@ import com.google.common.jimfs.Jimfs import com.pinterest.ktlint.core.Rule import com.pinterest.ktlint.core.api.UsesEditorConfigProperties import com.pinterest.ktlint.core.api.editorconfig.CodeStyleValue +import com.pinterest.ktlint.core.api.editorconfig.DISABLED_RULES_PROPERTY import com.pinterest.ktlint.core.api.editorconfig.EditorConfigProperty +import com.pinterest.ktlint.core.api.editorconfig.KTLINT_DISABLED_RULES_PROPERTY import java.nio.file.FileSystem import java.nio.file.Files import java.nio.file.Path @@ -37,8 +39,8 @@ internal class EditorConfigGeneratorTest { "ktlint_code_style = official", "max_line_length = -1", ).doesNotContain( - "${com.pinterest.ktlint.core.api.editorconfig.DISABLED_RULES_PROPERTY.name} = ", - "${com.pinterest.ktlint.core.api.editorconfig.KTLINT_DISABLED_RULES_PROPERTY.name} = ", + "${DISABLED_RULES_PROPERTY.name} = ", + "${KTLINT_DISABLED_RULES_PROPERTY.name} = ", ) } diff --git a/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/internal/EditorConfigLoaderTest.kt b/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/internal/EditorConfigLoaderTest.kt index 305e9d9ffe..5825aefa20 100644 --- a/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/internal/EditorConfigLoaderTest.kt +++ b/ktlint-core/src/test/kotlin/com/pinterest/ktlint/core/internal/EditorConfigLoaderTest.kt @@ -7,6 +7,8 @@ import com.pinterest.ktlint.core.api.EditorConfigOverride import com.pinterest.ktlint.core.api.EditorConfigProperties import com.pinterest.ktlint.core.api.UsesEditorConfigProperties import com.pinterest.ktlint.core.api.editorconfig.EditorConfigProperty +import com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY +import com.pinterest.ktlint.core.api.editorconfig.INSERT_FINAL_NEWLINE_PROPERTY import com.pinterest.ktlint.ruleset.standard.FinalNewlineRule import java.nio.file.FileSystem import java.nio.file.Files @@ -210,7 +212,7 @@ internal class EditorConfigLoaderTest { val parsedEditorConfig = editorConfigLoader.load( filePath = null, rules = rules, - editorConfigOverride = EditorConfigOverride.from(com.pinterest.ktlint.core.api.editorconfig.INSERT_FINAL_NEWLINE_PROPERTY to "true"), + editorConfigOverride = EditorConfigOverride.from(INSERT_FINAL_NEWLINE_PROPERTY to "true"), ) assertThat(parsedEditorConfig.convertToPropertyValues()).containsExactlyInAnyOrder( @@ -223,7 +225,7 @@ internal class EditorConfigLoaderTest { val parsedEditorConfig = editorConfigLoader.load( filePath = null, rules = rules, - editorConfigOverride = EditorConfigOverride.from(com.pinterest.ktlint.core.api.editorconfig.INSERT_FINAL_NEWLINE_PROPERTY to "true"), + editorConfigOverride = EditorConfigOverride.from(INSERT_FINAL_NEWLINE_PROPERTY to "true"), ) assertThat(parsedEditorConfig.convertToPropertyValues()).containsExactlyInAnyOrder( @@ -247,7 +249,7 @@ internal class EditorConfigLoaderTest { val editorConfigProperties = editorConfigLoader.load( filePath = null, rules = rules, - editorConfigOverride = EditorConfigOverride.from(com.pinterest.ktlint.core.api.editorconfig.INSERT_FINAL_NEWLINE_PROPERTY to true), + editorConfigOverride = EditorConfigOverride.from(INSERT_FINAL_NEWLINE_PROPERTY to true), ) assertThat(editorConfigProperties.convertToPropertyValues()) @@ -294,7 +296,7 @@ internal class EditorConfigLoaderTest { .load( filePath = lintFile, rules = rules, - editorConfigOverride = EditorConfigOverride.from(com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY to 2), + editorConfigOverride = EditorConfigOverride.from(INDENT_SIZE_PROPERTY to 2), ) assertThat(editorConfigProperties.convertToPropertyValues()) @@ -321,7 +323,7 @@ internal class EditorConfigLoaderTest { val editorConfigProperties = editorConfigLoader.load( filePath = null, rules = rules, - editorConfigOverride = EditorConfigOverride.from(com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY to 2), + editorConfigOverride = EditorConfigOverride.from(INDENT_SIZE_PROPERTY to 2), ) assertThat(editorConfigProperties.convertToPropertyValues()).containsExactlyInAnyOrder( @@ -383,7 +385,7 @@ internal class EditorConfigLoaderTest { val editorConfigProperties = editorConfigLoader.load( lintFile, rules = rules.plus(FinalNewlineRule()), - editorConfigOverride = EditorConfigOverride.from(com.pinterest.ktlint.core.api.editorconfig.INSERT_FINAL_NEWLINE_PROPERTY to "true"), + editorConfigOverride = EditorConfigOverride.from(INSERT_FINAL_NEWLINE_PROPERTY to "true"), ) assertThat(editorConfigProperties.convertToPropertyValues()).containsExactlyInAnyOrder( @@ -412,7 +414,7 @@ internal class EditorConfigLoaderTest { val editorConfigProperties = editorConfigLoader.load( lintFile, rules = rules.plus(FinalNewlineRule()), - editorConfigOverride = EditorConfigOverride.from(com.pinterest.ktlint.core.api.editorconfig.INSERT_FINAL_NEWLINE_PROPERTY to "false"), + editorConfigOverride = EditorConfigOverride.from(INSERT_FINAL_NEWLINE_PROPERTY to "false"), ) assertThat(editorConfigProperties.convertToPropertyValues()).containsExactlyInAnyOrder( diff --git a/ktlint-reporter-plain-summary/src/main/kotlin/com/pinterest/ktlint/reporter/plain/PlainSummaryReporter.kt b/ktlint-reporter-plain-summary/src/main/kotlin/com/pinterest/ktlint/reporter/plain/PlainSummaryReporter.kt index 26aa54db3f..5e45116eb0 100644 --- a/ktlint-reporter-plain-summary/src/main/kotlin/com/pinterest/ktlint/reporter/plain/PlainSummaryReporter.kt +++ b/ktlint-reporter-plain-summary/src/main/kotlin/com/pinterest/ktlint/reporter/plain/PlainSummaryReporter.kt @@ -22,7 +22,7 @@ public class PlainSummaryReporter( } } else { ruleViolationCountNoAutocorrection - .merge(err.ruleId, 1) { previousValue, _ -> + .merge(err.causedBy(), 1) { previousValue, _ -> previousValue + 1 } } @@ -47,6 +47,13 @@ public class PlainSummaryReporter( .map { out.println(" ${it.first}: ${it.second}") } } + private fun LintError.causedBy() = + when { + ruleId.isNotEmpty() -> ruleId + detail.startsWith(NOT_A_VALID_KOTLIN_FILE) -> NOT_A_VALID_KOTLIN_FILE + else -> "Unknown" + } + private companion object { val COUNT_DESC_AND_RULE_ID_ASC_COMPARATOR = kotlin @@ -56,5 +63,7 @@ public class PlainSummaryReporter( .thenComparator { left, right -> compareValuesBy(left, right) { it.first } } + + const val NOT_A_VALID_KOTLIN_FILE = "Not a valid Kotlin file" } } diff --git a/ktlint-reporter-plain-summary/src/test/kotlin/com/pinterest/ktlint/reporter/plain/PlainSummaryReporterTest.kt b/ktlint-reporter-plain-summary/src/test/kotlin/com/pinterest/ktlint/reporter/plain/PlainSummaryReporterTest.kt index 3a10b2c95d..36172ed170 100644 --- a/ktlint-reporter-plain-summary/src/test/kotlin/com/pinterest/ktlint/reporter/plain/PlainSummaryReporterTest.kt +++ b/ktlint-reporter-plain-summary/src/test/kotlin/com/pinterest/ktlint/reporter/plain/PlainSummaryReporterTest.kt @@ -86,4 +86,50 @@ class PlainSummaryReporterTest { """.trimIndent().replace("\n", System.lineSeparator()), ) } + + @Test + fun `Report other violations`() { + val out = ByteArrayOutputStream() + val reporter = PlainSummaryReporter(PrintStream(out, true)) + reporter.onLintError( + "file-1.kt", + LintError( + 18, + 51, + "", + "Not a valid Kotlin file (18:51 unexpected tokens (use ';' to separate expressions on the same line)) (cannot be auto-corrected) ()", + ), + false, + ) + reporter.onLintError( + "file-2.kt", + LintError( + 18, + 51, + "", + "Not a valid Kotlin file (18:51 unexpected tokens (use ';' to separate expressions on the same line)) (cannot be auto-corrected) ()", + ), + false, + ) + reporter.onLintError( + "file-3.kt", + LintError( + 18, + 51, + "", + "Something else", + ), + false, + ) + reporter.afterAll() + + assertThat(String(out.toByteArray())).isEqualTo( + """ + |Count (descending) of errors not autocorrected by rule: + | Not a valid Kotlin file: 2 + | Unknown: 1 + | + """.trimMargin().replace("\n", System.lineSeparator()), + ) + } } diff --git a/ktlint-reporter-plain/src/main/kotlin/com/pinterest/ktlint/reporter/plain/PlainReporter.kt b/ktlint-reporter-plain/src/main/kotlin/com/pinterest/ktlint/reporter/plain/PlainReporter.kt index 2c71a37e73..5ca76606f5 100644 --- a/ktlint-reporter-plain/src/main/kotlin/com/pinterest/ktlint/reporter/plain/PlainReporter.kt +++ b/ktlint-reporter-plain/src/main/kotlin/com/pinterest/ktlint/reporter/plain/PlainReporter.kt @@ -36,7 +36,7 @@ public class PlainReporter( ) } ruleViolationCount - .merge(err.ruleId, 1) { previousValue, _ -> + .merge(err.causedBy(), 1) { previousValue, _ -> previousValue + 1 } } @@ -85,6 +85,13 @@ public class PlainReporter( this } + private fun LintError.causedBy() = + when { + ruleId.isNotEmpty() -> ruleId + detail.startsWith(NOT_A_VALID_KOTLIN_FILE) -> NOT_A_VALID_KOTLIN_FILE + else -> "Unknown" + } + private companion object { val COUNT_DESC_AND_RULE_ID_ASC_COMPARATOR = kotlin @@ -94,6 +101,8 @@ public class PlainReporter( .thenComparator { left, right -> compareValuesBy(left, right) { it.first } } + + const val NOT_A_VALID_KOTLIN_FILE = "Not a valid Kotlin file" } } diff --git a/ktlint-reporter-plain/src/test/kotlin/com/pinterest/ktlint/reporter/plain/PlainReporterTest.kt b/ktlint-reporter-plain/src/test/kotlin/com/pinterest/ktlint/reporter/plain/PlainReporterTest.kt index 866e5aa0aa..afa2edb45a 100644 --- a/ktlint-reporter-plain/src/test/kotlin/com/pinterest/ktlint/reporter/plain/PlainReporterTest.kt +++ b/ktlint-reporter-plain/src/test/kotlin/com/pinterest/ktlint/reporter/plain/PlainReporterTest.kt @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Test class PlainReporterTest { @Test - fun testReportGeneration() { + fun `Report normal rule violations`() { val out = ByteArrayOutputStream() val reporter = PlainReporter(PrintStream(out, true)) reporter.onLintError( @@ -81,6 +81,56 @@ class PlainReporterTest { ) } + @Test + fun `Report other violations`() { + val out = ByteArrayOutputStream() + val reporter = PlainReporter(PrintStream(out, true)) + reporter.onLintError( + "file-1.kt", + LintError( + 18, + 51, + "", + "Not a valid Kotlin file (18:51 unexpected tokens (use ';' to separate expressions on the same line)) (cannot be auto-corrected) ()", + ), + false, + ) + reporter.onLintError( + "file-2.kt", + LintError( + 18, + 51, + "", + "Not a valid Kotlin file (18:51 unexpected tokens (use ';' to separate expressions on the same line)) (cannot be auto-corrected) ()", + ), + false, + ) + reporter.onLintError( + "file-3.kt", + LintError( + 18, + 51, + "", + "Something else", + ), + false, + ) + reporter.afterAll() + + assertThat(String(out.toByteArray())).isEqualTo( + """ + |file-1.kt:18:51: Not a valid Kotlin file (18:51 unexpected tokens (use ';' to separate expressions on the same line)) (cannot be auto-corrected) () () + |file-2.kt:18:51: Not a valid Kotlin file (18:51 unexpected tokens (use ';' to separate expressions on the same line)) (cannot be auto-corrected) () () + |file-3.kt:18:51: Something else () + | + |Summary error count (descending) by rule: + | Not a valid Kotlin file: 2 + | Unknown: 1 + | + """.trimMargin().replace("\n", System.lineSeparator()), + ) + } + @Test fun testColoredOutput() { val out = ByteArrayOutputStream() diff --git a/ktlint-ruleset-experimental/src/main/kotlin/com/pinterest/ktlint/ruleset/experimental/FunctionSignatureRule.kt b/ktlint-ruleset-experimental/src/main/kotlin/com/pinterest/ktlint/ruleset/experimental/FunctionSignatureRule.kt index 7bb934bf47..d6e2d3ddfe 100644 --- a/ktlint-ruleset-experimental/src/main/kotlin/com/pinterest/ktlint/ruleset/experimental/FunctionSignatureRule.kt +++ b/ktlint-ruleset-experimental/src/main/kotlin/com/pinterest/ktlint/ruleset/experimental/FunctionSignatureRule.kt @@ -5,6 +5,9 @@ import com.pinterest.ktlint.core.Rule import com.pinterest.ktlint.core.api.EditorConfigProperties import com.pinterest.ktlint.core.api.UsesEditorConfigProperties import com.pinterest.ktlint.core.api.editorconfig.EditorConfigProperty +import com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY +import com.pinterest.ktlint.core.api.editorconfig.INDENT_STYLE_PROPERTY +import com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY import com.pinterest.ktlint.core.ast.ElementType.ANNOTATION import com.pinterest.ktlint.core.ast.ElementType.ANNOTATION_ENTRY import com.pinterest.ktlint.core.ast.ElementType.BLOCK @@ -53,9 +56,9 @@ public class FunctionSignatureRule : UsesEditorConfigProperties { override val editorConfigProperties: List> = listOf( - com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY, - com.pinterest.ktlint.core.api.editorconfig.INDENT_STYLE_PROPERTY, - com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY, + INDENT_SIZE_PROPERTY, + INDENT_STYLE_PROPERTY, + MAX_LINE_LENGTH_PROPERTY, FORCE_MULTILINE_WHEN_PARAMETER_COUNT_GREATER_OR_EQUAL_THAN_PROPERTY, FUNCTION_BODY_EXPRESSION_WRAPPING_PROPERTY, ) @@ -70,11 +73,11 @@ public class FunctionSignatureRule : functionSignatureWrappingMinimumParameters = getEditorConfigValue(FORCE_MULTILINE_WHEN_PARAMETER_COUNT_GREATER_OR_EQUAL_THAN_PROPERTY) functionBodyExpressionWrapping = getEditorConfigValue(FUNCTION_BODY_EXPRESSION_WRAPPING_PROPERTY) val indentConfig = IndentConfig( - indentStyle = getEditorConfigValue(com.pinterest.ktlint.core.api.editorconfig.INDENT_STYLE_PROPERTY), - tabWidth = getEditorConfigValue(com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY), + indentStyle = getEditorConfigValue(INDENT_STYLE_PROPERTY), + tabWidth = getEditorConfigValue(INDENT_SIZE_PROPERTY), ) indent = indentConfig.indent - maxLineLength = getEditorConfigValue(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY) + maxLineLength = getEditorConfigValue(MAX_LINE_LENGTH_PROPERTY) } } diff --git a/ktlint-ruleset-experimental/src/test/kotlin/com/pinterest/ktlint/ruleset/experimental/SpacingAroundUnaryOperatorRuleTest.kt b/ktlint-ruleset-experimental/src/test/kotlin/com/pinterest/ktlint/ruleset/experimental/SpacingAroundUnaryOperatorRuleTest.kt index ec06797f0e..7ca11575bc 100644 --- a/ktlint-ruleset-experimental/src/test/kotlin/com/pinterest/ktlint/ruleset/experimental/SpacingAroundUnaryOperatorRuleTest.kt +++ b/ktlint-ruleset-experimental/src/test/kotlin/com/pinterest/ktlint/ruleset/experimental/SpacingAroundUnaryOperatorRuleTest.kt @@ -1,5 +1,6 @@ package com.pinterest.ktlint.ruleset.experimental +import com.pinterest.ktlint.ruleset.standard.SpacingAroundDotRule import com.pinterest.ktlint.ruleset.standard.SpacingAroundUnaryOperatorRule import com.pinterest.ktlint.test.KtLintAssertThat.Companion.assertThatRule import com.pinterest.ktlint.test.LintViolation @@ -143,15 +144,15 @@ class SpacingAroundUnaryOperatorRuleTest { """ val foo1 = "foo"!!.length val foo2 = "foo"!!.length - val foo3 = "foo"!! .length + val foo3 = "foo"!!.length val foo4 = "foo"!! .length """.trimIndent() spacingAroundUnaryOperatorRuleAssertThat(code) - .hasLintViolations( - LintViolation(2, 17, "Unexpected spacing in \"foo\" !!"), - // TODO: "foo3" should also be disallowed - ).isFormattedAs(formattedCode) + .addAdditionalRuleProvider { SpacingAroundDotRule() } + .hasLintViolation(2, 17, "Unexpected spacing in \"foo\" !!") + .hasLintViolationForAdditionalRule(3, 19, "Unexpected spacing before \".\"") + .isFormattedAs(formattedCode) } @Test diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/AnnotationSpacingRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/AnnotationSpacingRule.kt index e055a9a70c..7c9e8d2dd4 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/AnnotationSpacingRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/AnnotationSpacingRule.kt @@ -79,46 +79,43 @@ public class AnnotationSpacingRule : Rule("annotation-spacing") { }, ) if (next != null) { - if (node.elementType != ElementType.FILE_ANNOTATION_LIST) { + if (node.elementType != ElementType.FILE_ANNOTATION_LIST && next.isPartOfComment()) { val psi = node.psi - emit(psi.endOffset - 1, ERROR_MESSAGE, true) + emit(psi.endOffset, ERROR_MESSAGE, true) if (autoCorrect) { // Special-case autocorrection when the annotation is separated from the annotated construct // by a comment: we need to swap the order of the comment and the annotation - if (next.isPartOfComment()) { - // Remove the annotation and the following whitespace - val eolComment = node.nextSibling { it.isCommentOnSameLineAsPrevLeaf() } - if (eolComment != null) { - eolComment.prevSibling { it.isWhiteSpace() }?.let { it.treeParent.removeChild(it) } - eolComment.nextSibling { it.isWhiteSpace() }?.let { it.treeParent.removeChild(it) } - eolComment.treeParent?.removeChild(eolComment) - } else { - node.nextSibling { it.isWhiteSpace() }?.let { it.treeParent?.removeChild(it) } - } - node.treeParent.removeChild(node) - - // Insert the annotation prior to the annotated construct - val beforeAnchor = next.nextCodeSibling() - val treeParent = next.treeParent - treeParent.addChild(node, beforeAnchor) - if (eolComment != null) { - treeParent.addChild(PsiWhiteSpaceImpl(" "), beforeAnchor) - treeParent.addChild(eolComment, beforeAnchor) - } - treeParent.addChild(PsiWhiteSpaceImpl("\n"), beforeAnchor) + // Remove the annotation and the following whitespace + val eolComment = node.nextSibling { it.isCommentOnSameLineAsPrevLeaf() } + if (eolComment != null) { + eolComment.prevSibling { it.isWhiteSpace() }?.let { it.treeParent.removeChild(it) } + eolComment.nextSibling { it.isWhiteSpace() }?.let { it.treeParent.removeChild(it) } + eolComment.treeParent?.removeChild(eolComment) } else { - removeExtraLineBreaks(node) + node.nextSibling { it.isWhiteSpace() }?.let { it.treeParent?.removeChild(it) } + } + node.treeParent.removeChild(node) + + // Insert the annotation prior to the annotated construct + val beforeAnchor = next.nextCodeSibling() + val treeParent = next.treeParent + treeParent.addChild(node, beforeAnchor) + if (eolComment != null) { + treeParent.addChild(PsiWhiteSpaceImpl(" "), beforeAnchor) + treeParent.addChild(eolComment, beforeAnchor) } + treeParent.addChild(PsiWhiteSpaceImpl("\n"), beforeAnchor) } } } - if (whiteSpaces.isNotEmpty() && annotations.size > 1 && node.elementType != ElementType.FILE_ANNOTATION_LIST) { + if (whiteSpaces.isNotEmpty() && node.elementType != ElementType.FILE_ANNOTATION_LIST) { // Check to make sure there are multi breaks between annotations if (whiteSpaces.any { psi -> psi.textToCharArray().count { it == '\n' } > 1 }) { val psi = node.psi - emit(psi.endOffset - 1, ERROR_MESSAGE, true) + emit(psi.endOffset, ERROR_MESSAGE, true) if (autoCorrect) { removeIntraLineBreaks(node, annotations.last()) + removeExtraLineBreaks(node) } } } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/ArgumentListWrappingRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/ArgumentListWrappingRule.kt index 3c911a15b6..7da45b03d8 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/ArgumentListWrappingRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/ArgumentListWrappingRule.kt @@ -5,6 +5,9 @@ import com.pinterest.ktlint.core.Rule import com.pinterest.ktlint.core.api.EditorConfigProperties import com.pinterest.ktlint.core.api.UsesEditorConfigProperties import com.pinterest.ktlint.core.api.editorconfig.EditorConfigProperty +import com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY +import com.pinterest.ktlint.core.api.editorconfig.INDENT_STYLE_PROPERTY +import com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY import com.pinterest.ktlint.core.ast.ElementType import com.pinterest.ktlint.core.ast.ElementType.ELSE import com.pinterest.ktlint.core.ast.ElementType.VALUE_ARGUMENT_LIST @@ -50,9 +53,9 @@ public class ArgumentListWrappingRule : UsesEditorConfigProperties { override val editorConfigProperties: List> = listOf( - com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY, - com.pinterest.ktlint.core.api.editorconfig.INDENT_STYLE_PROPERTY, - com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY, + INDENT_SIZE_PROPERTY, + INDENT_STYLE_PROPERTY, + MAX_LINE_LENGTH_PROPERTY, ) private var editorConfigIndent = IndentConfig.DEFAULT_INDENT_CONFIG @@ -61,10 +64,10 @@ public class ArgumentListWrappingRule : override fun beforeFirstNode(editorConfigProperties: EditorConfigProperties) { editorConfigIndent = IndentConfig( - indentStyle = editorConfigProperties.getEditorConfigValue(com.pinterest.ktlint.core.api.editorconfig.INDENT_STYLE_PROPERTY), - tabWidth = editorConfigProperties.getEditorConfigValue(com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY), + indentStyle = editorConfigProperties.getEditorConfigValue(INDENT_STYLE_PROPERTY), + tabWidth = editorConfigProperties.getEditorConfigValue(INDENT_SIZE_PROPERTY), ) - maxLineLength = editorConfigProperties.getEditorConfigValue(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY) + maxLineLength = editorConfigProperties.getEditorConfigValue(MAX_LINE_LENGTH_PROPERTY) } override fun beforeVisitChildNodes( diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/FinalNewlineRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/FinalNewlineRule.kt index aaf9d7b838..55072c2b3b 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/FinalNewlineRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/FinalNewlineRule.kt @@ -4,6 +4,7 @@ import com.pinterest.ktlint.core.Rule import com.pinterest.ktlint.core.api.EditorConfigProperties import com.pinterest.ktlint.core.api.UsesEditorConfigProperties import com.pinterest.ktlint.core.api.editorconfig.EditorConfigProperty +import com.pinterest.ktlint.core.api.editorconfig.INSERT_FINAL_NEWLINE_PROPERTY import com.pinterest.ktlint.core.ast.isRoot import kotlin.properties.Delegates import org.jetbrains.kotlin.com.intellij.lang.ASTNode @@ -15,13 +16,13 @@ public class FinalNewlineRule : UsesEditorConfigProperties { override val editorConfigProperties: List> = listOf( - com.pinterest.ktlint.core.api.editorconfig.INSERT_FINAL_NEWLINE_PROPERTY, + INSERT_FINAL_NEWLINE_PROPERTY, ) private var insertFinalNewline by Delegates.notNull() override fun beforeFirstNode(editorConfigProperties: EditorConfigProperties) { - insertFinalNewline = editorConfigProperties.getEditorConfigValue(com.pinterest.ktlint.core.api.editorconfig.INSERT_FINAL_NEWLINE_PROPERTY) + insertFinalNewline = editorConfigProperties.getEditorConfigValue(INSERT_FINAL_NEWLINE_PROPERTY) } override fun beforeVisitChildNodes( diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/IndentationRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/IndentationRule.kt index e2244eec97..24db7a1c63 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/IndentationRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/IndentationRule.kt @@ -7,6 +7,8 @@ import com.pinterest.ktlint.core.Rule import com.pinterest.ktlint.core.api.EditorConfigProperties import com.pinterest.ktlint.core.api.UsesEditorConfigProperties import com.pinterest.ktlint.core.api.editorconfig.EditorConfigProperty +import com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY +import com.pinterest.ktlint.core.api.editorconfig.INDENT_STYLE_PROPERTY import com.pinterest.ktlint.core.ast.ElementType.ANNOTATED_EXPRESSION import com.pinterest.ktlint.core.ast.ElementType.ANNOTATION import com.pinterest.ktlint.core.ast.ElementType.ANNOTATION_ENTRY @@ -132,8 +134,8 @@ public class IndentationRule : UsesEditorConfigProperties { override val editorConfigProperties: List> = listOf( - com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY, - com.pinterest.ktlint.core.api.editorconfig.INDENT_STYLE_PROPERTY, + INDENT_SIZE_PROPERTY, + INDENT_STYLE_PROPERTY, ) private var indentConfig = IndentConfig.DEFAULT_INDENT_CONFIG @@ -145,8 +147,8 @@ public class IndentationRule : override fun beforeFirstNode(editorConfigProperties: EditorConfigProperties) { indentConfig = IndentConfig( - indentStyle = editorConfigProperties.getEditorConfigValue(com.pinterest.ktlint.core.api.editorconfig.INDENT_STYLE_PROPERTY), - tabWidth = editorConfigProperties.getEditorConfigValue(com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY), + indentStyle = editorConfigProperties.getEditorConfigValue(INDENT_STYLE_PROPERTY), + tabWidth = editorConfigProperties.getEditorConfigValue(INDENT_SIZE_PROPERTY), ) if (indentConfig.disabled) { stopTraversalOfAST() diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/MaxLineLengthRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/MaxLineLengthRule.kt index f48149a1e5..3220c275a2 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/MaxLineLengthRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/MaxLineLengthRule.kt @@ -4,6 +4,7 @@ import com.pinterest.ktlint.core.Rule import com.pinterest.ktlint.core.api.EditorConfigProperties import com.pinterest.ktlint.core.api.UsesEditorConfigProperties import com.pinterest.ktlint.core.api.editorconfig.EditorConfigProperty +import com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY import com.pinterest.ktlint.core.ast.ElementType import com.pinterest.ktlint.core.ast.isPartOf import com.pinterest.ktlint.core.ast.isRoot @@ -46,17 +47,17 @@ public class MaxLineLengthRule : UsesEditorConfigProperties { override val editorConfigProperties: List> = listOf( - com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY, + MAX_LINE_LENGTH_PROPERTY, IGNORE_BACKTICKED_IDENTIFIER_PROPERTY, ) - private var maxLineLength: Int = com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY.defaultValue + private var maxLineLength: Int = MAX_LINE_LENGTH_PROPERTY.defaultValue private var rangeTree = RangeTree() private var ignoreBackTickedIdentifier by Delegates.notNull() override fun beforeFirstNode(editorConfigProperties: EditorConfigProperties) { ignoreBackTickedIdentifier = editorConfigProperties.getEditorConfigValue(IGNORE_BACKTICKED_IDENTIFIER_PROPERTY) - maxLineLength = editorConfigProperties.getEditorConfigValue(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY) + maxLineLength = editorConfigProperties.getEditorConfigValue(MAX_LINE_LENGTH_PROPERTY) } override fun beforeVisitChildNodes( diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/NoConsecutiveBlankLinesRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/NoConsecutiveBlankLinesRule.kt index e26ca22dcb..65cfa086e1 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/NoConsecutiveBlankLinesRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/NoConsecutiveBlankLinesRule.kt @@ -5,12 +5,12 @@ import com.pinterest.ktlint.core.ast.ElementType.CLASS import com.pinterest.ktlint.core.ast.ElementType.IDENTIFIER import com.pinterest.ktlint.core.ast.ElementType.PRIMARY_CONSTRUCTOR import com.pinterest.ktlint.core.ast.nextLeaf +import com.pinterest.ktlint.core.ast.prevCodeLeaf import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement public class NoConsecutiveBlankLinesRule : Rule("no-consecutive-blank-lines") { - override fun beforeVisitChildNodes( node: ASTNode, autoCorrect: Boolean, @@ -20,20 +20,26 @@ public class NoConsecutiveBlankLinesRule : Rule("no-consecutive-blank-lines") { node.prevSibling != null ) { val text = node.getText() - val lfcount = text.count { it == '\n' } - if (lfcount < 2) { + val newLineCount = text.count { it == '\n' } + if (newLineCount < 2) { return } val eof = node.nextLeaf() == null - val prevNode = node.treePrev - val betweenClassAndPrimaryConstructor = prevNode.elementType == IDENTIFIER && - prevNode.treeParent.elementType == CLASS && - node.treeNext.elementType == PRIMARY_CONSTRUCTOR + val betweenClassAndPrimaryConstructor = node.isBetweenClassAndPrimaryConstructor() - if (lfcount > 2 || eof || betweenClassAndPrimaryConstructor) { + if (newLineCount > 2 || eof || betweenClassAndPrimaryConstructor) { val split = text.split("\n") - emit(node.startOffset + split[0].length + split[1].length + 2, "Needless blank line(s)", true) + val offset = + node.startOffset + + split[0].length + + split[1].length + + if (betweenClassAndPrimaryConstructor) { + 1 + } else { + 2 + } + emit(offset, "Needless blank line(s)", true) if (autoCorrect) { val newText = buildString { append(split.first()) @@ -46,4 +52,13 @@ public class NoConsecutiveBlankLinesRule : Rule("no-consecutive-blank-lines") { } } } + + private fun ASTNode.isBetweenClassAndPrimaryConstructor() = + prevCodeLeaf() + ?.let { prevNode -> + prevNode.elementType == IDENTIFIER && + prevNode.treeParent.elementType == CLASS && + this.treeNext.elementType == PRIMARY_CONSTRUCTOR + } + ?: false } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/NoLineBreakBeforeAssignmentRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/NoLineBreakBeforeAssignmentRule.kt index a45ed18c39..8d9fb92178 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/NoLineBreakBeforeAssignmentRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/NoLineBreakBeforeAssignmentRule.kt @@ -17,12 +17,13 @@ public class NoLineBreakBeforeAssignmentRule : Rule("no-line-break-before-assign override fun beforeVisitChildNodes(node: ASTNode, autoCorrect: Boolean, emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) { if (node.elementType == EQ) { val prevCodeSibling = node.prevCodeSibling() - val hasLineBreakBeforeAssignment = prevCodeSibling - ?.siblings() - ?.takeWhile { it.isWhiteSpace() || it.isPartOfComment() } - ?.any { it.isWhiteSpaceWithNewline() } - if (hasLineBreakBeforeAssignment == true) { - emit(node.startOffset, "Line break before assignment is not allowed", true) + val unexpectedLinebreak = + prevCodeSibling + ?.siblings() + ?.takeWhile { it.isWhiteSpace() || it.isPartOfComment() } + ?.lastOrNull { it.isWhiteSpaceWithNewline() } + if (unexpectedLinebreak != null) { + emit(unexpectedLinebreak.startOffset, "Line break before assignment is not allowed", true) if (autoCorrect) { val prevPsi = prevCodeSibling.psi val parentPsi = prevPsi.parent diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/NoSemicolonsRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/NoSemicolonsRule.kt index f23932b7b9..7089f3cd8b 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/NoSemicolonsRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/NoSemicolonsRule.kt @@ -1,13 +1,10 @@ package com.pinterest.ktlint.ruleset.standard import com.pinterest.ktlint.core.Rule -import com.pinterest.ktlint.core.ast.ElementType.KDOC_TEXT import com.pinterest.ktlint.core.ast.ElementType.OBJECT_KEYWORD import com.pinterest.ktlint.core.ast.ElementType.SEMICOLON -import com.pinterest.ktlint.core.ast.isPartOf -import com.pinterest.ktlint.core.ast.isPartOfComment -import com.pinterest.ktlint.core.ast.isPartOfString import com.pinterest.ktlint.core.ast.isWhiteSpace +import com.pinterest.ktlint.core.ast.nextCodeLeaf import com.pinterest.ktlint.core.ast.nextLeaf import com.pinterest.ktlint.core.ast.prevCodeLeaf import com.pinterest.ktlint.core.ast.prevLeaf @@ -18,8 +15,6 @@ import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace import org.jetbrains.kotlin.kdoc.psi.api.KDoc import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtAnnotationEntry -import org.jetbrains.kotlin.psi.KtClass -import org.jetbrains.kotlin.psi.KtClassBody import org.jetbrains.kotlin.psi.KtDoWhileExpression import org.jetbrains.kotlin.psi.KtEnumEntry import org.jetbrains.kotlin.psi.KtIfExpression @@ -27,61 +22,65 @@ import org.jetbrains.kotlin.psi.KtLoopExpression import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType public class NoSemicolonsRule : Rule("no-semi") { - override fun beforeVisitChildNodes( node: ASTNode, autoCorrect: Boolean, emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit, ) { - if (node.elementType == KDOC_TEXT) { + if (node.elementType != SEMICOLON) { return } - if (node.elementType == SEMICOLON && - !node.isPartOfString() && - !node.isPartOfEnumEntry() - ) { - val nextLeaf = node.nextLeaf() - val prevCodeLeaf = node.prevCodeLeaf() - if (doesNotRequirePreSemi(nextLeaf) && doesNotRequirePostSemi(prevCodeLeaf)) { - emit(node.startOffset, "Unnecessary semicolon", true) - if (autoCorrect) { - node.treeParent.removeChild(node) - } - } else if (nextLeaf !is PsiWhiteSpace) { - val prevLeaf = node.prevLeaf() - if (prevLeaf is PsiWhiteSpace && prevLeaf.textContains('\n')) { // \n;{ - return - } - // todo: move to a separate rule - emit(node.startOffset + 1, "Missing spacing after \";\"", true) - if (autoCorrect) { - node.upsertWhitespaceAfterMe(" ") + val nextLeaf = node.nextLeaf() + val prevCodeLeaf = node.prevCodeLeaf() + if (nextLeaf.doesNotRequirePreSemi() && prevCodeLeaf.doesNotRequirePostSemi()) { + emit(node.startOffset, "Unnecessary semicolon", true) + if (autoCorrect) { + val prevLeaf = node.prevLeaf(true) + node.treeParent.removeChild(node) + if (prevLeaf.isWhiteSpace() && (nextLeaf == null || nextLeaf.isWhiteSpace())) { + node.treeParent.removeChild(prevLeaf!!) } } + } else if (nextLeaf !is PsiWhiteSpace) { + val prevLeaf = node.prevLeaf() + if (prevLeaf is PsiWhiteSpace && prevLeaf.textContains('\n')) { // \n;{ + return + } + // todo: move to a separate rule + emit(node.startOffset + 1, "Missing spacing after \";\"", true) + if (autoCorrect) { + node.upsertWhitespaceAfterMe(" ") + } } } - private fun doesNotRequirePreSemi(nextLeaf: ASTNode?): Boolean { - if (nextLeaf is PsiWhiteSpace) { - val nextNextLeaf = nextLeaf.nextLeaf { + private fun ASTNode?.doesNotRequirePreSemi(): Boolean { + if (this == null) { + return true + } + if (this is PsiWhiteSpace) { + val nextLeaf = nextLeaf { val psi = it.psi it !is PsiWhiteSpace && it !is PsiComment && psi.getStrictParentOfType() == null && psi.getStrictParentOfType() == null } return ( - nextNextLeaf == null || // \s+ and then eof - nextLeaf.textContains('\n') && nextNextLeaf.elementType != KtTokens.LBRACE + nextLeaf == null || // \s+ and then eof + textContains('\n') && nextLeaf.elementType != KtTokens.LBRACE ) } - return nextLeaf == null // eof + return false } - private fun doesNotRequirePostSemi(prevLeaf: ASTNode?): Boolean { - if (prevLeaf?.elementType == OBJECT_KEYWORD) { + private fun ASTNode?.doesNotRequirePostSemi(): Boolean { + if (this == null) { + return true + } + if (this.elementType == OBJECT_KEYWORD) { // https://github.com/pinterest/ktlint/issues/281 return false } - val parent = prevLeaf?.treeParent?.psi + val parent = this.treeParent?.psi if (parent is KtLoopExpression && parent !is KtDoWhileExpression && parent.body == null) { // https://github.com/pinterest/ktlint/issues/955 return false @@ -89,16 +88,11 @@ public class NoSemicolonsRule : Rule("no-semi") { if (parent is KtIfExpression && parent.then == null) { return false } - return true - } + if (parent is KtEnumEntry) { + return this.nextCodeLeaf()?.nextCodeLeaf() == + parent.parent.lastChild + } - private fun ASTNode.isPartOfEnumEntry(): Boolean { - if (isPartOf(KtEnumEntry::class)) return true - val lBrace = prevLeaf { !it.isWhiteSpace() && !it.isPartOfComment() } - ?.takeIf { it.elementType == KtTokens.LBRACE } - ?: return false - val classBody = lBrace.treeParent?.psi as? KtClassBody ?: return false - if (classBody.children.isEmpty()) return false - return (classBody.parent as? KtClass)?.isEnum() == true + return true } } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/ParameterListWrappingRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/ParameterListWrappingRule.kt index b4de2ba277..99d9c9fcba 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/ParameterListWrappingRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/ParameterListWrappingRule.kt @@ -5,6 +5,9 @@ import com.pinterest.ktlint.core.Rule import com.pinterest.ktlint.core.api.EditorConfigProperties import com.pinterest.ktlint.core.api.UsesEditorConfigProperties import com.pinterest.ktlint.core.api.editorconfig.EditorConfigProperty +import com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY +import com.pinterest.ktlint.core.api.editorconfig.INDENT_STYLE_PROPERTY +import com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY import com.pinterest.ktlint.core.ast.ElementType.FUNCTION_LITERAL import com.pinterest.ktlint.core.ast.ElementType.FUNCTION_TYPE import com.pinterest.ktlint.core.ast.ElementType.LPAR @@ -34,19 +37,19 @@ public class ParameterListWrappingRule : UsesEditorConfigProperties { override val editorConfigProperties: List> = listOf( - com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY, - com.pinterest.ktlint.core.api.editorconfig.INDENT_STYLE_PROPERTY, - com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY, + INDENT_SIZE_PROPERTY, + INDENT_STYLE_PROPERTY, + MAX_LINE_LENGTH_PROPERTY, ) private var indentConfig = IndentConfig.DEFAULT_INDENT_CONFIG private var maxLineLength = -1 override fun beforeFirstNode(editorConfigProperties: EditorConfigProperties) { - maxLineLength = editorConfigProperties.getEditorConfigValue(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY) + maxLineLength = editorConfigProperties.getEditorConfigValue(MAX_LINE_LENGTH_PROPERTY) indentConfig = IndentConfig( - indentStyle = editorConfigProperties.getEditorConfigValue(com.pinterest.ktlint.core.api.editorconfig.INDENT_STYLE_PROPERTY), - tabWidth = editorConfigProperties.getEditorConfigValue(com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY), + indentStyle = editorConfigProperties.getEditorConfigValue(INDENT_STYLE_PROPERTY), + tabWidth = editorConfigProperties.getEditorConfigValue(INDENT_SIZE_PROPERTY), ) if (indentConfig.disabled) { stopTraversalOfAST() diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundAngleBracketsRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundAngleBracketsRule.kt index fd3416c529..9cbd178707 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundAngleBracketsRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundAngleBracketsRule.kt @@ -14,82 +14,84 @@ import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafElement public class SpacingAroundAngleBracketsRule : Rule("spacing-around-angle-brackets") { - private fun String.trimBeforeLastLine() = this.substring(this.lastIndexOf('\n')) - override fun beforeVisitChildNodes( node: ASTNode, autoCorrect: Boolean, emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit, ) { - if (node.elementType.let { it == TYPE_PARAMETER_LIST || it == TYPE_ARGUMENT_LIST }) { - val openingBracket = node.firstChildNode - if (openingBracket != null) { - // Check for rogue spacing before an opening bracket, e.g. Map - val beforeLeftAngle = openingBracket.prevLeaf() - if (beforeLeftAngle?.elementType == WHITE_SPACE) { - // Ignore when the whitespace is preceded by certain keywords, e.g. fun func(arg: T) {} - if (!ELEMENT_TYPES_ALLOWING_PRECEDING_WHITESPACE.contains(beforeLeftAngle.prevLeaf()?.elementType)) { - emit(beforeLeftAngle.startOffset, "Unexpected spacing before \"<\"", true) - if (autoCorrect) { - beforeLeftAngle.treeParent.removeChild(beforeLeftAngle) - } + if (node.elementType != TYPE_PARAMETER_LIST && node.elementType != TYPE_ARGUMENT_LIST) { + return + } + + val openingBracket = node.firstChildNode + if (openingBracket != null) { + // Check for rogue spacing before an opening bracket, e.g. Map + val beforeLeftAngle = openingBracket.prevLeaf() + if (beforeLeftAngle?.elementType == WHITE_SPACE) { + // Ignore when the whitespace is preceded by certain keywords, e.g. fun func(arg: T) {} + if (!ELEMENT_TYPES_ALLOWING_PRECEDING_WHITESPACE.contains(beforeLeftAngle.prevLeaf()?.elementType)) { + emit(beforeLeftAngle.startOffset, "Unexpected spacing before \"<\"", true) + if (autoCorrect) { + beforeLeftAngle.treeParent.removeChild(beforeLeftAngle) } } + } - // Check for rogue spacing after an opening bracket - val afterLeftAngle = openingBracket.nextLeaf() - if (afterLeftAngle?.elementType == WHITE_SPACE) { - if (afterLeftAngle.isWhiteSpaceWithoutNewline()) { - // when spacing does not include any new lines, e.g. Map< String, Int> - emit(afterLeftAngle.startOffset, "Unexpected spacing after \"<\"", true) - if (autoCorrect) { - afterLeftAngle.treeParent.removeChild(afterLeftAngle) - } - } else { - // when spacing contains at least one new line, e.g. - // SomeGenericType<[whitespace] - // - // String, Int, String> - // gets converted to - // SomeGenericType< - // String, Int, String> - val newLineWithIndent = afterLeftAngle.text.trimBeforeLastLine() - if (autoCorrect) { - (afterLeftAngle as LeafElement).rawReplaceWithText(newLineWithIndent) - } + // Check for rogue spacing after an opening bracket + val afterLeftAngle = openingBracket.nextLeaf() + if (afterLeftAngle?.elementType == WHITE_SPACE) { + if (afterLeftAngle.isWhiteSpaceWithoutNewline()) { + // when spacing does not include any new lines, e.g. Map< String, Int> + emit(afterLeftAngle.startOffset, "Unexpected spacing after \"<\"", true) + if (autoCorrect) { + afterLeftAngle.treeParent.removeChild(afterLeftAngle) + } + } else { + // when spacing contains at least one new line, e.g. + // SomeGenericType<[whitespace] + // + // String, Int, String> + // gets converted to + // SomeGenericType< + // String, Int, String> + val newLineWithIndent = afterLeftAngle.text.trimBeforeLastLine() + if (autoCorrect) { + (afterLeftAngle as LeafElement).rawReplaceWithText(newLineWithIndent) } } } + } - val closingBracket = node.lastChildNode - if (closingBracket != null) { - val beforeRightAngle = closingBracket.prevLeaf() - // Check for rogue spacing before a closing bracket - if (beforeRightAngle?.elementType == WHITE_SPACE) { - if (beforeRightAngle.isWhiteSpaceWithoutNewline()) { - // when spacing does not include any new lines, e.g. Map - emit(beforeRightAngle.startOffset, "Unexpected spacing before \">\"", true) - if (autoCorrect) { - beforeRightAngle.treeParent.removeChild(beforeRightAngle) - } - } else { - // when spacing contains at least one new line, e.g. - // SomeGenericType - // gets converted to - // SomeGenericType - val newLineWithIndent = beforeRightAngle.text.trimBeforeLastLine() - if (autoCorrect) { - (beforeRightAngle as LeafElement).rawReplaceWithText(newLineWithIndent) - } + val closingBracket = node.lastChildNode + if (closingBracket != null) { + val beforeRightAngle = closingBracket.prevLeaf() + // Check for rogue spacing before a closing bracket + if (beforeRightAngle?.elementType == WHITE_SPACE) { + if (beforeRightAngle.isWhiteSpaceWithoutNewline()) { + // when spacing does not include any new lines, e.g. Map + emit(beforeRightAngle.startOffset, "Unexpected spacing before \">\"", true) + if (autoCorrect) { + beforeRightAngle.treeParent.removeChild(beforeRightAngle) + } + } else { + // when spacing contains at least one new line, e.g. + // SomeGenericType + // gets converted to + // SomeGenericType + val newLineWithIndent = beforeRightAngle.text.trimBeforeLastLine() + if (autoCorrect) { + (beforeRightAngle as LeafElement).rawReplaceWithText(newLineWithIndent) } } } } } + private fun String.trimBeforeLastLine() = this.substring(this.lastIndexOf('\n')) + private companion object { val ELEMENT_TYPES_ALLOWING_PRECEDING_WHITESPACE = setOf(VAL_KEYWORD, VAR_KEYWORD, FUN_KEYWORD) } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundUnaryOperatorRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundUnaryOperatorRule.kt index f426c326a3..99b433ce6d 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundUnaryOperatorRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundUnaryOperatorRule.kt @@ -24,9 +24,14 @@ public class SpacingAroundUnaryOperatorRule : Rule("unary-op-spacing") { val children = node.children().toList() // ignore: var a = + /* comment */ 1 - if (children.any { it.isPartOfComment() }) return + if (children.any { it.isPartOfComment() }) { + return + } - val whiteSpace = children.firstOrNull { it.isWhiteSpace() } ?: return + val whiteSpace = + children + .firstOrNull { it.isWhiteSpace() } + ?: return emit(whiteSpace.startOffset, "Unexpected spacing in ${node.text.replace("\n", "\\n")}", true) if (autoCorrect) { diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/WrappingRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/WrappingRule.kt index 5d5b739685..167cc1323a 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/WrappingRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/WrappingRule.kt @@ -5,6 +5,9 @@ import com.pinterest.ktlint.core.Rule import com.pinterest.ktlint.core.api.EditorConfigProperties import com.pinterest.ktlint.core.api.UsesEditorConfigProperties import com.pinterest.ktlint.core.api.editorconfig.EditorConfigProperty +import com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY +import com.pinterest.ktlint.core.api.editorconfig.INDENT_STYLE_PROPERTY +import com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY import com.pinterest.ktlint.core.ast.ElementType import com.pinterest.ktlint.core.ast.ElementType.ANNOTATION import com.pinterest.ktlint.core.ast.ElementType.ARROW @@ -83,9 +86,9 @@ public class WrappingRule : UsesEditorConfigProperties { override val editorConfigProperties: List> = listOf( - com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY, - com.pinterest.ktlint.core.api.editorconfig.INDENT_STYLE_PROPERTY, - com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY, + INDENT_SIZE_PROPERTY, + INDENT_STYLE_PROPERTY, + MAX_LINE_LENGTH_PROPERTY, ) private var line = 1 @@ -95,10 +98,10 @@ public class WrappingRule : override fun beforeFirstNode(editorConfigProperties: EditorConfigProperties) { line = 1 indentConfig = IndentConfig( - indentStyle = editorConfigProperties.getEditorConfigValue(com.pinterest.ktlint.core.api.editorconfig.INDENT_STYLE_PROPERTY), - tabWidth = editorConfigProperties.getEditorConfigValue(com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY), + indentStyle = editorConfigProperties.getEditorConfigValue(INDENT_STYLE_PROPERTY), + tabWidth = editorConfigProperties.getEditorConfigValue(INDENT_SIZE_PROPERTY), ) - maxLineLength = editorConfigProperties.getEditorConfigValue(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY) + maxLineLength = editorConfigProperties.getEditorConfigValue(MAX_LINE_LENGTH_PROPERTY) } override fun beforeVisitChildNodes( diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/AnnotationSpacingRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/AnnotationSpacingRuleTest.kt index 978321b26d..4fcd68e779 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/AnnotationSpacingRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/AnnotationSpacingRuleTest.kt @@ -1,7 +1,6 @@ package com.pinterest.ktlint.ruleset.standard import com.pinterest.ktlint.test.KtLintAssertThat.Companion.assertThatRule -import com.pinterest.ktlint.test.LintViolation import org.junit.jupiter.api.Test class AnnotationSpacingRuleTest { @@ -32,7 +31,7 @@ class AnnotationSpacingRuleTest { fun foo() {} """.trimIndent() annotationSpacingRuleAssertThat(code) - .hasLintViolation(1, 9, "Annotations should occur immediately before the annotated construct") + .hasLintViolation(1, 10, "Annotations should occur immediately before the annotated construct") .isFormattedAs(formattedCode) } @@ -51,7 +50,7 @@ class AnnotationSpacingRuleTest { fun foo() {} """.trimIndent() annotationSpacingRuleAssertThat(code) - .hasLintViolation(1, 9, "Annotations should occur immediately before the annotated construct") + .hasLintViolation(1, 10, "Annotations should occur immediately before the annotated construct") .isFormattedAs(formattedCode) } @@ -78,11 +77,8 @@ class AnnotationSpacingRuleTest { fun foo() = Unit """.trimIndent() annotationSpacingRuleAssertThat(code) - .hasLintViolations( - // TODO: It is not correct that the error is reported twice - LintViolation(1, 20, "Annotations should occur immediately before the annotated construct"), - LintViolation(1, 20, "Annotations should occur immediately before the annotated construct"), - ).isFormattedAs(formattedCode) + .hasLintViolation(1, 21, "Annotations should occur immediately before the annotated construct") + .isFormattedAs(formattedCode) } @Test @@ -101,11 +97,8 @@ class AnnotationSpacingRuleTest { fun foo() = Unit """.trimIndent() annotationSpacingRuleAssertThat(code) - .hasLintViolations( - // TODO: It is not correct that the error is reported twice - LintViolation(2, 10, "Annotations should occur immediately before the annotated construct"), - LintViolation(2, 10, "Annotations should occur immediately before the annotated construct"), - ).isFormattedAs(formattedCode) + .hasLintViolation(2, 11, "Annotations should occur immediately before the annotated construct") + .isFormattedAs(formattedCode) } @Test @@ -124,7 +117,7 @@ class AnnotationSpacingRuleTest { fun foo() = Unit """.trimIndent() annotationSpacingRuleAssertThat(code) - .hasLintViolation(3, 10, "Annotations should occur immediately before the annotated construct") + .hasLintViolation(3, 11, "Annotations should occur immediately before the annotated construct") .isFormattedAs(formattedCode) } @@ -142,8 +135,7 @@ class AnnotationSpacingRuleTest { @JvmStatic fun foo() = Unit """.trimIndent() annotationSpacingRuleAssertThat(code) - // TODO: Offset of error is not correct - .hasLintViolation(3, 10, "Annotations should occur immediately before the annotated construct") + .hasLintViolation(3, 11, "Annotations should occur immediately before the annotated construct") .isFormattedAs(formattedCode) } @@ -168,7 +160,7 @@ class AnnotationSpacingRuleTest { } """.trimIndent() annotationSpacingRuleAssertThat(code) - .hasLintViolation(1, 31, "Annotations should occur immediately before the annotated construct") + .hasLintViolation(1, 32, "Annotations should occur immediately before the annotated construct") .isFormattedAs(formattedCode) } @@ -189,7 +181,7 @@ class AnnotationSpacingRuleTest { } """.trimIndent() annotationSpacingRuleAssertThat(code) - .hasLintViolation(1, 31, "Annotations should occur immediately before the annotated construct") + .hasLintViolation(1, 32, "Annotations should occur immediately before the annotated construct") .isFormattedAs(formattedCode) } diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/ArgumentListWrappingRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/ArgumentListWrappingRuleTest.kt index 8dacef013d..b314e8c3ff 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/ArgumentListWrappingRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/ArgumentListWrappingRuleTest.kt @@ -1,5 +1,6 @@ package com.pinterest.ktlint.ruleset.standard +import com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY import com.pinterest.ktlint.test.KtLintAssertThat.Companion.EOL_CHAR import com.pinterest.ktlint.test.KtLintAssertThat.Companion.MAX_LINE_LENGTH_MARKER import com.pinterest.ktlint.test.KtLintAssertThat.Companion.assertThatRule @@ -82,7 +83,7 @@ class ArgumentListWrappingRuleTest { ) """.trimIndent() argumentListWrappingRuleAssertThat(code) - .withEditorConfigOverride(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY to 10) + .withEditorConfigOverride(MAX_LINE_LENGTH_PROPERTY to 10) .hasLintViolations( LintViolation(1, 11, "Argument should be on a separate line (unless all arguments can fit a single line)"), LintViolation(1, 14, "Argument should be on a separate line (unless all arguments can fit a single line)"), @@ -161,7 +162,7 @@ class ArgumentListWrappingRuleTest { ) """.trimIndent() argumentListWrappingRuleAssertThat(code) - .withEditorConfigOverride(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY to 20) + .withEditorConfigOverride(MAX_LINE_LENGTH_PROPERTY to 20) .hasLintViolations( LintViolation(13, 10, "Argument should be on a separate line (unless all arguments can fit a single line)"), LintViolation(13, 19, "Argument should be on a separate line (unless all arguments can fit a single line)"), @@ -297,7 +298,7 @@ class ArgumentListWrappingRuleTest { val foo = foo(1, 2, 3, 4, 5, 6, 7, 8, 9) """.trimIndent() argumentListWrappingRuleAssertThat(code) - .withEditorConfigOverride(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY to 20) + .withEditorConfigOverride(MAX_LINE_LENGTH_PROPERTY to 20) .hasNoLintViolations() } @@ -522,7 +523,7 @@ class ArgumentListWrappingRuleTest { ) """.trimIndent() argumentListWrappingRuleAssertThat(code) - .withEditorConfigOverride(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY to 33) + .withEditorConfigOverride(MAX_LINE_LENGTH_PROPERTY to 33) .hasLintViolations( LintViolation(8, 23, "Argument should be on a separate line (unless all arguments can fit a single line)"), LintViolation(8, 34, "Missing newline before \")\""), @@ -554,7 +555,7 @@ class ArgumentListWrappingRuleTest { argumentListWrappingRuleAssertThat(code) // TODO: It is not clear how the length 65 is related to the lint errors below. Starting from length 66 the // lint errors are not reported anymore. - .withEditorConfigOverride(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY to 65) + .withEditorConfigOverride(MAX_LINE_LENGTH_PROPERTY to 65) .hasLintViolations( LintViolation(4, 15, "Argument should be on a separate line (unless all arguments can fit a single line)"), LintViolation(4, 70, "Missing newline before \")\""), @@ -580,7 +581,7 @@ class ArgumentListWrappingRuleTest { argumentListWrappingRuleAssertThat(code) // TODO: With max line length of 43 or below, lint errors occur. It is not clear how that is related to // example above - .withEditorConfigOverride(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY to 44) + .withEditorConfigOverride(MAX_LINE_LENGTH_PROPERTY to 44) .hasNoLintViolations() } diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/FinalNewlineRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/FinalNewlineRuleTest.kt index 23443e968b..eb0e70a85a 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/FinalNewlineRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/FinalNewlineRuleTest.kt @@ -1,5 +1,6 @@ package com.pinterest.ktlint.ruleset.standard +import com.pinterest.ktlint.core.api.editorconfig.INSERT_FINAL_NEWLINE_PROPERTY import com.pinterest.ktlint.test.KtLintAssertThat.Companion.assertThatRule import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test @@ -105,8 +106,8 @@ class FinalNewlineRuleTest { } private companion object { - val FINAL_NEW_LINE_REQUIRED = com.pinterest.ktlint.core.api.editorconfig.INSERT_FINAL_NEWLINE_PROPERTY to true + val FINAL_NEW_LINE_REQUIRED = INSERT_FINAL_NEWLINE_PROPERTY to true val FINAL_NEW_LINE_NOT_REQUIRED = - com.pinterest.ktlint.core.api.editorconfig.INSERT_FINAL_NEWLINE_PROPERTY to false + INSERT_FINAL_NEWLINE_PROPERTY to false } } diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/IndentationRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/IndentationRuleTest.kt index 4d7187c852..e89007a481 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/IndentationRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/IndentationRuleTest.kt @@ -1,5 +1,7 @@ package com.pinterest.ktlint.ruleset.standard +import com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY +import com.pinterest.ktlint.core.api.editorconfig.INDENT_STYLE_PROPERTY import com.pinterest.ktlint.test.KtLintAssertThat.Companion.assertThatRule import com.pinterest.ktlint.test.LintViolation import com.pinterest.ktlint.test.MULTILINE_STRING_QUOTE @@ -1163,7 +1165,7 @@ internal class IndentationRuleTest { } """.trimIndent() indentationRuleAssertThat(code) - .withEditorConfigOverride(com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY to 2) + .withEditorConfigOverride(INDENT_SIZE_PROPERTY to 2) .hasLintViolations( LintViolation(2, 1, "Unexpected indentation (3) (should be 2)"), LintViolation(3, 1, "Unexpected indentation (4) (should be 2)"), @@ -1222,7 +1224,7 @@ internal class IndentationRuleTest { } """.trimIndent() indentationRuleAssertThat(code) - .withEditorConfigOverride(com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY to "unset") + .withEditorConfigOverride(INDENT_SIZE_PROPERTY to "unset") .hasNoLintViolations() } @@ -2735,7 +2737,7 @@ internal class IndentationRuleTest { } """.trimIndent() indentationRuleAssertThat(code) - .withEditorConfigOverride(com.pinterest.ktlint.core.api.editorconfig.INDENT_SIZE_PROPERTY to 2) + .withEditorConfigOverride(INDENT_SIZE_PROPERTY to 2) .hasLintViolations( LintViolation(2, 1, "Unexpected tab character(s)"), LintViolation(3, 1, "Unexpected tab character(s)"), @@ -4757,7 +4759,7 @@ internal class IndentationRuleTest { private companion object { val INDENT_STYLE_TAB = - com.pinterest.ktlint.core.api.editorconfig.INDENT_STYLE_PROPERTY to PropertyType.IndentStyleValue.tab + INDENT_STYLE_PROPERTY to PropertyType.IndentStyleValue.tab } } diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/MaxLineLengthRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/MaxLineLengthRuleTest.kt index 37042e852c..9fb4af6eed 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/MaxLineLengthRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/MaxLineLengthRuleTest.kt @@ -1,5 +1,6 @@ package com.pinterest.ktlint.ruleset.standard +import com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY import com.pinterest.ktlint.ruleset.standard.MaxLineLengthRule.Companion.IGNORE_BACKTICKED_IDENTIFIER_PROPERTY import com.pinterest.ktlint.test.KtLintAssertThat.Companion.EOL_CHAR import com.pinterest.ktlint.test.KtLintAssertThat.Companion.MAX_LINE_LENGTH_MARKER @@ -183,7 +184,7 @@ class MaxLineLengthRuleTest { fun testLintOff() { val code = "// some" + " long ".repeat(100) + "comment" // Total length of line is 7 + 600 + 7 = 614 characters maxLineLengthRuleAssertThat(code) - .withEditorConfigOverride(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY to "off") + .withEditorConfigOverride(MAX_LINE_LENGTH_PROPERTY to "off") .hasNoLintViolations() } diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/NoConsecutiveBlankLinesRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/NoConsecutiveBlankLinesRuleTest.kt index 38220f756a..451cafd940 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/NoConsecutiveBlankLinesRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/NoConsecutiveBlankLinesRuleTest.kt @@ -135,10 +135,8 @@ class NoConsecutiveBlankLinesRuleTest { """.trimIndent() noConsecutiveBlankLinesRuleAssertThat(code) .hasLintViolations( - // TODO: Line number is incorrect - LintViolation(3, 1, "Needless blank line(s)"), - // TODO: Line number is incorrect - LintViolation(7, 1, "Needless blank line(s)"), + LintViolation(2, 1, "Needless blank line(s)"), + LintViolation(6, 1, "Needless blank line(s)"), ).isFormattedAs(formattedCode) } @@ -148,11 +146,16 @@ class NoConsecutiveBlankLinesRuleTest { """ class A // comment + constructor(a: Int) + """.trimIndent() + val formattedCode = + """ + class A // comment constructor(a: Int) """.trimIndent() noConsecutiveBlankLinesRuleAssertThat(code) - // TODO: Check why no error is reported here - .hasNoLintViolations() + .hasLintViolation(2, 1, "Needless blank line(s)") + .isFormattedAs(formattedCode) } } diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/NoLineBreakBeforeAssignmentRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/NoLineBreakBeforeAssignmentRuleTest.kt index 77406e955d..f9a48f84cf 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/NoLineBreakBeforeAssignmentRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/NoLineBreakBeforeAssignmentRuleTest.kt @@ -40,7 +40,7 @@ class NoLineBreakBeforeAssignmentRuleTest { "" """.trimIndent() noLineBreakBeforeAssignmentRuleAssertThat(code) - .hasLintViolation(2, 7, "Line break before assignment is not allowed") + .hasLintViolation(1, 9, "Line break before assignment is not allowed") .isFormattedAs(formattedCode) } @@ -57,7 +57,7 @@ class NoLineBreakBeforeAssignmentRuleTest { "" """.trimIndent() noLineBreakBeforeAssignmentRuleAssertThat(code) - .hasLintViolation(2, 7, "Line break before assignment is not allowed") + .hasLintViolation(1, 11, "Line break before assignment is not allowed") .isFormattedAs(formattedCode) } @@ -74,8 +74,7 @@ class NoLineBreakBeforeAssignmentRuleTest { f() """.trimIndent() noLineBreakBeforeAssignmentRuleAssertThat(code) - // TODO: The error description is not correct - .hasLintViolation(2, 9, "Line break before assignment is not allowed") + .hasLintViolation(1, 8, "Line break before assignment is not allowed") .isFormattedAs(formattedCode) } @@ -96,8 +95,7 @@ class NoLineBreakBeforeAssignmentRuleTest { a + b """.trimIndent() noLineBreakBeforeAssignmentRuleAssertThat(code) - // TODO: The error description is not correct - .hasLintViolation(3, 5, "Line break before assignment is not allowed") + .hasLintViolation(2, 15, "Line break before assignment is not allowed") .isFormattedAs(formattedCode) } @@ -119,9 +117,8 @@ class NoLineBreakBeforeAssignmentRuleTest { """.trimIndent() noLineBreakBeforeAssignmentRuleAssertThat(code) .hasLintViolations( - // TODO: The error description is not correct - LintViolation(2, 5, "Line break before assignment is not allowed"), - LintViolation(4, 5, "Line break before assignment is not allowed"), + LintViolation(1, 41, "Line break before assignment is not allowed"), + LintViolation(3, 40, "Line break before assignment is not allowed"), ).isFormattedAs(formattedCode) } } @@ -139,7 +136,7 @@ class NoLineBreakBeforeAssignmentRuleTest { null): Int = 3 """.trimIndent() noLineBreakBeforeAssignmentRuleAssertThat(code) - .hasLintViolation(2, 1, "Line break before assignment is not allowed") + .hasLintViolation(1, 21, "Line break before assignment is not allowed") .isFormattedAs(formattedCode) } } diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/NoSemicolonsRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/NoSemicolonsRuleTest.kt index 9566f695a7..84c1d129ef 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/NoSemicolonsRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/NoSemicolonsRuleTest.kt @@ -34,16 +34,48 @@ class NoSemicolonsRuleTest { noSemicolonsRuleAssertThat(code).hasNoLintViolations() } + @Test + fun `Given a semi colon at the start of a line and not followed by code or comment on the same line then do report a lint error`() { + val code = + """ + fun foo() { + ; + bar() + ; + + bar() + + ; + } + """.trimIndent() + val formattedCode = + """ + fun foo() { + bar() + + bar() + } + """.trimIndent() + noSemicolonsRuleAssertThat(code) + .hasLintViolations( + LintViolation(2, 5, "Unnecessary semicolon"), + LintViolation(4, 5, "Unnecessary semicolon"), + LintViolation(8, 5, "Unnecessary semicolon"), + ).isFormattedAs(formattedCode) + } + @Disabled("To be implemented") @Test - fun `Given a semi colon at the start of a line then do report a lint error`() { + fun `Given a semi colon at the start of a line and followed by code or comment on the same line then do report a lint error`() { val code = """ ;val fooBar = "fooBar" + ;// some comment """.trimIndent() val formattedCode = """ val fooBar = "fooBar" + // some comment """.trimIndent() noSemicolonsRuleAssertThat(code) .hasLintViolation(1, 1, "Unnecessary semicolon") @@ -275,11 +307,20 @@ class NoSemicolonsRuleTest { ; } """.trimIndent() - noSemicolonsRuleAssertThat(code).hasNoLintViolations() + val formattedCode = + """ + enum class Test { + ONE + // comment + } + """.trimIndent() + noSemicolonsRuleAssertThat(code) + .hasLintViolation(4, 5, "Unnecessary semicolon") + .isFormattedAs(formattedCode) } @Test - fun `Given an enumeration and the list of values is closed with a semicolon not followed by statements then do not return a lint error`() { + fun `Given an enumeration and the list of values is closed with a semicolon not followed by statements then do return a lint error`() { val code = """ enum class E1 { @@ -300,8 +341,9 @@ class NoSemicolonsRuleTest { } """.trimIndent() noSemicolonsRuleAssertThat(code) - // TODO: It is not consistent that the semicolon is only reported in one of cases above .hasLintViolations( + LintViolation(3, 6, "Unnecessary semicolon"), + LintViolation(8, 5, "Unnecessary semicolon"), LintViolation(11, 5, "Unnecessary semicolon"), LintViolation(15, 5, "Unnecessary semicolon"), ) diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/ParameterListWrappingRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/ParameterListWrappingRuleTest.kt index 2dc6001f32..4c2a305bc4 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/ParameterListWrappingRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/ParameterListWrappingRuleTest.kt @@ -1,6 +1,7 @@ package com.pinterest.ktlint.ruleset.standard import com.pinterest.ktlint.core.RuleProvider +import com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY import com.pinterest.ktlint.test.KtLintAssertThat.Companion.assertThatRule import com.pinterest.ktlint.test.LintViolation import org.junit.jupiter.api.Test @@ -54,7 +55,7 @@ class ParameterListWrappingRuleTest { ) """.trimIndent() parameterListWrappingRuleAssertThat(code) - .withEditorConfigOverride(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY to 10) + .withEditorConfigOverride(MAX_LINE_LENGTH_PROPERTY to 10) .hasLintViolations( LintViolation(1, 14, "Parameter should be on a separate line (unless all parameters can fit a single line)"), LintViolation(1, 30, "Parameter should be on a separate line (unless all parameters can fit a single line)"), @@ -70,7 +71,7 @@ class ParameterListWrappingRuleTest { class ClassAWithALongName() """.trimIndent() parameterListWrappingRuleAssertThat(code) - .withEditorConfigOverride(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY to 10) + .withEditorConfigOverride(MAX_LINE_LENGTH_PROPERTY to 10) .hasNoLintViolations() } @@ -164,7 +165,7 @@ class ParameterListWrappingRuleTest { } """.trimIndent() parameterListWrappingRuleAssertThat(code) - .withEditorConfigOverride(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY to 10) + .withEditorConfigOverride(MAX_LINE_LENGTH_PROPERTY to 10) .hasLintViolations( LintViolation(1, 7, "Parameter should be on a separate line (unless all parameters can fit a single line)"), LintViolation(1, 15, "Parameter should be on a separate line (unless all parameters can fit a single line)"), @@ -219,7 +220,7 @@ class ParameterListWrappingRuleTest { } """.trimIndent() parameterListWrappingRuleAssertThat(code) - .withEditorConfigOverride(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY to 10) + .withEditorConfigOverride(MAX_LINE_LENGTH_PROPERTY to 10) .hasLintViolations( LintViolation(2, 11, "Parameter should be on a separate line (unless all parameters can fit a single line)"), LintViolation(6, 19, "Parameter should be on a separate line (unless all parameters can fit a single line)"), @@ -309,7 +310,7 @@ class ParameterListWrappingRuleTest { ) {} """.trimIndent() parameterListWrappingRuleAssertThat(code) - .withEditorConfigOverride(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY to 10) + .withEditorConfigOverride(MAX_LINE_LENGTH_PROPERTY to 10) .hasLintViolations( LintViolation(1, 11, "Parameter should be on a separate line (unless all parameters can fit a single line)"), LintViolation(1, 26, "Parameter should be on a separate line (unless all parameters can fit a single line)"), @@ -475,7 +476,7 @@ class ParameterListWrappingRuleTest { )? = null """.trimIndent() parameterListWrappingRuleAssertThat(code) - .withEditorConfigOverride(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY to 80) + .withEditorConfigOverride(MAX_LINE_LENGTH_PROPERTY to 80) .hasLintViolations( LintViolation(1, 22, "Parameter of nullable type should be on a separate line (unless the type fits on a single line)"), LintViolation(1, 95, """Missing newline before ")""""), diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundAngleBracketRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundAngleBracketsRuleTest.kt similarity index 96% rename from ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundAngleBracketRuleTest.kt rename to ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundAngleBracketsRuleTest.kt index d5cdb450b8..d499b1d34a 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundAngleBracketRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundAngleBracketsRuleTest.kt @@ -4,7 +4,7 @@ import com.pinterest.ktlint.test.KtLintAssertThat.Companion.assertThatRule import com.pinterest.ktlint.test.LintViolation import org.junit.jupiter.api.Test -class SpacingAroundAngleBracketRuleTest { +class SpacingAroundAngleBracketsRuleTest { private val spacingAroundAngleBracketsRuleAssertThat = assertThatRule { SpacingAroundAngleBracketsRule() } @Test @@ -134,8 +134,9 @@ class SpacingAroundAngleBracketRuleTest { } """.trimIndent() spacingAroundAngleBracketsRuleAssertThat(code) - // TODO: This is not consistent with other rules that do not allow to align columns - .hasNoLintViolations() + .hasNoLintViolations( + // The redundant spaces before the angle bracket are cleared by the 'no-multi-spaces' rule + ) } @Test diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundColonRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundColonRuleTest.kt index f702ec7765..09c4362160 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundColonRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundColonRuleTest.kt @@ -215,7 +215,6 @@ class SpacingAroundColonRuleTest { fun foo(bar: String) {} """.trimIndent() spacingAroundColonRuleAssertThat(code) - // TODO: Offset col is not correct. .hasLintViolation(1, 13, "Unexpected spacing before \":\"") .isFormattedAs(formattedCode) } diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundCommaRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundCommaRuleTest.kt index af2c5b7e07..e3603b28ce 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundCommaRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundCommaRuleTest.kt @@ -20,7 +20,6 @@ class SpacingAroundCommaRuleTest { val foo2 = Foo(1, 3) """.trimIndent() spacingAroundCommaRuleAssertThat(code) - // TODO: Col offset is not correct .hasLintViolation(1, 18, "Missing spacing after \",\"") .isFormattedAs(formattedCode) } @@ -50,7 +49,6 @@ class SpacingAroundCommaRuleTest { } """.trimIndent() spacingAroundCommaRuleAssertThat(code) - // TODO: Col offset is not correct .hasLintViolation(2, 10, "Missing spacing after \",\"") .isFormattedAs(formattedCode) } diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundCurlyRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundCurlyRuleTest.kt index daf4cbd817..01a2bc4366 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundCurlyRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundCurlyRuleTest.kt @@ -81,7 +81,6 @@ class SpacingAroundCurlyRuleTest { """.trimIndent() spacingAroundCurlyRuleAssertThat(code) .hasLintViolations( - // TODO: Col offset is not correct LintViolation(1, 17, "Missing spacing after \"{\""), LintViolation(1, 23, "Missing spacing before \"}\""), ).isFormattedAs(formattedCode) @@ -176,7 +175,6 @@ class SpacingAroundCurlyRuleTest { fun Array.getFoo(): T = this[this.count { it == "foo" }] """.trimIndent() spacingAroundCurlyRuleAssertThat(code) - // TODO: Col offset is not correct .hasLintViolation(1, 62, "Unexpected space after \"}\"") .isFormattedAs(formattedCode) } @@ -213,12 +211,10 @@ class SpacingAroundCurlyRuleTest { LintViolation(2, 15, "Missing spacing around \"{\""), LintViolation(2, 26, "Missing spacing around \"}\""), LintViolation(2, 47, "Missing spacing before \"{\""), - // TODO: Col offset is not correct LintViolation(3, 13, "Missing spacing after \"{\""), LintViolation(3, 31, "Missing spacing around \"{\""), LintViolation(3, 40, "Missing spacing around \"}\""), LintViolation(3, 61, "Missing spacing before \"{\""), - // TODO: Col offset is not correct LintViolation(3, 63, "Missing spacing after \"}\""), LintViolation(3, 63, "Missing spacing before \"}\""), ).isFormattedAs(formattedCode) diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundUnaryOperatorRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundUnaryOperatorRuleTest.kt index a7dd19700e..1b137a3cca 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundUnaryOperatorRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/SpacingAroundUnaryOperatorRuleTest.kt @@ -149,7 +149,7 @@ class SpacingAroundUnaryOperatorRuleTest { spacingAroundUnaryOperatorRuleAssertThat(code) .hasLintViolations( LintViolation(2, 17, "Unexpected spacing in \"foo\" !!"), - // TODO: "foo3" should also be disallowed + // Space between the unary operator (!!) and the . is cleared by 'dot-spacing' rule ).isFormattedAs(formattedCode) } diff --git a/ktlint-test/src/main/kotlin/com/pinterest/ktlint/test/KtLintAssertThat.kt b/ktlint-test/src/main/kotlin/com/pinterest/ktlint/test/KtLintAssertThat.kt index ca66234cea..b611132d6d 100644 --- a/ktlint-test/src/main/kotlin/com/pinterest/ktlint/test/KtLintAssertThat.kt +++ b/ktlint-test/src/main/kotlin/com/pinterest/ktlint/test/KtLintAssertThat.kt @@ -5,6 +5,7 @@ import com.pinterest.ktlint.core.Rule import com.pinterest.ktlint.core.RuleProvider import com.pinterest.ktlint.core.api.EditorConfigOverride import com.pinterest.ktlint.core.api.editorconfig.EditorConfigProperty +import com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY import com.pinterest.ktlint.test.KtLintAssertThat.Companion.EOL_CHAR import com.pinterest.ktlint.test.KtLintAssertThat.Companion.MAX_LINE_LENGTH_MARKER import org.assertj.core.api.AbstractAssert @@ -85,7 +86,7 @@ public class KtLintAssertThat( ?.indexOf(EOL_CHAR) ?.let { index -> editorConfigProperties = - editorConfigProperties + setOf(com.pinterest.ktlint.core.api.editorconfig.MAX_LINE_LENGTH_PROPERTY to (index + 1).toString()) + editorConfigProperties + setOf(MAX_LINE_LENGTH_PROPERTY to (index + 1).toString()) } ?: throw MissingEolMarker() return this diff --git a/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/GenerateEditorConfigSubCommand.kt b/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/GenerateEditorConfigSubCommand.kt index 9be8bffa8d..32001dfd95 100644 --- a/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/GenerateEditorConfigSubCommand.kt +++ b/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/GenerateEditorConfigSubCommand.kt @@ -2,6 +2,7 @@ package com.pinterest.ktlint.internal import com.pinterest.ktlint.core.KtLintRuleEngine import com.pinterest.ktlint.core.api.EditorConfigOverride +import com.pinterest.ktlint.core.api.editorconfig.CODE_STYLE_PROPERTY import com.pinterest.ktlint.core.api.editorconfig.CodeStyleValue import com.pinterest.ktlint.core.initKtLintKLogger import java.nio.file.Paths @@ -30,7 +31,7 @@ internal class GenerateEditorConfigSubCommand : Runnable { val ktLintRuleEngine = KtLintRuleEngine( ruleProviders = ktlintCommand.ruleProviders(), - editorConfigOverride = EditorConfigOverride.from(com.pinterest.ktlint.core.api.editorconfig.CODE_STYLE_PROPERTY to codeStyle()), + editorConfigOverride = EditorConfigOverride.from(CODE_STYLE_PROPERTY to codeStyle()), isInvokedFromCli = true, ) val generatedEditorConfig = ktLintRuleEngine.generateKotlinEditorConfigSection(Paths.get(".")) diff --git a/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/KtlintCommandLine.kt b/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/KtlintCommandLine.kt index 0a7adcacaa..b6a3c6b9bb 100644 --- a/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/KtlintCommandLine.kt +++ b/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/KtlintCommandLine.kt @@ -14,9 +14,11 @@ import com.pinterest.ktlint.core.api.EditorConfigOverride.Companion.plus import com.pinterest.ktlint.core.api.KtLintParseException import com.pinterest.ktlint.core.api.KtLintRuleException import com.pinterest.ktlint.core.api.doesNotContain +import com.pinterest.ktlint.core.api.editorconfig.CODE_STYLE_PROPERTY import com.pinterest.ktlint.core.api.editorconfig.CodeStyleValue import com.pinterest.ktlint.core.api.editorconfig.RuleExecution import com.pinterest.ktlint.core.api.editorconfig.createRuleExecutionEditorConfigProperty +import com.pinterest.ktlint.core.api.editorconfig.createRuleSetExecutionEditorConfigProperty import com.pinterest.ktlint.core.api.loadBaseline import com.pinterest.ktlint.core.api.relativeRoute import com.pinterest.ktlint.core.initKtLintKLogger @@ -253,10 +255,12 @@ internal class KtlintCommandLine { get() = EditorConfigOverride .EMPTY_EDITOR_CONFIG_OVERRIDE - .applyIf(disabledRules.isNotBlank()) { + .applyIf(experimental) { + plus(createRuleSetExecutionEditorConfigProperty("experimental:all") to RuleExecution.enabled) + }.applyIf(disabledRules.isNotBlank()) { plus(*disabledRulesEditorConfigOverrides()) }.applyIf(android) { - plus(com.pinterest.ktlint.core.api.editorconfig.CODE_STYLE_PROPERTY to CodeStyleValue.android) + plus(CODE_STYLE_PROPERTY to CodeStyleValue.android) } private fun disabledRulesEditorConfigOverrides() = @@ -350,7 +354,7 @@ internal class KtlintCommandLine { internal fun ruleProviders() = rulesetJarPaths .toFilesURIList() - .loadRuleProviders(experimental, debug, disabledRules) + .loadRuleProviders(debug) private fun List.toFilesURIList() = map { diff --git a/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/LoadRuleProviders.kt b/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/LoadRuleProviders.kt index 1da317fee4..58c824582b 100644 --- a/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/LoadRuleProviders.kt +++ b/ktlint/src/main/kotlin/com/pinterest/ktlint/internal/LoadRuleProviders.kt @@ -14,11 +14,7 @@ private val LOGGER = KotlinLogging.logger {}.initKtLintKLogger() /** * Loads given list of paths to jar files. For files containing a [RuleSetProviderV2] class, get all [RuleProvider]s. */ -internal fun List.loadRuleProviders( - loadExperimental: Boolean, - debug: Boolean, - disabledRules: String, -): Set = +internal fun List.loadRuleProviders(debug: Boolean): Set = this .plus( // Ensure that always at least one element exists in this list so that the rule sets provided by the KtLint @@ -27,14 +23,7 @@ internal fun List.loadRuleProviders( ) // Remove JAR files which were provided multiple times .distinct() - .map { getRuleProvidersFromJar(it, debug) } - .flatMap { rulesProvidersFromJar -> - // Remove disabled rule sets - rulesProvidersFromJar - .filterKeys { loadExperimental || it != "experimental" } - .filterKeys { !(disabledRules.isStandardRuleSetDisabled() && it == "standard") } - .values - } + .flatMap { getRuleProvidersFromJar(it, debug).values } .flatten() .toSet() @@ -74,7 +63,4 @@ private fun getRuleProvidersFromJar( } } -private fun String.isStandardRuleSetDisabled() = - this.split(",").map { it.trim() }.toSet().contains("standard") - private val KTLINT_RULE_SETS = listOf("standard", "experimental")