diff --git a/RELEASE_TESTING.MD b/RELEASE_TESTING.MD index c831c3ab5f..f8121e1c68 100644 --- a/RELEASE_TESTING.MD +++ b/RELEASE_TESTING.MD @@ -40,7 +40,7 @@ Before releasing a new version of KtLint, the release candidate is tested on a s ``` 4. Create an alias or script to run the latest released version of ktlint (note that this script will print the version as reference to which version is used): ```shell - alias ktlint-prev="ktlint-1.1.0 $@" # Replace with the latest release version + alias ktlint-prev="ktlint-1.2.1 $@" # Replace with the latest release version ``` Note that `~/git/ktlint` is the directory in which the ktlint project is checked out and that `~/git/ktlint/ktlint` refers to the `ktlint` CLI-module. 5. Create an alias or script to run the latest development-version of ktlint (note that this script will print the version and the datetime of compilation as reference to which version is used): @@ -84,52 +84,57 @@ Formatting projects in which ktlint is not used may result in a huge amount of f # 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 + # 2) Remove property below from graphql-kotlin + # disabled_rules=import-ordering + # And add properties below: # ktlint_standard_import-ordering = disabled # ktlint_standard_package-name = disabled ktlint_code_style = ktlint_official ktlint_experimental = enabled ktlint_standard = enabled - ktlint_standard_filename = disabled - ktlint_standard_no-wildcard-imports = disabled - ktlint_standard_function-naming = disabled - ktlint_standard_property-naming = disabled - ktlint_standard_class-naming = disabled - ktlint_standard_comment-wrapping = disabled ``` 2. Commit changes: ```shell ./exec-in-each-project.sh "git add --all && git commit -m \"Update .editorconfig to fallback to integration test settings\"" ``` -3. Format the sample projects with the *latest released* ktlint version: +3. Build baseline file with previous (*latest released*) version of Lint (when building with format the offsets of the error are not saved correctly in the baseline) ```shell rm baseline.xml + ktlint-prev --baseline=baseline.xml --relative # Do not call this command via the "./exec-in-each-project.sh" script. + ``` + Note: Ignore all output as this is the old version! +4. Format the sample projects with the previous (*latest released*) ktlint version: + ```shell ktlint-prev -F --baseline=baseline.xml --relative # Do not call this command via the "./exec-in-each-project.sh" script. ``` Note: Ignore all output as this is the old version! -4. Commit changes: +5. Commit changes: ```shell - ./exec-in-each-project.sh "git add --all && git commit -m \"Format with previous ktlint version -F\"" + ./exec-in-each-project.sh "git add --all && git commit -m \"Format with previous ktlint version (round #)\"" ``` - Repeat step 3 and 4 until no files are changed anymore. Although ktlint reruns up to 3 times in case new violations are introduced, it can still happen that not all violations have been fixed with a single invocation. -5. Check that besides the `baseline.xml` no files are changed (in step 3 and 4 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. + Repeat step 4 and 5 until no files are changed anymore. Although ktlint reruns up to 3 times in case new violations are introduced, it can still happen that not all violations have been fixed with a single invocation. +6. Check that besides the `baseline.xml` no files are changed (in step 4 and 5 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 status" ``` - The `baseline.xml` file should only contain errors which can not be autocorrected. -6. Lint with *latest development* version: +7. Rebuild baseline file with previous (*latest released*) ktlint (when building with format the offsets of the error are not saved correctly in the baseline) so that all violations are now stored in the baseline. Note the old `baseline.xml` still contains all errors which are already autocorrected. After running next command, only the error which can not be autocorrected with the previous ktlint version remain. ```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. + rm baseline.xml + ktlint-prev --baseline=baseline.xml --relative # Do not call this command via the "./exec-in-each-project.sh" script. ``` - or when lots are violations are reported: + Note: Ignore all output as this is the old version! +8. Lint with *latest development* version: ```shell - 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. + 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. ``` 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? -7. Format with *latest development* version: + * 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! + ```plain + Internal Error (...) in file '...' at position '0:0. Please create a ticket at https://github.com/pinterest/ktlint/issues ... + ``` +9. Format with *latest development* version: ```shell 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. ``` @@ -138,20 +143,21 @@ Formatting projects in which ktlint is not used may result in a huge amount of f ```plain Internal Error (...) in file '...' at position '0:0. Please create a ticket at https://github.com/pinterest/ktlint/issues ... ``` - * Ideally, no violations are shown. This means that all violations have been autocorrected. + * Usually it helps to disable all rules that emit violations, except one of those rules. In this way it is possible to evaluate the changes rule by rule. + * Ideally, no violations are shown. This means that all violations have been autocorrected. Note that violations might pop up that previously were suppressed via the baseline. This can happen as due to code changes, the references in the baseline.xml no longer match with the positions where they occur. First check the code changes, and regenerating the baseline before verifying the next can be a helpful approach. * 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. -8. 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\"" - ``` -9. Rerun lint with *latest development* version and create a new baseline: +10. 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 - rm baseline.xml - 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. + ./exec-in-each-project.sh "git add --all && git commit -m \"Fixed with latest development version\"" ``` - No violations, except error that can not be autocorrected, should be expected. -10. Rerun with *latest development* version and verify that no violations are reported: +11. Rerun lint with *latest development* version and create a new baseline: + ```shell + rm baseline.xml + 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. + ``` + No violations, except error that can not be autocorrected, should be expected. +12. Rerun with *latest development* version and verify that no violations are reported: ```shell ktlint-dev --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. ``` diff --git a/ktlint-rule-engine/src/main/kotlin/com/pinterest/ktlint/rule/engine/internal/CodeFormatter.kt b/ktlint-rule-engine/src/main/kotlin/com/pinterest/ktlint/rule/engine/internal/CodeFormatter.kt index e3e9b82ceb..58d3ea5e90 100644 --- a/ktlint-rule-engine/src/main/kotlin/com/pinterest/ktlint/rule/engine/internal/CodeFormatter.kt +++ b/ktlint-rule-engine/src/main/kotlin/com/pinterest/ktlint/rule/engine/internal/CodeFormatter.kt @@ -59,7 +59,7 @@ internal class CodeFormatter( } formatRunCount++ } while (mutated && formatRunCount < maxFormatRunsPerFile) - if (mutated && formatRunCount == maxFormatRunsPerFile) { + if (mutated && formatRunCount == maxFormatRunsPerFile && autocorrectHandler !is NoneAutocorrectHandler) { // It is unknown if the last format run introduces new lint violations which can be autocorrected. So run lint once more // so that the user can be informed about this correctly. lintAfterFormat().also { diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/AnnotationSpacingRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/AnnotationSpacingRule.kt index 634bdc422d..ae1709a2b2 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/AnnotationSpacingRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/AnnotationSpacingRule.kt @@ -15,6 +15,7 @@ import com.pinterest.ktlint.rule.engine.core.api.nextCodeSibling import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.nextSibling import com.pinterest.ktlint.rule.engine.core.api.prevSibling +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace @@ -97,11 +98,11 @@ public class AnnotationSpacingRule : StandardRule("annotation-spacing") { // 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.prevSibling { it.isWhiteSpace() }?.remove() + eolComment.nextSibling { it.isWhiteSpace() }?.remove() eolComment.treeParent?.removeChild(eolComment) } else { - node.nextSibling { it.isWhiteSpace() }?.let { it.treeParent?.removeChild(it) } + node.nextSibling { it.isWhiteSpace() }?.remove() } node.treeParent.removeChild(node) diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ChainMethodContinuationRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ChainMethodContinuationRule.kt index e7e51314b4..4b0a48e54e 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ChainMethodContinuationRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ChainMethodContinuationRule.kt @@ -53,6 +53,7 @@ import com.pinterest.ktlint.rule.engine.core.api.nextSibling import com.pinterest.ktlint.rule.engine.core.api.prevCodeSibling import com.pinterest.ktlint.rule.engine.core.api.prevLeaf import com.pinterest.ktlint.rule.engine.core.api.prevSibling +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.rule.engine.core.api.upsertWhitespaceBeforeMe import com.pinterest.ktlint.ruleset.standard.StandardRule import org.ec4j.core.model.PropertyType @@ -368,9 +369,7 @@ public class ChainMethodContinuationRule : .takeIf { it.isWhiteSpaceWithNewline() } ?.let { whiteSpace -> emit(whiteSpace.startOffset - 1, "Unexpected newline after '${chainOperator.text}'", true) - .ifAutocorrectAllowed { - whiteSpace.treeParent.removeChild(whiteSpace) - } + .ifAutocorrectAllowed { whiteSpace.remove() } } } } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ChainWrappingRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ChainWrappingRule.kt index 9b7555c2b3..cf0b7fbd75 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ChainWrappingRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ChainWrappingRule.kt @@ -35,6 +35,7 @@ import com.pinterest.ktlint.rule.engine.core.api.nextSibling import com.pinterest.ktlint.rule.engine.core.api.prevCodeLeaf import com.pinterest.ktlint.rule.engine.core.api.prevCodeSibling import com.pinterest.ktlint.rule.engine.core.api.prevLeaf +import com.pinterest.ktlint.rule.engine.core.api.remove 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 @@ -96,7 +97,7 @@ public class ChainWrappingRule : node.upsertWhitespaceBeforeMe(indentConfig.childIndentOf(node)) node.upsertWhitespaceAfterMe(" ") } else { - node.treeParent.removeChild(node) + node.remove() (nextLeaf as LeafElement).rawInsertAfterMe(node as LeafElement) } } @@ -150,12 +151,12 @@ public class ChainWrappingRule : operationReference .prevCodeSibling() ?.nextSibling() - operationReference.treeParent.removeChild(operationReference) + operationReference.remove() insertBeforeSibling?.treeParent?.addChild(operationReference, insertBeforeSibling) node.treeParent.upsertWhitespaceBeforeMe(" ") } else { val insertionPoint = prevLeaf.prevCodeLeaf() as LeafPsiElement - (node as LeafPsiElement).treeParent.removeChild(node) + (node as LeafPsiElement).remove() insertionPoint.rawInsertAfterMe(node) (insertionPoint as ASTNode).upsertWhitespaceAfterMe(" ") } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ClassSignatureRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ClassSignatureRule.kt index c2d074a3c7..1cf50a8080 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ClassSignatureRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/ClassSignatureRule.kt @@ -47,6 +47,7 @@ import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.prevCodeSibling import com.pinterest.ktlint.rule.engine.core.api.prevLeaf import com.pinterest.ktlint.rule.engine.core.api.prevSibling +import com.pinterest.ktlint.rule.engine.core.api.remove 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 @@ -268,9 +269,7 @@ public class ClassSignatureRule : }?.let { parameterList -> if (!dryRun) { emit(parameterList.startOffset, "No parenthesis expected", true) - .ifAutocorrectAllowed { - parameterList.treeParent.removeChild(parameterList) - } + .ifAutocorrectAllowed { parameterList.remove() } } else { whiteSpaceCorrection -= parameterList.textLength } @@ -323,9 +322,7 @@ public class ClassSignatureRule : firstParameter!!.startOffset, "No whitespace expected between opening parenthesis and first parameter name", true, - ).ifAutocorrectAllowed { - whiteSpaceBeforeIdentifier.treeParent.removeChild(whiteSpaceBeforeIdentifier) - } + ).ifAutocorrectAllowed { whiteSpaceBeforeIdentifier.remove() } } else { whiteSpaceCorrection -= whiteSpaceBeforeIdentifier.textLength } @@ -434,9 +431,7 @@ public class ClassSignatureRule : whiteSpaceBeforeClosingParenthesis.startOffset, "No whitespace expected between last parameter and closing parenthesis", true, - ).ifAutocorrectAllowed { - whiteSpaceBeforeClosingParenthesis.treeParent.removeChild(whiteSpaceBeforeClosingParenthesis) - } + ).ifAutocorrectAllowed { whiteSpaceBeforeClosingParenthesis.remove() } } else { whiteSpaceCorrection -= whiteSpaceBeforeClosingParenthesis.textLength } @@ -582,9 +577,7 @@ public class ClassSignatureRule : .findChildByType(WHITE_SPACE) ?.let { whitespace -> emit(whitespace.startOffset, "No whitespace expected", true) - .ifAutocorrectAllowed { - whitespace.treeParent.removeChild(whitespace) - } + .ifAutocorrectAllowed { whitespace.remove() } } } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FinalNewlineRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FinalNewlineRule.kt index f0881263da..227c154790 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FinalNewlineRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FinalNewlineRule.kt @@ -8,6 +8,7 @@ import com.pinterest.ktlint.rule.engine.core.api.editorconfig.EditorConfig import com.pinterest.ktlint.rule.engine.core.api.editorconfig.INSERT_FINAL_NEWLINE_PROPERTY import com.pinterest.ktlint.rule.engine.core.api.ifAutocorrectAllowed import com.pinterest.ktlint.rule.engine.core.api.isRoot +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace @@ -45,9 +46,7 @@ public class FinalNewlineRule : } else { if (lastNode is PsiWhiteSpace && lastNode.textContains('\n')) { emit(lastNode.startOffset, "Redundant newline (\\n) at the end of file", true) - .ifAutocorrectAllowed { - lastNode.node.treeParent.removeChild(lastNode.node) - } + .ifAutocorrectAllowed { lastNode.node.remove() } } } } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionLiteralRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionLiteralRule.kt index 805fe9329c..e183e28894 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionLiteralRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionLiteralRule.kt @@ -40,6 +40,7 @@ import com.pinterest.ktlint.rule.engine.core.api.parent import com.pinterest.ktlint.rule.engine.core.api.prevCodeSibling import com.pinterest.ktlint.rule.engine.core.api.prevLeaf import com.pinterest.ktlint.rule.engine.core.api.prevSibling +import com.pinterest.ktlint.rule.engine.core.api.remove 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 @@ -372,8 +373,8 @@ public class FunctionLiteralRule : arrow .nextSibling() .takeIf { it.isWhiteSpace() } - ?.let { it.treeParent.removeChild(it) } - arrow.treeParent.removeChild(arrow) + ?.remove() + arrow.remove() } } } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionSignatureRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionSignatureRule.kt index 79961fc8b8..be2158d987 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionSignatureRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionSignatureRule.kt @@ -44,6 +44,7 @@ import com.pinterest.ktlint.rule.engine.core.api.nextCodeSibling import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.prevLeaf import com.pinterest.ktlint.rule.engine.core.api.prevSibling +import com.pinterest.ktlint.rule.engine.core.api.remove 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 @@ -339,9 +340,7 @@ public class FunctionSignatureRule : whiteSpace.startOffset, "No whitespace expected in empty parameter list", true, - ).ifAutocorrectAllowed { - whiteSpace.treeParent.removeChild(whiteSpace) - } + ).ifAutocorrectAllowed { whiteSpace.remove() } } else { whiteSpaceCorrection -= whiteSpace.textLength } @@ -393,9 +392,7 @@ public class FunctionSignatureRule : firstParameter!!.startOffset, "No whitespace expected between opening parenthesis and first parameter name", true, - ).ifAutocorrectAllowed { - whiteSpaceBeforeIdentifier.treeParent.removeChild(whiteSpaceBeforeIdentifier) - } + ).ifAutocorrectAllowed { whiteSpaceBeforeIdentifier.remove() } } else { whiteSpaceCorrection -= whiteSpaceBeforeIdentifier.textLength } @@ -509,9 +506,7 @@ public class FunctionSignatureRule : whiteSpaceBeforeClosingParenthesis.startOffset, "No whitespace expected between last parameter and closing parenthesis", true, - ).ifAutocorrectAllowed { - whiteSpaceBeforeClosingParenthesis.treeParent.removeChild(whiteSpaceBeforeClosingParenthesis) - } + ).ifAutocorrectAllowed { whiteSpaceBeforeClosingParenthesis.remove() } } else { whiteSpaceCorrection -= whiteSpaceBeforeClosingParenthesis.textLength } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionTypeReferenceSpacingRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionTypeReferenceSpacingRule.kt index 2792dd0450..566ef4979b 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionTypeReferenceSpacingRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/FunctionTypeReferenceSpacingRule.kt @@ -11,6 +11,7 @@ import com.pinterest.ktlint.rule.engine.core.api.SinceKtlint import com.pinterest.ktlint.rule.engine.core.api.SinceKtlint.Status.EXPERIMENTAL import com.pinterest.ktlint.rule.engine.core.api.ifAutocorrectAllowed import com.pinterest.ktlint.rule.engine.core.api.nextSibling +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode @@ -69,9 +70,7 @@ public class FunctionTypeReferenceSpacingRule : StandardRule("function-type-refe ) { if (node.elementType == WHITE_SPACE && node.text.isNotEmpty()) { emit(node.startOffset, "Unexpected whitespace", true) - .ifAutocorrectAllowed { - node.treeParent.removeChild(node) - } + .ifAutocorrectAllowed { node.remove() } } } } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/IndentationRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/IndentationRule.kt index 57d77f30f3..b50be93c1a 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/IndentationRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/IndentationRule.kt @@ -117,6 +117,7 @@ import com.pinterest.ktlint.rule.engine.core.api.prevCodeLeaf import com.pinterest.ktlint.rule.engine.core.api.prevCodeSibling import com.pinterest.ktlint.rule.engine.core.api.prevLeaf import com.pinterest.ktlint.rule.engine.core.api.prevSibling +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.ruleset.standard.StandardRule import io.github.oshai.kotlinlogging.KotlinLogging import org.jetbrains.kotlin.com.intellij.lang.ASTNode @@ -194,7 +195,7 @@ public class IndentationRule : ?.takeIf { it.isWhiteSpaceWithoutNewline() } ?.let { whitespaceWithoutNewline -> emit(node.startOffset, "Unexpected indentation", true) - .ifAutocorrectAllowed { whitespaceWithoutNewline.treeParent.removeChild(whitespaceWithoutNewline) } + .ifAutocorrectAllowed { whitespaceWithoutNewline.remove() } } indentContextStack.addLast(startNoIndentZone(node)) } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoEmptyClassBodyRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoEmptyClassBodyRule.kt index 3fbabcd793..ed68b38340 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoEmptyClassBodyRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoEmptyClassBodyRule.kt @@ -12,6 +12,7 @@ import com.pinterest.ktlint.rule.engine.core.api.children import com.pinterest.ktlint.rule.engine.core.api.ifAutocorrectAllowed import com.pinterest.ktlint.rule.engine.core.api.isPartOf import com.pinterest.ktlint.rule.engine.core.api.nextLeaf +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.psi.KtObjectLiteralExpression @@ -39,10 +40,10 @@ public class NoEmptyClassBodyRule : StandardRule("no-empty-class-body") { val prevNode = node.treePrev if (prevNode.elementType == WHITE_SPACE) { // remove space between declaration and block - prevNode.treeParent.removeChild(prevNode) + prevNode.remove() } // remove block - node.treeParent.removeChild(node) + node.remove() } } } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoSemicolonsRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoSemicolonsRule.kt index 1f82840129..5ad9bb779f 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoSemicolonsRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoSemicolonsRule.kt @@ -16,6 +16,7 @@ import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.parent import com.pinterest.ktlint.rule.engine.core.api.prevCodeLeaf import com.pinterest.ktlint.rule.engine.core.api.prevLeaf +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.rule.engine.core.api.upsertWhitespaceAfterMe import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode @@ -53,9 +54,9 @@ public class NoSemicolonsRule : emit(node.startOffset, "Unnecessary semicolon", true) .ifAutocorrectAllowed { val prevLeaf = node.prevLeaf(true) - node.treeParent.removeChild(node) + node.remove() if (prevLeaf.isWhiteSpace() && (nextLeaf == null || nextLeaf.isWhiteSpace())) { - node.treeParent.removeChild(prevLeaf!!) + prevLeaf?.remove() } } } else if (nextLeaf !is PsiWhiteSpace) { diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoUnusedImportsRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoUnusedImportsRule.kt index 9409ecb331..9300369cc0 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoUnusedImportsRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/NoUnusedImportsRule.kt @@ -21,6 +21,7 @@ import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.nextSibling import com.pinterest.ktlint.rule.engine.core.api.prevLeaf import com.pinterest.ktlint.rule.engine.core.api.prevSibling +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.rule.engine.core.util.safeAs import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode @@ -172,7 +173,7 @@ public class NoUnusedImportsRule : StandardRule("no-unused-imports") { if (node.prevLeaf() == null) { // Also it was the first import, and it is not preceded by any other node containing some text. So // all whitespace until the next is redundant - whitespace.treeParent.removeChild(whitespace) + whitespace.remove() } else { val textAfterFirstNewline = whitespace @@ -186,9 +187,7 @@ public class NoUnusedImportsRule : StandardRule("no-unused-imports") { } else { nextSibling .takeIf { it.isWhiteSpaceWithNewline() } - ?.let { whitespace -> - whitespace.treeParent.removeChild(whitespace) - } + ?.remove() } importDirective.delete() } @@ -217,7 +216,7 @@ public class NoUnusedImportsRule : StandardRule("no-unused-imports") { treeParent.lastChildNode == this -> { prevSibling() ?.takeIf { it.isWhiteSpaceWithNewline() } - ?.let { it.treeParent.removeChild(it) } + ?.remove() } else -> { @@ -226,7 +225,7 @@ public class NoUnusedImportsRule : StandardRule("no-unused-imports") { ?.let { it.treeParent.removeChild(it) } } } - treeParent.removeChild(this) + this.remove() } private fun ASTNode.isExpressionForStaticImportWithExistingParentImport(): Boolean { diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundAngleBracketsRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundAngleBracketsRule.kt index e49113f200..8821f79700 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundAngleBracketsRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundAngleBracketsRule.kt @@ -14,6 +14,7 @@ import com.pinterest.ktlint.rule.engine.core.api.ifAutocorrectAllowed import com.pinterest.ktlint.rule.engine.core.api.isWhiteSpaceWithoutNewline import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.prevLeaf +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafElement @@ -36,9 +37,7 @@ public class SpacingAroundAngleBracketsRule : StandardRule("spacing-around-angle // 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) - .ifAutocorrectAllowed { - beforeLeftAngle.treeParent.removeChild(beforeLeftAngle) - } + .ifAutocorrectAllowed { beforeLeftAngle.remove() } } } @@ -49,7 +48,7 @@ public class SpacingAroundAngleBracketsRule : StandardRule("spacing-around-angle emit(afterLeftAngle.startOffset, "Unexpected spacing after \"<\"", true) .ifAutocorrectAllowed { // when spacing does not include any new lines, e.g. Map< String, Int> - afterLeftAngle.treeParent.removeChild(afterLeftAngle) + afterLeftAngle.remove() } } else { // when spacing contains at least one new line, e.g. @@ -79,7 +78,7 @@ public class SpacingAroundAngleBracketsRule : StandardRule("spacing-around-angle emit(beforeRightAngle.startOffset, "Unexpected spacing before \">\"", true) .ifAutocorrectAllowed { // when spacing does not include any new lines, e.g. Map - beforeRightAngle.treeParent.removeChild(beforeRightAngle) + beforeRightAngle.remove() } } else { // when spacing contains at least one new line, e.g. diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundColonRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundColonRule.kt index c79581ec9e..4e71d6dfff 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundColonRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundColonRule.kt @@ -15,6 +15,7 @@ import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.nextSibling import com.pinterest.ktlint.rule.engine.core.api.prevLeaf import com.pinterest.ktlint.rule.engine.core.api.prevSibling +import com.pinterest.ktlint.rule.engine.core.api.remove 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 @@ -74,7 +75,7 @@ public class SpacingAroundColonRule : StandardRule("colon-spacing") { node.treeParent.addChild(it, treeNext) } if (treeNext.isWhiteSpace()) { - equalsSignElement.treeParent.removeChild(treeNext) + treeNext.remove() } Unit } @@ -91,11 +92,11 @@ public class SpacingAroundColonRule : StandardRule("colon-spacing") { prevNonCodeElements .let { if (it.first().isWhiteSpace()) { - blockElement.treeParent.removeChild(it.first()) + it.first().remove() it.drop(1) } if (it.last().isWhiteSpaceWithNewline()) { - blockElement.treeParent.removeChild(it.last()) + it.last().remove() it.dropLast(1) } else { it @@ -112,7 +113,7 @@ public class SpacingAroundColonRule : StandardRule("colon-spacing") { node.treeParent.addChild(it, nextLeaf) } if (nextLeaf != null && nextLeaf.isWhiteSpace()) { - node.treeParent.removeChild(nextLeaf) + nextLeaf.remove() } } @@ -121,7 +122,7 @@ public class SpacingAroundColonRule : StandardRule("colon-spacing") { if (node.spacingBefore) { (prevLeaf as LeafPsiElement).rawReplaceWithText(" ") } else { - prevLeaf.treeParent.removeChild(prevLeaf) + prevLeaf.remove() } node.upsertWhitespaceAfterMe(text) } @@ -139,9 +140,7 @@ public class SpacingAroundColonRule : StandardRule("colon-spacing") { .ifAutocorrectAllowed { node .prevSibling() - ?.let { prevSibling -> - prevSibling.treeParent.removeChild(prevSibling) - } + ?.remove() } } if (node.nextSibling().isWhiteSpaceWithoutNewline() && node.spacingAfter) { @@ -149,9 +148,7 @@ public class SpacingAroundColonRule : StandardRule("colon-spacing") { .ifAutocorrectAllowed { node .nextSibling() - ?.let { nextSibling -> - nextSibling.treeParent.removeChild(nextSibling) - } + ?.remove() } } } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundCommaRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundCommaRule.kt index a3c59d55df..b7df7e922c 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundCommaRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundCommaRule.kt @@ -14,6 +14,7 @@ import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.nextSibling import com.pinterest.ktlint.rule.engine.core.api.prevCodeLeaf import com.pinterest.ktlint.rule.engine.core.api.prevLeaf +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.rule.engine.core.api.upsertWhitespaceAfterMe import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode @@ -43,11 +44,11 @@ public class SpacingAroundCommaRule : StandardRule("comma-spacing") { previousStatement.treeParent.addChild(node.clone(), previousStatement.nextSibling()) val nextLeaf = node.nextLeaf() if (nextLeaf is PsiWhiteSpace) { - nextLeaf.treeParent.removeChild(nextLeaf) + nextLeaf.remove() } - node.treeParent.removeChild(node) + node.remove() } else { - prevLeaf.treeParent.removeChild(prevLeaf) + prevLeaf.remove() } } } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundCurlyRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundCurlyRule.kt index 3f5df33ee1..a4cc783dcd 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundCurlyRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundCurlyRule.kt @@ -37,6 +37,7 @@ import com.pinterest.ktlint.rule.engine.core.api.isWhiteSpaceWithoutNewline import com.pinterest.ktlint.rule.engine.core.api.leavesIncludingSelf import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.prevLeaf +import com.pinterest.ktlint.rule.engine.core.api.remove 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 @@ -98,9 +99,7 @@ public class SpacingAroundCurlyRule : } == true ) { emit(node.startOffset, "Unexpected space before \"${node.text}\"", true) - .ifAutocorrectAllowed { - prevLeaf.node.treeParent.removeChild(prevLeaf.node) - } + .ifAutocorrectAllowed { prevLeaf.node.remove() } } prevLeaf ?.takeIf { it.isWhiteSpaceWithNewline() } @@ -140,9 +139,7 @@ public class SpacingAroundCurlyRule : ?.takeIf { shouldNotToBeSeparatedBySpace(it.nextLeaf()) } ?.let { leaf -> emit(node.startOffset, "Unexpected space after \"${node.text}\"", true) - .ifAutocorrectAllowed { - leaf.treeParent.removeChild(leaf) - } + .ifAutocorrectAllowed { leaf.remove() } } } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundDotRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundDotRule.kt index 33a7278713..76a7f27da3 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundDotRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundDotRule.kt @@ -9,6 +9,7 @@ import com.pinterest.ktlint.rule.engine.core.api.isPartOfComment import com.pinterest.ktlint.rule.engine.core.api.isPartOfString import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.prevLeaf +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace @@ -25,14 +26,14 @@ public class SpacingAroundDotRule : StandardRule("dot-spacing") { if (prevLeaf is PsiWhiteSpace && !prevLeaf.textContains('\n')) { emit(prevLeaf.startOffset, "Unexpected spacing before \"${node.text}\"", true) .ifAutocorrectAllowed { - prevLeaf.node.treeParent.removeChild(prevLeaf.node) + prevLeaf.node.remove() } } val nextLeaf = node.nextLeaf() if (nextLeaf is PsiWhiteSpace) { emit(nextLeaf.startOffset, "Unexpected spacing after \"${node.text}\"", true) .ifAutocorrectAllowed { - nextLeaf.node.treeParent.removeChild(nextLeaf.node) + nextLeaf.node.remove() } } } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundDoubleColonRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundDoubleColonRule.kt index a1c4d6dfe7..3281926526 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundDoubleColonRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundDoubleColonRule.kt @@ -11,6 +11,7 @@ import com.pinterest.ktlint.rule.engine.core.api.ifAutocorrectAllowed import com.pinterest.ktlint.rule.engine.core.api.isPartOf import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.prevLeaf +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace @@ -48,7 +49,7 @@ public class SpacingAroundDoubleColonRule : StandardRule("double-colon-spacing") emit(node.startOffset, "Unexpected spacing around \"${node.text}\"", true) .ifAutocorrectAllowed { prevLeaf!!.removeSelf(removeSingleWhiteSpace) - nextLeaf!!.treeParent.removeChild(nextLeaf) + nextLeaf!!.remove() } } @@ -61,9 +62,7 @@ public class SpacingAroundDoubleColonRule : StandardRule("double-colon-spacing") spacingAfter -> { emit(nextLeaf!!.startOffset, "Unexpected spacing after \"${node.text}\"", true) - .ifAutocorrectAllowed { - nextLeaf.treeParent.removeChild(nextLeaf) - } + .ifAutocorrectAllowed { nextLeaf.remove() } } } } @@ -73,7 +72,7 @@ public class SpacingAroundDoubleColonRule : StandardRule("double-colon-spacing") if (removeSingleWhiteSpace) { (this as LeafPsiElement).rawReplaceWithText(text.substring(0, textLength - 1)) } else { - treeParent.removeChild(this) + this.remove() } } } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundKeywordRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundKeywordRule.kt index eb6fd39197..0b75319265 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundKeywordRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundKeywordRule.kt @@ -20,6 +20,7 @@ import com.pinterest.ktlint.rule.engine.core.api.SinceKtlint.Status.STABLE import com.pinterest.ktlint.rule.engine.core.api.ifAutocorrectAllowed import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.prevLeaf +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.rule.engine.core.api.upsertWhitespaceAfterMe import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode @@ -65,9 +66,7 @@ public class SpacingAroundKeywordRule : StandardRule("keyword-spacing") { val nextLeaf = node.nextLeaf() if (parent is KtPropertyAccessor && parent.hasBody() && nextLeaf != null) { emit(node.startOffset, "Unexpected spacing after \"${node.text}\"", true) - .ifAutocorrectAllowed { - nextLeaf.treeParent.removeChild(nextLeaf) - } + .ifAutocorrectAllowed { nextLeaf.remove() } } } if (noLFBeforeSet.contains(node.elementType)) { diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundParensRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundParensRule.kt index 171007e505..a48f70df15 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundParensRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundParensRule.kt @@ -2,6 +2,7 @@ package com.pinterest.ktlint.ruleset.standard.rules import com.pinterest.ktlint.rule.engine.core.api.AutocorrectDecision import com.pinterest.ktlint.rule.engine.core.api.ElementType.BLOCK_COMMENT +import com.pinterest.ktlint.rule.engine.core.api.ElementType.CONSTRUCTOR_CALLEE import com.pinterest.ktlint.rule.engine.core.api.ElementType.EOL_COMMENT import com.pinterest.ktlint.rule.engine.core.api.ElementType.FUNCTION_TYPE import com.pinterest.ktlint.rule.engine.core.api.ElementType.IDENTIFIER @@ -10,19 +11,23 @@ import com.pinterest.ktlint.rule.engine.core.api.ElementType.LPAR import com.pinterest.ktlint.rule.engine.core.api.ElementType.PRIMARY_CONSTRUCTOR import com.pinterest.ktlint.rule.engine.core.api.ElementType.RPAR import com.pinterest.ktlint.rule.engine.core.api.ElementType.SUPER_KEYWORD -import com.pinterest.ktlint.rule.engine.core.api.ElementType.TYPE_ARGUMENT_LIST +import com.pinterest.ktlint.rule.engine.core.api.ElementType.SUPER_TYPE_CALL_ENTRY import com.pinterest.ktlint.rule.engine.core.api.ElementType.VALUE_ARGUMENT_LIST import com.pinterest.ktlint.rule.engine.core.api.ElementType.VALUE_PARAMETER_LIST import com.pinterest.ktlint.rule.engine.core.api.RuleId import com.pinterest.ktlint.rule.engine.core.api.SinceKtlint import com.pinterest.ktlint.rule.engine.core.api.SinceKtlint.Status.STABLE import com.pinterest.ktlint.rule.engine.core.api.ifAutocorrectAllowed +import com.pinterest.ktlint.rule.engine.core.api.isWhiteSpace +import com.pinterest.ktlint.rule.engine.core.api.isWhiteSpaceWithNewline import com.pinterest.ktlint.rule.engine.core.api.isWhiteSpaceWithoutNewline import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.prevLeaf +import com.pinterest.ktlint.rule.engine.core.api.prevSibling +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode -import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace +import org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet /** * Ensures there are no extra spaces around parentheses. @@ -36,65 +41,140 @@ public class SpacingAroundParensRule : StandardRule("paren-spacing") { emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> AutocorrectDecision, ) { if (node.elementType == LPAR || node.elementType == RPAR) { - val prevLeaf = node.prevLeaf() - val nextLeaf = node.nextLeaf() - val spacingBefore = - if (node.elementType == LPAR) { - prevLeaf is PsiWhiteSpace && - !prevLeaf.textContains('\n') && - ( - prevLeaf.prevLeaf()?.elementType == IDENTIFIER && - // val foo: @Composable () -> Unit - node.treeParent?.treeParent?.elementType != FUNCTION_TYPE || - // Super keyword needs special-casing - prevLeaf.prevLeaf()?.elementType == SUPER_KEYWORD || - prevLeaf.prevLeaf()?.treeParent?.elementType == PRIMARY_CONSTRUCTOR || - prevLeaf.prevLeaf()?.treeParent?.elementType == TYPE_ARGUMENT_LIST - ) && - ( - node.treeParent?.elementType == VALUE_PARAMETER_LIST || - node.treeParent?.elementType == VALUE_ARGUMENT_LIST - ) - } else { - prevLeaf.isWhiteSpaceWithoutNewline() && prevLeaf?.prevLeaf()?.elementType != LPAR - } - val spacingAfter = - if (node.elementType == LPAR) { - nextLeaf is PsiWhiteSpace && - (!nextLeaf.textContains('\n') || nextLeaf.nextLeaf()?.elementType == RPAR) && - !nextLeaf.isNextLeafAComment() - } else { - nextLeaf.isWhiteSpaceWithoutNewline() && nextLeaf?.nextLeaf()?.elementType == RPAR - } + val spacingBefore = node.isUnexpectedSpacingBeforeParenthesis() + val spacingAfter = node.isUnexpectedSpacingAfterParenthesis() when { - spacingBefore && spacingAfter -> { - emit(node.startOffset, "Unexpected spacing around \"${node.text}\"", true) - .ifAutocorrectAllowed { - prevLeaf!!.treeParent.removeChild(prevLeaf) - nextLeaf!!.treeParent.removeChild(nextLeaf) - } - } - - spacingBefore -> { - emit(prevLeaf!!.startOffset, "Unexpected spacing before \"${node.text}\"", true) - .ifAutocorrectAllowed { - prevLeaf.treeParent.removeChild(prevLeaf) - } - } - - spacingAfter -> { - emit(node.startOffset + 1, "Unexpected spacing after \"${node.text}\"", true) - .ifAutocorrectAllowed { - nextLeaf!!.treeParent.removeChild(nextLeaf) - } - } + spacingBefore && spacingAfter -> node.fixUnexpectedSpacingAround(emit) + spacingBefore -> node.fixUnexpectedSpacingBefore(emit) + spacingAfter -> node.fixUnexpectSpacingAfter(emit) } } } - private fun ASTNode.isNextLeafAComment(): Boolean { - val commentTypes = setOf(EOL_COMMENT, BLOCK_COMMENT, KDOC_START) - return nextLeaf()?.elementType in commentTypes + private fun ASTNode.isUnexpectedSpacingBeforeParenthesis(): Boolean = + when { + !prevLeaf().isWhiteSpaceWithoutNewline() -> false + + elementType == LPAR -> { + treeParent?.elementType in elementListTokenSet && + ( + isUnexpectedSpacingBetweenIdentifierAndElementList() || + isUnexpectedSpacingInCallToSuper() || + isUnexpectedSpacingInExplicitConstructor() || + isUnexpectedSpacingInSuperTypeCallEntry() + ) + } + + elementType == RPAR -> { + // Disallow: + // val foo = fn("foo" ) + // val foo = fn( ) + prevLeaf()?.prevSibling()?.elementType != LPAR + } + + else -> false + } + + private fun ASTNode.isUnexpectedSpacingBetweenIdentifierAndElementList() = + prevLeaf() + ?.takeIf { it.isWhiteSpace() } + ?.takeIf { + // Disallow: + // fun foo () {} + // and + // @Deprecated ("bar) + // fun foo() {} + it.prevLeaf()?.elementType == IDENTIFIER + }?.let { + // But do allow: + // val foo: @Composable () -> Unit + treeParent?.treeParent?.elementType != FUNCTION_TYPE + } + ?: false + + private fun ASTNode.isUnexpectedSpacingInCallToSuper() = + prevLeaf() + ?.takeIf { it.isWhiteSpace() } + ?.let { + // Disallow: + // class Foo : Bar { + // constructor(string: String) : super () + // } + it.prevLeaf()?.elementType == SUPER_KEYWORD + } + ?: false + + private fun ASTNode.isUnexpectedSpacingInExplicitConstructor() = + prevLeaf() + ?.takeIf { it.isWhiteSpace() } + ?.let { + // Disallow: + // class Foo constructor () + it.prevLeaf()?.treeParent?.elementType == PRIMARY_CONSTRUCTOR + } + ?: false + + private fun ASTNode.isUnexpectedSpacingInSuperTypeCallEntry() = + prevLeaf() + ?.takeIf { it.isWhiteSpace() } + ?.let { + // Disallow: + // class Foo : Bar ("test") + // class Foo : Bar ("test") + treeParent.treeParent.elementType == SUPER_TYPE_CALL_ENTRY && + it.prevSibling()?.elementType == CONSTRUCTOR_CALLEE + } + ?: false + + private fun ASTNode.isUnexpectedSpacingAfterParenthesis(): Boolean = + takeIf { elementType == LPAR } + ?.nextLeaf() + ?.takeUnless { it.isNextLeafAComment() } + ?.let { it.isUnexpectedSpaceAfterLpar() || it.isUnexpectedNewlineAfterLpar() } + ?: false + + private fun ASTNode.isUnexpectedSpaceAfterLpar() = + // Disallow: + // val foo = fn( ) + // val foo = fn( "bar") + // val foo = ( (1 + 2) / 3) + isWhiteSpaceWithoutNewline() + + private fun ASTNode.isUnexpectedNewlineAfterLpar() = + // Disallow: + // val foo = fn( + // ) + isWhiteSpaceWithNewline() && nextLeaf()?.elementType == RPAR + + private fun ASTNode.isNextLeafAComment(): Boolean = nextLeaf()?.elementType in commentTypes + + private fun ASTNode.fixUnexpectedSpacingAround( + emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> AutocorrectDecision, + ) { + emit(startOffset, "Unexpected spacing around \"$text\"", true) + .ifAutocorrectAllowed { + prevLeaf()!!.remove() + nextLeaf()!!.remove() + } + } + + private fun ASTNode.fixUnexpectedSpacingBefore( + emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> AutocorrectDecision, + ) { + emit(prevLeaf()!!.startOffset, "Unexpected spacing before \"${text}\"", true) + .ifAutocorrectAllowed { prevLeaf()?.remove() } + } + + private fun ASTNode.fixUnexpectSpacingAfter( + emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> AutocorrectDecision, + ) { + emit(startOffset + 1, "Unexpected spacing after \"$text\"", true) + .ifAutocorrectAllowed { nextLeaf()!!.remove() } + } + + private companion object { + val elementListTokenSet = TokenSet.create(VALUE_PARAMETER_LIST, VALUE_ARGUMENT_LIST) + val commentTypes = TokenSet.create(EOL_COMMENT, BLOCK_COMMENT, KDOC_START) } } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundRangeOperatorRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundRangeOperatorRule.kt index 090e5fc2a7..d3eca90a05 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundRangeOperatorRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundRangeOperatorRule.kt @@ -9,6 +9,7 @@ import com.pinterest.ktlint.rule.engine.core.api.SinceKtlint.Status.STABLE import com.pinterest.ktlint.rule.engine.core.api.ifAutocorrectAllowed import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.prevLeaf +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace @@ -27,23 +28,19 @@ public class SpacingAroundRangeOperatorRule : StandardRule("range-spacing") { prevLeaf is PsiWhiteSpace && nextLeaf is PsiWhiteSpace -> { emit(node.startOffset, "Unexpected spacing around \"${node.elementTypeDescription()}\"", true) .ifAutocorrectAllowed { - prevLeaf.node.treeParent.removeChild(prevLeaf.node) - nextLeaf.node.treeParent.removeChild(nextLeaf.node) + prevLeaf.node.remove() + nextLeaf.node.remove() } } prevLeaf is PsiWhiteSpace -> { emit(prevLeaf.node.startOffset, "Unexpected spacing before \"${node.elementTypeDescription()}\"", true) - .ifAutocorrectAllowed { - prevLeaf.node.treeParent.removeChild(prevLeaf.node) - } + .ifAutocorrectAllowed { prevLeaf.node.remove() } } nextLeaf is PsiWhiteSpace -> { emit(nextLeaf.node.startOffset, "Unexpected spacing after \"${node.elementTypeDescription()}\"", true) - .ifAutocorrectAllowed { - nextLeaf.node.treeParent.removeChild(nextLeaf.node) - } + .ifAutocorrectAllowed { nextLeaf.node.remove() } } } } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundSquareBracketsRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundSquareBracketsRule.kt index 28f536d187..9cd51a39a1 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundSquareBracketsRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundSquareBracketsRule.kt @@ -13,6 +13,7 @@ import com.pinterest.ktlint.rule.engine.core.api.ifAutocorrectAllowed import com.pinterest.ktlint.rule.engine.core.api.isWhiteSpaceWithoutNewline import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.prevLeaf +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode @@ -78,23 +79,19 @@ public class SpacingAroundSquareBracketsRule : spacingBefore && spacingAfter -> { emit(node.startOffset, "Unexpected spacing around '${node.text}'", true) .ifAutocorrectAllowed { - prevLeaf!!.treeParent.removeChild(prevLeaf) - nextLeaf!!.treeParent.removeChild(nextLeaf) + prevLeaf?.remove() + nextLeaf?.remove() } } spacingBefore -> { emit(prevLeaf!!.startOffset, "Unexpected spacing before '${node.text}'", true) - .ifAutocorrectAllowed { - prevLeaf.treeParent.removeChild(prevLeaf) - } + .ifAutocorrectAllowed { prevLeaf.remove() } } spacingAfter -> { emit(node.startOffset + 1, "Unexpected spacing after '${node.text}'", true) - .ifAutocorrectAllowed { - nextLeaf!!.treeParent.removeChild(nextLeaf) - } + .ifAutocorrectAllowed { nextLeaf!!.remove() } } } } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingBetweenFunctionNameAndOpeningParenthesisRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingBetweenFunctionNameAndOpeningParenthesisRule.kt index e4b7c37df7..927caec1cb 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingBetweenFunctionNameAndOpeningParenthesisRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingBetweenFunctionNameAndOpeningParenthesisRule.kt @@ -9,6 +9,7 @@ import com.pinterest.ktlint.rule.engine.core.api.SinceKtlint.Status.EXPERIMENTAL import com.pinterest.ktlint.rule.engine.core.api.SinceKtlint.Status.STABLE import com.pinterest.ktlint.rule.engine.core.api.ifAutocorrectAllowed import com.pinterest.ktlint.rule.engine.core.api.nextSibling +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode @@ -26,9 +27,7 @@ public class SpacingBetweenFunctionNameAndOpeningParenthesisRule : StandardRule( ?.takeIf { it.elementType == WHITE_SPACE } ?.let { whiteSpace -> emit(whiteSpace.startOffset, "Unexpected whitespace", true) - .ifAutocorrectAllowed { - whiteSpace.treeParent.removeChild(whiteSpace) - } + .ifAutocorrectAllowed { whiteSpace.remove() } } } } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/StringTemplateRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/StringTemplateRule.kt index 68f3102e09..46efa5bbaf 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/StringTemplateRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/StringTemplateRule.kt @@ -10,6 +10,7 @@ import com.pinterest.ktlint.rule.engine.core.api.RuleId import com.pinterest.ktlint.rule.engine.core.api.SinceKtlint import com.pinterest.ktlint.rule.engine.core.api.SinceKtlint.Status.STABLE import com.pinterest.ktlint.rule.engine.core.api.ifAutocorrectAllowed +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode import org.jetbrains.kotlin.com.intellij.psi.PsiFileFactory @@ -56,7 +57,7 @@ public class StringTemplateRule : StandardRule("string-template") { .node .let { entryExpressionNode -> entryExpressionNode.treeParent.addChild(receiver.node, entryExpressionNode) - entryExpressionNode.treeParent.removeChild(entryExpressionNode) + entryExpressionNode.remove() } node .takeIf { it.isStringTemplate() } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TrailingCommaOnDeclarationSiteRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TrailingCommaOnDeclarationSiteRule.kt index 31ac49a2c2..c2a5a96e1c 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TrailingCommaOnDeclarationSiteRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TrailingCommaOnDeclarationSiteRule.kt @@ -29,6 +29,7 @@ import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.noNewLineInClosedRange import com.pinterest.ktlint.rule.engine.core.api.prevCodeLeaf import com.pinterest.ktlint.rule.engine.core.api.prevLeaf +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.rule.engine.core.api.upsertWhitespaceAfterMe import com.pinterest.ktlint.rule.engine.core.util.cast import com.pinterest.ktlint.ruleset.standard.StandardRule @@ -335,7 +336,7 @@ public class TrailingCommaOnDeclarationSiteRule : this.treeParent.addChild(PsiWhiteSpaceImpl(parentIndent), null) this.treeParent.addChild(LeafPsiElement(SEMICOLON, ";"), null) } - inspectNode.treeParent.removeChild(inspectNode) + inspectNode.remove() } else { inspectNode .prevCodeLeaf() diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TypeArgumentListSpacingRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TypeArgumentListSpacingRule.kt index 26059894aa..6cd0159ab2 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TypeArgumentListSpacingRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TypeArgumentListSpacingRule.kt @@ -19,6 +19,7 @@ import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.nextSibling import com.pinterest.ktlint.rule.engine.core.api.prevLeaf import com.pinterest.ktlint.rule.engine.core.api.prevSibling +import com.pinterest.ktlint.rule.engine.core.api.remove 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 @@ -158,13 +159,8 @@ public class TypeArgumentListSpacingRule : emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> AutocorrectDecision, ) { if (node.text != "") { - emit( - node.startOffset, - "No whitespace expected at this position", - true, - ).ifAutocorrectAllowed { - node.treeParent.removeChild(node) - } + emit(node.startOffset, "No whitespace expected at this position", true) + .ifAutocorrectAllowed { node.remove() } } } } diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TypeParameterListSpacingRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TypeParameterListSpacingRule.kt index 568724b72d..afe845fd6a 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TypeParameterListSpacingRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/rules/TypeParameterListSpacingRule.kt @@ -28,6 +28,7 @@ import com.pinterest.ktlint.rule.engine.core.api.nextLeaf import com.pinterest.ktlint.rule.engine.core.api.nextSibling import com.pinterest.ktlint.rule.engine.core.api.prevLeaf import com.pinterest.ktlint.rule.engine.core.api.prevSibling +import com.pinterest.ktlint.rule.engine.core.api.remove import com.pinterest.ktlint.rule.engine.core.api.upsertWhitespaceBeforeMe import com.pinterest.ktlint.ruleset.standard.StandardRule import org.jetbrains.kotlin.com.intellij.lang.ASTNode @@ -225,33 +226,22 @@ public class TypeParameterListSpacingRule : when { expectedWhitespace.isEmpty() -> { - emit( - node.startOffset, - "No whitespace expected", - true, - ).ifAutocorrectAllowed { - node.treeParent.removeChild(node) - } + emit(node.startOffset, "No whitespace expected", true) + .ifAutocorrectAllowed { node.remove() } } node.isWhiteSpaceWithoutNewline() && expectedWhitespace.startsWith("\n") -> { - emit( - node.startOffset, - "Expected a newline", - true, - ).ifAutocorrectAllowed { - (node as LeafPsiElement).rawReplaceWithText(expectedWhitespace) - } + emit(node.startOffset, "Expected a newline", true) + .ifAutocorrectAllowed { + (node as LeafPsiElement).rawReplaceWithText(expectedWhitespace) + } } expectedWhitespace == " " -> { - emit( - node.startOffset, - "Expected a single space", - true, - ).ifAutocorrectAllowed { - (node as LeafPsiElement).rawReplaceWithText(expectedWhitespace) - } + emit(node.startOffset, "Expected a single space", true) + .ifAutocorrectAllowed { + (node as LeafPsiElement).rawReplaceWithText(expectedWhitespace) + } } } } @@ -264,23 +254,17 @@ public class TypeParameterListSpacingRule : node.text == " " -> Unit node.textContains('\n') -> { - emit( - node.startOffset, - "Expected a single space instead of newline", - true, - ).ifAutocorrectAllowed { - (node as LeafPsiElement).rawReplaceWithText(" ") - } + emit(node.startOffset, "Expected a single space instead of newline", true) + .ifAutocorrectAllowed { + (node as LeafPsiElement).rawReplaceWithText(" ") + } } else -> { - emit( - node.startOffset, - "Expected a single space", - true, - ).ifAutocorrectAllowed { - node.upsertWhitespaceBeforeMe(" ") - } + emit(node.startOffset, "Expected a single space", true) + .ifAutocorrectAllowed { + node.upsertWhitespaceBeforeMe(" ") + } } } } diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundParensRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundParensRuleTest.kt index 1812e0e506..3420c22228 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundParensRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/pinterest/ktlint/ruleset/standard/rules/SpacingAroundParensRuleTest.kt @@ -62,6 +62,15 @@ class SpacingAroundParensRuleTest { .isFormattedAs(formattedCode) } + @Test + fun `Given a function type inside a type projection then do not remove space before the opening parenthesis`() { + val code = + """ + val foo: Map Foo> = emptyMap() + """.trimIndent() + spacingAroundParensRuleAssertThat(code).hasNoLintViolations() + } + @Test fun `Given a variable declaration with unexpected spacing around the opening parenthesis of the expression`() { val code = @@ -135,14 +144,18 @@ class SpacingAroundParensRuleTest { val code = """ val foo = fn("foo" ) + val foo = fn( ) """.trimIndent() val formattedCode = """ val foo = fn("foo") + val foo = fn() """.trimIndent() spacingAroundParensRuleAssertThat(code) - .hasLintViolation(1, 19, "Unexpected spacing before \")\"") - .isFormattedAs(formattedCode) + .hasLintViolations( + LintViolation(1, 19, "Unexpected spacing before \")\""), + LintViolation(2, 14, "Unexpected spacing after \"(\""), + ).isFormattedAs(formattedCode) } @Test