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