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