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