Formatter, NJ2K: fix indent for comments inside function literals
#KT-4194 Fixed #KT-31881 Fixed #KT-34673 Fixed #KT-35152 Fixed
This commit is contained in:
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.idea.formatter.KotlinSpacingBuilder.CustomSpacingBui
|
||||
import org.jetbrains.kotlin.idea.util.requireNode
|
||||
import org.jetbrains.kotlin.lexer.KtTokens.*
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.children
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral
|
||||
import org.jetbrains.kotlin.psi.psiUtil.siblings
|
||||
import org.jetbrains.kotlin.psi.psiUtil.textRangeWithoutComments
|
||||
@@ -90,6 +91,14 @@ fun createSpacingBuilder(settings: CodeStyleSettings, builderUtil: KotlinSpacing
|
||||
|
||||
inPosition(right = BLOCK_COMMENT).spacing(commentSpacing(0))
|
||||
inPosition(right = EOL_COMMENT).spacing(commentSpacing(1))
|
||||
inPosition(parent = FUNCTION_LITERAL, right = BLOCK).customRule { _, _, right ->
|
||||
when (right.node?.children()?.firstOrNull()?.elementType) {
|
||||
BLOCK_COMMENT -> commentSpacing(0)
|
||||
EOL_COMMENT -> commentSpacing(1)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
inPosition(leftSet = DECLARATIONS, rightSet = DECLARATIONS).customRule(fun(
|
||||
_: ASTBlock,
|
||||
_: ASTBlock,
|
||||
@@ -97,9 +106,12 @@ fun createSpacingBuilder(settings: CodeStyleSettings, builderUtil: KotlinSpacing
|
||||
): Spacing? {
|
||||
val node = right.node ?: return null
|
||||
val elementStart = node.startOfDeclaration() ?: return null
|
||||
return if (StringUtil.containsLineBreak(node.text.subSequence(0, elementStart.startOffset - node.startOffset).trimStart())) {
|
||||
return if (StringUtil.containsLineBreak(
|
||||
node.text.subSequence(0, elementStart.startOffset - node.startOffset).trimStart()
|
||||
)
|
||||
)
|
||||
createSpacing(0, minLineFeeds = 2)
|
||||
} else
|
||||
else
|
||||
null
|
||||
})
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.psi.*
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager
|
||||
import org.jetbrains.kotlin.lexer.KtToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtFunctionLiteral
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import java.util.*
|
||||
@@ -347,6 +348,11 @@ class CommentSaver(originalElements: PsiChildRange, private val saveLineBreaks:
|
||||
if (commentTreeElement.spaceAfter.isNotEmpty()) {
|
||||
parent.addBefore(psiFactory.createWhiteSpace(commentTreeElement.spaceAfter), anchorElement)
|
||||
}
|
||||
|
||||
val functionLiteral = restored.parent as? KtFunctionLiteral
|
||||
if (functionLiteral != null && commentTreeElement.spaceBefore.isNotEmpty()) {
|
||||
functionLiteral.addBefore(psiFactory.createWhiteSpace(commentTreeElement.spaceBefore), restored)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
restored = putAbandonedCommentsAfter.parent.addBefore(comment, putAbandonedCommentsAfter) as PsiComment
|
||||
|
||||
+64
-1
@@ -6,4 +6,67 @@ fun foo() {
|
||||
// Some comment
|
||||
it
|
||||
}
|
||||
}
|
||||
|
||||
test() {
|
||||
// val a = 42
|
||||
}
|
||||
|
||||
test() {
|
||||
/*
|
||||
val a = 42
|
||||
*/
|
||||
}
|
||||
|
||||
test() {
|
||||
/*
|
||||
val a = 42
|
||||
*/
|
||||
}
|
||||
|
||||
test() {
|
||||
// val a = 42
|
||||
val b = 44
|
||||
}
|
||||
}
|
||||
|
||||
val s = Shadow { -> // wdwd
|
||||
val a = 42
|
||||
}
|
||||
|
||||
val s2 = Shadow { // wdwd
|
||||
val a = 42
|
||||
}
|
||||
|
||||
val s3 = Shadow(fun() { // wdwd
|
||||
val a = 42
|
||||
})
|
||||
|
||||
val s4 = Shadow(fun() { /* s */
|
||||
val a = 42
|
||||
})
|
||||
|
||||
val s5 = Shadow { ->
|
||||
// wdwd
|
||||
val a = 42
|
||||
}
|
||||
|
||||
val s6 = Shadow {
|
||||
// wdwd
|
||||
val a = 42
|
||||
}
|
||||
|
||||
val s7 = Shadow(fun() {
|
||||
// wdwd
|
||||
val a = 42
|
||||
})
|
||||
|
||||
val s8 = Shadow(fun() {
|
||||
// wdwd
|
||||
val a = 42
|
||||
})
|
||||
|
||||
val s9 = Shadow { -> /* s */
|
||||
val a = 42
|
||||
}
|
||||
|
||||
class Shadow(callback: () -> Unit)
|
||||
|
||||
+64
-1
@@ -6,4 +6,67 @@ fun foo() {
|
||||
// Some comment
|
||||
it
|
||||
}
|
||||
}
|
||||
|
||||
test() {
|
||||
// val a = 42
|
||||
}
|
||||
|
||||
test() {
|
||||
/*
|
||||
val a = 42
|
||||
*/
|
||||
}
|
||||
|
||||
test() {
|
||||
/*
|
||||
val a = 42
|
||||
*/
|
||||
}
|
||||
|
||||
test() {
|
||||
// val a = 42
|
||||
val b = 44
|
||||
}
|
||||
}
|
||||
|
||||
val s = Shadow { -> // wdwd
|
||||
val a = 42
|
||||
}
|
||||
|
||||
val s2 = Shadow { // wdwd
|
||||
val a = 42
|
||||
}
|
||||
|
||||
val s3 = Shadow(fun() { // wdwd
|
||||
val a = 42
|
||||
})
|
||||
|
||||
val s4 = Shadow(fun() { /* s */
|
||||
val a = 42
|
||||
})
|
||||
|
||||
val s5 = Shadow { ->
|
||||
// wdwd
|
||||
val a = 42
|
||||
}
|
||||
|
||||
val s6 = Shadow {
|
||||
// wdwd
|
||||
val a = 42
|
||||
}
|
||||
|
||||
val s7 = Shadow(fun() {
|
||||
// wdwd
|
||||
val a = 42
|
||||
})
|
||||
|
||||
val s8 = Shadow(fun() {
|
||||
// wdwd
|
||||
val a = 42
|
||||
})
|
||||
|
||||
val s9 = Shadow { -> /* s */
|
||||
val a = 42
|
||||
}
|
||||
|
||||
class Shadow(callback: () -> Unit)
|
||||
|
||||
+1
-2
@@ -4,8 +4,7 @@
|
||||
fun foo(list: List<String>) {
|
||||
// string should be non-empty
|
||||
// save it into result
|
||||
val result: String? = list.firstOrNull {
|
||||
// search for first non-empty string in the list
|
||||
val result: String? = list.firstOrNull { // search for first non-empty string in the list
|
||||
it.length > 0
|
||||
}
|
||||
}
|
||||
@@ -5,14 +5,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.nj2k
|
||||
|
||||
import com.intellij.psi.PsiComment
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiKeyword
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.javadoc.PsiDocComment
|
||||
import org.jetbrains.kotlin.idea.j2k.IdeaDocCommentConverter
|
||||
import org.jetbrains.kotlin.nj2k.tree.JKComment
|
||||
import org.jetbrains.kotlin.nj2k.tree.JKFormattingOwner
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class FormattingCollector {
|
||||
private val commentCache = mutableMapOf<PsiElement, JKComment>()
|
||||
@@ -48,13 +47,21 @@ class FormattingCollector {
|
||||
this
|
||||
)
|
||||
)
|
||||
is PsiComment -> JKComment(text)
|
||||
is PsiComment -> JKComment(text, indent())
|
||||
else -> null
|
||||
} ?: return null
|
||||
commentCache[this] = token
|
||||
return token
|
||||
}
|
||||
|
||||
private fun PsiComment.indent(): String? = takeIf { parent is PsiCodeBlock }?.prevSibling?.safeAs<PsiWhiteSpace>()?.let { space ->
|
||||
val text = space.text
|
||||
if (space.prevSibling is PsiStatement)
|
||||
text.indexOfFirst(StringUtil::isLineBreak).takeIf { it != -1 }?.let { text.substring(it + 1) } ?: text
|
||||
else
|
||||
text
|
||||
}
|
||||
|
||||
private fun Sequence<PsiElement>.toComments(): List<JKComment> =
|
||||
takeWhile { it is PsiComment || it is PsiWhiteSpace || it.text == ";" }
|
||||
.mapNotNull { it.asComment() }
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.nj2k.printing
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jetbrains.kotlin.nj2k.tree.JKComment
|
||||
import org.jetbrains.kotlin.nj2k.tree.JKDeclaration
|
||||
import org.jetbrains.kotlin.nj2k.tree.JKFormattingOwner
|
||||
@@ -32,7 +33,8 @@ internal class JKCommentPrinter(val printer: JKPrinter) {
|
||||
for (comment in this@createText) {
|
||||
if (comment.shouldBeDropped()) continue
|
||||
val text = comment.createText() ?: continue
|
||||
if (needNewLine) appendln() else append(' ')
|
||||
if (needNewLine && comment.indent?.let { StringUtil.containsLineBreak(it) } != true) appendln()
|
||||
append(comment.indent ?: ' ')
|
||||
append(text)
|
||||
needNewLine = text.startsWith("//") || '\n' in text
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.nj2k.tree
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
|
||||
|
||||
class JKComment(val text: String) {
|
||||
class JKComment(val text: String, val indent: String? = null) {
|
||||
val isSingleline
|
||||
get() = text.startsWith("//")
|
||||
}
|
||||
|
||||
+2
-1
@@ -4,7 +4,8 @@ package test
|
||||
|
||||
class Test(str: String) {
|
||||
var myStr = "String2"
|
||||
fun sout(str: String) { // UNNECESSARY_NOT_NULL_ASSERTION heuristic does not work any more, instead we can skip generating !! altogether
|
||||
fun sout(str: String) {
|
||||
// UNNECESSARY_NOT_NULL_ASSERTION heuristic does not work any more, instead we can skip generating !! altogether
|
||||
println(str)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ object Test {
|
||||
fun main(args: Array<String>) {
|
||||
println() // Comment
|
||||
foo() // Comment1
|
||||
// Comment2
|
||||
// Comment2
|
||||
.indexOf("s")
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -6,16 +6,19 @@ package foo
|
||||
// we need ArrayList
|
||||
// let's declare a class:
|
||||
internal class A /* just a sample name*/ : Runnable /* let's implement Runnable */ {
|
||||
fun foo /* again a sample name */(p: Int /* parameter p */, c: Char /* parameter c */) { // let's print something:
|
||||
fun foo /* again a sample name */(p: Int /* parameter p */, c: Char /* parameter c */) {
|
||||
// let's print something:
|
||||
println("1") // print 1
|
||||
println("2") // print 2
|
||||
println("3") // print 3
|
||||
|
||||
// end of printing
|
||||
if (p > 0) { // do this only when p > 0
|
||||
// we print 4 and return
|
||||
// we print 4 and return
|
||||
println("3")
|
||||
return // do not continue
|
||||
}
|
||||
|
||||
// some code to be added
|
||||
}
|
||||
} // end of class A
|
||||
|
||||
+3
-2
@@ -3,8 +3,9 @@
|
||||
package foo
|
||||
|
||||
internal class A {
|
||||
fun /* nothing to return */foo( /* no parameters at all */) { // let declare a variable
|
||||
// with 2 comments before
|
||||
fun /* nothing to return */foo( /* no parameters at all */) {
|
||||
// let declare a variable
|
||||
// with 2 comments before
|
||||
val /*int*/a /* it's a */ = 2 /* it's 2 */ + 1 /* it's 1 */ // variable a declared
|
||||
} // end of foo
|
||||
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
public class Foo {
|
||||
public void foo() {
|
||||
System.out.println();
|
||||
// comment
|
||||
// comment 2
|
||||
// comment 3
|
||||
}
|
||||
|
||||
public void setState(Integer state) {
|
||||
/*some comment 1/*/
|
||||
/*some comment 2/*/
|
||||
/*some comment 3/*/
|
||||
/*some comment 4/*/
|
||||
}
|
||||
|
||||
public void setState2(Integer state) { /*some comment 1/*/
|
||||
/*some comment 2/*/
|
||||
/*some comment 3/*/
|
||||
/*some comment 4/*/
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
class Foo {
|
||||
fun foo() {
|
||||
println()
|
||||
// comment
|
||||
// comment 2
|
||||
// comment 3
|
||||
}
|
||||
|
||||
fun setState(state: Int?) {
|
||||
/*some comment 1/ */
|
||||
/*some comment 2/ */
|
||||
/*some comment 3/ */
|
||||
/*some comment 4/ */
|
||||
}
|
||||
|
||||
fun setState2(state: Int?) { /*some comment 1/ */
|
||||
/*some comment 2/ */
|
||||
/*some comment 3/ */
|
||||
/*some comment 4/ */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
public class Foo {
|
||||
private Integer someInt;
|
||||
public void setState(Integer state) {
|
||||
//some comment 1
|
||||
someInt = state;
|
||||
//some comment 2
|
||||
if (state == 2)
|
||||
System.out.println("2");
|
||||
}
|
||||
public Integer getState() {
|
||||
return someInt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
class Foo {
|
||||
var state: Int? = null
|
||||
private set
|
||||
|
||||
fun setState(state: Int) {
|
||||
//some comment 1
|
||||
this.state = state
|
||||
//some comment 2
|
||||
if (state == 2) println("2")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
internal class F {
|
||||
//c1
|
||||
/*c2*/
|
||||
/*c2*/
|
||||
fun f1() {}
|
||||
|
||||
//c3
|
||||
//c4
|
||||
//c4
|
||||
fun f2() {}
|
||||
var i = 0
|
||||
fun f3() {} //c5
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
internal class F {
|
||||
//c3
|
||||
//c4
|
||||
//c4
|
||||
fun f2() {}
|
||||
fun f3() {}
|
||||
fun f4() {}
|
||||
|
||||
companion object {
|
||||
//c1
|
||||
/*c2*/
|
||||
/*c2*/
|
||||
fun f1() {}
|
||||
var i = 0
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
internal object F {
|
||||
//c1
|
||||
/*c2*/
|
||||
/*c2*/
|
||||
fun f1() {}
|
||||
|
||||
//c3
|
||||
//c4
|
||||
//c4
|
||||
fun f2() {}
|
||||
var i = 0
|
||||
fun f3() {} //c5
|
||||
|
||||
@@ -8,7 +8,8 @@ internal class Test {
|
||||
return x.toDouble()
|
||||
}
|
||||
|
||||
fun nya(): Double { //TODO explicitlly call apply here
|
||||
fun nya(): Double {
|
||||
//TODO explicitlly call apply here
|
||||
return foo(1, FunctionalI<Int, Double> { x: Int -> this.toDouble(x) })
|
||||
}
|
||||
}
|
||||
+8
-7
@@ -15,7 +15,8 @@ internal class C {
|
||||
/**
|
||||
* This is a function doc comment.
|
||||
*/
|
||||
fun foo() { /* This is a function comment */
|
||||
fun foo() {
|
||||
/* This is a function comment */
|
||||
}
|
||||
|
||||
//simple one line comment for function
|
||||
@@ -25,29 +26,29 @@ internal class C {
|
||||
var j = 0
|
||||
|
||||
//double c style
|
||||
//comment before function
|
||||
//comment before function
|
||||
fun f2() {}
|
||||
|
||||
//double c style
|
||||
//comment before field
|
||||
//comment before field
|
||||
var k = 0
|
||||
//combination
|
||||
/** of
|
||||
*/
|
||||
//
|
||||
//
|
||||
/**
|
||||
* different
|
||||
*/
|
||||
//comments
|
||||
//comments
|
||||
fun f3() {}
|
||||
//combination
|
||||
/** of
|
||||
*/
|
||||
//
|
||||
//
|
||||
/**
|
||||
* different
|
||||
*/
|
||||
//comments
|
||||
//comments
|
||||
var l = 0
|
||||
|
||||
/*two*/ /*comments*/ /*line*/
|
||||
|
||||
+2
-2
@@ -14,6 +14,6 @@ class TestMutltipleCtorsWithJavadoc
|
||||
this.y = y
|
||||
}
|
||||
// ---
|
||||
// Constructors
|
||||
//
|
||||
// Constructors
|
||||
//
|
||||
}
|
||||
+2
-1
@@ -10,7 +10,8 @@ class C {
|
||||
val c = stream.read()
|
||||
println(c)
|
||||
}
|
||||
} finally { // dispose something else
|
||||
} finally {
|
||||
// dispose something else
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -1030,6 +1030,11 @@ public class NewJavaToKotlinConverterSingleFileTestGenerated extends AbstractNew
|
||||
runTest("nj2k/testData/newJ2k/comments/comments2.java");
|
||||
}
|
||||
|
||||
@TestMetadata("comments3.java")
|
||||
public void testComments3() throws Exception {
|
||||
runTest("nj2k/testData/newJ2k/comments/comments3.java");
|
||||
}
|
||||
|
||||
@TestMetadata("commentsForConstructors.java")
|
||||
public void testCommentsForConstructors() throws Exception {
|
||||
runTest("nj2k/testData/newJ2k/comments/commentsForConstructors.java");
|
||||
@@ -1040,6 +1045,11 @@ public class NewJavaToKotlinConverterSingleFileTestGenerated extends AbstractNew
|
||||
runTest("nj2k/testData/newJ2k/comments/fieldWithEndOfLineComment.java");
|
||||
}
|
||||
|
||||
@TestMetadata("fieldWithEndOfLineComment2.java")
|
||||
public void testFieldWithEndOfLineComment2() throws Exception {
|
||||
runTest("nj2k/testData/newJ2k/comments/fieldWithEndOfLineComment2.java");
|
||||
}
|
||||
|
||||
@TestMetadata("fieldsInitializedFromParams.java")
|
||||
public void testFieldsInitializedFromParams() throws Exception {
|
||||
runTest("nj2k/testData/newJ2k/comments/fieldsInitializedFromParams.java");
|
||||
|
||||
Reference in New Issue
Block a user