diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/SpacingAroundKeywordRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/SpacingAroundKeywordRule.kt index de579f225e..560e50d7c0 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/SpacingAroundKeywordRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/SpacingAroundKeywordRule.kt @@ -7,6 +7,7 @@ import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl import org.jetbrains.kotlin.com.intellij.psi.tree.TokenSet import org.jetbrains.kotlin.com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens.CATCH_KEYWORD import org.jetbrains.kotlin.lexer.KtTokens.DO_KEYWORD import org.jetbrains.kotlin.lexer.KtTokens.ELSE_KEYWORD @@ -16,32 +17,45 @@ import org.jetbrains.kotlin.lexer.KtTokens.IF_KEYWORD import org.jetbrains.kotlin.lexer.KtTokens.TRY_KEYWORD import org.jetbrains.kotlin.lexer.KtTokens.WHEN_KEYWORD import org.jetbrains.kotlin.lexer.KtTokens.WHILE_KEYWORD +import org.jetbrains.kotlin.psi.KtPropertyAccessor import org.jetbrains.kotlin.psi.KtWhenEntry +import org.jetbrains.kotlin.psi.psiUtil.nextLeaf class SpacingAroundKeywordRule : Rule("keyword-spacing") { private val noLFBeforeSet = TokenSet.create(ELSE_KEYWORD, CATCH_KEYWORD, FINALLY_KEYWORD) private val tokenSet = TokenSet.create(FOR_KEYWORD, IF_KEYWORD, ELSE_KEYWORD, WHILE_KEYWORD, DO_KEYWORD, TRY_KEYWORD, CATCH_KEYWORD, FINALLY_KEYWORD, WHEN_KEYWORD) - // todo: but not after fun(, get(, set( + + private val keywordsWithoutSpaces = TokenSet.create(KtTokens.GET_KEYWORD, KtTokens.SET_KEYWORD) override fun visit(node: ASTNode, autoCorrect: Boolean, - emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) { - if (tokenSet.contains(node.elementType) && node is LeafPsiElement && - PsiTreeUtil.nextLeaf(node) !is PsiWhiteSpace) { - emit(node.startOffset + node.text.length, "Missing spacing after \"${node.text}\"", true) - if (autoCorrect) { - node.rawInsertAfterMe(PsiWhiteSpaceImpl(" ")) - } - } - if (noLFBeforeSet.contains(node.elementType) && node is LeafPsiElement) { - val prevLeaf = PsiTreeUtil.prevLeaf(node) - if (prevLeaf is PsiWhiteSpaceImpl && prevLeaf.textContains('\n') && - (node.elementType != ELSE_KEYWORD || node.parent !is KtWhenEntry) && - (PsiTreeUtil.prevLeaf(prevLeaf)?.textMatches("}") ?: false)) { - emit(node.startOffset, "Unexpected newline before \"${node.text}\"", true) + emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) { + + if (node is LeafPsiElement) { + if (tokenSet.contains(node.elementType) && node.nextLeaf() !is PsiWhiteSpace) { + emit(node.startOffset + node.text.length, "Missing spacing after \"${node.text}\"", true) if (autoCorrect) { - prevLeaf.rawReplaceWithText(" ") + node.rawInsertAfterMe(PsiWhiteSpaceImpl(" ")) + } + } else if (keywordsWithoutSpaces.contains(node.elementType) && node.nextLeaf() is PsiWhiteSpace) { + val parent = node.parent + if (parent is KtPropertyAccessor && parent.hasBody()) { + emit(node.startOffset, "Unexpected spacing after \"${node.text}\"", true) + if (autoCorrect) { + node.nextLeaf()?.delete() + } + } + } + if (noLFBeforeSet.contains(node.elementType)) { + val prevLeaf = PsiTreeUtil.prevLeaf(node) + if (prevLeaf is PsiWhiteSpaceImpl && prevLeaf.textContains('\n') && + (node.elementType != ELSE_KEYWORD || node.parent !is KtWhenEntry) && + (PsiTreeUtil.prevLeaf(prevLeaf)?.textMatches("}") ?: false)) { + emit(node.startOffset, "Unexpected newline before \"${node.text}\"", true) + if (autoCorrect) { + prevLeaf.rawReplaceWithText(" ") + } } } } diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/github/shyiko/ktlint/ruleset/standard/SpacingAroundKeywordRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/github/shyiko/ktlint/ruleset/standard/SpacingAroundKeywordRuleTest.kt index 073df23c88..232eeb3145 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/github/shyiko/ktlint/ruleset/standard/SpacingAroundKeywordRuleTest.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/github/shyiko/ktlint/ruleset/standard/SpacingAroundKeywordRuleTest.kt @@ -1,8 +1,8 @@ package com.github.shyiko.ktlint.ruleset.standard import com.github.shyiko.ktlint.core.LintError -import com.github.shyiko.ktlint.test.lint import com.github.shyiko.ktlint.test.format +import com.github.shyiko.ktlint.test.lint import org.assertj.core.api.Assertions.assertThat import org.testng.annotations.Test @@ -94,5 +94,47 @@ class SpacingAroundKeywordRuleTest { ) } + @Test + fun getterAndSetterFunction() { + assertThat(SpacingAroundKeywordRule().format( + """ + var x: String + get () { + return "" + } + private set (value) { + x = value + } + """.trimIndent() + )).isEqualTo( + """ + var x: String + get() { + return "" + } + private set(value) { + x = value + } + """.trimIndent() + ) + } + + @Test + fun visibilityOrInjectProperty() { + assertThat(SpacingAroundKeywordRule().lint( + """ + var setterVisibility: String = "abc" + private set + var setterWithAnnotation: Any? = null + @Inject set + var setterOnNextLine: String + private set + (value) { setterOnNextLine = value} + """ + )).isEqualTo(listOf( + LintError(7, 21, "keyword-spacing", "Unexpected spacing after \"set\"") + )) + } + }