Fix flakiness of createByPattern results

Fix the order of pointers and place logical operators first

#KTIJ-28165 Fixed


Merge-request: KT-MR-14447
Merged-by: Vladimir Dolzhenko <Vladimir.Dolzhenko@jetbrains.com>
This commit is contained in:
Vladimir Dolzhenko
2024-02-19 12:16:09 +00:00
committed by Space Team
parent 302e38dd18
commit 60b4ce2c36
@@ -24,13 +24,13 @@ import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.psi.impl.source.codeStyle.CodeEditUtil
import org.jetbrains.annotations.NonNls
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.psiUtil.PsiChildRange
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.renderer.render
import java.util.*
fun KtPsiFactory.createExpressionByPattern(@NonNls pattern: String, @NonNls vararg args: Any, reformat: Boolean = true): KtExpression =
createByPattern(pattern, *args, reformat = reformat) { createExpression(it) }
@@ -151,7 +151,7 @@ fun <TElement : KtElement> createByPattern(
val pointerManager = SmartPointerManager.getInstance(project)
val pointers = HashMap<SmartPsiElementPointer<PsiElement>, Int>()
val pointers = LinkedHashMap<SmartPsiElementPointer<PsiElement>, Int>()
PlaceholdersLoop@
for ((n, placeholders) in allPlaceholders) {
@@ -182,7 +182,7 @@ fun <TElement : KtElement> createByPattern(
if (CREATE_BY_PATTERN_MAY_NOT_REFORMAT) {
throw java.lang.IllegalArgumentException("Reformatting is not allowed in the current context; please change the invocation to use reformat=false")
}
val stringPlaceholderRanges = allPlaceholders
val stringPlaceholderRanges = allPlaceholders.asSequence()
.filter { args[it.key] is String }
.flatMap { it.value }
.map { it.range }
@@ -205,18 +205,30 @@ fun <TElement : KtElement> createByPattern(
// do not reformat the whole expression in PostprocessReformattingAspect
CodeEditUtil.setNodeGeneratedRecursively(resultElement.node, false)
}
for ((pointer, n) in pointers) {
var element = pointer.element!!
if (element is KtFunctionLiteral) {
element = element.parent as KtLambdaExpression
}
@Suppress("UNCHECKED_CAST")
val argumentType = argumentTypes[n] as PsiElementPlaceholderArgumentType<in Any, in PsiElement>
val range = argumentType.replacePlaceholderElement(element, args[n], reformat)
if (element == resultElement) {
assert(range.first == range.last)
resultElement = range.first as KtElement
// it is needed to place logical operators first for expressions like `xyz xyz xyz` to become `xyz && xyz`
// otherwise if when we place an expression we have to wrap it with extra parenthesis => it becomes `(a != null) xyz xyz`
val (left, right) = pointers.entries.partition {
val n = it.value
val elementType = (args[n] as? KtOperationReferenceExpression)?.getReferencedNameElementType()
elementType == KtTokens.ANDAND || elementType == KtTokens.OROR
}
for (partition in listOf(left, right)) {
for ((pointer, n) in partition) {
var element = pointer.element!!
if (element is KtFunctionLiteral) {
element = element.parent as KtLambdaExpression
}
@Suppress("UNCHECKED_CAST")
val argumentType = argumentTypes[n] as PsiElementPlaceholderArgumentType<in Any, in PsiElement>
val range = argumentType.replacePlaceholderElement(element, args[n], reformat)
if (element == resultElement) {
assert(range.first == range.last)
resultElement = range.first as KtElement
}
}
}