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
18 
19 import java.util.ArrayList
20 import java.util.LinkedHashSet
21 import java.util.function.Predicate
22 
23 /**
24  * Represents a {@link https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html Class}
25  *
26  * If you need to model array dimensions or resolved type parameters, see {@link
27  * com.android.tools.metalava.model.TypeItem} instead
28  */
29 @MetalavaApi
30 interface ClassItem : Item, TypeParameterListOwner {
31     /** The simple name of a class. In class foo.bar.Outer.Inner, the simple name is "Inner" */
32     fun simpleName(): String
33 
34     /** The full name of a class. In class foo.bar.Outer.Inner, the full name is "Outer.Inner" */
35     fun fullName(): String
36 
37     /**
38      * The qualified name of a class. In class foo.bar.Outer.Inner, the qualified name is the whole
39      * thing.
40      */
41     @MetalavaApi fun qualifiedName(): String
42 
43     /** Is this an innerclass? */
44     @MetalavaApi fun isInnerClass(): Boolean = containingClass() != null
45 
46     /** Is this a top level class? */
47     fun isTopLevelClass(): Boolean = containingClass() == null
48 
49     /** This [ClassItem] and all of its inner classes, recursively */
50     fun allClasses(): Sequence<ClassItem> {
51         return sequenceOf(this).plus(innerClasses().asSequence().flatMap { it.allClasses() })
52     }
53 
54     override fun parent(): Item? = containingClass() ?: containingPackage()
55 
56     override val effectivelyDeprecated: Boolean
57         get() = originallyDeprecated || containingClass()?.effectivelyDeprecated == true
58 
59     /**
60      * The qualified name where inner classes use $ as a separator. In class foo.bar.Outer.Inner,
61      * this method will return foo.bar.Outer$Inner. (This is the name format used in ProGuard keep
62      * files for example.)
63      */
64     fun qualifiedNameWithDollarInnerClasses(): String {
65         var curr: ClassItem? = this
66         while (curr?.containingClass() != null) {
67             curr = curr.containingClass()
68         }
69 
70         if (curr == null) {
71             return fullName().replace('.', '$')
72         }
73 
74         return curr.containingPackage().qualifiedName() + "." + fullName().replace('.', '$')
75     }
76 
77     /** Returns the internal name of the class, as seen in bytecode */
78     fun internalName(): String {
79         var curr: ClassItem? = this
80         while (curr?.containingClass() != null) {
81             curr = curr.containingClass()
82         }
83 
84         if (curr == null) {
85             return fullName().replace('.', '$')
86         }
87 
88         return curr.containingPackage().qualifiedName().replace('.', '/') +
89             "/" +
90             fullName().replace('.', '$')
91     }
92 
93     /**
94      * The super class of this class, if any.
95      *
96      * Interfaces always return `null` for this.
97      */
98     @MetalavaApi fun superClass(): ClassItem?
99 
100     /** All super classes, if any */
101     fun allSuperClasses(): Sequence<ClassItem> {
102         return generateSequence(superClass()) { it.superClass() }
103     }
104 
105     /**
106      * The super class type of this class, if any. The difference between this and [superClass] is
107      * that the type reference can include type arguments; e.g. in "class MyList extends
108      * List<String>" the super class is java.util.List and the super class type is
109      * java.util.List<java.lang.String>.
110      */
111     fun superClassType(): ClassTypeItem?
112 
113     /** Returns true if this class extends the given class (includes self) */
114     fun extends(qualifiedName: String): Boolean {
115         if (qualifiedName() == qualifiedName) {
116             return true
117         }
118 
119         val superClass = superClass()
120         return superClass?.extends(qualifiedName)
121             ?: when {
122                 isEnum() -> qualifiedName == JAVA_LANG_ENUM
123                 isAnnotationType() -> qualifiedName == JAVA_LANG_ANNOTATION
124                 else -> qualifiedName == JAVA_LANG_OBJECT
125             }
126     }
127 
128     /** Returns true if this class implements the given interface (includes self) */
129     fun implements(qualifiedName: String): Boolean {
130         if (qualifiedName() == qualifiedName) {
131             return true
132         }
133 
134         interfaceTypes().forEach {
135             val cls = it.asClass()
136             if (cls != null && cls.implements(qualifiedName)) {
137                 return true
138             }
139         }
140 
141         // Might be implementing via superclass
142         if (superClass()?.implements(qualifiedName) == true) {
143             return true
144         }
145 
146         return false
147     }
148 
149     /** Returns true if this class extends or implements the given class or interface */
150     fun extendsOrImplements(qualifiedName: String): Boolean =
151         extends(qualifiedName) || implements(qualifiedName)
152 
153     /** Any interfaces implemented by this class */
154     @MetalavaApi fun interfaceTypes(): List<ClassTypeItem>
155 
156     /**
157      * All classes and interfaces implemented (by this class and its super classes and the
158      * interfaces themselves)
159      */
160     fun allInterfaces(): Sequence<ClassItem>
161 
162     /** Any inner classes of this class */
163     fun innerClasses(): List<ClassItem>
164 
165     /** The constructors in this class */
166     @MetalavaApi fun constructors(): List<ConstructorItem>
167 
168     /** Whether this class has an implicit default constructor */
169     fun hasImplicitDefaultConstructor(): Boolean
170 
171     /** The non-constructor methods in this class */
172     @MetalavaApi fun methods(): List<MethodItem>
173 
174     /** The properties in this class */
175     fun properties(): List<PropertyItem>
176 
177     /** The fields in this class */
178     @MetalavaApi fun fields(): List<FieldItem>
179 
180     /** The members in this class: constructors, methods, fields/enum constants */
181     fun members(): Sequence<MemberItem> {
182         return fields().asSequence().plus(constructors().asSequence()).plus(methods().asSequence())
183     }
184 
185     val classKind: ClassKind
186 
187     /** Whether this class is an interface */
188     fun isInterface() = classKind == ClassKind.INTERFACE
189 
190     /** Whether this class is an annotation type */
191     fun isAnnotationType() = classKind == ClassKind.ANNOTATION_TYPE
192 
193     /** Whether this class is an enum */
194     fun isEnum() = classKind == ClassKind.ENUM
195 
196     /** Whether this class is a regular class (not an interface, not an enum, etc) */
197     fun isClass() = classKind == ClassKind.CLASS
198 
199     /** The containing class, for inner classes */
200     @MetalavaApi override fun containingClass(): ClassItem?
201 
202     /** The containing package */
203     override fun containingPackage(): PackageItem
204 
205     /** Gets the type for this class */
206     override fun type(): ClassTypeItem
207 
208     override fun findCorrespondingItemIn(
209         codebase: Codebase,
210         superMethods: Boolean,
211         duplicate: Boolean,
212     ) = codebase.findClass(qualifiedName())
213 
214     /** Returns true if this class has type parameters */
215     fun hasTypeVariables(): Boolean
216 
217     fun isJavaLangObject(): Boolean {
218         return qualifiedName() == JAVA_LANG_OBJECT
219     }
220 
221     // Mutation APIs: Used to "fix up" the API hierarchy to only expose visible parts of the API.
222 
223     // This replaces the interface types implemented by this class
224     fun setInterfaceTypes(interfaceTypes: List<ClassTypeItem>)
225 
226     var hasPrivateConstructor: Boolean
227 
228     /** The primary constructor for this class in Kotlin, if present. */
229     val primaryConstructor: ConstructorItem?
230         get() = constructors().singleOrNull { it.isPrimary }
231 
232     /**
233      * Maven artifact of this class, if any. (Not used for the Android SDK, but used in for example
234      * support libraries.
235      */
236     var artifact: String?
237 
238     override fun baselineElementId() = qualifiedName()
239 
240     override fun accept(visitor: ItemVisitor) {
241         visitor.visit(this)
242     }
243 
244     override fun toStringForItem() = "class ${qualifiedName()}"
245 
246     companion object {
247         /** Looks up the retention policy for the given class */
248         fun findRetention(cls: ClassItem): AnnotationRetention {
249             val modifiers = cls.modifiers
250             val annotation = modifiers.findAnnotation(AnnotationItem::isRetention)
251             val value = annotation?.findAttribute(ANNOTATION_ATTR_VALUE)
252             val source = value?.value?.toSource()
253             return when {
254                 source == null -> AnnotationRetention.getDefault(cls)
255                 source.contains("CLASS") -> AnnotationRetention.CLASS
256                 source.contains("RUNTIME") -> AnnotationRetention.RUNTIME
257                 source.contains("SOURCE") -> AnnotationRetention.SOURCE
258                 source.contains("BINARY") -> AnnotationRetention.BINARY
259                 else -> AnnotationRetention.getDefault(cls)
260             }
261         }
262 
263         // Same as doclava1 (modulo the new handling when class names match)
264         val comparator: Comparator<in ClassItem> = Comparator { o1, o2 ->
265             val delta = o1.fullName().compareTo(o2.fullName())
266             if (delta == 0) {
267                 o1.qualifiedName().compareTo(o2.qualifiedName())
268             } else {
269                 delta
270             }
271         }
272 
273         /** A partial ordering over [ClassItem] comparing [ClassItem.fullName]. */
274         val fullNameComparator: Comparator<ClassItem> = Comparator.comparing { it.fullName() }
275 
276         /** A total ordering over [ClassItem] comparing [ClassItem.qualifiedName]. */
277         private val qualifiedComparator: Comparator<ClassItem> =
278             Comparator.comparing { it.qualifiedName() }
279 
280         /**
281          * A total ordering over [ClassItem] comparing [ClassItem.fullName] first and then
282          * [ClassItem.qualifiedName].
283          */
284         val fullNameThenQualifierComparator: Comparator<ClassItem> =
285             fullNameComparator.thenComparing(qualifiedComparator)
286 
287         fun classNameSorter(): Comparator<in ClassItem> = ClassItem.qualifiedComparator
288     }
289 
290     fun findMethod(
291         template: MethodItem,
292         includeSuperClasses: Boolean = false,
293         includeInterfaces: Boolean = false
294     ): MethodItem? {
295         if (template.isConstructor()) {
296             return findConstructor(template as ConstructorItem)
297         }
298 
299         methods()
300             .asSequence()
301             .filter { it.matches(template) }
302             .forEach {
303                 return it
304             }
305 
306         if (includeSuperClasses) {
307             superClass()?.findMethod(template, true, includeInterfaces)?.let {
308                 return it
309             }
310         }
311 
312         if (includeInterfaces) {
313             for (itf in interfaceTypes()) {
314                 val cls = itf.asClass() ?: continue
315                 cls.findMethod(template, includeSuperClasses, true)?.let {
316                     return it
317                 }
318             }
319         }
320         return null
321     }
322 
323     /**
324      * Finds a method matching the given method that satisfies the given predicate, considering all
325      * methods defined on this class and its super classes
326      */
327     fun findPredicateMethodWithSuper(template: MethodItem, filter: Predicate<Item>?): MethodItem? {
328         val method = findMethod(template, true, true)
329         if (method == null) {
330             return null
331         }
332         if (filter == null || filter.test(method)) {
333             return method
334         }
335         return method.findPredicateSuperMethod(filter)
336     }
337 
338     fun findConstructor(template: ConstructorItem): ConstructorItem? {
339         constructors()
340             .asSequence()
341             .filter { it.matches(template) }
342             .forEach {
343                 return it
344             }
345         return null
346     }
347 
348     fun findField(
349         fieldName: String,
350         includeSuperClasses: Boolean = false,
351         includeInterfaces: Boolean = false
352     ): FieldItem? {
353         val field = fields().firstOrNull { it.name() == fieldName }
354         if (field != null) {
355             return field
356         }
357 
358         if (includeSuperClasses) {
359             superClass()?.findField(fieldName, true, includeInterfaces)?.let {
360                 return it
361             }
362         }
363 
364         if (includeInterfaces) {
365             for (itf in interfaceTypes()) {
366                 val cls = itf.asClass() ?: continue
367                 cls.findField(fieldName, includeSuperClasses, true)?.let {
368                     return it
369                 }
370             }
371         }
372         return null
373     }
374 
375     /**
376      * Find the [MethodItem] in this.
377      *
378      * If [methodName] is the same as [simpleName] then this will look for [ConstructorItem]s,
379      * otherwise it will look for [MethodItem]s whose [MethodItem.name] is equal to [methodName].
380      *
381      * Out of those matching items it will select the first [MethodItem] (or [ConstructorItem]
382      * subclass) whose parameters match the supplied parameters string. Parameters are matched
383      * against a candidate [MethodItem] as follows:
384      * * The [parameters] string is split on `,` and trimmed and then each item in the list is
385      *   matched with the corresponding [ParameterItem] in `candidate.parameters()` as follows:
386      * * Everything after `<` is removed.
387      * * The result is compared to the result of calling [TypeItem.toErasedTypeString]`(candidate)`
388      *   on the [ParameterItem.type].
389      *
390      * If every parameter matches then the matched [MethodItem] is returned. If no `candidate`
391      * matches then it returns 'null`.
392      *
393      * @param methodName the name of the method or [simpleName] if looking for constructors.
394      * @param parameters the comma separated erased types of the parameters.
395      */
396     fun findMethod(methodName: String, parameters: String): MethodItem? {
397         if (methodName == simpleName()) {
398             // Constructor
399             constructors()
400                 .filter { parametersMatch(it, parameters) }
401                 .forEach {
402                     return it
403                 }
404         } else {
405             methods()
406                 .filter { it.name() == methodName && parametersMatch(it, parameters) }
407                 .forEach {
408                     return it
409                 }
410         }
411 
412         return null
413     }
414 
415     private fun parametersMatch(method: MethodItem, description: String): Boolean {
416         val parameterStrings =
417             description.splitToSequence(",").map(String::trim).filter(String::isNotEmpty).toList()
418         val parameters = method.parameters()
419         if (parameters.size != parameterStrings.size) {
420             return false
421         }
422         for (i in parameters.indices) {
423             var parameterString = parameterStrings[i]
424             val index = parameterString.indexOf('<')
425             if (index != -1) {
426                 parameterString = parameterString.substring(0, index)
427             }
428             val parameter = parameters[i].type().toErasedTypeString()
429             if (parameter != parameterString) {
430                 return false
431             }
432         }
433 
434         return true
435     }
436 
437     /** Returns the corresponding source file, if any */
438     fun getSourceFile(): SourceFile? = null
439 
440     /** If this class is an annotation type, returns the retention of this class */
441     fun getRetention(): AnnotationRetention
442 
443     /**
444      * Return superclass matching the given predicate. When a superclass doesn't match, we'll keep
445      * crawling up the tree until we find someone who matches.
446      */
447     fun filteredSuperclass(predicate: Predicate<Item>): ClassItem? {
448         val superClass = superClass() ?: return null
449         return if (predicate.test(superClass)) {
450             superClass
451         } else {
452             superClass.filteredSuperclass(predicate)
453         }
454     }
455 
456     fun filteredSuperClassType(predicate: Predicate<Item>): TypeItem? {
457         var superClassType: ClassTypeItem? = superClassType() ?: return null
458         var prev: ClassItem? = null
459         while (superClassType != null) {
460             val superClass = superClassType.asClass() ?: return null
461             if (predicate.test(superClass)) {
462                 if (prev == null || superClass == superClass()) {
463                     // Direct reference; no need to map type variables
464                     return superClassType
465                 }
466                 if (!superClassType.hasTypeArguments()) {
467                     // No type variables - also no need for mapping
468                     return superClassType
469                 }
470 
471                 return superClassType.convertType(this, prev)
472             }
473 
474             prev = superClass
475             superClassType = superClass.superClassType()
476         }
477 
478         return null
479     }
480 
481     /**
482      * Return methods matching the given predicate. Forcibly includes local methods that override a
483      * matching method in an ancestor class.
484      */
485     fun filteredMethods(
486         predicate: Predicate<Item>,
487         includeSuperClassMethods: Boolean = false
488     ): Collection<MethodItem> {
489         val methods = LinkedHashSet<MethodItem>()
490         for (method in methods()) {
491             if (predicate.test(method) || method.findPredicateSuperMethod(predicate) != null) {
492                 // val duplicated = method.duplicate(this)
493                 // methods.add(duplicated)
494                 methods.remove(method)
495                 methods.add(method)
496             }
497         }
498         if (includeSuperClassMethods) {
499             superClass()?.filteredMethods(predicate, includeSuperClassMethods)?.let {
500                 methods += it
501             }
502         }
503         return methods
504     }
505 
506     /** Returns the constructors that match the given predicate */
507     fun filteredConstructors(predicate: Predicate<Item>): Sequence<ConstructorItem> {
508         return constructors().asSequence().filter { predicate.test(it) }
509     }
510 
511     /**
512      * Return fields matching the given predicate. Also clones fields from ancestors that would
513      * match had they been defined in this class.
514      */
515     fun filteredFields(predicate: Predicate<Item>, showUnannotated: Boolean): List<FieldItem> {
516         val fields = LinkedHashSet<FieldItem>()
517         if (showUnannotated) {
518             for (clazz in allInterfaces()) {
519                 // If this class is an interface then it will be included in allInterfaces(). If it
520                 // is a class then it will not be included. Either way, this class' fields will be
521                 // handled below so there is no point in processing the fields here.
522                 if (clazz == this) {
523                     continue
524                 }
525                 if (!clazz.isInterface()) {
526                     continue
527                 }
528                 for (field in clazz.fields()) {
529                     if (!predicate.test(field)) {
530                         val duplicated = field.duplicate(this)
531                         if (predicate.test(duplicated)) {
532                             fields.remove(duplicated)
533                             fields.add(duplicated)
534                         }
535                     }
536                 }
537             }
538 
539             val superClass = superClass()
540             if (superClass != null && !predicate.test(superClass) && predicate.test(this)) {
541                 // Include constants from hidden super classes.
542                 for (field in superClass.fields()) {
543                     val fieldModifiers = field.modifiers
544                     if (
545                         !fieldModifiers.isStatic() ||
546                             !fieldModifiers.isFinal() ||
547                             !fieldModifiers.isPublic()
548                     ) {
549                         continue
550                     }
551                     if (!field.originallyHidden) {
552                         val duplicated = field.duplicate(this)
553                         if (predicate.test(duplicated)) {
554                             fields.remove(duplicated)
555                             fields.add(duplicated)
556                         }
557                     }
558                 }
559             }
560         }
561         for (field in fields()) {
562             if (predicate.test(field)) {
563                 fields.remove(field)
564                 fields.add(field)
565             }
566         }
567         if (fields.isEmpty()) {
568             return emptyList()
569         }
570         val list = fields.toMutableList()
571         list.sortWith(FieldItem.comparator)
572         return list
573     }
574 
575     fun filteredInterfaceTypes(predicate: Predicate<Item>): Collection<TypeItem> {
576         val interfaceTypes =
577             filteredInterfaceTypes(
578                 predicate,
579                 LinkedHashSet(),
580                 includeSelf = false,
581                 includeParents = false,
582                 target = this
583             )
584         if (interfaceTypes.isEmpty()) {
585             return interfaceTypes
586         }
587 
588         return interfaceTypes
589     }
590 
591     fun allInterfaceTypes(predicate: Predicate<Item>): Collection<TypeItem> {
592         val interfaceTypes =
593             filteredInterfaceTypes(
594                 predicate,
595                 LinkedHashSet(),
596                 includeSelf = false,
597                 includeParents = true,
598                 target = this
599             )
600         if (interfaceTypes.isEmpty()) {
601             return interfaceTypes
602         }
603 
604         return interfaceTypes
605     }
606 
607     private fun filteredInterfaceTypes(
608         predicate: Predicate<Item>,
609         types: LinkedHashSet<TypeItem>,
610         includeSelf: Boolean,
611         includeParents: Boolean,
612         target: ClassItem
613     ): LinkedHashSet<TypeItem> {
614         val superClassType = superClassType()
615         if (superClassType != null) {
616             val superClass = superClassType.asClass()
617             if (superClass != null) {
618                 if (!predicate.test(superClass)) {
619                     superClass.filteredInterfaceTypes(
620                         predicate,
621                         types,
622                         true,
623                         includeParents,
624                         target
625                     )
626                 } else if (includeSelf && superClass.isInterface()) {
627                     types.add(superClassType)
628                     if (includeParents) {
629                         superClass.filteredInterfaceTypes(
630                             predicate,
631                             types,
632                             true,
633                             includeParents,
634                             target
635                         )
636                     }
637                 }
638             }
639         }
640         for (type in interfaceTypes()) {
641             val cls = type.asClass() ?: continue
642             if (predicate.test(cls)) {
643                 if (hasTypeVariables() && type.hasTypeArguments()) {
644                     val replacementMap = target.mapTypeVariables(this)
645                     if (replacementMap.isNotEmpty()) {
646                         val mapped = type.convertType(replacementMap)
647                         types.add(mapped)
648                         continue
649                     }
650                 }
651                 types.add(type)
652                 if (includeParents) {
653                     cls.filteredInterfaceTypes(predicate, types, true, includeParents, target)
654                 }
655             } else {
656                 cls.filteredInterfaceTypes(predicate, types, true, includeParents, target)
657             }
658         }
659         return types
660     }
661 
662     fun allInnerClasses(includeSelf: Boolean = false): Sequence<ClassItem> {
663         if (!includeSelf && innerClasses().isEmpty()) {
664             return emptySequence()
665         }
666 
667         val list = ArrayList<ClassItem>()
668         if (includeSelf) {
669             list.add(this)
670         }
671         addInnerClasses(list, this)
672         return list.asSequence()
673     }
674 
675     private fun addInnerClasses(list: MutableList<ClassItem>, cls: ClassItem) {
676         for (innerClass in cls.innerClasses()) {
677             list.add(innerClass)
678             addInnerClasses(list, innerClass)
679         }
680     }
681 
682     /**
683      * The default constructor to invoke on this class from subclasses; initially null but may be
684      * updated during use. (Note that in some cases [stubConstructor] may not be in [constructors],
685      * e.g. when we need to create a constructor to match a public parent class with a non-default
686      * constructor and the one in the code is not a match, e.g. is marked @hide etc.)
687      */
688     var stubConstructor: ConstructorItem?
689 
690     /**
691      * Creates a map of type parameters of the target class to the type variables substituted for
692      * those parameters by this class.
693      *
694      * If this class is declared as `class A<X,Y> extends B<X,Y>`, and target class `B` is declared
695      * as `class B<M,N>`, this method returns the map `{M->X, N->Y}`.
696      *
697      * There could be multiple intermediate classes between this class and the target class, and in
698      * some cases we could be substituting in a concrete class, e.g. if this class is declared as
699      * `class MyClass extends Parent<String,Number>` and target class `Parent` is declared as `class
700      * Parent<M,N>` would return the map `{M->java.lang.String, N>java.lang.Number}`.
701      *
702      * The target class can be an interface. If the interface can be found through multiple paths in
703      * the class hierarchy, this method returns the mapping from the first path found in terms of
704      * declaration order. For instance, given declarations `class C<X, Y> implements I1<X>, I2<Y>`,
705      * `interface I1<T1> implements Root<T1>`, `interface I2<T2> implements Root<T2>`, and
706      * `interface Root<T>`, this method will return `{T->X}` as the mapping from `C` to `Root`, not
707      * `{T->Y}`.
708      */
709     fun mapTypeVariables(target: ClassItem): TypeParameterBindings {
710         // Gather the supertypes to check for [target]. It is only possible for [target] to be found
711         // in the class hierarchy through this class's interfaces if [target] is an interface.
712         val candidates =
713             if (target.isInterface()) {
714                 interfaceTypes() + superClassType()
715             } else {
716                 listOf(superClassType())
717             }
718 
719         for (superClassType in candidates.filterNotNull()) {
720             superClassType as? ClassTypeItem ?: continue
721             // Get the class from the class type so that its type parameters can be accessed.
722             val declaringClass = superClassType.asClass() ?: continue
723 
724             if (declaringClass.qualifiedName() == target.qualifiedName()) {
725                 // The target has been found, return the map directly.
726                 return mapTypeVariables(declaringClass, superClassType)
727             } else {
728                 // This superClassType isn't target, but maybe it has target as a superclass.
729                 val nextLevelMap = declaringClass.mapTypeVariables(target)
730                 if (nextLevelMap.isNotEmpty()) {
731                     val thisLevelMap = mapTypeVariables(declaringClass, superClassType)
732                     // Link the two maps by removing intermediate type variables.
733                     return nextLevelMap.mapValues { (_, value) ->
734                         (value as? VariableTypeItem?)?.let { thisLevelMap[it.asTypeParameter] }
735                             ?: value
736                     }
737                 }
738             }
739         }
740         return emptyMap()
741     }
742 
743     /**
744      * Creates a map between the type parameters of [declaringClass] and the arguments of
745      * [classTypeItem].
746      */
747     private fun mapTypeVariables(
748         declaringClass: ClassItem,
749         classTypeItem: ClassTypeItem
750     ): TypeParameterBindings {
751         // Don't include arguments of class types, for consistency with the old psi implementation.
752         // i.e. if the mapping is from `T -> List<String>` then just use `T -> List`.
753         // TODO (b/319300404): remove this section
754         val classTypeArguments =
755             classTypeItem.arguments.map {
756                 if (it is ClassTypeItem && it.arguments.isNotEmpty()) {
757                     it.duplicate(it.outerClassType, arguments = emptyList())
758                 } else {
759                     it
760                 }
761                 // Although a `ClassTypeItem`'s arguments can be `WildcardTypeItem`s as well as
762                 // `ReferenceTypeItem`s, a `ClassTypeItem` used in an extends or implements list
763                 // cannot have a `WildcardTypeItem` as an argument so this cast is safe. See
764                 // https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-Superclass
765                 as ReferenceTypeItem
766             }
767         return declaringClass.typeParameterList.zip(classTypeArguments).toMap()
768     }
769 
770     /** Creates a constructor in this class */
771     fun createDefaultConstructor(): ConstructorItem = codebase.unsupported()
772 
773     /**
774      * Creates a method corresponding to the given method signature in this class.
775      *
776      * This is used to inherit a [MethodItem] from a super class that will not be part of the API
777      * into a class that will be part of the API.
778      *
779      * The [MethodItem.inheritedFrom] property in the returned [MethodItem] is set to
780      * [MethodItem.containingClass] of the [template].
781      */
782     fun inheritMethodFromNonApiAncestor(template: MethodItem): MethodItem = codebase.unsupported()
783 
784     fun addMethod(method: MethodItem): Unit = codebase.unsupported()
785 
786     fun addInnerClass(cls: ClassItem): Unit = codebase.unsupported()
787 
788     /**
789      * Return true if a [ClassItem] could be subclassed, i.e. is not final or sealed and has at
790      * least one accessible constructor.
791      */
792     fun isExtensible() =
793         !modifiers.isFinal() &&
794             !modifiers.isSealed() &&
795             constructors().any { it.isPublic || it.isProtected }
796 }
797