• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.SdkConstants
20 import com.android.tools.metalava.ApiAnalyzer
21 import com.android.tools.metalava.JAVA_LANG_ANNOTATION
22 import com.android.tools.metalava.JAVA_LANG_ENUM
23 import com.android.tools.metalava.JAVA_LANG_OBJECT
24 import com.android.tools.metalava.model.visitors.ApiVisitor
25 import com.android.tools.metalava.model.visitors.ItemVisitor
26 import com.android.tools.metalava.model.visitors.TypeVisitor
27 import com.google.common.base.Splitter
28 import java.util.ArrayList
29 import java.util.LinkedHashSet
30 import java.util.function.Predicate
31 
32 /**
33  * Represents a {@link https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html Class}
34  *
35  * If you need to model array dimensions or resolved type parameters, see {@link com.android.tools.metalava.model.TypeItem} instead
36  */
37 interface ClassItem : Item {
38     /** The simple name of a class. In class foo.bar.Outer.Inner, the simple name is "Inner" */
39     fun simpleName(): String
40 
41     /** The full name of a class. In class foo.bar.Outer.Inner, the full name is "Outer.Inner" */
42     fun fullName(): String
43 
44     /** The qualified name of a class. In class foo.bar.Outer.Inner, the qualified name is the whole thing. */
45     fun qualifiedName(): String
46 
47     /** Is the class explicitly defined in the source file? */
48     fun isDefined(): Boolean
49 
50     /** Is this an innerclass? */
51     fun isInnerClass(): Boolean = containingClass() != null
52 
53     /** Is this a top level class? */
54     fun isTopLevelClass(): Boolean = containingClass() == null
55 
56     /** This [ClassItem] and all of its inner classes, recursively */
57     fun allClasses(): Sequence<ClassItem> {
58         return sequenceOf(this).plus(innerClasses().asSequence().flatMap { it.allClasses() })
59     }
60 
61     override fun parent(): Item? = containingClass() ?: containingPackage()
62 
63     /**
64      * The qualified name where inner classes use $ as a separator.
65      * In class foo.bar.Outer.Inner, this method will return foo.bar.Outer$Inner.
66      * (This is the name format used in ProGuard keep files for example.)
67      */
68     fun qualifiedNameWithDollarInnerClasses(): String {
69         var curr: ClassItem? = this
70         while (curr?.containingClass() != null) {
71             curr = curr.containingClass()
72         }
73 
74         if (curr == null) {
75             return fullName().replace('.', '$')
76         }
77 
78         return curr.containingPackage().qualifiedName() + "." + fullName().replace('.', '$')
79     }
80 
81     /** Returns the internal name of the class, as seen in bytecode */
82     fun internalName(): String {
83         var curr: ClassItem? = this
84         while (curr?.containingClass() != null) {
85             curr = curr.containingClass()
86         }
87 
88         if (curr == null) {
89             return fullName().replace('.', '$')
90         }
91 
92         return curr.containingPackage().qualifiedName().replace('.', '/') + "/" +
93             fullName().replace('.', '$')
94     }
95 
96     /** The super class of this class, if any  */
97     fun superClass(): ClassItem?
98 
99     /** The super class type of this class, if any. The difference between this and [superClass] is
100      * that the type reference can include type arguments; e.g. in "class MyList extends List<String>"
101      * the super class is java.util.List and the super class type is java.util.List<java.lang.String>.
102      * */
103     fun superClassType(): TypeItem?
104 
105     /** Finds the public super class of this class, if any */
106     fun publicSuperClass(): ClassItem? {
107         var superClass = superClass()
108         while (superClass != null && !superClass.checkLevel()) {
109             superClass = superClass.superClass()
110         }
111 
112         return superClass
113     }
114 
115     /** Returns true if this class extends the given class (includes self) */
116     fun extends(qualifiedName: String): Boolean {
117         if (qualifiedName() == qualifiedName) {
118             return true
119         }
120 
121         val superClass = superClass()
122         return superClass?.extends(qualifiedName) ?: when {
123             isEnum() -> qualifiedName == JAVA_LANG_ENUM
124             isAnnotationType() -> qualifiedName == JAVA_LANG_ANNOTATION
125             else -> qualifiedName == JAVA_LANG_OBJECT
126         }
127     }
128 
129     /** Returns true if this class implements the given interface (includes self) */
130     fun implements(qualifiedName: String): Boolean {
131         if (qualifiedName() == qualifiedName) {
132             return true
133         }
134 
135         interfaceTypes().forEach {
136             val cls = it.asClass()
137             if (cls != null && cls.implements(qualifiedName)) {
138                 return true
139             }
140         }
141 
142         // Might be implementing via superclass
143         if (superClass()?.implements(qualifiedName) == true) {
144             return true
145         }
146 
147         return false
148     }
149 
150     /** Returns true if this class extends or implements the given class or interface */
151     fun extendsOrImplements(qualifiedName: String): Boolean = extends(qualifiedName) || implements(qualifiedName)
152 
153     /** Any interfaces implemented by this class */
154     fun interfaceTypes(): List<TypeItem>
155 
156     /** All classes and interfaces implemented (by this class and its super classes and the interfaces themselves) */
157     fun allInterfaces(): Sequence<ClassItem>
158 
159     /** Any inner classes of this class */
160     fun innerClasses(): List<ClassItem>
161 
162     /** The constructors in this class */
163     fun constructors(): List<ConstructorItem>
164 
165     /** Whether this class has an implicit default constructor */
166     fun hasImplicitDefaultConstructor(): Boolean
167 
168     /** The non-constructor methods in this class */
169     fun methods(): List<MethodItem>
170 
171     /** The properties in this class */
172     fun properties(): List<PropertyItem>
173 
174     /** The fields in this class */
175     fun fields(): List<FieldItem>
176 
177     /** The members in this class: constructors, methods, fields/enum constants */
178     fun members(): Sequence<MemberItem> {
179         return fields().asSequence().plus(constructors().asSequence()).plus(methods().asSequence())
180     }
181 
182     /** Whether this class is an interface */
183     fun isInterface(): Boolean
184 
185     /** Whether this class is an annotation type */
186     fun isAnnotationType(): Boolean
187 
188     /** Whether this class is an enum */
189     fun isEnum(): Boolean
190 
191     /** Whether this class is a regular class (not an interface, not an enum, etc) */
192     fun isClass(): Boolean = !isInterface() && !isAnnotationType() && !isEnum()
193 
194     /** The containing class, for inner classes */
195     fun containingClass(): ClassItem?
196 
197     /** The containing package */
198     fun containingPackage(): PackageItem
199 
200     override fun containingPackage(strict: Boolean): PackageItem = containingPackage()
201 
202     override fun containingClass(strict: Boolean): ClassItem? {
203         return if (strict) containingClass() else this
204     }
205 
206     /** Gets the type for this class */
207     fun toType(): TypeItem
208 
209     override fun type(): TypeItem? = null
210 
211     /** Returns true if this class has type parameters */
212     fun hasTypeVariables(): Boolean
213 
214     /** Any type parameters for the class, if any, as a source string (with fully qualified class names) */
215     fun typeParameterList(): TypeParameterList
216 
217     /** Returns the classes that are part of the type parameters of this method, if any */
218     fun typeArgumentClasses(): List<ClassItem> = codebase.unsupported()
219 
220     fun isJavaLangObject(): Boolean {
221         return qualifiedName() == JAVA_LANG_OBJECT
222     }
223 
224     // Mutation APIs: Used to "fix up" the API hierarchy (in [ApiAnalyzer]) to only expose
225     // visible parts of the API)
226 
227     // This replaces the "real" super class
228     fun setSuperClass(superClass: ClassItem?, superClassType: TypeItem? = superClass?.toType())
229 
230     // This replaces the interface types implemented by this class
231     fun setInterfaceTypes(interfaceTypes: List<TypeItem>)
232 
233     // Whether this class is a generic type parameter, such as T, rather than a non-generic type, like String
234     val isTypeParameter: Boolean
235 
236     var hasPrivateConstructor: Boolean
237 
238     /**
239      * Maven artifact of this class, if any. (Not used for the Android SDK, but used in
240      * for example support libraries.
241      */
242     var artifact: String?
243 
244     override fun accept(visitor: ItemVisitor) {
245         if (visitor is ApiVisitor) {
246             accept(visitor)
247             return
248         }
249 
250         if (visitor.skip(this)) {
251             return
252         }
253 
254         visitor.visitItem(this)
255         visitor.visitClass(this)
256 
257         for (constructor in constructors()) {
258             constructor.accept(visitor)
259         }
260 
261         for (method in methods()) {
262             method.accept(visitor)
263         }
264 
265         for (property in properties()) {
266             property.accept(visitor)
267         }
268 
269         if (isEnum()) {
270             // In enums, visit the enum constants first, then the fields
271             for (field in fields()) {
272                 if (field.isEnumConstant()) {
273                     field.accept(visitor)
274                 }
275             }
276             for (field in fields()) {
277                 if (!field.isEnumConstant()) {
278                     field.accept(visitor)
279                 }
280             }
281         } else {
282             for (field in fields()) {
283                 field.accept(visitor)
284             }
285         }
286 
287         if (visitor.nestInnerClasses) {
288             for (cls in innerClasses()) {
289                 cls.accept(visitor)
290             }
291         } // otherwise done below
292 
293         visitor.afterVisitClass(this)
294         visitor.afterVisitItem(this)
295 
296         if (!visitor.nestInnerClasses) {
297             for (cls in innerClasses()) {
298                 cls.accept(visitor)
299             }
300         }
301     }
302 
303     fun accept(visitor: ApiVisitor) {
304 
305         if (!visitor.include(this)) {
306             return
307         }
308 
309         // We build up a separate data structure such that we can compute the
310         // sets of fields, methods, etc even for inner classes (recursively); that way
311         // we can easily and up front determine whether we have any matches for
312         // inner classes (which is vital for computing the removed-api for example, where
313         // only something like the appearance of a removed method inside an inner class
314         // results in the outer class being described in the signature file.
315         val candidate = VisitCandidate(this, visitor)
316         candidate.accept()
317     }
318 
319     override fun acceptTypes(visitor: TypeVisitor) {
320         if (visitor.skip(this)) {
321             return
322         }
323 
324         val type = toType()
325         visitor.visitType(type, this)
326 
327         // TODO: Visit type parameter list (at least the bounds types, e.g. View in <T extends View>
328         superClass()?.let {
329             visitor.visitType(it.toType(), it)
330         }
331 
332         if (visitor.includeInterfaces) {
333             for (itf in interfaceTypes()) {
334                 val owner = itf.asClass()
335                 owner?.let { visitor.visitType(itf, it) }
336             }
337         }
338 
339         for (constructor in constructors()) {
340             constructor.acceptTypes(visitor)
341         }
342         for (field in fields()) {
343             field.acceptTypes(visitor)
344         }
345         for (method in methods()) {
346             method.acceptTypes(visitor)
347         }
348         for (cls in innerClasses()) {
349             cls.acceptTypes(visitor)
350         }
351 
352         visitor.afterVisitType(type, this)
353     }
354 
355     companion object {
356         /** Looks up the retention policy for the given class */
357         fun findRetention(cls: ClassItem): AnnotationRetention {
358             val modifiers = cls.modifiers
359             val annotation = modifiers.findAnnotation("java.lang.annotation.Retention")
360                 ?: modifiers.findAnnotation("kotlin.annotation.Retention")
361             val value = annotation?.findAttribute(SdkConstants.ATTR_VALUE)
362             val source = value?.value?.toSource()
363             return when {
364                 source == null -> AnnotationRetention.CLASS // default
365                 source.contains("RUNTIME") -> AnnotationRetention.RUNTIME
366                 source.contains("SOURCE") -> AnnotationRetention.SOURCE
367                 else -> AnnotationRetention.CLASS // default
368             }
369         }
370 
371         // Same as doclava1 (modulo the new handling when class names match)
372         val comparator: Comparator<in ClassItem> = Comparator { o1, o2 ->
373             val delta = o1.fullName().compareTo(o2.fullName())
374             if (delta == 0) {
375                 o1.qualifiedName().compareTo(o2.qualifiedName())
376             } else {
377                 delta
378             }
379         }
380 
381         val nameComparator: Comparator<ClassItem> = Comparator { a, b ->
382             a.simpleName().compareTo(b.simpleName())
383         }
384 
385         val fullNameComparator: Comparator<ClassItem> = Comparator { a, b -> a.fullName().compareTo(b.fullName()) }
386 
387         val qualifiedComparator: Comparator<ClassItem> = Comparator { a, b ->
388             a.qualifiedName().compareTo(b.qualifiedName())
389         }
390 
391         fun classNameSorter(): Comparator<in ClassItem> = ClassItem.qualifiedComparator
392     }
393 
394     fun findMethod(
395         template: MethodItem,
396         includeSuperClasses: Boolean = false,
397         includeInterfaces: Boolean = false
398     ): MethodItem? {
399         if (template.isConstructor()) {
400             return findConstructor(template as ConstructorItem)
401         }
402 
403         methods().asSequence()
404             .filter { it.matches(template) }
405             .forEach { return it }
406 
407         if (includeSuperClasses) {
408             superClass()?.findMethod(template, true, includeInterfaces)?.let { return it }
409         }
410 
411         if (includeInterfaces) {
412             for (itf in interfaceTypes()) {
413                 val cls = itf.asClass() ?: continue
414                 cls.findMethod(template, includeSuperClasses, true)?.let { return it }
415             }
416         }
417         return null
418     }
419 
420     /**
421      * Finds a method matching the given method that satisfies the given predicate,
422      * considering all methods defined on this class and its super classes
423      */
424     fun findPredicateMethodWithSuper(template: MethodItem, filter: Predicate<Item>?): MethodItem? {
425         val method = findMethod(template, true, true)
426         if (method == null) {
427             return null
428         }
429         if (filter == null || filter.test(method)) {
430             return method
431         }
432         return method.findPredicateSuperMethod(filter)
433     }
434 
435     /** Finds a given method in this class matching the VM name signature */
436     fun findMethodByDesc(
437         name: String,
438         desc: String,
439         includeSuperClasses: Boolean = false,
440         includeInterfaces: Boolean = false
441     ): MethodItem? {
442         if (desc.startsWith("<init>")) {
443             constructors().asSequence()
444                 .filter { it.internalDesc() == desc }
445                 .forEach { return it }
446             return null
447         } else {
448             methods().asSequence()
449                 .filter { it.name() == name && it.internalDesc() == desc }
450                 .forEach { return it }
451         }
452 
453         if (includeSuperClasses) {
454             superClass()?.findMethodByDesc(name, desc, true, includeInterfaces)?.let { return it }
455         }
456 
457         if (includeInterfaces) {
458             for (itf in interfaceTypes()) {
459                 val cls = itf.asClass() ?: continue
460                 cls.findMethodByDesc(name, desc, includeSuperClasses, true)?.let { return it }
461             }
462         }
463         return null
464     }
465 
466     fun findConstructor(template: ConstructorItem): ConstructorItem? {
467         constructors().asSequence()
468             .filter { it.matches(template) }
469             .forEach { return it }
470         return null
471     }
472 
473     fun findField(
474         fieldName: String,
475         includeSuperClasses: Boolean = false,
476         includeInterfaces: Boolean = false
477     ): FieldItem? {
478         val field = fields().firstOrNull { it.name() == fieldName }
479         if (field != null) {
480             return field
481         }
482 
483         if (includeSuperClasses) {
484             superClass()?.findField(fieldName, true, includeInterfaces)?.let { return it }
485         }
486 
487         if (includeInterfaces) {
488             for (itf in interfaceTypes()) {
489                 val cls = itf.asClass() ?: continue
490                 cls.findField(fieldName, includeSuperClasses, true)?.let { return it }
491             }
492         }
493         return null
494     }
495 
496     fun findMethod(methodName: String, parameters: String): MethodItem? {
497         if (methodName == simpleName()) {
498             // Constructor
499             constructors()
500                 .filter { parametersMatch(it, parameters) }
501                 .forEach { return it }
502         } else {
503             methods()
504                 .filter { it.name() == methodName && parametersMatch(it, parameters) }
505                 .forEach { return it }
506         }
507 
508         return null
509     }
510 
511     private fun parametersMatch(method: MethodItem, description: String): Boolean {
512         val parameterStrings = Splitter.on(",").trimResults().omitEmptyStrings().splitToList(description)
513         val parameters = method.parameters()
514         if (parameters.size != parameterStrings.size) {
515             return false
516         }
517         for (i in parameters.indices) {
518             var parameterString = parameterStrings[i]
519             val index = parameterString.indexOf('<')
520             if (index != -1) {
521                 parameterString = parameterString.substring(0, index)
522             }
523             val parameter = parameters[i].type().toErasedTypeString(method)
524             if (parameter != parameterString) {
525                 return false
526             }
527         }
528 
529         return true
530     }
531 
532     /** Returns the corresponding compilation unit, if any */
533     fun getCompilationUnit(): CompilationUnit? = null
534 
535     /** If this class is an annotation type, returns the retention of this class */
536     fun getRetention(): AnnotationRetention
537 
538     /**
539      * Return superclass matching the given predicate. When a superclass doesn't
540      * match, we'll keep crawling up the tree until we find someone who matches.
541      */
542     fun filteredSuperclass(predicate: Predicate<Item>): ClassItem? {
543         val superClass = superClass() ?: return null
544         return if (predicate.test(superClass)) {
545             superClass
546         } else {
547             superClass.filteredSuperclass(predicate)
548         }
549     }
550 
551     fun filteredSuperClassType(predicate: Predicate<Item>): TypeItem? {
552         var superClassType: TypeItem? = superClassType() ?: return null
553         var prev: ClassItem? = null
554         while (superClassType != null) {
555             val superClass = superClassType.asClass() ?: return null
556             if (predicate.test(superClass)) {
557                 if (prev == null || superClass == superClass()) {
558                     // Direct reference; no need to map type variables
559                     return superClassType
560                 }
561                 if (!superClassType.hasTypeArguments()) {
562                     // No type variables - also no need for mapping
563                     return superClassType
564                 }
565 
566                 return superClassType.convertType(this, prev)
567             }
568 
569             prev = superClass
570             superClassType = superClass.superClassType()
571         }
572 
573         return null
574     }
575 
576     /**
577      * Return methods matching the given predicate. Forcibly includes local
578      * methods that override a matching method in an ancestor class.
579      */
580     fun filteredMethods(
581         predicate: Predicate<Item>,
582         includeSuperClassMethods: Boolean = false
583     ): Collection<MethodItem> {
584         val methods = LinkedHashSet<MethodItem>()
585         for (method in methods()) {
586             if (predicate.test(method) || method.findPredicateSuperMethod(predicate) != null) {
587                 // val duplicated = method.duplicate(this)
588                 // methods.add(duplicated)
589                 methods.remove(method)
590                 methods.add(method)
591             }
592         }
593         if (includeSuperClassMethods) {
594             superClass()?.filteredMethods(predicate, includeSuperClassMethods)?.let { methods += it }
595         }
596         return methods
597     }
598 
599     /** Returns the constructors that match the given predicate */
600     fun filteredConstructors(predicate: Predicate<Item>): Sequence<ConstructorItem> {
601         return constructors().asSequence().filter { predicate.test(it) }
602     }
603 
604     /**
605      * Return fields matching the given predicate. Also clones fields from
606      * ancestors that would match had they been defined in this class.
607      */
608     fun filteredFields(predicate: Predicate<Item>, showUnannotated: Boolean): List<FieldItem> {
609         val fields = LinkedHashSet<FieldItem>()
610         if (showUnannotated) {
611             for (clazz in allInterfaces()) {
612                 if (!clazz.isInterface()) {
613                     continue
614                 }
615                 for (field in clazz.fields()) {
616                     if (!predicate.test(field)) {
617                         val duplicated = field.duplicate(this)
618                         if (predicate.test(duplicated)) {
619                             fields.remove(duplicated)
620                             fields.add(duplicated)
621                         }
622                     }
623                 }
624             }
625 
626             val superClass = superClass()
627             if (superClass != null && !predicate.test(superClass) && predicate.test(this)) {
628                 // Include constants from hidden super classes.
629                 for (field in superClass.fields()) {
630                     val fieldModifiers = field.modifiers
631                     if (!fieldModifiers.isStatic() || !fieldModifiers.isFinal() || !fieldModifiers.isPublic()) {
632                         continue
633                     }
634                     if (!field.originallyHidden) {
635                         val duplicated = field.duplicate(this)
636                         if (predicate.test(duplicated)) {
637                             duplicated.inheritedField = true
638                             fields.remove(duplicated)
639                             fields.add(duplicated)
640                         }
641                     }
642                 }
643             }
644         }
645         for (field in fields()) {
646             if (predicate.test(field)) {
647                 fields.remove(field)
648                 fields.add(field)
649             }
650         }
651         if (fields.isEmpty()) {
652             return emptyList()
653         }
654         val list = fields.toMutableList()
655         list.sortWith(FieldItem.comparator)
656         return list
657     }
658 
659     fun filteredInterfaceTypes(predicate: Predicate<Item>): Collection<TypeItem> {
660         val interfaceTypes = filteredInterfaceTypes(
661             predicate, LinkedHashSet(),
662             includeSelf = false, includeParents = false, target = this
663         )
664         if (interfaceTypes.isEmpty()) {
665             return interfaceTypes
666         }
667 
668         return interfaceTypes
669     }
670 
671     fun allInterfaceTypes(predicate: Predicate<Item>): Collection<TypeItem> {
672         val interfaceTypes = filteredInterfaceTypes(
673             predicate, LinkedHashSet(),
674             includeSelf = false, includeParents = true, target = this
675         )
676         if (interfaceTypes.isEmpty()) {
677             return interfaceTypes
678         }
679 
680         return interfaceTypes
681     }
682 
683     private fun filteredInterfaceTypes(
684         predicate: Predicate<Item>,
685         types: LinkedHashSet<TypeItem>,
686         includeSelf: Boolean,
687         includeParents: Boolean,
688         target: ClassItem
689     ): LinkedHashSet<TypeItem> {
690         val superClassType = superClassType()
691         if (superClassType != null) {
692             val superClass = superClassType.asClass()
693             if (superClass != null) {
694                 if (!predicate.test(superClass)) {
695                     superClass.filteredInterfaceTypes(predicate, types, true, includeParents, target)
696                 } else if (includeSelf && superClass.isInterface()) {
697                     types.add(superClassType)
698                     if (includeParents) {
699                         superClass.filteredInterfaceTypes(predicate, types, true, includeParents, target)
700                     }
701                 }
702             }
703         }
704         for (type in interfaceTypes()) {
705             val cls = type.asClass() ?: continue
706             if (predicate.test(cls)) {
707                 if (hasTypeVariables() && type.hasTypeArguments()) {
708                     val replacementMap = target.mapTypeVariables(this)
709                     if (replacementMap.isNotEmpty()) {
710                         val mapped = type.convertType(replacementMap)
711                         types.add(mapped)
712                         continue
713                     }
714                 }
715                 types.add(type)
716                 if (includeParents) {
717                     cls.filteredInterfaceTypes(predicate, types, true, includeParents, target)
718                 }
719             } else {
720                 cls.filteredInterfaceTypes(predicate, types, true, includeParents, target)
721             }
722         }
723         return types
724     }
725 
726     fun allInnerClasses(includeSelf: Boolean = false): Sequence<ClassItem> {
727         if (!includeSelf && innerClasses().isEmpty()) {
728             return emptySequence()
729         }
730 
731         val list = ArrayList<ClassItem>()
732         if (includeSelf) {
733             list.add(this)
734         }
735         addInnerClasses(list, this)
736         return list.asSequence()
737     }
738 
739     private fun addInnerClasses(list: MutableList<ClassItem>, cls: ClassItem) {
740         for (innerClass in cls.innerClasses()) {
741             list.add(innerClass)
742             addInnerClasses(list, innerClass)
743         }
744     }
745 
746     /**
747      * The default constructor to invoke on this class from subclasses; initially null
748      * but populated by [ApiAnalyzer.addConstructors]. (Note that in some cases
749      * [stubConstructor] may not be in [constructors], e.g. when we need to
750      * create a constructor to match a public parent class with a non-default constructor
751      * and the one in the code is not a match, e.g. is marked @hide etc.)
752      */
753     var stubConstructor: ConstructorItem?
754 
755     /**
756      * Creates a map of type variables from this class to the given target class.
757      * If class A<X,Y> extends B<X,Y>, and B is declared as class B<M,N>,
758      * this returns the map {"X"->"M", "Y"->"N"}. There could be multiple intermediate
759      * classes between this class and the target class, and in some cases we could
760      * be substituting in a concrete class, e.g. class MyClass extends B<String,Number>
761      * would return the map {"java.lang.String"->"M", "java.lang.Number"->"N"}.
762      *
763      * If [reverse] is true, compute the reverse map: keys are the variables in
764      * the target and the values are the variables in the source.
765      */
766     fun mapTypeVariables(target: ClassItem): Map<String, String> = codebase.unsupported()
767 
768     /**
769      * Creates a constructor in this class
770      */
771     fun createDefaultConstructor(): ConstructorItem = codebase.unsupported()
772 
773     /**
774      * Creates a method corresponding to the given method signature in this class
775      */
776     fun createMethod(template: MethodItem): MethodItem = codebase.unsupported()
777 
778     fun addMethod(method: MethodItem): Unit = codebase.unsupported()
779 }
780 
781 class VisitCandidate(val cls: ClassItem, private val visitor: ApiVisitor) {
782     val innerClasses: Sequence<VisitCandidate>
783     private val constructors: Sequence<MethodItem>
784     private val methods: Sequence<MethodItem>
785     private val fields: Sequence<FieldItem>
786     private val enums: Sequence<FieldItem>
787     private val properties: Sequence<PropertyItem>
788 
789     init {
790         val filterEmit = visitor.filterEmit
791 
792         constructors = cls.constructors().asSequence()
<lambda>null793             .filter { filterEmit.test(it) }
794             .sortedWith(MethodItem.comparator)
795 
796         methods = cls.methods().asSequence()
<lambda>null797             .filter { filterEmit.test(it) }
798             .sortedWith(MethodItem.comparator)
799 
800         val fieldSequence =
801             if (visitor.inlineInheritedFields) {
802                 cls.filteredFields(filterEmit, visitor.showUnannotated).asSequence()
803             } else {
804                 cls.fields().asSequence()
<lambda>null805                     .filter { filterEmit.test(it) }
806             }
807         if (cls.isEnum()) {
808             fields = fieldSequence
<lambda>null809                 .filter { !it.isEnumConstant() }
810                 .sortedWith(FieldItem.comparator)
811             enums = fieldSequence
<lambda>null812                 .filter { it.isEnumConstant() }
<lambda>null813                 .filter { filterEmit.test(it) }
814                 .sortedWith(FieldItem.comparator)
815         } else {
816             fields = fieldSequence.sortedWith(FieldItem.comparator)
817             enums = emptySequence()
818         }
819 
820         properties = if (cls.properties().isEmpty()) {
821             emptySequence()
822         } else {
823             cls.properties().asSequence()
<lambda>null824                 .filter { filterEmit.test(it) }
825                 .sortedWith(PropertyItem.comparator)
826         }
827 
828         innerClasses = cls.innerClasses()
829             .asSequence()
830             .sortedWith(ClassItem.classNameSorter())
<lambda>null831             .map { VisitCandidate(it, visitor) }
832     }
833 
834     /** Whether the class body contains any Item's (other than inner Classes) */
nonEmptynull835     fun nonEmpty(): Boolean {
836         return !(constructors.none() && methods.none() && enums.none() && fields.none() && properties.none())
837     }
838 
acceptnull839     fun accept() {
840         if (!visitor.include(this)) {
841             return
842         }
843 
844         val emitThis = visitor.shouldEmitClass(this)
845         if (emitThis) {
846             if (!visitor.visitingPackage) {
847                 visitor.visitingPackage = true
848                 val pkg = cls.containingPackage()
849                 visitor.visitItem(pkg)
850                 visitor.visitPackage(pkg)
851             }
852 
853             visitor.visitItem(cls)
854             visitor.visitClass(cls)
855 
856             val sortedConstructors = if (visitor.methodComparator != null) {
857                 constructors.sortedWith(visitor.methodComparator)
858             } else {
859                 constructors
860             }
861             val sortedMethods = if (visitor.methodComparator != null) {
862                 methods.sortedWith(visitor.methodComparator)
863             } else {
864                 methods
865             }
866             val sortedFields = if (visitor.fieldComparator != null) {
867                 fields.sortedWith(visitor.fieldComparator)
868             } else {
869                 fields
870             }
871 
872             for (constructor in sortedConstructors) {
873                 constructor.accept(visitor)
874             }
875 
876             for (method in sortedMethods) {
877                 method.accept(visitor)
878             }
879 
880             for (property in properties) {
881                 property.accept(visitor)
882             }
883             for (enumConstant in enums) {
884                 enumConstant.accept(visitor)
885             }
886             for (field in sortedFields) {
887                 field.accept(visitor)
888             }
889         }
890 
891         if (visitor.nestInnerClasses) { // otherwise done below
892             innerClasses.forEach { it.accept() }
893         }
894 
895         if (emitThis) {
896             visitor.afterVisitClass(cls)
897             visitor.afterVisitItem(cls)
898         }
899 
900         if (!visitor.nestInnerClasses) {
901             innerClasses.forEach { it.accept() }
902         }
903     }
904 }
905