Reformat & cleanup: CodeInliner
This commit is contained in:
@@ -40,7 +40,6 @@ import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
|
|||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
@@ -49,12 +48,12 @@ import org.jetbrains.kotlin.utils.addIfNotNull
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class CodeInliner<TCallElement : KtElement>(
|
class CodeInliner<TCallElement : KtElement>(
|
||||||
private val nameExpression: KtSimpleNameExpression,
|
private val nameExpression: KtSimpleNameExpression,
|
||||||
private val bindingContext: BindingContext,
|
private val bindingContext: BindingContext,
|
||||||
private val resolvedCall: ResolvedCall<out CallableDescriptor>,
|
private val resolvedCall: ResolvedCall<out CallableDescriptor>,
|
||||||
private val callElement: TCallElement,
|
private val callElement: TCallElement,
|
||||||
private val inlineSetter: Boolean,
|
private val inlineSetter: Boolean,
|
||||||
codeToInline: CodeToInline
|
codeToInline: CodeToInline
|
||||||
) {
|
) {
|
||||||
private val codeToInline = codeToInline.toMutable()
|
private val codeToInline = codeToInline.toMutable()
|
||||||
private val project = nameExpression.project
|
private val project = nameExpression.project
|
||||||
@@ -66,8 +65,8 @@ class CodeInliner<TCallElement : KtElement>(
|
|||||||
|
|
||||||
val qualifiedElement = if (callElement is KtExpression) callElement.getQualifiedExpressionForSelectorOrThis() else callElement
|
val qualifiedElement = if (callElement is KtExpression) callElement.getQualifiedExpressionForSelectorOrThis() else callElement
|
||||||
val assignment = (qualifiedElement as? KtExpression)
|
val assignment = (qualifiedElement as? KtExpression)
|
||||||
?.getAssignmentByLHS()
|
?.getAssignmentByLHS()
|
||||||
?.takeIf { it.operationToken == KtTokens.EQ }
|
?.takeIf { it.operationToken == KtTokens.EQ }
|
||||||
val callableForParameters = if (assignment != null && descriptor is PropertyDescriptor)
|
val callableForParameters = if (assignment != null && descriptor is PropertyDescriptor)
|
||||||
descriptor.setter?.takeIf { inlineSetter && it.hasBody() } ?: descriptor
|
descriptor.setter?.takeIf { inlineSetter && it.hasBody() } ?: descriptor
|
||||||
else
|
else
|
||||||
@@ -114,8 +113,7 @@ class CodeInliner<TCallElement : KtElement>(
|
|||||||
|
|
||||||
if (elementToBeReplaced is KtSafeQualifiedExpression) {
|
if (elementToBeReplaced is KtSafeQualifiedExpression) {
|
||||||
wrapCodeForSafeCall(receiver!!, receiverType, elementToBeReplaced)
|
wrapCodeForSafeCall(receiver!!, receiverType, elementToBeReplaced)
|
||||||
}
|
} else if (callElement is KtBinaryExpression && callElement.operationToken == KtTokens.IDENTIFIER) {
|
||||||
else if (callElement is KtBinaryExpression && callElement.operationToken == KtTokens.IDENTIFIER) {
|
|
||||||
keepInfixFormIfPossible()
|
keepInfixFormIfPossible()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,13 +127,19 @@ class CodeInliner<TCallElement : KtElement>(
|
|||||||
|
|
||||||
for ((parameter, value, valueType) in introduceValuesForParameters) {
|
for ((parameter, value, valueType) in introduceValuesForParameters) {
|
||||||
val usagesReplaced = codeToInline.collectDescendantsOfType<KtExpression> { it[PARAMETER_VALUE_KEY] == parameter }
|
val usagesReplaced = codeToInline.collectDescendantsOfType<KtExpression> { it[PARAMETER_VALUE_KEY] == parameter }
|
||||||
codeToInline.introduceValue(value, valueType, usagesReplaced, elementToBeReplaced, nameSuggestion = parameter.name.asString())
|
codeToInline.introduceValue(
|
||||||
|
value,
|
||||||
|
valueType,
|
||||||
|
usagesReplaced,
|
||||||
|
elementToBeReplaced,
|
||||||
|
nameSuggestion = parameter.name.asString()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
codeToInline.fqNamesToImport
|
codeToInline.fqNamesToImport
|
||||||
.flatMap { file.resolveImportReference(it) }
|
.flatMap { file.resolveImportReference(it) }
|
||||||
.forEach { ImportInsertHelper.getInstance(project).importDescriptor(file, it) }
|
.forEach { ImportInsertHelper.getInstance(project).importDescriptor(file, it) }
|
||||||
|
|
||||||
val replacementPerformer = when (elementToBeReplaced) {
|
val replacementPerformer = when (elementToBeReplaced) {
|
||||||
is KtExpression -> ExpressionReplacementPerformer(codeToInline, elementToBeReplaced)
|
is KtExpression -> ExpressionReplacementPerformer(codeToInline, elementToBeReplaced)
|
||||||
@@ -152,8 +156,10 @@ class CodeInliner<TCallElement : KtElement>(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renameDuplicates(declarations: List<KtNamedDeclaration>,
|
private fun renameDuplicates(
|
||||||
lexicalScope: LexicalScope) {
|
declarations: List<KtNamedDeclaration>,
|
||||||
|
lexicalScope: LexicalScope
|
||||||
|
) {
|
||||||
|
|
||||||
val validator = CollectingNameValidator { !it.nameHasConflictsInScope(lexicalScope) }
|
val validator = CollectingNameValidator { !it.nameHasConflictsInScope(lexicalScope) }
|
||||||
for (declaration in declarations) {
|
for (declaration in declarations) {
|
||||||
@@ -201,9 +207,10 @@ class CodeInliner<TCallElement : KtElement>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private data class IntroduceValueForParameter(
|
private data class IntroduceValueForParameter(
|
||||||
val parameter: ValueParameterDescriptor,
|
val parameter: ValueParameterDescriptor,
|
||||||
val value: KtExpression,
|
val value: KtExpression,
|
||||||
val valueType: KotlinType?)
|
val valueType: KotlinType?
|
||||||
|
)
|
||||||
|
|
||||||
private fun processTypeParameterUsages() {
|
private fun processTypeParameterUsages() {
|
||||||
val typeParameters = resolvedCall.resultingDescriptor.original.typeParameters
|
val typeParameters = resolvedCall.resultingDescriptor.original.typeParameters
|
||||||
@@ -221,10 +228,9 @@ class CodeInliner<TCallElement : KtElement>(
|
|||||||
|
|
||||||
val type = resolvedCall.typeArguments[typeParameter]!!
|
val type = resolvedCall.typeArguments[typeParameter]!!
|
||||||
val typeElement = if (explicitTypeArgs != null) { // we use explicit type arguments if available to avoid shortening
|
val typeElement = if (explicitTypeArgs != null) { // we use explicit type arguments if available to avoid shortening
|
||||||
val _typeElement = explicitTypeArgs[index].typeReference?.typeElement ?: continue
|
val explicitArgTypeElement = explicitTypeArgs[index].typeReference?.typeElement ?: continue
|
||||||
_typeElement.marked(USER_CODE_KEY)
|
explicitArgTypeElement.marked(USER_CODE_KEY)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
psiFactory.createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type)).typeElement!!
|
psiFactory.createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type)).typeElement!!
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,16 +241,16 @@ class CodeInliner<TCallElement : KtElement>(
|
|||||||
if (parent is KtClassLiteralExpression && typeClassifier != null) {
|
if (parent is KtClassLiteralExpression && typeClassifier != null) {
|
||||||
// for class literal ("X::class") we need type arguments only for kotlin.Array
|
// for class literal ("X::class") we need type arguments only for kotlin.Array
|
||||||
val arguments =
|
val arguments =
|
||||||
if (typeElement is KtUserType && KotlinBuiltIns.isArray(type)) typeElement.typeArgumentList?.text.orEmpty()
|
if (typeElement is KtUserType && KotlinBuiltIns.isArray(type)) typeElement.typeArgumentList?.text.orEmpty()
|
||||||
else ""
|
else ""
|
||||||
codeToInline.replaceExpression(usage, psiFactory.createExpression(
|
codeToInline.replaceExpression(
|
||||||
|
usage, psiFactory.createExpression(
|
||||||
IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(typeClassifier) + arguments
|
IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(typeClassifier) + arguments
|
||||||
))
|
)
|
||||||
}
|
)
|
||||||
else if (parent is KtUserType) {
|
} else if (parent is KtUserType) {
|
||||||
parent.replace(typeElement)
|
parent.replace(typeElement)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
//TODO: tests for this?
|
//TODO: tests for this?
|
||||||
codeToInline.replaceExpression(usage, psiFactory.createExpression(typeElement.text))
|
codeToInline.replaceExpression(usage, psiFactory.createExpression(typeElement.text))
|
||||||
}
|
}
|
||||||
@@ -270,8 +276,7 @@ class CodeInliner<TCallElement : KtElement>(
|
|||||||
if (expressionToBeReplaced.isUsedAsExpression(bindingContext)) {
|
if (expressionToBeReplaced.isUsedAsExpression(bindingContext)) {
|
||||||
val thisReplaced = codeToInline.collectDescendantsOfType<KtExpression> { it[RECEIVER_VALUE_KEY] }
|
val thisReplaced = codeToInline.collectDescendantsOfType<KtExpression> { it[RECEIVER_VALUE_KEY] }
|
||||||
codeToInline.introduceValue(receiver, receiverType, thisReplaced, expressionToBeReplaced, safeCall = true)
|
codeToInline.introduceValue(receiver, receiverType, thisReplaced, expressionToBeReplaced, safeCall = true)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val ifExpression = psiFactory.buildExpression {
|
val ifExpression = psiFactory.buildExpression {
|
||||||
appendFixedText("if (")
|
appendFixedText("if (")
|
||||||
appendExpression(receiver)
|
appendExpression(receiver)
|
||||||
@@ -311,13 +316,21 @@ class CodeInliner<TCallElement : KtElement>(
|
|||||||
return when (this) {
|
return when (this) {
|
||||||
is KtSimpleNameExpression -> false
|
is KtSimpleNameExpression -> false
|
||||||
is KtQualifiedExpression -> receiverExpression.shouldKeepValue(usageCount) || selectorExpression.shouldKeepValue(usageCount)
|
is KtQualifiedExpression -> receiverExpression.shouldKeepValue(usageCount) || selectorExpression.shouldKeepValue(usageCount)
|
||||||
is KtUnaryExpression -> operationToken in setOf(KtTokens.PLUSPLUS, KtTokens.MINUSMINUS) || baseExpression.shouldKeepValue(usageCount)
|
is KtUnaryExpression -> operationToken in setOf(KtTokens.PLUSPLUS, KtTokens.MINUSMINUS) || baseExpression.shouldKeepValue(
|
||||||
|
usageCount
|
||||||
|
)
|
||||||
is KtStringTemplateExpression -> entries.any { if (sideEffectOnly) it.expression.shouldKeepValue(usageCount) else it is KtStringTemplateEntryWithExpression }
|
is KtStringTemplateExpression -> entries.any { if (sideEffectOnly) it.expression.shouldKeepValue(usageCount) else it is KtStringTemplateEntryWithExpression }
|
||||||
is KtThisExpression, is KtSuperExpression, is KtConstantExpression -> false
|
is KtThisExpression, is KtSuperExpression, is KtConstantExpression -> false
|
||||||
is KtParenthesizedExpression -> expression.shouldKeepValue(usageCount)
|
is KtParenthesizedExpression -> expression.shouldKeepValue(usageCount)
|
||||||
is KtArrayAccessExpression -> if (sideEffectOnly) arrayExpression.shouldKeepValue(usageCount) || indexExpressions.any { it.shouldKeepValue(usageCount) } else true
|
is KtArrayAccessExpression -> if (sideEffectOnly) arrayExpression.shouldKeepValue(usageCount) || indexExpressions.any {
|
||||||
|
it.shouldKeepValue(
|
||||||
|
usageCount
|
||||||
|
)
|
||||||
|
} else true
|
||||||
is KtBinaryExpression -> if (sideEffectOnly) left.shouldKeepValue(usageCount) || right.shouldKeepValue(usageCount) else true
|
is KtBinaryExpression -> if (sideEffectOnly) left.shouldKeepValue(usageCount) || right.shouldKeepValue(usageCount) else true
|
||||||
is KtIfExpression -> if (sideEffectOnly) condition.shouldKeepValue(usageCount) || then.shouldKeepValue(usageCount) || `else`.shouldKeepValue(usageCount) else true
|
is KtIfExpression -> if (sideEffectOnly) condition.shouldKeepValue(usageCount) || then.shouldKeepValue(usageCount) || `else`.shouldKeepValue(
|
||||||
|
usageCount
|
||||||
|
) else true
|
||||||
is KtBinaryExpressionWithTypeRHS -> true
|
is KtBinaryExpressionWithTypeRHS -> true
|
||||||
null -> false
|
null -> false
|
||||||
else -> true
|
else -> true
|
||||||
@@ -325,17 +338,18 @@ class CodeInliner<TCallElement : KtElement>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class Argument(
|
private class Argument(
|
||||||
val expression: KtExpression,
|
val expression: KtExpression,
|
||||||
val expressionType: KotlinType?,
|
val expressionType: KotlinType?,
|
||||||
val isNamed: Boolean = false,
|
val isNamed: Boolean = false,
|
||||||
val isDefaultValue: Boolean = false)
|
val isDefaultValue: Boolean = false
|
||||||
|
)
|
||||||
|
|
||||||
private fun argumentForParameter(parameter: ValueParameterDescriptor, callableDescriptor: CallableDescriptor): Argument? {
|
private fun argumentForParameter(parameter: ValueParameterDescriptor, callableDescriptor: CallableDescriptor): Argument? {
|
||||||
if (callableDescriptor is PropertySetterDescriptor) {
|
if (callableDescriptor is PropertySetterDescriptor) {
|
||||||
val valueAssigned = (callElement as? KtExpression)
|
val valueAssigned = (callElement as? KtExpression)
|
||||||
?.getQualifiedExpressionForSelectorOrThis()
|
?.getQualifiedExpressionForSelectorOrThis()
|
||||||
?.getAssignmentByLHS()
|
?.getAssignmentByLHS()
|
||||||
?.right ?: return null
|
?.right ?: return null
|
||||||
return Argument(valueAssigned, bindingContext.getType(valueAssigned))
|
return Argument(valueAssigned, bindingContext.getType(valueAssigned))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,8 +433,7 @@ class CodeInliner<TCallElement : KtElement>(
|
|||||||
val shortenFilter = { element: PsiElement ->
|
val shortenFilter = { element: PsiElement ->
|
||||||
if (element[USER_CODE_KEY]) {
|
if (element[USER_CODE_KEY]) {
|
||||||
ShortenReferences.FilterResult.SKIP
|
ShortenReferences.FilterResult.SKIP
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val thisReceiver = (element as? KtQualifiedExpression)?.receiverExpression as? KtThisExpression
|
val thisReceiver = (element as? KtQualifiedExpression)?.receiverExpression as? KtThisExpression
|
||||||
if (thisReceiver != null && thisReceiver[USER_CODE_KEY]) // don't remove explicit 'this' coming from user's code
|
if (thisReceiver != null && thisReceiver[USER_CODE_KEY]) // don't remove explicit 'this' coming from user's code
|
||||||
ShortenReferences.FilterResult.GO_INSIDE
|
ShortenReferences.FilterResult.GO_INSIDE
|
||||||
@@ -430,7 +443,7 @@ class CodeInliner<TCallElement : KtElement>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val newElements = elements.map {
|
val newElements = elements.map {
|
||||||
ShortenReferences({ ShortenReferences.Options(removeThis = true) }).process(it, shortenFilter)
|
ShortenReferences { ShortenReferences.Options(removeThis = true) }.process(it, shortenFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
newElements.forEach {
|
newElements.forEach {
|
||||||
@@ -556,8 +569,7 @@ class CodeInliner<TCallElement : KtElement>(
|
|||||||
val list = parent as KtValueArgumentList
|
val list = parent as KtValueArgumentList
|
||||||
if (arguments.isEmpty()) {
|
if (arguments.isEmpty()) {
|
||||||
list.removeArgument(this)
|
list.removeArgument(this)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
var anchor = this
|
var anchor = this
|
||||||
for (argument in arguments) {
|
for (argument in arguments) {
|
||||||
anchor = list.addArgumentAfter(argument, anchor)
|
anchor = list.addArgumentAfter(argument, anchor)
|
||||||
@@ -569,7 +581,7 @@ class CodeInliner<TCallElement : KtElement>(
|
|||||||
private fun restoreFunctionLiteralArguments(expression: KtElement) {
|
private fun restoreFunctionLiteralArguments(expression: KtElement) {
|
||||||
val callExpressions = ArrayList<KtCallExpression>()
|
val callExpressions = ArrayList<KtCallExpression>()
|
||||||
|
|
||||||
expression.forEachDescendantOfType<KtExpression>(fun (expr) {
|
expression.forEachDescendantOfType<KtExpression>(fun(expr) {
|
||||||
if (!expr[WAS_FUNCTION_LITERAL_ARGUMENT_KEY]) return
|
if (!expr[WAS_FUNCTION_LITERAL_ARGUMENT_KEY]) return
|
||||||
assert(expr.unpackFunctionLiteral() != null)
|
assert(expr.unpackFunctionLiteral() != null)
|
||||||
|
|
||||||
@@ -592,24 +604,26 @@ class CodeInliner<TCallElement : KtElement>(
|
|||||||
callExpressions.forEach { it.moveFunctionLiteralOutsideParentheses() }
|
callExpressions.forEach { it.moveFunctionLiteralOutsideParentheses() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private operator fun <T: Any> PsiElement.get(key: Key<T>): T? = getCopyableUserData(key)
|
private operator fun <T : Any> PsiElement.get(key: Key<T>): T? = getCopyableUserData(key)
|
||||||
private operator fun PsiElement.get(key: Key<Unit>): Boolean = getCopyableUserData(key) != null
|
private operator fun PsiElement.get(key: Key<Unit>): Boolean = getCopyableUserData(key) != null
|
||||||
private fun <T: Any> KtElement.clear(key: Key<T>) = putCopyableUserData(key, null)
|
private fun <T : Any> KtElement.clear(key: Key<T>) = putCopyableUserData(key, null)
|
||||||
private fun <T: Any> KtElement.put(key: Key<T>, value: T) = putCopyableUserData(key, value)
|
private fun <T : Any> KtElement.put(key: Key<T>, value: T) = putCopyableUserData(key, value)
|
||||||
private fun KtElement.mark(key: Key<Unit>) = putCopyableUserData(key, Unit)
|
private fun KtElement.mark(key: Key<Unit>) = putCopyableUserData(key, Unit)
|
||||||
|
|
||||||
private fun <T: KtElement> T.marked(key: Key<Unit>): T {
|
private fun <T : KtElement> T.marked(key: Key<Unit>): T {
|
||||||
putCopyableUserData(key, Unit)
|
putCopyableUserData(key, Unit)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
// keys below are used on expressions
|
companion object {
|
||||||
private val USER_CODE_KEY = Key<Unit>("USER_CODE")
|
// keys below are used on expressions
|
||||||
private val PARAMETER_VALUE_KEY = Key<ValueParameterDescriptor>("PARAMETER_VALUE")
|
private val USER_CODE_KEY = Key<Unit>("USER_CODE")
|
||||||
private val RECEIVER_VALUE_KEY = Key<Unit>("RECEIVER_VALUE")
|
private val PARAMETER_VALUE_KEY = Key<ValueParameterDescriptor>("PARAMETER_VALUE")
|
||||||
private val WAS_FUNCTION_LITERAL_ARGUMENT_KEY = Key<Unit>("WAS_FUNCTION_LITERAL_ARGUMENT")
|
private val RECEIVER_VALUE_KEY = Key<Unit>("RECEIVER_VALUE")
|
||||||
|
private val WAS_FUNCTION_LITERAL_ARGUMENT_KEY = Key<Unit>("WAS_FUNCTION_LITERAL_ARGUMENT")
|
||||||
|
|
||||||
// these keys are used on KtValueArgument
|
// these keys are used on KtValueArgument
|
||||||
private val MAKE_ARGUMENT_NAMED_KEY = Key<Unit>("MAKE_ARGUMENT_NAMED")
|
private val MAKE_ARGUMENT_NAMED_KEY = Key<Unit>("MAKE_ARGUMENT_NAMED")
|
||||||
private val DEFAULT_PARAMETER_VALUE_KEY = Key<Unit>("DEFAULT_PARAMETER_VALUE")
|
private val DEFAULT_PARAMETER_VALUE_KEY = Key<Unit>("DEFAULT_PARAMETER_VALUE")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user