diff --git a/j2k/src/org/jetbrains/kotlin/j2k/CodeBuilder.kt b/j2k/src/org/jetbrains/kotlin/j2k/CodeBuilder.kt index 1568b628fe5..299e78f8254 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/CodeBuilder.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/CodeBuilder.kt @@ -19,12 +19,12 @@ package org.jetbrains.kotlin.j2k import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.* import com.intellij.psi.javadoc.PsiDocComment +import com.intellij.util.SmartList import org.jetbrains.kotlin.j2k.ast.CommentsAndSpacesInheritance import org.jetbrains.kotlin.j2k.ast.Element import org.jetbrains.kotlin.j2k.ast.SpacesInheritance import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.psiUtil.isAncestor -import org.jetbrains.kotlin.utils.addIfNotNull import java.util.ArrayList import java.util.HashSet import java.util.LinkedHashSet @@ -122,13 +122,13 @@ class CodeBuilder(private val topElement: PsiElement?) { val notInsideElements = HashSet() var prefix = Prefix.Empty - val postfixElements = ArrayList(1) + var postfix = emptyList() for ((prototype, inheritance) in element.prototypes!!) { assert(prototype !is PsiComment) assert(prototype !is PsiWhiteSpace) if (!topElement.isAncestor(prototype)) continue prefix += collectPrefixElements(prototype, inheritance, notInsideElements) - postfixElements.collectPostfixElements(prototype, inheritance, notInsideElements) + postfix += collectPostfixElements(prototype, inheritance, notInsideElements) } if (prefix.lineBreaksBefore > 0) { @@ -155,15 +155,23 @@ class CodeBuilder(private val topElement: PsiElement?) { } } - postfixElements.forEach { appendCommentOrWhiteSpace(it) } + postfix.forEach { appendCommentOrWhiteSpace(it) } element.postGenerateCode(this) return this } - private data class Prefix(val elements: Collection, val lineBreaksBefore: Int) { - fun plus(other: Prefix) = Prefix(elements + other.elements, Math.max(lineBreaksBefore, other.lineBreaksBefore)) + private data class Prefix(val elements: List, val lineBreaksBefore: Int) { + fun plus(other: Prefix): Prefix { + return when { + isEmpty() -> other + other.isEmpty() -> this + else -> Prefix(elements + other.elements, Math.max(lineBreaksBefore, other.lineBreaksBefore)) + } + } + + private fun isEmpty() = elements.isEmpty() && lineBreaksBefore == 0 companion object { val Empty = Prefix(emptyList(), 0) @@ -175,8 +183,8 @@ class CodeBuilder(private val topElement: PsiElement?) { inheritance: CommentsAndSpacesInheritance, notInsideElements: MutableSet ): Prefix { - val before = ArrayList(1).collectCommentsAndSpacesBefore(element) - val atStart = ArrayList(1).collectCommentsAndSpacesAtStart(element) + val before = SmartList().collectCommentsAndSpacesBefore(element) + val atStart = SmartList().collectCommentsAndSpacesAtStart(element) notInsideElements.addAll(atStart) if (inheritance.spacesBefore == SpacesInheritance.NONE && !inheritance.commentsBefore) return Prefix.Empty @@ -210,13 +218,17 @@ class CodeBuilder(private val topElement: PsiElement?) { return Prefix(elements, lineBreaks) } - private fun MutableList.collectPostfixElements(element: PsiElement, inheritance: CommentsAndSpacesInheritance, notInsideElements: MutableSet) { - val atEnd = ArrayList(1).collectCommentsAndSpacesAtEnd(element) + private fun collectPostfixElements( + element: PsiElement, + inheritance: CommentsAndSpacesInheritance, + notInsideElements: MutableSet + ): List { + val atEnd = SmartList().collectCommentsAndSpacesAtEnd(element) notInsideElements.addAll(atEnd) - if (!inheritance.commentsAfter) return + if (!inheritance.commentsAfter) return emptyList() - val after = ArrayList(1).collectCommentsAndSpacesAfter(element) + val after = SmartList().collectCommentsAndSpacesAfter(element) if (after.isNotEmpty()) { val last = after.last() if (last is PsiWhiteSpace) { @@ -224,11 +236,9 @@ class CodeBuilder(private val topElement: PsiElement?) { } } - addAll(atEnd.reverse()) - addAll(after) - - commentsAndSpacesUsed.addAll(atEnd) - commentsAndSpacesUsed.addAll(after) + val result = atEnd.reverse() + after + commentsAndSpacesUsed.addAll(result) + return result } private fun MutableList.collectCommentsAndSpacesBefore(element: PsiElement): MutableList { @@ -304,20 +314,44 @@ class CodeBuilder(private val topElement: PsiElement?) { return this } - private fun PsiElement.isCommentOrSpace() = this is PsiComment || this is PsiWhiteSpace + private companion object { + fun List.plus(other: List): List { + when { + isEmpty() -> return other - private fun PsiElement.isEndOfLineComment() = this is PsiComment && getTokenType() == JavaTokenType.END_OF_LINE_COMMENT + other.isEmpty() -> return this - private fun PsiElement.isEmptyElement() = getFirstChild() == null && getTextLength() == 0 + else -> { + val result = ArrayList(size() + other.size()) + result.addAll(this) + result.addAll(other) + return result + } + } + } - private fun PsiWhiteSpace.newLinesCount() = StringUtil.getLineBreakCount(getText()!!) + fun List.reverse(): List { + return if (size() <= 1) + this + else + (this as Iterable).reverse() + } - private fun PsiWhiteSpace.hasNewLines() = StringUtil.containsLineBreak(getText()!!) + fun PsiElement.isCommentOrSpace() = this is PsiComment || this is PsiWhiteSpace - private fun CharSequence.trailingLineBreakCount(): Int { - val index = ((length()-1 downTo 0).firstOrNull { val c = this[it]; c != '\n' && c != '\r' } ?: -1) + 1 - if (index == length()) return 0 - return StringUtil.getLineBreakCount(subSequence(index, length())) + fun PsiElement.isEndOfLineComment() = this is PsiComment && getTokenType() == JavaTokenType.END_OF_LINE_COMMENT + + fun PsiElement.isEmptyElement() = getFirstChild() == null && getTextLength() == 0 + + fun PsiWhiteSpace.newLinesCount() = StringUtil.getLineBreakCount(getText()!!) + + fun PsiWhiteSpace.hasNewLines() = StringUtil.containsLineBreak(getText()!!) + + fun CharSequence.trailingLineBreakCount(): Int { + val index = ((length()-1 downTo 0).firstOrNull { val c = this[it]; c != '\n' && c != '\r' } ?: -1) + 1 + if (index == length()) return 0 + return StringUtil.getLineBreakCount(subSequence(index, length())) + } } }