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
@@ -0,0 +1,45 @@
/*
* Copyright 2010-2015 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.util
import org.jetbrains.kotlin.psi.*
public fun JetFunctionLiteral.findLabelAndCall(): Pair<String?, JetCallExpression?> {
val literalParent = (this.getParent() as JetFunctionLiteralExpression).getParent()
fun JetValueArgument.callExpression(): JetCallExpression? {
val parent = getParent()
return (if (parent is JetValueArgumentList) parent else this).getParent() as? JetCallExpression
}
when (literalParent) {
is JetLabeledExpression -> {
val callExpression = (literalParent.getParent() as? JetValueArgument)?.callExpression()
return Pair(literalParent.getLabelName(), callExpression)
}
is JetValueArgument -> {
val callExpression = literalParent.callExpression()
val label = (callExpression?.getCalleeExpression() as? JetSimpleNameExpression)?.getReferencedName()
return Pair(label, callExpression)
}
else -> {
return Pair(null, null)
}
}
}
@@ -20,22 +20,33 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.psi.JetFunctionLiteral
import org.jetbrains.kotlin.psi.JetPsiFactory
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.scopes.JetScope
import java.util.HashSet
import java.util.LinkedHashMap
import java.util.LinkedHashSet
public fun JetScope.getImplicitReceiversWithInstance(): List<ReceiverParameterDescriptor> {
public fun JetScope.getImplicitReceiversWithInstance(): Collection<ReceiverParameterDescriptor>
= getImplicitReceiversWithInstanceToExpression().keySet()
public interface ReceiverExpressionFactory {
public fun createExpression(psiFactory: JetPsiFactory, shortThis: Boolean = true): JetExpression
}
public fun JetScope.getImplicitReceiversWithInstanceToExpression(): Map<ReceiverParameterDescriptor, ReceiverExpressionFactory?> {
// we use a set to workaround a bug with receiver for companion object present twice in the result of getImplicitReceiversHierarchy()
val receivers = LinkedHashSet(getImplicitReceiversHierarchy())
val withInstance = HashSet<DeclarationDescriptor>()
val outerDeclarationsWithInstance = LinkedHashSet<DeclarationDescriptor>()
var current: DeclarationDescriptor? = getContainingDeclaration()
while (current != null) {
if (current is PropertyAccessorDescriptor) {
current = current.getCorrespondingProperty()
}
withInstance.add(current)
outerDeclarationsWithInstance.add(current)
val classDescriptor = current as? ClassDescriptor
if (classDescriptor != null && !classDescriptor.isInner() && !DescriptorUtils.isLocal(classDescriptor)) break
@@ -43,8 +54,42 @@ public fun JetScope.getImplicitReceiversWithInstance(): List<ReceiverParameterDe
current = current!!.getContainingDeclaration()
}
return receivers.filter {
val owner = it.getContainingDeclaration()
owner is ClassDescriptor && owner.getKind().isSingleton() || owner in withInstance
val result = LinkedHashMap<ReceiverParameterDescriptor, ReceiverExpressionFactory?>()
for ((index, receiver) in receivers.withIndex()) {
val owner = receiver.getContainingDeclaration()
val (expressionText, isImmediateThis) = if (owner in outerDeclarationsWithInstance) {
val thisWithLabel = thisQualifierName(receiver)?.let { "this@$it" }
if (index == 0)
(thisWithLabel ?: "this") to true
else
thisWithLabel to false
}
else if (owner is ClassDescriptor && owner.getKind().isSingleton()) {
IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(owner) to false
}
else {
continue
}
val factory = if (expressionText != null)
object : ReceiverExpressionFactory {
override fun createExpression(psiFactory: JetPsiFactory, shortThis: Boolean): JetExpression {
return psiFactory.createExpression(if (shortThis && isImmediateThis) "this" else expressionText)
}
}
else
null
result.put(receiver, factory)
}
return result
}
private fun thisQualifierName(receiver: ReceiverParameterDescriptor): String? {
val descriptor = receiver.getContainingDeclaration()
val name = descriptor.getName()
if (!name.isSpecial()) {
return name.asString()
}
val functionLiteral = DescriptorToSourceUtils.descriptorToDeclaration(descriptor) as? JetFunctionLiteral
return functionLiteral?.findLabelAndCall()?.first
}