From 60b4ce2c368b8e3aba195e9a9f32fad7fe168a4e Mon Sep 17 00:00:00 2001 From: Vladimir Dolzhenko Date: Mon, 19 Feb 2024 12:16:09 +0000 Subject: [PATCH] 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 --- .../jetbrains/kotlin/psi/createByPattern.kt | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/compiler/psi/src/org/jetbrains/kotlin/psi/createByPattern.kt b/compiler/psi/src/org/jetbrains/kotlin/psi/createByPattern.kt index 4cc15eb0446..0c5f5e0641d 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/psi/createByPattern.kt +++ b/compiler/psi/src/org/jetbrains/kotlin/psi/createByPattern.kt @@ -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 createByPattern( val pointerManager = SmartPointerManager.getInstance(project) - val pointers = HashMap, Int>() + val pointers = LinkedHashMap, Int>() PlaceholdersLoop@ for ((n, placeholders) in allPlaceholders) { @@ -182,7 +182,7 @@ fun 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 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 - 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 + val range = argumentType.replacePlaceholderElement(element, args[n], reformat) + + if (element == resultElement) { + assert(range.first == range.last) + resultElement = range.first as KtElement + } } }