Skip to content

Commit

Permalink
Fix statement-wrapping and align rule classes (#2178)
Browse files Browse the repository at this point in the history
* Add rule `statement-wrapping` to the `StandardRuleSetProvider` and remove `statement-wrapping` rule from release docs (`0.50`) as the rule is not run by Ktlint CLI

 Closes #2170

 Align names of Rule classes, file and `RULE_ID` constants

 Closes #2176

 Do not wrap a single line enum class

 Closes #2177
  • Loading branch information
paul-dingemans authored Aug 12, 2023
1 parent c7a2b09 commit 165facb
Show file tree
Hide file tree
Showing 16 changed files with 140 additions and 112 deletions.
19 changes: 17 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,27 @@ This project adheres to [Semantic Versioning](https://semver.org/).

## Unreleased

### API changes

* As a part of public API stabilization, data classes are no longer used in the public API. As of that, functions like `copy()` or `componentN()` (used for destructuring declarations) are not available anymore. This is a binary incompatible change, breaking backwards compatibility. ([#2133](https://github.com/pinterest/ktlint/issues/2133))

* Align names of Rule classes, file and `RULE_ID` constants ([#2176](https://github.com/pinterest/ktlint/issues/2176)). Rule class `MultilineExpressionWrapping` has been renamed to `MultilineExpressionWrappingRule`. Rule class `StatementWrapping` has been renamed to `StatementWrappingRule`. `RULE_ID` constants below are moved to a different Java class at compile time. Each rule provided by Ktlint is to be accompanied by a `RULE_ID` constant that can be used in the `VisitorModifier.RunAfter`. Filenames did not comply with standard that it should end with `Rule` suffix.

| RULE ID | Old Java class name | New Java class name |
|---------------------------------------|-------------------------------|-----------------------------------|
| FUNCTION_EXPRESSION_BODY_RULE_ID | FunctionExpressionBodyKt | FunctionExpressionBodyRuleKt |
| FUNCTION_LITERAL_RULE_ID | FunctionLiteralKt | FunctionLiteralRuleKt |
| MULTILINE_EXPRESSION_WRAPPING_RULE_ID | MultilineExpressionWrappingKt | MultilineExpressionWrappingRuleKt |
| NO_BLANK_LINE_IN_LIST_RULE_ID | NoBlankLineInListKt | NoBlankLineInListRuleKt |
| NO_EMPTY_FILE_RULE_ID | (not applicable) | NoEmptyFileRuleKt |

### Added

* Add experimental rule `class-signature`. This rule rewrites the class header to a consistent format. In code style `ktlint_official`, super types are always wrapped to a separate line. In other code styles, super types are only wrapped in classes having multiple super types. Especially for code style `ktlint_official` the class headers are rewritten in a more consistent format. See [examples in documentation](https://pinterest.github.io/ktlint/latest/rules/experimental/#class-signature). `class-signature` [#875](https://github.com/pinterest/ktlint/issues/1349), [#1349](https://github.com/pinterest/ktlint/issues/875)
* Add experimental rule `function-expression-body`. This rule rewrites function bodies only contain a `return` or `throw` expression to an expression body. [#2150](https://github.com/pinterest/ktlint/issues/2150)
* Add new experimental rule `statement-wrapping` which ensures function, class, or other blocks statement body doesn't start or end at starting or ending braces of the block ([#1938](https://github.com/pinterest/ktlint/issues/1938)). This rule was added in `0.50` release, but was never executed outside the unit tests. The rule is now added to the `StandardRuleSetProvider` ([#2170](https://github.com/pinterest/ktlint/issues/2170))

### Removed
* As a part of public API stabilization, data classes are no longer used in the public API. As of that, functions like `copy()` or `componentN()` (used for destructuring declarations) are not available anymore. This is a binary incompatible change, breaking backwards compatibility. ([#2133](https://github.com/pinterest/ktlint/issues/2133))

### Fixed

Expand All @@ -27,6 +41,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
* Add new experimental rule `function-literal`. This rule enforces the parameter list of a function literal to be formatted consistently. `function-literal` [#2121](https://github.com/pinterest/ktlint/issues/2121)
* Store relative path of file in baseline file [#2146](https://github.com/pinterest/ktlint/issues/2146)
* Fix null pointer exception for if-else statement with empty THEN block `if-else-bracing` [#2135](https://github.com/pinterest/ktlint/issues/2135)
* Do not wrap a single line enum class `statement-wrapping` [#2177](https://github.com/pinterest/ktlint/issues/2177)

### Changed

Expand Down Expand Up @@ -73,7 +88,7 @@ At this point in time, it is not yet decided what the next steps will be. Ktlint
* Add new experimental rule `binary-expression-wrapping`. This rule wraps a binary expression in case the max line length is exceeded ([#1940](https://github.com/pinterest/ktlint/issues/1940))
* Add flag to disable extension point `org.jetbrains.kotlin.com.intellij.treeCopyHandler` to analyse impact on custom rules [#1981](https://github.com/pinterest/ktlint/issues/1981)
* Add new experimental rule `no-empty-file` for all code styles. A kotlin (script) file may not be empty ([#1074](https://github.com/pinterest/ktlint/issues/1074))
* Add new experimental rule `statement-wrapping` which ensures function, class, or other blocks statement body doesn't start or end at starting or ending braces of the block ([#1938](https://github.com/pinterest/ktlint/issues/1938))
* Add new experimental rule `statement-wrapping` which ensures function, class, or other blocks statement body doesn't start or end at starting or ending braces of the block ([#1938](https://github.com/pinterest/ktlint/issues/1938)). Note, although this rule is added in this release, it is never executed except in unit tests.
* Add new experimental rule `blank-line-before-declaration`. This rule requires a blank line before class, function or property declarations ([#1939](https://github.com/pinterest/ktlint/issues/1939))
* Wrap multiple statements on same line `wrapping` ([#1078](https://github.com/pinterest/ktlint/issues/1078))
* Add new rule `ktlint-suppression` to replace the `ktlint-disable` and `ktlint-enable` directives with annotations. This rule can not be disabled via the `.editorconfig` ([#1947](https://github.com/pinterest/ktlint/issues/1947))
Expand Down
30 changes: 0 additions & 30 deletions documentation/release-latest/docs/rules/experimental.md
Original file line number Diff line number Diff line change
Expand Up @@ -900,33 +900,3 @@ Rule id: `multiline-expression-wrapping` (`standard` rule set)
!!! Note
This rule is only run when `ktlint_code_style` is set to `ktlint_official` or when the rule is enabled explicitly.

### Statement wrapping

A function, class/object body or other block body statement has to be placed on different line than the braces of the body block.

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

```kotlin
fun foo() {
if (true) {
// do something
}
}
class A {
val a = 0
val b = 1
}
```

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

```kotlin
fun foo() { if (true) {
// do something
}
}
class A { val a = 0
val b = 1 }
```

Rule id: `statement-wrapping`
5 changes: 5 additions & 0 deletions documentation/snapshot/docs/rules/experimental.md
Original file line number Diff line number Diff line change
Expand Up @@ -1206,6 +1206,11 @@ A function, class/object body or other block body statement has to be placed on
val a = 0
val b = 1
}
enum class FooBar1 { FOO, BAR }
enum class FooBar2 {
FOO,
BAR,
}
```

=== "[:material-heart-off-outline:](#) Disallowed"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,9 @@ internal class KtlintCommandLine {

private var KLogger.level: Level?
get() = underlyingLogger()?.level
set(value) { underlyingLogger()?.level = value }
set(value) {
underlyingLogger()?.level = value
}

private fun KLogger.underlyingLogger(): Logger? =
@Suppress("UNCHECKED_CAST")
Expand Down
30 changes: 17 additions & 13 deletions ktlint-ruleset-standard/api/ktlint-ruleset-standard.api
Original file line number Diff line number Diff line change
Expand Up @@ -184,18 +184,14 @@ public final class com/pinterest/ktlint/ruleset/standard/rules/FunKeywordSpacing
public static final fun getFUN_KEYWORD_SPACING_RULE ()Lcom/pinterest/ktlint/rule/engine/core/api/RuleId;
}

public final class com/pinterest/ktlint/ruleset/standard/rules/FunctionExpressionBodyKt {
public static final fun getFUNCTION_EXPRESSION_BODY_RULE_ID ()Lcom/pinterest/ktlint/rule/engine/core/api/RuleId;
}

public final class com/pinterest/ktlint/ruleset/standard/rules/FunctionExpressionBodyRule : com/pinterest/ktlint/ruleset/standard/StandardRule, com/pinterest/ktlint/rule/engine/core/api/Rule$Experimental {
public fun <init> ()V
public fun beforeFirstNode (Lcom/pinterest/ktlint/rule/engine/core/api/editorconfig/EditorConfig;)V
public fun beforeVisitChildNodes (Lorg/jetbrains/kotlin/com/intellij/lang/ASTNode;ZLkotlin/jvm/functions/Function3;)V
}

public final class com/pinterest/ktlint/ruleset/standard/rules/FunctionLiteralKt {
public static final fun getFUNCTION_LITERAL_RULE_ID ()Lcom/pinterest/ktlint/rule/engine/core/api/RuleId;
public final class com/pinterest/ktlint/ruleset/standard/rules/FunctionExpressionBodyRuleKt {
public static final fun getFUNCTION_EXPRESSION_BODY_RULE_ID ()Lcom/pinterest/ktlint/rule/engine/core/api/RuleId;
}

public final class com/pinterest/ktlint/ruleset/standard/rules/FunctionLiteralRule : com/pinterest/ktlint/ruleset/standard/StandardRule, com/pinterest/ktlint/rule/engine/core/api/Rule$Experimental {
Expand All @@ -204,6 +200,10 @@ public final class com/pinterest/ktlint/ruleset/standard/rules/FunctionLiteralRu
public fun beforeVisitChildNodes (Lorg/jetbrains/kotlin/com/intellij/lang/ASTNode;ZLkotlin/jvm/functions/Function3;)V
}

public final class com/pinterest/ktlint/ruleset/standard/rules/FunctionLiteralRuleKt {
public static final fun getFUNCTION_LITERAL_RULE_ID ()Lcom/pinterest/ktlint/rule/engine/core/api/RuleId;
}

public final class com/pinterest/ktlint/ruleset/standard/rules/FunctionNamingRule : com/pinterest/ktlint/ruleset/standard/StandardRule, com/pinterest/ktlint/rule/engine/core/api/Rule$Experimental {
public fun <init> ()V
public fun beforeVisitChildNodes (Lorg/jetbrains/kotlin/com/intellij/lang/ASTNode;ZLkotlin/jvm/functions/Function3;)V
Expand Down Expand Up @@ -366,13 +366,13 @@ public final class com/pinterest/ktlint/ruleset/standard/rules/MultiLineIfElseRu
public static final fun getMULTI_LINE_IF_ELSE_RULE_ID ()Lcom/pinterest/ktlint/rule/engine/core/api/RuleId;
}

public final class com/pinterest/ktlint/ruleset/standard/rules/MultilineExpressionWrapping : com/pinterest/ktlint/ruleset/standard/StandardRule, com/pinterest/ktlint/rule/engine/core/api/Rule$Experimental, com/pinterest/ktlint/rule/engine/core/api/Rule$OfficialCodeStyle {
public final class com/pinterest/ktlint/ruleset/standard/rules/MultilineExpressionWrappingRule : com/pinterest/ktlint/ruleset/standard/StandardRule, com/pinterest/ktlint/rule/engine/core/api/Rule$Experimental, com/pinterest/ktlint/rule/engine/core/api/Rule$OfficialCodeStyle {
public fun <init> ()V
public fun beforeFirstNode (Lcom/pinterest/ktlint/rule/engine/core/api/editorconfig/EditorConfig;)V
public fun beforeVisitChildNodes (Lorg/jetbrains/kotlin/com/intellij/lang/ASTNode;ZLkotlin/jvm/functions/Function3;)V
}

public final class com/pinterest/ktlint/ruleset/standard/rules/MultilineExpressionWrappingKt {
public final class com/pinterest/ktlint/ruleset/standard/rules/MultilineExpressionWrappingRuleKt {
public static final fun getMULTILINE_EXPRESSION_WRAPPING_RULE_ID ()Lcom/pinterest/ktlint/rule/engine/core/api/RuleId;
}

Expand All @@ -385,15 +385,15 @@ public final class com/pinterest/ktlint/ruleset/standard/rules/NoBlankLineBefore
public static final fun getNO_BLANK_LINE_BEFORE_RBRACE_RULE_ID ()Lcom/pinterest/ktlint/rule/engine/core/api/RuleId;
}

public final class com/pinterest/ktlint/ruleset/standard/rules/NoBlankLineInListKt {
public static final fun getNO_BLANK_LINE_IN_LIST_RULE_ID ()Lcom/pinterest/ktlint/rule/engine/core/api/RuleId;
}

public final class com/pinterest/ktlint/ruleset/standard/rules/NoBlankLineInListRule : com/pinterest/ktlint/ruleset/standard/StandardRule, com/pinterest/ktlint/rule/engine/core/api/Rule$Experimental, com/pinterest/ktlint/rule/engine/core/api/Rule$OfficialCodeStyle {
public fun <init> ()V
public fun beforeVisitChildNodes (Lorg/jetbrains/kotlin/com/intellij/lang/ASTNode;ZLkotlin/jvm/functions/Function3;)V
}

public final class com/pinterest/ktlint/ruleset/standard/rules/NoBlankLineInListRuleKt {
public static final fun getNO_BLANK_LINE_IN_LIST_RULE_ID ()Lcom/pinterest/ktlint/rule/engine/core/api/RuleId;
}

public final class com/pinterest/ktlint/ruleset/standard/rules/NoBlankLinesInChainedMethodCallsRule : com/pinterest/ktlint/ruleset/standard/StandardRule {
public fun <init> ()V
public fun beforeVisitChildNodes (Lorg/jetbrains/kotlin/com/intellij/lang/ASTNode;ZLkotlin/jvm/functions/Function3;)V
Expand Down Expand Up @@ -435,6 +435,10 @@ public final class com/pinterest/ktlint/ruleset/standard/rules/NoEmptyFileRule :
public fun beforeVisitChildNodes (Lorg/jetbrains/kotlin/com/intellij/lang/ASTNode;ZLkotlin/jvm/functions/Function3;)V
}

public final class com/pinterest/ktlint/ruleset/standard/rules/NoEmptyFileRuleKt {
public static final fun getNO_EMPTY_FILE_RULE_ID ()Lcom/pinterest/ktlint/rule/engine/core/api/RuleId;
}

public final class com/pinterest/ktlint/ruleset/standard/rules/NoEmptyFirstLineInClassBodyRule : com/pinterest/ktlint/ruleset/standard/StandardRule, com/pinterest/ktlint/rule/engine/core/api/Rule$Experimental, com/pinterest/ktlint/rule/engine/core/api/Rule$OfficialCodeStyle {
public fun <init> ()V
public fun beforeFirstNode (Lcom/pinterest/ktlint/rule/engine/core/api/editorconfig/EditorConfig;)V
Expand Down Expand Up @@ -735,7 +739,7 @@ public final class com/pinterest/ktlint/ruleset/standard/rules/SpacingBetweenFun
public static final fun getSPACING_BETWEEN_FUNCTION_NAME_AND_OPENING_PARENTHESIS_RULE_ID ()Lcom/pinterest/ktlint/rule/engine/core/api/RuleId;
}

public final class com/pinterest/ktlint/ruleset/standard/rules/StatementWrapping : com/pinterest/ktlint/ruleset/standard/StandardRule, com/pinterest/ktlint/rule/engine/core/api/Rule$Experimental {
public final class com/pinterest/ktlint/ruleset/standard/rules/StatementWrappingRule : com/pinterest/ktlint/ruleset/standard/StandardRule, com/pinterest/ktlint/rule/engine/core/api/Rule$Experimental {
public fun <init> ()V
public fun beforeFirstNode (Lcom/pinterest/ktlint/rule/engine/core/api/editorconfig/EditorConfig;)V
public fun beforeVisitChildNodes (Lorg/jetbrains/kotlin/com/intellij/lang/ASTNode;ZLkotlin/jvm/functions/Function3;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import com.pinterest.ktlint.ruleset.standard.rules.MaxLineLengthRule
import com.pinterest.ktlint.ruleset.standard.rules.ModifierListSpacingRule
import com.pinterest.ktlint.ruleset.standard.rules.ModifierOrderRule
import com.pinterest.ktlint.ruleset.standard.rules.MultiLineIfElseRule
import com.pinterest.ktlint.ruleset.standard.rules.MultilineExpressionWrapping
import com.pinterest.ktlint.ruleset.standard.rules.MultilineExpressionWrappingRule
import com.pinterest.ktlint.ruleset.standard.rules.NoBlankLineBeforeRbraceRule
import com.pinterest.ktlint.ruleset.standard.rules.NoBlankLineInListRule
import com.pinterest.ktlint.ruleset.standard.rules.NoBlankLinesInChainedMethodCallsRule
Expand Down Expand Up @@ -77,6 +77,7 @@ import com.pinterest.ktlint.ruleset.standard.rules.SpacingAroundUnaryOperatorRul
import com.pinterest.ktlint.ruleset.standard.rules.SpacingBetweenDeclarationsWithAnnotationsRule
import com.pinterest.ktlint.ruleset.standard.rules.SpacingBetweenDeclarationsWithCommentsRule
import com.pinterest.ktlint.ruleset.standard.rules.SpacingBetweenFunctionNameAndOpeningParenthesisRule
import com.pinterest.ktlint.ruleset.standard.rules.StatementWrappingRule
import com.pinterest.ktlint.ruleset.standard.rules.StringTemplateIndentRule
import com.pinterest.ktlint.ruleset.standard.rules.StringTemplateRule
import com.pinterest.ktlint.ruleset.standard.rules.TrailingCommaOnCallSiteRule
Expand Down Expand Up @@ -124,7 +125,7 @@ public class StandardRuleSetProvider : RuleSetProviderV3(RuleSetId.STANDARD) {
RuleProvider { ModifierListSpacingRule() },
RuleProvider { ModifierOrderRule() },
RuleProvider { MultiLineIfElseRule() },
RuleProvider { MultilineExpressionWrapping() },
RuleProvider { MultilineExpressionWrappingRule() },
RuleProvider { NoBlankLineBeforeRbraceRule() },
RuleProvider { NoBlankLineInListRule() },
RuleProvider { NoBlankLinesInChainedMethodCallsRule() },
Expand Down Expand Up @@ -164,6 +165,7 @@ public class StandardRuleSetProvider : RuleSetProviderV3(RuleSetId.STANDARD) {
RuleProvider { SpacingBetweenDeclarationsWithAnnotationsRule() },
RuleProvider { SpacingBetweenDeclarationsWithCommentsRule() },
RuleProvider { SpacingBetweenFunctionNameAndOpeningParenthesisRule() },
RuleProvider { StatementWrappingRule() },
RuleProvider { StringTemplateRule() },
RuleProvider { StringTemplateIndentRule() },
RuleProvider { TrailingCommaOnCallSiteRule() },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import org.jetbrains.kotlin.com.intellij.lang.ASTNode
/**
* This rule wraps each multiline expression to a newline.
*/
public class MultilineExpressionWrapping :
public class MultilineExpressionWrappingRule :
StandardRule(
id = "multiline-expression-wrapping",
usesEditorConfigProperties =
Expand Down Expand Up @@ -188,4 +188,4 @@ public class MultilineExpressionWrapping :
}
}

public val MULTILINE_EXPRESSION_WRAPPING_RULE_ID: RuleId = MultilineExpressionWrapping().ruleId
public val MULTILINE_EXPRESSION_WRAPPING_RULE_ID: RuleId = MultilineExpressionWrappingRule().ruleId
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.pinterest.ktlint.ruleset.standard.rules

import com.pinterest.ktlint.rule.engine.core.api.ElementType
import com.pinterest.ktlint.rule.engine.core.api.Rule
import com.pinterest.ktlint.rule.engine.core.api.RuleId
import com.pinterest.ktlint.rule.engine.core.api.children
import com.pinterest.ktlint.rule.engine.core.api.isPartOfComment
import com.pinterest.ktlint.rule.engine.core.api.isRoot
Expand Down Expand Up @@ -42,3 +43,5 @@ public class NoEmptyFileRule :
!(it.elementType == ElementType.SCRIPT && it.text.isBlank())
}
}

public val NO_EMPTY_FILE_RULE_ID: RuleId = NoEmptyFileRule().ruleId
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ import com.pinterest.ktlint.rule.engine.core.api.upsertWhitespaceAfterMe
import com.pinterest.ktlint.rule.engine.core.api.upsertWhitespaceBeforeMe
import com.pinterest.ktlint.ruleset.standard.StandardRule
import org.jetbrains.kotlin.com.intellij.lang.ASTNode
import org.jetbrains.kotlin.com.intellij.psi.PsiElement
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.utils.addToStdlib.applyIf

public class StatementWrapping :
public class StatementWrappingRule :
StandardRule(
"statement-wrapping",
usesEditorConfigProperties =
Expand Down Expand Up @@ -72,9 +74,16 @@ public class StatementWrapping :
.takeUnless {
// Allow
// val foo = {}
it.isBlockWithoutStatements
}?.takeUnless {
// Allow
// val foo = { /* no-op */ }
// val foo = { a, b -> println(a + b) }
it.isBlockWithoutStatements || it.isFunctionLiteralWithSingleStatementOnSingleLine
it.isFunctionLiteralWithSingleStatementOnSingleLine
}?.takeUnless {
// Allow
// enum class FooBar { FOO, BAR }
it.treeParent.isEnumClassOnSingleLine
}?.findChildByType(LBRACE)
?.applyIf(node.isFunctionLiteralWithParameterList) {
// Allow:
Expand Down Expand Up @@ -132,6 +141,15 @@ public class StatementWrapping :
?.let { count -> count <= 1 }
?: false

private inline val ASTNode.isEnumClassOnSingleLine: Boolean
get() =
takeIf { psi.isEnumClass }
?.let { !it.textContains('\n') }
?: false

private inline val PsiElement.isEnumClass: Boolean
get() = (this as? KtClass)?.isEnum() ?: false

private inline val ASTNode.indentAsChild: String
get() = indent().plus(indentConfig.indent)

Expand Down
Loading

0 comments on commit 165facb

Please sign in to comment.