0
# Call Type Detection
1
2
Advanced call context analysis for determining the type of call being made and providing appropriate completion suggestions. This system analyzes the syntactic context around the cursor to provide context-aware completions.
3
4
## Capabilities
5
6
### CallType
7
8
Sealed class hierarchy representing different types of calls that can occur in Kotlin code.
9
10
```kotlin { .api }
11
/**
12
* Represents the type of call being made in Kotlin code
13
* Used for context-aware completion and analysis
14
*/
15
sealed class CallType<TReceiver : KtElement?>
16
17
/**
18
* Unknown or unrecognized call context
19
*/
20
object UNKNOWN : CallType<Nothing?>
21
22
/**
23
* Default call context (no specific receiver)
24
*/
25
object DEFAULT : CallType<Nothing?>
26
27
/**
28
* Dot call (receiver.member)
29
*/
30
object DOT : CallType<KtExpression>
31
32
/**
33
* Safe call (receiver?.member)
34
*/
35
object SAFE : CallType<KtExpression>
36
37
/**
38
* Super member access (super.member)
39
*/
40
object SUPER_MEMBERS : CallType<KtSuperExpression>
41
42
/**
43
* Infix function call (receiver infix function)
44
*/
45
object INFIX : CallType<KtExpression>
46
47
/**
48
* Operator call (receiver + other)
49
*/
50
object OPERATOR : CallType<KtExpression>
51
52
/**
53
* Callable reference (::member or receiver::member)
54
*/
55
object CALLABLE_REFERENCE : CallType<KtExpression?>
56
57
/**
58
* Import directive context (import package.member)
59
*/
60
object IMPORT_DIRECTIVE : CallType<Nothing?>
61
62
/**
63
* Package directive context (package name.subpackage)
64
*/
65
object PACKAGE_DIRECTIVE : CallType<Nothing?>
66
67
/**
68
* Type context (for type annotations, generic parameters)
69
*/
70
object TYPE : CallType<Nothing?>
71
72
/**
73
* Delegate context (by delegate)
74
*/
75
object DELEGATE : CallType<Nothing?>
76
77
/**
78
* Annotation context (@Annotation)
79
*/
80
object ANNOTATION : CallType<Nothing?>
81
```
82
83
### CallTypeAndReceiver
84
85
Combines call type information with receiver details for comprehensive context analysis.
86
87
```kotlin { .api }
88
/**
89
* Combines call type with receiver information for completion context
90
* Provides both the type of call and the receiver element
91
*/
92
sealed class CallTypeAndReceiver<TReceiver : KtElement?, out TCallType : CallType<TReceiver>> {
93
abstract val callType: TCallType
94
abstract val receiver: TReceiver
95
96
/**
97
* Detects the call type and receiver for a given expression
98
* @param expression - The simple name expression to analyze
99
* @returns CallTypeAndReceiver instance with detected context
100
*/
101
companion object {
102
fun detect(expression: KtSimpleNameExpression): CallTypeAndReceiver<*, *>
103
}
104
}
105
106
/**
107
* Dot call with receiver (receiver.member)
108
*/
109
data class DOT<TReceiver : KtExpression>(
110
override val receiver: TReceiver
111
) : CallTypeAndReceiver<TReceiver, CallType.DOT>() {
112
override val callType: CallType.DOT get() = CallType.DOT
113
}
114
115
/**
116
* Safe call with receiver (receiver?.member)
117
*/
118
data class SAFE<TReceiver : KtExpression>(
119
override val receiver: TReceiver
120
) : CallTypeAndReceiver<TReceiver, CallType.SAFE>() {
121
override val callType: CallType.SAFE get() = CallType.SAFE
122
}
123
124
/**
125
* Super member access (super.member)
126
*/
127
data class SUPER_MEMBERS<TReceiver : KtSuperExpression>(
128
override val receiver: TReceiver
129
) : CallTypeAndReceiver<TReceiver, CallType.SUPER_MEMBERS>() {
130
override val callType: CallType.SUPER_MEMBERS get() = CallType.SUPER_MEMBERS
131
}
132
133
/**
134
* Infix call with receiver (receiver infix function)
135
*/
136
data class INFIX<TReceiver : KtExpression>(
137
override val receiver: TReceiver
138
) : CallTypeAndReceiver<TReceiver, CallType.INFIX>() {
139
override val callType: CallType.INFIX get() = CallType.INFIX
140
}
141
142
/**
143
* Operator call with receiver (receiver + other)
144
*/
145
data class OPERATOR<TReceiver : KtExpression>(
146
override val receiver: TReceiver
147
) : CallTypeAndReceiver<TReceiver, CallType.OPERATOR>() {
148
override val callType: CallType.OPERATOR get() = CallType.OPERATOR
149
}
150
151
/**
152
* Callable reference (::member or receiver::member)
153
*/
154
data class CALLABLE_REFERENCE<TReceiver : KtExpression?>(
155
override val receiver: TReceiver
156
) : CallTypeAndReceiver<TReceiver, CallType.CALLABLE_REFERENCE>() {
157
override val callType: CallType.CALLABLE_REFERENCE get() = CallType.CALLABLE_REFERENCE
158
}
159
160
/**
161
* Default context (no specific receiver)
162
*/
163
object DEFAULT : CallTypeAndReceiver<Nothing?, CallType.DEFAULT>() {
164
override val callType: CallType.DEFAULT get() = CallType.DEFAULT
165
override val receiver: Nothing? get() = null
166
}
167
168
/**
169
* Unknown context
170
*/
171
object UNKNOWN : CallTypeAndReceiver<Nothing?, CallType.UNKNOWN>() {
172
override val callType: CallType.UNKNOWN get() = CallType.UNKNOWN
173
override val receiver: Nothing? get() = null
174
}
175
```
176
177
**Usage Examples:**
178
179
```kotlin
180
// Detect call type from expression
181
val expression: KtSimpleNameExpression = // PSI element at cursor
182
val callTypeAndReceiver = CallTypeAndReceiver.detect(expression)
183
184
when (callTypeAndReceiver) {
185
is CallTypeAndReceiver.DOT -> {
186
println("Dot call on receiver: ${callTypeAndReceiver.receiver.text}")
187
// Provide member completions for the receiver type
188
}
189
is CallTypeAndReceiver.SAFE -> {
190
println("Safe call on receiver: ${callTypeAndReceiver.receiver.text}")
191
// Provide nullable member completions
192
}
193
is CallTypeAndReceiver.DEFAULT -> {
194
println("Default context - no specific receiver")
195
// Provide local variables, functions, and imports
196
}
197
is CallTypeAndReceiver.SUPER_MEMBERS -> {
198
println("Super member access")
199
// Provide super class member completions
200
}
201
else -> {
202
println("Other call type: ${callTypeAndReceiver.callType}")
203
}
204
}
205
```
206
207
### ReceiverType
208
209
Data class representing receiver type information for completion context.
210
211
```kotlin { .api }
212
/**
213
* Represents receiver type information for completion
214
* Contains the Kotlin type and additional metadata about the receiver
215
*/
216
data class ReceiverType(
217
/** The Kotlin type of the receiver */
218
val type: KotlinType,
219
/** Index of the receiver in implicit receiver chain */
220
val receiverIndex: Int,
221
/** Optional implicit receiver value */
222
val implicitValue: ReceiverValue?
223
) {
224
/**
225
* Extracts DSL markers from the receiver type
226
* @returns Collection of annotation class IDs representing DSL markers
227
*/
228
fun extractDslMarkers(): Collection<ClassId>
229
}
230
```
231
232
### Receiver Type Resolution
233
234
Functions for resolving receiver types from call context:
235
236
```kotlin { .api }
237
/**
238
* Gets the receiver types for a call type and receiver
239
* @param bindingContext - Binding context from analysis
240
* @param contextElement - PSI element providing context
241
* @param moduleDescriptor - Module descriptor for resolution
242
* @param resolutionFacade - Resolution facade for type resolution
243
* @param stableSmartCastsOnly - Whether to only consider stable smart casts
244
* @param withImplicitReceiversWhenExplicitPresent - Include implicit receivers even with explicit receiver
245
* @returns List of Kotlin types for the receivers
246
*/
247
fun CallTypeAndReceiver<*, *>.receiverTypes(
248
bindingContext: BindingContext,
249
contextElement: PsiElement,
250
moduleDescriptor: ModuleDescriptor,
251
resolutionFacade: ResolutionFacade,
252
stableSmartCastsOnly: Boolean,
253
withImplicitReceiversWhenExplicitPresent: Boolean = false
254
): List<KotlinType>?
255
256
/**
257
* Gets receiver types with index information
258
* @param bindingContext - Binding context from analysis
259
* @param contextElement - PSI element providing context
260
* @param moduleDescriptor - Module descriptor for resolution
261
* @param resolutionFacade - Resolution facade for type resolution
262
* @param stableSmartCastsOnly - Whether to only consider stable smart casts
263
* @param withImplicitReceiversWhenExplicitPresent - Include implicit receivers even with explicit receiver
264
* @returns List of ReceiverType objects with detailed information
265
*/
266
fun CallTypeAndReceiver<*, *>.receiverTypesWithIndex(
267
bindingContext: BindingContext,
268
contextElement: PsiElement,
269
moduleDescriptor: ModuleDescriptor,
270
resolutionFacade: ResolutionFacade,
271
stableSmartCastsOnly: Boolean,
272
withImplicitReceiversWhenExplicitPresent: Boolean = false
273
): List<ReceiverType>?
274
```
275
276
**Usage Examples:**
277
278
```kotlin
279
// Get receiver types for completion
280
val callTypeAndReceiver = CallTypeAndReceiver.detect(expression)
281
val receiverTypes = callTypeAndReceiver.receiverTypes(
282
bindingContext = bindingContext,
283
contextElement = expression,
284
moduleDescriptor = moduleDescriptor,
285
resolutionFacade = resolutionFacade,
286
stableSmartCastsOnly = true
287
)
288
289
receiverTypes?.forEach { receiverType ->
290
println("Receiver type: ${receiverType}")
291
// Get members for this receiver type
292
val members = receiverType.memberScope.getContributedDescriptors()
293
// Process members for completion
294
}
295
296
// Get detailed receiver information
297
val receiverTypesWithIndex = callTypeAndReceiver.receiverTypesWithIndex(
298
bindingContext = bindingContext,
299
contextElement = expression,
300
moduleDescriptor = moduleDescriptor,
301
resolutionFacade = resolutionFacade,
302
stableSmartCastsOnly = true
303
)
304
305
receiverTypesWithIndex?.forEach { receiverType ->
306
println("Receiver ${receiverType.receiverIndex}: ${receiverType.type}")
307
receiverType.implicitValue?.let { implicit ->
308
println(" Implicit value: $implicit")
309
}
310
311
// Extract DSL markers for context-aware completion
312
val dslMarkers = receiverType.extractDslMarkers()
313
if (dslMarkers.isNotEmpty()) {
314
println(" DSL markers: ${dslMarkers.joinToString()}")
315
}
316
}
317
```
318
319
## Integration with Completion System
320
321
The call type detection system is automatically used by the completion engine:
322
323
```kotlin
324
// Internal usage in completion system
325
private val getDescriptorsQualified = ResultGetter { element, options ->
326
val expression = element.thisOrParent<KtQualifiedExpression>() ?: return@ResultGetter null
327
328
val receiverExpression = expression.receiverExpression
329
val expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE_INFO, receiverExpression)?.type
330
331
DescriptorsResult(targetElement = expression).apply {
332
if (expressionType != null) {
333
sortNeeded = false
334
descriptors.addAll(
335
getVariantsHelper { true }
336
.getReferenceVariants(
337
receiverExpression,
338
CallTypeAndReceiver.DOT(receiverExpression), // Using call type detection
339
DescriptorKindFilter.ALL,
340
ALL_NAME_FILTER,
341
filterOutShadowed = options.filterOutShadowedDescriptors,
342
)
343
)
344
}
345
}
346
}
347
```
348
349
## Context-Aware Completion Scenarios
350
351
Different call types enable different completion strategies:
352
353
### Dot Call Completion
354
```kotlin
355
val list = listOf(1, 2, 3)
356
list. // DOT call type
357
// Provides: map, filter, size, isEmpty, etc.
358
```
359
360
### Safe Call Completion
361
```kotlin
362
val nullable: String? = "hello"
363
nullable?. // SAFE call type
364
// Provides: length, uppercase, lowercase, etc. (nullable context)
365
```
366
367
### Super Member Completion
368
```kotlin
369
class Child : Parent() {
370
override fun method() {
371
super. // SUPER_MEMBERS call type
372
// Provides: parent class members only
373
}
374
}
375
```
376
377
### Import Completion
378
```kotlin
379
import kotlin.collections. // IMPORT_DIRECTIVE call type
380
// Provides: package members and subpackages
381
```
382
383
### Type Context Completion
384
```kotlin
385
fun method(): List< // TYPE call type
386
// Provides: type names, generic parameters
387
```