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