From 40184f053efa656e5091f6aeb8c29e790a2580bd Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 13 Dec 2017 19:00:40 +0100 Subject: [PATCH] Don't invoke formatter while checking availability of intentions #KT-21632 Fixed --- .../jetbrains/kotlin/psi/createByPattern.kt | 11 ++++- .../idea/intentions/SelfTargetingIntention.kt | 14 +++++- .../intentions/AddForLoopIndicesIntention.kt | 9 ++-- .../RemoveExplicitSuperQualifierIntention.kt | 11 +++-- .../UsePropertyAccessSyntaxIntention.kt | 15 +++--- .../jetbrains/kotlin/idea/intentions/Utils.kt | 16 ++++--- .../LoopToCallChainIntention.kt | 4 +- .../loopToCallChain/UseWithIndexIntention.kt | 6 +-- .../loopToCallChain/baseTransformations.kt | 2 +- .../intentions/loopToCallChain/interfaces.kt | 8 ++-- .../loopToCallChain/matchAndConvert.kt | 33 +++++++------ .../result/AddToCollectionTransformation.kt | 18 +++++--- .../result/CountTransformation.kt | 12 +++-- .../result/FindTransformationMatcher.kt | 46 +++++++++++-------- .../result/ForEachTransformation.kt | 2 +- .../result/MaxOrMinTransformation.kt | 5 +- .../result/SumTransformation.kt | 9 ++-- .../loopToCallChain/sequence/Condition.kt | 18 ++++---- .../sequence/FilterTransformation.kt | 45 +++++++++++------- .../sequence/FlatMapTransformation.kt | 18 +++++--- .../sequence/MapTransformation.kt | 2 +- .../idea/intentions/loopToCallChain/utils.kt | 30 +++++++----- .../kotlin/idea/j2k/J2kPostProcessings.kt | 2 +- 23 files changed, 210 insertions(+), 126 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/createByPattern.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/createByPattern.kt index 206190d43cf..6fcd77a049c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/createByPattern.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/createByPattern.kt @@ -22,6 +22,7 @@ import com.intellij.psi.SmartPointerManager import com.intellij.psi.SmartPsiElementPointer import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.psi.impl.source.codeStyle.CodeEditUtil +import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.psiUtil.PsiChildRange import org.jetbrains.kotlin.psi.psiUtil.endOffset @@ -94,6 +95,9 @@ private val SUPPORTED_ARGUMENT_TYPES = listOf( PsiChildRangeArgumentType ) +@TestOnly +var CREATEBYPATTERN_MAY_NOT_REFORMAT = false + fun createByPattern(pattern: String, vararg args: Any, reformat: Boolean = true, factory: (String) -> TElement): TElement { val argumentTypes = args.map { arg -> SUPPORTED_ARGUMENT_TYPES.firstOrNull { it.klass.isInstance(arg) } @@ -147,6 +151,9 @@ fun createByPattern(pattern: String, vararg args: Any, re val codeStyleManager = CodeStyleManager.getInstance(project) if (reformat) { + if (CREATEBYPATTERN_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 .filter { args[it.key] is String } .flatMap { it.value } @@ -325,8 +332,8 @@ class BuilderByPattern { } } -fun KtPsiFactory.buildExpression(build: BuilderByPattern.() -> Unit): KtExpression { - return buildByPattern({ pattern, args -> this.createExpressionByPattern(pattern, *args) }, build) +fun KtPsiFactory.buildExpression(reformat: Boolean = true, build: BuilderByPattern.() -> Unit): KtExpression { + return buildByPattern({ pattern, args -> this.createExpressionByPattern(pattern, *args, reformat = reformat) }, build) } fun KtPsiFactory.buildValueArgumentList(build: BuilderByPattern.() -> Unit): KtValueArgumentList { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/intentions/SelfTargetingIntention.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/intentions/SelfTargetingIntention.kt index 0fbaf87bcd3..904f0bdd4f7 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/intentions/SelfTargetingIntention.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/intentions/SelfTargetingIntention.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.intentions import com.intellij.codeInsight.FileModificationService import com.intellij.codeInsight.intention.IntentionAction import com.intellij.codeInspection.IntentionWrapper +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.openapi.util.TextRange @@ -27,6 +28,7 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection +import org.jetbrains.kotlin.psi.CREATEBYPATTERN_MAY_NOT_REFORMAT import org.jetbrains.kotlin.psi.KtBlockExpression import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.psiUtil.containsInside @@ -82,7 +84,17 @@ abstract class SelfTargetingIntention( protected open fun allowCaretInsideElement(element: PsiElement): Boolean = element !is KtBlockExpression - final override fun isAvailable(project: Project, editor: Editor, file: PsiFile) = getTarget(editor, file) != null + final override fun isAvailable(project: Project, editor: Editor, file: PsiFile): Boolean { + if (ApplicationManager.getApplication().isUnitTestMode) { + CREATEBYPATTERN_MAY_NOT_REFORMAT = true + } + try { + return getTarget(editor, file) != null + } + finally { + CREATEBYPATTERN_MAY_NOT_REFORMAT = false + } + } var inspection: IntentionBasedInspection? = null internal set diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/AddForLoopIndicesIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/AddForLoopIndicesIntention.kt index b7b35d1de48..9481f8136a3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/AddForLoopIndicesIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/AddForLoopIndicesIntention.kt @@ -44,7 +44,7 @@ class AddForLoopIndicesIntention : SelfTargetingRangeIntention( val resolvedCall = loopRange.getResolvedCall(bindingContext) if (resolvedCall?.resultingDescriptor?.fqNameUnsafe?.asString() in WITH_INDEX_FQ_NAMES) return null // already withIndex() call - val potentialExpression = createWithIndexExpression(loopRange) + val potentialExpression = createWithIndexExpression(loopRange, reformat = false) val newBindingContext = potentialExpression.analyzeAsReplacement(loopRange, bindingContext) val newResolvedCall = potentialExpression.getResolvedCall(newBindingContext) ?: return null @@ -59,7 +59,7 @@ class AddForLoopIndicesIntention : SelfTargetingRangeIntention( val loopParameter = element.loopParameter!! val psiFactory = KtPsiFactory(element) - loopRange.replace(createWithIndexExpression(loopRange)) + loopRange.replace(createWithIndexExpression(loopRange, reformat = true)) var multiParameter = (psiFactory.createExpressionByPattern("for((index, $0) in x){}", loopParameter.text) as KtForExpression).destructuringDeclaration!! @@ -97,7 +97,8 @@ class AddForLoopIndicesIntention : SelfTargetingRangeIntention( templateBuilder.run(editor, true) } - private fun createWithIndexExpression(originalExpression: KtExpression): KtExpression { - return KtPsiFactory(originalExpression).createExpressionByPattern("$0.$WITH_INDEX_NAME()", originalExpression) + private fun createWithIndexExpression(originalExpression: KtExpression, reformat: Boolean): KtExpression { + return KtPsiFactory(originalExpression).createExpressionByPattern("$0.$WITH_INDEX_NAME()", originalExpression, + reformat = reformat) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveExplicitSuperQualifierIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveExplicitSuperQualifierIntention.kt index 29462dc312d..9a39789220a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveExplicitSuperQualifierIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveExplicitSuperQualifierIntention.kt @@ -51,7 +51,10 @@ class RemoveExplicitSuperQualifierIntention : SelfTargetingRangeIntention replaceWithPropertyGet(element, propertyName) - 1 -> replaceWithPropertySet(element, propertyName) + 1 -> replaceWithPropertySet(element, propertyName, reformat) else -> error("More than one argument in call to accessor") } } @@ -168,7 +168,7 @@ class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention if (isSetUsage && property.type != function.valueParameters.single().type) { val qualifiedExpressionCopy = qualifiedExpression.copied() val callExpressionCopy = ((qualifiedExpressionCopy as? KtQualifiedExpression)?.selectorExpression ?: qualifiedExpressionCopy) as KtCallExpression - val newExpression = applyTo(callExpressionCopy, property.name) + val newExpression = applyTo(callExpressionCopy, property.name, reformat = false) val bindingTrace = DelegatingBindingTrace(bindingContext, "Temporary trace") val newBindingContext = newExpression.analyzeInContext( resolutionScope, @@ -195,7 +195,7 @@ class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention ): Boolean { val project = resolvedCall.call.callElement.project val newCall = object : DelegatingCall(resolvedCall.call) { - private val newCallee = KtPsiFactory(project).createExpressionByPattern("$0", property.name) + private val newCallee = KtPsiFactory(project).createExpressionByPattern("$0", property.name, reformat = false) override fun getCalleeExpression() = newCallee override fun getValueArgumentList(): KtValueArgumentList? = null @@ -227,7 +227,7 @@ class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention return callExpression.replaced(newExpression) } - private fun replaceWithPropertySet(callExpression: KtCallExpression, propertyName: Name): KtExpression { + private fun replaceWithPropertySet(callExpression: KtCallExpression, propertyName: Name, reformat: Boolean): KtExpression { val call = callExpression.getQualifiedExpressionForSelector() ?: callExpression val callParent = call.parent var callToConvert = callExpression @@ -251,7 +251,8 @@ class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention pattern, qualifiedExpression.receiverExpression, propertyName, - argument.getArgumentExpression()!! + argument.getArgumentExpression()!!, + reformat = reformat ) return qualifiedExpression.replaced(newExpression) } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt index c33d0a66ad2..7f1d542a2f2 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt @@ -118,10 +118,10 @@ fun KtQualifiedExpression.isReceiverExpressionWithValue(): Boolean { return analyze().getType(receiver) != null } -fun KtExpression.negate(): KtExpression { - val specialNegation = specialNegation() +fun KtExpression.negate(reformat: Boolean = true): KtExpression { + val specialNegation = specialNegation(reformat) if (specialNegation != null) return specialNegation - return KtPsiFactory(this).createExpressionByPattern("!$0", this) + return KtPsiFactory(this).createExpressionByPattern("!$0", this, reformat = reformat) } fun KtExpression.resultingWhens(): List = when (this) { @@ -142,7 +142,7 @@ fun KtExpression?.hasResultingIfWithoutElse(): Boolean = when (this) { else -> false } -private fun KtExpression.specialNegation(): KtExpression? { +private fun KtExpression.specialNegation(reformat: Boolean): KtExpression? { val factory = KtPsiFactory(this) when (this) { is KtPrefixExpression -> { @@ -163,14 +163,18 @@ private fun KtExpression.specialNegation(): KtExpression? { if (operator !in NEGATABLE_OPERATORS) return null val left = left ?: return null val right = right ?: return null - return factory.createExpressionByPattern("$0 $1 $2", left, getNegatedOperatorText(operator), right) + return factory.createExpressionByPattern( + "$0 $1 $2", left, getNegatedOperatorText(operator), right, + reformat = reformat + ) } is KtIsExpression -> { return factory.createExpressionByPattern("$0 $1 $2", leftHandSide, if (isNegated) "is" else "!is", - typeReference ?: return null) + typeReference ?: return null, + reformat = reformat) } is KtConstantExpression -> { diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/LoopToCallChainIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/LoopToCallChainIntention.kt index 6c62ec66b5e..e00838e8ccd 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/LoopToCallChainIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/LoopToCallChainIntention.kt @@ -41,7 +41,7 @@ abstract class AbstractLoopToCallChainIntention(private val lazy: Boolean, text: text ) { override fun applicabilityRange(element: KtForExpression): TextRange? { - val match = match(element, lazy) + val match = match(element, lazy, false) text = if (match != null) "Replace with '${match.transformationMatch.buildPresentation()}'" else defaultText return if (match != null) element.forKeyword.textRange else null } @@ -68,7 +68,7 @@ abstract class AbstractLoopToCallChainIntention(private val lazy: Boolean, text: } override fun applyTo(element: KtForExpression, editor: Editor?) { - val match = match(element, lazy)!! + val match = match(element, lazy, true)!! val result = convertLoop(element, match) val offset = when (result) { diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/UseWithIndexIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/UseWithIndexIntention.kt index d515a8f57c2..b1a9c9e91a4 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/UseWithIndexIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/UseWithIndexIntention.kt @@ -32,11 +32,11 @@ class UseWithIndexIntention : SelfTargetingRangeIntention( "Use withIndex() instead of manual index increment" ) { override fun applicabilityRange(element: KtForExpression): TextRange? { - return if (matchIndexToIntroduce(element) != null) element.forKeyword.textRange else null + return if (matchIndexToIntroduce(element, reformat = false) != null) element.forKeyword.textRange else null } override fun applyTo(element: KtForExpression, editor: Editor?) { - val (indexVariable, initializationStatement, incrementExpression) = matchIndexToIntroduce(element)!! + val (indexVariable, initializationStatement, incrementExpression) = matchIndexToIntroduce(element, reformat = true)!! val factory = KtPsiFactory(element) val loopRange = element.loopRange!! @@ -53,7 +53,7 @@ class UseWithIndexIntention : SelfTargetingRangeIntention( incrementExpression.delete() } else { - removePlusPlus(incrementExpression) + removePlusPlus(incrementExpression, true) } } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/baseTransformations.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/baseTransformations.kt index 6aed059b9fb..7d94b0321a8 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/baseTransformations.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/baseTransformations.kt @@ -76,7 +76,7 @@ abstract class AssignToVariableResultTransformation( copy } else { - psiFactory.createExpressionByPattern("$0 = $1", initialization.variable.nameAsSafeName, resultCallChain) + psiFactory.createExpressionByPattern("$0 = $1", initialization.variable.nameAsSafeName, resultCallChain, reformat = false) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/interfaces.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/interfaces.kt index 01f7e8d5ed3..97604d34fc9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/interfaces.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/interfaces.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.psi.psiUtil.siblings */ interface ChainedCallGenerator { val receiver: KtExpression + val reformat: Boolean /** * @param pattern pattern string for generating the part of the call to the right from the dot @@ -54,7 +55,7 @@ interface Transformation { presentation } - fun mergeWithPrevious(previousTransformation: SequenceTransformation): Transformation? + fun mergeWithPrevious(previousTransformation: SequenceTransformation, reformat: Boolean): Transformation? fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression @@ -66,7 +67,7 @@ interface Transformation { * Represents a transformation of input sequence into another sequence */ interface SequenceTransformation : Transformation { - override fun mergeWithPrevious(previousTransformation: SequenceTransformation): SequenceTransformation? = null + override fun mergeWithPrevious(previousTransformation: SequenceTransformation, reformat: Boolean): SequenceTransformation? = null val affectsIndex: Boolean } @@ -75,7 +76,7 @@ interface SequenceTransformation : Transformation { * Represents a final transformation of sequence which produces the result of the whole loop (for example, assigning a found value into a variable). */ interface ResultTransformation : Transformation { - override fun mergeWithPrevious(previousTransformation: SequenceTransformation): ResultTransformation? = null + override fun mergeWithPrevious(previousTransformation: SequenceTransformation, reformat: Boolean): ResultTransformation? = null val commentSavingRange: PsiChildRange @@ -105,6 +106,7 @@ data class MatchingState( val indexVariable: KtCallableDeclaration?, val lazySequence: Boolean, val pseudocodeProvider: () -> Pseudocode, + val reformat: Boolean, val initializationStatementsToDelete: Collection = emptyList(), val previousTransformations: MutableList = arrayListOf(), val incrementExpressions: Collection = emptyList() diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/matchAndConvert.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/matchAndConvert.kt index 4d3e6dae12d..87c878a0fca 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/matchAndConvert.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/matchAndConvert.kt @@ -59,10 +59,10 @@ data class MatchResult( ) //TODO: loop which is already over Sequence -fun match(loop: KtForExpression, useLazySequence: Boolean): MatchResult? { +fun match(loop: KtForExpression, useLazySequence: Boolean, reformat: Boolean): MatchResult? { val (inputVariable, indexVariable, sequenceExpression) = extractLoopData(loop) ?: return null - var state = createInitialMatchingState(loop, inputVariable, indexVariable, useLazySequence) ?: return null + var state = createInitialMatchingState(loop, inputVariable, indexVariable, useLazySequence, reformat) ?: return null // used just as optimization to avoid unnecessary checks val loopContainsEmbeddedBreakOrContinue = loop.containsEmbeddedBreakOrContinue() @@ -123,7 +123,7 @@ fun match(loop: KtForExpression, useLazySequence: Boolean): MatchResult? { state.previousTransformations += match.sequenceTransformations var result = TransformationMatch.Result(match.resultTransformation, state.previousTransformations) - result = mergeTransformations(result) + result = mergeTransformations(result, reformat) if (useLazySequence) { val sequenceTransformations = result.sequenceTransformations @@ -157,7 +157,7 @@ fun convertLoop(loop: KtForExpression, matchResult: MatchResult): KtExpression { matchResult.initializationStatementsToDelete.forEach { commentSavingRangeHolder.add(it) } - val callChain = matchResult.generateCallChain(loop) + val callChain = matchResult.generateCallChain(loop, true) commentSavingRangeHolder.remove(loop.unwrapIfLabeled()) // loop will be deleted in all cases val result = resultTransformation.convertLoop(callChain, commentSavingRangeHolder) @@ -204,7 +204,8 @@ private fun createInitialMatchingState( loop: KtForExpression, inputVariable: KtCallableDeclaration, indexVariable: KtCallableDeclaration?, - useLazySequence: Boolean + useLazySequence: Boolean, + reformat: Boolean ): MatchingState? { val pseudocodeProvider: () -> Pseudocode = object : () -> Pseudocode { @@ -224,7 +225,8 @@ private fun createInitialMatchingState( inputVariable = inputVariable, indexVariable = indexVariable, lazySequence = useLazySequence, - pseudocodeProvider = pseudocodeProvider + pseudocodeProvider = pseudocodeProvider, + reformat = reformat ) } @@ -272,7 +274,7 @@ private fun checkSmartCastsPreserved(loop: KtForExpression, matchResult: MatchRe if (smartCastCount == 0) return true // optimization - val callChain = matchResult.generateCallChain(loop) + val callChain = matchResult.generateCallChain(loop, false) val newBindingContext = callChain.analyzeAsReplacement(loop, bindingContext) @@ -312,12 +314,12 @@ private fun checkSmartCastsPreserved(loop: KtForExpression, matchResult: MatchRe } } -private fun MatchResult.generateCallChain(loop: KtForExpression): KtExpression { +private fun MatchResult.generateCallChain(loop: KtForExpression, reformat: Boolean): KtExpression { var sequenceTransformations = transformationMatch.sequenceTransformations var resultTransformation = transformationMatch.resultTransformation while(true) { val last = sequenceTransformations.lastOrNull() ?: break - resultTransformation = resultTransformation.mergeWithPrevious(last) ?: break + resultTransformation = resultTransformation.mergeWithPrevious(last, reformat) ?: break sequenceTransformations = sequenceTransformations.dropLast(1) } @@ -331,10 +333,13 @@ private fun MatchResult.generateCallChain(loop: KtForExpression): KtExpression { override val receiver: KtExpression get() = callChain + override val reformat: Boolean + get() = reformat + override fun generate(pattern: String, vararg args: Any, receiver: KtExpression, safeCall: Boolean): KtExpression { val dot = if (safeCall) "?." else "." val newPattern = "$" + args.size + lineBreak + dot + pattern - return psiFactory.createExpressionByPattern(newPattern, *args, receiver) + return psiFactory.createExpressionByPattern(newPattern, *args, receiver, reformat = reformat) } } @@ -346,7 +351,7 @@ private fun MatchResult.generateCallChain(loop: KtForExpression): KtExpression { return callChain } -private fun mergeTransformations(match: TransformationMatch.Result): TransformationMatch.Result { +private fun mergeTransformations(match: TransformationMatch.Result, reformat: Boolean): TransformationMatch.Result { val transformations = (match.sequenceTransformations + match.resultTransformation).toMutableList() var anyChange: Boolean @@ -355,7 +360,7 @@ private fun mergeTransformations(match: TransformationMatch.Result): Transformat for (index in 0..transformations.lastIndex - 1) { val transformation = transformations[index] as SequenceTransformation val next = transformations[index + 1] - val merged = next.mergeWithPrevious(transformation) ?: continue + val merged = next.mergeWithPrevious(transformation, reformat) ?: continue transformations[index] = merged transformations.removeAt(index + 1) anyChange = true @@ -373,11 +378,11 @@ data class IntroduceIndexData( val incrementExpression: KtUnaryExpression ) -fun matchIndexToIntroduce(loop: KtForExpression): IntroduceIndexData? { +fun matchIndexToIntroduce(loop: KtForExpression, reformat: Boolean): IntroduceIndexData? { val (inputVariable, indexVariable) = extractLoopData(loop) ?: return null if (indexVariable != null) return null // loop is already with "withIndex" - val state = createInitialMatchingState(loop, inputVariable, indexVariable, useLazySequence = false)?.unwrapBlock() ?: return null + val state = createInitialMatchingState(loop, inputVariable, indexVariable, useLazySequence = false, reformat = reformat)?.unwrapBlock() ?: return null val match = IntroduceIndexMatcher.match(state) ?: return null assert(match.sequenceTransformations.isEmpty()) diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/AddToCollectionTransformation.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/AddToCollectionTransformation.kt index a2849e33bd4..d9860709e88 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/AddToCollectionTransformation.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/AddToCollectionTransformation.kt @@ -34,7 +34,7 @@ class AddToCollectionTransformation( private val targetCollection: KtExpression ) : ReplaceLoopResultTransformation(loop) { - override fun mergeWithPrevious(previousTransformation: SequenceTransformation): ResultTransformation? { + override fun mergeWithPrevious(previousTransformation: SequenceTransformation, reformat: Boolean): ResultTransformation? { return when (previousTransformation) { is FilterTransformation -> { FilterToTransformation.create( @@ -72,7 +72,10 @@ class AddToCollectionTransformation( get() = 0 override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression { - return KtPsiFactory(loop).createExpressionByPattern("$0 += $1", targetCollection, chainedCallGenerator.receiver) + return KtPsiFactory(loop).createExpressionByPattern( + "$0 += $1", targetCollection, chainedCallGenerator.receiver, + reformat = chainedCallGenerator.reformat + ) } /** @@ -219,10 +222,11 @@ class FilterToTransformation private constructor( get() = "$functionName(){}" override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression { + val reformat = chainedCallGenerator.reformat val lambda = if (indexVariable != null) - generateLambda(inputVariable, indexVariable, effectiveCondition.asExpression()) + generateLambda(inputVariable, indexVariable, effectiveCondition.asExpression(reformat), reformat) else - generateLambda(inputVariable, if (isFilterNot) effectiveCondition.asNegatedExpression() else effectiveCondition.asExpression()) + generateLambda(inputVariable, if (isFilterNot) effectiveCondition.asNegatedExpression(reformat) else effectiveCondition.asExpression(reformat), reformat) return chainedCallGenerator.generate("$functionName($0) $1:'{}'", targetCollection, lambda) } @@ -294,7 +298,7 @@ class MapToTransformation private constructor( get() = "$functionName(){}" override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression { - val lambda = generateLambda(inputVariable, indexVariable, mapping) + val lambda = generateLambda(inputVariable, indexVariable, mapping, chainedCallGenerator.reformat) return chainedCallGenerator.generate("$functionName($0) $1:'{}'", targetCollection, lambda) } @@ -330,7 +334,7 @@ class FlatMapToTransformation private constructor( get() = "flatMapTo(){}" override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression { - val lambda = generateLambda(inputVariable, transform) + val lambda = generateLambda(inputVariable, transform, chainedCallGenerator.reformat) return chainedCallGenerator.generate("flatMapTo($0) $1:'{}'", targetCollection, lambda) } @@ -367,7 +371,7 @@ class AssignToListTransformation( override val presentation: String get() = "toList()" - override fun mergeWithPrevious(previousTransformation: SequenceTransformation): ResultTransformation? { + override fun mergeWithPrevious(previousTransformation: SequenceTransformation, reformat: Boolean): ResultTransformation? { if (lazySequence) return null // toList() is necessary if the result is Sequence //TODO: can be any SequenceTransformation's that return not List? return AssignSequenceResultTransformation(previousTransformation, initialization) diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/CountTransformation.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/CountTransformation.kt index f5c77413172..64e68af0967 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/CountTransformation.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/CountTransformation.kt @@ -30,13 +30,14 @@ class CountTransformation( private val filter: KtExpression? ) : AssignToVariableResultTransformation(loop, initialization) { - override fun mergeWithPrevious(previousTransformation: SequenceTransformation): ResultTransformation? { + override fun mergeWithPrevious(previousTransformation: SequenceTransformation, reformat: Boolean): ResultTransformation? { if (previousTransformation !is FilterTransformationBase) return null if (previousTransformation.indexVariable != null) return null val newFilter = if (filter == null) - previousTransformation.effectiveCondition.asExpression() + previousTransformation.effectiveCondition.asExpression(reformat) else - KtPsiFactory(filter).createExpressionByPattern("$0 && $1", previousTransformation.effectiveCondition.asExpression(), filter) + KtPsiFactory(filter).createExpressionByPattern("$0 && $1", previousTransformation.effectiveCondition.asExpression(reformat), filter, + reformat = reformat) return CountTransformation(loop, previousTransformation.inputVariable, initialization, newFilter) } @@ -44,8 +45,9 @@ class CountTransformation( get() = "count" + (if (filter != null) "{}" else "()") override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression { + val reformat = chainedCallGenerator.reformat val call = if (filter != null) { - val lambda = generateLambda(inputVariable, filter) + val lambda = generateLambda(inputVariable, filter, reformat) chainedCallGenerator.generate("count $0:'{}'", lambda) } else { @@ -56,7 +58,7 @@ class CountTransformation( call } else { - KtPsiFactory(call).createExpressionByPattern("$0 + $1", initialization.initializer, call) + KtPsiFactory(call).createExpressionByPattern("$0 + $1", initialization.initializer, call, reformat = reformat) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/FindTransformationMatcher.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/FindTransformationMatcher.kt index 873c6c2d50a..96f9f0fb5a8 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/FindTransformationMatcher.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/FindTransformationMatcher.kt @@ -91,7 +91,8 @@ object FindTransformationMatcher : TransformationMatcher { val generator = buildFindOperationGenerator(state.outerLoop, state.inputVariable, state.indexVariable, filterTransformation, valueIfFound = right, valueIfNotFound = initialization.initializer, - findFirst = findFirst) + findFirst = findFirst, + reformat = state.reformat) ?: return null val transformation = FindAndAssignTransformation(state.outerLoop, generator, initialization) @@ -110,7 +111,8 @@ object FindTransformationMatcher : TransformationMatcher { filterTransformation, valueIfFound = returnValueInLoop, valueIfNotFound = returnValueAfterLoop, - findFirst = true) + findFirst = true, + reformat = state.reformat) ?: return null val transformation = FindAndReturnTransformation(state.outerLoop, generator, returnAfterLoop) @@ -136,7 +138,7 @@ object FindTransformationMatcher : TransformationMatcher { } override fun generateExpressionToReplaceLoopAndCheckErrors(resultCallChain: KtExpression): KtExpression { - return KtPsiFactory(resultCallChain).createExpressionByPattern("return $0", resultCallChain) + return KtPsiFactory(resultCallChain).createExpressionByPattern("return $0", resultCallChain, reformat = false) } override fun convertLoop(resultCallChain: KtExpression, commentSavingRangeHolder: CommentSavingRangeHolder): KtExpression { @@ -203,7 +205,7 @@ object FindTransformationMatcher : TransformationMatcher { } } else { - val lambda = generateLambda(inputVariable, filter) + val lambda = generateLambda(inputVariable, filter, chainedCallGenerator.reformat) if (argument != null) { chainedCallGenerator.generate("$stdlibFunName($0) $1:'{}'", argument, lambda) } @@ -220,7 +222,8 @@ object FindTransformationMatcher : TransformationMatcher { filterTransformation: FilterTransformationBase?, valueIfFound: KtExpression, valueIfNotFound: KtExpression, - findFirst: Boolean + findFirst: Boolean, + reformat: Boolean ): FindOperationGenerator? { assert(valueIfFound.isPhysical) assert(valueIfNotFound.isPhysical) @@ -233,7 +236,7 @@ object FindTransformationMatcher : TransformationMatcher { //TODO: what if value when not found is not "-1"? if (valueIfFound.isVariableReference(indexVariable) && valueIfNotFound.text == "-1") { - val filterExpression = filterCondition!!.asExpression() + val filterExpression = filterCondition!!.asExpression(reformat) val containsArgument = filterExpression.isFilterForContainsOperation(inputVariable, loop) return if (containsArgument != null) { val functionName = if (findFirst) "indexOf" else "lastIndexOf" @@ -260,7 +263,10 @@ object FindTransformationMatcher : TransformationMatcher { return object : FindOperationGenerator(this) { override fun generate(chainedCallGenerator: ChainedCallGenerator): KtExpression { val generated = this@useElvisOperatorIfNeeded.generate(chainedCallGenerator) - return KtPsiFactory(generated).createExpressionByPattern("$0\n ?: $1", generated, valueIfNotFound) + return KtPsiFactory(generated).createExpressionByPattern( + "$0\n ?: $1", generated, valueIfNotFound, + reformat = chainedCallGenerator.reformat + ) } } } @@ -268,16 +274,16 @@ object FindTransformationMatcher : TransformationMatcher { when { valueIfFound.isVariableReference(inputVariable) -> { val functionName = if (findFirst) "firstOrNull" else "lastOrNull" - val generator = SimpleGenerator(functionName, inputVariable, filterCondition?.asExpression()) + val generator = SimpleGenerator(functionName, inputVariable, filterCondition?.asExpression(reformat)) return generator.useElvisOperatorIfNeeded() } valueIfFound.isTrueConstant() && valueIfNotFound.isFalseConstant() -> { - return buildFoundFlagGenerator(loop, inputVariable, filterCondition, negated = false) + return buildFoundFlagGenerator(loop, inputVariable, filterCondition, negated = false, reformat = reformat) } valueIfFound.isFalseConstant() && valueIfNotFound.isTrueConstant() -> { - return buildFoundFlagGenerator(loop, inputVariable, filterCondition, negated = true) + return buildFoundFlagGenerator(loop, inputVariable, filterCondition, negated = true, reformat = reformat) } inputVariable.hasUsages(valueIfFound) -> { @@ -291,7 +297,7 @@ object FindTransformationMatcher : TransformationMatcher { if (receiver.isVariableReference(inputVariable) && selector != null && !inputVariable.hasUsages(selector)) { return object: FindOperationGenerator("firstOrNull", filterCondition != null, chainCallCount = 2) { override fun generate(chainedCallGenerator: ChainedCallGenerator): KtExpression { - val findFirstCall = generateChainedCall(functionName, chainedCallGenerator, inputVariable, filterCondition?.asExpression()) + val findFirstCall = generateChainedCall(functionName, chainedCallGenerator, inputVariable, filterCondition?.asExpression(reformat)) return chainedCallGenerator.generate("$0", selector, receiver = findFirstCall, safeCall = true) } }.useElvisOperatorIfNeeded() @@ -303,19 +309,22 @@ object FindTransformationMatcher : TransformationMatcher { return object : FindOperationGenerator("firstOrNull", filterCondition != null, chainCallCount = 2 /* also includes "let" */) { override fun generate(chainedCallGenerator: ChainedCallGenerator): KtExpression { - val findFirstCall = generateChainedCall(functionName, chainedCallGenerator, inputVariable, filterCondition?.asExpression()) - val letBody = generateLambda(inputVariable, valueIfFound) + val findFirstCall = generateChainedCall(functionName, chainedCallGenerator, inputVariable, filterCondition?.asExpression(reformat)) + val letBody = generateLambda(inputVariable, valueIfFound, chainedCallGenerator.reformat) return chainedCallGenerator.generate("let $0:'{}'", letBody, receiver = findFirstCall, safeCall = true) } }.useElvisOperatorIfNeeded() } else -> { - val generator = buildFoundFlagGenerator(loop, inputVariable, filterCondition, negated = false) + val generator = buildFoundFlagGenerator(loop, inputVariable, filterCondition, negated = false, reformat = reformat) return object : FindOperationGenerator(generator) { override fun generate(chainedCallGenerator: ChainedCallGenerator): KtExpression { val chainedCall = generator.generate(chainedCallGenerator) - return KtPsiFactory(chainedCall).createExpressionByPattern("if ($0) $1 else $2", chainedCall, valueIfFound, valueIfNotFound) + return KtPsiFactory(chainedCall).createExpressionByPattern( + "if ($0) $1 else $2", chainedCall, valueIfFound, valueIfNotFound, + reformat = chainedCallGenerator.reformat + ) } } } @@ -327,13 +336,14 @@ object FindTransformationMatcher : TransformationMatcher { loop: KtForExpression, inputVariable: KtCallableDeclaration, filter: Condition?, - negated: Boolean + negated: Boolean, + reformat: Boolean ): FindOperationGenerator { if (filter == null) { return SimpleGenerator(if (negated) "none" else "any", inputVariable, null) } - val filterExpression = filter.asExpression() + val filterExpression = filter.asExpression(reformat) val containsArgument = filterExpression.isFilterForContainsOperation(inputVariable, loop) if (containsArgument != null) { val generator = SimpleGenerator("contains", inputVariable, null, containsArgument) @@ -349,7 +359,7 @@ object FindTransformationMatcher : TransformationMatcher { } if (filterExpression is KtPrefixExpression && filterExpression.operationToken == KtTokens.EXCL) { - return SimpleGenerator(if (negated) "any" else "none", inputVariable, filter.asNegatedExpression()) + return SimpleGenerator(if (negated) "any" else "none", inputVariable, filter.asNegatedExpression(reformat)) } return SimpleGenerator(if (negated) "none" else "any", inputVariable, filterExpression) diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/ForEachTransformation.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/ForEachTransformation.kt index f13828a8408..29ed640d0ab 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/ForEachTransformation.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/ForEachTransformation.kt @@ -40,7 +40,7 @@ class ForEachTransformation( get() = functionName + "{}" override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression { - val lambda = generateLambda(inputVariable, indexVariable, statement) + val lambda = generateLambda(inputVariable, indexVariable, statement, chainedCallGenerator.reformat) return chainedCallGenerator.generate("$functionName $0:'{}'", lambda) } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/MaxOrMinTransformation.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/MaxOrMinTransformation.kt index d97c1fe0803..ca96b600e3b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/MaxOrMinTransformation.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/MaxOrMinTransformation.kt @@ -33,7 +33,10 @@ class MaxOrMinTransformation( override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression { val call = chainedCallGenerator.generate(presentation) - return KtPsiFactory(call).createExpressionByPattern("$0\n ?: $1", call, initialization.initializer) + return KtPsiFactory(call).createExpressionByPattern( + "$0\n ?: $1", call, initialization.initializer, + reformat = chainedCallGenerator.reformat + ) } /** diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/SumTransformation.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/SumTransformation.kt index d0197a99d90..7e001a86b41 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/SumTransformation.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/SumTransformation.kt @@ -40,7 +40,10 @@ abstract class SumTransformationBase( call } else { - KtPsiFactory(call).createExpressionByPattern("$0 + $1", initialization.initializer, call) + KtPsiFactory(call).createExpressionByPattern( + "$0 + $1", initialization.initializer, call, + reformat = chainedCallGenerator.reformat + ) } } @@ -95,7 +98,7 @@ abstract class SumTransformationBase( } val byExpression = if (conversionFunctionName != null) - KtPsiFactory(value).createExpressionByPattern("$0.$conversionFunctionName()", value) + KtPsiFactory(value).createExpressionByPattern("$0.$conversionFunctionName()", value, reformat = state.reformat) else value @@ -171,7 +174,7 @@ class SumByTransformation( get() = "$functionName{}" override fun generateCall(chainedCallGenerator: ChainedCallGenerator): KtExpression { - val lambda = generateLambda(inputVariable, byExpression) + val lambda = generateLambda(inputVariable, byExpression, chainedCallGenerator.reformat) return chainedCallGenerator.generate("$functionName $0:'{}'", lambda) } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/sequence/Condition.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/sequence/Condition.kt index c807af89d5a..a88c79383f4 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/sequence/Condition.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/sequence/Condition.kt @@ -22,8 +22,8 @@ import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* interface Condition { - fun asExpression(): KtExpression - fun asNegatedExpression(): KtExpression + fun asExpression(reformat: Boolean): KtExpression + fun asNegatedExpression(reformat: Boolean): KtExpression fun toAtomicConditions(): List companion object { @@ -62,28 +62,28 @@ class AtomicCondition(val expression: KtExpression, private val isNegated: Boole assert(expression.isPhysical) } - override fun asExpression() = if (isNegated) expression.negate() else expression - override fun asNegatedExpression() = if (isNegated) expression else expression.negate() + override fun asExpression(reformat: Boolean) = if (isNegated) expression.negate(reformat) else expression + override fun asNegatedExpression(reformat: Boolean) = if (isNegated) expression else expression.negate(reformat) override fun toAtomicConditions() = listOf(this) fun negate() = AtomicCondition(expression, !isNegated) } class CompositeCondition private constructor(val conditions: List) : Condition { - override fun asExpression(): KtExpression { + override fun asExpression(reformat: Boolean): KtExpression { val factory = KtPsiFactory(conditions.first().expression) - return factory.buildExpression { + return factory.buildExpression(reformat = reformat) { for ((index, condition) in conditions.withIndex()) { if (index > 0) { appendFixedText("&&") } - appendExpression(condition.asExpression()) + appendExpression(condition.asExpression(reformat)) } } } - override fun asNegatedExpression(): KtExpression { - return asExpression().negate() + override fun asNegatedExpression(reformat: Boolean): KtExpression { + return asExpression(reformat).negate() } override fun toAtomicConditions() = conditions diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/sequence/FilterTransformation.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/sequence/FilterTransformation.kt index 25a988594c1..bace16a6de9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/sequence/FilterTransformation.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/sequence/FilterTransformation.kt @@ -97,7 +97,8 @@ abstract class FilterTransformationBase : SequenceTransformation { currentState.inputVariable, currentState.indexVariable, atomicConditions, - currentState.statements) + currentState.statements, + currentState.reformat) assert(transformations.isNotEmpty()) val findTransformationMatch = FindTransformationMatcher.matchWithFilterBefore(currentState, transformations.last()) @@ -115,13 +116,14 @@ abstract class FilterTransformationBase : SequenceTransformation { inputVariable: KtCallableDeclaration, indexVariable: KtCallableDeclaration?, conditions: List, - restStatements: List + restStatements: List, + reformat: Boolean ): List { if (conditions.size == 1) { - return listOf(createFilterTransformation(loop, inputVariable, indexVariable, conditions.single())) + return listOf(createFilterTransformation(loop, inputVariable, indexVariable, conditions.single(), reformat = reformat)) } - var transformations = conditions.map { createFilterTransformation(loop, inputVariable, indexVariable, it) } + var transformations = conditions.map { createFilterTransformation(loop, inputVariable, indexVariable, it, reformat = reformat) } val resultTransformations = ArrayList() @@ -129,7 +131,7 @@ abstract class FilterTransformationBase : SequenceTransformation { if (lastUseOfIndex != null) { val index = transformations.indexOf(lastUseOfIndex) val condition = CompositeCondition.create(conditions.take(index + 1)) - resultTransformations.add(createFilterTransformation(loop, inputVariable, indexVariable, condition)) + resultTransformations.add(createFilterTransformation(loop, inputVariable, indexVariable, condition, reformat = reformat)) transformations = transformations.drop(index + 1) } @@ -141,11 +143,11 @@ abstract class FilterTransformationBase : SequenceTransformation { val prevFilter = resultTransformations.lastOrNull() as? FilterTransformation if (prevFilter != null) { val mergedCondition = CompositeCondition.create(prevFilter.effectiveCondition.toAtomicConditions() + transformation.effectiveCondition.toAtomicConditions()) - val mergedTransformation = createFilterTransformation(loop, inputVariable, indexVariable, mergedCondition, onlyFilterOrFilterNot = true) + val mergedTransformation = createFilterTransformation(loop, inputVariable, indexVariable, mergedCondition, onlyFilterOrFilterNot = true, reformat = reformat) resultTransformations[resultTransformations.lastIndex] = mergedTransformation } else { - resultTransformations.add(createFilterTransformation(loop, inputVariable, indexVariable, condition, onlyFilterOrFilterNot = true)) + resultTransformations.add(createFilterTransformation(loop, inputVariable, indexVariable, condition, onlyFilterOrFilterNot = true, reformat = reformat)) } } } @@ -188,7 +190,10 @@ abstract class FilterTransformationBase : SequenceTransformation { if (!state.inputVariable.hasUsages(condition) && (state.indexVariable == null || !state.indexVariable.hasUsages(condition))) return null if (restStatements.isEmpty()) { - val transformation = createFilterTransformation(state.outerLoop, state.inputVariable, state.indexVariable, Condition.create(condition, negateCondition)) + val transformation = createFilterTransformation( + state.outerLoop, state.inputVariable, state.indexVariable, Condition.create(condition, negateCondition), + reformat = state.reformat + ) val newState = state.copy(statements = listOf(then)) return transformation to newState } @@ -197,14 +202,20 @@ abstract class FilterTransformationBase : SequenceTransformation { when (statement) { is KtContinueExpression -> { if (statement.targetLoop() != state.innerLoop) return null - val transformation = createFilterTransformation(state.outerLoop, state.inputVariable, state.indexVariable, Condition.create(condition, !negateCondition)) + val transformation = createFilterTransformation( + state.outerLoop, state.inputVariable, state.indexVariable, Condition.create(condition, !negateCondition), + reformat = state.reformat + ) val newState = state.copy(statements = restStatements) return transformation to newState } is KtBreakExpression -> { if (statement.targetLoop() != state.outerLoop) return null - val transformation = TakeWhileTransformation(state.outerLoop, state.inputVariable, if (negateCondition) condition else condition.negate()) + val transformation = TakeWhileTransformation( + state.outerLoop, state.inputVariable, + if (negateCondition) condition else condition.negate(reformat = state.reformat) + ) val newState = state.copy(statements = restStatements) return transformation to newState } @@ -219,14 +230,15 @@ abstract class FilterTransformationBase : SequenceTransformation { inputVariable: KtCallableDeclaration, indexVariable: KtCallableDeclaration?, condition: Condition, - onlyFilterOrFilterNot: Boolean = false + onlyFilterOrFilterNot: Boolean = false, + reformat: Boolean ): FilterTransformationBase { if (indexVariable != null && condition.hasUsagesOf(indexVariable)) { return FilterTransformation(loop, inputVariable, indexVariable, condition, isFilterNot = false) } - val conditionAsExpression = condition.asExpression() + val conditionAsExpression = condition.asExpression(reformat) if (!onlyFilterOrFilterNot) { if (conditionAsExpression is KtIsExpression && !conditionAsExpression.isNegated @@ -288,10 +300,11 @@ class FilterTransformation( get() = "$functionName{}" override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression { + val reformat = chainedCallGenerator.reformat val lambda = if (indexVariable != null) - generateLambda(inputVariable, indexVariable, effectiveCondition.asExpression()) + generateLambda(inputVariable, indexVariable, effectiveCondition.asExpression(reformat), reformat) else - generateLambda(inputVariable, if (isFilterNot) effectiveCondition.asNegatedExpression() else effectiveCondition.asExpression()) + generateLambda(inputVariable, if (isFilterNot) effectiveCondition.asNegatedExpression(reformat) else effectiveCondition.asExpression(reformat), reformat) return chainedCallGenerator.generate("$0$1:'{}'", functionName, lambda) } } @@ -321,7 +334,7 @@ class FilterNotNullTransformation( override val indexVariable: KtCallableDeclaration? get() = null - override fun mergeWithPrevious(previousTransformation: SequenceTransformation): SequenceTransformation? { + override fun mergeWithPrevious(previousTransformation: SequenceTransformation, reformat: Boolean): SequenceTransformation? { if (previousTransformation is MapTransformation) { return MapTransformation(loop, previousTransformation.inputVariable, previousTransformation.indexVariable, previousTransformation.mapping, mapNotNull = true) } @@ -351,7 +364,7 @@ class TakeWhileTransformation( get() = "takeWhile{}" override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression { - val lambda = generateLambda(inputVariable, condition) + val lambda = generateLambda(inputVariable, condition, chainedCallGenerator.reformat) return chainedCallGenerator.generate("takeWhile$0:'{}'", lambda) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/sequence/FlatMapTransformation.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/sequence/FlatMapTransformation.kt index f637a75793f..8cae280f54c 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/sequence/FlatMapTransformation.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/sequence/FlatMapTransformation.kt @@ -36,7 +36,7 @@ class FlatMapTransformation( get() = "flatMap{}" override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression { - val lambda = generateLambda(inputVariable, transform) + val lambda = generateLambda(inputVariable, transform, chainedCallGenerator.reformat) return chainedCallGenerator.generate("flatMap$0:'{}'", lambda) } @@ -69,8 +69,11 @@ class FlatMapTransformation( if (state.indexVariable != null && state.indexVariable.hasUsages(transform)) { // if nested loop range uses index, convert to "mapIndexed {...}.flatMap { it }" val mapIndexedTransformation = MapTransformation(state.outerLoop, state.inputVariable, state.indexVariable, transform, mapNotNull = false) - val inputVarExpression = KtPsiFactory(nestedLoop).createExpressionByPattern("$0", state.inputVariable.nameAsSafeName) - val transformToUse = if (state.lazySequence) inputVarExpression.asSequence() else inputVarExpression + val inputVarExpression = KtPsiFactory(nestedLoop).createExpressionByPattern( + "$0", state.inputVariable.nameAsSafeName, + reformat = state.reformat + ) + val transformToUse = if (state.lazySequence) inputVarExpression.asSequence(state.reformat) else inputVarExpression val flatMapTransformation = FlatMapTransformation(state.outerLoop, state.inputVariable, transformToUse) val newState = state.copy( innerLoop = nestedLoop, @@ -80,7 +83,7 @@ class FlatMapTransformation( return TransformationMatch.Sequence(listOf(mapIndexedTransformation, flatMapTransformation), newState) } - val transformToUse = if (state.lazySequence) transform.asSequence() else transform + val transformToUse = if (state.lazySequence) transform.asSequence(state.reformat) else transform val transformation = FlatMapTransformation(state.outerLoop, state.inputVariable, transformToUse) val newState = state.copy( innerLoop = nestedLoop, @@ -90,8 +93,11 @@ class FlatMapTransformation( return TransformationMatch.Sequence(transformation, newState) } - private fun KtExpression.asSequence(): KtExpression { - return KtPsiFactory(this).createExpressionByPattern("$0.asSequence()", this) + private fun KtExpression.asSequence(reformat: Boolean): KtExpression { + return KtPsiFactory(this).createExpressionByPattern( + "$0.asSequence()", this, + reformat = reformat + ) } } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/sequence/MapTransformation.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/sequence/MapTransformation.kt index 0cd97b8050a..34a75386ad7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/sequence/MapTransformation.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/sequence/MapTransformation.kt @@ -40,7 +40,7 @@ class MapTransformation( get() = "$functionName{}" override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression { - val lambda = generateLambda(inputVariable, indexVariable, mapping) + val lambda = generateLambda(inputVariable, indexVariable, mapping, chainedCallGenerator.reformat) return chainedCallGenerator.generate("$functionName$0:'{}'", lambda) } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt index ee26279ee51..aaec7c434e8 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/utils.kt @@ -44,10 +44,13 @@ import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluat import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import java.util.* -fun generateLambda(inputVariable: KtCallableDeclaration, expression: KtExpression): KtLambdaExpression { +fun generateLambda(inputVariable: KtCallableDeclaration, expression: KtExpression, reformat: Boolean): KtLambdaExpression { val psiFactory = KtPsiFactory(expression) - val lambdaExpression = psiFactory.createExpressionByPattern("{ $0 -> $1 }", inputVariable.nameAsSafeName, expression) as KtLambdaExpression + val lambdaExpression = psiFactory.createExpressionByPattern( + "{ $0 -> $1 }", inputVariable.nameAsSafeName, expression, + reformat = reformat + ) as KtLambdaExpression val isItUsedInside = expression.anyDescendantOfType { it.getQualifiedExpressionForSelector() == null && it.getReferencedName() == "it" @@ -65,15 +68,20 @@ fun generateLambda(inputVariable: KtCallableDeclaration, expression: KtExpressio (usage.node as UserDataHolderBase).copyCopyableDataTo(replaced.node as UserDataHolderBase) } - return psiFactory.createExpressionByPattern("{ $0 }", lambdaExpression.bodyExpression!!) as KtLambdaExpression + return psiFactory.createExpressionByPattern("{ $0 }", lambdaExpression.bodyExpression!!, reformat = reformat) as KtLambdaExpression } -fun generateLambda(inputVariable: KtCallableDeclaration, indexVariable: KtCallableDeclaration?, expression: KtExpression): KtLambdaExpression { +fun generateLambda( + inputVariable: KtCallableDeclaration, + indexVariable: KtCallableDeclaration?, + expression: KtExpression, + reformat: Boolean +): KtLambdaExpression { if (indexVariable == null) { - return generateLambda(inputVariable, expression) + return generateLambda(inputVariable, expression, reformat) } - val lambdaExpression = generateLambda(expression, *arrayOf(indexVariable, inputVariable)) + val lambdaExpression = generateLambda(expression, *arrayOf(indexVariable, inputVariable), reformat = reformat) // replace "index++" with "index" or "index + 1" (see IntroduceIndexMatcher) val indexPlusPlus = lambdaExpression.findDescendantOfType { unaryExpression -> @@ -89,23 +97,23 @@ fun generateLambda(inputVariable: KtCallableDeclaration, indexVariable: KtCallab } } if (indexPlusPlus != null) { - removePlusPlus(indexPlusPlus) + removePlusPlus(indexPlusPlus, reformat) } return lambdaExpression } -fun removePlusPlus(indexPlusPlus: KtUnaryExpression) { +fun removePlusPlus(indexPlusPlus: KtUnaryExpression, reformat: Boolean) { val operand = indexPlusPlus.baseExpression!! val replacement = if (indexPlusPlus is KtPostfixExpression) // index++ operand else // ++index - KtPsiFactory(operand).createExpressionByPattern("$0 + 1", operand) + KtPsiFactory(operand).createExpressionByPattern("$0 + 1", operand, reformat = reformat) indexPlusPlus.replace(replacement) } -fun generateLambda(expression: KtExpression, vararg inputVariables: KtCallableDeclaration): KtLambdaExpression { - return KtPsiFactory(expression).buildExpression { +fun generateLambda(expression: KtExpression, vararg inputVariables: KtCallableDeclaration, reformat: Boolean): KtLambdaExpression { + return KtPsiFactory(expression).buildExpression(reformat = reformat) { appendFixedText("{") for ((index, variable) in inputVariables.withIndex()) { diff --git a/idea/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessings.kt b/idea/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessings.kt index 45104863400..407668c9428 100644 --- a/idea/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessings.kt +++ b/idea/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessings.kt @@ -252,7 +252,7 @@ object J2KPostProcessingRegistrar { override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? { if (element !is KtCallExpression) return null val propertyName = intention.detectPropertyNameToUse(element) ?: return null - return { intention.applyTo(element, propertyName) } + return { intention.applyTo(element, propertyName, reformat = true) } } }