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