Reformat & cleanup: CodeInliner

This commit is contained in:
Mikhail Glukhikh
2018-05-23 12:02:00 +03:00
parent 2d7e274860
commit bb8c3495b8
@@ -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")
}
}