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