@@ -8,39 +8,45 @@ import org.jetbrains.kotlin.analyzer.AnalysisResult
88import org.jetbrains.kotlin.config.CompilerConfiguration
99import org.jetbrains.kotlin.container.StorageComponentContainer
1010import org.jetbrains.kotlin.container.useInstance
11+ import org.jetbrains.kotlin.descriptors.CallableDescriptor
1112import org.jetbrains.kotlin.descriptors.ClassDescriptor
1213import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
1314import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
1415import org.jetbrains.kotlin.descriptors.FunctionDescriptor
1516import org.jetbrains.kotlin.descriptors.ModuleDescriptor
16- import org.jetbrains.kotlin.descriptors.ParameterDescriptor
1717import org.jetbrains.kotlin.descriptors.PropertyDescriptor
1818import org.jetbrains.kotlin.descriptors.SourceElement
19+ import org.jetbrains.kotlin.descriptors.ValueDescriptor
1920import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
2021import 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
2323import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
2424import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
2525import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaField
26+ import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
2627import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
2728import org.jetbrains.kotlin.load.kotlin.VirtualFileKotlinClass
2829import org.jetbrains.kotlin.load.kotlin.getContainingKotlinJvmBinaryClass
2930import org.jetbrains.kotlin.platform.TargetPlatform
3031import org.jetbrains.kotlin.psi.KtDeclaration
3132import org.jetbrains.kotlin.psi.KtFile
3233import 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
3535import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
3636import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
37+ import org.jetbrains.kotlin.resolve.calls.model.ExpressionKotlinCallArgument
3738import 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
3941import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
4042import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
43+ import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
4144import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
45+ import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedTypeAliasDescriptor
46+ import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
4247import org.jetbrains.kotlin.types.KotlinType
4348import org.jetbrains.kotlin.types.TypeConstructor
49+ import org.jetbrains.kotlin.types.getAbbreviation
4450import org.jetbrains.kotlin.types.typeUtil.supertypes
4551import java.io.BufferedOutputStream
4652import java.io.File
@@ -77,7 +83,22 @@ class JdepsGenExtension(
7783 * @return the path corresponding to the JAR where this class was loaded from, or null.
7884 */
7985 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) {
81102 is JavaSourceElement ->
82103 if (sourceElement.javaElement is BinaryJavaClass ) {
83104 (sourceElement.javaElement as BinaryJavaClass ).virtualFile.canonicalPath
@@ -92,13 +113,21 @@ class JdepsGenExtension(
92113 // Ignore Java source local to this module.
93114 null
94115 }
116+
95117 is KotlinJvmBinarySourceElement ->
96118 (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+ }
98127 }
99128 }
100129
101- fun getClassCanonicalPath (typeConstructor : TypeConstructor ): String? {
130+ private fun getClassCanonicalPath (typeConstructor : TypeConstructor ): String? {
102131 return (typeConstructor.declarationDescriptor as ? DeclarationDescriptorWithSource )?.let {
103132 getClassCanonicalPath(
104133 it,
@@ -130,54 +159,88 @@ class JdepsGenExtension(
130159 reportOn : PsiElement ,
131160 context : CallCheckerContext ,
132161 ) {
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)
139188 }
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+ }
144203 }
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+ }
151236 }
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)
162237 }
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 )
177242 }
178- collectTypeReferences(resultingDescriptor.type, isExplicit = false )
179243 }
180- else -> return
181244 }
182245 }
183246
@@ -192,8 +255,9 @@ class JdepsGenExtension(
192255 collectTypeReferences(it)
193256 }
194257 }
258+
195259 is FunctionDescriptor -> {
196- descriptor.returnType?.let { collectTypeReferences(it) }
260+ descriptor.returnType?.let { collectTypeReferences(it, collectTypeArguments = false ) }
197261 descriptor.valueParameters.forEach { valueParameter ->
198262 collectTypeReferences(valueParameter.type)
199263 }
@@ -204,6 +268,7 @@ class JdepsGenExtension(
204268 collectTypeReferences(it)
205269 }
206270 }
271+
207272 is PropertyDescriptor -> {
208273 collectTypeReferences(descriptor.type)
209274 descriptor.annotations.forEach { annotation ->
@@ -213,6 +278,7 @@ class JdepsGenExtension(
213278 collectTypeReferences(annotation.type)
214279 }
215280 }
281+
216282 is LocalVariableDescriptor -> {
217283 collectTypeReferences(descriptor.type)
218284 }
@@ -245,6 +311,17 @@ class JdepsGenExtension(
245311 }
246312 }
247313
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+
248325 kotlinType.supertypes().forEach { supertype ->
249326 collectTypeReferences(
250327 supertype,
0 commit comments