KT-13884 Exception "Invalid root block PSI element" on replacing trivial when-expression to if
#KT-13884 Fixed
This commit is contained in:
@@ -47,28 +47,30 @@ private abstract class ArgumentType<T : Any>(val klass: Class<T>)
|
|||||||
private class PlainTextArgumentType<T : Any>(klass: Class<T>, val toPlainText: (T) -> String) : ArgumentType<T>(klass)
|
private class PlainTextArgumentType<T : Any>(klass: Class<T>, val toPlainText: (T) -> String) : ArgumentType<T>(klass)
|
||||||
|
|
||||||
private abstract class PsiElementPlaceholderArgumentType<T : Any, TPlaceholder : PsiElement>(klass: Class<T>, val placeholderClass: Class<TPlaceholder>) : ArgumentType<T>(klass) {
|
private abstract class PsiElementPlaceholderArgumentType<T : Any, TPlaceholder : PsiElement>(klass: Class<T>, val placeholderClass: Class<TPlaceholder>) : ArgumentType<T>(klass) {
|
||||||
abstract fun replacePlaceholderElement(placeholder: TPlaceholder, argument: T)
|
abstract fun replacePlaceholderElement(placeholder: TPlaceholder, argument: T): PsiChildRange
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PsiElementArgumentType<T : PsiElement>(klass: Class<T>) : PsiElementPlaceholderArgumentType<T, T>(klass, klass) {
|
private class PsiElementArgumentType<T : PsiElement>(klass: Class<T>) : PsiElementPlaceholderArgumentType<T, T>(klass, klass) {
|
||||||
override fun replacePlaceholderElement(placeholder: T, argument: T) {
|
override fun replacePlaceholderElement(placeholder: T, argument: T): PsiChildRange {
|
||||||
// if argument element has generated flag then it has not been formatted yet and we should do this manually
|
// if argument element has generated flag then it has not been formatted yet and we should do this manually
|
||||||
// (because we cleared this flag for the whole tree above and PostprocessReformattingAspect won't format anything)
|
// (because we cleared this flag for the whole tree above and PostprocessReformattingAspect won't format anything)
|
||||||
val reformat = CodeEditUtil.isNodeGenerated(argument.node)
|
val reformat = CodeEditUtil.isNodeGenerated(argument.node)
|
||||||
val result = placeholder.replace(argument)
|
var result = placeholder.replace(argument)
|
||||||
if (reformat) {
|
if (reformat) {
|
||||||
CodeStyleManager.getInstance(result.project).reformat(result, true)
|
result = CodeStyleManager.getInstance(result.project).reformat(result, true)
|
||||||
}
|
}
|
||||||
|
return PsiChildRange.singleElement(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private object PsiChildRangeArgumentType : PsiElementPlaceholderArgumentType<PsiChildRange, KtElement>(PsiChildRange::class.java, KtElement::class.java) {
|
private object PsiChildRangeArgumentType : PsiElementPlaceholderArgumentType<PsiChildRange, KtElement>(PsiChildRange::class.java, KtElement::class.java) {
|
||||||
override fun replacePlaceholderElement(placeholder: KtElement, argument: PsiChildRange) {
|
override fun replacePlaceholderElement(placeholder: KtElement, argument: PsiChildRange): PsiChildRange {
|
||||||
val project = placeholder.project
|
val project = placeholder.project
|
||||||
val codeStyleManager = CodeStyleManager.getInstance(project)
|
val codeStyleManager = CodeStyleManager.getInstance(project)
|
||||||
|
|
||||||
if (argument.isEmpty) {
|
if (argument.isEmpty) {
|
||||||
placeholder.delete()
|
placeholder.delete()
|
||||||
|
return PsiChildRange.EMPTY
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val first = placeholder.parent.addRangeBefore(argument.first!!, argument.last!!, placeholder)
|
val first = placeholder.parent.addRangeBefore(argument.first!!, argument.last!!, placeholder)
|
||||||
@@ -79,6 +81,7 @@ private object PsiChildRangeArgumentType : PsiElementPlaceholderArgumentType<Psi
|
|||||||
if (last != first) {
|
if (last != first) {
|
||||||
codeStyleManager.reformatNewlyAddedElement(last.node.treeParent, last.node)
|
codeStyleManager.reformatNewlyAddedElement(last.node.treeParent, last.node)
|
||||||
}
|
}
|
||||||
|
return PsiChildRange(first, last)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,7 +175,14 @@ fun <TElement : KtElement> createByPattern(pattern: String, vararg args: Any, fa
|
|||||||
if (element is KtFunctionLiteral) {
|
if (element is KtFunctionLiteral) {
|
||||||
element = element.getParent() as KtLambdaExpression
|
element = element.getParent() as KtLambdaExpression
|
||||||
}
|
}
|
||||||
(argumentTypes[n] as PsiElementPlaceholderArgumentType<in Any, in PsiElement>).replacePlaceholderElement(element, args[n])
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val argumentType = argumentTypes[n] as PsiElementPlaceholderArgumentType<in Any, in PsiElement>
|
||||||
|
val range = argumentType.replacePlaceholderElement(element, args[n])
|
||||||
|
|
||||||
|
if (element == resultElement) {
|
||||||
|
assert(range.first == range.last)
|
||||||
|
resultElement = range.first as TElement
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
codeStyleManager.adjustLineIndent(resultElement.containingFile, resultElement.textRange)
|
codeStyleManager.adjustLineIndent(resultElement.containingFile, resultElement.textRange)
|
||||||
|
|||||||
+1
@@ -33,6 +33,7 @@ class WhenToIfIntention : SelfTargetingRangeIntention<KtWhenExpression>(KtWhenEx
|
|||||||
if (entries.isEmpty()) return null
|
if (entries.isEmpty()) return null
|
||||||
val lastEntry = entries.last()
|
val lastEntry = entries.last()
|
||||||
if (entries.any { it != lastEntry && it.isElse }) return null
|
if (entries.any { it != lastEntry && it.isElse }) return null
|
||||||
|
if (entries.all { it.isElse }) return null // 'when' with only 'else' branch is not supported
|
||||||
return element.whenKeyword.textRange
|
return element.whenKeyword.textRange
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
//IS_APPLICABLE: false
|
||||||
|
fun foo() {
|
||||||
|
<caret>when {
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1771,6 +1771,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt13884.kt")
|
||||||
|
public void testKt13884() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/branched/ifWhen/whenToIf/kt13884.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("whenWithDotQualifiedExpression.kt")
|
@TestMetadata("whenWithDotQualifiedExpression.kt")
|
||||||
public void testWhenWithDotQualifiedExpression() throws Exception {
|
public void testWhenWithDotQualifiedExpression() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/branched/ifWhen/whenToIf/whenWithDotQualifiedExpression.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/branched/ifWhen/whenToIf/whenWithDotQualifiedExpression.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user