DeprecatedSymbolUsageFix - correct dealing with implicit receivers + fixed KT-7776 in completion

#KT-7776 Fixed
This commit is contained in:
Valentin Kipyatkov
2015-05-19 18:11:12 +03:00
parent 5da192ddd4
commit 2a5ca095ee
15 changed files with 251 additions and 90 deletions
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.core.asExpression
import org.jetbrains.kotlin.idea.core.collectElementsOfType
import org.jetbrains.kotlin.idea.core.refactoring.JetNameSuggester
import org.jetbrains.kotlin.idea.core.refactoring.JetNameValidator
@@ -52,6 +53,8 @@ import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.JetType
import java.util.ArrayList
@@ -98,11 +101,20 @@ public class DeprecatedSymbolUsageFix(
val FROM_PARAMETER_KEY = Key<ValueParameterDescriptor>("FROM_PARAMETER")
val FROM_THIS_KEY = Key<Unit>("FROM_THIS")
val explicitReceiver = qualifiedExpression?.getReceiverExpression()
explicitReceiver?.putCopyableUserData(USER_CODE_KEY, Unit)
explicitReceiver?.putCopyableUserData(FROM_THIS_KEY, Unit)
var receiver = qualifiedExpression?.getReceiverExpression()
receiver?.putCopyableUserData(USER_CODE_KEY, Unit)
//TODO: infix and operator calls
if (receiver == null) {
val receiverValue = if (descriptor.isExtension) resolvedCall.getExtensionReceiver() else resolvedCall.getDispatchReceiver()
val resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, expressionToReplace]
if (receiverValue is ThisReceiver && resolutionScope != null) {
receiver = receiverValue.asExpression(resolutionScope, psiFactory)
}
}
receiver?.putCopyableUserData(FROM_THIS_KEY, Unit)
val originalDescriptor = (if (descriptor is CallableMemberDescriptor)
DescriptorUtils.unwrapFakeOverride(descriptor)
else
@@ -111,11 +123,10 @@ public class DeprecatedSymbolUsageFix(
var (expression, imports, parameterUsages) = ReplaceWithAnnotationAnalyzer.analyze(
replaceWith, originalDescriptor, element.getResolutionFacade(), file, project)
//TODO: implicit receiver is not always "this"
//TODO: this@
for (thisExpression in expression.collectElementsOfType<JetThisExpression>()) {
if (explicitReceiver != null) {
thisExpression.replace(explicitReceiver)
if (receiver != null) {
thisExpression.replace(receiver)
}
else {
thisExpression.putCopyableUserData(FROM_THIS_KEY, Unit)
@@ -151,7 +162,7 @@ public class DeprecatedSymbolUsageFix(
if (qualified.getReceiverExpression().getCopyableUserData(FROM_THIS_KEY) != null) {
val selector = qualified.getSelectorExpression()
if (selector != null) {
expression = psiFactory.createExpressionByPattern("$0?.$1", explicitReceiver!!, selector)
expression = psiFactory.createExpressionByPattern("$0?.$1", receiver!!, selector)
return
}
}
@@ -159,19 +170,19 @@ public class DeprecatedSymbolUsageFix(
if (expressionToReplace.isUsedAsExpression(bindingContext)) {
val thisReplaced = expression.collectElementsOfType<JetExpression> { it.getCopyableUserData(FROM_THIS_KEY) != null }
expression = expression.introduceValue(explicitReceiver!!, expressionToReplace, bindingContext, thisReplaced, safeCall = true)
expression = expression.introduceValue(receiver!!, expressionToReplace, bindingContext, thisReplaced, safeCall = true)
}
else {
expression = psiFactory.createExpressionByPattern("if ($0 != null) { $1 }", explicitReceiver!!, expression)
expression = psiFactory.createExpressionByPattern("if ($0 != null) { $1 }", receiver!!, expression)
}
}
processSafeCall()
}
if (explicitReceiver != null && explicitReceiver.shouldIntroduceVariableIfUsedTwice()) {
if (receiver != null && receiver.shouldIntroduceVariableIfUsedTwice()) {
val thisReplaced = expression.collectElementsOfType<JetExpression> { it.getCopyableUserData(FROM_THIS_KEY) != null }
if (thisReplaced.size() > 1) {
expression = expression.introduceValue(explicitReceiver, expressionToReplace, bindingContext, thisReplaced)
expression = expression.introduceValue(receiver!!, expressionToReplace, bindingContext, thisReplaced)
}
}
@@ -23,6 +23,7 @@ import com.intellij.psi.PsiRecursiveElementVisitor
import org.jetbrains.kotlin.analyzer.analyzeInContext
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.core.asExpression
import org.jetbrains.kotlin.idea.core.collectElementsOfType
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
import org.jetbrains.kotlin.idea.imports.importableFqName
@@ -76,10 +77,7 @@ object ReplaceWithAnnotationAnalyzer {
val bindingContext = expression.analyzeInContext(scope)
val thisType = symbolDescriptor.getExtensionReceiverParameter()?.getType()
?: (symbolDescriptor.getContainingDeclaration() as? ClassifierDescriptor)?.getDefaultType()
val receiversToAdd = ArrayList<Pair<JetExpression, String>>()
val receiversToAdd = ArrayList<Pair<JetExpression, JetExpression>>()
val parameterUsageKey = Key<ValueParameterDescriptor>("parameterUsageKey")
@@ -105,14 +103,9 @@ object ReplaceWithAnnotationAnalyzer {
else
resolvedCall.getDispatchReceiver()
if (receiver is ThisReceiver) {
if (receiver.getType() == thisType) {
receiversToAdd.add(expression to "this")
}
else {
val descriptor = receiver.getDeclarationDescriptor()
if (descriptor is ClassDescriptor && descriptor.isCompanionObject()) {
receiversToAdd.add(expression to IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(descriptor))
}
val receiverExpression = receiver.asExpression(symbolScope, psiFactory)
if (receiverExpression != null) {
receiversToAdd.add(expression to receiverExpression)
}
}
}
@@ -124,9 +117,9 @@ object ReplaceWithAnnotationAnalyzer {
}
})
for ((expr, receiverText) in receiversToAdd) {
for ((expr, receiverExpression) in receiversToAdd) {
val expressionToReplace = expr.getParent() as? JetCallExpression ?: expr
val newExpr = expressionToReplace.replaced(psiFactory.createExpressionByPattern("$receiverText.$0", expressionToReplace))
val newExpr = expressionToReplace.replaced(psiFactory.createExpressionByPattern("$0.$1", receiverExpression, expressionToReplace))
if (expressionToReplace == expression) {
expression = newExpr
}