Minor: refactoring codeInliner package

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