@@ -8,39 +8,45 @@ import org.jetbrains.kotlin.analyzer.AnalysisResult
8
8
import org.jetbrains.kotlin.config.CompilerConfiguration
9
9
import org.jetbrains.kotlin.container.StorageComponentContainer
10
10
import org.jetbrains.kotlin.container.useInstance
11
+ import org.jetbrains.kotlin.descriptors.CallableDescriptor
11
12
import org.jetbrains.kotlin.descriptors.ClassDescriptor
12
13
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
13
14
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
14
15
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
15
16
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
16
- import org.jetbrains.kotlin.descriptors.ParameterDescriptor
17
17
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
18
18
import org.jetbrains.kotlin.descriptors.SourceElement
19
+ import org.jetbrains.kotlin.descriptors.ValueDescriptor
19
20
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
20
21
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
21
- import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
22
- import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor
22
+ import org.jetbrains.kotlin.load.java.descriptors.JavaClassConstructorDescriptor
23
23
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
24
24
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
25
25
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaField
26
+ import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
26
27
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
27
28
import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass
28
29
import org.jetbrains.kotlin.load.kotlin.getContainingKotlinJvmBinaryClass
29
30
import org.jetbrains.kotlin.platform.TargetPlatform
30
31
import org.jetbrains.kotlin.psi.KtDeclaration
31
32
import org.jetbrains.kotlin.psi.KtFile
32
33
import org.jetbrains.kotlin.resolve.BindingTrace
33
- import org.jetbrains.kotlin.resolve.FunctionImportedFromObject
34
- import org.jetbrains.kotlin.resolve.PropertyImportedFromObject
34
+ import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
35
35
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
36
36
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
37
+ import org.jetbrains.kotlin.resolve.calls.model.ExpressionKotlinCallArgument
37
38
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
38
- import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
39
+ import org.jetbrains.kotlin.resolve.calls.tower.NewAbstractResolvedCall
40
+ import org.jetbrains.kotlin.resolve.calls.tower.PSIKotlinCallArgument
39
41
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
40
42
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
43
+ import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
41
44
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
45
+ import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedTypeAliasDescriptor
46
+ import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
42
47
import org.jetbrains.kotlin.types.KotlinType
43
48
import org.jetbrains.kotlin.types.TypeConstructor
49
+ import org.jetbrains.kotlin.types.getAbbreviation
44
50
import org.jetbrains.kotlin.types.typeUtil.supertypes
45
51
import java.io.BufferedOutputStream
46
52
import java.io.File
@@ -77,7 +83,22 @@ class JdepsGenExtension(
77
83
* @return the path corresponding to the JAR where this class was loaded from, or null.
78
84
*/
79
85
fun getClassCanonicalPath (descriptor : DeclarationDescriptorWithSource ): String? {
80
- return when (val sourceElement: SourceElement = descriptor.source) {
86
+ // Get the descriptor's source element which may be a type alias
87
+ val sourceElement = if (descriptor.source != SourceElement .NO_SOURCE ) {
88
+ descriptor.source
89
+ } else {
90
+ when (val declarationDescriptor = descriptor.getImportableDescriptor()) {
91
+ is DeserializedTypeAliasDescriptor -> {
92
+ declarationDescriptor.containerSource
93
+ }
94
+
95
+ else -> {
96
+ null
97
+ }
98
+ }
99
+ }
100
+
101
+ return when (sourceElement) {
81
102
is JavaSourceElement ->
82
103
if (sourceElement.javaElement is BinaryJavaClass ) {
83
104
(sourceElement.javaElement as BinaryJavaClass ).virtualFile.canonicalPath
@@ -92,13 +113,21 @@ class JdepsGenExtension(
92
113
// Ignore Java source local to this module.
93
114
null
94
115
}
116
+
95
117
is KotlinJvmBinarySourceElement ->
96
118
(sourceElement.binaryClass as VirtualFileKotlinClass ).file.canonicalPath
97
- else -> null
119
+
120
+ is JvmPackagePartSource -> { // This case is needed to collect type aliases
121
+ ((sourceElement.knownJvmBinaryClass) as VirtualFileKotlinClass ).file.canonicalPath
122
+ }
123
+
124
+ else -> {
125
+ null
126
+ }
98
127
}
99
128
}
100
129
101
- fun getClassCanonicalPath (typeConstructor : TypeConstructor ): String? {
130
+ private fun getClassCanonicalPath (typeConstructor : TypeConstructor ): String? {
102
131
return (typeConstructor.declarationDescriptor as ? DeclarationDescriptorWithSource )?.let {
103
132
getClassCanonicalPath(
104
133
it,
@@ -130,54 +159,88 @@ class JdepsGenExtension(
130
159
reportOn : PsiElement ,
131
160
context : CallCheckerContext ,
132
161
) {
133
- when (val resultingDescriptor = resolvedCall.resultingDescriptor) {
134
- is FunctionImportedFromObject -> {
135
- collectTypeReferences(resultingDescriptor.containingObject.defaultType)
136
- }
137
- is PropertyImportedFromObject -> {
138
- collectTypeReferences(resultingDescriptor.containingObject.defaultType)
162
+ // First collect type from the Resolved Call
163
+ collectExplicitTypes(resolvedCall)
164
+
165
+ resolvedCall.valueArguments.keys.forEach { valueArgument ->
166
+ collectTypeReferences(valueArgument.type, isExplicit = false )
167
+ }
168
+
169
+ // And then collect types from any ResultingDescriptor
170
+ val resultingDescriptor = resolvedCall.resultingDescriptor
171
+ collectExplicitTypes(resultingDescriptor)
172
+
173
+ val isExplicitReturnType = resultingDescriptor is JavaClassConstructorDescriptor
174
+ resultingDescriptor.returnType?.let {
175
+ collectTypeReferences(it, isExplicit = isExplicitReturnType, collectTypeArguments = false )
176
+ }
177
+
178
+ resultingDescriptor.valueParameters.forEach { valueParameter ->
179
+ collectTypeReferences(valueParameter.type, isExplicit = false )
180
+ }
181
+
182
+ // Finally, collect types that depend on the type of the ResultingDescriptor and note that
183
+ // these descriptors may be composed of multiple classes that we need to extract types from
184
+ if (resultingDescriptor is DeclarationDescriptor ) {
185
+ val containingDeclaration = resultingDescriptor.containingDeclaration
186
+ if (containingDeclaration is ClassDescriptor ) {
187
+ collectTypeReferences(containingDeclaration.defaultType)
139
188
}
140
- is JavaMethodDescriptor -> {
141
- getClassCanonicalPath(
142
- (resultingDescriptor.containingDeclaration as ClassDescriptor ).typeConstructor,
143
- )?.let { explicitClassesCanonicalPaths.add(it) }
189
+
190
+ if (resultingDescriptor is PropertyDescriptor ) {
191
+ (
192
+ resultingDescriptor.getter
193
+ ?.correspondingProperty as ? SyntheticJavaPropertyDescriptor
194
+ )
195
+ ?.let { syntheticJavaPropertyDescriptor ->
196
+ collectTypeReferences(syntheticJavaPropertyDescriptor.type, isExplicit = false )
197
+
198
+ val functionDescriptor = syntheticJavaPropertyDescriptor.getMethod
199
+ functionDescriptor.dispatchReceiverParameter?.type?.let { dispatchReceiverType ->
200
+ collectTypeReferences(dispatchReceiverType, isExplicit = false )
201
+ }
202
+ }
144
203
}
145
- is FunctionDescriptor -> {
146
- resultingDescriptor.returnType?.let {
147
- collectTypeReferences(it, isExplicit = false , collectTypeArguments = false )
148
- }
149
- resultingDescriptor.valueParameters.forEach { valueParameter ->
150
- collectTypeReferences(valueParameter.type, isExplicit = false )
204
+ }
205
+
206
+ if (resultingDescriptor is ImportedFromObjectCallableDescriptor <* >) {
207
+ collectTypeReferences(resultingDescriptor.containingObject.defaultType, isExplicit = false )
208
+ }
209
+
210
+ if (resultingDescriptor is ValueDescriptor ) {
211
+ collectTypeReferences(resultingDescriptor.type, isExplicit = false )
212
+ }
213
+ }
214
+
215
+ private fun collectExplicitTypes (resultingDescriptor : CallableDescriptor ) {
216
+ val kotlinJvmBinaryClass = resultingDescriptor.getContainingKotlinJvmBinaryClass()
217
+ if (kotlinJvmBinaryClass is VirtualFileKotlinClass ) {
218
+ explicitClassesCanonicalPaths.add(kotlinJvmBinaryClass.file.path)
219
+ }
220
+ }
221
+
222
+ private fun collectExplicitTypes (resolvedCall : ResolvedCall <* >) {
223
+ val kotlinCallArguments = (resolvedCall as ? NewAbstractResolvedCall )
224
+ ?.resolvedCallAtom?.atom?.argumentsInParenthesis
225
+
226
+ // note that callArgument can be both a PSIKotlinCallArgument and an ExpressionKotlinCallArgument
227
+ kotlinCallArguments?.forEach { callArgument ->
228
+ if (callArgument is PSIKotlinCallArgument ) {
229
+ val dataFlowInfos = listOf (callArgument.dataFlowInfoBeforeThisArgument) +
230
+ callArgument.dataFlowInfoAfterThisArgument
231
+
232
+ dataFlowInfos.forEach { dataFlowInfo ->
233
+ dataFlowInfo.completeTypeInfo.values().flatten().forEach { kotlinType ->
234
+ collectTypeReferences(kotlinType, isExplicit = true )
235
+ }
151
236
}
152
- val virtualFileClass =
153
- resultingDescriptor.getContainingKotlinJvmBinaryClass() as ? VirtualFileKotlinClass
154
- ? : return
155
- explicitClassesCanonicalPaths.add(virtualFileClass.file.path)
156
- }
157
- is ParameterDescriptor -> {
158
- getClassCanonicalPath(resultingDescriptor)?.let { explicitClassesCanonicalPaths.add(it) }
159
- }
160
- is FakeCallableDescriptorForObject -> {
161
- collectTypeReferences(resultingDescriptor.type)
162
237
}
163
- is JavaPropertyDescriptor -> {
164
- getClassCanonicalPath(resultingDescriptor)?.let { explicitClassesCanonicalPaths.add(it) }
165
- }
166
- is PropertyDescriptor -> {
167
- when (resultingDescriptor.containingDeclaration) {
168
- is ClassDescriptor -> collectTypeReferences(
169
- (resultingDescriptor.containingDeclaration as ClassDescriptor ).defaultType,
170
- )
171
- else -> {
172
- val virtualFileClass =
173
- (resultingDescriptor).getContainingKotlinJvmBinaryClass() as ? VirtualFileKotlinClass
174
- ? : return
175
- explicitClassesCanonicalPaths.add(virtualFileClass.file.path)
176
- }
238
+
239
+ if (callArgument is ExpressionKotlinCallArgument ) {
240
+ callArgument.receiver.allOriginalTypes.forEach { kotlinType ->
241
+ collectTypeReferences(kotlinType, isExplicit = true )
177
242
}
178
- collectTypeReferences(resultingDescriptor.type, isExplicit = false )
179
243
}
180
- else -> return
181
244
}
182
245
}
183
246
@@ -192,8 +255,9 @@ class JdepsGenExtension(
192
255
collectTypeReferences(it)
193
256
}
194
257
}
258
+
195
259
is FunctionDescriptor -> {
196
- descriptor.returnType?.let { collectTypeReferences(it) }
260
+ descriptor.returnType?.let { collectTypeReferences(it, collectTypeArguments = false ) }
197
261
descriptor.valueParameters.forEach { valueParameter ->
198
262
collectTypeReferences(valueParameter.type)
199
263
}
@@ -204,6 +268,7 @@ class JdepsGenExtension(
204
268
collectTypeReferences(it)
205
269
}
206
270
}
271
+
207
272
is PropertyDescriptor -> {
208
273
collectTypeReferences(descriptor.type)
209
274
descriptor.annotations.forEach { annotation ->
@@ -213,6 +278,7 @@ class JdepsGenExtension(
213
278
collectTypeReferences(annotation.type)
214
279
}
215
280
}
281
+
216
282
is LocalVariableDescriptor -> {
217
283
collectTypeReferences(descriptor.type)
218
284
}
@@ -245,6 +311,17 @@ class JdepsGenExtension(
245
311
}
246
312
}
247
313
314
+ // Collect type aliases aka abbreviations
315
+ // See: https://github.com/Kotlin/KEEP/blob/master/proposals/type-aliases.md#type-alias-expansion
316
+ kotlinType.getAbbreviation()?.let { abbreviationType ->
317
+ collectTypeReferences(
318
+ abbreviationType,
319
+ isExplicit = isExplicit,
320
+ collectTypeArguments = collectTypeArguments,
321
+ visitedKotlinTypes = visitedKotlinTypes,
322
+ )
323
+ }
324
+
248
325
kotlinType.supertypes().forEach { supertype ->
249
326
collectTypeReferences(
250
327
supertype,
0 commit comments