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