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
@@ -29,7 +29,8 @@ import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.completion.handlers.CastReceiverInsertHandler
import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler
import org.jetbrains.kotlin.idea.util.FuzzyType
import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstance
import org.jetbrains.kotlin.idea.util.findLabelAndCall
import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstanceToExpression
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.parents
@@ -197,75 +198,32 @@ data class ThisItemInfo(val factory: () -> LookupElement, val type: FuzzyType)
fun thisExpressionItems(bindingContext: BindingContext, position: JetExpression, prefix: String): Collection<ThisItemInfo> {
val scope = bindingContext[BindingContext.RESOLUTION_SCOPE, position] ?: return listOf()
val psiFactory = JetPsiFactory(position)
val result = ArrayList<ThisItemInfo>()
for ((i, receiver) in scope.getImplicitReceiversWithInstance().withIndex()) {
for ((receiver, expressionFactory) in scope.getImplicitReceiversWithInstanceToExpression()) {
if (expressionFactory == null) continue
// if prefix does not start with "this@" do not include immediate this in the form with label
val expression = expressionFactory.createExpression(psiFactory, shortThis = !prefix.startsWith("this@")) as? JetThisExpression ?: continue
val thisType = receiver.getType()
val fuzzyType = FuzzyType(thisType, listOf())
fun createLookupElement(label: String?): LookupElement {
var element = createKeywordWithLabelElement("this", label)
element = element.withTypeText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(thisType))
return element
}
fun createLookupElement() = createKeywordWithLabelElement("this", expression.getLabelName())
.withTypeText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(thisType))
if (i == 0) {
result.add(ThisItemInfo({ createLookupElement(null) }, fuzzyType))
if (!prefix.startsWith("this@")) continue // if prefix does not start with "this@" do not include immediate this in the form with label
}
val label = thisQualifierName(receiver) ?: continue
result.add(ThisItemInfo({ createLookupElement(label) }, fuzzyType))
result.add(ThisItemInfo(::createLookupElement, fuzzyType))
}
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 null
return functionLiteralLabel(functionLiteral)
}
private fun functionLiteralLabel(functionLiteral: JetFunctionLiteral): String?
= functionLiteralLabelAndCall(functionLiteral).first
private fun functionLiteralLabelAndCall(functionLiteral: JetFunctionLiteral): Pair<String?, JetCallExpression?> {
val literalParent = (functionLiteral.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)
}
}
}
fun returnExpressionItems(bindingContext: BindingContext, position: JetElement): Collection<LookupElement> {
val result = ArrayList<LookupElement>()
for (parent in position.parents()) {
if (parent is JetDeclarationWithBody) {
val returnsUnit = returnsUnit(parent, bindingContext)
if (parent is JetFunctionLiteral) {
val (label, call) = functionLiteralLabelAndCall(parent)
val (label, call) = parent.findLabelAndCall()
if (label != null) {
result.add(createKeywordWithLabelElement("return", label, addSpace = !returnsUnit))
}
@@ -0,0 +1,12 @@
class C {
fun foo() {
<caret>
}
companion object {
}
}
// INVOCATION_COUNT: 1
// EXIST: "this"
// ABSENT: "this@Companion"
@@ -281,6 +281,12 @@ public class KeywordCompletionTestGenerated extends AbstractKeywordCompletionTes
doTest(fileName);
}
@TestMetadata("NoCompanionThis.kt")
public void testNoCompanionThis() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/NoCompanionThis.kt");
doTest(fileName);
}
@TestMetadata("NoCompletionForCapitalPrefix.kt")
public void testNoCompletionForCapitalPrefix() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/NoCompletionForCapitalPrefix.kt");