Formatter: support trailing comma in lambda value parameters & fix comments in KtParameter

#KT-34744
This commit is contained in:
Dmitry Gridin
2019-12-27 19:32:08 +07:00
parent d013fc2234
commit 96a11707ca
21 changed files with 468 additions and 50 deletions
@@ -609,6 +609,7 @@ abstract class KotlinCommonBlock(
node.withTrailingComma, node.withTrailingComma,
additionalWrap = trailingCommaWrappingStrategyWithMultiLineCheck(LPAR, RPAR) additionalWrap = trailingCommaWrappingStrategyWithMultiLineCheck(LPAR, RPAR)
) )
FUNCTION_TYPE -> return defaultTrailingCommaWrappingStrategy(LPAR, RPAR)
FUNCTION_LITERAL -> { FUNCTION_LITERAL -> {
if (nodePsi.parent?.safeAs<KtFunctionLiteral>()?.needTrailingComma(settings) == true) { if (nodePsi.parent?.safeAs<KtFunctionLiteral>()?.needTrailingComma(settings) == true) {
val check = thisOrPrevIsMultiLineElement(COMMA, LBRACE /* not necessary */, ARROW /* not necessary */) val check = thisOrPrevIsMultiLineElement(COMMA, LBRACE /* not necessary */, ARROW /* not necessary */)
@@ -8,8 +8,10 @@ package org.jetbrains.kotlin.idea.formatter
import com.intellij.lang.ASTNode import com.intellij.lang.ASTNode
import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.psi.codeStyle.CodeStyleSettings import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.impl.source.codeStyle.PostFormatProcessor import com.intellij.psi.impl.source.codeStyle.PostFormatProcessor
@@ -81,8 +83,9 @@ private class TrailingCommaVisitor(val settings: CodeStyleSettings) : KtTreeVisi
if (elementType === KtTokens.COMMA || parent.needComma) { if (elementType === KtTokens.COMMA || parent.needComma) {
// add a missing comma // add a missing comma
if (elementType !== KtTokens.COMMA) { if (elementType !== KtTokens.COMMA) {
changePsi(parent) { element, factory -> changePsi(parent) { factory ->
element.addAfter(factory.createComma(), lastElement) lastElement.addCommaAfter(factory)
true
} }
} }
@@ -97,31 +100,31 @@ private class TrailingCommaVisitor(val settings: CodeStyleSettings) : KtTreeVisi
else -> settings.kotlinCustomSettings.ALLOW_TRAILING_COMMA && isMultiline() else -> settings.kotlinCustomSettings.ALLOW_TRAILING_COMMA && isMultiline()
} }
private fun changePsi(element: KtElement, update: (KtElement, KtPsiFactory) -> Unit) { private fun changePsi(element: KtElement, update: (KtPsiFactory) -> Boolean) {
val oldLength = element.textLength val oldLength = element.textLength
update(element, KtPsiFactory(element)) if (update(KtPsiFactory(element))) {
val result = CodeStyleManager.getInstance(element.project).reformat(element) val result = CodeStyleManager.getInstance(element.project).reformat(element)
myPostProcessor.updateResultRange(oldLength, result.textLength) myPostProcessor.updateResultRange(oldLength, result.textLength)
}
} }
private fun correctCommaPosition(parent: KtElement) { private fun correctCommaPosition(parent: KtElement) {
val invalidElements = parent.firstChild?.siblings(withItself = false)?.mapNotNull { val invalidElements = parent.firstChild?.siblings(withItself = false)?.mapNotNull {
if (it !is ASTNode || it.elementType != KtTokens.COMMA) return@mapNotNull null if (it.safeAs<ASTNode>()?.elementType != KtTokens.COMMA) return@mapNotNull null
it.createSmartPointer()
val prevWithComment = it.getPrevSiblingIgnoringWhitespace(false)
val prevWithoutComment = it.getPrevSiblingIgnoringWhitespaceAndComments(false)
if (prevWithoutComment?.equals(prevWithComment) == false) {
it.createSmartPointer() to prevWithoutComment.createSmartPointer()
} else
null
}?.toList() ?: return }?.toList() ?: return
if (invalidElements.isNotEmpty()) { if (invalidElements.isNotEmpty()) {
changePsi(parent) { element, factory -> changePsi(parent) { factory ->
for ((pointToComma, pointToElement) in invalidElements) { var change = false
element.addAfter(factory.createComma(), pointToElement.element) for (pointerToComma in invalidElements) {
pointToComma.element?.delete() pointerToComma.element?.let {
if (correctComma(it, factory)) {
change = true
}
}
} }
change
} }
} }
} }
@@ -146,6 +149,33 @@ private class TrailingCommaVisitor(val settings: CodeStyleSettings) : KtTreeVisi
} }
} }
private fun PsiElement.addCommaAfter(factory: KtPsiFactory) {
val comma = factory.createComma()
parent.addAfter(comma, this)
}
private fun correctComma(comma: PsiElement, factory: KtPsiFactory): Boolean {
val prevWithComment = comma.getPrevSiblingIgnoringWhitespace(false)
val prevWithoutComment = comma.getPrevSiblingIgnoringWhitespaceAndComments(false)
return when {
prevWithoutComment?.equals(prevWithComment) == false -> {
prevWithoutComment.addCommaAfter(factory)
comma.delete()
true
}
prevWithoutComment is KtParameter -> {
val check = { element: PsiElement -> element is PsiWhiteSpace || element is PsiComment }
val lastElement = prevWithoutComment.lastChild?.takeIf(check) ?: return false
val firstElement = lastElement.siblings(forward = false, withItself = true).takeWhile(check).last()
comma.parent.addRangeAfter(firstElement, lastElement, comma)
prevWithoutComment.deleteChildRange(firstElement, lastElement)
true
}
else ->
false
}
}
private val PsiElement.lastCommaOwnerOrComma: PsiElement? private val PsiElement.lastCommaOwnerOrComma: PsiElement?
get() { get() {
val lastChild = lastSignificantChild ?: return null val lastChild = lastSignificantChild ?: return null
@@ -239,4 +239,42 @@ class L<
x : String, y : String, z : String x : String, y : String, z : String
> >
class C<
x : Int // adad
>
class G<
x : String, y : String, /* */ z : String // adad
>
class G<
x : String,
y : String,
/* */ /* */
z : String, /**/
>()
class H<
x : String, /*
*/
y : String,
z : String, /*
*/
>
class J<
x : String, y : String,
z : String, /*
*/ /**/
>
class K<
x : String, y : String,
z : String, // aw
>
class L<
x : String, y : String, z : String //awd
>
// SET_TRUE: ALLOW_TRAILING_COMMA // SET_TRUE: ALLOW_TRAILING_COMMA
@@ -247,4 +247,43 @@ class L<
x : String, y : String, z : String, x : String, y : String, z : String,
> >
class C<
x : Int, // adad
>
class G<
x : String, y : String, /* */
z : String, // adad
>
class G<
x : String,
y : String,
/* */ /* */
z : String, /**/
>()
class H<
x : String, /*
*/
y : String,
z : String, /*
*/
>
class J<
x : String, y : String,
z : String, /*
*/ /**/
>
class K<
x : String, y : String,
z : String, // aw
>
class L<
x : String, y : String, z : String, //awd
>
// SET_TRUE: ALLOW_TRAILING_COMMA // SET_TRUE: ALLOW_TRAILING_COMMA
@@ -226,4 +226,38 @@ class L<
x: String, y: String, z: String x: String, y: String, z: String
> >
class C<
x: Int // adad
>
class G<
x: String, y: String
, /* */ z: String // adad
>
class G<
x: String, y: String
/* */, /* */ z: String /**/,
>()
class H<
x: String, /*
*/ y: String,
z: String /*
*/ ,>
class J<
x: String, y: String , z: String /*
*/
, /**/ >
class K<
x: String, y: String,
z: String // aw
, >
class L<
x: String, y: String, z: String //awd
>
// SET_TRUE: ALLOW_TRAILING_COMMA // SET_TRUE: ALLOW_TRAILING_COMMA
@@ -0,0 +1,89 @@
fun main() {
val x: (
y: Comparable<Comparable<Number>>,
z: Iterable<Iterable<Number>> // trailing comma
) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>,
z: Iterable<Iterable<Number>>
) -> Int = {
10
}
val x: (y: Comparable<Comparable<Number>>, z: Iterable<Iterable<Number>>) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>, z: Iterable<Iterable<Number>>,
) -> Int = {
10
}
val x: (y: Comparable<Comparable<Number>>) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>,
) -> Int = {
10
}
val x: (y: Comparable<Comparable<Number>>
) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>, //
z: Iterable<Iterable<Number>> // /**/
) -> Int = {
10
}
val x: (y: Comparable<Comparable<Number>>, z: Iterable<Iterable<Number>>
// wd
) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>,/*
*/
z: Iterable<Iterable<Number>>, /* //
*/
) -> Int = {
10
}
val x: (/**/y: Comparable<Comparable<Number>>/**/) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>,/**/
) -> Int = {
10
}
val x: (y: Comparable<Comparable<Number>>
) -> Int = {
10
}
val x: ( /*
*/y: Comparable<Comparable<Number>>) -> Int = {
10
}
}
// SET_TRUE: ALLOW_TRAILING_COMMA
@@ -0,0 +1,97 @@
fun main() {
val x: (
y: Comparable<Comparable<Number>>,
z: Iterable<Iterable<Number>>, // trailing comma
) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>,
z: Iterable<Iterable<Number>>,
) -> Int = {
10
}
val x: (y: Comparable<Comparable<Number>>, z: Iterable<Iterable<Number>>) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>, z: Iterable<Iterable<Number>>,
) -> Int = {
10
}
val x: (y: Comparable<Comparable<Number>>) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>,
) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>,
) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>,
) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>, //
z: Iterable<Iterable<Number>>, // /**/
) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>,
z: Iterable<Iterable<Number>>,
// wd
) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>,/*
*/
z: Iterable<Iterable<Number>>, /* //
*/
) -> Int = {
10
}
val x: (/**/y: Comparable<Comparable<Number>>/**/) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>,/**/
) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>,
) -> Int = {
10
}
val x: (
/*
*/
y: Comparable<Comparable<Number>>,
) -> Int = {
10
}
}
// SET_TRUE: ALLOW_TRAILING_COMMA
@@ -0,0 +1,80 @@
fun main() {
val x: (
y: Comparable<Comparable<Number>>,
z: Iterable<Iterable<Number>> // trailing comma
) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>,
z: Iterable<Iterable<Number>>
) -> Int = {
10
}
val x: (y: Comparable<Comparable<Number>>, z: Iterable<Iterable<Number>>) -> Int = {
10
}
val x: (y: Comparable<Comparable<Number>>, z: Iterable<Iterable<Number>>,) -> Int = {
10
}
val x: (y: Comparable<Comparable<Number>>) -> Int = {
10
}
val x: (y: Comparable<Comparable<Number>>,) -> Int = {
10
}
val x: (y: Comparable<Comparable<Number>>
) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>) -> Int = {
10
}
val x: (
y: Comparable<Comparable<Number>>, //
z: Iterable<Iterable<Number>> // /**/
) -> Int = {
10
}
val x: (y: Comparable<Comparable<Number>>, z: Iterable<Iterable<Number>>
// wd
) -> Int = {
10
}
val x: (y: Comparable<Comparable<Number>>/*
*/, z: Iterable<Iterable<Number>>, /* //
*/) -> Int = {
10
}
val x: (/**/y: Comparable<Comparable<Number>>/**/) -> Int = {
10
}
val x: (y: Comparable<Comparable<Number>>/**/,) -> Int = {
10
}
val x: (y: Comparable<Comparable<Number>>
) -> Int = {
10
}
val x: ( /*
*/y: Comparable<Comparable<Number>>) -> Int = {
10
}
}
// SET_TRUE: ALLOW_TRAILING_COMMA
@@ -468,8 +468,8 @@ class H(
class J( class J(
val x: String, val y: String, val x: String, val y: String,
val z: String /* val z: String, /*
*/, */
) )
class K( class K(
@@ -478,7 +478,7 @@ class K(
) )
class L( class L(
val x: String, val y: String, val z: String val x: String, val y: String, val z: String // adwd
) )
// SET_TRUE: ALLOW_TRAILING_COMMA // SET_TRUE: ALLOW_TRAILING_COMMA
@@ -462,7 +462,7 @@ class G(
class G( class G(
val x: String, val x: String,
val y: String val y: String
= "" /* */, /* */ = "", /* */ /* */
val z: String, val z: String,
) )
@@ -475,8 +475,8 @@ class H(
class J( class J(
val x: String, val y: String, val x: String, val y: String,
val z: String /* val z: String, /*
*/, */
) )
class K( class K(
@@ -485,7 +485,7 @@ class K(
) )
class L( class L(
val x: String, val y: String, val z: String, val x: String, val y: String, val z: String, // adwd
) )
// SET_TRUE: ALLOW_TRAILING_COMMA // SET_TRUE: ALLOW_TRAILING_COMMA
@@ -454,7 +454,7 @@ class K(
, ) , )
class L( class L(
val x: String, val y: String, val z: String val x: String, val y: String, val z: String // adwd
) )
// SET_TRUE: ALLOW_TRAILING_COMMA // SET_TRUE: ALLOW_TRAILING_COMMA
@@ -468,8 +468,8 @@ class H(
class J( class J(
val x: String, val y: String, val x: String, val y: String,
val z: String /* val z: String, /*
*/, */
) )
class K( class K(
@@ -478,7 +478,7 @@ class K(
) )
class L( class L(
val x: String, val y: String, val z: String val x: String, val y: String, val z: String // adwd
) )
// SET_TRUE: ALLOW_TRAILING_COMMA // SET_TRUE: ALLOW_TRAILING_COMMA
@@ -462,7 +462,7 @@ class G(
class G( class G(
val x: String, val x: String,
val y: String val y: String
= "" /* */, /* */ = "", /* */ /* */
val z: String, val z: String,
) )
@@ -475,8 +475,8 @@ class H(
class J( class J(
val x: String, val y: String, val x: String, val y: String,
val z: String /* val z: String, /*
*/, */
) )
class K( class K(
@@ -485,7 +485,7 @@ class K(
) )
class L( class L(
val x: String, val y: String, val z: String, val x: String, val y: String, val z: String, // adwd
) )
// SET_TRUE: ALLOW_TRAILING_COMMA // SET_TRUE: ALLOW_TRAILING_COMMA
@@ -454,7 +454,7 @@ class K(
, ) , )
class L( class L(
val x: String, val y: String, val z: String val x: String, val y: String, val z: String // adwd
) )
// SET_TRUE: ALLOW_TRAILING_COMMA // SET_TRUE: ALLOW_TRAILING_COMMA
@@ -490,8 +490,8 @@ class H(
class J( class J(
val x: String, val x: String,
val y: String, val y: String,
val z: String /* val z: String, /*
*/, */
) )
class K( class K(
@@ -503,7 +503,7 @@ class K(
class L( class L(
val x: String, val x: String,
val y: String, val y: String,
val z: String val z: String // adwd
) )
// SET_TRUE: ALLOW_TRAILING_COMMA // SET_TRUE: ALLOW_TRAILING_COMMA
@@ -477,7 +477,7 @@ class G(
class G( class G(
val x: String, val x: String,
val y: String val y: String
= "" /* */, /* */ = "", /* */ /* */
val z: String, val z: String,
) )
@@ -491,8 +491,8 @@ class H(
class J( class J(
val x: String, val x: String,
val y: String, val y: String,
val z: String /* val z: String, /*
*/, */
) )
class K( class K(
@@ -504,7 +504,7 @@ class K(
class L( class L(
val x: String, val x: String,
val y: String, val y: String,
val z: String, val z: String, // adwd
) )
// SET_TRUE: ALLOW_TRAILING_COMMA // SET_TRUE: ALLOW_TRAILING_COMMA
@@ -454,7 +454,7 @@ class K(
, ) , )
class L( class L(
val x: String, val y: String, val z: String val x: String, val y: String, val z: String // adwd
) )
// SET_TRUE: ALLOW_TRAILING_COMMA // SET_TRUE: ALLOW_TRAILING_COMMA
@@ -468,8 +468,8 @@ class H(
class J( class J(
val x: String, val y: String, val x: String, val y: String,
val z: String /* val z: String, /*
*/, */
) )
class K( class K(
@@ -478,7 +478,7 @@ class K(
) )
class L( class L(
val x: String, val y: String, val z: String val x: String, val y: String, val z: String // adwd
) )
// SET_TRUE: ALLOW_TRAILING_COMMA // SET_TRUE: ALLOW_TRAILING_COMMA
@@ -462,7 +462,7 @@ class G(
class G( class G(
val x: String, val x: String,
val y: String val y: String
= "" /* */, /* */ = "", /* */ /* */
val z: String, val z: String,
) )
@@ -475,8 +475,8 @@ class H(
class J( class J(
val x: String, val y: String, val x: String, val y: String,
val z: String /* val z: String, /*
*/, */
) )
class K( class K(
@@ -485,7 +485,7 @@ class K(
) )
class L( class L(
val x: String, val y: String, val z: String, val x: String, val y: String, val z: String, // adwd
) )
// SET_TRUE: ALLOW_TRAILING_COMMA // SET_TRUE: ALLOW_TRAILING_COMMA
@@ -454,7 +454,7 @@ class K(
, ) , )
class L( class L(
val x: String, val y: String, val z: String val x: String, val y: String, val z: String // adwd
) )
// SET_TRUE: ALLOW_TRAILING_COMMA // SET_TRUE: ALLOW_TRAILING_COMMA
@@ -1299,6 +1299,11 @@ public class FormatterTestGenerated extends AbstractFormatterTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/formatter/trailingComma/valueParameters"), Pattern.compile("^([^\\.]+)\\.after\\.kt.*$"), null, true); KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/formatter/trailingComma/valueParameters"), Pattern.compile("^([^\\.]+)\\.after\\.kt.*$"), null, true);
} }
@TestMetadata("LambdaValueParameters.after.kt")
public void testLambdaValueParameters() throws Exception {
runTest("idea/testData/formatter/trailingComma/valueParameters/LambdaValueParameters.after.kt");
}
@TestMetadata("ParameterListChopAsNeeded.after.kt") @TestMetadata("ParameterListChopAsNeeded.after.kt")
public void testParameterListChopAsNeeded() throws Exception { public void testParameterListChopAsNeeded() throws Exception {
runTest("idea/testData/formatter/trailingComma/valueParameters/ParameterListChopAsNeeded.after.kt"); runTest("idea/testData/formatter/trailingComma/valueParameters/ParameterListChopAsNeeded.after.kt");
@@ -1851,6 +1856,11 @@ public class FormatterTestGenerated extends AbstractFormatterTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/formatter/trailingComma/valueParameters"), Pattern.compile("^([^\\.]+)\\.after\\.inv\\.kt.*$"), null, true); KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/formatter/trailingComma/valueParameters"), Pattern.compile("^([^\\.]+)\\.after\\.inv\\.kt.*$"), null, true);
} }
@TestMetadata("LambdaValueParameters.after.inv.kt")
public void testLambdaValueParameters() throws Exception {
runTest("idea/testData/formatter/trailingComma/valueParameters/LambdaValueParameters.after.inv.kt");
}
@TestMetadata("ParameterListChopAsNeeded.after.inv.kt") @TestMetadata("ParameterListChopAsNeeded.after.inv.kt")
public void testParameterListChopAsNeeded() throws Exception { public void testParameterListChopAsNeeded() throws Exception {
runTest("idea/testData/formatter/trailingComma/valueParameters/ParameterListChopAsNeeded.after.inv.kt"); runTest("idea/testData/formatter/trailingComma/valueParameters/ParameterListChopAsNeeded.after.inv.kt");