Added parameter-list-wrapping rule
diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/EditorConfig.kt b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/EditorConfig.kt
new file mode 100644
index 0000000..0a213bf
--- /dev/null
+++ b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/EditorConfig.kt
@@ -0,0 +1,41 @@
+package com.github.shyiko.ktlint.ruleset.standard
+
+import com.github.shyiko.ktlint.core.KtLint
+import org.jetbrains.kotlin.com.intellij.lang.FileASTNode
+
+// http://editorconfig.org/
+internal data class EditorConfig(
+    val indentSize: Int,
+    val continuationIndentSize: Int,
+    val maxLineLength: Int,
+    val insertFinalNewline: Boolean?
+) {
+
+    companion object {
+
+        private const val DEFAULT_INDENT = 4
+        private const val DEFAULT_CONTINUATION_INDENT = 4
+
+        // https://android.github.io/kotlin-guides/style.html#line-wrapping
+        private const val ANDROID_MAX_LINE_LENGTH = 100
+
+        fun from(node: FileASTNode): EditorConfig {
+            val editorConfig = node.getUserData(KtLint.EDITOR_CONFIG_USER_DATA_KEY)!!
+            val indentSizeRaw = editorConfig.get("indent_size")
+            val indentSize = when {
+                indentSizeRaw?.toLowerCase() == "unset" -> -1
+                else -> indentSizeRaw?.toIntOrNull() ?: DEFAULT_INDENT
+            }
+            val continuationIndentSizeRaw = editorConfig.get("continuation_indent_size")
+            val continuationIndentSize = when {
+                continuationIndentSizeRaw?.toLowerCase() == "unset" -> -1
+                else -> continuationIndentSizeRaw?.toIntOrNull() ?: DEFAULT_CONTINUATION_INDENT
+            }
+            val android = node.getUserData(KtLint.ANDROID_USER_DATA_KEY)!!
+            val maxLineLength = editorConfig.get("max_line_length")?.toIntOrNull()
+                ?: if (android) ANDROID_MAX_LINE_LENGTH else -1
+            val insertFinalNewline = editorConfig.get("insert_final_newline")?.toBoolean()
+            return EditorConfig(indentSize, continuationIndentSize, maxLineLength, insertFinalNewline)
+        }
+    }
+}
diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/IndentationRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/IndentationRule.kt
index b6c108c..15835fa 100644
--- a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/IndentationRule.kt
+++ b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/IndentationRule.kt
@@ -1,17 +1,14 @@
 package com.github.shyiko.ktlint.ruleset.standard
 
-import com.github.shyiko.ktlint.core.KtLint
 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.lang.FileASTNode
 import org.jetbrains.kotlin.com.intellij.psi.PsiComment
-import org.jetbrains.kotlin.com.intellij.psi.PsiElement
 import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace
-import org.jetbrains.kotlin.com.intellij.psi.util.PsiTreeUtil
 import org.jetbrains.kotlin.lexer.KtTokens
 import org.jetbrains.kotlin.psi.KtBinaryExpression
 import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
-import org.jetbrains.kotlin.psi.KtParameter
 import org.jetbrains.kotlin.psi.KtParameterList
 import org.jetbrains.kotlin.psi.KtParenthesizedExpression
 import org.jetbrains.kotlin.psi.KtSafeQualifiedExpression
@@ -20,69 +17,40 @@
 import org.jetbrains.kotlin.psi.KtSuperTypeListEntry
 import org.jetbrains.kotlin.psi.KtTypeProjection
 import org.jetbrains.kotlin.psi.KtValueArgumentList
