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