From c343876f7c171af7efcd1326efe41e15220ea9a5 Mon Sep 17 00:00:00 2001 From: Dmitry Gridin Date: Wed, 27 Mar 2019 16:15:25 +0700 Subject: [PATCH] Minor: refactoring codeInliner package --- .../ClassUsageReplacementStrategy.kt | 12 +-- .../kotlin/idea/codeInliner/CodeInliner.kt | 15 ++- .../idea/codeInliner/CodeToInlineBuilder.kt | 41 ++++--- .../idea/codeInliner/MutableCodeToInline.kt | 4 +- .../idea/codeInliner/ReplacementPerformer.kt | 49 ++++----- .../codeInliner/UsageReplacementStrategy.kt | 101 +++++++++--------- .../kotlin/idea/codeInliner/introduceValue.kt | 34 +++--- 7 files changed, 127 insertions(+), 129 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInliner/ClassUsageReplacementStrategy.kt b/idea/src/org/jetbrains/kotlin/idea/codeInliner/ClassUsageReplacementStrategy.kt index 345c0259375..cba185ab60a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInliner/ClassUsageReplacementStrategy.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInliner/ClassUsageReplacementStrategy.kt @@ -26,9 +26,9 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis class ClassUsageReplacementStrategy( - typeReplacement: KtUserType?, - constructorReplacement: CodeToInline?, - project: Project + typeReplacement: KtUserType?, + constructorReplacement: CodeToInline?, + project: Project ) : UsageReplacementStrategy { private val factory = KtPsiFactory(project) @@ -45,8 +45,7 @@ class ClassUsageReplacementStrategy( constructorReplacementStrategy?.createReplacer(usage)?.let { return it } - val parent = usage.parent - when (parent) { + when (val parent = usage.parent) { is KtUserType -> { if (typeReplacement == null) return null return { @@ -91,8 +90,7 @@ class ClassUsageReplacementStrategy( val result = if (expressionToReplace != newExpression) { expressionToReplace.replaced(newExpression) - } - else { + } else { expressionToReplace } diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeInliner.kt b/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeInliner.kt index 057f2ea8093..28331100987 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeInliner.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeInliner.kt @@ -354,12 +354,11 @@ class CodeInliner( return Argument(valueAssigned, bindingContext.getType(valueAssigned)) } - val resolvedArgument = resolvedCall.valueArguments[parameter]!! - when (resolvedArgument) { + when (val resolvedArgument = resolvedCall.valueArguments[parameter] ?: return null) { is ExpressionValueArgument -> { - val valueArgument = resolvedArgument.valueArgument!! - val expression = valueArgument.getArgumentExpression()!! - expression.mark(USER_CODE_KEY) + val valueArgument = resolvedArgument.valueArgument + val expression = valueArgument?.getArgumentExpression() + expression?.mark(USER_CODE_KEY) ?: return null if (valueArgument is LambdaArgument) { expression.mark(WAS_FUNCTION_LITERAL_ARGUMENT_KEY) } @@ -447,9 +446,9 @@ class CodeInliner( ShortenReferences { ShortenReferences.Options(removeThis = true) }.process(it, shortenFilter) } - newElements.forEach { + newElements.forEach { element -> // clean up user data - it.forEachDescendantOfType { + element.forEachDescendantOfType { it.clear(USER_CODE_KEY) it.clear(CodeToInline.PARAMETER_USAGE_KEY) it.clear(CodeToInline.TYPE_PARAMETER_USAGE_KEY) @@ -457,7 +456,7 @@ class CodeInliner( it.clear(RECEIVER_VALUE_KEY) it.clear(WAS_FUNCTION_LITERAL_ARGUMENT_KEY) } - it.forEachDescendantOfType { + element.forEachDescendantOfType { it.clear(MAKE_ARGUMENT_NAMED_KEY) it.clear(DEFAULT_PARAMETER_VALUE_KEY) } diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt b/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt index 50ea1ee290f..d146cfc5ad3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt @@ -45,17 +45,17 @@ import org.jetbrains.kotlin.utils.sure import java.util.* class CodeToInlineBuilder( - private val targetCallable: CallableDescriptor, - private val resolutionFacade: ResolutionFacade + private val targetCallable: CallableDescriptor, + private val resolutionFacade: ResolutionFacade ) { private val psiFactory = KtPsiFactory(resolutionFacade.project) //TODO: document that code will be modified fun prepareCodeToInline( - mainExpression: KtExpression?, - statementsBefore: List, - analyze: () -> BindingContext, - reformat: Boolean + mainExpression: KtExpression?, + statementsBefore: List, + analyze: () -> BindingContext, + reformat: Boolean ): CodeToInline { var bindingContext = analyze() @@ -113,8 +113,8 @@ class CodeToInlineBuilder( } private fun needToAddParameterTypes( - lambdaExpression: KtLambdaExpression, - resolutionFacade: ResolutionFacade + lambdaExpression: KtLambdaExpression, + resolutionFacade: ResolutionFacade ): Boolean { val functionLiteral = lambdaExpression.functionLiteral val context = resolutionFacade.analyze(lambdaExpression, BodyResolveMode.PARTIAL_WITH_DIAGNOSTICS) @@ -122,15 +122,19 @@ class CodeToInlineBuilder( val factory = diagnostic.factory val element = diagnostic.psiElement val hasCantInferParameter = factory == Errors.CANNOT_INFER_PARAMETER_TYPE && - element.parent.parent == functionLiteral + element.parent.parent == functionLiteral val hasUnresolvedItOrThis = factory == Errors.UNRESOLVED_REFERENCE && - element.text == "it" && - element.getStrictParentOfType() == functionLiteral + element.text == "it" && + element.getStrictParentOfType() == functionLiteral hasCantInferParameter || hasUnresolvedItOrThis } } - private fun insertExplicitTypeArguments(codeToInline: MutableCodeToInline, bindingContext: BindingContext, analyze: () -> BindingContext): BindingContext { + private fun insertExplicitTypeArguments( + codeToInline: MutableCodeToInline, + bindingContext: BindingContext, + analyze: () -> BindingContext + ): BindingContext { val typeArgsToAdd = ArrayList>() codeToInline.forEachDescendantOfType { if (InsertExplicitTypeArgumentsIntention.isApplicableTo(it, bindingContext)) { @@ -162,8 +166,7 @@ class CodeToInlineBuilder( if (expression.getReceiverExpression() == null) { if (target is ValueParameterDescriptor && target.containingDeclaration == targetCallable) { expression.putCopyableUserData(CodeToInline.PARAMETER_USAGE_KEY, target.name) - } - else if (target is TypeParameterDescriptor && target.containingDeclaration == targetCallable) { + } else if (target is TypeParameterDescriptor && target.containingDeclaration == targetCallable) { expression.putCopyableUserData(CodeToInline.TYPE_PARAMETER_USAGE_KEY, target.name) } @@ -187,9 +190,13 @@ class CodeToInlineBuilder( // add receivers in reverse order because arguments of a call were processed after the callee's name for ((expr, receiverExpression) in receiversToAdd.asReversed()) { val expressionToReplace = expr.parent as? KtCallExpression ?: expr - codeToInline.replaceExpression(expressionToReplace, - psiFactory.createExpressionByPattern("$0.$1", receiverExpression, expressionToReplace, - reformat = reformat)) + codeToInline.replaceExpression( + expressionToReplace, + psiFactory.createExpressionByPattern( + "$0.$1", receiverExpression, expressionToReplace, + reformat = reformat + ) + ) } } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInliner/MutableCodeToInline.kt b/idea/src/org/jetbrains/kotlin/idea/codeInliner/MutableCodeToInline.kt index d1f0ebd2307..c93a07d7873 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInliner/MutableCodeToInline.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInliner/MutableCodeToInline.kt @@ -95,10 +95,10 @@ internal fun MutableCodeToInline.toNonMutable(): CodeToInline { } internal inline fun MutableCodeToInline.collectDescendantsOfType(noinline predicate: (T) -> Boolean = { true }): List { - return expressions.flatMap { it.collectDescendantsOfType({ true }, predicate) } + return expressions.flatMap { it.collectDescendantsOfType({ true }, predicate) } } internal inline fun MutableCodeToInline.forEachDescendantOfType(noinline action: (T) -> Unit) { - expressions.forEach { it.forEachDescendantOfType(action) } + expressions.forEach { it.forEachDescendantOfType(action) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInliner/ReplacementPerformer.kt b/idea/src/org/jetbrains/kotlin/idea/codeInliner/ReplacementPerformer.kt index 7506dd83640..b3b07cfefa2 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInliner/ReplacementPerformer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInliner/ReplacementPerformer.kt @@ -34,8 +34,8 @@ import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments import java.util.* internal abstract class ReplacementPerformer( - protected val codeToInline: MutableCodeToInline, - protected var elementToBeReplaced: TElement + protected val codeToInline: MutableCodeToInline, + protected var elementToBeReplaced: TElement ) { protected val psiFactory = KtPsiFactory(elementToBeReplaced) @@ -43,8 +43,8 @@ internal abstract class ReplacementPerformer( } internal class AnnotationEntryReplacementPerformer( - codeToInline: MutableCodeToInline, - elementToBeReplaced: KtAnnotationEntry + codeToInline: MutableCodeToInline, + elementToBeReplaced: KtAnnotationEntry ) : ReplacementPerformer(codeToInline, elementToBeReplaced) { override fun doIt(postProcessing: (PsiChildRange) -> PsiChildRange): KtAnnotationEntry { @@ -63,21 +63,22 @@ internal class AnnotationEntryReplacementPerformer( assert(range.first is KtAnnotationEntry) val annotationEntry = range.first as KtAnnotationEntry val text = annotationEntry.valueArguments.single().getArgumentExpression()!!.text - return annotationEntry.replaced(psiFactory.createAnnotationEntry("@" + text)) + return annotationEntry.replaced(psiFactory.createAnnotationEntry("@$text")) } } internal class ExpressionReplacementPerformer( - codeToInline: MutableCodeToInline, - expressionToBeReplaced: KtExpression + codeToInline: MutableCodeToInline, + expressionToBeReplaced: KtExpression ) : ReplacementPerformer(codeToInline, expressionToBeReplaced) { fun KtExpression.replacedWithStringTemplate(templateExpression: KtStringTemplateExpression): KtExpression? { val parent = this.parent return if (parent is KtStringTemplateEntryWithExpression - // Do not mix raw and non-raw templates - && parent.parent.firstChild.text == templateExpression.firstChild.text) { + // Do not mix raw and non-raw templates + && parent.parent.firstChild.text == templateExpression.firstChild.text + ) { val entriesToAdd = templateExpression.entries val grandParentTemplateExpression = parent.parent as KtStringTemplateExpression @@ -87,17 +88,16 @@ internal class ExpressionReplacementPerformer( val nextElement = parent.nextSibling if (lastNewEntry is KtSimpleNameStringTemplateEntry && lastNewEntry.expression != null && - !canPlaceAfterSimpleNameEntry(nextElement)) { + !canPlaceAfterSimpleNameEntry(nextElement) + ) { lastNewEntry.replace(KtPsiFactory(this).createBlockStringTemplateEntry(lastNewEntry.expression!!)) } grandParentTemplateExpression - } - else null + } else null parent.delete() result - } - else { + } else { replaced(templateExpression) } } @@ -129,8 +129,7 @@ internal class ExpressionReplacementPerformer( if (canDropElementToBeReplaced) { stub.delete() null - } - else { + } else { stub.replaced(psiFactory.createExpression("Unit")) } } @@ -141,17 +140,14 @@ internal class ExpressionReplacementPerformer( var range = if (replaced != null) { if (insertedStatements.isEmpty()) { PsiChildRange.singleElement(replaced) - } - else { + } else { val statement = insertedStatements.first() PsiChildRange(statement, replaced.parentsWithSelf.first { it.parent == statement.parent }) } - } - else { + } else { if (insertedStatements.isEmpty()) { PsiChildRange.EMPTY - } - else { + } else { PsiChildRange(insertedStatements.first(), insertedStatements.last()) } } @@ -160,8 +156,7 @@ internal class ExpressionReplacementPerformer( listener?.attach() try { range = postProcessing(range) - } - finally { + } finally { listener?.detach() } @@ -214,8 +209,8 @@ internal class ExpressionReplacementPerformer( val runAfterReplacement = elementToBeReplaced.replaced(runExpression) val ktLambdaArgument = runAfterReplacement.lambdaArguments[0] val block = ktLambdaArgument.getLambdaExpression()?.bodyExpression - ?: throw KotlinExceptionWithAttachments("cant get body expression for $ktLambdaArgument") - .withAttachment("ktLambdaArgument", ktLambdaArgument.text) + ?: throw KotlinExceptionWithAttachments("cant get body expression for $ktLambdaArgument") + .withAttachment("ktLambdaArgument", ktLambdaArgument.text) elementToBeReplaced = block.statements.single() return elementToBeReplaced @@ -231,7 +226,7 @@ internal class ExpressionReplacementPerformer( private fun withElementToBeReplacedPreserved(action: () -> TElement): TElement { elementToBeReplaced.putCopyableUserData(ELEMENT_TO_BE_REPLACED_KEY, Unit) val result = action() - elementToBeReplaced = result.findDescendantOfType { it.getCopyableUserData(ELEMENT_TO_BE_REPLACED_KEY) != null }!! + elementToBeReplaced = result.findDescendantOfType { it.getCopyableUserData(ELEMENT_TO_BE_REPLACED_KEY) != null }!! elementToBeReplaced.putCopyableUserData(ELEMENT_TO_BE_REPLACED_KEY, null) return result } diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInliner/UsageReplacementStrategy.kt b/idea/src/org/jetbrains/kotlin/idea/codeInliner/UsageReplacementStrategy.kt index a09246005cb..4b7be5ccb9f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInliner/UsageReplacementStrategy.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInliner/UsageReplacementStrategy.kt @@ -51,72 +51,72 @@ interface UsageReplacementStrategy { private val LOG = Logger.getInstance(UsageReplacementStrategy::class.java) fun UsageReplacementStrategy.replaceUsagesInWholeProject( - targetPsiElement: PsiElement, - progressTitle: String, - commandName: String, - postAction: () -> Unit = {} + targetPsiElement: PsiElement, + progressTitle: String, + commandName: String, + postAction: () -> Unit = {} ) { val project = targetPsiElement.project ProgressManager.getInstance().run( - object : Task.Modal(project, progressTitle, true) { - override fun run(indicator: ProgressIndicator) { - val usages = runReadAction { - val searchScope = KotlinSourceFilterScope.projectSources(GlobalSearchScope.projectScope(project), project) - ReferencesSearch.search(targetPsiElement, searchScope) - .filterIsInstance() - .map { ref -> ref.expression } - } - this@replaceUsagesInWholeProject.replaceUsages(usages, targetPsiElement, project, commandName, postAction) + object : Task.Modal(project, progressTitle, true) { + override fun run(indicator: ProgressIndicator) { + val usages = runReadAction { + val searchScope = KotlinSourceFilterScope.projectSources(GlobalSearchScope.projectScope(project), project) + ReferencesSearch.search(targetPsiElement, searchScope) + .filterIsInstance() + .map { ref -> ref.expression } } - }) + this@replaceUsagesInWholeProject.replaceUsages(usages, targetPsiElement, project, commandName, postAction) + } + }) } fun UsageReplacementStrategy.replaceUsages( - usages: Collection, - targetPsiElement: PsiElement, - project: Project, - commandName: String, - postAction: () -> Unit = {} + usages: Collection, + targetPsiElement: PsiElement, + project: Project, + commandName: String, + postAction: () -> Unit = {} ) { GuiUtils.invokeLaterIfNeeded({ - project.executeWriteCommand(commandName) { - val targetDeclaration = targetPsiElement as? KtNamedDeclaration + project.executeWriteCommand(commandName) { + val targetDeclaration = targetPsiElement as? KtNamedDeclaration - val usagesByFile = usages.groupBy { it.containingFile } + val usagesByFile = usages.groupBy { it.containingFile } - val KEY = Key("UsageReplacementStrategy.replaceUsages") + val KEY = Key("UsageReplacementStrategy.replaceUsages") - for ((file, usagesInFile) in usagesByFile) { - usagesInFile.forEach { it.putCopyableUserData(KEY, Unit) } + for ((file, usagesInFile) in usagesByFile) { + usagesInFile.forEach { it.putCopyableUserData(KEY, Unit) } - // we should delete imports later to not affect other usages - val importsToDelete = mutableListOf() + // we should delete imports later to not affect other usages + val importsToDelete = mutableListOf() - var usagesToProcess = usagesInFile - while (usagesToProcess.isNotEmpty()) { - if (processUsages(usagesToProcess, targetDeclaration, importsToDelete)) break + var usagesToProcess = usagesInFile + while (usagesToProcess.isNotEmpty()) { + if (processUsages(usagesToProcess, targetDeclaration, importsToDelete)) break - // some usages may get invalidated we need to find them in the tree - usagesToProcess = file.collectDescendantsOfType { it.getCopyableUserData(KEY) != null } - } + // some usages may get invalidated we need to find them in the tree + usagesToProcess = file.collectDescendantsOfType { it.getCopyableUserData(KEY) != null } + } - file.forEachDescendantOfType { it.putCopyableUserData(KEY, null) } - - importsToDelete.forEach { it.delete() } - } + file.forEachDescendantOfType { it.putCopyableUserData(KEY, null) } - postAction() - } - }, ModalityState.NON_MODAL) + importsToDelete.forEach { it.delete() } + } + + postAction() + } + }, ModalityState.NON_MODAL) } /** * @return false if some usages were invalidated */ private fun UsageReplacementStrategy.processUsages( - usages: List, - targetDeclaration: KtNamedDeclaration?, - importsToDelete: MutableList + usages: List, + targetDeclaration: KtNamedDeclaration?, + importsToDelete: MutableList ): Boolean { var invalidUsagesFound = false for (usage in usages) { @@ -138,17 +138,18 @@ private fun UsageReplacementStrategy.processUsages( } createReplacer(usage)?.invoke() - } - catch (e: Throwable) { + } catch (e: Throwable) { LOG.error(e) } } return !invalidUsagesFound } -private fun UsageReplacementStrategy.specialUsageProcessing(usage: KtSimpleNameExpression, targetDeclaration: KtNamedDeclaration?): Boolean { - val usageParent = usage.parent - when (usageParent) { +private fun UsageReplacementStrategy.specialUsageProcessing( + usage: KtSimpleNameExpression, + targetDeclaration: KtNamedDeclaration? +): Boolean { + when (val usageParent = usage.parent) { is KtCallableReferenceExpression -> { val grandParent = usageParent.parent ConvertReferenceToLambdaIntention().applyTo(usageParent, null) @@ -166,7 +167,7 @@ private fun UsageReplacementStrategy.specialUsageProcessing(usage: KtSimpleNameE for (lambdaArgument in lambdaArguments) { val lambdaExpression = lambdaArgument.getLambdaExpression() ?: continue val functionDescriptor = - lambdaExpression.functionLiteral.resolveToDescriptorIfAny() as? FunctionDescriptor ?: continue + lambdaExpression.functionLiteral.resolveToDescriptorIfAny() as? FunctionDescriptor ?: continue if (functionDescriptor.valueParameters.isNotEmpty()) { specifySignature.applyTo(lambdaExpression, null) } @@ -183,7 +184,7 @@ private fun UsageReplacementStrategy.specialUsageProcessing(usage: KtSimpleNameE } private fun UsageReplacementStrategy.doRefactoringInside( - element: KtElement, targetName: String?, targetDescriptor: DeclarationDescriptor? + element: KtElement, targetName: String?, targetDescriptor: DeclarationDescriptor? ) { element.forEachDescendantOfType { usage -> if (usage.isValid && usage.getReferencedName() == targetName) { diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInliner/introduceValue.kt b/idea/src/org/jetbrains/kotlin/idea/codeInliner/introduceValue.kt index 553f865f5c1..d335f314d10 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInliner/introduceValue.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInliner/introduceValue.kt @@ -50,12 +50,12 @@ import org.jetbrains.kotlin.types.KotlinType * @param safeCall If true, then the whole code must not be executed if the [value] evaluates to null. */ internal fun MutableCodeToInline.introduceValue( - value: KtExpression, - valueType: KotlinType?, - usages: Collection, - expressionToBeReplaced: KtExpression, - nameSuggestion: String? = null, - safeCall: Boolean = false + value: KtExpression, + valueType: KotlinType?, + usages: Collection, + expressionToBeReplaced: KtExpression, + nameSuggestion: String? = null, + safeCall: Boolean = false ) { assert(usages.all { this.containsStrictlyInside(it) }) @@ -100,12 +100,10 @@ internal fun MutableCodeToInline.introduceValue( } replaceUsages(name) - } - else { + } else { statementsBefore.add(0, value) } - } - else { + } else { val useIt = !isNameUsed("it") val name = if (useIt) Name.identifier("it") else suggestName { !isNameUsed(it) } replaceUsages(name) @@ -139,17 +137,17 @@ fun String.nameHasConflictsInScope(lexicalScope: LexicalScope) = lexicalScope.ge } private fun variableNeedsExplicitType( - initializer: KtExpression, - initializerType: KotlinType, - context: KtExpression, - resolutionScope: LexicalScope, - bindingContext: BindingContext + initializer: KtExpression, + initializerType: KotlinType, + context: KtExpression, + resolutionScope: LexicalScope, + bindingContext: BindingContext ): Boolean { if (ErrorUtils.containsErrorType(initializerType)) return false val valueTypeWithoutExpectedType = initializer.computeTypeInContext( - resolutionScope, - context, - dataFlowInfo = bindingContext.getDataFlowInfoBefore(context) + resolutionScope, + context, + dataFlowInfo = bindingContext.getDataFlowInfoBefore(context) ) return valueTypeWithoutExpectedType == null || ErrorUtils.containsErrorType(valueTypeWithoutExpectedType) }