-import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
 import org.jetbrains.kotlin.psi.psiUtil.getPrevSiblingIgnoringWhitespaceAndComments
 import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
 
 class IndentationRule : Rule("indent") {
 
-    companion object {
-        // indentation size recommended by JetBrains
-        private const val DEFAULT_INDENT = 4
-        private const val DEFAULT_CONTINUATION_INDENT = 4
-    }
+    private var indentSize = -1
+    private var continuationIndentSize = -1
 
-    private var indent = -1
-    private var continuationIndent = -1
-
-    override fun visit(node: ASTNode, autoCorrect: Boolean,
-            emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit) {
+    override fun visit(
+        node: ASTNode,
+        autoCorrect: Boolean,
+        emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit
+    ) {
         if (node.elementType == KtStubElementTypes.FILE) {
-            val editorConfig = node.getUserData(KtLint.EDITOR_CONFIG_USER_DATA_KEY)!!
-            val indentSize = editorConfig.get("indent_size")
-            val continuationIndentSize = editorConfig.get("continuation_indent_size")
-            indent = indentSize?.toIntOrNull() ?: if (indentSize?.toLowerCase() == "unset") -1 else DEFAULT_INDENT
-            continuationIndent = continuationIndentSize?.toIntOrNull() ?: DEFAULT_CONTINUATION_INDENT
+            val ec = EditorConfig.from(node as FileASTNode)
+            indentSize = ec.indentSize
+            continuationIndentSize = ec.continuationIndentSize
             return
         }
-        if (indent <= 0 || continuationIndent <= 0) {
+        if (indentSize <= 0 || continuationIndentSize <= 0) {
             return
         }
         if (node is PsiWhiteSpace && !node.isPartOf(PsiComment::class)) {
             val lines = node.getText().split("\n")
             if (lines.size > 1) {
                 var offset = node.startOffset + lines.first().length + 1
-                val firstParameter = lazy {
-                    PsiTreeUtil.findChildOfType(
-                        node.getNonStrictParentOfType(KtParameterList::class.java),
-                        KtParameter::class.java
-                    )
-                }
-                val firstParameterColumn = lazy { firstParameter.value?.column ?: 0 }
-                val previousIndent = calculatePreviousIndent(node)
-                val expectedIndentSize = if (continuationIndent == indent || shouldUseContinuationIndent(node))
-                    continuationIndent else indent
+                val previousIndentSize = node.previousIndentSize()
+                val expectedIndentSize = if (continuationIndentSize == indentSize || shouldUseContinuationIndent(node))
+                    continuationIndentSize else indentSize
                 lines.tail().forEach { line ->
-                    if (line.isNotEmpty() && (line.length - previousIndent) % expectedIndentSize != 0) {
-                        if (node.isPartOf(KtParameterList::class) &&
-                            firstParameterColumn.value != 0 &&
-                            (
-                                // is not the first parameter
-                                node.parent.node.findChildByType(KtStubElementTypes.VALUE_PARAMETER) !=
-                                firstParameter.value?.node ||
-                                // ... or is next to (
-                                firstParameter.value?.let { PsiTreeUtil.prevLeaf(it, true) }?.node
-                                    ?.elementType == KtTokens.LPAR)
-                            ) {
-                            if (firstParameterColumn.value - 1 != line.length) {
-                                emit(offset, "Unexpected indentation (${line.length}) (" +
-                                    "parameters should be either vertically aligned or " +
-                                    "indented by the multiple of $indent" +
-                                    ")", false)
-                            }
-                        } else {
+                    if (line.isNotEmpty() && (line.length - previousIndentSize) % expectedIndentSize != 0) {
+                        if (!node.isPartOf(KtParameterList::class)) { // parameter list wrapping enforced by ParameterListWrappingRule
                             emit(offset,
-                                "Unexpected indentation (${line.length - previousIndent}) " +
+                                "Unexpected indentation (${line.length - previousIndentSize}) " +
                                     "(it should be $expectedIndentSize)",
                                 false)
                         }
@@ -93,67 +61,41 @@
         }
     }
 
-    private val PsiElement.column: Int
-        get() {
-            var leaf = PsiTreeUtil.prevLeaf(this)
-            var offsetToTheLeft = 0
-            while (leaf != null) {
-                if (leaf.node.elementType == KtTokens.WHITE_SPACE && leaf.textContains('\n')) {
-                    offsetToTheLeft += leaf.textLength - 1 - leaf.text.lastIndexOf('\n')
-                    break
-                }
-                offsetToTheLeft += leaf.textLength
-                leaf = PsiTreeUtil.prevLeaf(leaf)
-            }
-            return offsetToTheLeft + 1
-        }
-
     private fun shouldUseContinuationIndent(node: PsiWhiteSpace): Boolean {
         val parentNode = node.parent
         val prevNode = node.getPrevSiblingIgnoringWhitespaceAndComments()?.node?.elementType
         val nextNode = node.nextSibling?.node?.elementType
         return (
-            prevNode in KtTokens.ALL_ASSIGNMENTS
-                || parentNode is KtSecondaryConstructor
-                || nextNode == KtStubElementTypes.TYPE_REFERENCE
-                || node.nextSibling is KtSuperTypeList
-                || node.nextSibling is KtSuperTypeListEntry
-                || node.nextSibling is KtTypeProjection
-                || parentNode is KtValueArgumentList
-                || parentNode is KtBinaryExpression
-                || parentNode is KtDotQualifiedExpression
-                || parentNode is KtSafeQualifiedExpression
-                || parentNode is KtParenthesizedExpression
-            )
+            prevNode in KtTokens.ALL_ASSIGNMENTS ||
+            parentNode is KtSecondaryConstructor ||
+            nextNode == KtStubElementTypes.TYPE_REFERENCE ||
+            node.nextSibling is KtSuperTypeList ||
+            node.nextSibling is KtSuperTypeListEntry ||
+            node.nextSibling is KtTypeProjection ||
+            parentNode is KtValueArgumentList ||
+            parentNode is KtBinaryExpression ||
+            parentNode is KtDotQualifiedExpression ||
+            parentNode is KtSafeQualifiedExpression ||
+            parentNode is KtParenthesizedExpression
+        )
     }
 
-    private fun calculatePreviousIndent(node: ASTNode): Int {
-        val parentNode = node.treeParent?.psi
-        var prevIndent = 0
+    private fun ASTNode.previousIndentSize(): Int {
+        val parentNode = this.treeParent?.psi
         var prevSibling = parentNode
-        var prevSpaceIsFound = false
-        while (prevSibling != null && !prevSpaceIsFound) {
+        while (prevSibling != null) {
             val nextNode = prevSibling.nextSibling?.node?.elementType
-            if (prevSibling is PsiWhiteSpace
-                && nextNode != KtStubElementTypes.TYPE_REFERENCE
-                && nextNode != KtStubElementTypes.SUPER_TYPE_LIST
-                && nextNode != KtNodeTypes.CONSTRUCTOR_DELEGATION_CALL) {
+            if (prevSibling is PsiWhiteSpace &&
+                nextNode != KtStubElementTypes.TYPE_REFERENCE &&
+                nextNode != KtStubElementTypes.SUPER_TYPE_LIST &&
+                nextNode != KtNodeTypes.CONSTRUCTOR_DELEGATION_CALL) {
                 val prevLines = prevSibling.text.split('\n')
                 if (prevLines.size > 1) {
-                    prevIndent = prevLines.last().length
-                    prevSpaceIsFound = true
+                    return prevLines.last().length
                 }
             }
-            prevSibling = if (prevSpaceIsFound) {
-                null
-            } else {
-                if (prevSibling.prevSibling != null) {
-                    prevSibling.prevSibling
-                } else {
-                    prevSibling.parent
-                }
-            }
+            prevSibling = prevSibling.prevSibling ?: prevSibling.parent
         }
-        return prevIndent
+        return 0
     }
 }
diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/ParameterListWrappingRule.kt b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/ParameterListWrappingRule.kt
new file mode 100644
index 0000000..ad4af27
--- /dev/null
+++ b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/ParameterListWrappingRule.kt
@@ -0,0 +1,101 @@
+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.lang.FileASTNode
+import org.jetbrains.kotlin.com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl
+import org.jetbrains.kotlin.com.intellij.psi.util.PsiTreeUtil
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.psiUtil.children
+import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
+
+class ParameterListWrappingRule : Rule("parameter-list-wrapping") {
+
+    private var indentSize = -1
+    private var maxLineLength: Int = -1
+
+    override fun visit(
+        node: ASTNode,
+        autoCorrect: Boolean,
+        emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit
+    ) {
+        if (node.elementType == KtStubElementTypes.FILE) {
+            val ec = EditorConfig.from(node as FileASTNode)
+            indentSize = ec.indentSize
+            maxLineLength = ec.maxLineLength
+            return
+        }
+        if (node.elementType == KtStubElementTypes.VALUE_PARAMETER_LIST &&
+            // skip lambda parameters
+            node.treeParent?.elementType != KtNodeTypes.FUNCTION_LITERAL) {
+            // each parameter should be on a separate line if
+            // - at least one of the parameters is
+            // - maxLineLength exceeded (and separating parameters with \n would actually help)
+            // in addition, "(" and ")" must be on separates line if any of the parameters are (otherwise on the same)
+            val putParametersOnSeparateLines = node.textContains('\n')
+                // maxLineLength > 0 && node.lineLength() > maxLineLength
+            if (putParametersOnSeparateLines) {
+                // aiming for
+                // ... LPAR
+                // <LPAR line indent + indentSize> VALUE_PARAMETER...
+                // <LPAR line indent> RPAR
+                val indent = "\n" + node.psi.lineIndent()
+                val paramIndent = indent + " ".repeat(indentSize) // single indent as recommended by Jetbrains/Google
+                nextChild@ for (child in node.children()) {
+                    when (child.elementType) {
+                        KtStubElementTypes.VALUE_PARAMETER,
+                        KtTokens.RPAR -> {
+                            val prevLeaf = child.psi.prevLeaf()!!
+                            val intendedIndent = if (child.elementType == KtStubElementTypes.VALUE_PARAMETER)
+                                paramIndent else indent
+                            if (prevLeaf.node.elementType == KtTokens.WHITE_SPACE) {
+                                val spacing = prevLeaf.text
+                                val cut = spacing.lastIndexOf("\n")
+                                if (cut > -1) {
+                                    val childIndent = spacing.substring(cut)
+                                    if (childIndent == intendedIndent) {
+                                        continue@nextChild
+                                    }
+                                    emit(child.startOffset, "Unexpected indentation" +
+                                        " (expected ${intendedIndent.length - 1}, actual ${childIndent.length - 1})", true)
+                                } else {
+                                    emit(child.startOffset, errorMessage(child), true)
+                                }
+                                if (autoCorrect) {
+                                    val prefix = if (cut > -1) spacing.substring(0, cut) else ""
+                                    prevLeaf.rawReplaceWithText(prefix + intendedIndent)
+                                }
+                            } else {
+                                emit(child.startOffset, errorMessage(child), true)
+                                if (autoCorrect) {
+                                    node.addChild(PsiWhiteSpaceImpl(intendedIndent), child)
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private fun errorMessage(node: ASTNode) =
+        when (node.elementType) {
+            KtStubElementTypes.VALUE_PARAMETER ->
+                "Parameter should be on a separate line (unless all parameters can fit a single line)"
+            KtTokens.RPAR -> """Missing newline before ")""""
+            else -> throw UnsupportedOperationException()
+        }
+
+    private fun PsiElement.lineIndent(): String {
+        var leaf = PsiTreeUtil.prevLeaf(this)
+        while (leaf != null) {
+            if (leaf.node.elementType == KtTokens.WHITE_SPACE && leaf.textContains('\n')) {
+                return leaf.text.substring(leaf.text.lastIndexOf('\n') + 1)
+            }
+            leaf = PsiTreeUtil.prevLeaf(leaf)
+        }
+        return ""
+    }
+}
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 cdb5b0c..17a2ddd 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,7 +10,6 @@
         FinalNewlineRule(),
         // disabled until it's clear how to reconcile difference in Intellij & Android Studio import layout
         // ImportOrderingRule(),
-        NoLineBreakAfterElseRule(),
         IndentationRule(),
         MaxLineLengthRule(),
         ModifierOrderRule(),
@@ -19,6 +18,7 @@
         NoEmptyClassBodyRule(),
         // disabled until it's clear what to do in case of `import _.it`
         // NoItParamInMultilineLambdaRule(),
+        NoLineBreakAfterElseRule(),
         NoLineBreakBeforeAssignmentRule(),
         NoMultipleSpacesRule(),
         NoSemicolonsRule(),
@@ -26,6 +26,7 @@
         NoUnitReturnRule(),
         NoUnusedImportsRule(),
         NoWildcardImportsRule(),
+        ParameterListWrappingRule(),
         SpacingAroundColonRule(),
         SpacingAroundCommaRule(),
         SpacingAroundCurlyRule(),
diff --git a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/package.kt b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/package.kt
index faec925..087a193 100644
--- a/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/package.kt
+++ b/ktlint-ruleset-standard/src/main/kotlin/com/github/shyiko/ktlint/ruleset/standard/package.kt
@@ -1,12 +1,16 @@
 package com.github.shyiko.ktlint.ruleset.standard
 
 import org.jetbrains.kotlin.com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.LeafPsiElement
+import org.jetbrains.kotlin.com.intellij.psi.util.PsiTreeUtil
 import org.jetbrains.kotlin.psi.KtStringTemplateEntry
 import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
 import kotlin.reflect.KClass
 
 internal fun PsiElement.isPartOf(clazz: KClass<out PsiElement>) = getNonStrictParentOfType(clazz.java) != null
 internal fun PsiElement.isPartOfString() = isPartOf(KtStringTemplateEntry::class)
+internal fun PsiElement.prevLeaf(): LeafPsiElement? = PsiTreeUtil.prevLeaf(this) as LeafPsiElement?
+internal fun PsiElement.nextLeaf(): LeafPsiElement? = PsiTreeUtil.nextLeaf(this) as LeafPsiElement?
 
 internal fun <T> List<T>.head() = this.subList(0, this.size - 1)
 internal fun <T> List<T>.tail() = this.subList(1, this.size)
diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/github/shyiko/ktlint/ruleset/standard/IndentationRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/github/shyiko/ktlint/ruleset/standard/IndentationRuleTest.kt
index 0b0514e..866396e 100644
--- a/ktlint-ruleset-standard/src/test/kotlin/com/github/shyiko/ktlint/ruleset/standard/IndentationRuleTest.kt
+++ b/ktlint-ruleset-standard/src/test/kotlin/com/github/shyiko/ktlint/ruleset/standard/IndentationRuleTest.kt
@@ -8,7 +8,7 @@
 class IndentationRuleTest {
 
     @Test
-    fun testRule() {
+    fun testLint() {
         assertThat(IndentationRule().lint(
             """
             /**
@@ -39,47 +39,37 @@
     }
 
     @Test
-    fun testVerticallyAlignedParametersDoNotTriggerAnError() {
+    fun testLintNested() {
         assertThat(IndentationRule().lint(
             """
-            data class D(val a: Any,
-                         @Test val b: Any,
-                         val c: Any = 0) {
-            }
-
-            data class D2(
-                val a: Any,
-                val b: Any,
-                val c: Any
-            ) {
-            }
-
-            fun f(a: Any,
-                  b: Any,
-                  c: Any) {
-            }
-
-            fun f2(
-                a: Any,
-                b: Any,
-                c: Any
-            ) {
-            }
-            """.trimIndent()
+            fun funA() =
+                  doStuff().use {
+                      while (it.moveToNext()) {
+                          doMore()
+                      }
+                  }
+              """.trimIndent(),
+            mapOf("indent_size" to "4", "continuation_indent_size" to "6")
         )).isEmpty()
+    }
+
+    @Test
+    fun testLintCustomIndentSize() {
         assertThat(IndentationRule().lint(
             """
-            class A(
-               //
-            ) {}
-            """.trimIndent()
+            fun main() {
+               val v = ""
+                println(v)
+            }
+            """.trimIndent(),
+            mapOf("indent_size" to "3")
         )).isEqualTo(listOf(
-            LintError(2, 1, "indent", "Unexpected indentation (3) (it should be 4)")
+            LintError(3, 1, "indent", "Unexpected indentation (4) (it should be 3)")
         ))
     }
 
     @Test
-    fun testWithCustomIndentSize() {
+    fun testLintCustomIndentSizeValid() {
         assertThat(IndentationRule().lint(
             """
             /**
@@ -101,22 +91,7 @@
     }
 
     @Test
-    fun testErrorWithCustomIndentSize() {
-        assertThat(IndentationRule().lint(
-            """
-            fun main() {
-               val v = ""
-                println(v)
-            }
-            """.trimIndent(),
-            mapOf("indent_size" to "3")
-        )).isEqualTo(listOf(
-            LintError(3, 1, "indent", "Unexpected indentation (4) (it should be 3)")
-        ))
-    }
-
-    @Test
-    fun testErrorWithIndentSizeUnset() {
+    fun testLintIndentSizeUnset() {
         assertThat(IndentationRule().lint(
             """
             fun main() {
@@ -129,23 +104,7 @@
     }
 
     @Test
-    fun testShouldReportIncorrectIndentOfFirstParameter() {
-        assertThat(IndentationRule().lint(
-            """
-            fun x(
-                 x: Int = 0,
-                y: Int = 0
-            ) {
-            }
-            """.trimIndent(),
-            script = true
-        )).isEqualTo(listOf(
-            LintError(2, 1, "indent", "Unexpected indentation (5) (it should be 4)")
-        ))
-    }
-
-    @Test
-    fun testShouldRespectContinuationIndent() {
+    fun testLintContinuationIndent() {
         assertThat(IndentationRule().lint(
             """
                 class TestContinuation {
@@ -160,13 +119,12 @@
                     }
                 }
               """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
+            mapOf("indent_size" to "4", "continuation_indent_size" to "6")
         )).isEmpty()
     }
 
     @Test
-    fun `testUseContinuationIndentForConcatenation`() {
+    fun testLintContinuationIndentConcatenation() {
         assertThat(IndentationRule().lint(
             """
                 class TestSubClass {
@@ -175,13 +133,12 @@
                           "")
                 }
               """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
+            mapOf("indent_size" to "4", "continuation_indent_size" to "6")
         )).isEmpty()
     }
 
     @Test
-    fun testUseContinuationIndentForDotQualifiedExpression() {
+    fun testLintContinuationIndentDotQualifiedExpression() {
         assertThat(IndentationRule().lint(
             """
                 fun funA() {
@@ -189,13 +146,12 @@
                           .methodA()
                 }
               """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
+            mapOf("indent_size" to "4", "continuation_indent_size" to "6")
         )).isEmpty()
     }
 
     @Test
-    fun testUseIndentForObjectImplementation() {
+    fun testLintIndentInsideObjectBody() {
         assertThat(IndentationRule().lint(
             """
                 @Test fun field() {
@@ -211,29 +167,13 @@
                           })
                 }
               """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
+            mapOf("indent_size" to "4", "continuation_indent_size" to "6")
         )).isEmpty()
     }
 
+    // fixme: should each argument be on a separate line?
     @Test
-    fun testComplexAssignmentQualifiedAccessAndFunctionBody() {
-        assertThat(IndentationRule().lint(
-            """
-            fun funA() =
-                  doStuff().use {
-                      while (it.moveToNext()) {
-                          doMore()
-                      }
-                  }
-              """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
-        )).isEmpty()
-    }
-
-    @Test
-    fun testUseContinuationIndentForArgumentList() {
+    fun testLintContinuationIndentFunctionCallArgumentList() {
         assertThat(IndentationRule().lint(
             """
                 fun funA() {
@@ -241,14 +181,23 @@
                           listOf(ClassA(),
                                 ClassB())
                 }
+                fun data() = listOf(
+                      with(ClassA()) {
+                          arrayOf({ paramA: TypeA ->
+                              paramA.build()
+                          }, funB())
+                      },
+                      arrayOf({ paramA: TypeA -> paramA.build() },
+                            funB()
+                      )
+                )
               """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
+            mapOf("indent_size" to "4", "continuation_indent_size" to "6")
         )).isEmpty()
     }
 
     @Test
-    fun testUseContinuationIndentInsideParenthesis() {
+    fun testLintContinuationIndentInsideParenthesis() {
         assertThat(IndentationRule().lint(
             """
                 fun funA() {
@@ -262,50 +211,39 @@
                     )
                 }
               """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
+            mapOf("indent_size" to "4", "continuation_indent_size" to "6")
         )).isEmpty()
     }
 
     @Test
-    fun testUseIndentForCustomGetter() {
+    fun testLintIndentGettersAndSetters() {
         assertThat(IndentationRule().lint(
             """
                 val storyBody: String
                     get() = String.format(body, "")
               """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
+            mapOf("indent_size" to "4", "continuation_indent_size" to "6")
         )).isEmpty()
     }
 
     @Test
-    fun testUseContinuationIndentAfterAssignment() {
+    fun testLintContinuationIndentSuperTypeList() {
         assertThat(IndentationRule().lint(
             """
-        val valueA =
-              "{\"title\"}"
-              """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
-        )).isEmpty()
-    }
-
-    @Test
-    fun testUseContinuationIndentForSuperTypeList() {
-        assertThat(IndentationRule().lint(
-            """
-            class ClassA(fieldA: TypeA,
-                         fieldB: TypeB = DefaultB) :
+            class ClassA(fieldA: TypeA, fieldB: TypeB = DefaultB) :
                   SuperClassA(fieldA, fieldB)
-              """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
+            class ClassA(a: TypeA) :
+                  BasePresenter<View>() {
+
+                private lateinit var view: View
+            }
+            """.trimIndent(),
+            mapOf("indent_size" to "4", "continuation_indent_size" to "6")
         )).isEmpty()
     }
 
     @Test
-    fun testUseIndentForFunctionBody() {
+    fun testLintIndentInsideFunctionBody() {
         assertThat(IndentationRule().lint(
             """
                 fun funA() {
@@ -314,53 +252,35 @@
                     assertThat(valueA.getFieldB()).isEqualTo(100L)
                 }
               """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
+            mapOf("indent_size" to "4", "continuation_indent_size" to "6")
         )).isEmpty()
     }
 
     @Test
-    fun testUseContinuationIndentInsideSuperTypeList() {
+    fun testLintContinuationIndentInsideSuperTypeList() {
         assertThat(IndentationRule().lint(
             """
             class ClassA : ClassB(), InterfaceA,
                   InterfaceB {
             }
               """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
+            mapOf("indent_size" to "4", "continuation_indent_size" to "6")
         )).isEmpty()
     }
 
     @Test
-    fun testUseContinuationIndentForTypeProjection() {
+    fun testLintContinuationIndentTypeProjection() {
         assertThat(IndentationRule().lint(
             """
             val variable: SuperTpe<TypeA,
                   TypeB> = Implementation()
               """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
-        )).isEmpty()
-    }
-
-    @Test(enabled = false)
-        //not sure if it should use continuation indent or same as parameters
-    fun testCommentBetweenParameterListShouldUseSameIndent() {
-        assertThat(IndentationRule().lint(
-            """
-            data class MyClass(val a: String,
-                               val b: String,
-                  //comment between properties
-                               val c: String)
-              """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
+            mapOf("indent_size" to "4", "continuation_indent_size" to "6")
         )).isEmpty()
     }
 
     @Test
-    fun testUseContinuationIndentForAssignment() {
+    fun testLintContinuationIndentAssignment() {
         assertThat(IndentationRule().lint(
             """
             fun funA() {
@@ -368,52 +288,54 @@
                       anotherFun()
             }
               """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
+            mapOf("indent_size" to "4", "continuation_indent_size" to "6")
         )).isEmpty()
     }
 
     @Test()
-    fun testUseContinuationIndentForTypeCasting() {
+    fun testLintContinuationIndentTypeCasting() {
         assertThat(IndentationRule().lint(
             """
             fun funA() = funB() as
                   TypeA
               """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
+            mapOf("indent_size" to "4", "continuation_indent_size" to "6")
         )).isEmpty()
     }
 
     @Test
-    fun testUseContinuationIndentForConstructorDelegation() {
+    fun testLintContinuationIndentConstructorDelegation() {
         assertThat(IndentationRule().lint(
             """
             class A : B() {
                 constructor(a: String) :
                       this(a)
             }
-              """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
+            class MyClass{
+                constructor(a: TypeA) :
+                      super(a) {
+                    init(a)
+                }
+            }
+            """.trimIndent(),
+            mapOf("indent_size" to "4", "continuation_indent_size" to "6")
         )).isEmpty()
     }
 
     @Test
-    fun shouldUseContinuationInsideSafeQualifiedExpression() {
+    fun testLintContinuationIndentSafeChaining() {
         assertThat(IndentationRule().lint(
             """
             val valueA = call()
                   //comment
                   ?.chainCallC { it.anotherCall() }
               """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
+            mapOf("indent_size" to "4", "continuation_indent_size" to "6")
         )).isEmpty()
     }
 
     @Test
-    fun testUseContinuationIndentForTypeDeclaration() {
+    fun testLintContinuationIndentTypeDeclaration() {
         assertThat(IndentationRule().lint(
             """
             private fun funA(a: Int, b: String):
@@ -421,91 +343,20 @@
                 return MyTypeA(a, b)
             }
               """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
+            mapOf("indent_size" to "4", "continuation_indent_size" to "6")
         )).isEmpty()
     }
 
     @Test
-    fun testIgnoreSuperTypeListWhenCalculatePreviousIndent() {
-        assertThat(IndentationRule().lint(
-            """
-            class ClassA(a: TypeA) :
-                  BasePresenter<View>() {
-
-                private lateinit var view: View
-            }
-              """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
-        )).isEmpty()
-    }
-
-    @Test
-    fun testIgnoreConstructorDelegationCallWhenCalculatingPreviousIntent() {
-        assertThat(IndentationRule().lint(
-            """
-                class MyClass{
-                    constructor(a: TypeA) :
-                          super(a) {
-                        init(a)
-                    }
-                }
-            """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
-        )).isEmpty()
-    }
-
-    @Test(enabled = false)
-        //Not sure it should be supported. Recommended way can be to put each argument on separate line
-    fun testFuncIndent() {
-        assertThat(IndentationRule().lint(
-            """
-            fun funA(a: A, b: B) {
-                return funB(a,
-                      b, { (id) ->
-                    funC(id)
-                }
-                )
-            }
-            """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
-        )).isEmpty()
-    }
-
-    @Test
-    fun testComplexValueArgumentUsage() {
-        assertThat(IndentationRule().lint(
-            """
-            fun data() = listOf(
-                  with(ClassA()) {
-                      arrayOf({ paramA: TypeA ->
-                          paramA.build()
-                      }, funB())
-                  },
-                  arrayOf({ paramA: TypeA -> paramA.build() },
-                        funB()
-                  )
-            )
-            """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
-        )).isEmpty()
-    }
-
-    @Test
-    fun testIgnoreCommentWhenCalculateParentIndent() {
+    fun testLintCommentsAreIgnored() {
         assertThat(IndentationRule().lint(
             """
             fun funA(argA: String) =
                   // comment
-                  // comment
+            // comment
                   call(argA)
             """.trimIndent(),
-            mapOf("indent_size" to "4",
-                "continuation_indent_size" to "6")
+            mapOf("indent_size" to "4", "continuation_indent_size" to "6")
         )).isEmpty()
     }
 }
diff --git a/ktlint-ruleset-standard/src/test/kotlin/com/github/shyiko/ktlint/ruleset/standard/ParameterListWrappingRuleTest.kt b/ktlint-ruleset-standard/src/test/kotlin/com/github/shyiko/ktlint/ruleset/standard/ParameterListWrappingRuleTest.kt
new file mode 100644
index 0000000..a8ef3a0
--- /dev/null
+++ b/ktlint-ruleset-standard/src/test/kotlin/com/github/shyiko/ktlint/ruleset/standard/ParameterListWrappingRuleTest.kt
@@ -0,0 +1,251 @@
+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.assertThat
+import org.testng.annotations.Test
+
+class ParameterListWrappingRuleTest {
+
+    @Test
+    fun testLintClassParameterList() {
+        assertThat(
+            ParameterListWrappingRule().lint(
+            """
+            class ClassA(paramA: String, paramB: String,
+                         paramC: String)
+            """.trimIndent()
+            )
+        ).isEqualTo(
+            listOf(
+                LintError(1, 14, "parameter-list-wrapping", "Parameter should be on a separate line (unless all parameters can fit a single line)"),
+                LintError(1, 30, "parameter-list-wrapping", "Parameter should be on a separate line (unless all parameters can fit a single line)"),
+                LintError(2, 14, "parameter-list-wrapping", "Unexpected indentation (expected 4, actual 13)"),
+                LintError(2, 28, "parameter-list-wrapping", """Missing newline before ")"""")
+            )
+        )
+    }
+
+    @Test
+    fun testLintClassParameterListValid() {
+        assertThat(
+            ParameterListWrappingRule().lint(
+            """
+            class ClassA(paramA: String, paramB: String, paramC: String)
+            """.trimIndent()
+            )
+        ).isEmpty()
+    }
+
+    @Test
+    fun testLintClassParameterListValidMultiLine() {
+        assertThat(
+            ParameterListWrappingRule().lint(
+            """
+            class ClassA(
+                paramA: String,
+                paramB: String,
+                paramC: String
+            )
+            """.trimIndent()
+            )
+        ).isEmpty()
+    }
+
+    @Test
+    fun testFormatClassParameterList() {
+        assertThat(
+            ParameterListWrappingRule().format(
+            """
+            class ClassA(paramA: String, paramB: String,
+                         paramC: String)
+            """.trimIndent()
+            )
+        ).isEqualTo(
+            """
+            class ClassA(
+                paramA: String,
+                paramB: String,
+                paramC: String
+            )
+            """.trimIndent()
+        )
+    }
+
+    @Test
+    fun testLintFunctionParameterList() {
+        assertThat(
+            ParameterListWrappingRule().lint(
+            """
+            fun f(a: Any,
+                  b: Any,
+                  c: Any) {
+            }
+            """.trimIndent()
+            )).isEqualTo(
+            listOf(
+                LintError(1, 7, "parameter-list-wrapping", "Parameter should be on a separate line (unless all parameters can fit a single line)"),
+                LintError(2, 7, "parameter-list-wrapping", "Unexpected indentation (expected 4, actual 6)"),
+                LintError(3, 7, "parameter-list-wrapping", "Unexpected indentation (expected 4, actual 6)"),
+                LintError(3, 13, "parameter-list-wrapping", """Missing newline before ")"""")
+            )
+        )
+    }
+
+    @Test
+    fun testFormatFunctionParameterList() {
+        assertThat(
+            ParameterListWrappingRule().format(
+            """
+            fun f(a: Any,
+                  b: Any,
+                  c: Any) {
+            }
+            """.trimIndent()
+            )).isEqualTo(
+            """
+            fun f(
+                a: Any,
+                b: Any,
+                c: Any
+            ) {
+            }
+            """.trimIndent()
+        )
+    }
+
+    @Test
+    fun testLambdaParametersAreIgnored() {
+        assertThat(
+            ParameterListWrappingRule().lint(
+            """
+            val fieldExample =
+                  LongNameClass { paramA,
+                                  paramB,
+                                  paramC ->
+                      ClassB(paramA, paramB, paramC)
+                  }
+            """.trimIndent()
+            )).isEmpty()
+    }
+
+    @Test
+    fun testFormatPreservesIndent() {
+        assertThat(
+            ParameterListWrappingRule().format(
+            """
+            class A {
+                fun f(a: Any,
+                      b: Any,
+                      c: Any) {
+                }
+            }
+            """.trimIndent()
+            )).isEqualTo(
+            """
+            class A {
+                fun f(
+                    a: Any,
+                    b: Any,
+                    c: Any
+                ) {
+                }
+            }
+            """.trimIndent()
+        )
+    }
+
+    @Test
+    fun testFormatCorrectsRPARIndentIfNeeded() {
+        assertThat(
+            ParameterListWrappingRule().format(
+            """
+            class A {
+                fun f(a: Any,
+                      b: Any,
+                      c: Any
+                   ) {
+                }
+            }
+            """.trimIndent()
+            )).isEqualTo(
+            """
+            class A {
+                fun f(
+                    a: Any,
+                    b: Any,
+                    c: Any
+                ) {
+                }
+            }
+            """.trimIndent()
+        )
+    }
+
+    @Test
+    fun testFormatNestedDeclarations() {
+        assertThat(
+            ParameterListWrappingRule().format(
+            """
+            fun visit(
+                node: ASTNode,
+                    autoCorrect: Boolean,
+                emit: (offset: Int, errorMessage: String,
+                canBeAutoCorrected: Boolean) -> Unit
+            ) {}
+            """.trimIndent()
+            )).isEqualTo(
+            """
+            fun visit(
+                node: ASTNode,
+                autoCorrect: Boolean,
+                emit: (
+                    offset: Int,
+                    errorMessage: String,
+                    canBeAutoCorrected: Boolean
+                ) -> Unit
+            ) {}
+            """.trimIndent()
+        )
+    }
+
+    @Test
+    fun testFormatNestedDeclarationsValid() {
+        assertThat(
+            ParameterListWrappingRule().format(
+            """
+            fun visit(
+                node: ASTNode,
+                autoCorrect: Boolean,
+                emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit
+            ) {}
+            """.trimIndent()
+            )).isEqualTo(
+            """
+            fun visit(
+                node: ASTNode,
+                autoCorrect: Boolean,
+                emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit
+            ) {}
+            """.trimIndent()
+        )
+    }
+
+    @Test
+    fun testCommentsAreIgnored() {
+        assertThat(ParameterListWrappingRule().lint(
+            """
+            data class A(
+               /*
+                * comment
+                */
+               //
+               var v: String
+            )
+            """.trimIndent()
+        )).isEqualTo(listOf(
+            LintError(6, 4, "parameter-list-wrapping", "Unexpected indentation (expected 4, actual 3)")
+        ))
+    }
+}