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