Don't invoke formatter while checking availability of intentions

#KT-21632 Fixed
This commit is contained in:
Dmitry Jemerov
2017-12-13 19:00:40 +01:00
parent 54d626fe7d
commit 40184f053e
23 changed files with 210 additions and 126 deletions
@@ -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 <TElement : KtElement> 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 <TElement : KtElement> 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<TElement> {
}
}
fun KtPsiFactory.buildExpression(build: BuilderByPattern<KtExpression>.() -> Unit): KtExpression {
return buildByPattern({ pattern, args -> this.createExpressionByPattern(pattern, *args) }, build)
fun KtPsiFactory.buildExpression(reformat: Boolean = true, build: BuilderByPattern<KtExpression>.() -> Unit): KtExpression {
return buildByPattern({ pattern, args -> this.createExpressionByPattern(pattern, *args, reformat = reformat) }, build)
}
fun KtPsiFactory.buildValueArgumentList(build: BuilderByPattern<KtValueArgumentList>.() -> Unit): KtValueArgumentList {
@@ -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<TElement : PsiElement>(
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<TElement>? = null
internal set
@@ -44,7 +44,7 @@ class AddForLoopIndicesIntention : SelfTargetingRangeIntention<KtForExpression>(
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<KtForExpression>(
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<KtForExpression>(
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)
}
}
@@ -51,7 +51,10 @@ class RemoveExplicitSuperQualifierIntention : SelfTargetingRangeIntention<KtSupe
val bindingContext = selector.analyze(BodyResolveMode.PARTIAL)
if (selector.getResolvedCall(bindingContext) == null) return null
val newQualifiedExpression = KtPsiFactory(element).createExpressionByPattern("$0.$1", toNonQualified(element), selector) as KtQualifiedExpression
val newQualifiedExpression = KtPsiFactory(element).createExpressionByPattern(
"$0.$1", toNonQualified(element, reformat = false), selector,
reformat = false
) as KtQualifiedExpression
val newBindingContext = newQualifiedExpression.analyzeAsReplacement(qualifiedExpression, bindingContext)
val newResolvedCall = newQualifiedExpression.selectorExpression.getResolvedCall(newBindingContext) ?: return null
if (ErrorUtils.isError(newResolvedCall.resultingDescriptor)) return null
@@ -60,14 +63,14 @@ class RemoveExplicitSuperQualifierIntention : SelfTargetingRangeIntention<KtSupe
}
override fun applyTo(element: KtSuperExpression, editor: Editor?) {
element.replace(toNonQualified(element))
element.replace(toNonQualified(element, reformat = true))
}
private fun toNonQualified(superExpression: KtSuperExpression): KtSuperExpression {
private fun toNonQualified(superExpression: KtSuperExpression, reformat: Boolean): KtSuperExpression {
val factory = KtPsiFactory(superExpression)
val labelName = superExpression.getLabelNameAsName()
return (if (labelName != null)
factory.createExpressionByPattern("super@$0", labelName)
factory.createExpressionByPattern("super@$0", labelName, reformat = reformat)
else
factory.createExpression("super")) as KtSuperExpression
}
@@ -119,14 +119,14 @@ class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention
}
override fun applyTo(element: KtCallExpression, editor: Editor?) {
applyTo(element, detectPropertyNameToUse(element)!!)
applyTo(element, detectPropertyNameToUse(element)!!, reformat = true)
}
fun applyTo(element: KtCallExpression, propertyName: Name): KtExpression {
fun applyTo(element: KtCallExpression, propertyName: Name, reformat: Boolean): KtExpression {
val arguments = element.valueArguments
return when (arguments.size) {
0 -> 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)
}
@@ -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<KtWhenExpression> = 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 -> {
@@ -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) {
@@ -32,11 +32,11 @@ class UseWithIndexIntention : SelfTargetingRangeIntention<KtForExpression>(
"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<KtForExpression>(
incrementExpression.delete()
}
else {
removePlusPlus(incrementExpression)
removePlusPlus(incrementExpression, true)
}
}
}
@@ -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)
}
}
@@ -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<KtExpression> = emptyList(),
val previousTransformations: MutableList<SequenceTransformation> = arrayListOf(),
val incrementExpressions: Collection<KtUnaryExpression> = emptyList()
@@ -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())
@@ -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<T>?
return AssignSequenceResultTransformation(previousTransformation, initialization)
@@ -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)
}
}
@@ -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)
@@ -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)
}
@@ -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
)
}
/**
@@ -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)
}
}
@@ -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<AtomicCondition>
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<AtomicCondition>) : 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
@@ -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<AtomicCondition>,
restStatements: List<KtExpression>
restStatements: List<KtExpression>,
reformat: Boolean
): List<FilterTransformationBase> {
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<FilterTransformationBase>()
@@ -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)
}
}
@@ -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
)
}
}
}
@@ -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)
}
@@ -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<KtNameReferenceExpression> {
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<KtUnaryExpression> { 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()) {
@@ -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) }
}
}