Refactoring to make receiver type safe
This commit is contained in:
+29
-14
@@ -303,7 +303,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
|
||||
val contextVariablesProvider = {
|
||||
nameExpression?.let {
|
||||
referenceVariantsHelper.getReferenceVariants(it, DescriptorKindFilter.VARIABLES, { true }, CallTypeAndReceiver(CallType.NORMAL, null))
|
||||
referenceVariantsHelper.getReferenceVariants(it, DescriptorKindFilter.VARIABLES, { true }, CallTypeAndReceiver.DEFAULT)
|
||||
.map { it as VariableDescriptor }
|
||||
} ?: emptyList()
|
||||
}
|
||||
@@ -314,23 +314,38 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
insertHandlerProvider, contextVariablesProvider)
|
||||
}
|
||||
|
||||
private fun detectCallTypeAndReceiverTypes(): Pair<CallType, Collection<JetType>> {
|
||||
private fun detectCallTypeAndReceiverTypes(): Pair<CallType<*>, Collection<JetType>> {
|
||||
if (nameExpression == null) {
|
||||
return CallType.NORMAL to emptyList()
|
||||
return CallType.DEFAULT to emptyList()
|
||||
}
|
||||
|
||||
val (callType, receiverElement) = CallTypeAndReceiver.detect(nameExpression)
|
||||
val callTypeAndReceiver = CallTypeAndReceiver.detect(nameExpression)
|
||||
|
||||
if (callType == CallType.CALLABLE_REFERENCE && receiverElement != null) {
|
||||
val type = bindingContext[BindingContext.TYPE, receiverElement as JetTypeReference]
|
||||
return callType to type.singletonOrEmptyList()
|
||||
val receiverExpression: JetExpression?
|
||||
when (callTypeAndReceiver) {
|
||||
is CallTypeAndReceiver.CALLABLE_REFERENCE -> {
|
||||
if (callTypeAndReceiver.receiver != null) {
|
||||
val type = bindingContext[BindingContext.TYPE, callTypeAndReceiver.receiver]
|
||||
return callTypeAndReceiver.callType to type.singletonOrEmptyList()
|
||||
}
|
||||
else {
|
||||
receiverExpression = null
|
||||
}
|
||||
}
|
||||
|
||||
is CallTypeAndReceiver.DEFAULT -> receiverExpression = null
|
||||
is CallTypeAndReceiver.DOT -> receiverExpression = callTypeAndReceiver.receiver
|
||||
is CallTypeAndReceiver.SAFE -> receiverExpression = callTypeAndReceiver.receiver
|
||||
is CallTypeAndReceiver.INFIX -> receiverExpression = callTypeAndReceiver.receiver
|
||||
is CallTypeAndReceiver.UNARY -> receiverExpression = callTypeAndReceiver.receiver
|
||||
is CallTypeAndReceiver.IMPORT_DIRECTIVE -> receiverExpression = callTypeAndReceiver.receiver
|
||||
is CallTypeAndReceiver.PACKAGE_DIRECTIVE -> receiverExpression = callTypeAndReceiver.receiver
|
||||
is CallTypeAndReceiver.TYPE -> receiverExpression = callTypeAndReceiver.receiver
|
||||
}
|
||||
|
||||
receiverElement as JetExpression?
|
||||
|
||||
val receiverValues = if (receiverElement != null) {
|
||||
val expressionType = bindingContext.getType(receiverElement)
|
||||
expressionType?.let { listOf(ExpressionReceiver(receiverElement, expressionType)) } ?: emptyList()
|
||||
val receiverValues = if (receiverExpression != null) {
|
||||
val expressionType = bindingContext.getType(receiverExpression)
|
||||
expressionType?.let { listOf(ExpressionReceiver(receiverExpression, expressionType)) } ?: emptyList()
|
||||
}
|
||||
else {
|
||||
val resolutionScope = referenceVariantsHelper.resolutionScope(nameExpression)
|
||||
@@ -350,10 +365,10 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
}
|
||||
}
|
||||
|
||||
if (callType == CallType.SAFE) {
|
||||
if (callTypeAndReceiver is CallTypeAndReceiver.SAFE) {
|
||||
receiverTypes = receiverTypes.map { it.makeNotNullable() }
|
||||
}
|
||||
|
||||
return callType to receiverTypes
|
||||
return callTypeAndReceiver.callType to receiverTypes
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.types.JetType
|
||||
import java.util.*
|
||||
|
||||
class InsertHandlerProvider(
|
||||
private val callType: CallType,
|
||||
private val callType: CallType<*>,
|
||||
expectedInfosCalculator: () -> Collection<ExpectedInfo>
|
||||
) {
|
||||
private val expectedInfos by lazy(LazyThreadSafetyMode.NONE) { expectedInfosCalculator() }
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ class KDocNameCompletionSession(parameters: CompletionParameters,
|
||||
val extensionReceiver = descriptor.getExtensionReceiverParameter()
|
||||
if (extensionReceiver != null) {
|
||||
val substituted = descriptor.substituteExtensionIfCallable(implicitReceivers, bindingContext, DataFlowInfo.EMPTY,
|
||||
CallType.NORMAL, moduleDescriptor)
|
||||
CallType.DEFAULT, moduleDescriptor)
|
||||
return !substituted.isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ object KeywordCompletion {
|
||||
.withInsertHandler(if (keywordToken !in FUNCTION_KEYWORDS)
|
||||
KotlinKeywordInsertHandler
|
||||
else
|
||||
KotlinFunctionInsertHandler(CallType.NORMAL, inputTypeArguments = false, inputValueArguments = false))
|
||||
KotlinFunctionInsertHandler(CallType.DEFAULT, inputTypeArguments = false, inputValueArguments = false))
|
||||
consumer(element)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -45,7 +45,7 @@ import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
class LookupElementFactory(
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val receiverTypes: Collection<JetType>,
|
||||
private val callType: CallType,
|
||||
private val callType: CallType<*>,
|
||||
private val isInStringTemplateAfterDollar: Boolean,
|
||||
public val insertHandlerProvider: InsertHandlerProvider,
|
||||
contextVariablesProvider: () -> Collection<VariableDescriptor>
|
||||
@@ -66,7 +66,7 @@ class LookupElementFactory(
|
||||
result.add(lookupElement)
|
||||
|
||||
// add special item for function with one argument of function type with more than one parameter
|
||||
if (descriptor is FunctionDescriptor && (callType == CallType.NORMAL || callType == CallType.SAFE)) {
|
||||
if (descriptor is FunctionDescriptor && (callType == CallType.DEFAULT || callType == CallType.DOT || callType == CallType.SAFE)) {
|
||||
result.addSpecialFunctionCallElements(descriptor, useReceiverTypes)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ object PackageDirectiveCompletion {
|
||||
val bindingContext = resolutionFacade.analyze(expression)
|
||||
|
||||
val variants = ReferenceVariantsHelper(bindingContext, resolutionFacade, { true }).getPackageReferenceVariants(expression, prefixMatcher.asNameFilter())
|
||||
val lookupElementFactory = BasicLookupElementFactory(resolutionFacade.project, InsertHandlerProvider(callType = CallType.NORMAL/*TODO*/, expectedInfosCalculator = { emptyList() }))
|
||||
val lookupElementFactory = BasicLookupElementFactory(resolutionFacade.project, InsertHandlerProvider(callType = CallType.PACKAGE_DIRECTIVE, expectedInfosCalculator = { emptyList() }))
|
||||
for (variant in variants) {
|
||||
val lookupElement = lookupElementFactory.createLookupElement(variant)
|
||||
if (!lookupElement.getLookupString().contains(DUMMY_IDENTIFIER)) {
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ import org.jetbrains.kotlin.types.JetType
|
||||
class GenerateLambdaInfo(val lambdaType: JetType, val explicitParameters: Boolean)
|
||||
|
||||
class KotlinFunctionInsertHandler(
|
||||
val callType: CallType,
|
||||
val callType: CallType<*>,
|
||||
val inputTypeArguments: Boolean,
|
||||
val inputValueArguments: Boolean,
|
||||
val argumentText: String = "",
|
||||
|
||||
+21
-25
@@ -22,12 +22,10 @@ import com.intellij.codeInsight.completion.CompletionSorter
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.completion.*
|
||||
import org.jetbrains.kotlin.idea.util.CallType
|
||||
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
|
||||
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptorKindExclude
|
||||
import org.jetbrains.kotlin.psi.FunctionLiteralArgument
|
||||
import org.jetbrains.kotlin.psi.JetCodeFragment
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.psi.ValueArgumentName
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
||||
import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall
|
||||
@@ -91,30 +89,28 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
|
||||
// special completion for outside parenthesis lambda argument
|
||||
private fun addFunctionLiteralArgumentCompletions() {
|
||||
if (nameExpression != null) {
|
||||
val (callType, receiverElement) = CallTypeAndReceiver.detect(nameExpression)
|
||||
if (callType == CallType.INFIX) {
|
||||
val call = (receiverElement as JetExpression).getCall(bindingContext)
|
||||
if (call != null && call.getFunctionLiteralArguments().isEmpty()) {
|
||||
val dummyArgument = object : FunctionLiteralArgument {
|
||||
override fun getFunctionLiteral() = throw UnsupportedOperationException()
|
||||
override fun getArgumentExpression() = throw UnsupportedOperationException()
|
||||
override fun getArgumentName(): ValueArgumentName? = null
|
||||
override fun isNamed() = false
|
||||
override fun asElement() = throw UnsupportedOperationException()
|
||||
override fun getSpreadElement(): LeafPsiElement? = null
|
||||
override fun isExternal() = false
|
||||
}
|
||||
val dummyArguments = call.getValueArguments() + listOf(dummyArgument)
|
||||
val dummyCall = object : DelegatingCall(call) {
|
||||
override fun getValueArguments() = dummyArguments
|
||||
override fun getFunctionLiteralArguments() = listOf(dummyArgument)
|
||||
override fun getValueArgumentList() = throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
val expectedInfos = ExpectedInfos(bindingContext, resolutionFacade)
|
||||
.calculateForArgument(dummyCall, dummyArgument)
|
||||
collector.addElements(LambdaItems.collect(expectedInfos))
|
||||
val callTypeAndReceiver = CallTypeAndReceiver.detect(nameExpression) as? CallTypeAndReceiver.INFIX ?: return
|
||||
val call = callTypeAndReceiver.receiver.getCall(bindingContext)
|
||||
if (call != null && call.getFunctionLiteralArguments().isEmpty()) {
|
||||
val dummyArgument = object : FunctionLiteralArgument {
|
||||
override fun getFunctionLiteral() = throw UnsupportedOperationException()
|
||||
override fun getArgumentExpression() = throw UnsupportedOperationException()
|
||||
override fun getArgumentName(): ValueArgumentName? = null
|
||||
override fun isNamed() = false
|
||||
override fun asElement() = throw UnsupportedOperationException()
|
||||
override fun getSpreadElement(): LeafPsiElement? = null
|
||||
override fun isExternal() = false
|
||||
}
|
||||
val dummyArguments = call.getValueArguments() + listOf(dummyArgument)
|
||||
val dummyCall = object : DelegatingCall(call) {
|
||||
override fun getValueArguments() = dummyArguments
|
||||
override fun getFunctionLiteralArguments() = listOf(dummyArgument)
|
||||
override fun getValueArgumentList() = throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
val expectedInfos = ExpectedInfos(bindingContext, resolutionFacade)
|
||||
.calculateForArgument(dummyCall, dummyArgument)
|
||||
collector.addElements(LambdaItems.collect(expectedInfos))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -204,9 +204,9 @@ class TypeInstantiationItems(
|
||||
}
|
||||
|
||||
val baseInsertHandler = when (visibleConstructors.size()) {
|
||||
0 -> KotlinFunctionInsertHandler(CallType.NORMAL, inputTypeArguments = false, inputValueArguments = false)
|
||||
0 -> KotlinFunctionInsertHandler(CallType.DEFAULT, inputTypeArguments = false, inputValueArguments = false)
|
||||
1 -> lookupElementFactory.insertHandlerProvider.insertHandler(visibleConstructors.single()) as KotlinFunctionInsertHandler
|
||||
else -> KotlinFunctionInsertHandler(CallType.NORMAL, inputTypeArguments = false, inputValueArguments = true)
|
||||
else -> KotlinFunctionInsertHandler(CallType.DEFAULT, inputTypeArguments = false, inputValueArguments = true)
|
||||
}
|
||||
|
||||
insertHandler = object : InsertHandler<LookupElement> {
|
||||
|
||||
Reference in New Issue
Block a user