Code refactoring

This commit is contained in:
Valentin Kipyatkov
2016-10-19 19:18:49 +03:00
parent 8c65379711
commit 29175e96e9
10 changed files with 239 additions and 118 deletions
+1
View File
@@ -50,6 +50,7 @@
<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" />
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="descriptors" />
<orderEntry type="module" module-name="idea-analysis" />
<orderEntry type="library" name="idea-full" level="project" />
<orderEntry type="module" module-name="descriptor.loader.java" />
<orderEntry type="module" module-name="light-classes" />
<orderEntry type="module" module-name="frontend" />
<orderEntry type="module" module-name="idea-core" />
<orderEntry type="module" module-name="frontend.java" />
<orderEntry type="module" module-name="util" />
<orderEntry type="library" scope="PROVIDED" name="properties" level="project" />
<orderEntry type="module" module-name="idea" scope="RUNTIME" />
<orderEntry type="module" module-name="formatter" />
</component>
</module>
@@ -0,0 +1,143 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.replacement
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.idea.core.asExpression
import org.jetbrains.kotlin.idea.core.copied
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.intentions.InsertExplicitTypeArgumentsIntention
import org.jetbrains.kotlin.idea.references.canBeResolvedViaImport
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTraceContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor
import java.util.*
class ReplacementBuilder(
private val targetCallable: CallableDescriptor,
private val resolutionFacade: ResolutionFacade
) {
fun buildReplacementExpression(
expression: KtExpression,
resolutionScope: LexicalScope,
importFqNames: Collection<FqName> = emptyList(),
copyExpression: Boolean = true
): ReplacementExpression {
@Suppress("NAME_SHADOWING")
var expression = if (copyExpression) expression.copied() else expression
var bindingContext = analyzeInContext(expression, resolutionScope)
val typeArgsToAdd = ArrayList<Pair<KtCallExpression, KtTypeArgumentList>>()
expression.forEachDescendantOfType<KtCallExpression> {
if (InsertExplicitTypeArgumentsIntention.isApplicableTo(it, bindingContext)) {
typeArgsToAdd.add(it to InsertExplicitTypeArgumentsIntention.createTypeArguments(it, bindingContext)!!)
}
}
if (typeArgsToAdd.isNotEmpty()) {
for ((callExpr, typeArgs) in typeArgsToAdd) {
callExpr.addAfter(typeArgs, callExpr.calleeExpression)
}
// reanalyze expression - new usages of type parameters may be added
bindingContext = analyzeInContext(expression, resolutionScope)
}
val receiversToAdd = ArrayList<Pair<KtExpression, KtExpression>>()
val resultImportFqNames = importFqNames.toMutableSet()
val psiFactory = KtPsiFactory(expression)
expression.forEachDescendantOfType<KtSimpleNameExpression> { expression ->
val target = bindingContext[BindingContext.REFERENCE_TARGET, expression] ?: return@forEachDescendantOfType
//TODO: other types of references ('[]' etc)
if (expression.mainReference.canBeResolvedViaImport(target)) {
resultImportFqNames.add(target.importableFqName!!)
}
if (expression.getReceiverExpression() == null) {
if (target is ValueParameterDescriptor && target.containingDeclaration == targetCallable) {
expression.putCopyableUserData(ReplacementExpression.PARAMETER_USAGE_KEY, target.name)
}
else if (target is TypeParameterDescriptor && target.containingDeclaration == targetCallable) {
expression.putCopyableUserData(ReplacementExpression.TYPE_PARAMETER_USAGE_KEY, target.name)
}
val resolvedCall = expression.getResolvedCall(bindingContext)
if (resolvedCall != null && resolvedCall.isReallySuccess()) {
val receiver = if (resolvedCall.resultingDescriptor.isExtension)
resolvedCall.extensionReceiver
else
resolvedCall.dispatchReceiver
if (receiver is ImplicitReceiver) {
val receiverExpression = receiver.asExpression(resolutionScope, psiFactory)
if (receiverExpression != null) {
receiversToAdd.add(expression to receiverExpression)
}
}
}
}
}
// add receivers in reverse order because arguments of a call were processed after the callee's name
for ((expr, receiverExpression) in receiversToAdd.asReversed()) {
val expressionToReplace = expr.parent as? KtCallExpression ?: expr
val newExpr = expressionToReplace.replaced(psiFactory.createExpressionByPattern("$0.$1", receiverExpression, expressionToReplace))
if (expressionToReplace == expression) {
expression = newExpr
}
}
return ReplacementExpression(expression, resultImportFqNames)
}
//TODO: there can be expected type and maybe something else
private fun analyzeInContext(expression: KtExpression, scope: LexicalScope): BindingContext {
val module = scope.ownerDescriptor.module
val traceContext = BindingTraceContext()
val frontendService = if (module.builtIns.builtInsModule == module) {
// TODO: doubtful place, do we require this module or not? Built-ins module doesn't have some necessary components...
resolutionFacade.getFrontendService(ExpressionTypingServices::class.java)
}
else {
resolutionFacade.getFrontendService(module, ExpressionTypingServices::class.java)
}
PreliminaryDeclarationVisitor.createForExpression(expression, traceContext)
frontendService.getTypeInfo(scope, expression, TypeUtils.NO_EXPECTED_TYPE, DataFlowInfo.EMPTY, traceContext, false)
return traceContext.bindingContext
}
}
@@ -0,0 +1,47 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.replacement
import com.intellij.openapi.util.Key
import org.jetbrains.kotlin.idea.core.copied
import org.jetbrains.kotlin.idea.replacement.ReplacementExpression.Companion.PARAMETER_USAGE_KEY
import org.jetbrains.kotlin.idea.replacement.ReplacementExpression.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.
* 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.buildReplacementExpression].
*/
//TODO: should it be data class?
data class ReplacementExpression(
val expression: KtExpression,
val fqNamesToImport: Collection<FqName>
) {
fun copy() = ReplacementExpression(expression.copied(), fqNamesToImport)
companion object {
val PARAMETER_USAGE_KEY: Key<Name> = Key("PARAMETER_USAGE")
val TYPE_PARAMETER_USAGE_KEY: Key<Name> = Key("TYPE_PARAMETER_USAGE")
}
}
+1
View File
@@ -55,5 +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" />
</component>
</module>
@@ -17,13 +17,14 @@
package org.jetbrains.kotlin.idea.quickfix.replaceWith
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.replacement.ReplacementExpression
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
internal interface CallKindHandler {
val elementToReplace: KtElement
fun precheckReplacementPattern(pattern: ReplaceWithAnnotationAnalyzer.ReplacementExpression): Boolean
fun precheckReplacementPattern(pattern: ReplacementExpression): Boolean
fun wrapGeneratedExpression(expression: KtExpression): KtElement
@@ -33,7 +34,7 @@ internal interface CallKindHandler {
internal class CallExpressionHandler(callElement: KtExpression) : CallKindHandler {
override val elementToReplace = callElement.getQualifiedExpressionForSelectorOrThis()
override fun precheckReplacementPattern(pattern: ReplaceWithAnnotationAnalyzer.ReplacementExpression) = true
override fun precheckReplacementPattern(pattern: ReplacementExpression) = true
override fun wrapGeneratedExpression(expression: KtExpression) = expression
@@ -43,7 +44,7 @@ internal class CallExpressionHandler(callElement: KtExpression) : CallKindHandle
internal class AnnotationEntryHandler(annotationEntry: KtAnnotationEntry) : CallKindHandler {
override val elementToReplace = annotationEntry
override fun precheckReplacementPattern(pattern: ReplaceWithAnnotationAnalyzer.ReplacementExpression): Boolean {
override fun precheckReplacementPattern(pattern: ReplacementExpression): Boolean {
//TODO
return true
}
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.idea.core.*
import org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention
import org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeArgumentsIntention
import org.jetbrains.kotlin.idea.intentions.setType
import org.jetbrains.kotlin.idea.replacement.ReplacementExpression
import org.jetbrains.kotlin.idea.util.CommentSaver
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
@@ -55,7 +56,7 @@ import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.*
class CallableUsageReplacementStrategy(
private val replacement: ReplaceWithAnnotationAnalyzer.ReplacementExpression
private val replacement: ReplacementExpression
) : UsageReplacementStrategy {
override fun createReplacer(usage: KtSimpleNameExpression): (() -> KtElement)? {
@@ -95,7 +96,7 @@ private fun performCallReplacement(
resolvedCall: ResolvedCall<out CallableDescriptor>,
callElement: KtElement,
callKindHandler: CallKindHandler,
replacement: ReplaceWithAnnotationAnalyzer.ReplacementExpression
replacement: ReplacementExpression
): KtElement {
val project = element.project
val psiFactory = KtPsiFactory(project)
@@ -196,7 +197,7 @@ private fun ConstructedExpressionWrapper.processValueParameterUsages(
val parameterName = parameter.name
val usages = expression.collectDescendantsOfType<KtExpression> {
it[ReplaceWithAnnotationAnalyzer.PARAMETER_USAGE_KEY] == parameterName
it[ReplacementExpression.PARAMETER_USAGE_KEY] == parameterName
}
usages.forEach {
val usageArgument = it.parent as? KtValueArgument
@@ -235,7 +236,7 @@ private fun ConstructedExpressionWrapper.processTypeParameterUsages(resolvedCall
for ((index, typeParameter) in typeParameters.withIndex()) {
val parameterName = typeParameter.name
val usages = expression.collectDescendantsOfType<KtExpression> {
it[ReplaceWithAnnotationAnalyzer.TYPE_PARAMETER_USAGE_KEY] == parameterName
it[ReplacementExpression.TYPE_PARAMETER_USAGE_KEY] == parameterName
}
val factory = KtPsiFactory(callElement)
@@ -353,13 +354,13 @@ private fun argumentForParameter(
val (expression, parameterUsages) = defaultValue
for ((param, usages) in parameterUsages) {
usages.forEach { it.put(ReplaceWithAnnotationAnalyzer.PARAMETER_USAGE_KEY, param.name) }
usages.forEach { it.put(ReplacementExpression.PARAMETER_USAGE_KEY, param.name) }
}
val expressionCopy = expression.copied()
// clean up user data in original
expression.forEachDescendantOfType<KtExpression> { it.clear(ReplaceWithAnnotationAnalyzer.PARAMETER_USAGE_KEY) }
expression.forEachDescendantOfType<KtExpression> { it.clear(ReplacementExpression.PARAMETER_USAGE_KEY) }
return Argument(expressionCopy, null/*TODO*/, isDefaultValue = true)
}
@@ -430,8 +431,8 @@ private fun postProcessInsertedCode(range: PsiChildRange): PsiChildRange {
// clean up user data
it.forEachDescendantOfType<KtExpression> {
it.clear(USER_CODE_KEY)
it.clear(ReplaceWithAnnotationAnalyzer.PARAMETER_USAGE_KEY)
it.clear(ReplaceWithAnnotationAnalyzer.TYPE_PARAMETER_USAGE_KEY)
it.clear(ReplacementExpression.PARAMETER_USAGE_KEY)
it.clear(ReplacementExpression.TYPE_PARAMETER_USAGE_KEY)
it.clear(PARAMETER_VALUE_KEY)
it.clear(RECEIVER_VALUE_KEY)
it.clear(WAS_FUNCTION_LITERAL_ARGUMENT_KEY)
@@ -19,13 +19,14 @@ package org.jetbrains.kotlin.idea.quickfix.replaceWith
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.replacement.ReplacementExpression
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
import org.jetbrains.kotlin.utils.addToStdlib.check
class ClassUsageReplacementStrategy(
typeReplacement: KtUserType?,
constructorReplacement: ReplaceWithAnnotationAnalyzer.ReplacementExpression?,
constructorReplacement: ReplacementExpression?,
project: Project
) : UsageReplacementStrategy {
@@ -16,57 +16,34 @@
package org.jetbrains.kotlin.idea.quickfix.replaceWith
import com.intellij.openapi.util.Key
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
import org.jetbrains.kotlin.idea.core.asExpression
import org.jetbrains.kotlin.idea.core.copied
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.intentions.InsertExplicitTypeArgumentsIntention
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.references.canBeResolvedViaImport
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.replacement.ReplacementBuilder
import org.jetbrains.kotlin.idea.replacement.ReplacementExpression
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtUserType
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.lazy.DefaultImportProvider
import org.jetbrains.kotlin.resolve.lazy.descriptors.ClassResolutionScopesSupport
import org.jetbrains.kotlin.resolve.scopes.*
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
import org.jetbrains.kotlin.resolve.scopes.utils.chainImportingScopes
import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor
import java.util.*
data class ReplaceWith(val pattern: String, val imports: List<String>)
object ReplaceWithAnnotationAnalyzer {
val PARAMETER_USAGE_KEY: Key<Name> = Key("PARAMETER_USAGE")
val TYPE_PARAMETER_USAGE_KEY: Key<Name> = Key("TYPE_PARAMETER_USAGE")
data class ReplacementExpression(
val expression: KtExpression,
val fqNamesToImport: Collection<FqName>
) {
fun copy() = ReplacementExpression(expression.copied(), fqNamesToImport)
}
fun analyzeCallableReplacement(
annotation: ReplaceWith,
symbolDescriptor: CallableDescriptor,
@@ -85,7 +62,7 @@ object ReplaceWithAnnotationAnalyzer {
resolutionFacade: ResolutionFacade
): ReplacementExpression? {
val psiFactory = KtPsiFactory(resolutionFacade.project)
var expression = try {
val expression = try {
psiFactory.createExpression(annotation.pattern)
}
catch(t: Throwable) {
@@ -98,69 +75,8 @@ object ReplaceWithAnnotationAnalyzer {
val scope = getResolutionScope(symbolDescriptor, symbolDescriptor,
listOf(explicitImportsScope) + defaultImportsScopes) ?: return null
var bindingContext = analyzeInContext(expression, module, scope, resolutionFacade)
val typeArgsToAdd = ArrayList<Pair<KtCallExpression, KtTypeArgumentList>>()
expression.forEachDescendantOfType<KtCallExpression> {
if (InsertExplicitTypeArgumentsIntention.isApplicableTo(it, bindingContext)) {
typeArgsToAdd.add(it to InsertExplicitTypeArgumentsIntention.createTypeArguments(it, bindingContext)!!)
}
}
if (typeArgsToAdd.isNotEmpty()) {
for ((callExpr, typeArgs) in typeArgsToAdd) {
callExpr.addAfter(typeArgs, callExpr.calleeExpression)
}
// reanalyze expression - new usages of type parameters may be added
bindingContext = analyzeInContext(expression, module, scope, resolutionFacade)
}
val receiversToAdd = ArrayList<Pair<KtExpression, KtExpression>>()
val importFqNames = importFqNames(annotation).toMutableSet()
expression.forEachDescendantOfType<KtSimpleNameExpression> { expression ->
val target = bindingContext[BindingContext.REFERENCE_TARGET, expression] ?: return@forEachDescendantOfType
//TODO: other types of references ('[]' etc)
if (expression.mainReference.canBeResolvedViaImport(target)) {
importFqNames.add(target.importableFqName!!)
}
if (expression.getReceiverExpression() == null) {
if (target is ValueParameterDescriptor && target.containingDeclaration == symbolDescriptor) {
expression.putCopyableUserData(PARAMETER_USAGE_KEY, target.name)
}
else if (target is TypeParameterDescriptor && target.containingDeclaration == symbolDescriptor) {
expression.putCopyableUserData(TYPE_PARAMETER_USAGE_KEY, target.name)
}
val resolvedCall = expression.getResolvedCall(bindingContext)
if (resolvedCall != null && resolvedCall.isReallySuccess()) {
val receiver = if (resolvedCall.resultingDescriptor.isExtension)
resolvedCall.extensionReceiver
else
resolvedCall.dispatchReceiver
if (receiver is ImplicitReceiver) {
val receiverExpression = receiver.asExpression(scope, psiFactory)
if (receiverExpression != null) {
receiversToAdd.add(expression to receiverExpression)
}
}
}
}
}
// add receivers in reverse order because arguments of a call were processed after the callee's name
for ((expr, receiverExpression) in receiversToAdd.asReversed()) {
val expressionToReplace = expr.parent as? KtCallExpression ?: expr
val newExpr = expressionToReplace.replaced(psiFactory.createExpressionByPattern("$0.$1", receiverExpression, expressionToReplace))
if (expressionToReplace == expression) {
expression = newExpr
}
}
return ReplacementExpression(expression, importFqNames)
return ReplacementBuilder(symbolDescriptor, resolutionFacade)
.buildReplacementExpression(expression, scope, importFqNames(annotation), copyExpression = false)
}
fun analyzeClassReplacement(
@@ -232,19 +148,6 @@ object ReplaceWithAnnotationAnalyzer {
.map(FqNameUnsafe::toSafe)
}
private fun analyzeInContext(
expression: KtExpression,
module: ModuleDescriptor,
scope: LexicalScope,
resolutionFacade: ResolutionFacade
): BindingContext {
val trace = BindingTraceContext()
val expressionTypingServices = resolutionFacade.getFrontendService(module, ExpressionTypingServices::class.java)
PreliminaryDeclarationVisitor.createForExpression(expression, trace)
expressionTypingServices.getTypeInfo(scope, expression, TypeUtils.NO_EXPECTED_TYPE, DataFlowInfo.EMPTY, trace, false)
return trace.bindingContext
}
private fun getResolutionScope(descriptor: DeclarationDescriptor, ownerDescriptor: DeclarationDescriptor, additionalScopes: Collection<ImportingScope>): LexicalScope? {
return when (descriptor) {
is PackageFragmentDescriptor -> {