• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tools.metalava.model.psi
18 
19 import com.android.tools.metalava.compatibility
20 import com.android.tools.metalava.model.AnnotationRetention
21 import com.android.tools.metalava.model.ClassItem
22 import com.android.tools.metalava.model.CompilationUnit
23 import com.android.tools.metalava.model.ConstructorItem
24 import com.android.tools.metalava.model.FieldItem
25 import com.android.tools.metalava.model.MethodItem
26 import com.android.tools.metalava.model.PackageItem
27 import com.android.tools.metalava.model.PropertyItem
28 import com.android.tools.metalava.model.TypeItem
29 import com.android.tools.metalava.model.TypeParameterList
30 import com.android.tools.metalava.model.VisibilityLevel
31 import com.intellij.lang.jvm.types.JvmReferenceType
32 import com.intellij.psi.PsiClass
33 import com.intellij.psi.PsiClassType
34 import com.intellij.psi.PsiCompiledFile
35 import com.intellij.psi.PsiModifier
36 import com.intellij.psi.PsiModifierListOwner
37 import com.intellij.psi.PsiType
38 import com.intellij.psi.PsiTypeParameter
39 import com.intellij.psi.impl.source.PsiClassReferenceType
40 import com.intellij.psi.util.PsiUtil
41 import org.jetbrains.kotlin.psi.KtProperty
42 import org.jetbrains.uast.UClass
43 import org.jetbrains.uast.UMethod
44 import org.jetbrains.uast.kotlin.KotlinUClass
45 
46 open class PsiClassItem(
47     override val codebase: PsiBasedCodebase,
48     val psiClass: PsiClass,
49     private val name: String,
50     private val fullName: String,
51     private val qualifiedName: String,
52     private val hasImplicitDefaultConstructor: Boolean,
53     val classType: ClassType,
54     modifiers: PsiModifierItem,
55     documentation: String
56 ) :
57     PsiItem(
58         codebase = codebase,
59         modifiers = modifiers,
60         documentation = documentation,
61         element = psiClass
62     ), ClassItem {
63 
64     lateinit var containingPackage: PsiPackageItem
65 
66     override fun containingPackage(): PackageItem = containingClass?.containingPackage() ?: containingPackage
67     override fun simpleName(): String = name
68     override fun fullName(): String = fullName
69     override fun qualifiedName(): String = qualifiedName
70     override fun isDefined(): Boolean = codebase.unsupported()
71     override fun isInterface(): Boolean = classType == ClassType.INTERFACE
72     override fun isAnnotationType(): Boolean = classType == ClassType.ANNOTATION_TYPE
73     override fun isEnum(): Boolean = classType == ClassType.ENUM
74     override fun hasImplicitDefaultConstructor(): Boolean = hasImplicitDefaultConstructor
75 
76     private var superClass: ClassItem? = null
77     private var superClassType: TypeItem? = null
78     override fun superClass(): ClassItem? = superClass
79     override fun superClassType(): TypeItem? = superClassType
80 
81     override fun setSuperClass(superClass: ClassItem?, superClassType: TypeItem?) {
82         this.superClass = superClass
83         this.superClassType = superClassType
84     }
85 
86     override var stubConstructor: ConstructorItem? = null
87     override var notStrippable = false
88     override var artifact: String? = null
89 
90     private var containingClass: PsiClassItem? = null
91     override fun containingClass(): PsiClassItem? = containingClass
92 
93     // TODO: Come up with a better scheme for how to compute this
94     override var included: Boolean = true
95 
96     override var hasPrivateConstructor: Boolean = false
97 
98     override fun interfaceTypes(): List<TypeItem> = interfaceTypes
99 
100     override fun setInterfaceTypes(interfaceTypes: List<TypeItem>) {
101         @Suppress("UNCHECKED_CAST")
102         setInterfaces(interfaceTypes as List<PsiTypeItem>)
103     }
104 
105     private fun setInterfaces(interfaceTypes: List<PsiTypeItem>) {
106         this.interfaceTypes = interfaceTypes
107     }
108 
109     private var allInterfaces: List<ClassItem>? = null
110 
111     override fun allInterfaces(): Sequence<ClassItem> {
112         if (allInterfaces == null) {
113             val classes = mutableSetOf<PsiClass>()
114             var curr: PsiClass? = psiClass
115             while (curr != null) {
116                 if (curr.isInterface && !classes.contains(curr)) {
117                     classes.add(curr)
118                 }
119                 addInterfaces(classes, curr.interfaces)
120                 curr = curr.superClass
121             }
122             val result = mutableListOf<ClassItem>()
123             for (cls in classes) {
124                 val item = codebase.findOrCreateClass(cls)
125                 result.add(item)
126             }
127 
128             allInterfaces = result
129         }
130 
131         return allInterfaces!!.asSequence()
132     }
133 
134     private fun addInterfaces(result: MutableSet<PsiClass>, interfaces: Array<out PsiClass>) {
135         for (itf in interfaces) {
136             if (itf.isInterface && !result.contains(itf)) {
137                 result.add(itf)
138                 addInterfaces(result, itf.interfaces)
139                 val superClass = itf.superClass
140                 if (superClass != null) {
141                     addInterfaces(result, arrayOf(superClass))
142                 }
143             }
144         }
145     }
146 
147     private lateinit var innerClasses: List<PsiClassItem>
148     private lateinit var interfaceTypes: List<TypeItem>
149     private lateinit var constructors: List<PsiConstructorItem>
150     private lateinit var methods: List<PsiMethodItem>
151     private lateinit var properties: List<PsiPropertyItem>
152     private lateinit var fields: List<FieldItem>
153 
154     /**
155      * If this item was created by filtering down a different codebase, this temporarily
156      * points to the original item during construction. This is used to let us initialize
157      * for example throws lists later, when all classes in the codebase have been
158      * initialized.
159      */
160     internal var source: PsiClassItem? = null
161 
162     override fun innerClasses(): List<PsiClassItem> = innerClasses
163     override fun constructors(): List<PsiConstructorItem> = constructors
164     override fun methods(): List<PsiMethodItem> = methods
165     override fun properties(): List<PropertyItem> = properties
166     override fun fields(): List<FieldItem> = fields
167 
168     override fun toType(): TypeItem {
169         return PsiTypeItem.create(codebase, codebase.getClassType(psiClass))
170     }
171 
172     override fun hasTypeVariables(): Boolean = psiClass.hasTypeParameters()
173 
174     override fun typeParameterList(): TypeParameterList {
175         if (psiClass.hasTypeParameters()) {
176             return PsiTypeParameterList(
177                 codebase, psiClass.typeParameterList
178                     ?: return TypeParameterList.NONE
179             )
180         } else {
181             return TypeParameterList.NONE
182         }
183     }
184 
185     override fun typeArgumentClasses(): List<ClassItem> {
186         return PsiTypeItem.typeParameterClasses(
187             codebase,
188             psiClass.typeParameterList
189         )
190     }
191 
192     override val isTypeParameter: Boolean
193         get() = psiClass is PsiTypeParameter
194 
195     override fun getCompilationUnit(): CompilationUnit? {
196         if (isInnerClass()) {
197             return null
198         }
199 
200         val containingFile = psiClass.containingFile ?: return null
201         if (containingFile is PsiCompiledFile) {
202             return null
203         }
204 
205         return PsiCompilationUnit(codebase, containingFile)
206     }
207 
208     override fun finishInitialization() {
209         super.finishInitialization()
210 
211         for (method in methods) {
212             method.finishInitialization()
213         }
214         for (method in constructors) {
215             method.finishInitialization()
216         }
217         for (field in fields) {
218             // There may be non-Psi fields here later (thanks to addField) but not during construction
219             (field as PsiFieldItem).finishInitialization()
220         }
221         for (inner in innerClasses) {
222             inner.finishInitialization()
223         }
224 
225         // Delay initializing super classes and implemented interfaces for all inner classes: they may refer
226         // to *other* inner classes in this class, which would lead to an attempt to construct
227         // recursively. Instead, we wait until all the inner classes have been constructed, and at
228         // the very end, initialize super classes and interfaces recursively.
229         if (psiClass.containingClass == null) {
230             initializeSuperClasses()
231         }
232     }
233 
234     private fun initializeSuperClasses() {
235         val extendsListTypes = psiClass.extendsListTypes
236         if (!extendsListTypes.isEmpty()) {
237             val type = PsiTypeItem.create(codebase, extendsListTypes[0])
238             this.superClassType = type
239             this.superClass = type.asClass()
240         } else {
241             val superType = psiClass.superClassType
242             if (superType is PsiType) {
243                 this.superClassType = PsiTypeItem.create(codebase, superType)
244                 this.superClass = this.superClassType?.asClass()
245             }
246         }
247 
248         // Add interfaces. If this class is an interface, it can implement both
249         // classes from the extends clause and from the implements clause.
250         val interfaces = psiClass.implementsListTypes
251         setInterfaces(if (interfaces.isEmpty() && extendsListTypes.size <= 1) {
252             emptyList()
253         } else {
254             val result = ArrayList<PsiTypeItem>(interfaces.size + extendsListTypes.size - 1)
255             val create: (PsiClassType) -> PsiTypeItem = {
256                 val type = PsiTypeItem.create(codebase, it)
257                 type.asClass() // ensure that we initialize classes eagerly too such that they're registered etc
258                 type
259             }
260             (1 until extendsListTypes.size).mapTo(result) { create(extendsListTypes[it]) }
261             interfaces.mapTo(result) { create(it) }
262             result
263         })
264 
265         for (inner in innerClasses) {
266             inner.initializeSuperClasses()
267         }
268     }
269 
270     protected fun initialize(
271         innerClasses: List<PsiClassItem>,
272         interfaceTypes: List<TypeItem>,
273         constructors: List<PsiConstructorItem>,
274         methods: List<PsiMethodItem>,
275         fields: List<FieldItem>
276     ) {
277         this.innerClasses = innerClasses
278         this.interfaceTypes = interfaceTypes
279         this.constructors = constructors
280         this.methods = methods
281         this.fields = fields
282     }
283 
284     override fun mapTypeVariables(target: ClassItem): Map<String, String> {
285         val targetPsi = target.psi() as PsiClass
286         val maps = mapTypeVariablesToSuperclass(
287             psiClass, targetPsi, considerSuperClasses = true,
288             considerInterfaces = targetPsi.isInterface
289         ) ?: return emptyMap()
290 
291         if (maps.isEmpty()) {
292             return emptyMap()
293         }
294 
295         if (maps.size == 1) {
296             return maps[0]
297         }
298 
299         val first = maps[0]
300         val flattened = mutableMapOf<String, String>()
301         for (key in first.keys) {
302             var variable: String? = key
303             for (map in maps) {
304                 val value = map[variable]
305                 variable = value
306                 if (value == null) {
307                     break
308                 } else {
309                     flattened[key] = value
310                 }
311             }
312         }
313         return flattened
314     }
315 
316     override fun equals(other: Any?): Boolean {
317         if (this === other) {
318             return true
319         }
320         return other is ClassItem && qualifiedName == other.qualifiedName()
321     }
322 
323     /**
324      * Creates a constructor in this class
325      */
326     override fun createDefaultConstructor(): ConstructorItem {
327         return PsiConstructorItem.createDefaultConstructor(codebase, this, psiClass)
328     }
329 
330     override fun createMethod(template: MethodItem): MethodItem {
331         val method = template as PsiMethodItem
332 
333         val replacementMap = mapTypeVariables(template.containingClass())
334         val newMethod: PsiMethodItem
335         if (replacementMap.isEmpty()) {
336             newMethod = PsiMethodItem.create(codebase, this, method)
337         } else {
338             val stub = method.toStub(replacementMap)
339             val psiMethod = codebase.createPsiMethod(stub, psiClass)
340             newMethod = PsiMethodItem.create(codebase, this, psiMethod)
341             newMethod.inheritedMethod = method.inheritedMethod
342             newMethod.documentation = method.documentation
343         }
344 
345         if (template.throwsTypes().isEmpty()) {
346             newMethod.setThrowsTypes(emptyList())
347         } else {
348             val throwsTypes = mutableListOf<ClassItem>()
349             for (type in template.throwsTypes()) {
350                 if (type.codebase === codebase) {
351                     throwsTypes.add(type)
352                 } else {
353                     throwsTypes.add(codebase.findOrCreateClass(((type as PsiClassItem).psiClass)))
354                 }
355             }
356             newMethod.setThrowsTypes(throwsTypes)
357         }
358 
359         return newMethod
360     }
361 
362     override fun addMethod(method: MethodItem) {
363         (methods as MutableList<PsiMethodItem>).add(method as PsiMethodItem)
364     }
365 
366     private var retention: AnnotationRetention? = null
367 
368     override fun getRetention(): AnnotationRetention {
369         retention?.let { return it }
370 
371         if (!isAnnotationType()) {
372             error("getRetention() should only be called on annotation classes")
373         }
374 
375         retention = ClassItem.findRetention(this)
376         return retention!!
377     }
378 
379     override fun hashCode(): Int = qualifiedName.hashCode()
380 
381     override fun toString(): String = "class ${qualifiedName()}"
382 
383     companion object {
384         private fun hasExplicitRetention(modifiers: PsiModifierItem, psiClass: PsiClass, isKotlin: Boolean): Boolean {
385             if (modifiers.findAnnotation("java.lang.annotation.Retention") != null) {
386                 return true
387             }
388             if (modifiers.findAnnotation("kotlin.annotation.Retention") != null) {
389                 return true
390             }
391             if (isKotlin && psiClass is UClass) {
392                 // In Kotlin some annotations show up on the Java facade only; for example,
393                 // a @DslMarker annotation will imply a runtime annotation which is present
394                 // in the java facade, not in the source list of annotations
395                 val modifierList = psiClass.modifierList
396                 if (modifierList != null && modifierList.annotations.any {
397                         val qualifiedName = it.qualifiedName
398                         qualifiedName == "kotlin.annotation.Retention" ||
399                             qualifiedName == "java.lang.annotation.Retention"
400                     }) {
401                     return true
402                 }
403             }
404             return false
405         }
406 
407         fun create(codebase: PsiBasedCodebase, psiClass: PsiClass): PsiClassItem {
408             if (psiClass is PsiTypeParameter) {
409                 return PsiTypeParameterItem.create(codebase, psiClass)
410             }
411             val simpleName = psiClass.name!!
412             val fullName = computeFullClassName(psiClass)
413             val qualifiedName = psiClass.qualifiedName ?: simpleName
414             val hasImplicitDefaultConstructor = hasImplicitDefaultConstructor(psiClass)
415             val classType = ClassType.getClassType(psiClass)
416 
417             val commentText = PsiItem.javadoc(psiClass)
418             val modifiers = modifiers(codebase, psiClass, commentText)
419             val item = PsiClassItem(
420                 codebase = codebase,
421                 psiClass = psiClass,
422                 name = simpleName,
423                 fullName = fullName,
424                 qualifiedName = qualifiedName,
425                 classType = classType,
426                 hasImplicitDefaultConstructor = hasImplicitDefaultConstructor,
427                 documentation = commentText,
428                 modifiers = modifiers
429             )
430             codebase.registerClass(item)
431             item.modifiers.setOwner(item)
432 
433             // Construct the children
434             val psiMethods = psiClass.methods
435             val methods: MutableList<PsiMethodItem> = ArrayList(psiMethods.size)
436             val isKotlin = isKotlin(psiClass)
437 
438             if (classType == ClassType.ENUM) {
439                 addEnumMethods(codebase, item, psiClass, methods)
440             } else if (classType == ClassType.ANNOTATION_TYPE && compatibility.explicitlyListClassRetention &&
441                 !hasExplicitRetention(modifiers, psiClass, isKotlin)
442             ) {
443                 // By policy, include explicit retention policy annotation if missing
444                 modifiers.addAnnotation(
445                     codebase.createAnnotation(
446                         "@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS)",
447                         item, false
448                     )
449                 )
450             }
451 
452             val constructors: MutableList<PsiConstructorItem> = ArrayList(5)
453             for (psiMethod in psiMethods) {
454                 if (psiMethod.isConstructor) {
455                     val constructor = PsiConstructorItem.create(codebase, item, psiMethod)
456                     constructors.add(constructor)
457                 } else {
458                     val method = PsiMethodItem.create(codebase, item, psiMethod)
459                     methods.add(method)
460                 }
461             }
462 
463             if (hasImplicitDefaultConstructor) {
464                 assert(constructors.isEmpty())
465                 constructors.add(PsiConstructorItem.createDefaultConstructor(codebase, item, psiClass))
466             }
467 
468             val fields: MutableList<FieldItem> = mutableListOf()
469             val psiFields = psiClass.fields
470             if (!psiFields.isEmpty()) {
471                 psiFields.asSequence()
472                     .mapTo(fields) {
473                         PsiFieldItem.create(codebase, item, it)
474                     }
475             }
476 
477             if (classType == ClassType.INTERFACE) {
478                 // All members are implicitly public, fields are implicitly static, non-static methods are abstract
479                 // (except in Java 1.9, where they can be private
480                 for (method in methods) {
481                     if (!method.isPrivate) {
482                         method.mutableModifiers().setVisibilityLevel(VisibilityLevel.PUBLIC)
483                     }
484                 }
485                 for (method in fields) {
486                     val m = method.mutableModifiers()
487                     m.setVisibilityLevel(VisibilityLevel.PUBLIC)
488                     m.setStatic(true)
489                 }
490             }
491 
492             item.constructors = constructors
493             item.methods = methods
494             item.fields = fields
495 
496             item.properties = emptyList()
497             if (isKotlin) {
498                 // Try to initialize the Kotlin properties
499                 val properties = mutableListOf<PsiPropertyItem>()
500                 for (method in psiMethods) {
501                     if (method is UMethod) {
502                         if (method.modifierList.hasModifierProperty(PsiModifier.STATIC)) {
503                             // Skip extension properties
504                             continue
505                         }
506                         val sourcePsi = method.sourcePsi
507                         if (sourcePsi is KtProperty) {
508                             if (method.name.startsWith("set")) {
509                                 continue
510                             }
511                             val name = sourcePsi.name ?: continue
512                             val psiType = method.returnType ?: continue
513                             properties.add(PsiPropertyItem.create(codebase, item, name, psiType, method))
514                         }
515                     }
516                 }
517                 item.properties = properties
518             }
519 
520             val psiInnerClasses = psiClass.innerClasses
521             item.innerClasses = if (psiInnerClasses.isEmpty()) {
522                 emptyList()
523             } else {
524                 val result = psiInnerClasses.asSequence()
525                     .map {
526                         val inner = codebase.findOrCreateClass(it)
527                         inner.containingClass = item
528                         inner
529                     }
530                     .toMutableList()
531                 result
532             }
533 
534             return item
535         }
536 
537         private fun addEnumMethods(
538             codebase: PsiBasedCodebase,
539             classItem: PsiClassItem,
540             psiClass: PsiClass,
541             result: MutableList<PsiMethodItem>
542         ) {
543             // Add these two methods as overrides into the API; this isn't necessary but is done in the old
544             // API generator
545             //    method public static android.graphics.ColorSpace.Adaptation valueOf(java.lang.String);
546             //    method public static final android.graphics.ColorSpace.Adaptation[] values();
547 
548             if (compatibility.defaultEnumMethods) {
549                 // TODO: Skip if we already have these methods here (but that shouldn't happen; nobody would
550                 // type this by hand)
551                 addEnumMethod(
552                     codebase, classItem,
553                     psiClass, result,
554                     "public static ${psiClass.qualifiedName} valueOf(java.lang.String s) { return null; }"
555                 )
556                 addEnumMethod(
557                     codebase, classItem,
558                     psiClass, result,
559                     "public static final ${psiClass.qualifiedName}[] values() { return null; }"
560                 )
561                 // Also add a private constructor; used when emitting the private API
562                 val psiMethod = codebase.createConstructor("private ${psiClass.name}", psiClass)
563                 result.add(PsiConstructorItem.create(codebase, classItem, psiMethod))
564             }
565         }
566 
567         private fun addEnumMethod(
568             codebase: PsiBasedCodebase,
569             classItem: PsiClassItem,
570             psiClass: PsiClass,
571             result: MutableList<PsiMethodItem>,
572             source: String
573         ) {
574             val psiMethod = codebase.createPsiMethod(source, psiClass)
575             result.add(PsiMethodItem.create(codebase, classItem, psiMethod))
576         }
577 
578         /**
579          * Computes the "full" class name; this is not the qualified class name (e.g. with package)
580          * but for an inner class it includes all the outer classes
581          */
582         fun computeFullClassName(cls: PsiClass): String {
583             if (cls.containingClass == null) {
584                 val name = cls.name
585                 return name!!
586             } else {
587                 val list = mutableListOf<String>()
588                 var curr: PsiClass? = cls
589                 while (curr != null) {
590                     val name = curr.name
591                     curr = if (name != null) {
592                         list.add(name)
593                         curr.containingClass
594                     } else {
595                         break
596                     }
597                 }
598                 return list.asReversed().asSequence().joinToString(separator = ".") { it }
599             }
600         }
601 
602         private fun hasImplicitDefaultConstructor(psiClass: PsiClass): Boolean {
603             if (psiClass.name?.startsWith("-") == true) {
604                 // Deliberately hidden; see examples like
605                 //     @file:JvmName("-ViewModelExtensions") // Hide from Java sources in the IDE.
606                 return false
607             }
608             if (psiClass is KotlinUClass && psiClass.sourcePsi == null) {
609                 // Top level kt classes (FooKt for Foo.kt) do not have implicit default constructor
610                 return false
611             }
612 
613             val constructors = psiClass.constructors
614             if (constructors.isEmpty() && !psiClass.isInterface && !psiClass.isAnnotationType && !psiClass.isEnum) {
615                 if (PsiUtil.hasDefaultConstructor(psiClass)) {
616                     return true
617                 }
618 
619                 // The above method isn't always right; for example, for the ContactsContract.Presence class
620                 // in the framework, which looks like this:
621                 //    @Deprecated
622                 //    public static final class Presence extends StatusUpdates {
623                 //    }
624                 // javac makes a default constructor:
625                 //    public final class android.provider.ContactsContract$Presence extends android.provider.ContactsContract$StatusUpdates {
626                 //        public android.provider.ContactsContract$Presence();
627                 //    }
628                 // but the above method returns false. So add some of our own heuristics:
629                 if (psiClass.hasModifierProperty(PsiModifier.FINAL) && !psiClass.hasModifierProperty(
630                         PsiModifier.ABSTRACT
631                     ) &&
632                     psiClass.hasModifierProperty(PsiModifier.PUBLIC)
633                 ) {
634                     return true
635                 }
636             }
637 
638             return false
639         }
640 
641         fun mapTypeVariablesToSuperclass(
642             psiClass: PsiClass,
643             targetClass: PsiClass,
644             considerSuperClasses: Boolean = true,
645             considerInterfaces: Boolean = psiClass.isInterface
646         ): MutableList<Map<String, String>>? {
647             // TODO: Prune search if type doesn't have type arguments!
648             if (considerSuperClasses) {
649                 val list = mapTypeVariablesToSuperclass(
650                     psiClass.superClassType, targetClass,
651                     considerSuperClasses, considerInterfaces
652                 )
653                 if (list != null) {
654                     return list
655                 }
656             }
657 
658             if (considerInterfaces) {
659                 for (interfaceType in psiClass.interfaceTypes) {
660                     val list = mapTypeVariablesToSuperclass(
661                         interfaceType, targetClass,
662                         considerSuperClasses, considerInterfaces
663                     )
664                     if (list != null) {
665                         return list
666                     }
667                 }
668             }
669 
670             return null
671         }
672 
673         private fun mapTypeVariablesToSuperclass(
674             type: JvmReferenceType?,
675             targetClass: PsiClass,
676             considerSuperClasses: Boolean = true,
677             considerInterfaces: Boolean = true
678         ): MutableList<Map<String, String>>? {
679             // TODO: Prune search if type doesn't have type arguments!
680             val superType = type as? PsiClassReferenceType
681             val superClass = superType?.resolve()
682             if (superClass != null) {
683                 if (superClass == targetClass) {
684                     val map = mapTypeVariablesToSuperclass(superType)
685                     return if (map != null) {
686                         mutableListOf(map)
687                     } else {
688                         null
689                     }
690                 } else {
691                     val list = mapTypeVariablesToSuperclass(
692                         superClass, targetClass, considerSuperClasses,
693                         considerInterfaces
694                     )
695                     if (list != null) {
696                         val map = mapTypeVariablesToSuperclass(superType)
697                         if (map != null) {
698                             list.add(map)
699                         }
700                         return list
701                     }
702                 }
703             }
704 
705             return null
706         }
707 
708         private fun mapTypeVariablesToSuperclass(superType: PsiClassReferenceType?): Map<String, String>? {
709             superType ?: return null
710 
711             val map = mutableMapOf<String, String>()
712             val superClass = superType.resolve()
713             if (superClass != null && superType.hasParameters()) {
714                 val superTypeParameters = superClass.typeParameters
715                 superType.parameters.forEachIndexed { index, parameter ->
716                     if (parameter is PsiClassReferenceType) {
717                         val parameterClass = parameter.resolve()
718                         if (parameterClass != null) {
719                             val parameterName = parameterClass.qualifiedName ?: parameterClass.name ?: parameter.name
720                             if (index < superTypeParameters.size) {
721                                 val superTypeParameter = superTypeParameters[index]
722                                 val superTypeName = superTypeParameter.qualifiedName ?: superTypeParameter.name
723                                 if (superTypeName != null) {
724                                     map[superTypeName] = parameterName
725                                 }
726                             }
727                         }
728                     }
729                 }
730             }
731 
732             return map
733         }
734     }
735 }
736 
PsiModifierListOwnernull737 fun PsiModifierListOwner.isPrivate(): Boolean = modifierList?.hasExplicitModifier(PsiModifier.PRIVATE) == true
738 fun PsiModifierListOwner.isPackagePrivate(): Boolean {
739     val modifiers = modifierList ?: return false
740     return !(modifiers.hasModifierProperty(PsiModifier.PUBLIC) ||
741         modifiers.hasModifierProperty(PsiModifier.PROTECTED))
742 }