Don't invoke formatter while checking availability of intentions
#KT-21632 Fixed
This commit is contained in:
@@ -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 {
|
||||
|
||||
+13
-1
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+7
-4
@@ -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 -> {
|
||||
|
||||
+2
-2
@@ -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) {
|
||||
|
||||
+3
-3
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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())
|
||||
|
||||
+11
-7
@@ -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)
|
||||
|
||||
+7
-5
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+28
-18
@@ -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)
|
||||
|
||||
+1
-1
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+6
-3
@@ -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
|
||||
|
||||
+29
-16
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+12
-6
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user