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