DeprecatedSymbolUsageFix to keep line breaks when possible
This commit is contained in:
@@ -19,27 +19,30 @@ package org.jetbrains.kotlin.idea.core
|
|||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
|
import com.intellij.psi.codeStyle.CodeStyleManager
|
||||||
import org.jetbrains.kotlin.lexer.JetToken
|
import org.jetbrains.kotlin.lexer.JetToken
|
||||||
import org.jetbrains.kotlin.lexer.JetTokens
|
import org.jetbrains.kotlin.lexer.JetTokens
|
||||||
import org.jetbrains.kotlin.psi.JetPsiFactory
|
import org.jetbrains.kotlin.psi.JetPsiFactory
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
import java.util.HashMap
|
import java.util.HashMap
|
||||||
import java.util.LinkedHashMap
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
public class CommentSaver(originalElements: PsiChildRange) {
|
public class CommentSaver(originalElements: PsiChildRange, private val saveLineBreaks: Boolean = false/*TODO?*/) {
|
||||||
public constructor(originalElement: PsiElement) : this(PsiChildRange.singleElement(originalElement))
|
public constructor(originalElement: PsiElement, saveLineBreaks: Boolean = false/*TODO?*/) : this(PsiChildRange.singleElement(originalElement), saveLineBreaks)
|
||||||
|
|
||||||
private val SAVED_TREE_KEY = Key<TreeElement>("SAVED_TREE")
|
private val SAVED_TREE_KEY = Key<TreeElement>("SAVED_TREE")
|
||||||
|
private val psiFactory = JetPsiFactory(originalElements.first!!)
|
||||||
|
|
||||||
private abstract class TreeElement {
|
private abstract class TreeElement {
|
||||||
public companion object {
|
public companion object {
|
||||||
public fun create(element: PsiElement): TreeElement? {
|
public fun create(element: PsiElement): TreeElement? {
|
||||||
val elementType = element.getNode().getElementType()
|
val tokenType = element.tokenType
|
||||||
val treeElement = when (elementType) {
|
val treeElement = when {
|
||||||
TokenType.WHITE_SPACE -> if (element.textContains('\n')) LineBreakTreeElement() else null
|
element is PsiWhiteSpace -> if (element.textContains('\n')) LineBreakTreeElement() else null
|
||||||
is JetToken -> if (element is PsiComment) CommentTreeElement.create(element) else TokenTreeElement(elementType)
|
element is PsiComment -> CommentTreeElement.create(element)
|
||||||
else -> StandardTreeElement()
|
tokenType != null -> TokenTreeElement(tokenType)
|
||||||
|
else -> if (element.getTextLength() > 0) StandardTreeElement() else null // don't save empty elements
|
||||||
}
|
}
|
||||||
// treeElement?.debugText = element.getText()
|
// treeElement?.debugText = element.getText()
|
||||||
return treeElement
|
return treeElement
|
||||||
@@ -64,6 +67,46 @@ public class CommentSaver(originalElements: PsiChildRange) {
|
|||||||
val nextSiblings: Sequence<TreeElement>
|
val nextSiblings: Sequence<TreeElement>
|
||||||
get() = sequence({ next }, { it.next })
|
get() = sequence({ next }, { it.next })
|
||||||
|
|
||||||
|
val parents: Sequence<TreeElement>
|
||||||
|
get() = sequence({ parent }, { it.parent })
|
||||||
|
|
||||||
|
val parentsWithSelf: Sequence<TreeElement>
|
||||||
|
get() = sequence(this, { it.parent })
|
||||||
|
|
||||||
|
val firstLeafInside: TreeElement
|
||||||
|
get() {
|
||||||
|
var result = this
|
||||||
|
while (true) {
|
||||||
|
result = result.firstChild ?: break
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
val lastLeafInside: TreeElement
|
||||||
|
get() {
|
||||||
|
var result = this
|
||||||
|
while (true) {
|
||||||
|
result = result.lastChild ?: break
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
val prevLeaf: TreeElement?
|
||||||
|
get() {
|
||||||
|
return (prev ?: return parent?.prevLeaf).lastLeafInside
|
||||||
|
}
|
||||||
|
|
||||||
|
val nextLeaf: TreeElement?
|
||||||
|
get() {
|
||||||
|
return (next ?: return parent?.nextLeaf).firstLeafInside
|
||||||
|
}
|
||||||
|
|
||||||
|
val prevLeafs: Sequence<TreeElement>
|
||||||
|
get() = sequence({ prevLeaf }, { it.prevLeaf })
|
||||||
|
|
||||||
|
val nextLeafs: Sequence<TreeElement>
|
||||||
|
get() = sequence({ nextLeaf }, { it.nextLeaf })
|
||||||
|
|
||||||
fun withDescendants(leftToRight: Boolean): Sequence<TreeElement> {
|
fun withDescendants(leftToRight: Boolean): Sequence<TreeElement> {
|
||||||
val children = if (leftToRight) children else reverseChildren
|
val children = if (leftToRight) children else reverseChildren
|
||||||
return sequenceOf(this) + children.flatMap { it.withDescendants(leftToRight) }
|
return sequenceOf(this) + children.flatMap { it.withDescendants(leftToRight) }
|
||||||
@@ -97,18 +140,13 @@ public class CommentSaver(originalElements: PsiChildRange) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val commentsToRestore = ArrayList<CommentTreeElement>()
|
private val commentsToRestore = ArrayList<CommentTreeElement>()
|
||||||
|
private val lineBreaksToRestore = ArrayList<LineBreakTreeElement>()
|
||||||
|
private var toNewPsiElementMap by Delegates.notNull<MutableMap<TreeElement, MutableCollection<PsiElement>>>()
|
||||||
|
private var needAdjustIndentAfterRestore = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (originalElements.any { it.anyDescendantOfType<PsiComment>() }) {
|
if (saveLineBreaks || originalElements.any { it.anyDescendantOfType<PsiComment>() }) {
|
||||||
originalElements.save(null)
|
originalElements.save(null)
|
||||||
|
|
||||||
for (element in originalElements) {
|
|
||||||
element.accept(object : PsiRecursiveElementVisitor(){
|
|
||||||
override fun visitComment(comment: PsiComment) {
|
|
||||||
commentsToRestore.add(comment.savedTreeElement as CommentTreeElement)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,6 +169,11 @@ public class CommentSaver(originalElements: PsiChildRange) {
|
|||||||
first = savedChild
|
first = savedChild
|
||||||
}
|
}
|
||||||
|
|
||||||
|
when (savedChild) {
|
||||||
|
is CommentTreeElement -> commentsToRestore.add(savedChild)
|
||||||
|
is LineBreakTreeElement -> if (saveLineBreaks) lineBreaksToRestore.add(savedChild)
|
||||||
|
}
|
||||||
|
|
||||||
child.allChildren.save(savedChild)
|
child.allChildren.save(savedChild)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,12 +222,44 @@ public class CommentSaver(originalElements: PsiChildRange) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun restoreComments(resultElement: PsiElement) {
|
private fun putNewElementIntoMap(psiElement: PsiElement, treeElement: TreeElement) {
|
||||||
restoreComments(PsiChildRange.singleElement(resultElement))
|
toNewPsiElementMap.getOrPut(treeElement) { ArrayList(1) }.add(psiElement)
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun restoreComments(resultElements: PsiChildRange) {
|
private fun bindNewElement(newPsiElement: PsiElement, treeElement: TreeElement) {
|
||||||
doRestoreComments(resultElements)
|
newPsiElement.savedTreeElement = treeElement
|
||||||
|
putNewElementIntoMap(newPsiElement, treeElement)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun restore(resultElement: PsiElement) {
|
||||||
|
restore(PsiChildRange.singleElement(resultElement))
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun restore(resultElements: PsiChildRange) {
|
||||||
|
assert(!resultElements.isEmpty)
|
||||||
|
|
||||||
|
if (commentsToRestore.isEmpty() && lineBreaksToRestore.isEmpty()) return
|
||||||
|
|
||||||
|
// remove comments that present inside resultElements from commentsToRestore
|
||||||
|
resultElements.forEach { deleteCommentsInside(it) }
|
||||||
|
if (commentsToRestore.isEmpty() && lineBreaksToRestore.isEmpty()) return
|
||||||
|
|
||||||
|
toNewPsiElementMap = HashMap<TreeElement, MutableCollection<PsiElement>>()
|
||||||
|
for (element in resultElements) {
|
||||||
|
element.accept(object : PsiRecursiveElementVisitor() {
|
||||||
|
override fun visitElement(element: PsiElement) {
|
||||||
|
val treeElement = element.savedTreeElement
|
||||||
|
if (treeElement != null) {
|
||||||
|
putNewElementIntoMap(element, treeElement)
|
||||||
|
}
|
||||||
|
super.visitElement(element)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreComments(resultElements)
|
||||||
|
|
||||||
|
restoreLineBreaks()
|
||||||
|
|
||||||
// clear user data
|
// clear user data
|
||||||
resultElements.forEach {
|
resultElements.forEach {
|
||||||
@@ -195,74 +270,122 @@ public class CommentSaver(originalElements: PsiChildRange) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (needAdjustIndentAfterRestore) {
|
||||||
|
val file = resultElements.first().getContainingFile()
|
||||||
|
val project = file.getProject()
|
||||||
|
val psiDocumentManager = PsiDocumentManager.getInstance(project)
|
||||||
|
psiDocumentManager.doPostponedOperationsAndUnblockDocument(psiDocumentManager.getDocument(file)!!)
|
||||||
|
CodeStyleManager.getInstance(project).adjustLineIndent(file, resultElements.textRange)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doRestoreComments(resultElements: PsiChildRange) {
|
private fun restoreComments(resultElements: PsiChildRange) {
|
||||||
assert(!resultElements.isEmpty)
|
|
||||||
|
|
||||||
if (commentsToRestore.isEmpty()) return
|
|
||||||
|
|
||||||
// remove comments that present inside resultElements from commentsToRestore
|
|
||||||
resultElements.forEach { deleteCommentsInside(it) }
|
|
||||||
if (commentsToRestore.isEmpty()) return
|
|
||||||
|
|
||||||
val toNewPsiElementMap = HashMap<TreeElement, MutableCollection<PsiElement>>()
|
|
||||||
for (element in resultElements) {
|
|
||||||
element.accept(object : PsiRecursiveElementVisitor() {
|
|
||||||
override fun visitElement(element: PsiElement) {
|
|
||||||
val treeElement = element.savedTreeElement
|
|
||||||
if (treeElement != null) {
|
|
||||||
toNewPsiElementMap.getOrPut(treeElement) { ArrayList(1) }.add(element)
|
|
||||||
}
|
|
||||||
super.visitElement(element)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
val psiFactory = JetPsiFactory(resultElements.first!!)
|
|
||||||
var putAbandonedCommentsAfter = resultElements.last!!
|
var putAbandonedCommentsAfter = resultElements.last!!
|
||||||
|
|
||||||
for (commentTreeElement in commentsToRestore) {
|
for (commentTreeElement in commentsToRestore) {
|
||||||
val comment = psiFactory.createComment(commentTreeElement.commentText)
|
val comment = psiFactory.createComment(commentTreeElement.commentText)
|
||||||
|
|
||||||
val anchorBefore = findAnchor(commentTreeElement, toNewPsiElementMap, before = true)
|
val anchorBefore = findAnchor(commentTreeElement, before = true)
|
||||||
val anchorAfter = findAnchor(commentTreeElement, toNewPsiElementMap, before = false)
|
val anchorAfter = findAnchor(commentTreeElement, before = false)
|
||||||
val anchor = chooseAnchor(anchorBefore, anchorAfter)
|
val anchor = chooseAnchor(anchorBefore, anchorAfter)
|
||||||
|
|
||||||
|
val restored: PsiComment
|
||||||
if (anchor != null) {
|
if (anchor != null) {
|
||||||
val anchorElement = findFinalAnchorElement(anchor, comment)
|
val anchorElement = findFinalAnchorElement(anchor, comment)
|
||||||
val parent = anchorElement.getParent()
|
val parent = anchorElement.getParent()
|
||||||
if (anchor.before) {
|
if (anchor.before) {
|
||||||
parent.addAfter(comment, anchorElement)
|
restored = parent.addAfter(comment, anchorElement) as PsiComment
|
||||||
if (commentTreeElement.spaceBefore.isNotEmpty()) {
|
if (commentTreeElement.spaceBefore.isNotEmpty()) {
|
||||||
parent.addAfter(psiFactory.createWhiteSpace(commentTreeElement.spaceBefore), anchorElement)
|
parent.addAfter(psiFactory.createWhiteSpace(commentTreeElement.spaceBefore), anchorElement)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
parent.addBefore(comment, anchorElement)
|
restored = parent.addBefore(comment, anchorElement) as PsiComment
|
||||||
if (commentTreeElement.spaceAfter.isNotEmpty()) {
|
if (commentTreeElement.spaceAfter.isNotEmpty()) {
|
||||||
parent.addBefore(psiFactory.createWhiteSpace(commentTreeElement.spaceAfter), anchorElement)
|
parent.addBefore(psiFactory.createWhiteSpace(commentTreeElement.spaceAfter), anchorElement)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
putAbandonedCommentsAfter = putAbandonedCommentsAfter.getParent().addAfter(comment, putAbandonedCommentsAfter)
|
restored = putAbandonedCommentsAfter.getParent().addAfter(comment, putAbandonedCommentsAfter) as PsiComment
|
||||||
|
putAbandonedCommentsAfter = restored
|
||||||
|
}
|
||||||
|
|
||||||
|
bindNewElement(restored, commentTreeElement) // will be used when restoring line breaks
|
||||||
|
|
||||||
|
if (restored.tokenType == JetTokens.EOL_COMMENT) {
|
||||||
|
needAdjustIndentAfterRestore = true // TODO: do we really need it?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun restoreLineBreaks() {
|
||||||
|
for (lineBreakElement in lineBreaksToRestore) {
|
||||||
|
if (toNewPsiElementMap[lineBreakElement] != null) continue
|
||||||
|
|
||||||
|
val lineBreakParent = lineBreakElement.parent
|
||||||
|
|
||||||
|
fun findRestored(leaf: TreeElement): PsiElement? {
|
||||||
|
if (leaf is LineBreakTreeElement) return null
|
||||||
|
return leaf.parentsWithSelf
|
||||||
|
.takeWhile { it != lineBreakParent }
|
||||||
|
.map { toNewPsiElementMap[it]?.first() } //TODO: what about multiple?
|
||||||
|
.filterNotNull()
|
||||||
|
.firstOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val tokensToMatch = arrayListOf<JetToken>()
|
||||||
|
for (leaf in lineBreakElement.prevLeafs) {
|
||||||
|
var psiElement = findRestored(leaf)
|
||||||
|
if (psiElement != null) {
|
||||||
|
psiElement = skipTokensForward(psiElement, tokensToMatch.reverse())
|
||||||
|
psiElement?.restoreLineBreakAfter()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (leaf !is TokenTreeElement) break
|
||||||
|
tokensToMatch.add(leaf.tokenType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun skipTokensForward(psiElement: PsiElement, tokensToMatch: List<JetToken>): PsiElement? {
|
||||||
|
var currentPsiElement = psiElement
|
||||||
|
for (token in tokensToMatch) {
|
||||||
|
currentPsiElement = currentPsiElement.nextLeaf(nonSpaceAndNonEmptyFilter) ?: return null
|
||||||
|
if (currentPsiElement.tokenType != token) return null
|
||||||
|
}
|
||||||
|
return currentPsiElement
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun PsiElement.restoreLineBreakAfter() {
|
||||||
|
val addAfter = shiftNewLineAnchor(this).anchorToAddCommentOrSpace(before = false)
|
||||||
|
var whitespace = addAfter.getNextSibling() as? PsiWhiteSpace
|
||||||
|
//TODO: restore blank lines
|
||||||
|
if (whitespace != null && whitespace.getText().contains('\n')) return // line break is already there
|
||||||
|
|
||||||
|
if (whitespace == null) {
|
||||||
|
addAfter.getParent().addAfter(psiFactory.createNewLine(), addAfter)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
whitespace.replace(psiFactory.createWhiteSpace("\n" + whitespace.getText()))
|
||||||
|
}
|
||||||
|
|
||||||
|
needAdjustIndentAfterRestore = true
|
||||||
|
}
|
||||||
|
|
||||||
private class Anchor(val element: PsiElement, val treeElementsBetween: Collection<TreeElement>, val before: Boolean)
|
private class Anchor(val element: PsiElement, val treeElementsBetween: Collection<TreeElement>, val before: Boolean)
|
||||||
|
|
||||||
private fun findAnchor(commentTreeElement: CommentTreeElement, toNewPsiElementMap: Map<TreeElement, Collection<PsiElement>>, before: Boolean): Anchor? {
|
private fun findAnchor(commentTreeElement: CommentTreeElement, before: Boolean): Anchor? {
|
||||||
val treeElementsBetween = ArrayList<TreeElement>()
|
val treeElementsBetween = ArrayList<TreeElement>()
|
||||||
val sequence = if (before) commentTreeElement.prevElements else commentTreeElement.nextElements
|
val sequence = if (before) commentTreeElement.prevElements else commentTreeElement.nextElements
|
||||||
for (treeElement in sequence) {
|
for (treeElement in sequence) {
|
||||||
val newPsiElements = toNewPsiElementMap[treeElement]
|
val newPsiElements = toNewPsiElementMap[treeElement]
|
||||||
if (newPsiElements != null) {
|
if (newPsiElements != null) {
|
||||||
var psiElement = newPsiElements.first() //TODO: should we restore multiple?
|
val psiElement = newPsiElements.first().anchorToAddCommentOrSpace(!before) //TODO: should we restore multiple?
|
||||||
psiElement = psiElement.parents()
|
|
||||||
.dropWhile { it.getParent() !is PsiFile && (if (before) it.getNextSibling() else it.getPrevSibling()) == null }
|
|
||||||
.first()
|
|
||||||
return Anchor(psiElement, treeElementsBetween, before)
|
return Anchor(psiElement, treeElementsBetween, before)
|
||||||
}
|
}
|
||||||
if (treeElement.firstChild == null) { // we put only leafs into treeElementsBetween
|
if (treeElement.firstChild == null) { // we put only leafs into treeElementsBetween
|
||||||
@@ -272,6 +395,12 @@ public class CommentSaver(originalElements: PsiChildRange) {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun PsiElement.anchorToAddCommentOrSpace(before: Boolean): PsiElement {
|
||||||
|
return parents()
|
||||||
|
.dropWhile { it.getParent() !is PsiFile && (if (before) it.getPrevSibling() else it.getNextSibling()) == null }
|
||||||
|
.first()
|
||||||
|
}
|
||||||
|
|
||||||
private fun chooseAnchor(anchorBefore: Anchor?, anchorAfter: Anchor?): Anchor? {
|
private fun chooseAnchor(anchorBefore: Anchor?, anchorAfter: Anchor?): Anchor? {
|
||||||
if (anchorBefore == null) return anchorAfter
|
if (anchorBefore == null) return anchorAfter
|
||||||
if (anchorAfter == null) return anchorBefore
|
if (anchorAfter == null) return anchorBefore
|
||||||
@@ -292,25 +421,35 @@ public class CommentSaver(originalElements: PsiChildRange) {
|
|||||||
val tokensBetween = anchor.treeElementsBetween.filterIsInstance<TokenTreeElement>()
|
val tokensBetween = anchor.treeElementsBetween.filterIsInstance<TokenTreeElement>()
|
||||||
|
|
||||||
fun PsiElement.next(): PsiElement? {
|
fun PsiElement.next(): PsiElement? {
|
||||||
val filter = { element: PsiElement -> element !is PsiWhiteSpace && element.getTextLength() > 0 }
|
return if (anchor.before) nextLeaf(nonSpaceAndNonEmptyFilter) else prevLeaf(nonSpaceAndNonEmptyFilter)
|
||||||
return if (anchor.before) nextLeaf(filter) else prevLeaf(filter)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var psiElement = anchor.element
|
var psiElement = anchor.element
|
||||||
for (token in tokensBetween.reverse()) {
|
for (token in tokensBetween.reverse()) {
|
||||||
val next = psiElement.next() ?: break
|
val next = psiElement.next() ?: break
|
||||||
if (next.getNode().getElementType() != token.tokenType) break
|
if (next.tokenType != token.tokenType) break
|
||||||
psiElement = next
|
psiElement = next
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't put end of line comment right before comma
|
// don't put end of line comment right before comma
|
||||||
if (anchor.before && comment.getNode().getElementType() == JetTokens.EOL_COMMENT) {
|
if (anchor.before && comment.tokenType == JetTokens.EOL_COMMENT) {
|
||||||
val next = psiElement.next()
|
psiElement = shiftNewLineAnchor(psiElement)
|
||||||
if (next != null && next.getNode().getElementType() == JetTokens.COMMA) {
|
|
||||||
psiElement = next
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return psiElement
|
return psiElement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// don't put line break right before comma
|
||||||
|
private fun shiftNewLineAnchor(putAfter: PsiElement): PsiElement {
|
||||||
|
val next = putAfter.nextLeaf(nonSpaceAndNonEmptyFilter)
|
||||||
|
return if (next?.tokenType == JetTokens.COMMA) next!! else putAfter
|
||||||
|
}
|
||||||
|
|
||||||
|
private val nonSpaceAndNonEmptyFilter = { element: PsiElement -> element !is PsiWhiteSpace && element.getTextLength() > 0 }
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
//TODO: making it private causes error on runtime
|
||||||
|
val PsiElement.tokenType: JetToken?
|
||||||
|
get() = getNode().getElementType() as? JetToken
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ public class ConvertForEachToForLoopIntention : JetSelfTargetingOffsetIndependen
|
|||||||
val loop = generateLoop(functionLiteral, receiver)
|
val loop = generateLoop(functionLiteral, receiver)
|
||||||
val result = expressionToReplace.replace(loop)
|
val result = expressionToReplace.replace(loop)
|
||||||
|
|
||||||
commentSaver.restoreComments(result)
|
commentSaver.restore(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class Data(
|
private data class Data(
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public class ConvertToExpressionBodyIntention : JetSelfTargetingOffsetIndependen
|
|||||||
declaration.addBefore(JetPsiFactory(declaration).createEQ(), body)
|
declaration.addBefore(JetPsiFactory(declaration).createEQ(), body)
|
||||||
val newBody = body.replace(value)
|
val newBody = body.replace(value)
|
||||||
|
|
||||||
commentSaver.restoreComments(newBody)
|
commentSaver.restore(newBody)
|
||||||
|
|
||||||
if (omitType) {
|
if (omitType) {
|
||||||
onFinish(declaration as JetCallableDeclaration)
|
onFinish(declaration as JetCallableDeclaration)
|
||||||
|
|||||||
+1
-1
@@ -44,6 +44,6 @@ public class ConvertToForEachFunctionCallIntention : JetSelfTargetingIntention<J
|
|||||||
"$0.forEach{$1->$2}", element.getLoopRange()!!, loopParameter, functionBodyArgument)
|
"$0.forEach{$1->$2}", element.getLoopRange()!!, loopParameter, functionBodyArgument)
|
||||||
val result = element.replace(foreachExpression)
|
val result = element.replace(foreachExpression)
|
||||||
|
|
||||||
commentSaver.restoreComments(result)
|
commentSaver.restore(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public class SplitIfIntention : JetSelfTargetingIntention<JetExpression>(javaCla
|
|||||||
val secondIf = container.addAfter(innerIf, ifExpression)
|
val secondIf = container.addAfter(innerIf, ifExpression)
|
||||||
container.addAfter(psiFactory.createNewLine(), ifExpression)
|
container.addAfter(psiFactory.createNewLine(), ifExpression)
|
||||||
val firstIf = ifExpression.replace(psiFactory.createIf(leftExpression, thenBranch))
|
val firstIf = ifExpression.replace(psiFactory.createIf(leftExpression, thenBranch))
|
||||||
commentSaver.restoreComments(PsiChildRange(firstIf, secondIf))
|
commentSaver.restore(PsiChildRange(firstIf, secondIf))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -81,7 +81,7 @@ public class SplitIfIntention : JetSelfTargetingIntention<JetExpression>(javaCla
|
|||||||
}
|
}
|
||||||
|
|
||||||
val result = ifExpression.replace(newIf)
|
val result = ifExpression.replace(newIf)
|
||||||
commentSaver.restoreComments(result)
|
commentSaver.restore(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getRight(element: JetBinaryExpression, condition: JetExpression, commentSaver: CommentSaver): JetExpression {
|
private fun getRight(element: JetBinaryExpression, condition: JetExpression, commentSaver: CommentSaver): JetExpression {
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ public abstract class DeprecatedSymbolUsageFixBase(
|
|||||||
val qualifiedExpression = if (parent is JetQualifiedExpression && callExpression == parent.getSelectorExpression()) parent else null
|
val qualifiedExpression = if (parent is JetQualifiedExpression && callExpression == parent.getSelectorExpression()) parent else null
|
||||||
val expressionToBeReplaced = qualifiedExpression ?: callExpression
|
val expressionToBeReplaced = qualifiedExpression ?: callExpression
|
||||||
|
|
||||||
val commentSaver = CommentSaver(expressionToBeReplaced)
|
val commentSaver = CommentSaver(expressionToBeReplaced, saveLineBreaks = true)
|
||||||
|
|
||||||
var receiver = element.getReceiverExpression()?.marked(USER_CODE_KEY)
|
var receiver = element.getReceiverExpression()?.marked(USER_CODE_KEY)
|
||||||
var receiverType = if (receiver != null) bindingContext.getType(receiver) else null
|
var receiverType = if (receiver != null) bindingContext.getType(receiver) else null
|
||||||
@@ -231,7 +231,7 @@ public abstract class DeprecatedSymbolUsageFixBase(
|
|||||||
PsiChildRange.singleElement(result)
|
PsiChildRange.singleElement(result)
|
||||||
else
|
else
|
||||||
PsiChildRange(wrapper.addedStatements.first(), result)
|
PsiChildRange(wrapper.addedStatements.first(), result)
|
||||||
commentSaver.restoreComments(resultRange)
|
commentSaver.restore(resultRange)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -8,5 +8,6 @@ fun newFun(p4: Int, p3: Int, p2: Int, p1: Int, p0: Int){}
|
|||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
newFun(/* 4 */ 4, 3, 2, // 2
|
newFun(/* 4 */ 4, 3, 2, // 2
|
||||||
/* 1 */ 1, /* 0 */ 0)
|
/* 1 */ 1,
|
||||||
|
/* 0 */ 0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// "Replace with 'newFun(p1, p2, 0)'" "true"
|
||||||
|
|
||||||
|
interface X {
|
||||||
|
@deprecated("", ReplaceWith("newFun(p1, p2, 0)"))
|
||||||
|
fun oldFun(p1: Int, p2: Int)
|
||||||
|
|
||||||
|
fun newFun(p1: Int, p2: Int, p3: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(x: X) {
|
||||||
|
x.<caret>oldFun(
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// "Replace with 'newFun(p1, p2, 0)'" "true"
|
||||||
|
|
||||||
|
interface X {
|
||||||
|
@deprecated("", ReplaceWith("newFun(p1, p2, 0)"))
|
||||||
|
fun oldFun(p1: Int, p2: Int)
|
||||||
|
|
||||||
|
fun newFun(p1: Int, p2: Int, p3: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(x: X) {
|
||||||
|
x.newFun(1,
|
||||||
|
2,
|
||||||
|
0)
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
// "Replace with 'newFun()'" "true"
|
||||||
|
|
||||||
|
@deprecated("", ReplaceWith("newFun()"))
|
||||||
|
fun Int.oldFun(): Int = this
|
||||||
|
|
||||||
|
fun Int.newFun(): Int = this
|
||||||
|
|
||||||
|
fun foo(list: List<String>): Int {
|
||||||
|
return list
|
||||||
|
.filter { it.isNotEmpty() }
|
||||||
|
.map { it.length() }
|
||||||
|
.first()
|
||||||
|
.<caret>oldFun()
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
// "Replace with 'newFun()'" "true"
|
||||||
|
|
||||||
|
@deprecated("", ReplaceWith("newFun()"))
|
||||||
|
fun Int.oldFun(): Int = this
|
||||||
|
|
||||||
|
fun Int.newFun(): Int = this
|
||||||
|
|
||||||
|
fun foo(list: List<String>): Int {
|
||||||
|
return list
|
||||||
|
.filter { it.isNotEmpty() }
|
||||||
|
.map { it.length() }
|
||||||
|
.first()
|
||||||
|
.<caret>newFun()
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// "Replace with 'newFun(p1, p2, p3)'" "true"
|
||||||
|
|
||||||
|
interface X {
|
||||||
|
@deprecated("", ReplaceWith("newFun(p1, p2, p3)"))
|
||||||
|
fun oldFun(p1: Int, p2: Int, p3: Int)
|
||||||
|
|
||||||
|
fun newFun(p1: Int, p2: Int, p3: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(x: X) {
|
||||||
|
x.<caret>oldFun(1,
|
||||||
|
2,
|
||||||
|
3)
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// "Replace with 'newFun(p1, p2, p3)'" "true"
|
||||||
|
|
||||||
|
interface X {
|
||||||
|
@deprecated("", ReplaceWith("newFun(p1, p2, p3)"))
|
||||||
|
fun oldFun(p1: Int, p2: Int, p3: Int)
|
||||||
|
|
||||||
|
fun newFun(p1: Int, p2: Int, p3: Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(x: X) {
|
||||||
|
x.<caret>newFun(1,
|
||||||
|
2,
|
||||||
|
3)
|
||||||
|
}
|
||||||
@@ -3289,6 +3289,33 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/keepLineBreaks")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class KeepLineBreaks extends AbstractQuickFixTest {
|
||||||
|
@TestMetadata("addArgument.kt")
|
||||||
|
public void testAddArgument() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/keepLineBreaks/addArgument.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInKeepLineBreaks() throws Exception {
|
||||||
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/deprecatedSymbolUsage/keepLineBreaks"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("lineBreakAfterReceiverRuntime.kt")
|
||||||
|
public void testLineBreakAfterReceiverRuntime() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/keepLineBreaks/lineBreakAfterReceiverRuntime.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simple.kt")
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/keepLineBreaks/simple.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/optionalParameters")
|
@TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/optionalParameters")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user