xref: /aosp_15_r20/external/ksp/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/symbol/impl/utils.kt (revision af87fb4bb8e3042070d2a054e912924f599b22b7)
1 /*
<lambda>null2  * Copyright 2020 Google LLC
3  * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 package com.google.devtools.ksp.symbol.impl
18 
19 import com.google.devtools.ksp.BinaryClassInfoCache
20 import com.google.devtools.ksp.ExceptionMessage
21 import com.google.devtools.ksp.KspExperimental
22 import com.google.devtools.ksp.processing.impl.ResolverImpl
23 import com.google.devtools.ksp.processing.impl.workaroundForNested
24 import com.google.devtools.ksp.symbol.*
25 import com.google.devtools.ksp.symbol.Variance
26 import com.google.devtools.ksp.symbol.impl.binary.KSClassDeclarationDescriptorImpl
27 import com.google.devtools.ksp.symbol.impl.binary.KSDeclarationDescriptorImpl
28 import com.google.devtools.ksp.symbol.impl.binary.KSFunctionDeclarationDescriptorImpl
29 import com.google.devtools.ksp.symbol.impl.binary.KSPropertyDeclarationDescriptorImpl
30 import com.google.devtools.ksp.symbol.impl.binary.KSTypeArgumentDescriptorImpl
31 import com.google.devtools.ksp.symbol.impl.java.*
32 import com.google.devtools.ksp.symbol.impl.kotlin.*
33 import com.google.devtools.ksp.symbol.impl.synthetic.KSPropertyGetterSyntheticImpl
34 import com.google.devtools.ksp.symbol.impl.synthetic.KSPropertySetterSyntheticImpl
35 import com.google.devtools.ksp.symbol.impl.synthetic.KSValueParameterSyntheticImpl
36 import com.intellij.psi.*
37 import com.intellij.psi.impl.light.LightMethod
38 import com.intellij.psi.impl.source.PsiClassImpl
39 import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMapper
40 import org.jetbrains.kotlin.descriptors.*
41 import org.jetbrains.kotlin.load.java.descriptors.JavaClassConstructorDescriptor
42 import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
43 import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolver
44 import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
45 import org.jetbrains.kotlin.load.java.structure.impl.JavaConstructorImpl
46 import org.jetbrains.kotlin.load.java.structure.impl.JavaMethodImpl
47 import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaField
48 import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaMethodBase
49 import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
50 import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
51 import org.jetbrains.kotlin.load.kotlin.getContainingKotlinJvmBinaryClass
52 import org.jetbrains.kotlin.name.Name
53 import org.jetbrains.kotlin.psi.*
54 import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
55 import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
56 import org.jetbrains.kotlin.resolve.descriptorUtil.getOwnerForEffectiveDispatchReceiverParameter
57 import org.jetbrains.kotlin.resolve.source.getPsi
58 import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
59 import org.jetbrains.kotlin.types.*
60 import java.util.*
61 import kotlin.Comparator
62 import kotlin.collections.ArrayDeque
63 
64 fun PsiElement.findParentAnnotated(): KSAnnotated? {
65     var parent = when (this) {
66         // Unfortunately, LightMethod doesn't implement parent.
67         is LightMethod -> this.containingClass
68         else -> this.parent
69     }
70 
71     while (parent != null && parent !is KtDeclaration && parent !is KtFile && parent !is PsiClass &&
72         parent !is PsiMethod && parent !is PsiJavaFile && parent !is KtTypeAlias
73     ) {
74         parent = parent.parent
75     }
76 
77     return when (parent) {
78         is KtClassOrObject -> KSClassDeclarationImpl.getCached(parent)
79         is KtFile -> KSFileImpl.getCached(parent)
80         is KtFunction -> KSFunctionDeclarationImpl.getCached(parent)
81         is PsiClass -> KSClassDeclarationJavaImpl.getCached(parent)
82         is PsiJavaFile -> KSFileJavaImpl.getCached(parent)
83         is PsiMethod -> KSFunctionDeclarationJavaImpl.getCached(parent)
84         is KtProperty -> KSPropertyDeclarationImpl.getCached(parent)
85         is KtPropertyAccessor -> if (parent.isGetter) {
86             KSPropertyGetterImpl.getCached(parent)
87         } else {
88             KSPropertySetterImpl.getCached(parent)
89         }
90         is KtTypeAlias -> KSTypeAliasImpl.getCached(parent)
91         else -> null
92     }
93 }
94 
findParentDeclarationnull95 fun PsiElement.findParentDeclaration(): KSDeclaration? {
96     return this.findParentAnnotated() as? KSDeclaration
97 }
98 
toLocationnull99 fun PsiElement.toLocation(): Location {
100     val file = this.containingFile
101     val document = ResolverImpl.instance!!.psiDocumentManager.getDocument(file) ?: return NonExistLocation
102     return FileLocation(file.virtualFile.path, document.getLineNumber(this.textOffset) + 1)
103 }
104 
105 // TODO: handle local functions/classes correctly
Sequencenull106 fun Sequence<KtElement>.getKSDeclarations(): Sequence<KSDeclaration> =
107     this.mapNotNull {
108         when (it) {
109             is KtFunction -> KSFunctionDeclarationImpl.getCached(it)
110             is KtProperty -> KSPropertyDeclarationImpl.getCached(it)
111             is KtClassOrObject -> KSClassDeclarationImpl.getCached(it)
112             is KtTypeAlias -> KSTypeAliasImpl.getCached(it)
113             else -> null
114         }
115     }
116 
getKSJavaDeclarationsnull117 fun List<PsiElement>.getKSJavaDeclarations() =
118     this.mapNotNull {
119         when (it) {
120             is PsiClass -> KSClassDeclarationJavaImpl.getCached(it)
121             is PsiMethod -> KSFunctionDeclarationJavaImpl.getCached(it)
122             is PsiField -> KSPropertyDeclarationJavaImpl.getCached(it)
123             else -> null
124         }
125     }
126 
orgnull127 fun org.jetbrains.kotlin.types.Variance.toKSVariance(): Variance {
128     return when (this) {
129         org.jetbrains.kotlin.types.Variance.IN_VARIANCE -> Variance.CONTRAVARIANT
130         org.jetbrains.kotlin.types.Variance.OUT_VARIANCE -> Variance.COVARIANT
131         org.jetbrains.kotlin.types.Variance.INVARIANT -> Variance.INVARIANT
132         else -> throw IllegalStateException("Unexpected variance value $this, $ExceptionMessage")
133     }
134 }
135 
KSTypeReferencenull136 private fun KSTypeReference.toKotlinType() = (resolve() as? KSTypeImpl)?.kotlinType
137 
138 // returns null if error
139 internal fun KotlinType.replaceTypeArguments(newArguments: List<KSTypeArgument>): KotlinType? {
140     if (newArguments.isNotEmpty() && this.arguments.size != newArguments.size)
141         return null
142     return replace(
143         newArguments.mapIndexed { index, ksTypeArgument ->
144             val variance = when (ksTypeArgument.variance) {
145                 Variance.INVARIANT -> org.jetbrains.kotlin.types.Variance.INVARIANT
146                 Variance.COVARIANT -> org.jetbrains.kotlin.types.Variance.OUT_VARIANCE
147                 Variance.CONTRAVARIANT -> org.jetbrains.kotlin.types.Variance.IN_VARIANCE
148                 Variance.STAR -> return@mapIndexed StarProjectionImpl(constructor.parameters[index])
149             }
150 
151             val type = when (ksTypeArgument) {
152                 is KSTypeArgumentKtImpl, is KSTypeArgumentJavaImpl, is KSTypeArgumentLiteImpl -> ksTypeArgument.type!!
153                 is KSTypeArgumentDescriptorImpl -> return@mapIndexed ksTypeArgument.descriptor
154                 else -> throw IllegalStateException(
155                     "Unexpected psi for type argument: ${ksTypeArgument.javaClass}, $ExceptionMessage"
156                 )
157             }.toKotlinType() ?: return null
158 
159             TypeProjectionImpl(variance, type)
160         }
161     )
162 }
163 
toKSDeclarationnull164 internal fun FunctionDescriptor.toKSDeclaration(): KSDeclaration {
165     if (this.kind != CallableMemberDescriptor.Kind.DECLARATION)
166         return KSFunctionDeclarationDescriptorImpl.getCached(this)
167     val psi = this.findPsi() ?: return KSFunctionDeclarationDescriptorImpl.getCached(this)
168     // Java default constructor has a kind DECLARATION of while still being synthetic.
169     if (psi is PsiClassImpl && this is JavaClassConstructorDescriptor) {
170         return KSFunctionDeclarationDescriptorImpl.getCached(this)
171     }
172     return when (psi) {
173         is KtFunction -> KSFunctionDeclarationImpl.getCached(psi)
174         is PsiMethod -> KSFunctionDeclarationJavaImpl.getCached(psi)
175         is KtProperty -> KSPropertyDeclarationImpl.getCached(psi)
176         else -> throw IllegalStateException("unexpected psi: ${psi.javaClass}")
177     }
178 }
179 
toKSPropertyDeclarationnull180 internal fun PropertyDescriptor.toKSPropertyDeclaration(): KSPropertyDeclaration {
181     if (this.kind != CallableMemberDescriptor.Kind.DECLARATION)
182         return KSPropertyDeclarationDescriptorImpl.getCached(this)
183     val psi = this.findPsi() ?: return KSPropertyDeclarationDescriptorImpl.getCached(this)
184     return when (psi) {
185         is KtProperty -> KSPropertyDeclarationImpl.getCached(psi)
186         is KtParameter -> KSPropertyDeclarationParameterImpl.getCached(psi)
187         is PsiField -> KSPropertyDeclarationJavaImpl.getCached(psi)
188         is PsiMethod -> {
189             // happens when a java class implements a kotlin interface that declares properties.
190             KSPropertyDeclarationDescriptorImpl.getCached(this)
191         }
192         else -> throw IllegalStateException("unexpected psi: ${psi.javaClass}")
193     }
194 }
195 
196 /**
197  * @see KSFunctionDeclaration.findOverridee / [KSPropertyDeclaration.findOverridee] for docs.
198  */
findClosestOverrideenull199 internal inline fun <reified T : CallableMemberDescriptor> T.findClosestOverridee(): T? {
200     // When there is an intermediate class between the overridden and our function, we might receive
201     // a FAKE_OVERRIDE function which is not desired as we are trying to find the actual
202     // declared method.
203 
204     // we also want to return the closes function declaration. That is either the closest
205     // class / interface method OR in case of equal distance (e.g. diamon dinheritance), pick the
206     // one declared first in the code.
207 
208     (getOwnerForEffectiveDispatchReceiverParameter() as? ClassDescriptor)?.defaultType?.let {
209         ResolverImpl.instance!!.incrementalContext.recordLookupWithSupertypes(it)
210     }
211 
212     val queue = ArrayDeque<T>()
213     queue.add(this)
214 
215     while (queue.isNotEmpty()) {
216         val current = queue.removeFirst()
217         ResolverImpl.instance!!.incrementalContext.recordLookupForCallableMemberDescriptor(current.original)
218         val overriddenDescriptors: Collection<T> = current.original.overriddenDescriptors.filterIsInstance<T>()
219         overriddenDescriptors.firstOrNull {
220             it.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE
221         }?.let {
222             ResolverImpl.instance!!.incrementalContext.recordLookupForCallableMemberDescriptor(it.original)
223             return it.original as T?
224         }
225         // if all methods are fake, add them to the queue
226         queue.addAll(overriddenDescriptors)
227     }
228     return null
229 }
230 
resolveContainingClassnull231 internal fun ModuleClassResolver.resolveContainingClass(psiMethod: PsiMethod): ClassDescriptor? {
232     return if (psiMethod.isConstructor) {
233         resolveClass(JavaConstructorImpl(psiMethod).containingClass.apply { workaroundForNested() })
234     } else {
235         resolveClass(JavaMethodImpl(psiMethod).containingClass.apply { workaroundForNested() })
236     }
237 }
238 
getInstanceForCurrentRoundnull239 internal fun getInstanceForCurrentRound(node: KSNode): KSNode? {
240     return when (node.origin) {
241         Origin.KOTLIN_LIB, Origin.JAVA_LIB -> null
242         else -> when (node) {
243             is KSClassDeclarationImpl -> KSClassDeclarationImpl.getCached(node.ktClassOrObject)
244             is KSFileImpl -> KSFileImpl.getCached(node.file)
245             is KSFunctionDeclarationImpl -> KSFunctionDeclarationImpl.getCached(node.ktFunction)
246             is KSPropertyDeclarationImpl -> KSPropertyDeclarationImpl.getCached(node.ktProperty)
247             is KSPropertyGetterImpl -> KSPropertyGetterImpl.getCached(node.ktPropertyAccessor)
248             is KSPropertySetterImpl -> KSPropertySetterImpl.getCached(node.ktPropertyAccessor)
249             is KSTypeAliasImpl -> KSTypeAliasImpl.getCached(node.ktTypeAlias)
250             is KSTypeArgumentLiteImpl -> KSTypeArgumentLiteImpl.getCached(node.type, node.variance)
251             is KSTypeArgumentKtImpl -> KSTypeArgumentKtImpl.getCached(node.ktTypeArgument)
252             is KSTypeParameterImpl -> KSTypeParameterImpl.getCached(node.ktTypeParameter)
253             is KSTypeReferenceImpl -> KSTypeReferenceImpl.getCached(node.ktTypeReference)
254             is KSValueParameterImpl -> KSValueParameterImpl.getCached(node.ktParameter)
255             is KSClassDeclarationJavaEnumEntryImpl -> KSClassDeclarationJavaEnumEntryImpl.getCached(node.psi)
256             is KSClassDeclarationJavaImpl -> KSClassDeclarationJavaImpl.getCached(node.psi)
257             is KSFileJavaImpl -> KSFileJavaImpl.getCached(node.psi)
258             is KSFunctionDeclarationJavaImpl -> KSFunctionDeclarationJavaImpl.getCached(node.psi)
259             is KSPropertyDeclarationJavaImpl -> KSPropertyDeclarationJavaImpl.getCached(node.psi)
260             is KSTypeArgumentJavaImpl -> KSTypeArgumentJavaImpl.getCached(node.psi, node.parent)
261             is KSTypeParameterJavaImpl -> KSTypeParameterJavaImpl.getCached(node.psi)
262             is KSTypeReferenceJavaImpl ->
263                 KSTypeReferenceJavaImpl.getCached(node.psi, (node.parent as? KSAnnotated)?.getInstanceForCurrentRound())
264             is KSValueParameterJavaImpl -> KSValueParameterJavaImpl.getCached(node.psi)
265             is KSPropertyGetterSyntheticImpl -> KSPropertyGetterSyntheticImpl.getCached(node.ksPropertyDeclaration)
266             is KSPropertySetterSyntheticImpl -> KSPropertySetterSyntheticImpl.getCached(node.ksPropertyDeclaration)
267             is KSValueParameterSyntheticImpl ->
268                 KSPropertySetterImpl.getCached(node.owner as KtPropertyAccessor).parameter
269             is KSAnnotationJavaImpl -> KSAnnotationJavaImpl.getCached(node.psi)
270             is KSAnnotationImpl -> KSAnnotationImpl.getCached(node.ktAnnotationEntry)
271             is KSClassifierReferenceJavaImpl -> KSClassifierReferenceJavaImpl.getCached(node.psi, node.parent)
272             is KSValueArgumentJavaImpl ->
273                 KSValueArgumentJavaImpl.getCached(node.name, node.value, getInstanceForCurrentRound(node.parent!!))
274             else -> null
275         }
276     }
277 }
278 
getInstanceForCurrentRoundnull279 internal fun KSAnnotated.getInstanceForCurrentRound(): KSAnnotated? = getInstanceForCurrentRound(this) as? KSAnnotated
280 
281 /**
282  * Helper class to read the order of fields/methods in a .class file compiled from Kotlin.
283  *
284  * When a compiled Kotlin class is read from descriptors, the order of fields / methods do not match
285  * the order in the original source file (or the .class file).
286  * This helper class reads the order from the binary class (using the visitor API) and allows
287  * [KSClassDeclarationDescriptorImpl] to sort its declarations based on the .class file.
288  *
289  * Note that the ordering is relevant only for fields and methods. For any other declaration, the
290  * order that was returned from the descriptor API is kept.
291  *
292  * see: https://github.com/google/ksp/issues/250
293  */
294 @KspExperimental
295 internal class DeclarationOrdering(
296     binaryClass: KotlinJvmBinaryClass
297 ) : KotlinJvmBinaryClass.MemberVisitor {
298     // Map of fieldName -> Order
299     private val fieldOrdering = mutableMapOf<String, Int>()
300     // Map of method name to (jvm desc -> Order) map
301     // multiple methods might have the same name, hence we need to use signature matching for
302     // methods. That being said, we only do it when we find multiple methods with the same name
303     // otherwise, there is no reason to compute the jvm signature.
304     private val methodOrdering = mutableMapOf<String, MutableMap<String, Int>>()
305     // This map is built while we are sorting to ensure for the same declaration, we return the same
306     // order, in case it is not found in fields / methods.
307     private val declOrdering = IdentityHashMap<KSDeclaration, Int>()
308     // Helper class to generate ids that can be used for comparison.
309     private val orderProvider = OrderProvider()
310 
311     init {
312         binaryClass.visitMembers(this, null)
313         orderProvider.seal()
314     }
315 
316     val comparator = Comparator<KSDeclarationDescriptorImpl> { first, second ->
317         getOrder(first).compareTo(getOrder(second))
318     }
319 
320     private fun getOrder(decl: KSDeclarationDescriptorImpl): Int {
321         return declOrdering.getOrPut(decl) {
322             when (decl) {
323                 is KSPropertyDeclarationDescriptorImpl -> {
324                     fieldOrdering[decl.simpleName.asString()]?.let {
325                         return@getOrPut it
326                     }
327                     // might be a property without backing field. Use method ordering instead
328                     decl.getter?.let { getter ->
329                         return@getOrPut findMethodOrder(
330                             ResolverImpl.instance!!.getJvmName(getter).toString()
331                         ) {
332                             ResolverImpl.instance!!.mapToJvmSignature(getter)
333                         }
334                     }
335                     decl.setter?.let { setter ->
336                         return@getOrPut findMethodOrder(
337                             ResolverImpl.instance!!.getJvmName(setter).toString()
338                         ) {
339                             ResolverImpl.instance!!.mapToJvmSignature(setter)
340                         }
341                     }
342                     orderProvider.next(decl)
343                 }
344                 is KSFunctionDeclarationDescriptorImpl -> {
345                     findMethodOrder(
346                         ResolverImpl.instance!!.getJvmName(decl).toString()
347                     ) {
348                         ResolverImpl.instance!!.mapToJvmSignature(decl).toString()
349                     }
350                 }
351                 else -> orderProvider.nextIgnoreSealed()
352             }
353         }
354     }
355 
356     private inline fun findMethodOrder(
357         jvmName: String,
358         crossinline getJvmDesc: () -> String
359     ): Int {
360         val methods = methodOrdering[jvmName]
361         // if there is 1 method w/ that name, just return.
362         // otherwise, we need signature matching
363         return when {
364             methods == null -> {
365                 orderProvider.next(jvmName)
366             }
367             methods.size == 1 -> {
368                 // only 1 method with this name, return it, no reason to resolve jvm
369                 // signature
370                 methods.values.first()
371             }
372             else -> {
373                 // need to match using the jvm signature
374                 val jvmDescriptor = getJvmDesc()
375                 methods.getOrPut(jvmDescriptor) {
376                     orderProvider.next(jvmName)
377                 }
378             }
379         }
380     }
381 
382     override fun visitField(
383         name: Name,
384         desc: String,
385         initializer: Any?
386     ): KotlinJvmBinaryClass.AnnotationVisitor? {
387         fieldOrdering.getOrPut(name.asString()) {
388             orderProvider.next(name)
389         }
390         return null
391     }
392 
393     override fun visitMethod(
394         name: Name,
395         desc: String
396     ): KotlinJvmBinaryClass.MethodAnnotationVisitor? {
397         methodOrdering.getOrPut(name.asString()) {
398             mutableMapOf()
399         }.put(desc, orderProvider.next(name))
400         return null
401     }
402 
403     /**
404      * Helper class to generate order values for items.
405      * Each time we see a new declaration, we give it an increasing order.
406      *
407      * This provider can also run in STRICT MODE to ensure that if we don't find an expected value
408      * during sorting, we can crash instead of picking the next ID. For now, it is only used for
409      * testing.
410      */
411     private class OrderProvider {
412         private var nextId = 0
413         private var sealed = false
414 
415         /**
416          * Seals the provider, preventing it from generating new IDs if [STRICT_MODE] is enabled.
417          */
418         fun seal() {
419             sealed = true
420         }
421 
422         /**
423          * Returns the next available order value.
424          *
425          * @param ref Used for logging if the data is sealed and we shouldn't provide a new order.
426          */
427         fun next(ref: Any): Int {
428             check(!sealed || !STRICT_MODE) {
429                 "couldn't find item $ref"
430             }
431             return nextId ++
432         }
433 
434         /**
435          * Returns the next ID without checking whether the model is sealed or not. This is useful
436          * for declarations where we don't care about the order (e.g. inner class declarations).
437          */
438         fun nextIgnoreSealed(): Int {
439             return nextId ++
440         }
441     }
442     companion object {
443         /**
444          * Used in tests to prevent fallback behavior of creating a new ID when we cannot find the
445          * order.
446          */
447         var STRICT_MODE = false
448     }
449 }
450 
451 /**
452  * Same as KSDeclarationContainer.declarations, but sorted by declaration order in the source.
453  *
454  * Note that this is SLOW. AVOID IF POSSIBLE.
455  */
456 @KspExperimental
457 internal val KSDeclarationContainer.declarationsInSourceOrder: Sequence<KSDeclaration>
458     get() {
459         // Only Kotlin libs can be out of order.
460         if (this !is KSClassDeclarationDescriptorImpl || origin != Origin.KOTLIN_LIB)
461             return declarations
462 
463         val declarationOrdering = (
464             (descriptor as? DeserializedClassDescriptor)?.source as? KotlinJvmBinarySourceElement
<lambda>null465             )?.binaryClass?.let {
466             DeclarationOrdering(it)
467         } ?: return declarations
468 
469         return (declarations as? Sequence<KSDeclarationDescriptorImpl>)?.sortedWith(declarationOrdering.comparator)
470             ?: declarations
471     }
472 
473 internal val KSPropertyDeclaration.jvmAccessFlag: Int
474     get() = when (origin) {
475         Origin.KOTLIN_LIB -> {
476             val descriptor = (this as KSPropertyDeclarationDescriptorImpl).descriptor
477             val kotlinBinaryJavaClass = descriptor.getContainingKotlinJvmBinaryClass()
478             // 0 if no backing field
<lambda>null479             kotlinBinaryJavaClass?.let {
480                 BinaryClassInfoCache.getCached(it).fieldAccFlags.get(this.simpleName.asString()) ?: 0
481             } ?: 0
482         }
483         Origin.JAVA_LIB -> {
484             val descriptor = (this as KSPropertyDeclarationDescriptorImpl).descriptor
485             ((descriptor.source as? JavaSourceElement)?.javaElement as? BinaryJavaField)?.access ?: 0
486         }
487         else -> throw IllegalStateException("this function expects only KOTLIN_LIB or JAVA_LIB")
488     }
489 
490 internal val KSFunctionDeclaration.jvmAccessFlag: Int
491     get() = when (origin) {
492         Origin.KOTLIN_LIB -> {
493             val jvmDesc = ResolverImpl.instance!!.mapToJvmSignatureInternal(this)
494             val descriptor = (this as KSFunctionDeclarationDescriptorImpl).descriptor
495             // Companion.<init> doesn't have containing KotlinJvmBinaryClass.
496             val kotlinBinaryJavaClass = descriptor.getContainingKotlinJvmBinaryClass()
<lambda>null497             kotlinBinaryJavaClass?.let {
498                 BinaryClassInfoCache.getCached(it).methodAccFlags.get(this.simpleName.asString() + jvmDesc) ?: 0
499             } ?: 0
500         }
501         Origin.JAVA_LIB -> {
502             val descriptor = (this as KSFunctionDeclarationDescriptorImpl).descriptor
503             // Some functions, like `equals` in builtin types, doesn't have source.
504             ((descriptor.source as? JavaSourceElement)?.javaElement as? BinaryJavaMethodBase)?.access ?: 0
505         }
506         else -> throw IllegalStateException("this function expects only KOTLIN_LIB or JAVA_LIB")
507     }
508 
509 // Compiler subtype checking does not convert Java types to Kotlin types, while getting super types
510 // from a java type does the conversion, therefore resulting in subtype checking for Java types to fail.
511 // Check if candidate super type is a Java type, convert to Kotlin type for subtype checking.
512 // Also, if the type is a generic deserialized type, that actually represents a function type,
513 // a conversion is also required to yield a type with a correctly recognised descriptor.
convertKotlinTypenull514 internal fun KotlinType.convertKotlinType(): KotlinType {
515     val declarationDescriptor = this.constructor.declarationDescriptor
516     val base = if (declarationDescriptor?.shouldMapToKotlinForAssignabilityCheck() == true) {
517         JavaToKotlinClassMapper
518             .mapJavaToKotlin(declarationDescriptor.fqNameSafe, ResolverImpl.instance!!.module.builtIns)
519             ?.defaultType
520             ?.replace(this.arguments)
521             ?: this
522     } else this
523     val newarguments =
524         base.arguments.map { if (it !is StarProjectionImpl) it.replaceType(it.type.convertKotlinType()) else it }
525     val upperBound = if (base.unwrap() is FlexibleType) {
526         (base.unwrap() as FlexibleType).upperBound.arguments
527             .map { if (it !is StarProjectionImpl) it.replaceType(it.type.convertKotlinType()) else it }
528     } else newarguments
529     return base.replace(
530         newarguments,
531         annotations,
532         upperBound
533     )
534 }
535 
ClassifierDescriptornull536 private fun ClassifierDescriptor.shouldMapToKotlinForAssignabilityCheck(): Boolean {
537     return when (this) {
538         is JavaClassDescriptor -> true // All java types need to be mapped to kotlin
539         is DeserializedDescriptor -> {
540             // If this is a generic deserialized type descriptor, which actually is a kotlin function type.
541             // This may be the case if the client explicitly mapped a kotlin function type to the JVM one.
542             // Such types need to be remapped to be represented by a correct function class descriptor.
543             fqNameSafe.parent().asString() == "kotlin.jvm.functions"
544         }
545         else -> false
546     }
547 }
548 
DeclarationDescriptornull549 fun DeclarationDescriptor.findPsi(): PsiElement? {
550     // For synthetic members.
551     if ((this is CallableMemberDescriptor) && this.kind != CallableMemberDescriptor.Kind.DECLARATION) return null
552     val psi = (this as? DeclarationDescriptorWithSource)?.source?.getPsi() ?: return null
553     if (psi is KtElement) return psi
554 
555     // Find Java PSIs loaded by KSP
556     val containingFile = ResolverImpl.instance!!.findPsiJavaFile(psi.containingFile.virtualFile.path) ?: return null
557     val leaf = containingFile.findElementAt(psi.textOffset) ?: return null
558     return leaf.parentsWithSelf.firstOrNull { psi.manager.areElementsEquivalent(it, psi) }
559 }
560