• 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> = TODO("Not yet implemented")
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     /** If true, this is an invisible element that was referenced by a public API. */
239     var notStrippable: Boolean
240 
241     /**
242      * Maven artifact of this class, if any. (Not used for the Android SDK, but used in
243      * for example support libraries.
244      */
245     var artifact: String?
246 
247     override fun accept(visitor: ItemVisitor) {
248         if (visitor is ApiVisitor) {
249             accept(visitor)
250             return
251         }
252 
253         if (visitor.skip(this)) {
254             return
255         }
256 
257         visitor.visitItem(this)
258         visitor.visitClass(this)
259 
260         for (constructor in constructors()) {
261             constructor.accept(visitor)
262         }
263 
264         for (method in methods()) {
265             method.accept(visitor)
266         }
267 
268         for (property in properties()) {
269             property.accept(visitor)
270         }
271 
272         if (isEnum()) {
273             // In enums, visit the enum constants first, then the fields
274             for (field in fields()) {
275                 if (field.isEnumConstant()) {
276                     field.accept(visitor)
277                 }
278             }
279             for (field in fields()) {
280                 if (!field.isEnumConstant()) {
281                     field.accept(visitor)
282                 }
283             }
284         } else {
285             for (field in fields()) {
286                 field.accept(visitor)
287             }
288         }
289 
290         if (visitor.nestInnerClasses) {
291             for (cls in innerClasses()) {
292                 cls.accept(visitor)
293             }
294         } // otherwise done below
295 
296         visitor.afterVisitClass(this)
297         visitor.afterVisitItem(this)
298 
299         if (!visitor.nestInnerClasses) {
300             for (cls in innerClasses()) {
301                 cls.accept(visitor)
302             }
303         }
304     }
305 
306     fun accept(visitor: ApiVisitor) {
307 
308         if (!visitor.include(this)) {
309             return
310         }
311 
312         // We build up a separate data structure such that we can compute the
313         // sets of fields, methods, etc even for inner classes (recursively); that way
314         // we can easily and up front determine whether we have any matches for
315         // inner classes (which is vital for computing the removed-api for example, where
316         // only something like the appearance of a removed method inside an inner class
317         // results in the outer class being described in the signature file.
318         val candidate = VisitCandidate(this, visitor)
319         candidate.accept()
320     }
321 
322     override fun acceptTypes(visitor: TypeVisitor) {
323         if (visitor.skip(this)) {
324             return
325         }
326 
327         val type = toType()
328         visitor.visitType(type, this)
329 
330         // TODO: Visit type parameter list (at least the bounds types, e.g. View in <T extends View>
331         superClass()?.let {
332             visitor.visitType(it.toType(), it)
333         }
334 
335         if (visitor.includeInterfaces) {
336             for (itf in interfaceTypes()) {
337                 val owner = itf.asClass()
338                 owner?.let { visitor.visitType(itf, it) }
339             }
340         }
341 
342         for (constructor in constructors()) {
343             constructor.acceptTypes(visitor)
344         }
345         for (field in fields()) {
346             field.acceptTypes(visitor)
347         }
348         for (method in methods()) {
349             method.acceptTypes(visitor)
350         }
351         for (cls in innerClasses()) {
352             cls.acceptTypes(visitor)
353         }
354 
355         visitor.afterVisitType(type, this)
356     }
357 
358     companion object {
359         /** Looks up the retention policy for the given class */
360         fun findRetention(cls: ClassItem): AnnotationRetention {
361             val modifiers = cls.modifiers
362             val annotation = modifiers.findAnnotation("java.lang.annotation.Retention")
363                 ?: modifiers.findAnnotation("kotlin.annotation.Retention")
364             val value = annotation?.findAttribute(SdkConstants.ATTR_VALUE)
365             val source = value?.value?.toSource()
366             return when {
367                 source == null -> AnnotationRetention.CLASS // default
368                 source.contains("RUNTIME") -> AnnotationRetention.RUNTIME
369                 source.contains("SOURCE") -> AnnotationRetention.SOURCE
370                 else -> AnnotationRetention.CLASS // default
371             }
372         }
373 
374         // Same as doclava1 (modulo the new handling when class names match)
375         val comparator: Comparator<in ClassItem> = Comparator { o1, o2 ->
376             val delta = o1.fullName().compareTo(o2.fullName())
377             if (delta == 0) {
378                 o1.qualifiedName().compareTo(o2.qualifiedName())
379             } else {
380                 delta
381             }
382         }
383 
384         val nameComparator: Comparator<ClassItem> = Comparator { a, b ->
385             a.simpleName().compareTo(b.simpleName())
386         }
387 
388         val fullNameComparator: Comparator<ClassItem> = Comparator { a, b -> a.fullName().compareTo(b.fullName()) }
389 
390         val qualifiedComparator: Comparator<ClassItem> = Comparator { a, b ->
391             a.qualifiedName().compareTo(b.qualifiedName())
392         }
393 
394         fun classNameSorter(): Comparator<in ClassItem> = ClassItem.qualifiedComparator
395     }
396 
397     fun findMethod(
398         template: MethodItem,
399         includeSuperClasses: Boolean = false,
400         includeInterfaces: Boolean = false
401     ): MethodItem? {
402         if (template.isConstructor()) {
403             return findConstructor(template as ConstructorItem)
404         }
405 
406         methods().asSequence()
407             .filter { it.matches(template) }
408             .forEach { return it }
409 
410         if (includeSuperClasses) {
411             superClass()?.findMethod(template, true, includeInterfaces)?.let { return it }
412         }
413 
414         if (includeInterfaces) {
415             for (itf in interfaceTypes()) {
416                 val cls = itf.asClass() ?: continue
417                 cls.findMethod(template, includeSuperClasses, true)?.let { return it }
418             }
419         }
420         return null
421     }
422 
423     /** Finds a given method in this class matching the VM name signature */
424     fun findMethodByDesc(
425         name: String,
426         desc: String,
427         includeSuperClasses: Boolean = false,
428         includeInterfaces: Boolean = false
429     ): MethodItem? {
430         if (desc.startsWith("<init>")) {
431             constructors().asSequence()
432                 .filter { it.internalDesc() == desc }
433                 .forEach { return it }
434             return null
435         } else {
436             methods().asSequence()
437                 .filter { it.name() == name && it.internalDesc() == desc }
438                 .forEach { return it }
439         }
440 
441         if (includeSuperClasses) {
442             superClass()?.findMethodByDesc(name, desc, true, includeInterfaces)?.let { return it }
443         }
444 
445         if (includeInterfaces) {
446             for (itf in interfaceTypes()) {
447                 val cls = itf.asClass() ?: continue
448                 cls.findMethodByDesc(name, desc, includeSuperClasses, true)?.let { return it }
449             }
450         }
451         return null
452     }
453 
454     fun findConstructor(template: ConstructorItem): ConstructorItem? {
455         constructors().asSequence()
456             .filter { it.matches(template) }
457             .forEach { return it }
458         return null
459     }
460 
461     fun findField(
462         fieldName: String,
463         includeSuperClasses: Boolean = false,
464         includeInterfaces: Boolean = false
465     ): FieldItem? {
466         val field = fields().firstOrNull { it.name() == fieldName }
467         if (field != null) {
468             return field
469         }
470 
471         if (includeSuperClasses) {
472             superClass()?.findField(fieldName, true, includeInterfaces)?.let { return it }
473         }
474 
475         if (includeInterfaces) {
476             for (itf in interfaceTypes()) {
477                 val cls = itf.asClass() ?: continue
478                 cls.findField(fieldName, includeSuperClasses, true)?.let { return it }
479             }
480         }
481         return null
482     }
483 
484     fun findMethod(methodName: String, parameters: String): MethodItem? {
485         if (methodName == simpleName()) {
486             // Constructor
487             constructors()
488                 .filter { parametersMatch(it, parameters) }
489                 .forEach { return it }
490         } else {
491             methods()
492                 .filter { it.name() == methodName && parametersMatch(it, parameters) }
493                 .forEach { return it }
494         }
495 
496         return null
497     }
498 
499     private fun parametersMatch(method: MethodItem, description: String): Boolean {
500         val parameterStrings = Splitter.on(",").trimResults().omitEmptyStrings().splitToList(description)
501         val parameters = method.parameters()
502         if (parameters.size != parameterStrings.size) {
503             return false
504         }
505         for (i in 0 until parameters.size) {
506             var parameterString = parameterStrings[i]
507             val index = parameterString.indexOf('<')
508             if (index != -1) {
509                 parameterString = parameterString.substring(0, index)
510             }
511             val parameter = parameters[i].type().toErasedTypeString(method)
512             if (parameter != parameterString) {
513                 return false
514             }
515         }
516 
517         return true
518     }
519 
520     /** Returns the corresponding compilation unit, if any */
521     fun getCompilationUnit(): CompilationUnit? = null
522 
523     /** If this class is an annotation type, returns the retention of this class */
524     fun getRetention(): AnnotationRetention
525 
526     /**
527      * Return superclass matching the given predicate. When a superclass doesn't
528      * match, we'll keep crawling up the tree until we find someone who matches.
529      */
530     fun filteredSuperclass(predicate: Predicate<Item>): ClassItem? {
531         val superClass = superClass() ?: return null
532         return if (predicate.test(superClass)) {
533             superClass
534         } else {
535             superClass.filteredSuperclass(predicate)
536         }
537     }
538 
539     fun filteredSuperClassType(predicate: Predicate<Item>): TypeItem? {
540         var superClassType: TypeItem? = superClassType() ?: return null
541         var prev: ClassItem? = null
542         while (superClassType != null) {
543             val superClass = superClassType.asClass() ?: return null
544             if (predicate.test(superClass)) {
545                 if (prev == null || superClass == superClass()) {
546                     // Direct reference; no need to map type variables
547                     return superClassType
548                 }
549                 if (!superClassType.hasTypeArguments()) {
550                     // No type variables - also no need for mapping
551                     return superClassType
552                 }
553 
554                 return superClassType.convertType(this, prev)
555             }
556 
557             prev = superClass
558             superClassType = superClass.superClassType()
559         }
560 
561         return null
562     }
563 
564     /**
565      * Return methods matching the given predicate. Forcibly includes local
566      * methods that override a matching method in an ancestor class.
567      */
568     fun filteredMethods(predicate: Predicate<Item>): Collection<MethodItem> {
569         val methods = LinkedHashSet<MethodItem>()
570         for (method in methods()) {
571             if (predicate.test(method) || method.findPredicateSuperMethod(predicate) != null) {
572                 // val duplicated = method.duplicate(this)
573                 // methods.add(duplicated)
574                 methods.remove(method)
575                 methods.add(method)
576             }
577         }
578         return methods
579     }
580 
581     /** Returns the constructors that match the given predicate */
582     fun filteredConstructors(predicate: Predicate<Item>): Sequence<ConstructorItem> {
583         return constructors().asSequence().filter { predicate.test(it) }
584     }
585 
586     /**
587      * Return fields matching the given predicate. Also clones fields from
588      * ancestors that would match had they been defined in this class.
589      */
590     fun filteredFields(predicate: Predicate<Item>, showUnannotated: Boolean): List<FieldItem> {
591         val fields = LinkedHashSet<FieldItem>()
592         if (showUnannotated) {
593             for (clazz in allInterfaces()) {
594                 if (!clazz.isInterface()) {
595                     continue
596                 }
597                 for (field in clazz.fields()) {
598                     if (!predicate.test(field)) {
599                         val duplicated = field.duplicate(this)
600                         if (predicate.test(duplicated)) {
601                             fields.remove(duplicated)
602                             fields.add(duplicated)
603                         }
604                     }
605                 }
606             }
607 
608             val superClass = superClass()
609             if (superClass != null && !predicate.test(superClass) && predicate.test(this)) {
610                 // Include constants from hidden super classes.
611                 for (field in superClass.fields()) {
612                     val fieldModifiers = field.modifiers
613                     if (!fieldModifiers.isStatic() || !fieldModifiers.isFinal() || !fieldModifiers.isPublic()) {
614                         continue
615                     }
616                     if (!field.originallyHidden) {
617                         val duplicated = field.duplicate(this)
618                         if (predicate.test(duplicated)) {
619                             duplicated.inheritedField = true
620                             fields.remove(duplicated)
621                             fields.add(duplicated)
622                         }
623                     }
624                 }
625             }
626         }
627         for (field in fields()) {
628             if (predicate.test(field)) {
629                 fields.remove(field)
630                 fields.add(field)
631             }
632         }
633         if (fields.isEmpty()) {
634             return emptyList()
635         }
636         val list = fields.toMutableList()
637         list.sortWith(FieldItem.comparator)
638         return list
639     }
640 
641     fun filteredInterfaceTypes(predicate: Predicate<Item>): Collection<TypeItem> {
642         val interfaceTypes = filteredInterfaceTypes(
643             predicate, LinkedHashSet(),
644             includeSelf = false, includeParents = false, target = this
645         )
646         if (interfaceTypes.isEmpty()) {
647             return interfaceTypes
648         }
649 
650         return interfaceTypes
651     }
652 
653     fun allInterfaceTypes(predicate: Predicate<Item>): Collection<TypeItem> {
654         val interfaceTypes = filteredInterfaceTypes(
655             predicate, LinkedHashSet(),
656             includeSelf = false, includeParents = true, target = this
657         )
658         if (interfaceTypes.isEmpty()) {
659             return interfaceTypes
660         }
661 
662         return interfaceTypes
663     }
664 
665     private fun filteredInterfaceTypes(
666         predicate: Predicate<Item>,
667         types: LinkedHashSet<TypeItem>,
668         includeSelf: Boolean,
669         includeParents: Boolean,
670         target: ClassItem
671     ): LinkedHashSet<TypeItem> {
672         val superClassType = superClassType()
673         if (superClassType != null) {
674             val superClass = superClassType.asClass()
675             if (superClass != null) {
676                 if (!predicate.test(superClass)) {
677                     superClass.filteredInterfaceTypes(predicate, types, true, includeParents, target)
678                 } else if (includeSelf && superClass.isInterface()) {
679                     types.add(superClassType)
680                     if (includeParents) {
681                         superClass.filteredInterfaceTypes(predicate, types, true, includeParents, target)
682                     }
683                 }
684             }
685         }
686         for (type in interfaceTypes()) {
687             val cls = type.asClass() ?: continue
688             if (predicate.test(cls)) {
689                 if (hasTypeVariables() && type.hasTypeArguments()) {
690                     val replacementMap = target.mapTypeVariables(this)
691                     if (replacementMap.isNotEmpty()) {
692                         val mapped = type.convertType(replacementMap)
693                         types.add(mapped)
694                         continue
695                     }
696                 }
697                 types.add(type)
698                 if (includeParents) {
699                     cls.filteredInterfaceTypes(predicate, types, true, includeParents, target)
700                 }
701             } else {
702                 cls.filteredInterfaceTypes(predicate, types, true, includeParents, target)
703             }
704         }
705         return types
706     }
707 
708     fun allInnerClasses(includeSelf: Boolean = false): Sequence<ClassItem> {
709         if (!includeSelf && innerClasses().isEmpty()) {
710             return emptySequence()
711         }
712 
713         val list = ArrayList<ClassItem>()
714         if (includeSelf) {
715             list.add(this)
716         }
717         addInnerClasses(list, this)
718         return list.asSequence()
719     }
720 
721     private fun addInnerClasses(list: MutableList<ClassItem>, cls: ClassItem) {
722         for (innerClass in cls.innerClasses()) {
723             list.add(innerClass)
724             addInnerClasses(list, innerClass)
725         }
726     }
727 
728     /**
729      * The default constructor to invoke on this class from subclasses; initially null
730      * but populated by [ApiAnalyzer.addConstructors]. (Note that in some cases
731      * [stubConstructor] may not be in [constructors], e.g. when we need to
732      * create a constructor to match a public parent class with a non-default constructor
733      * and the one in the code is not a match, e.g. is marked @hide etc.)
734      */
735     var stubConstructor: ConstructorItem?
736 
737     /**
738      * Creates a map of type variables from this class to the given target class.
739      * If class A<X,Y> extends B<X,Y>, and B is declared as class B<M,N>,
740      * this returns the map {"X"->"M", "Y"->"N"}. There could be multiple intermediate
741      * classes between this class and the target class, and in some cases we could
742      * be substituting in a concrete class, e.g. class MyClass extends B<String,Number>
743      * would return the map {"java.lang.String"->"M", "java.lang.Number"->"N"}.
744      *
745      * If [reverse] is true, compute the reverse map: keys are the variables in
746      * the target and the values are the variables in the source.
747      */
748     fun mapTypeVariables(target: ClassItem): Map<String, String> = codebase.unsupported()
749 
750     /**
751      * Creates a constructor in this class
752      */
753     fun createDefaultConstructor(): ConstructorItem = codebase.unsupported()
754 
755     /**
756      * Creates a method corresponding to the given method signature in this class
757      */
758     fun createMethod(template: MethodItem): MethodItem = codebase.unsupported()
759 
760     fun addMethod(method: MethodItem): Unit = codebase.unsupported()
761 }
762 
763 class VisitCandidate(val cls: ClassItem, private val visitor: ApiVisitor) {
764     public val innerClasses: Sequence<VisitCandidate>
765     private val constructors: Sequence<MethodItem>
766     private val methods: Sequence<MethodItem>
767     private val fields: Sequence<FieldItem>
768     private val enums: Sequence<FieldItem>
769     private val properties: Sequence<PropertyItem>
770 
771     init {
772         val filterEmit = visitor.filterEmit
773 
774         constructors = cls.constructors().asSequence()
<lambda>null775             .filter { filterEmit.test(it) }
776             .sortedWith(MethodItem.comparator)
777 
778         methods = cls.methods().asSequence()
<lambda>null779             .filter { filterEmit.test(it) }
780             .sortedWith(MethodItem.comparator)
781 
782         val fieldSequence =
783             if (visitor.inlineInheritedFields) {
784                 cls.filteredFields(filterEmit, visitor.showUnannotated).asSequence()
785             } else {
786                 cls.fields().asSequence()
<lambda>null787                     .filter { filterEmit.test(it) }
788             }
789         if (cls.isEnum()) {
790             fields = fieldSequence
<lambda>null791                 .filter { !it.isEnumConstant() }
792                 .sortedWith(FieldItem.comparator)
793             enums = fieldSequence
<lambda>null794                 .filter { it.isEnumConstant() }
<lambda>null795                 .filter { filterEmit.test(it) }
796                 .sortedWith(FieldItem.comparator)
797         } else {
798             fields = fieldSequence.sortedWith(FieldItem.comparator)
799             enums = emptySequence()
800         }
801 
802         properties = if (cls.properties().isEmpty()) {
803             emptySequence()
804         } else {
805             cls.properties().asSequence()
<lambda>null806                 .filter { filterEmit.test(it) }
807                 .sortedWith(PropertyItem.comparator)
808         }
809 
810         innerClasses = cls.innerClasses()
811             .asSequence()
812             .sortedWith(ClassItem.classNameSorter())
<lambda>null813             .map { VisitCandidate(it, visitor) }
814     }
815 
816     /** Whether the class body contains any Item's (other than inner Classes) */
nonEmptynull817     public fun nonEmpty(): Boolean {
818         return !(constructors.none() && methods.none() && enums.none() && fields.none() && properties.none())
819     }
820 
acceptnull821     fun accept() {
822         if (!visitor.include(this)) {
823             return
824         }
825 
826         val emitThis = visitor.shouldEmitClass(this)
827         if (emitThis) {
828             if (!visitor.visitingPackage) {
829                 visitor.visitingPackage = true
830                 val pkg = cls.containingPackage()
831                 visitor.visitItem(pkg)
832                 visitor.visitPackage(pkg)
833             }
834 
835             visitor.visitItem(cls)
836             visitor.visitClass(cls)
837 
838             val sortedConstructors = if (visitor.methodComparator != null) {
839                 constructors.sortedWith(visitor.methodComparator)
840             } else {
841                 constructors
842             }
843             val sortedMethods = if (visitor.methodComparator != null) {
844                 methods.sortedWith(visitor.methodComparator)
845             } else {
846                 methods
847             }
848             val sortedFields = if (visitor.fieldComparator != null) {
849                 fields.sortedWith(visitor.fieldComparator)
850             } else {
851                 fields
852             }
853 
854             for (constructor in sortedConstructors) {
855                 constructor.accept(visitor)
856             }
857 
858             for (method in sortedMethods) {
859                 method.accept(visitor)
860             }
861 
862             for (property in properties) {
863                 property.accept(visitor)
864             }
865             for (enumConstant in enums) {
866                 enumConstant.accept(visitor)
867             }
868             for (field in sortedFields) {
869                 field.accept(visitor)
870             }
871         }
872 
873         if (visitor.nestInnerClasses) { // otherwise done below
874             innerClasses.forEach { it.accept() }
875         }
876 
877         if (emitThis) {
878             visitor.afterVisitClass(cls)
879             visitor.afterVisitItem(cls)
880         }
881 
882         if (!visitor.nestInnerClasses) {
883             innerClasses.forEach { it.accept() }
884         }
885     }
886 }
887