This commit is contained in:
Valentin Kipyatkov
2016-10-25 13:12:33 +03:00
parent 4c4c85e37a
commit e5748f7a86
17 changed files with 105 additions and 105 deletions
+1 -1
View File
@@ -44,13 +44,13 @@
<module fileurl="file://$PROJECT_DIR$/idea/idea-analysis/idea-analysis.iml" filepath="$PROJECT_DIR$/idea/idea-analysis/idea-analysis.iml" group="ide" />
<module fileurl="file://$PROJECT_DIR$/idea/idea-android/idea-android.iml" filepath="$PROJECT_DIR$/idea/idea-android/idea-android.iml" group="ide" />
<module fileurl="file://$PROJECT_DIR$/idea/idea-android/idea-android-output-parser/idea-android-output-parser.iml" filepath="$PROJECT_DIR$/idea/idea-android/idea-android-output-parser/idea-android-output-parser.iml" group="ide" />
<module fileurl="file://$PROJECT_DIR$/idea/idea-code-inliner/idea-replacement-engine.iml" filepath="$PROJECT_DIR$/idea/idea-code-inliner/idea-replacement-engine.iml" group="ide" />
<module fileurl="file://$PROJECT_DIR$/idea/idea-completion/idea-completion.iml" filepath="$PROJECT_DIR$/idea/idea-completion/idea-completion.iml" group="ide" />
<module fileurl="file://$PROJECT_DIR$/idea/idea-core/idea-core.iml" filepath="$PROJECT_DIR$/idea/idea-core/idea-core.iml" group="ide" />
<module fileurl="file://$PROJECT_DIR$/idea/idea-jps-common/idea-jps-common.iml" filepath="$PROJECT_DIR$/idea/idea-jps-common/idea-jps-common.iml" group="ide" />
<module fileurl="file://$PROJECT_DIR$/idea/idea-live-templates/idea-live-templates.iml" filepath="$PROJECT_DIR$/idea/idea-live-templates/idea-live-templates.iml" group="ide" />
<module fileurl="file://$PROJECT_DIR$/idea/idea-maven/idea-maven.iml" filepath="$PROJECT_DIR$/idea/idea-maven/idea-maven.iml" group="ide" />
<module fileurl="file://$PROJECT_DIR$/idea/idea-repl/idea-repl.iml" filepath="$PROJECT_DIR$/idea/idea-repl/idea-repl.iml" group="ide" />
<module fileurl="file://$PROJECT_DIR$/idea/idea-replacement-engine/idea-replacement-engine.iml" filepath="$PROJECT_DIR$/idea/idea-replacement-engine/idea-replacement-engine.iml" group="ide" />
<module fileurl="file://$PROJECT_DIR$/idea-runner/idea-runner.iml" filepath="$PROJECT_DIR$/idea-runner/idea-runner.iml" group="ide" />
<module fileurl="file://$PROJECT_DIR$/idea/idea-test-framework/idea-test-framework.iml" filepath="$PROJECT_DIR$/idea/idea-test-framework/idea-test-framework.iml" group="ide" />
<module fileurl="file://$PROJECT_DIR$/compiler/preloader/instrumentation/instrumentation.iml" filepath="$PROJECT_DIR$/compiler/preloader/instrumentation/instrumentation.iml" group="compiler/cli" />
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.replacement
package org.jetbrains.kotlin.idea.inliner
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class CallableUsageReplacementStrategy(
private val replacement: ReplacementCode
private val replacement: CodeToInline
) : UsageReplacementStrategy {
override fun createReplacer(usage: KtSimpleNameExpression): (() -> KtElement?)? {
@@ -44,7 +44,7 @@ class CallableUsageReplacementStrategy(
createReplacer(nameExpression)!!.invoke()
}
else {
CallReplacementEngine(usage, bindingContext, resolvedCall, callElement, replacement).performReplacement()
CodeInliner(usage, bindingContext, resolvedCall, callElement, replacement).doInline()
}
}
}
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.replacement
package org.jetbrains.kotlin.idea.inliner
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.idea.core.ShortenReferences
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.check
class ClassUsageReplacementStrategy(
typeReplacement: KtUserType?,
constructorReplacement: ReplacementCode?,
constructorReplacement: CodeToInline?,
project: Project
) : UsageReplacementStrategy {
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.replacement
package org.jetbrains.kotlin.idea.inliner
import com.intellij.openapi.util.Key
import com.intellij.psi.PsiElement
@@ -45,18 +45,18 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.*
class CallReplacementEngine<TCallElement : KtElement>(
class CodeInliner<TCallElement : KtElement>(
private val nameExpression: KtSimpleNameExpression,
private val bindingContext: BindingContext,
private val resolvedCall: ResolvedCall<out CallableDescriptor>,
private val callElement: TCallElement,
replacement: ReplacementCode
codeToInline: CodeToInline
) {
private val replacement = replacement.toMutable()
private val codeToInline = codeToInline.toMutable()
private val project = nameExpression.project
private val psiFactory = KtPsiFactory(project)
fun performReplacement(): KtElement? {
fun doInline(): KtElement? {
val descriptor = resolvedCall.resultingDescriptor
val file = nameExpression.getContainingKtFile()
@@ -82,9 +82,9 @@ class CallReplacementEngine<TCallElement : KtElement>(
receiver?.mark(RECEIVER_VALUE_KEY)
//TODO: this@
for (thisExpression in replacement.collectDescendantsOfType<KtThisExpression>()) {
for (thisExpression in codeToInline.collectDescendantsOfType<KtThisExpression>()) {
if (receiver != null) {
replacement.replaceExpression(thisExpression, receiver)
codeToInline.replaceExpression(thisExpression, receiver)
}
else {
thisExpression.mark(RECEIVER_VALUE_KEY)
@@ -104,25 +104,25 @@ class CallReplacementEngine<TCallElement : KtElement>(
if (elementToBeReplaced is KtExpression) {
if (receiver != null) {
val thisReplaced = replacement.collectDescendantsOfType<KtExpression> { it[RECEIVER_VALUE_KEY] }
val thisReplaced = codeToInline.collectDescendantsOfType<KtExpression> { it[RECEIVER_VALUE_KEY] }
if (receiver.shouldKeepValue(thisReplaced.size)) {
replacement.introduceValue(receiver, receiverType, thisReplaced, elementToBeReplaced)
codeToInline.introduceValue(receiver, receiverType, thisReplaced, elementToBeReplaced)
}
}
for ((parameter, value, valueType) in introduceValuesForParameters) {
val usagesReplaced = replacement.collectDescendantsOfType<KtExpression> { it[PARAMETER_VALUE_KEY] == parameter }
replacement.introduceValue(value, valueType, usagesReplaced, elementToBeReplaced, nameSuggestion = parameter.name.asString())
val usagesReplaced = codeToInline.collectDescendantsOfType<KtExpression> { it[PARAMETER_VALUE_KEY] == parameter }
codeToInline.introduceValue(value, valueType, usagesReplaced, elementToBeReplaced, nameSuggestion = parameter.name.asString())
}
}
replacement.fqNamesToImport
codeToInline.fqNamesToImport
.flatMap { file.resolveImportReference(it) }
.forEach { ImportInsertHelper.getInstance(project).importDescriptor(file, it) }
val replacementPerformer = when (elementToBeReplaced) {
is KtExpression -> ExpressionReplacementPerformer(replacement, elementToBeReplaced)
is KtAnnotationEntry -> AnnotationEntryReplacementPerformer(replacement, elementToBeReplaced)
is KtExpression -> ExpressionReplacementPerformer(codeToInline, elementToBeReplaced)
is KtAnnotationEntry -> AnnotationEntryReplacementPerformer(codeToInline, elementToBeReplaced)
else -> error("Unsupported element")
}
@@ -146,8 +146,8 @@ class CallReplacementEngine<TCallElement : KtElement>(
argument.expression.put(PARAMETER_VALUE_KEY, parameter)
val parameterName = parameter.name
val usages = replacement.collectDescendantsOfType<KtExpression> {
it[ReplacementCode.PARAMETER_USAGE_KEY] == parameterName
val usages = codeToInline.collectDescendantsOfType<KtExpression> {
it[CodeToInline.PARAMETER_USAGE_KEY] == parameterName
}
usages.forEach {
val usageArgument = it.parent as? KtValueArgument
@@ -157,7 +157,7 @@ class CallReplacementEngine<TCallElement : KtElement>(
if (argument.isDefaultValue) {
usageArgument?.mark(DEFAULT_PARAMETER_VALUE_KEY)
}
replacement.replaceExpression(it, argument.expression)
codeToInline.replaceExpression(it, argument.expression)
}
//TODO: sometimes we need to add explicit type arguments here because we don't have expected type in the new context
@@ -185,8 +185,8 @@ class CallReplacementEngine<TCallElement : KtElement>(
for ((index, typeParameter) in typeParameters.withIndex()) {
val parameterName = typeParameter.name
val usages = replacement.collectDescendantsOfType<KtExpression> {
it[ReplacementCode.TYPE_PARAMETER_USAGE_KEY] == parameterName
val usages = codeToInline.collectDescendantsOfType<KtExpression> {
it[CodeToInline.TYPE_PARAMETER_USAGE_KEY] == parameterName
}
val type = resolvedCall.typeArguments[typeParameter]!!
@@ -207,7 +207,7 @@ class CallReplacementEngine<TCallElement : KtElement>(
val arguments =
if (typeElement is KtUserType && KotlinBuiltIns.isArray(type)) typeElement.typeArgumentList?.text.orEmpty()
else ""
replacement.replaceExpression(usage, psiFactory.createExpression(
codeToInline.replaceExpression(usage, psiFactory.createExpression(
IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(typeClassifier) + arguments
))
}
@@ -216,21 +216,21 @@ class CallReplacementEngine<TCallElement : KtElement>(
}
else {
//TODO: tests for this?
replacement.replaceExpression(usage, psiFactory.createExpression(typeElement.text))
codeToInline.replaceExpression(usage, psiFactory.createExpression(typeElement.text))
}
}
}
}
private fun wrapCodeForSafeCall(receiver: KtExpression, receiverType: KotlinType?, expressionToBeReplaced: KtExpression) {
if (replacement.statementsBefore.isEmpty()) {
val qualified = replacement.mainExpression as? KtQualifiedExpression
if (codeToInline.statementsBefore.isEmpty()) {
val qualified = codeToInline.mainExpression as? KtQualifiedExpression
if (qualified != null) {
if (qualified.receiverExpression[RECEIVER_VALUE_KEY]) {
if (qualified is KtSafeQualifiedExpression) return // already safe
val selector = qualified.selectorExpression
if (selector != null) {
replacement.mainExpression = psiFactory.createExpressionByPattern("$0?.$1", receiver, selector)
codeToInline.mainExpression = psiFactory.createExpressionByPattern("$0?.$1", receiver, selector)
return
}
}
@@ -238,32 +238,32 @@ class CallReplacementEngine<TCallElement : KtElement>(
}
if (expressionToBeReplaced.isUsedAsExpression(bindingContext)) {
val thisReplaced = replacement.collectDescendantsOfType<KtExpression> { it[RECEIVER_VALUE_KEY] }
replacement.introduceValue(receiver, receiverType, thisReplaced, expressionToBeReplaced, safeCall = true)
val thisReplaced = codeToInline.collectDescendantsOfType<KtExpression> { it[RECEIVER_VALUE_KEY] }
codeToInline.introduceValue(receiver, receiverType, thisReplaced, expressionToBeReplaced, safeCall = true)
}
else {
val ifExpression = psiFactory.buildExpression {
appendFixedText("if (")
appendExpression(receiver)
appendFixedText("!=null) {")
replacement.statementsBefore.forEach {
codeToInline.statementsBefore.forEach {
appendExpression(it)
appendFixedText("\n")
}
replacement.mainExpression?.let {
codeToInline.mainExpression?.let {
appendExpression(it)
appendFixedText("\n")
}
appendFixedText("}")
}
replacement.mainExpression = ifExpression
replacement.statementsBefore.clear()
codeToInline.mainExpression = ifExpression
codeToInline.statementsBefore.clear()
}
}
private fun keepInfixFormIfPossible() {
if (replacement.statementsBefore.isNotEmpty()) return
val dotQualified = replacement.mainExpression as? KtDotQualifiedExpression ?: return
if (codeToInline.statementsBefore.isNotEmpty()) return
val dotQualified = codeToInline.mainExpression as? KtDotQualifiedExpression ?: return
val receiver = dotQualified.receiverExpression
if (!receiver[RECEIVER_VALUE_KEY]) return
val call = dotQualified.selectorExpression as? KtCallExpression ?: return
@@ -271,7 +271,7 @@ class CallReplacementEngine<TCallElement : KtElement>(
val argument = call.valueArguments.singleOrNull() ?: return
if (argument.getArgumentName() != null) return
val argumentExpression = argument.getArgumentExpression() ?: return
replacement.mainExpression = psiFactory.createExpressionByPattern("$0 ${nameExpression.text} $1", receiver, argumentExpression)
codeToInline.mainExpression = psiFactory.createExpressionByPattern("$0 ${nameExpression.text} $1", receiver, argumentExpression)
}
private fun KtExpression?.shouldKeepValue(usageCount: Int): Boolean {
@@ -317,13 +317,13 @@ class CallReplacementEngine<TCallElement : KtElement>(
val (expression, parameterUsages) = defaultValue
for ((param, usages) in parameterUsages) {
usages.forEach { it.put(ReplacementCode.PARAMETER_USAGE_KEY, param.name) }
usages.forEach { it.put(CodeToInline.PARAMETER_USAGE_KEY, param.name) }
}
val expressionCopy = expression.copied()
// clean up user data in original
expression.forEachDescendantOfType<KtExpression> { it.clear(ReplacementCode.PARAMETER_USAGE_KEY) }
expression.forEachDescendantOfType<KtExpression> { it.clear(CodeToInline.PARAMETER_USAGE_KEY) }
return Argument(expressionCopy, null/*TODO*/, isDefaultValue = true)
}
@@ -395,8 +395,8 @@ class CallReplacementEngine<TCallElement : KtElement>(
// clean up user data
it.forEachDescendantOfType<KtExpression> {
it.clear(USER_CODE_KEY)
it.clear(ReplacementCode.PARAMETER_USAGE_KEY)
it.clear(ReplacementCode.TYPE_PARAMETER_USAGE_KEY)
it.clear(CodeToInline.PARAMETER_USAGE_KEY)
it.clear(CodeToInline.TYPE_PARAMETER_USAGE_KEY)
it.clear(PARAMETER_VALUE_KEY)
it.clear(RECEIVER_VALUE_KEY)
it.clear(WAS_FUNCTION_LITERAL_ARGUMENT_KEY)
@@ -14,25 +14,25 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.replacement
package org.jetbrains.kotlin.idea.inliner
import com.intellij.openapi.util.Key
import org.jetbrains.kotlin.idea.replacement.ReplacementCode.Companion.PARAMETER_USAGE_KEY
import org.jetbrains.kotlin.idea.replacement.ReplacementCode.Companion.TYPE_PARAMETER_USAGE_KEY
import org.jetbrains.kotlin.idea.inliner.CodeToInline.Companion.PARAMETER_USAGE_KEY
import org.jetbrains.kotlin.idea.inliner.CodeToInline.Companion.TYPE_PARAMETER_USAGE_KEY
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtExpression
/**
* Represents an expression to replace usages of particular callable.
* Represents code to be inlined to replace usages of particular callable.
* The expression should be preprocessed in the following way:
* * Type arguments for all calls should be made explicit
* * All external symbols to be imported should be either referenced via fully-qualified form or included into [fqNamesToImport]
* * All usages of value parameters (of our callable) should be marked with [PARAMETER_USAGE_KEY] copyable user data (holds the name of the corresponding parameter)
* * All usages of type parameters (of our callable) should be marked with [TYPE_PARAMETER_USAGE_KEY] copyable user data (holds the name of the corresponding type parameter)
* Use [ReplacementBuilder.buildReplacementCode].
* Use [CodeToInlineBuilder.prepareCodeToInline].
*/
class ReplacementCode(
class CodeToInline(
val mainExpression: KtExpression?,
val statementsBefore: List<KtExpression>,
val fqNamesToImport: Collection<FqName>
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.replacement
package org.jetbrains.kotlin.idea.inliner
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
@@ -36,21 +36,21 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
import java.util.*
class ReplacementBuilder(
class CodeToInlineBuilder(
private val targetCallable: CallableDescriptor,
private val resolutionFacade: ResolutionFacade
) {
private val psiFactory = KtPsiFactory(resolutionFacade.project)
fun buildReplacementCode(
fun prepareCodeToInline(
mainExpression: KtExpression?,
statementsBefore: List<KtExpression>,
analyze: () -> BindingContext,
importFqNames: Collection<FqName> = emptyList()
): ReplacementCode {
): CodeToInline {
var bindingContext = analyze()
val result = MutableReplacementCode(mainExpression, statementsBefore.toMutableList(), importFqNames.toMutableSet())
val result = MutableCodeToInline(mainExpression, statementsBefore.toMutableList(), importFqNames.toMutableSet())
val typeArgsToAdd = ArrayList<Pair<KtCallExpression, KtTypeArgumentList>>()
result.forEachDescendantOfType<KtCallExpression> {
@@ -80,10 +80,10 @@ class ReplacementBuilder(
if (expression.getReceiverExpression() == null) {
if (target is ValueParameterDescriptor && target.containingDeclaration == targetCallable) {
expression.putCopyableUserData(ReplacementCode.PARAMETER_USAGE_KEY, target.name)
expression.putCopyableUserData(CodeToInline.PARAMETER_USAGE_KEY, target.name)
}
else if (target is TypeParameterDescriptor && target.containingDeclaration == targetCallable) {
expression.putCopyableUserData(ReplacementCode.TYPE_PARAMETER_USAGE_KEY, target.name)
expression.putCopyableUserData(CodeToInline.TYPE_PARAMETER_USAGE_KEY, target.name)
}
val resolvedCall = expression.getResolvedCall(bindingContext)
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.replacement
package org.jetbrains.kotlin.idea.inliner
import com.intellij.openapi.util.Key
import com.intellij.psi.PsiElement
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
private val POST_INSERTION_ACTION: Key<(KtElement) -> Unit> = Key("POST_INSERTION_ACTION")
internal class MutableReplacementCode(
internal class MutableCodeToInline(
var mainExpression: KtExpression?,
val statementsBefore: MutableList<KtExpression>,
val fqNamesToImport: MutableCollection<FqName>
@@ -81,22 +81,22 @@ internal class MutableReplacementCode(
}
}
internal fun ReplacementCode.toMutable(): MutableReplacementCode {
return MutableReplacementCode(
internal fun CodeToInline.toMutable(): MutableCodeToInline {
return MutableCodeToInline(
mainExpression?.copied(),
statementsBefore.map { it.copied() }.toMutableList(),
fqNamesToImport.toMutableSet())
}
internal fun MutableReplacementCode.toNonMutable(): ReplacementCode {
return ReplacementCode(mainExpression, statementsBefore, fqNamesToImport)
internal fun MutableCodeToInline.toNonMutable(): CodeToInline {
return CodeToInline(mainExpression, statementsBefore, fqNamesToImport)
}
internal inline fun <reified T : PsiElement> MutableReplacementCode.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) }
}
internal inline fun <reified T : PsiElement> MutableReplacementCode.forEachDescendantOfType(noinline action: (T) -> Unit) {
internal inline fun <reified T : PsiElement> MutableCodeToInline.forEachDescendantOfType(noinline action: (T) -> Unit) {
expressions.forEach { it.forEachDescendantOfType<T>(action) }
}
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.replacement
package org.jetbrains.kotlin.idea.inliner
import com.intellij.openapi.util.Key
import org.jetbrains.kotlin.idea.caches.resolve.analyze
@@ -31,7 +31,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
import java.util.*
internal abstract class ReplacementPerformer<TElement : KtElement>(
protected val replacement: MutableReplacementCode,
protected val codeToInline: MutableCodeToInline,
protected var elementToBeReplaced: TElement
) {
protected val psiFactory = KtPsiFactory(elementToBeReplaced)
@@ -40,18 +40,18 @@ internal abstract class ReplacementPerformer<TElement : KtElement>(
}
internal class AnnotationEntryReplacementPerformer(
replacement: MutableReplacementCode,
codeToInline: MutableCodeToInline,
elementToBeReplaced: KtAnnotationEntry
) : ReplacementPerformer<KtAnnotationEntry>(replacement, elementToBeReplaced) {
) : ReplacementPerformer<KtAnnotationEntry>(codeToInline, elementToBeReplaced) {
override fun doIt(postProcessing: (PsiChildRange) -> PsiChildRange): KtAnnotationEntry {
assert(replacement.mainExpression != null)
assert(replacement.statementsBefore.isEmpty())
assert(codeToInline.mainExpression != null)
assert(codeToInline.statementsBefore.isEmpty())
val dummyAnnotationEntry = createByPattern("@Dummy($0)", replacement.mainExpression!!) { psiFactory.createAnnotationEntry(it) }
val dummyAnnotationEntry = createByPattern("@Dummy($0)", codeToInline.mainExpression!!) { psiFactory.createAnnotationEntry(it) }
val replaced = elementToBeReplaced.replace(dummyAnnotationEntry)
replacement.performPostInsertionActions(replaced.singletonList())
codeToInline.performPostInsertionActions(replaced.singletonList())
var range = PsiChildRange.singleElement(replaced)
range = postProcessing(range)
@@ -65,13 +65,13 @@ internal class AnnotationEntryReplacementPerformer(
}
internal class ExpressionReplacementPerformer(
replacement: MutableReplacementCode,
codeToInline: MutableCodeToInline,
expressionToBeReplaced: KtExpression
) : ReplacementPerformer<KtExpression>(replacement, expressionToBeReplaced) {
) : ReplacementPerformer<KtExpression>(codeToInline, expressionToBeReplaced) {
override fun doIt(postProcessing: (PsiChildRange) -> PsiChildRange): KtExpression? {
val insertedStatements = ArrayList<KtExpression>()
for (statement in replacement.statementsBefore) {
for (statement in codeToInline.statementsBefore) {
// copy the statement if it can get invalidated by findOrCreateBlockToInsertStatement()
val statementToUse = if (statement.isPhysical) statement.copy() else statement
val anchor = findOrCreateBlockToInsertStatement()
@@ -83,8 +83,8 @@ internal class ExpressionReplacementPerformer(
insertedStatements.add(inserted)
}
val replaced = if (replacement.mainExpression != null) {
elementToBeReplaced.replace(replacement.mainExpression!!)
val replaced = if (codeToInline.mainExpression != null) {
elementToBeReplaced.replace(codeToInline.mainExpression!!)
}
else {
val bindingContext = elementToBeReplaced.analyze(BodyResolveMode.FULL)
@@ -98,7 +98,7 @@ internal class ExpressionReplacementPerformer(
}
}
replacement.performPostInsertionActions(insertedStatements + replaced.singletonOrEmptyList())
codeToInline.performPostInsertionActions(insertedStatements + replaced.singletonOrEmptyList())
var range = if (replaced != null) {
if (insertedStatements.isEmpty()) {
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.replacement
package org.jetbrains.kotlin.idea.inliner
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.progress.ProgressIndicator
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.replacement
package org.jetbrains.kotlin.idea.inliner
import org.jetbrains.kotlin.idea.analysis.computeTypeInContext
import org.jetbrains.kotlin.idea.caches.resolve.analyze
@@ -38,17 +38,17 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.addToStdlib.check
/**
* Modifies [MutableReplacementCode] introducing a variable initialized by [value] and replacing all of [usages] with its use.
* The variable must be initialized (and so the value is calculated) before any other code in [MutableReplacementCode].
* Modifies [MutableCodeToInline] introducing a variable initialized by [value] and replacing all of [usages] with its use.
* The variable must be initialized (and so the value is calculated) before any other code in [MutableCodeToInline].
* @param value Value to use for variable initialization
* @param valueType Type of the value
* @param usages Usages to be replaced. This collection can be empty and in this case the actual variable is not needed.
* But the expression [value] must be calculated because it may have side effects.
* @param expressionToBeReplaced Expression to be replaced by the [MutableReplacementCode].
* @param expressionToBeReplaced Expression to be replaced by the [MutableCodeToInline].
* @param nameSuggestion Name suggestion for the variable.
* @param safeCall If true, then the whole code must not be executed if the [value] evaluates to null.
*/
internal fun MutableReplacementCode.introduceValue(
internal fun MutableCodeToInline.introduceValue(
value: KtExpression,
valueType: KotlinType?,
usages: Collection<KtExpression>,
@@ -151,7 +151,7 @@ private fun variableNeedsExplicitType(
return valueTypeWithoutExpectedType == null || ErrorUtils.containsErrorType(valueTypeWithoutExpectedType)
}
private fun collectNameUsages(scope: MutableReplacementCode, name: String): List<KtSimpleNameExpression> {
private fun collectNameUsages(scope: MutableCodeToInline, name: String): List<KtSimpleNameExpression> {
return scope.expressions.flatMap { expression ->
expression.collectDescendantsOfType<KtSimpleNameExpression> { it.getReceiverExpression() == null && it.getReferencedName() == name }
}
+1 -1
View File
@@ -55,6 +55,6 @@
<orderEntry type="module" module-name="formatter" />
<orderEntry type="module" module-name="idea-maven" />
<orderEntry type="library" scope="TEST" name="native-platform-uberjar" level="project" />
<orderEntry type="module" module-name="idea-replacement-engine" />
<orderEntry type="module" module-name="idea-code-inliner" />
</component>
</module>
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.idea.core.moveCaret
import org.jetbrains.kotlin.idea.core.targetDescriptors
import org.jetbrains.kotlin.idea.quickfix.CleanupFix
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
import org.jetbrains.kotlin.idea.replacement.UsageReplacementStrategy
import org.jetbrains.kotlin.idea.inliner.UsageReplacementStrategy
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
@@ -31,9 +31,9 @@ import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.core.OptionalParametersHelper
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.replacement.CallableUsageReplacementStrategy
import org.jetbrains.kotlin.idea.replacement.ClassUsageReplacementStrategy
import org.jetbrains.kotlin.idea.replacement.UsageReplacementStrategy
import org.jetbrains.kotlin.idea.inliner.CallableUsageReplacementStrategy
import org.jetbrains.kotlin.idea.inliner.ClassUsageReplacementStrategy
import org.jetbrains.kotlin.idea.inliner.UsageReplacementStrategy
import org.jetbrains.kotlin.psi.KtConstructorCalleeExpression
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
@@ -23,8 +23,8 @@ import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.replacement.UsageReplacementStrategy
import org.jetbrains.kotlin.idea.replacement.replaceUsagesInWholeProject
import org.jetbrains.kotlin.idea.inliner.UsageReplacementStrategy
import org.jetbrains.kotlin.idea.inliner.replaceUsagesInWholeProject
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.renderer.ClassifierNamePolicy
import org.jetbrains.kotlin.renderer.DescriptorRenderer
@@ -21,8 +21,8 @@ import org.jetbrains.kotlin.idea.analysis.analyzeInContext
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.replacement.ReplacementBuilder
import org.jetbrains.kotlin.idea.replacement.ReplacementCode
import org.jetbrains.kotlin.idea.inliner.CodeToInlineBuilder
import org.jetbrains.kotlin.idea.inliner.CodeToInline
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.name.FqName
@@ -50,7 +50,7 @@ object ReplaceWithAnnotationAnalyzer {
annotation: ReplaceWith,
symbolDescriptor: CallableDescriptor,
resolutionFacade: ResolutionFacade
): ReplacementCode? {
): CodeToInline? {
val originalDescriptor = (if (symbolDescriptor is CallableMemberDescriptor)
DescriptorUtils.unwrapFakeOverride(symbolDescriptor)
else
@@ -62,7 +62,7 @@ object ReplaceWithAnnotationAnalyzer {
annotation: ReplaceWith,
symbolDescriptor: CallableDescriptor,
resolutionFacade: ResolutionFacade
): ReplacementCode? {
): CodeToInline? {
val psiFactory = KtPsiFactory(resolutionFacade.project)
val expression = try {
psiFactory.createExpression(annotation.pattern)
@@ -89,8 +89,8 @@ object ReplaceWithAnnotationAnalyzer {
return expression.analyzeInContext(scope, expressionTypingServices = expressionTypingServices)
}
return ReplacementBuilder(symbolDescriptor, resolutionFacade)
.buildReplacementCode(expression, emptyList(), ::analyzeExpression, importFqNames = importFqNames(annotation))
return CodeToInlineBuilder(symbolDescriptor, resolutionFacade)
.prepareCodeToInline(expression, emptyList(), ::analyzeExpression, importFqNames = importFqNames(annotation))
}
fun analyzeClassReplacement(
@@ -29,9 +29,9 @@ import org.jetbrains.kotlin.idea.analysis.analyzeInContext
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.core.copied
import org.jetbrains.kotlin.idea.replacement.CallableUsageReplacementStrategy
import org.jetbrains.kotlin.idea.replacement.ReplacementBuilder
import org.jetbrains.kotlin.idea.replacement.replaceUsagesInWholeProject
import org.jetbrains.kotlin.idea.inliner.CallableUsageReplacementStrategy
import org.jetbrains.kotlin.idea.inliner.CodeToInlineBuilder
import org.jetbrains.kotlin.idea.inliner.replaceUsagesInWholeProject
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtNamedFunction
@@ -67,21 +67,21 @@ class KotlinInlineFunctionHandler: InlineActionHandler() {
expectedType = expectedType)
}
val replacementBuilder = ReplacementBuilder(descriptor, element.getResolutionFacade())
val replacementBuilder = CodeToInlineBuilder(descriptor, element.getResolutionFacade())
val replacement = if (element.hasBlockBody()) {
bodyCopy as KtBlockExpression
val statements = bodyCopy.statements
//TODO: check no other return's!
val lastReturn = statements.lastOrNull() as? KtReturnExpression
if (lastReturn != null) {
replacementBuilder.buildReplacementCode(lastReturn.returnedExpression, statements.dropLast(1), ::analyzeBodyCopy)
replacementBuilder.prepareCodeToInline(lastReturn.returnedExpression, statements.dropLast(1), ::analyzeBodyCopy)
}
else {
replacementBuilder.buildReplacementCode(null, statements, ::analyzeBodyCopy)
replacementBuilder.prepareCodeToInline(null, statements, ::analyzeBodyCopy)
}
}
else {
replacementBuilder.buildReplacementCode(bodyCopy, emptyList(), ::analyzeBodyCopy)
replacementBuilder.prepareCodeToInline(bodyCopy, emptyList(), ::analyzeBodyCopy)
}
val commandName = RefactoringBundle.message("inline.command", element.name)