New J2K: rework Java code formatting collecting

#KT-33687 fixed
This commit is contained in:
Ilya Kirillov
2019-09-26 14:38:46 +03:00
parent 37ee81dfa1
commit f3b53a9532
43 changed files with 396 additions and 358 deletions
@@ -0,0 +1,107 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
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.psi.javadoc.PsiDocComment
import org.jetbrains.kotlin.idea.j2k.IdeaDocCommentConverter
import org.jetbrains.kotlin.nj2k.tree.JKComment
import org.jetbrains.kotlin.nj2k.tree.JKFormattingOwner
class FormattingCollector {
private val commentCache = mutableMapOf<PsiElement, JKComment>()
fun takeFormattingFrom(
element: JKFormattingOwner,
psi: PsiElement?,
saveLineBreaks: Boolean,
takeTrailingComments: Boolean,
takeLeadingComments: Boolean
) {
if (psi == null) return
val (leftTokens, rightTokens) = psi.collectComments(takeTrailingComments, takeLeadingComments)
element.trailingComments += leftTokens
element.leadingComments += rightTokens
if (saveLineBreaks) {
element.hasLeadingLineBreak = psi.hasLineBreakAfter()
element.hasTrailingLineBreak = psi.hasLineBreakBefore()
}
}
fun takeLineBreaksFrom(element: JKFormattingOwner, psi: PsiElement?) {
if (psi == null) return
element.hasLeadingLineBreak = psi.hasLineBreakAfter()
element.hasTrailingLineBreak = psi.hasLineBreakBefore()
}
private fun PsiElement.asComment(): JKComment? {
if (this in commentCache) return commentCache.getValue(this)
val token = when (this) {
is PsiDocComment -> JKComment(
IdeaDocCommentConverter.convertDocComment(
this
)
)
is PsiComment -> JKComment(text)
else -> null
} ?: return null
commentCache[this] = token
return token
}
private fun Sequence<PsiElement>.toComments(): List<JKComment> =
takeWhile { it is PsiComment || it is PsiWhiteSpace || it.text == ";" }
.mapNotNull { it.asComment() }
.toList()
fun PsiElement.leadingCommentsWithParent(): Sequence<JKComment> {
val innerElements = leadingComments()
return (if (innerElements.lastOrNull()?.nextSibling == null && this is PsiKeyword)
innerElements + parent?.leadingComments().orEmpty()
else innerElements).mapNotNull { it.asComment() }
}
private fun PsiElement.trailingCommentsWithParent(): Sequence<JKComment> {
val innerElements = trailingComments()
return (if (innerElements.firstOrNull()?.prevSibling == null && this is PsiKeyword)
innerElements + parent?.trailingComments().orEmpty()
else innerElements).mapNotNull { it.asComment() }
}
private fun PsiElement.isNonCodeElement() =
this is PsiComment || this is PsiWhiteSpace || textMatches(";") || textLength == 0
private fun PsiElement.leadingComments() =
generateSequence(nextSibling) { it.nextSibling }
.takeWhile { it.isNonCodeElement() }
private fun PsiElement.trailingComments() =
generateSequence(prevSibling) { it.prevSibling }
.takeWhile { it.isNonCodeElement() }
private fun PsiElement.hasLineBreakBefore() = trailingComments().any { it is PsiWhiteSpace && it.textContains('\n') }
private fun PsiElement.hasLineBreakAfter() = leadingComments().any { it is PsiWhiteSpace && it.textContains('\n') }
private fun PsiElement.collectComments(
takeTrailingComments: Boolean,
takeLeadingComments: Boolean
): Pair<List<JKComment>, List<JKComment>> {
val leftInnerTokens = children.asSequence().toComments().asReversed()
val rightInnerTokens = when {
children.isEmpty() -> emptyList()
else -> generateSequence(children.last()) { it.prevSibling }
.toComments()
.asReversed()
}
val leftComments = (leftInnerTokens + if (takeTrailingComments) trailingCommentsWithParent() else emptySequence()).asReversed()
val rightComments = rightInnerTokens + if (takeLeadingComments) leadingCommentsWithParent() else emptySequence()
return leftComments to rightComments
}
}
@@ -35,13 +35,11 @@ import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.elements.KtLightField import org.jetbrains.kotlin.asJava.elements.KtLightField
import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.idea.caches.lightClasses.KtLightClassForDecompiledDeclaration import org.jetbrains.kotlin.idea.caches.lightClasses.KtLightClassForDecompiledDeclaration
import org.jetbrains.kotlin.idea.j2k.IdeaDocCommentConverter
import org.jetbrains.kotlin.idea.j2k.content import org.jetbrains.kotlin.idea.j2k.content
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
import org.jetbrains.kotlin.j2k.ReferenceSearcher import org.jetbrains.kotlin.j2k.ReferenceSearcher
import org.jetbrains.kotlin.j2k.ast.Nullability import org.jetbrains.kotlin.j2k.ast.Nullability
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.nj2k.symbols.* import org.jetbrains.kotlin.nj2k.symbols.*
import org.jetbrains.kotlin.nj2k.tree.* import org.jetbrains.kotlin.nj2k.tree.*
import org.jetbrains.kotlin.nj2k.tree.JKLiteralExpression.LiteralType.* import org.jetbrains.kotlin.nj2k.tree.JKLiteralExpression.LiteralType.*
@@ -52,7 +50,6 @@ import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration
import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -68,11 +65,36 @@ class JavaToJKTreeBuilder constructor(
} }
private val expressionTreeMapper = ExpressionTreeMapper() private val expressionTreeMapper = ExpressionTreeMapper()
private val referenceSearcher: ReferenceSearcher = converterServices.oldServices.referenceSearcher private val referenceSearcher: ReferenceSearcher = converterServices.oldServices.referenceSearcher
private val declarationMapper = DeclarationMapper(expressionTreeMapper) private val declarationMapper = DeclarationMapper(expressionTreeMapper)
private val formattingCollector = FormattingCollector()
// we don't want to capture comments of previous declaration/statement
private fun PsiElement.takeLeadingCommentsNeeded() =
this !is PsiMember && this !is PsiStatement
private fun <T : JKFormattingOwner> T.withFormattingFrom(
psi: PsiElement?,
assignLineBreaks: Boolean = false,
takeTrailingComments: Boolean = true,
takeLeadingComments: Boolean = psi?.takeLeadingCommentsNeeded() ?: false
): T = with(formattingCollector) {
takeFormattingFrom(this@withFormattingFrom, psi, assignLineBreaks, takeTrailingComments, takeLeadingComments)
this@withFormattingFrom
}
private fun <O : JKFormattingOwner> O.withLineBreaksFrom(psi: PsiElement?) = with(formattingCollector) {
takeLineBreaksFrom(this@withLineBreaksFrom, psi)
this@withLineBreaksFrom
}
private fun <O : JKFormattingOwner> O.withLeadingCommentsWithParent(psi: PsiElement?) = with(formattingCollector) {
if (psi == null) return@with this@withLeadingCommentsWithParent
this@withLeadingCommentsWithParent.leadingComments += psi.leadingCommentsWithParent()
return this@withLeadingCommentsWithParent
}
private fun PsiJavaFile.toJK(): JKFile = private fun PsiJavaFile.toJK(): JKFile =
JKFile( JKFile(
packageStatement?.toJK() ?: JKPackageDeclaration(JKNameIdentifier("")), packageStatement?.toJK() ?: JKPackageDeclaration(JKNameIdentifier("")),
@@ -83,15 +105,15 @@ class JavaToJKTreeBuilder constructor(
private fun PsiImportList?.toJK(saveImports: Boolean): JKImportList = private fun PsiImportList?.toJK(saveImports: Boolean): JKImportList =
JKImportList(this?.allImportStatements?.mapNotNull { it.toJK(saveImports) }.orEmpty()).also { importList -> JKImportList(this?.allImportStatements?.mapNotNull { it.toJK(saveImports) }.orEmpty()).also { importList ->
val innerComments = this?.collectDescendantsOfType<PsiComment>()?.map { comment -> val innerComments = this?.collectDescendantsOfType<PsiComment>()?.map { comment ->
JKCommentElement(comment.text) JKComment(comment.text)
}.orEmpty() }.orEmpty()
importList.leftNonCodeElements += innerComments importList.trailingComments += innerComments
} }
private fun PsiPackageStatement.toJK(): JKPackageDeclaration = private fun PsiPackageStatement.toJK(): JKPackageDeclaration =
JKPackageDeclaration(JKNameIdentifier(packageName)) JKPackageDeclaration(JKNameIdentifier(packageName))
.also { .also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
symbolProvider.provideUniverseSymbol(this, it) symbolProvider.provideUniverseSymbol(this, it)
} }
@@ -118,14 +140,14 @@ class JavaToJKTreeBuilder constructor(
return JKImportStatement(JKNameIdentifier(name)) return JKImportStatement(JKNameIdentifier(name))
.also { .also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
} }
private fun PsiIdentifier?.toJK(): JKNameIdentifier = private fun PsiIdentifier?.toJK(): JKNameIdentifier =
this?.let { this?.let {
JKNameIdentifier(it.text).also { JKNameIdentifier(it.text).also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
} ?: JKNameIdentifier("") } ?: JKNameIdentifier("")
@@ -165,7 +187,7 @@ class JavaToJKTreeBuilder constructor(
is PsiPolyadicExpression -> { is PsiPolyadicExpression -> {
val token = JKOperatorToken.fromElementType(operationTokenType) val token = JKOperatorToken.fromElementType(operationTokenType)
val type = type?.toJK() ?: typeFactory.types.nullableAny val type = type?.toJK() ?: typeFactory.types.nullableAny
val jkOperands = operands.map { it.toJK().parenthesizeIfBinaryExpression() } val jkOperands = operands.map { it.toJK().withLineBreaksFrom(it).parenthesizeIfBinaryExpression() }
jkOperands.reduce { acc, operand -> jkOperands.reduce { acc, operand ->
JKBinaryExpression(acc, operand, JKKtOperatorImpl(token, type)) JKBinaryExpression(acc, operand, JKKtOperatorImpl(token, type))
}.let { folded -> }.let { folded ->
@@ -180,7 +202,7 @@ class JavaToJKTreeBuilder constructor(
}.also { }.also {
if (this != null) { if (this != null) {
(it as PsiOwner).psi = this (it as PsiOwner).psi = this
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
} }
} }
@@ -195,14 +217,14 @@ class JavaToJKTreeBuilder constructor(
else -> JKClassLiteralExpression.ClassLiteralType.JAVA_CLASS else -> JKClassLiteralExpression.ClassLiteralType.JAVA_CLASS
} }
).also { ).also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
} }
fun PsiInstanceOfExpression.toJK(): JKIsExpression = fun PsiInstanceOfExpression.toJK(): JKIsExpression =
JKIsExpression(operand.toJK(), JKTypeElement(checkType?.type?.toJK() ?: JKNoType)) JKIsExpression(operand.toJK(), JKTypeElement(checkType?.type?.toJK() ?: JKNoType))
.also { .also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
fun PsiAssignmentExpression.toJK(): JKJavaAssignmentExpression { fun PsiAssignmentExpression.toJK(): JKJavaAssignmentExpression {
@@ -211,7 +233,7 @@ class JavaToJKTreeBuilder constructor(
rExpression.toJK(), rExpression.toJK(),
createOperator(operationSign.tokenType, type) createOperator(operationSign.tokenType, type)
).also { ).also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
} }
@@ -226,14 +248,14 @@ class JavaToJKTreeBuilder constructor(
else -> JKOperatorToken.fromElementType(operationSign.tokenType) else -> JKOperatorToken.fromElementType(operationSign.tokenType)
} }
return JKBinaryExpression( return JKBinaryExpression(
lOperand.toJK(), lOperand.toJK().withLineBreaksFrom(lOperand),
rOperand.toJK(), rOperand.toJK().withLineBreaksFrom(rOperand),
JKKtOperatorImpl( JKKtOperatorImpl(
token, token,
type?.toJK() ?: typeFactory.types.nullableAny type?.toJK() ?: typeFactory.types.nullableAny
) )
).also { ).also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
} }
@@ -252,7 +274,7 @@ class JavaToJKTreeBuilder constructor(
JavaTokenType.DOUBLE_LITERAL -> JKLiteralExpression(text, DOUBLE) JavaTokenType.DOUBLE_LITERAL -> JKLiteralExpression(text, DOUBLE)
else -> throwCanNotConvertError("Unknown literal element type: $literalElementType") else -> throwCanNotConvertError("Unknown literal element type: $literalElementType")
}.also { }.also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
} }
@@ -266,12 +288,12 @@ class JavaToJKTreeBuilder constructor(
JavaTokenType.TILDE -> operand.toJK().callOn(symbolProvider.provideMethodSymbol("kotlin.Int.inv")) JavaTokenType.TILDE -> operand.toJK().callOn(symbolProvider.provideMethodSymbol("kotlin.Int.inv"))
else -> JKPrefixExpression(operand.toJK(), createOperator(operationSign.tokenType, type)) else -> JKPrefixExpression(operand.toJK(), createOperator(operationSign.tokenType, type))
}.also { }.also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
fun PsiPostfixExpression.toJK(): JKExpression = fun PsiPostfixExpression.toJK(): JKExpression =
JKPostfixExpression(operand.toJK(), createOperator(operationSign.tokenType, type)).also { JKPostfixExpression(operand.toJK(), createOperator(operationSign.tokenType, type)).also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
fun PsiLambdaExpression.toJK(): JKExpression { fun PsiLambdaExpression.toJK(): JKExpression {
@@ -286,7 +308,7 @@ class JavaToJKTreeBuilder constructor(
with(declarationMapper) { parameterList.parameters.map { it.toJK() } }, with(declarationMapper) { parameterList.parameters.map { it.toJK() } },
functionalType() functionalType()
).also { ).also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
} }
@@ -309,7 +331,7 @@ class JavaToJKTreeBuilder constructor(
fun PsiMethodCallExpression.toJK(): JKExpression { fun PsiMethodCallExpression.toJK(): JKExpression {
val arguments = argumentList val arguments = argumentList
val typeArguments = getExplicitTypeArguments().toJK() val typeArguments = getExplicitTypeArguments().toJK()
val qualifier = methodExpression.qualifierExpression?.toJK() val qualifier = methodExpression.qualifierExpression?.toJK()?.withLineBreaksFrom(methodExpression.qualifierExpression)
val target = methodExpression.resolve() val target = methodExpression.resolve()
val symbol = target?.let { val symbol = target?.let {
symbolProvider.provideDirectSymbol(it) symbolProvider.provideDirectSymbol(it)
@@ -397,7 +419,7 @@ class JavaToJKTreeBuilder constructor(
JKFieldAccessExpression(symbol).qualified(qualifier) JKFieldAccessExpression(symbol).qualified(qualifier)
else -> throwCanNotConvertError("unexpected symbol ${symbol::class}") else -> throwCanNotConvertError("unexpected symbol ${symbol::class}")
}.also { }.also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
} }
@@ -447,16 +469,16 @@ class JavaToJKTreeBuilder constructor(
is JKPackageSymbol -> JKPackageAccessExpression(symbol) is JKPackageSymbol -> JKPackageAccessExpression(symbol)
else -> throwCanNotConvertError("unexpected symbol ${symbol::class}") else -> throwCanNotConvertError("unexpected symbol ${symbol::class}")
}.qualified(qualifierExpression?.toJK()).also { }.qualified(qualifierExpression?.toJK()).also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
} }
fun PsiArrayInitializerExpression.toJK(): JKExpression { fun PsiArrayInitializerExpression.toJK(): JKExpression {
return JKJavaNewArray( return JKJavaNewArray(
initializers.map { it.toJK() }, initializers.map { it.toJK().withLineBreaksFrom(it) },
JKTypeElement(type?.toJK().safeAs<JKJavaArrayType>()?.type ?: JKContextType) JKTypeElement(type?.toJK().safeAs<JKJavaArrayType>()?.type ?: JKContextType)
).also { ).also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
} }
@@ -479,7 +501,7 @@ class JavaToJKTreeBuilder constructor(
child = child.nextSibling child = child.nextSibling
} }
JKJavaNewEmptyArray( JKJavaNewEmptyArray(
dimensions.map { it?.toJK() ?: JKStubExpression() }, dimensions.map { it?.toJK()?.withLineBreaksFrom(it) ?: JKStubExpression() },
JKTypeElement(generateSequence(type?.toJK()) { it.safeAs<JKJavaArrayType>()?.type }.last()) JKTypeElement(generateSequence(type?.toJK()) { it.safeAs<JKJavaArrayType>()?.type }.last())
).also { ).also {
it.psi = this it.psi = this
@@ -515,7 +537,7 @@ class JavaToJKTreeBuilder constructor(
fun PsiReferenceParameterList.toJK(): JKTypeArgumentList = fun PsiReferenceParameterList.toJK(): JKTypeArgumentList =
JKTypeArgumentList(typeArguments.map { JKTypeElement(it.toJK()) }) JKTypeArgumentList(typeArguments.map { JKTypeElement(it.toJK()) })
.also { .also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
@@ -525,7 +547,7 @@ class JavaToJKTreeBuilder constructor(
symbolProvider.provideMethodSymbol("kotlin.Array.get"), symbolProvider.provideMethodSymbol("kotlin.Array.get"),
arguments = listOf(indexExpression?.toJK() ?: JKStubExpression()) arguments = listOf(indexExpression?.toJK() ?: JKStubExpression())
).also { ).also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
@@ -534,19 +556,19 @@ class JavaToJKTreeBuilder constructor(
operand?.toJK() ?: throwCanNotConvertError(), operand?.toJK() ?: throwCanNotConvertError(),
(castType?.type?.toJK() ?: JKNoType).asTypeElement() (castType?.type?.toJK() ?: JKNoType).asTypeElement()
).also { ).also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
} }
fun PsiParenthesizedExpression.toJK(): JKExpression { fun PsiParenthesizedExpression.toJK(): JKExpression {
return JKParenthesizedExpression(expression.toJK()) return JKParenthesizedExpression(expression.toJK())
.also { .also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
} }
fun PsiExpressionList.toJK(): JKArgumentList { fun PsiExpressionList.toJK(): JKArgumentList {
val jkExpressions = expressions.map { it.toJK() } val jkExpressions = expressions.map { it.toJK().withLineBreaksFrom(it) }
return ((parent as? PsiCall)?.resolveMethod() return ((parent as? PsiCall)?.resolveMethod()
?.let { method -> ?.let { method ->
val lastExpressionType = expressions.lastOrNull()?.type val lastExpressionType = expressions.lastOrNull()?.type
@@ -558,13 +580,17 @@ class JavaToJKTreeBuilder constructor(
JKPrefixExpression( JKPrefixExpression(
jkExpressions.last(), jkExpressions.last(),
JKKtSpreadOperator(lastExpressionType.toJK()) JKKtSpreadOperator(lastExpressionType.toJK())
).withNonCodeElementsFrom(jkExpressions.last()) ).withFormattingFrom(jkExpressions.last())
staredExpression.expression.also {
it.hasLeadingLineBreak = false
it.hasTrailingLineBreak = false
}
jkExpressions.dropLast(1) + staredExpression jkExpressions.dropLast(1) + staredExpression
} else jkExpressions } else jkExpressions
} ?: jkExpressions) } ?: jkExpressions)
.toArgumentList() .toArgumentList()
.also { .also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
} }
@@ -575,7 +601,7 @@ class JavaToJKTreeBuilder constructor(
fun PsiTypeParameterList.toJK(): JKTypeParameterList = fun PsiTypeParameterList.toJK(): JKTypeParameterList =
JKTypeParameterList(typeParameters.map { it.toJK() }) JKTypeParameterList(typeParameters.map { it.toJK() })
.also { .also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
fun PsiTypeParameter.toJK(): JKTypeParameter = fun PsiTypeParameter.toJK(): JKTypeParameter =
@@ -584,7 +610,7 @@ class JavaToJKTreeBuilder constructor(
extendsListTypes.map { JKTypeElement(it.toJK()) } extendsListTypes.map { JKTypeElement(it.toJK()) }
).also { ).also {
symbolProvider.provideUniverseSymbol(this, it) symbolProvider.provideUniverseSymbol(this, it)
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
fun PsiClass.toJK(): JKClass = fun PsiClass.toJK(): JKClass =
@@ -601,7 +627,7 @@ class JavaToJKTreeBuilder constructor(
).also { klass -> ).also { klass ->
klass.psi = this klass.psi = this
symbolProvider.provideUniverseSymbol(this, klass) symbolProvider.provideUniverseSymbol(this, klass)
klass.assignNonCodeElements(this) klass.withFormattingFrom(this)
} }
@@ -611,7 +637,7 @@ class JavaToJKTreeBuilder constructor(
return JKInheritanceInfo(extensionType, implTypes) return JKInheritanceInfo(extensionType, implTypes)
.also { .also {
if (implementsList != null) { if (implementsList != null) {
it.assignNonCodeElements(implementsList!!) it.withFormattingFrom(implementsList!!)
} }
} }
} }
@@ -630,15 +656,21 @@ class JavaToJKTreeBuilder constructor(
} }
} }
).also { ).also {
it.leftBrace.assignNonCodeElements(lBrace) it.leftBrace.withFormattingFrom(
it.rightBrace.assignNonCodeElements(rBrace) lBrace,
takeLeadingComments = false
) // do not capture comments which belongs to following declarations
it.rightBrace.withFormattingFrom(rBrace)
it.declarations.lastOrNull()?.let { lastMember ->
lastMember.withLeadingCommentsWithParent(lastMember.psi)
}
} }
fun PsiClassInitializer.toJK(): JKDeclaration = when { fun PsiClassInitializer.toJK(): JKDeclaration = when {
hasModifier(JvmModifier.STATIC) -> JKJavaStaticInitDeclaration(body.toJK()) hasModifier(JvmModifier.STATIC) -> JKJavaStaticInitDeclaration(body.toJK())
else -> JKKtInitDeclaration(body.toJK()) else -> JKKtInitDeclaration(body.toJK())
}.also { }.also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
@@ -658,12 +690,12 @@ class JavaToJKTreeBuilder constructor(
).also { ).also {
symbolProvider.provideUniverseSymbol(this, it) symbolProvider.provideUniverseSymbol(this, it)
it.psi = this it.psi = this
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
fun PsiMember.modality() = fun PsiMember.modality() =
modality { ast, psi -> ast.assignNonCodeElements(psi) } modality { ast, psi -> ast.withFormattingFrom(psi) }
fun PsiMember.otherModifiers() = fun PsiMember.otherModifiers() =
modifierList?.children?.mapNotNull { child -> modifierList?.children?.mapNotNull { child ->
@@ -678,17 +710,17 @@ class JavaToJKTreeBuilder constructor(
else -> null else -> null
}?.let { }?.let {
JKOtherModifierElement(it).withAssignedNonCodeElements(child) JKOtherModifierElement(it).withFormattingFrom(child)
} }
}.orEmpty() }.orEmpty()
private fun PsiMember.visibility(): JKVisibilityModifierElement = private fun PsiMember.visibility(): JKVisibilityModifierElement =
visibility(referenceSearcher) { ast, psi -> ast.assignNonCodeElements(psi) } visibility(referenceSearcher) { ast, psi -> ast.withFormattingFrom(psi) }
fun PsiField.toJK(): JKField { fun PsiField.toJK(): JKField {
return JKField( return JKField(
JKTypeElement(type.toJK()).withAssignedNonCodeElements(typeElement), JKTypeElement(type.toJK()).withFormattingFrom(typeElement),
nameIdentifier.toJK(), nameIdentifier.toJK(),
with(expressionTreeMapper) { initializer.toJK() }, with(expressionTreeMapper) { initializer.toJK() },
annotationList(this), annotationList(this),
@@ -699,7 +731,7 @@ class JavaToJKTreeBuilder constructor(
).also { ).also {
symbolProvider.provideUniverseSymbol(this, it) symbolProvider.provideUniverseSymbol(this, it)
it.psi = this it.psi = this
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
} }
@@ -735,7 +767,7 @@ class JavaToJKTreeBuilder constructor(
} }
} }
).also { ).also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
fun PsiDocComment.deprecatedAnnotation(): JKAnnotation? = fun PsiDocComment.deprecatedAnnotation(): JKAnnotation? =
@@ -756,7 +788,7 @@ class JavaToJKTreeBuilder constructor(
JKKtAnnotationArrayInitializerExpression(initializers.map { it.toJK() }) JKKtAnnotationArrayInitializerExpression(initializers.map { it.toJK() })
else -> throwCanNotConvertError() else -> throwCanNotConvertError()
}.also { }.also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
fun PsiAnnotationMethod.toJK(): JKJavaAnnotationMethod = fun PsiAnnotationMethod.toJK(): JKJavaAnnotationMethod =
@@ -773,7 +805,7 @@ class JavaToJKTreeBuilder constructor(
).also { ).also {
it.psi = this it.psi = this
symbolProvider.provideUniverseSymbol(this, it) symbolProvider.provideUniverseSymbol(this, it)
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
@@ -784,7 +816,7 @@ class JavaToJKTreeBuilder constructor(
?: JKJavaVoidType.takeIf { isConstructor } ?: JKJavaVoidType.takeIf { isConstructor }
?: JKNoType), ?: JKNoType),
nameIdentifier.toJK(), nameIdentifier.toJK(),
parameterList.parameters.map { it.toJK() }, parameterList.parameters.map { it.toJK().withLineBreaksFrom(it) },
body?.toJK() ?: JKBodyStub, body?.toJK() ?: JKBodyStub,
typeParameterList?.toJK() ?: JKTypeParameterList(), typeParameterList?.toJK() ?: JKTypeParameterList(),
annotationList(this), annotationList(this),
@@ -798,10 +830,10 @@ class JavaToJKTreeBuilder constructor(
parameterList.node parameterList.node
?.safeAs<CompositeElement>() ?.safeAs<CompositeElement>()
?.also { ?.also {
jkMethod.leftParen.assignNonCodeElements(it.findChildByRoleAsPsiElement(ChildRole.LPARENTH)) jkMethod.leftParen.withFormattingFrom(it.findChildByRoleAsPsiElement(ChildRole.LPARENTH))
jkMethod.rightParen.assignNonCodeElements(it.findChildByRoleAsPsiElement(ChildRole.RPARENTH)) jkMethod.rightParen.withFormattingFrom(it.findChildByRoleAsPsiElement(ChildRole.RPARENTH))
} }
}.withAssignedNonCodeElements(this) }.withFormattingFrom(this)
} }
fun PsiParameter.toJK(): JKParameter { fun PsiParameter.toJK(): JKParameter {
@@ -817,22 +849,22 @@ class JavaToJKTreeBuilder constructor(
).also { ).also {
symbolProvider.provideUniverseSymbol(this, it) symbolProvider.provideUniverseSymbol(this, it)
it.psi = this it.psi = this
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
} }
fun PsiCodeBlock.toJK(): JKBlock = fun PsiCodeBlock.toJK(): JKBlock =
JKBlockImpl(statements.map { it.toJK() }) JKBlockImpl(statements.map { it.toJK() })
.withAssignedNonCodeElements(this) .withFormattingFrom(this)
.also { .also {
it.leftBrace.assignNonCodeElements(lBrace) it.leftBrace.withFormattingFrom(lBrace)
it.rightBrace.assignNonCodeElements(rBrace) it.rightBrace.withFormattingFrom(rBrace)
} }
fun PsiLocalVariable.toJK(): JKLocalVariable = fun PsiLocalVariable.toJK(): JKLocalVariable =
JKLocalVariable( JKLocalVariable(
JKTypeElement(type.toJK()).withAssignedNonCodeElements(typeElement), JKTypeElement(type.toJK()).withFormattingFrom(typeElement),
nameIdentifier.toJK(), nameIdentifier.toJK(),
with(expressionTreeMapper) { initializer.toJK() }, with(expressionTreeMapper) { initializer.toJK() },
JKMutabilityModifierElement( JKMutabilityModifierElement(
@@ -844,7 +876,7 @@ class JavaToJKTreeBuilder constructor(
symbolProvider.provideUniverseSymbol(this, i) symbolProvider.provideUniverseSymbol(this, i)
i.psi = this i.psi = this
}.also { }.also {
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
fun PsiStatement?.toJK(): JKStatement { fun PsiStatement?.toJK(): JKStatement {
@@ -903,7 +935,7 @@ class JavaToJKTreeBuilder constructor(
with(expressionTreeMapper) { statement.caseValue.toJK() }, with(expressionTreeMapper) { statement.caseValue.toJK() },
emptyList() emptyList()
) )
}.withAssignedNonCodeElements(statement) }.withFormattingFrom(statement)
else -> else ->
cases.lastOrNull()?.also { it.statements = it.statements + statement.toJK() } cases.lastOrNull()?.also { it.statements = it.statements + statement.toJK() }
?: run { ?: run {
@@ -947,7 +979,7 @@ class JavaToJKTreeBuilder constructor(
}.also { }.also {
if (this != null) { if (this != null) {
(it as PsiOwner).psi = this (it as PsiOwner).psi = this
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
} }
} }
@@ -958,7 +990,7 @@ class JavaToJKTreeBuilder constructor(
catchBlock?.toJK() ?: JKBodyStub catchBlock?.toJK() ?: JKBodyStub
).also { ).also {
it.psi = this it.psi = this
it.assignNonCodeElements(this) it.withFormattingFrom(this)
} }
} }
@@ -989,77 +1021,6 @@ class JavaToJKTreeBuilder constructor(
else -> null else -> null
}?.let { JKTreeRoot(it) } }?.let { JKTreeRoot(it) }
private val tokenCache = mutableMapOf<PsiElement, JKNonCodeElement>()
private fun PsiElement.collectNonCodeElements(): Pair<List<JKNonCodeElement>, List<JKNonCodeElement>> {
fun PsiElement.toToken(): JKNonCodeElement? {
if (this in tokenCache) return tokenCache.getValue(this)
val token = when {
this is PsiDocComment ->
JKCommentElement(IdeaDocCommentConverter.convertDocComment(this))
this is PsiComment -> JKCommentElement(text)
this is PsiWhiteSpace -> JKSpaceElement(text)
text == ";" -> null
text == "" -> null
else -> null
} ?: return null
tokenCache[this] = token
return token
}
fun Sequence<PsiElement>.toNonCodeElements(): List<JKNonCodeElement> =
takeWhile { it is PsiComment || it is PsiWhiteSpace || it.text == ";" }
.mapNotNull { it.toToken() }
.toList()
fun PsiElement.isNonCodeElement() =
this is PsiComment || this is PsiWhiteSpace || text == ";" || text == ""
fun PsiElement.nextNonCodeElements() =
generateSequence(nextSibling) { it.nextSibling }
.takeWhile { it.isNonCodeElement() }
fun PsiElement.prevNonCodeElements() =
generateSequence(prevSibling) { it.prevSibling }
.takeWhile { it.isNonCodeElement() }
fun PsiElement.nextNonCodeElementsWithParent(): Sequence<JKNonCodeElement> {
val innerElements = nextNonCodeElements()
return (if (innerElements.lastOrNull()?.nextSibling == null && this is PsiKeyword)
innerElements + parent?.nextNonCodeElements().orEmpty()
else innerElements).mapNotNull { it.toToken() }
}
fun PsiElement.prevNonCodeElementsWithParent(): Sequence<JKNonCodeElement> {
val innerElements = prevNonCodeElements()
return (if (innerElements.firstOrNull()?.prevSibling == null && this is PsiKeyword)
innerElements + parent?.prevNonCodeElements().orEmpty()
else innerElements).mapNotNull { it.toToken() }
}
val leftInnerTokens = children.asSequence().toNonCodeElements().reversed()
val rightInnerTokens =
if (children.isEmpty()) emptyList()
else generateSequence(children.last()) { it.prevSibling }
.toNonCodeElements()
.reversed()
return (leftInnerTokens + prevNonCodeElementsWithParent()).reversed() to
(rightInnerTokens + nextNonCodeElementsWithParent())
}
private fun JKNonCodeElementsListOwner.assignNonCodeElements(psi: PsiElement?) {
if (psi == null) return
val (leftTokens, rightTokens) = psi.collectNonCodeElements()
this.leftNonCodeElements += leftTokens
this.rightNonCodeElements += rightTokens
}
private inline fun <reified T : JKNonCodeElementsListOwner> T.withAssignedNonCodeElements(psi: PsiElement?): T =
also { it.assignNonCodeElements(psi) }
private fun PsiElement.throwCanNotConvertError(message: String? = null): Nothing { private fun PsiElement.throwCanNotConvertError(message: String? = null): Nothing {
throw KotlinExceptionWithAttachments("Cannot convert the following Java element ${this::class}" + message?.let { " due to `$it`" }) throw KotlinExceptionWithAttachments("Cannot convert the following Java element ${this::class}" + message?.let { " due to `$it`" })
@@ -29,49 +29,50 @@ class NewCodeBuilder(context: NewJ2kConverterContext) {
} }
inner class Visitor : JKVisitorWithCommentsPrinting() { inner class Visitor : JKVisitorWithCommentsPrinting() {
private val printedTokens = mutableSetOf<JKNonCodeElement>() private val printedTokens = mutableSetOf<JKComment>()
//TODO move to ast transformation phase //TODO move to ast transformation phase
private fun JKNonCodeElement.shouldBeDropped(): Boolean = private fun JKComment.shouldBeDropped(): Boolean =
this is JKCommentElement && text.startsWith("//noinspection") text.startsWith("//noinspection")
private fun JKNonCodeElement.createText() = private fun JKComment.createText() =
if (this !in printedTokens) { if (this !in printedTokens) {
printedTokens += this printedTokens += this
text text
} else "" } else null
private fun List<JKNonCodeElement>.createText(): String { private fun List<JKComment>.createText(): String = buildString {
val text = filterNot { it.shouldBeDropped() }.joinToString("") { token -> token.createText() } var needNewLine = false
val needNewLine = text.lastIndexOf('\n') < text.lastIndexOf("//") for (comment in this@createText) {
return text + "\n".takeIf { needNewLine }.orEmpty() if (comment.shouldBeDropped()) continue
val text = comment.createText() ?: continue
if (needNewLine) appendln() else append(' ')
append(text)
needNewLine = text.startsWith("//") || '\n' in text
}
} }
private fun JKNonCodeElementsListOwner.needPreserveSpacesAfterLastComment() = private fun String.hasNoLineBreakAfterSingleLineComment() = lastIndexOf('\n') < lastIndexOf("//")
this is JKArgument
|| this is JKParameter
|| safeAs<JKTreeElement>()?.parent is JKArgument
|| safeAs<JKTreeElement>()?.parent is JKBinaryExpression
|| safeAs<JKTreeElement>()?.parent is JKQualifiedExpression
override fun printLeftNonCodeElements(element: JKNonCodeElementsListOwner) { override fun printLeftNonCodeElements(element: JKFormattingOwner) {
val text = element.leftNonCodeElements val text = element.trailingComments.createText()
.let {
if (element.needPreserveSpacesAfterLastComment()) it
else it.dropWhile { it is JKSpaceElement }
}.createText()
printer.printWithNoIndent(text) printer.printWithNoIndent(text)
val addNewLine = element.hasTrailingLineBreak
|| element is JKDeclaration && element.trailingComments.isNotEmpty() // add new line between comment & declaration
|| text.hasNoLineBreakAfterSingleLineComment()
if (addNewLine) printer.println()
} }
override fun printRightNonCodeElements(element: JKNonCodeElementsListOwner) { override fun printRightNonCodeElements(element: JKFormattingOwner) {
val text = element.rightNonCodeElements val text = element.leadingComments.createText()
.let {
if (element.needPreserveSpacesAfterLastComment()) it
else it.dropLastWhile { it is JKSpaceElement }
}.createText()
printer.printWithNoIndent(text) printer.printWithNoIndent(text)
val addNewLine = element.hasLeadingLineBreak || text.hasNoLineBreakAfterSingleLineComment()
if (addNewLine) printer.println()
} }
private fun renderTokenElement(tokenElement: JKTokenElement) { private fun renderTokenElement(tokenElement: JKTokenElement) {
@@ -13,15 +13,13 @@ class AddParenthesisForLineBreaksInBinaryExpression(override val context: NewJ2k
override fun applyToElement(element: JKTreeElement): JKTreeElement { override fun applyToElement(element: JKTreeElement): JKTreeElement {
if (element !is JKBinaryExpression) return recurse(element) if (element !is JKBinaryExpression) return recurse(element)
if (element.parent is JKBinaryExpression) return recurse(element) if (element.parent is JKBinaryExpression) return recurse(element)
if (element.left.rightNonCodeElements.any { if (element.left.hasLeadingLineBreak) {
it is JKSpaceElement && '\n' in it.text
}) {
return JKParenthesizedExpression( return JKParenthesizedExpression(
JKBinaryExpression( JKBinaryExpression(
element::left.detached(), element::left.detached(),
element::right.detached(), element::right.detached(),
element.operator element.operator
).withNonCodeElementsFrom(element) ).withFormattingFrom(element)
) )
} }
return recurse(element) return recurse(element)
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.nj2k.conversions
import org.jetbrains.kotlin.j2k.ast.Nullability import org.jetbrains.kotlin.j2k.ast.Nullability
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
import org.jetbrains.kotlin.nj2k.modality
import org.jetbrains.kotlin.nj2k.toExpression import org.jetbrains.kotlin.nj2k.toExpression
import org.jetbrains.kotlin.nj2k.tree.* import org.jetbrains.kotlin.nj2k.tree.*
@@ -58,11 +57,11 @@ class AnnotationClassConversion(context: NewJ2kConverterContext) : RecursiveAppl
JKKtAnnotationArrayInitializerExpression(initializer) JKKtAnnotationArrayInitializerExpression(initializer)
} else initializer } else initializer
).also { parameter -> ).also { parameter ->
if (leftNonCodeElements.any { it is JKCommentElement }) { if (trailingComments.any { it is JKComment }) {
parameter.leftNonCodeElements += leftNonCodeElements parameter.trailingComments += trailingComments
} }
if (rightNonCodeElements.any { it is JKCommentElement }) { if (leadingComments.any { it is JKComment }) {
parameter.rightNonCodeElements += rightNonCodeElements parameter.leadingComments += leadingComments
} }
} }
@@ -34,14 +34,14 @@ class AssignmentExpressionUnfoldingConversion(context: NewJ2kConverterContext) :
val assignment = statement.expression as JKJavaAssignmentExpression val assignment = statement.expression as JKJavaAssignmentExpression
newStatements += assignment newStatements += assignment
.unfoldToStatementsList(assignmentTarget = null) .unfoldToStatementsList(assignmentTarget = null)
.withNonCodeElementsFrom(statement) .withFormattingFrom(statement)
} }
statement is JKDeclarationStatement && statement.containsAssignment() -> { statement is JKDeclarationStatement && statement.containsAssignment() -> {
val variable = statement.declaredStatements.single() as JKVariable val variable = statement.declaredStatements.single() as JKVariable
val assignment = variable.initializer as JKJavaAssignmentExpression val assignment = variable.initializer as JKJavaAssignmentExpression
newStatements += assignment newStatements += assignment
.unfoldToStatementsList(variable.detached(statement)) .unfoldToStatementsList(variable.detached(statement))
.withNonCodeElementsFrom(statement) .withFormattingFrom(statement)
} }
else -> { else -> {
newStatements += statement newStatements += statement
@@ -62,7 +62,7 @@ class AssignmentExpressionUnfoldingConversion(context: NewJ2kConverterContext) :
assignment::expression.detached(), assignment::expression.detached(),
assignment.operator assignment.operator
) )
}.withNonCodeElementsFrom(this) }.withFormattingFrom(this)
} }
private fun JKExpressionStatement.canBeConvertedToBlock() = when (val parent = parent) { private fun JKExpressionStatement.canBeConvertedToBlock() = when (val parent = parent) {
@@ -73,7 +73,7 @@ class AssignmentExpressionUnfoldingConversion(context: NewJ2kConverterContext) :
} }
private fun JKJavaAssignmentExpression.convertAssignments() = private fun JKJavaAssignmentExpression.convertAssignments() =
unfoldToExpressionsChain().withNonCodeElementsFrom(this) unfoldToExpressionsChain().withFormattingFrom(this)
private fun JKDeclarationStatement.containsAssignment() = private fun JKDeclarationStatement.containsAssignment() =
declaredStatements.singleOrNull()?.safeAs<JKVariable>()?.initializer is JKJavaAssignmentExpression declaredStatements.singleOrNull()?.safeAs<JKVariable>()?.initializer is JKJavaAssignmentExpression
@@ -118,7 +118,7 @@ class AssignmentExpressionUnfoldingConversion(context: NewJ2kConverterContext) :
this::field.detached(), this::field.detached(),
JKKtItExpression(operator.returnType), JKKtItExpression(operator.returnType),
operator operator
).withNonCodeElementsFrom(this) ).withFormattingFrom(this)
return when { return when {
operator.isSimpleToken() -> operator.isSimpleToken() ->
JKAssignmentChainAlsoLink(receiver, assignment, field.copyTreeAndDetach()) JKAssignmentChainAlsoLink(receiver, assignment, field.copyTreeAndDetach())
@@ -129,7 +129,7 @@ class AssignmentExpressionUnfoldingConversion(context: NewJ2kConverterContext) :
private fun JKJavaAssignmentExpression.toDeclarationChainLink(expression: JKExpression) = private fun JKJavaAssignmentExpression.toDeclarationChainLink(expression: JKExpression) =
createKtAssignmentStatement(this::field.detached(), expression, this.operator) createKtAssignmentStatement(this::field.detached(), expression, this.operator)
.withNonCodeElementsFrom(this) .withFormattingFrom(this)
private fun createKtAssignmentStatement( private fun createKtAssignmentStatement(
field: JKExpression, field: JKExpression,
@@ -27,7 +27,7 @@ class BlockToRunConversion(context: NewJ2kConverterContext) : RecursiveApplicabl
symbolProvider.provideMethodSymbol("kotlin.run"), symbolProvider.provideMethodSymbol("kotlin.run"),
JKArgumentList(lambda) JKArgumentList(lambda)
) )
return recurse(JKExpressionStatement(call).withNonCodeElementsFrom(element)) return recurse(JKExpressionStatement(call).withFormattingFrom(element))
} }
} }
@@ -43,7 +43,7 @@ class BoxedTypeOperationsConversion(context: NewJ2kConverterContext) : Recursive
"kotlin.${primitiveTypeName.capitalize()}.to${operationType.capitalize()}" "kotlin.${primitiveTypeName.capitalize()}.to${operationType.capitalize()}"
), ),
JKArgumentList() JKArgumentList()
).withNonCodeElementsFrom(methodCallExpression) ).withFormattingFrom(methodCallExpression)
} }
companion object { companion object {
@@ -33,11 +33,11 @@ class BuiltinMembersConversion(context: NewJ2kConverterContext) : RecursiveAppli
val newSelector = conversion.createBuilder().build(selector) val newSelector = conversion.createBuilder().build(selector)
if (this is JKQualifiedExpression && conversion.replaceType == ReplaceType.REPLACE_WITH_QUALIFIER) { if (this is JKQualifiedExpression && conversion.replaceType == ReplaceType.REPLACE_WITH_QUALIFIER) {
newSelector.rightNonCodeElements += receiver.leftNonCodeElements newSelector.leadingComments += receiver.trailingComments
newSelector.rightNonCodeElements += receiver.leftNonCodeElements newSelector.leadingComments += receiver.trailingComments
newSelector.rightNonCodeElements += receiver.rightNonCodeElements newSelector.leadingComments += receiver.leadingComments
newSelector.rightNonCodeElements += selector.leftNonCodeElements newSelector.leadingComments += selector.trailingComments
newSelector.rightNonCodeElements += selector.rightNonCodeElements newSelector.leadingComments += selector.leadingComments
} }
return when (conversion.replaceType) { return when (conversion.replaceType) {
@@ -93,19 +93,19 @@ class BuiltinMembersConversion(context: NewJ2kConverterContext) : RecursiveAppli
symbolProvider.provideMethodSymbol(fqName), symbolProvider.provideMethodSymbol(fqName),
argumentsProvider(from::arguments.detached()), argumentsProvider(from::arguments.detached()),
from::typeArgumentList.detached() from::typeArgumentList.detached()
).withNonCodeElementsFrom(from) ).withFormattingFrom(from)
is JKFieldAccessExpression -> is JKFieldAccessExpression ->
JKCallExpressionImpl( JKCallExpressionImpl(
symbolProvider.provideMethodSymbol(fqName), symbolProvider.provideMethodSymbol(fqName),
JKArgumentList(), JKArgumentList(),
JKTypeArgumentList() JKTypeArgumentList()
).withNonCodeElementsFrom(from) ).withFormattingFrom(from)
is JKNewExpression -> is JKNewExpression ->
JKCallExpressionImpl( JKCallExpressionImpl(
symbolProvider.provideMethodSymbol(fqName), symbolProvider.provideMethodSymbol(fqName),
argumentsProvider(from::arguments.detached()), argumentsProvider(from::arguments.detached()),
JKTypeArgumentList() JKTypeArgumentList()
).withNonCodeElementsFrom(from) ).withFormattingFrom(from)
else -> error("Bad conversion") else -> error("Bad conversion")
} }
} }
@@ -118,11 +118,11 @@ class BuiltinMembersConversion(context: NewJ2kConverterContext) : RecursiveAppli
is JKCallExpression -> is JKCallExpression ->
JKFieldAccessExpression( JKFieldAccessExpression(
symbolProvider.provideFieldSymbol(fqName) symbolProvider.provideFieldSymbol(fqName)
).withNonCodeElementsFrom(from) ).withFormattingFrom(from)
is JKFieldAccessExpression -> is JKFieldAccessExpression ->
JKFieldAccessExpression( JKFieldAccessExpression(
symbolProvider.provideFieldSymbol(fqName) symbolProvider.provideFieldSymbol(fqName)
).withNonCodeElementsFrom(from) ).withFormattingFrom(from)
else -> error("Bad conversion") else -> error("Bad conversion")
} }
} }
@@ -141,7 +141,7 @@ class BuiltinMembersConversion(context: NewJ2kConverterContext) : RecursiveAppli
JKArgumentList(arguments.drop(1)), JKArgumentList(arguments.drop(1)),
from::typeArgumentList.detached() from::typeArgumentList.detached()
) )
).withNonCodeElementsFrom(from) ).withFormattingFrom(from)
} }
else -> error("Bad conversion") else -> error("Bad conversion")
} }
@@ -354,7 +354,7 @@ class BuiltinMembersConversion(context: NewJ2kConverterContext) : RecursiveAppli
JKArgumentList( JKArgumentList(
detachedArguments.drop(1) + JKNamedArgument( detachedArguments.drop(1) + JKNamedArgument(
detachedArguments.first()::value.detached().also { detachedArguments.first()::value.detached().also {
it.clearNonCodeElements() it.clearFormatting()
}, },
JKNameIdentifier("ignoreCase") JKNameIdentifier("ignoreCase")
) )
@@ -53,7 +53,7 @@ class ClassToObjectPromotionConversion(context: NewJ2kConverterContext) : Recurs
element.otherModifierElements, element.otherModifierElements,
element.visibilityElement, element.visibilityElement,
JKModalityModifierElement(Modality.FINAL) JKModalityModifierElement(Modality.FINAL)
).withNonCodeElementsFrom(element) ).withFormattingFrom(element)
) )
} }
} }
@@ -29,7 +29,7 @@ class ConstructorConversion(context: NewJ2kConverterContext) : RecursiveApplicab
element.modalityElement element.modalityElement
).also { ).also {
symbolProvider.transferSymbol(it, element) symbolProvider.transferSymbol(it, element)
}.withNonCodeElementsFrom(element) }.withFormattingFrom(element)
} }
private fun lookupDelegationCall(block: JKBlock): JKDelegationConstructorCall? { private fun lookupDelegationCall(block: JKBlock): JKDelegationConstructorCall? {
@@ -108,7 +108,7 @@ class DefaultArgumentsConversion(context: NewJ2kConverterContext) : RecursiveApp
parameter.initializer = remapParameterSymbol(defaultValue) as JKExpression parameter.initializer = remapParameterSymbol(defaultValue) as JKExpression
} }
element.declarations -= method element.declarations -= method
calledMethod.withNonCodeElementsFrom(method) calledMethod.withFormattingFrom(method)
} }
if (element.parentOfType<JKClass>()?.classKind != JKClass.ClassKind.ANNOTATION) { if (element.parentOfType<JKClass>()?.classKind != JKClass.ClassKind.ANNOTATION) {
for (method in element.declarations) { for (method in element.declarations) {
@@ -27,8 +27,8 @@ class ForConversion(context: NewJ2kConverterContext) : RecursiveApplicableConver
override fun applyToElement(element: JKTreeElement): JKTreeElement { override fun applyToElement(element: JKTreeElement): JKTreeElement {
if (element !is JKJavaForLoopStatement) return recurse(element) if (element !is JKJavaForLoopStatement) return recurse(element)
convertToForeach(element)?.also { return recurse(it.withNonCodeElementsFrom(element)) } convertToForeach(element)?.also { return recurse(it.withFormattingFrom(element)) }
convertToWhile(element)?.also { return recurse(it.withNonCodeElementsFrom(element)) } convertToWhile(element)?.also { return recurse(it.withFormattingFrom(element)) }
return recurse(element) return recurse(element)
} }
@@ -23,25 +23,25 @@ class JavaModifiersConversion(context: NewJ2kConverterContext) : RecursiveApplic
element.elementByModifier(OtherModifier.VOLATILE)?.also { modifierElement -> element.elementByModifier(OtherModifier.VOLATILE)?.also { modifierElement ->
element.otherModifierElements -= modifierElement element.otherModifierElements -= modifierElement
element.annotationList.annotations += element.annotationList.annotations +=
jvmAnnotation("Volatile", symbolProvider).withNonCodeElementsFrom(modifierElement) jvmAnnotation("Volatile", symbolProvider).withFormattingFrom(modifierElement)
} }
element.elementByModifier(OtherModifier.TRANSIENT)?.also { modifierElement -> element.elementByModifier(OtherModifier.TRANSIENT)?.also { modifierElement ->
element.otherModifierElements -= modifierElement element.otherModifierElements -= modifierElement
element.annotationList.annotations += element.annotationList.annotations +=
jvmAnnotation("Transient", symbolProvider).withNonCodeElementsFrom(modifierElement) jvmAnnotation("Transient", symbolProvider).withFormattingFrom(modifierElement)
} }
element.elementByModifier(OtherModifier.STRICTFP)?.also { modifierElement -> element.elementByModifier(OtherModifier.STRICTFP)?.also { modifierElement ->
element.otherModifierElements -= modifierElement element.otherModifierElements -= modifierElement
element.annotationList.annotations += element.annotationList.annotations +=
jvmAnnotation("Strictfp", symbolProvider).withNonCodeElementsFrom(modifierElement) jvmAnnotation("Strictfp", symbolProvider).withFormattingFrom(modifierElement)
} }
element.elementByModifier(OtherModifier.SYNCHRONIZED)?.also { modifierElement -> element.elementByModifier(OtherModifier.SYNCHRONIZED)?.also { modifierElement ->
element.otherModifierElements -= modifierElement element.otherModifierElements -= modifierElement
element.annotationList.annotations += element.annotationList.annotations +=
jvmAnnotation("Synchronized", symbolProvider).withNonCodeElementsFrom(modifierElement) jvmAnnotation("Synchronized", symbolProvider).withFormattingFrom(modifierElement)
} }
element.elementByModifier(OtherModifier.NATIVE)?.also { modifierElement -> element.elementByModifier(OtherModifier.NATIVE)?.also { modifierElement ->
@@ -14,8 +14,8 @@ class NonCodeElementsConversion(context: NewJ2kConverterContext) : RecursiveAppl
override fun applyToElement(element: JKTreeElement): JKTreeElement { override fun applyToElement(element: JKTreeElement): JKTreeElement {
when (element) { when (element) {
is JKClass -> { is JKClass -> {
element.name.rightNonCodeElements += element.inheritance.leftNonCodeElements element.name.leadingComments += element.inheritance.trailingComments
element.inheritance.leftNonCodeElements.clear() element.inheritance.trailingComments.clear()
} }
} }
return recurse(element) return recurse(element)
@@ -32,10 +32,10 @@ class PrimaryConstructorDetectConversion(context: NewJ2kConverterContext) : Recu
primaryConstructorCandidate.invalidate() primaryConstructorCandidate.invalidate()
if (primaryConstructorCandidate.block.statements.isNotEmpty()) { if (primaryConstructorCandidate.block.statements.isNotEmpty()) {
val initDeclaration = JKKtInitDeclaration(primaryConstructorCandidate.block) val initDeclaration = JKKtInitDeclaration(primaryConstructorCandidate.block)
.withNonCodeElementsFrom(primaryConstructorCandidate) .withFormattingFrom(primaryConstructorCandidate)
primaryConstructorCandidate.clearNonCodeElements() primaryConstructorCandidate.clearFormatting()
primaryConstructorCandidate.forEachModifier { modifierElement -> primaryConstructorCandidate.forEachModifier { modifierElement ->
modifierElement.clearNonCodeElements() modifierElement.clearFormatting()
} }
element.classBody.declarations = element.classBody.declarations =
element.classBody.declarations.replace(primaryConstructorCandidate, initDeclaration) element.classBody.declarations.replace(primaryConstructorCandidate, initDeclaration)
@@ -52,7 +52,7 @@ class PrimaryConstructorDetectConversion(context: NewJ2kConverterContext) : Recu
primaryConstructorCandidate.otherModifierElements, primaryConstructorCandidate.otherModifierElements,
primaryConstructorCandidate.visibilityElement, primaryConstructorCandidate.visibilityElement,
primaryConstructorCandidate.modalityElement primaryConstructorCandidate.modalityElement
).withNonCodeElementsFrom(primaryConstructorCandidate) ).withFormattingFrom(primaryConstructorCandidate)
symbolProvider.transferSymbol(primaryConstructor, primaryConstructorCandidate) symbolProvider.transferSymbol(primaryConstructor, primaryConstructorCandidate)
@@ -24,7 +24,7 @@ class RemoveRedundantQualifiersForCallsConversion(context: NewJ2kConverterContex
} }
if (needRemoveQualifier) { if (needRemoveQualifier) {
element.invalidate() element.invalidate()
return recurse(element.selector.withNonCodeElementsFrom(element.receiver).withNonCodeElementsFrom(element)) return recurse(element.selector.withFormattingFrom(element.receiver).withFormattingFrom(element))
} }
return recurse(element) return recurse(element)
} }
@@ -34,5 +34,5 @@ class StaticInitDeclarationConversion(context : NewJ2kConverterContext) : Recurs
} }
private fun JKJavaStaticInitDeclaration.toKtInitDeclaration() = private fun JKJavaStaticInitDeclaration.toKtInitDeclaration() =
JKKtInitDeclaration(::block.detached()).withNonCodeElementsFrom(this) JKKtInitDeclaration(::block.detached()).withFormattingFrom(this)
} }
@@ -48,7 +48,7 @@ class SwitchStatementConversion(context: NewJ2kConverterContext) : RecursiveAppl
statement.block.statements statement.block.statements
.takeWhile { !isSwitchBreak(it) } .takeWhile { !isSwitchBreak(it) }
.map { it.copyTreeAndDetach() } .map { it.copyTreeAndDetach() }
).withNonCodeElementsFrom(statement) ).withFormattingFrom(statement)
isSwitchBreak(statement) -> null isSwitchBreak(statement) -> null
else -> statement.copyTreeAndDetach() else -> statement.copyTreeAndDetach()
} }
@@ -24,7 +24,7 @@ class SynchronizedStatementConversion(context: NewJ2kConverterContext) : Recursi
element.lockExpression, element.lockExpression,
lambdaBody lambdaBody
) )
).withNonCodeElementsFrom(element) ).withFormattingFrom(element)
return recurse(JKExpressionStatement(synchronizedCall)) return recurse(JKExpressionStatement(synchronizedCall))
} }
@@ -29,7 +29,7 @@ class TryStatementConversion(context: NewJ2kConverterContext) : RecursiveApplica
tryStatement::finallyBlock.detached(), tryStatement::finallyBlock.detached(),
tryStatement.catchSections.flatMap(::convertCatchSection) tryStatement.catchSections.flatMap(::convertCatchSection)
) )
).withNonCodeElementsFrom(tryStatement) ).withFormattingFrom(tryStatement)
private fun convertTryStatementWithResources(tryStatement: JKJavaTryStatement): JKStatement { private fun convertTryStatementWithResources(tryStatement: JKJavaTryStatement): JKStatement {
val body = val body =
@@ -44,7 +44,7 @@ class TryStatementConversion(context: NewJ2kConverterContext) : RecursiveApplica
tryStatement::finallyBlock.detached(), tryStatement::finallyBlock.detached(),
tryStatement.catchSections.flatMap(::convertCatchSection) tryStatement.catchSections.flatMap(::convertCatchSection)
) )
).withNonCodeElementsFrom(tryStatement) ).withFormattingFrom(tryStatement)
} else body } else body
} }
@@ -77,7 +77,7 @@ class TryStatementConversion(context: NewJ2kConverterContext) : RecursiveApplica
JKKtTryCatchSection( JKKtTryCatchSection(
parameter, parameter,
javaCatchSection.block.copyTreeAndDetach() javaCatchSection.block.copyTreeAndDetach()
).withNonCodeElementsFrom(javaCatchSection) ).withFormattingFrom(javaCatchSection)
} }
} }
} }
@@ -37,7 +37,7 @@ class TypeMappingConversion(
element::typeArgumentList.detached().fixTypeArguments(newClassSymbol), element::typeArgumentList.detached().fixTypeArguments(newClassSymbol),
element::classBody.detached(), element::classBody.detached(),
element.isAnonymousClass element.isAnonymousClass
).withNonCodeElementsFrom(element) ).withFormattingFrom(element)
) )
} }
} }
@@ -45,7 +45,7 @@ fun canKeepEqEq(left: PsiExpression, right: PsiExpression?): Boolean {
internal fun PsiMember.visibility( internal fun PsiMember.visibility(
referenceSearcher: ReferenceSearcher, referenceSearcher: ReferenceSearcher,
assignNonCodeElements: ((JKNonCodeElementsListOwner, PsiElement) -> Unit)? assignNonCodeElements: ((JKFormattingOwner, PsiElement) -> Unit)?
): JKVisibilityModifierElement = ): JKVisibilityModifierElement =
modifierList?.children?.mapNotNull { child -> modifierList?.children?.mapNotNull { child ->
if (child !is PsiKeyword) return@mapNotNull null if (child !is PsiKeyword) return@mapNotNull null
@@ -64,7 +64,7 @@ internal fun PsiMember.visibility(
}?.firstOrNull() ?: JKVisibilityModifierElement(Visibility.INTERNAL) }?.firstOrNull() ?: JKVisibilityModifierElement(Visibility.INTERNAL)
fun PsiMember.modality(assignNonCodeElements: ((JKNonCodeElementsListOwner, PsiElement) -> Unit)?) = fun PsiMember.modality(assignNonCodeElements: ((JKFormattingOwner, PsiElement) -> Unit)?) =
modifierList?.children?.mapNotNull { child -> modifierList?.children?.mapNotNull { child ->
if (child !is PsiKeyword) return@mapNotNull null if (child !is PsiKeyword) return@mapNotNull null
when (child.text) { when (child.text) {
@@ -46,9 +46,11 @@ private class JKListChild<T : JKElement>(val value: Int) : ReadWriteProperty<JKT
} }
abstract class JKTreeElement : JKElement, JKNonCodeElementsListOwner, Cloneable { abstract class JKTreeElement : JKElement, JKFormattingOwner, Cloneable {
override val leftNonCodeElements: MutableList<JKNonCodeElement> = mutableListOf() override val trailingComments: MutableList<JKComment> = mutableListOf()
override val rightNonCodeElements: MutableList<JKNonCodeElement> = mutableListOf() override val leadingComments: MutableList<JKComment> = mutableListOf()
override var hasTrailingLineBreak = false
override var hasLeadingLineBreak = false
override var parent: JKElement? = null override var parent: JKElement? = null
@@ -149,11 +151,11 @@ interface PsiOwner {
class PsiOwnerImpl(override var psi: PsiElement? = null) : PsiOwner class PsiOwnerImpl(override var psi: PsiElement? = null) : PsiOwner
interface JKTypeArgumentListOwner : JKNonCodeElementsListOwner { interface JKTypeArgumentListOwner : JKFormattingOwner {
var typeArgumentList: JKTypeArgumentList var typeArgumentList: JKTypeArgumentList
} }
interface JKTypeParameterListOwner : JKNonCodeElementsListOwner { interface JKTypeParameterListOwner : JKFormattingOwner {
var typeParameterList: JKTypeParameterList var typeParameterList: JKTypeParameterList
} }
@@ -40,8 +40,10 @@ abstract class JKBlock : JKTreeElement() {
object JKBodyStub : JKBlock() { object JKBodyStub : JKBlock() {
override val leftNonCodeElements: MutableList<JKNonCodeElement> = mutableListOf() override val trailingComments: MutableList<JKComment> = mutableListOf()
override val rightNonCodeElements: MutableList<JKNonCodeElement> = mutableListOf() override val leadingComments: MutableList<JKComment> = mutableListOf()
override var hasTrailingLineBreak = false
override var hasLeadingLineBreak = false
override fun copy(): JKTreeElement = this override fun copy(): JKTreeElement = this
@@ -172,7 +174,7 @@ class JKNameIdentifier(val value: String) : JKTreeElement() {
} }
interface JKAnnotationListOwner : JKNonCodeElementsListOwner { interface JKAnnotationListOwner : JKFormattingOwner {
var annotationList: JKAnnotationList var annotationList: JKAnnotationList
} }
@@ -26,8 +26,8 @@ class JKBinaryExpression(
right: JKExpression, right: JKExpression,
override var operator: JKOperator override var operator: JKOperator
) : JKOperatorExpression() { ) : JKOperatorExpression() {
var right by child(right)
var left by child(left) var left by child(left)
var right by child(right)
override fun accept(visitor: JKVisitor) = visitor.visitBinaryExpression(this) override fun accept(visitor: JKVisitor) = visitor.visitBinaryExpression(this)
} }
@@ -0,0 +1,58 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.nj2k.tree
import org.jetbrains.kotlin.utils.SmartList
class JKComment(val text: String) {
val isSingleline
get() = text.startsWith("//")
}
class JKTokenElementImpl(override val text: String) : JKTokenElement {
override val trailingComments: MutableList<JKComment> = SmartList()
override val leadingComments: MutableList<JKComment> = SmartList()
override var hasTrailingLineBreak: Boolean = false
override var hasLeadingLineBreak: Boolean = false
}
interface JKFormattingOwner {
val trailingComments: MutableList<JKComment>
val leadingComments: MutableList<JKComment>
var hasTrailingLineBreak: Boolean
var hasLeadingLineBreak: Boolean
}
inline fun <reified T : JKFormattingOwner> T.withFormattingFrom(other: JKFormattingOwner): T = also {
trailingComments += other.trailingComments
leadingComments += other.leadingComments
hasTrailingLineBreak = other.hasTrailingLineBreak
hasLeadingLineBreak = other.hasLeadingLineBreak
}
inline fun <reified T : JKFormattingOwner> List<T>.withFormattingFrom(other: JKFormattingOwner): List<T> = also {
if (isNotEmpty()) {
it.first().trailingComments += other.trailingComments
it.first().hasTrailingLineBreak = other.hasTrailingLineBreak
it.last().leadingComments += other.leadingComments
it.last().hasLeadingLineBreak = other.hasLeadingLineBreak
}
}
fun JKFormattingOwner.clearFormatting() {
trailingComments.clear()
leadingComments.clear()
hasTrailingLineBreak = false
hasLeadingLineBreak = false
}
interface JKTokenElement : JKFormattingOwner {
val text: String
}
fun JKFormattingOwner.containsNewLine(): Boolean =
hasTrailingLineBreak || hasLeadingLineBreak
@@ -98,7 +98,7 @@ enum class Mutability(override val text: String) : Modifier {
UNKNOWN("var") UNKNOWN("var")
} }
interface JKModifiersListOwner : JKNonCodeElementsListOwner interface JKModifiersListOwner : JKFormattingOwner
fun JKOtherModifiersOwner.elementByModifier(modifier: OtherModifier): JKOtherModifierElement? = fun JKOtherModifiersOwner.elementByModifier(modifier: OtherModifier): JKOtherModifierElement? =
otherModifierElements.firstOrNull { it.otherModifier == modifier } otherModifierElements.firstOrNull { it.otherModifier == modifier }
@@ -1,56 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.nj2k.tree
import org.jetbrains.kotlin.utils.SmartList
interface JKNonCodeElement {
val text: String
}
class JKSpaceElement(override val text: String) : JKNonCodeElement
class JKCommentElement(override val text: String) : JKNonCodeElement
class JKTokenElementImpl(override val text: String) : JKTokenElement {
override val leftNonCodeElements: MutableList<JKNonCodeElement> = SmartList()
override val rightNonCodeElements: MutableList<JKNonCodeElement> = SmartList()
}
interface JKNonCodeElementsListOwner {
val leftNonCodeElements: MutableList<JKNonCodeElement>
val rightNonCodeElements: MutableList<JKNonCodeElement>
}
fun JKNonCodeElementsListOwner.takeNonCodeElementsFrom(other: JKNonCodeElementsListOwner) {
leftNonCodeElements += other.leftNonCodeElements
rightNonCodeElements += other.rightNonCodeElements
}
inline fun <reified T : JKNonCodeElementsListOwner> T.withNonCodeElementsFrom(other: JKNonCodeElementsListOwner): T =
also { it.takeNonCodeElementsFrom(other) }
inline fun <reified T : JKNonCodeElementsListOwner> List<T>.withNonCodeElementsFrom(other: JKNonCodeElementsListOwner): List<T> =
also {
if (isNotEmpty()) {
it.first().leftNonCodeElements += other.leftNonCodeElements
it.last().rightNonCodeElements += other.rightNonCodeElements
}
}
fun JKNonCodeElementsListOwner.clearNonCodeElements() {
leftNonCodeElements.clear()
rightNonCodeElements.clear()
}
interface JKTokenElement : JKNonCodeElementsListOwner {
val text: String
}
fun JKNonCodeElementsListOwner.containsNewLine(): Boolean =
(leftNonCodeElements + rightNonCodeElements).any {
it is JKSpaceElement && '\n' in it.text
}
@@ -102,7 +102,7 @@ fun <R : JKTreeElement> applyRecursive(
inline fun <reified T : JKTreeElement> T.copyTree(): T = inline fun <reified T : JKTreeElement> T.copyTree(): T =
copy().withNonCodeElementsFrom(this) as T copy().withFormattingFrom(this) as T
inline fun <reified T : JKTreeElement> T.copyTreeAndDetach(): T = inline fun <reified T : JKTreeElement> T.copyTreeAndDetach(): T =
copyTree().also { copyTree().also {
@@ -3,8 +3,8 @@ package org.jetbrains.kotlin.nj2k.tree.visitors
import org.jetbrains.kotlin.nj2k.tree.* import org.jetbrains.kotlin.nj2k.tree.*
abstract class JKVisitorWithCommentsPrinting : JKVisitor() { abstract class JKVisitorWithCommentsPrinting : JKVisitor() {
abstract fun printLeftNonCodeElements(element: JKNonCodeElementsListOwner) abstract fun printLeftNonCodeElements(element: JKFormattingOwner)
abstract fun printRightNonCodeElements(element: JKNonCodeElementsListOwner) abstract fun printRightNonCodeElements(element: JKFormattingOwner)
override fun visitTreeElement(treeElement: JKTreeElement) { override fun visitTreeElement(treeElement: JKTreeElement) {
printLeftNonCodeElements(treeElement) printLeftNonCodeElements(treeElement)
@@ -1 +1 @@
/*pre*/ 5 /*operand '5'*/ shl /*left shift*/ 16 /*operand '16'*/ or (/*or*/ 1 /*operand '1'*/ shr /*right shift*/ 8 /*operand '8'*/) or /*or*/ 0 /*operand '0'*/ /*post comment*/ /*pre*/5 /*operand '5'*/ shl /*left shift*/16 /*operand '16'*/ or ( /*or*/1 /*operand '1'*/ shr /*right shift*/8 /*operand '8'*/) or /*or*/0 /*operand '0'*/ /*post comment*/
+9 -11
View File
@@ -3,19 +3,17 @@
package foo package foo
internal class A { internal class A {
fun /* nothing to return */ foo(/* no parameters at all */) { fun /* nothing to return */foo( /* no parameters at all */) { // let declare a variable
// let declare a variable // with 2 comments before
// with 2 comments before val /*int*/a /* it's a */ = 2 /* it's 2 */ + 1 /* it's 1 */ // variable a declared
val /*int*/ a /* it's a */ = 2 /* it's 2 */ + 1 /* it's 1 */ // variable a declared
} // end of foo } // end of foo
fun /* we return int*/ foo( /*int*/ p: Int/* parameter p */): Int { /* body is empty */ fun /* we return int*/foo( /*int*/p: Int /* parameter p */): Int { /* body is empty */
} }
private/*it's private*/ val field = 0 private /*it's private*/ val field = 0
/*it's public*/ fun foo(s: String?): Char {} /*it's public*/ fun foo(s: String?): Char {}
protected/*it's protected*/ fun foo(c: Char) {} protected /*it's protected*/ fun foo(c: Char) {}
/** /**
* Method description. * Method description.
* Multi-line method description. * Multi-line method description.
@@ -28,7 +26,7 @@ internal class A {
*/ */
fun foo(param1: String?, param2: String?, param3: String?) {} fun foo(param1: String?, param2: String?, param3: String?) {}
companion object { companion object { /*it's public*/ /*and static*/ /*and final*/
/*it's public*/ /*and static*/ /*and final*/ const val C = 1 const val C = 1
} }
} }
+2 -5
View File
@@ -5,10 +5,7 @@ internal class A // end of primary constructor body
// this is a secondary constructor 2 // this is a secondary constructor 2
constructor(s: String) : this(s.length) {} // end of secondary constructor 2 body constructor(s: String) : this(s.length) {} // end of secondary constructor 2 body
// this is a primary constructor
// this is a primary constructor
// this is a secondary constructor 1 // this is a secondary constructor 1
@@ -18,7 +15,7 @@ internal class A // end of primary constructor body
internal class B // end of constructor body internal class B // end of constructor body
(private val x: Int) { (private val x: Int) {
fun foo() {} fun foo() {}
// this constructor will disappear // this constructor will disappear
} }
@@ -3,4 +3,5 @@ internal class C(// field p1
/** /**
* Field myP2 * Field myP2
*/ */
private val myP2: Int, /* Field p3 */var p3: Int) private val myP2: Int, /* Field p3 */
var p3: Int)
+3 -3
View File
@@ -1,14 +1,12 @@
internal class A(// comment for field2 setter internal class A(// comment for field2 setter
// comment for field2 getter // comment for field2 getter
var field2 // comment for field2 var field2 // comment for field2
: Int) { : Int) { // Comment for field1
/** /**
* Comment for field1 setter * Comment for field1 setter
*/ */
// Comment for field1 getter // Comment for field1 getter
// Comment for field1
var field1 = 0 var field1 = 0
// comment for field3 setter // comment for field3 setter
// comment for field3 getter // comment for field3 getter
// comment before field3 // comment before field3
@@ -22,4 +20,6 @@ internal class A(// comment for field2 setter
var property: Int var property: Int
get() = 1 get() = 1
set(value) {} set(value) {}
} }
@@ -1,3 +1,2 @@
class Nya /*comment before*/ class Nya /*comment before*/ /* comment after*/ // and after again
/* comment after*/ // and after again (/*1*/ /*3*/ /*4*/private val i: Int)
(/*1*//*3*/ /*4*/private val i: Int)
@@ -1,29 +1,16 @@
internal class F { internal class F { //c3
//c1
/*c2*///c3
//c4 //c4
fun f2() {} fun f2() {}
fun f3() {} fun f3() {}
fun f4() {} fun f4() {}
//c5 companion object { //c1
/*c2*/
companion object {
fun f1() {} fun f1() {}
var i = 0 var i = 0
//c5
fun f5() {} //c6
fun f5() {}
//c6
} }
} }
+5 -13
View File
@@ -1,17 +1,12 @@
// This is an end-of-line comment // This is an end-of-line comment
/* /*
This is a block comment This is a block comment
*/ */
/*doc comment of class*/ /*doc comment of class*/
//one line comment of class //one line comment of class
//another one //another one
/*another doc*/ /*another doc*/
internal class C { internal class C { // This is a class comment
// This is a class comment
/** /**
* This is a field doc comment. * This is a field doc comment.
@@ -21,8 +16,7 @@ internal class C {
/** /**
* This is a function doc comment. * This is a function doc comment.
*/ */
fun foo() { fun foo() { /* This is a function comment */
/* This is a function comment */
} }
//simple one line comment for function //simple one line comment for function
@@ -43,8 +37,6 @@ internal class C {
/** of /** of
*/ */
// //
/** /**
* different * different
*/ */
@@ -55,13 +47,13 @@ internal class C {
/** of /** of
*/ */
// //
/** /**
* different * different
*/ */
//comments //comments
var l = 0 var l = 0
/*two*/ /*comments*//*line*/ /*two*/
/*comments*/
/*line*/
var z = 0 var z = 0
} }
+3 -6
View File
@@ -5,10 +5,6 @@ class TestMutltipleCtorsWithJavadoc
*/(private val x: String?) { */(private val x: String?) {
private var y: String? = null private var y: String? = null
// ---
// Constructors
//
/** /**
* Javadoc for 2nd ctor * Javadoc for 2nd ctor
* @param x * @param x
@@ -17,6 +13,7 @@ class TestMutltipleCtorsWithJavadoc
constructor(x: String?, y: String?) : this(x) { constructor(x: String?, y: String?) : this(x) {
this.y = y this.y = y
} }
// ---
// Constructors
//
} }
+4 -4
View File
@@ -3,12 +3,12 @@ import java.util.stream.Collectors
internal class Test { internal class Test {
fun main(lst: List<Int>) { fun main(lst: List<Int>) {
val newLst = /*before list*/ lst/*after list*/.stream/*before stream*/()/* after stream*/ val newLst = /*before list*/lst /*after list*/.stream /*before stream*/() /* after stream*/
.filter { x: Int -> x > 10 } .filter { x: Int -> x > 10 }
.map { x: Int -> x + 2 }/*some comment*/.distinct/*another comment*/()/* one more comment */.sorted()/*another one comment*/ .map { x: Int -> x + 2 } /*some comment*/.distinct /*another comment*/() /* one more comment */.sorted() /*another one comment*/
.sorted(Comparator.naturalOrder()) .sorted(Comparator.naturalOrder())
.peek { x: Int? -> println(x) }.limit(1) .peek { x: Int? -> println(x) }.limit(1)
.skip(42)/*skipped*/ .skip(42) /*skipped*/ /*collecting one*/
/*collecting one*/.collect/*collecting two */(Collectors.toList())/* cool */ .collect /*collecting two */(Collectors.toList()) /* cool */
} }
} }
@@ -87,7 +87,6 @@ class A {
int limit = 5; int limit = 5;
useSplit(s.split("\\s+", limit)); useSplit(s.split("\\s+", limit));
*/ */
*/
s.trim(); s.trim();
s.concat(" another"); s.concat(" another");
+2 -6
View File
@@ -8,8 +8,6 @@ internal class A {
fun constructors() { fun constructors() {
String() String()
// TODO: new String("original"); // TODO: new String("original");
String(charArrayOf('a', 'b', 'c')) String(charArrayOf('a', 'b', 'c'))
String(charArrayOf('b', 'd'), 1, 1) String(charArrayOf('b', 'd'), 1, 1)
String(intArrayOf(32, 65, 127), 0, 3) String(intArrayOf(32, 65, 127), 0, 3)
@@ -88,8 +86,7 @@ internal class A {
useSplit(s.split("\\s+", 2)); useSplit(s.split("\\s+", 2));
int limit = 5; int limit = 5;
useSplit(s.split("\\s+", limit)); useSplit(s.split("\\s+", limit));
*/ */s.trim { it <= ' ' }
s.trim { it <= ' ' }
"$s another" "$s another"
s.toByteArray() s.toByteArray()
s.toByteArray(Charset.forName("utf-8")) s.toByteArray(Charset.forName("utf-8"))
@@ -121,8 +118,7 @@ internal class A {
} }
fun unsupportedMethods() { fun unsupportedMethods() {
val s = "test string" val s = "test string" /* TODO:
/* TODO:
s.indexOf(32); s.indexOf(32);
s.indexOf(32, 2); s.indexOf(32, 2);
s.lastIndexOf(32); s.lastIndexOf(32);