new rule: NoLineBreakAfterElse Reports line breaks after "else" clause. Supports auto format by replacing linebreak with space. Doesn't take into account maximum line length.
diff --git a/ktlint-core/src/test/kotlin/com/github/shyiko/ktlint/core/KtLintTest.kt b/ktlint-core/src/test/kotlin/com/github/shyiko/ktlint/core/KtLintTest.kt index d3e30a7..3e6840a 100644 --- a/ktlint-core/src/test/kotlin/com/github/shyiko/ktlint/core/KtLintTest.kt +++ b/ktlint-core/src/test/kotlin/com/github/shyiko/ktlint/core/KtLintTest.kt
@@ -15,8 +15,7 @@ emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) { if (node.elementType == KtStubElementTypes.FILE) { bus.add("file:$id") - } else - if (!done) { + } else if (!done) { bus.add(id) done = true }
diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/ChainWrappingRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/ChainWrappingRule.kt index dda6839..63549b1 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/ChainWrappingRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/ChainWrappingRule.kt
@@ -46,8 +46,7 @@ } } } - } else - if (sameLineTokens.contains(elementType)) { + } else if (sameLineTokens.contains(elementType)) { val prevLeaf = node.psi.prevLeaf(true) if (prevLeaf is PsiWhiteSpaceImpl && prevLeaf.textContains('\n')) { emit(node.startOffset, "Line must not begin with \"${node.text}\"", true)
diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/NoLineBreakAfterElseRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/NoLineBreakAfterElseRule.kt new file mode 100644 index 0000000..3b904d4 --- /dev/null +++ b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/NoLineBreakAfterElseRule.kt
@@ -0,0 +1,31 @@ +package com.github.shyiko.ktlint.ruleset.standard + +import com.github.shyiko.ktlint.core.Rule +import org.jetbrains.kotlin.KtNodeTypes +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 +import org.jetbrains.kotlin.lexer.KtKeywordToken + +class NoLineBreakAfterElseRule : Rule(RULE_ID) { + override fun visit(node: ASTNode, autoCorrect: Boolean, emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) { + if (node is PsiWhiteSpace) { + if ( + node.nextSibling?.node?.elementType == KtNodeTypes.ELSE + && node.prevSibling?.node?.elementType is KtKeywordToken + && node.prevSibling.text == "else" + && node.getText().contains("\n")) { + emit(node.startOffset + 1, + "Unexpected line break after \"else\"", + true) + if (autoCorrect) { + (node as LeafPsiElement).rawReplaceWithText(" ") + } + } + } + } + + companion object { + const val RULE_ID = "no-line-break-after-else" + } +}
diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/NoMultipleSpacesRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/NoMultipleSpacesRule.kt index 0fcd6e8..e57aed3 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/NoMultipleSpacesRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/NoMultipleSpacesRule.kt
@@ -51,8 +51,7 @@ emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) { if (node.elementType == KtStubElementTypes.FILE) { fileNode = node - } else - if (node is PsiWhiteSpace && !node.textContains('\n') && node.getTextLength() > 1) { + } else if (node is PsiWhiteSpace && !node.textContains('\n') && node.getTextLength() > 1) { val nextLeaf = PsiTreeUtil.nextLeaf(node, true) if (nextLeaf is PsiComment) { val positionMap = commentMap
diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/NoTrailingSpacesRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/NoTrailingSpacesRule.kt index 5d81af6..dc64bb7 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/NoTrailingSpacesRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/NoTrailingSpacesRule.kt
@@ -17,8 +17,7 @@ if (autoCorrect) { (node as LeafPsiElement).rawReplaceWithText("\n".repeat(lines.size - 1) + lines.last()) } - } else - if (PsiTreeUtil.nextLeaf(node) == null /* eof */) { + } else if (PsiTreeUtil.nextLeaf(node) == null /* eof */) { checkForTrailingSpaces(lines, node.startOffset, emit) if (autoCorrect) { (node as LeafPsiElement).rawReplaceWithText("\n".repeat(lines.size - 1))
diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/NoUnusedImportsRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/NoUnusedImportsRule.kt index 4d9618b..9961b67 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/NoUnusedImportsRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/NoUnusedImportsRule.kt
@@ -52,18 +52,15 @@ if (type == KDocTokens.MARKDOWN_LINK && psi is KDocLink) { val linkText = psi.getLinkText().replace("`", "") ref.add(linkText.split('.').first()) - } else - if ((type == KtNodeTypes.REFERENCE_EXPRESSION || type == KtNodeTypes.OPERATION_REFERENCE) && + } else if ((type == KtNodeTypes.REFERENCE_EXPRESSION || type == KtNodeTypes.OPERATION_REFERENCE) && !psi.isPartOf(KtImportDirective::class)) { ref.add(vnode.text.trim('`')) } } - } else - if (node.elementType == KtStubElementTypes.PACKAGE_DIRECTIVE) { + } else if (node.elementType == KtStubElementTypes.PACKAGE_DIRECTIVE) { val packageDirective = node.psi as KtPackageDirective packageName = packageDirective.qualifiedName - } else - if (node.elementType == KtStubElementTypes.IMPORT_DIRECTIVE) { + } else if (node.elementType == KtStubElementTypes.IMPORT_DIRECTIVE) { val importDirective = node.psi as KtImportDirective val name = importDirective.importPath?.importedName?.asString() val importPath = importDirective.importPath?.pathStr!! @@ -74,8 +71,7 @@ if (autoCorrect) { importDirective.delete() } - } else - if (name != null && !ref.contains(name) && !operatorSet.contains(name)) { + } else if (name != null && !ref.contains(name) && !operatorSet.contains(name)) { emit(importDirective.startOffset, "Unused import", true) if (autoCorrect) { importDirective.delete()
diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/SpacingAroundCurlyRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/SpacingAroundCurlyRule.kt index f592ca1..c46c477 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/SpacingAroundCurlyRule.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/SpacingAroundCurlyRule.kt
@@ -44,8 +44,7 @@ (prevLeaf.node as LeafPsiElement).rawReplaceWithText(" ") } } - } else - if (node.textMatches("}")) { + } else if (node.textMatches("}")) { spacingBefore = prevLeaf is PsiWhiteSpace || prevLeaf?.node?.elementType == KtTokens.LBRACE spacingAfter = nextLeaf == null || nextLeaf is PsiWhiteSpace || shouldNotToBeSeparatedBySpace(nextLeaf) if (nextLeaf is PsiWhiteSpace && !nextLeaf.textContains('\n') &&
diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/StandardRuleSetProvider.kt b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/StandardRuleSetProvider.kt index aa57a54..cdb5b0c 100644 --- a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/StandardRuleSetProvider.kt +++ b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/StandardRuleSetProvider.kt
@@ -10,6 +10,7 @@ FinalNewlineRule(), // disabled until it's clear how to reconcile difference in Intellij & Android Studio import layout // ImportOrderingRule(), + NoLineBreakAfterElseRule(), IndentationRule(), MaxLineLengthRule(), ModifierOrderRule(),
diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/github/shyiko/ktlint/ruleset/standard/NoLineBreakAfterElseRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/github/shyiko/ktlint/ruleset/standard/NoLineBreakAfterElseRuleTest.kt new file mode 100644 index 0000000..6bb70bf --- /dev/null +++ b/ktlint-ruleset-standard/src/test/kotlin/com/github/shyiko/ktlint/ruleset/standard/NoLineBreakAfterElseRuleTest.kt
@@ -0,0 +1,128 @@ +package com.github.shyiko.ktlint.ruleset.standard + +import com.github.shyiko.ktlint.core.LintError +import com.github.shyiko.ktlint.test.format +import com.github.shyiko.ktlint.test.lint +import org.assertj.core.api.Assertions +import org.testng.annotations.Test + +class NoLineBreakAfterElseRuleTest { + @Test + fun testViolationForLineBreakBetweenElseAndIf() { + Assertions.assertThat(NoLineBreakAfterElseRule().lint( + """ + fun funA() { + if (conditionA()) { + doSomething() + } else + if (conditionB()) { + doAnotherThing() + } + } + """.trimIndent() + )).isEqualTo(listOf( + LintError(5, 1, NoLineBreakAfterElseRule.RULE_ID, "Unexpected line break after \"else\"") + )) + } + + @Test + fun testFixViolationForLineBreakBetweenElseAndIf() { + Assertions.assertThat(NoLineBreakAfterElseRule().format( + """ + fun funA() { + if (conditionA()) { + doSomething() + } else + if (conditionB()) { + doAnotherThing() + } + } + """.trimIndent() + )).isEqualTo( + """ + fun funA() { + if (conditionA()) { + doSomething() + } else if (conditionB()) { + doAnotherThing() + } + } + """.trimIndent() + ) + } + + @Test + fun testValidElseIf() { + Assertions.assertThat(NoLineBreakAfterElseRule().lint( + """ + fun funA() { + if (conditionA()) { + doSomething() + } else if (conditionB()) { + doAnotherThing() + } + } + """.trimIndent() + )).isEmpty() + } + + @Test + fun testValidSimpleElse() { + Assertions.assertThat(NoLineBreakAfterElseRule().lint( + """ + fun funA() { + if (conditionA()) { + doSomething() + } else { + doAnotherThing() + } + } + """.trimIndent() + )).isEmpty() + } + + @Test + fun testViolationForLineBreakBetweenElseAndBracket() { + Assertions.assertThat(NoLineBreakAfterElseRule().lint( + """ + fun funA() { + if (conditionA()) { + doSomething() + } else + { + doAnotherThing() + } + } + """.trimIndent() + )).isEqualTo(listOf( + LintError(5, 1, NoLineBreakAfterElseRule.RULE_ID, "Unexpected line break after \"else\"") + )) + } + + @Test + fun testViolationWhenBracketOmitted() { + Assertions.assertThat(NoLineBreakAfterElseRule().lint( + """ + fun funA() { + if (conditionA()) + doSomething() + else + doAnotherThing() + } + """.trimIndent() + )).isEqualTo(listOf( + LintError(5, 1, NoLineBreakAfterElseRule.RULE_ID, "Unexpected line break after \"else\"") + )) + } + + @Test + fun testValidWhenBracketOmitted() { + Assertions.assertThat(NoLineBreakAfterElseRule().lint( + """ + fun funA() { + if (conditionA()) doSomething() else doAnotherThing() + } + """.trimIndent() + )).isEmpty() + } +}
diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/github/shyiko/ktlint/ruleset/standard/package-test.kt b/ktlint-ruleset-standard/src/test/kotlin/com/github/shyiko/ktlint/ruleset/standard/package-test.kt index 016cbd4..3c42d4b 100644 --- a/ktlint-ruleset-standard/src/test/kotlin/com/github/shyiko/ktlint/ruleset/standard/package-test.kt +++ b/ktlint-ruleset-standard/src/test/kotlin/com/github/shyiko/ktlint/ruleset/standard/package-test.kt
@@ -20,14 +20,17 @@ } val input = resourceText.substring(0, dividerIndex) val errors = resourceText.substring(dividerIndex + 1).split('\n').mapNotNull { line -> - if (line.isBlank() || line == "// expect") null else + if (line.isBlank() || line == "// expect") { + null + } else { line.trimMargin("// ").split(':', limit = 3).let { expectation -> if (expectation.size != 3) { throw RuntimeException("$resource expectation must be a triple <line>:<column>:<message>") - // " (<message> is not allowed to contain \":\")") + // " (<message> is not allowed to contain \":\")") } LintError(expectation[0].toInt(), expectation[1].toInt(), rule.id, expectation[2]) } + } } assertThat(rule.lint(input, userData)).isEqualTo(errors) }
diff --git a/ktlint/src/main/kotlin/com/github/shyiko/ktlint/Main.kt b/ktlint/src/main/kotlin/com/github/shyiko/ktlint/Main.kt index 593b240..23b7f00 100644 --- a/ktlint/src/main/kotlin/com/github/shyiko/ktlint/Main.kt +++ b/ktlint/src/main/kotlin/com/github/shyiko/ktlint/Main.kt
@@ -373,8 +373,7 @@ } val stream = if (output != null) { File(output).parentFile?.mkdirsOrFail(); PrintStream(output, "UTF-8") - } else - if (stdin) System.err else System.out + } else if (stdin) System.err else System.out return reporterProvider.get(stream, config) .let { reporter -> if (output != null) @@ -384,8 +383,7 @@ stream.close() } } - else - reporter + else reporter } } return Reporter.from(*tpls.map { it.toReporter() }.toTypedArray()) @@ -584,13 +582,11 @@ private fun lint(fileName: String, text: String, ruleSets: Iterable<RuleSet>, userData: Map<String, String>, cb: (e: LintError) -> Unit) = - if (fileName.endsWith(".kt", ignoreCase = true)) KtLint.lint(text, ruleSets, userData, cb) else - KtLint.lintScript(text, ruleSets, userData, cb) + if (fileName.endsWith(".kt", ignoreCase = true)) KtLint.lint(text, ruleSets, userData, cb) else KtLint.lintScript(text, ruleSets, userData, cb) private fun format(fileName: String, text: String, ruleSets: Iterable<RuleSet>, userData: Map<String, String>, cb: (e: LintError, corrected: Boolean) -> Unit): String = - if (fileName.endsWith(".kt", ignoreCase = true)) KtLint.format(text, ruleSets, userData, cb) else - KtLint.formatScript(text, ruleSets, userData, cb) + if (fileName.endsWith(".kt", ignoreCase = true)) KtLint.format(text, ruleSets, userData, cb) else KtLint.formatScript(text, ruleSets, userData, cb) private fun java.net.URLClassLoader.addURLs(url: Iterable<java.net.URL>) { val method = java.net.URLClassLoader::class.java.getDeclaredMethod("addURL", java.net.URL::class.java)
diff --git a/ktlint/src/main/kotlin/com/github/shyiko/ktlint/internal/MavenDependencyResolver.kt b/ktlint/src/main/kotlin/com/github/shyiko/ktlint/internal/MavenDependencyResolver.kt index 9d74666..9ebf5fd 100644 --- a/ktlint/src/main/kotlin/com/github/shyiko/ktlint/internal/MavenDependencyResolver.kt +++ b/ktlint/src/main/kotlin/com/github/shyiko/ktlint/internal/MavenDependencyResolver.kt
@@ -23,7 +23,7 @@ import java.io.File class MavenDependencyResolver(baseDir: File, val repositories: Iterable<RemoteRepository>, - forceUpdate: Boolean) { + forceUpdate: Boolean) { private val repoSystem: RepositorySystem private val session: RepositorySystemSession @@ -41,8 +41,11 @@ repoSystem = locator.getService(RepositorySystem::class.java) session = MavenRepositorySystemUtils.newSession() session.localRepositoryManager = repoSystem.newLocalRepositoryManager(session, LocalRepository(baseDir)) - session.updatePolicy = if (forceUpdate) RepositoryPolicy.UPDATE_POLICY_ALWAYS else + session.updatePolicy = if (forceUpdate) { + RepositoryPolicy.UPDATE_POLICY_ALWAYS + } else { RepositoryPolicy.UPDATE_POLICY_NEVER + } } fun setTransferEventListener(listener: (event: TransferEvent) -> Unit) {