/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.tools.metalava.model

import com.android.SdkConstants
import com.android.tools.metalava.ApiAnalyzer
import com.android.tools.metalava.JAVA_LANG_ANNOTATION
import com.android.tools.metalava.JAVA_LANG_ENUM
import com.android.tools.metalava.JAVA_LANG_OBJECT
import com.android.tools.metalava.model.visitors.ApiVisitor
import com.android.tools.metalava.model.visitors.ItemVisitor
import com.android.tools.metalava.model.visitors.TypeVisitor
import com.google.common.base.Splitter
import java.util.ArrayList
import java.util.LinkedHashSet
import java.util.function.Predicate

interface ClassItem : Item {
    /** The simple name of a class. In class foo.bar.Outer.Inner, the simple name is "Inner" */
    fun simpleName(): String

    /** The full name of a class. In class foo.bar.Outer.Inner, the full name is "Outer.Inner" */
    fun fullName(): String

    /** The qualified name of a class. In class foo.bar.Outer.Inner, the qualified name is the whole thing. */
    fun qualifiedName(): String

    /** Is the class explicitly defined in the source file? */
    fun isDefined(): Boolean

    /** Is this an innerclass? */
    fun isInnerClass(): Boolean = containingClass() != null

    /** Is this a top level class? */
    fun isTopLevelClass(): Boolean = containingClass() == null

    /** This [ClassItem] and all of its inner classes, recursively */
    fun allClasses(): Sequence<ClassItem> {
        return sequenceOf(this).plus(innerClasses().asSequence().flatMap { it.allClasses() })
    }

    override fun parent(): Item? = containingClass() ?: containingPackage()

    /**
     * The qualified name where inner classes use $ as a separator.
     * In class foo.bar.Outer.Inner, this method will return foo.bar.Outer$Inner.
     * (This is the name format used in ProGuard keep files for example.)
     */
    fun qualifiedNameWithDollarInnerClasses(): String {
        var curr: ClassItem? = this
        while (curr?.containingClass() != null) {
            curr = curr.containingClass()
        }

        if (curr == null) {
            return fullName().replace('.', '$')
        }

        return curr.containingPackage().qualifiedName() + "." + fullName().replace('.', '$')
    }

    /** Returns the internal name of the class, as seen in bytecode */
    fun internalName(): String {
        var curr: ClassItem? = this
        while (curr?.containingClass() != null) {
            curr = curr.containingClass()
        }

        if (curr == null) {
            return fullName().replace('.', '$')
        }

        return curr.containingPackage().qualifiedName().replace('.', '/') + "/" +
            fullName().replace('.', '$')
    }

    /** The super class of this class, if any  */
    fun superClass(): ClassItem?

    /** The super class type of this class, if any. The difference between this and [superClass] is
     * that the type reference can include type arguments; e.g. in "class MyList extends List<String>"
     * the super class is java.util.List and the super class type is java.util.List<java.lang.String>.
     * */
    fun superClassType(): TypeItem?

    /** Finds the public super class of this class, if any */
    fun publicSuperClass(): ClassItem? {
        var superClass = superClass()
        while (superClass != null && !superClass.checkLevel()) {
            superClass = superClass.superClass()
        }

        return superClass
    }

    /** Returns true if this class extends the given class (includes self) */
    fun extends(qualifiedName: String): Boolean {
        if (qualifiedName() == qualifiedName) {
            return true
        }

        val superClass = superClass()
        return superClass?.extends(qualifiedName) ?: when {
            isEnum() -> qualifiedName == JAVA_LANG_ENUM
            isAnnotationType() -> qualifiedName == JAVA_LANG_ANNOTATION
            else -> qualifiedName == JAVA_LANG_OBJECT
        }
    }

    /** Returns true if this class implements the given interface (includes self) */
    fun implements(qualifiedName: String): Boolean {
        if (qualifiedName() == qualifiedName) {
            return true
        }

        interfaceTypes().forEach {
            val cls = it.asClass()
            if (cls != null && cls.implements(qualifiedName)) {
                return true
            }
        }

        // Might be implementing via superclass
        if (superClass()?.implements(qualifiedName) == true) {
            return true
        }

        return false
    }

    /** Returns true if this class extends or implements the given class or interface */
    fun extendsOrImplements(qualifiedName: String): Boolean = extends(qualifiedName) || implements(qualifiedName)

    /** Any interfaces implemented by this class */
    fun interfaceTypes(): List<TypeItem>

    /** All classes and interfaces implemented (by this class and its super classes and the interfaces themselves) */
    fun allInterfaces(): Sequence<ClassItem>

    /** Any inner classes of this class */
    fun innerClasses(): List<ClassItem>

    /** The constructors in this class */
    fun constructors(): List<ConstructorItem>

    /** Whether this class has an implicit default constructor */
    fun hasImplicitDefaultConstructor(): Boolean

    /** The non-constructor methods in this class */
    fun methods(): List<MethodItem>

    /** The properties in this class */
    fun properties(): List<PropertyItem>

    /** The fields in this class */
    fun fields(): List<FieldItem>

    /** The members in this class: constructors, methods, fields/enum constants */
    fun members(): Sequence<MemberItem> {
        return fields().asSequence().plus(constructors().asSequence()).plus(methods().asSequence())
    }

    /** Whether this class is an interface */
    fun isInterface(): Boolean

    /** Whether this class is an annotation type */
    fun isAnnotationType(): Boolean

    /** Whether this class is an enum */
    fun isEnum(): Boolean

    /** Whether this class is a regular class (not an interface, not an enum, etc) */
    fun isClass(): Boolean = !isInterface() && !isAnnotationType() && !isEnum()

    /** The containing class, for inner classes */
    fun containingClass(): ClassItem?

    /** The containing package */
    fun containingPackage(): PackageItem

    override fun containingPackage(strict: Boolean): PackageItem = containingPackage()

    override fun containingClass(strict: Boolean): ClassItem? {
        return if (strict) containingClass() else this
    }

    /** Gets the type for this class */
    fun toType(): TypeItem

    override fun type(): TypeItem? = null

    /** Returns true if this class has type parameters */
    fun hasTypeVariables(): Boolean

    /** Any type parameters for the class, if any, as a source string (with fully qualified class names) */
    fun typeParameterList(): TypeParameterList

    /** Returns the classes that are part of the type parameters of this method, if any */
    fun typeArgumentClasses(): List<ClassItem> = TODO("Not yet implemented")

    fun isJavaLangObject(): Boolean {
        return qualifiedName() == JAVA_LANG_OBJECT
    }

    // Mutation APIs: Used to "fix up" the API hierarchy (in [ApiAnalyzer]) to only expose
    // visible parts of the API)

    // This replaces the "real" super class
    fun setSuperClass(superClass: ClassItem?, superClassType: TypeItem? = superClass?.toType())

    // This replaces the interface types implemented by this class
    fun setInterfaceTypes(interfaceTypes: List<TypeItem>)

    val isTypeParameter: Boolean

    var hasPrivateConstructor: Boolean

    /** If true, this is an invisible element that was referenced by a public API. */
    var notStrippable: Boolean

    /**
     * Maven artifact of this class, if any. (Not used for the Android SDK, but used in
     * for example support libraries.
     */
    var artifact: String?

    override fun accept(visitor: ItemVisitor) {
        if (visitor is ApiVisitor) {
            accept(visitor)
            return
        }

        if (visitor.skip(this)) {
            return
        }

        visitor.visitItem(this)
        visitor.visitClass(this)

        for (constructor in constructors()) {
            constructor.accept(visitor)
        }

        for (method in methods()) {
            method.accept(visitor)
        }

        for (property in properties()) {
            property.accept(visitor)
        }

        if (isEnum()) {
            // In enums, visit the enum constants first, then the fields
            for (field in fields()) {
                if (field.isEnumConstant()) {
                    field.accept(visitor)
                }
            }
            for (field in fields()) {
                if (!field.isEnumConstant()) {
                    field.accept(visitor)
                }
            }
        } else {
            for (field in fields()) {
                field.accept(visitor)
            }
        }

        if (visitor.nestInnerClasses) {
            for (cls in innerClasses()) {
                cls.accept(visitor)
            }
        } // otherwise done below

        visitor.afterVisitClass(this)
        visitor.afterVisitItem(this)

        if (!visitor.nestInnerClasses) {
            for (cls in innerClasses()) {
                cls.accept(visitor)
            }
        }
    }

    fun accept(visitor: ApiVisitor) {

        if (!visitor.include(this)) {
            return
        }

        // We build up a separate data structure such that we can compute the
        // sets of fields, methods, etc even for inner classes (recursively); that way
        // we can easily and up front determine whether we have any matches for
        // inner classes (which is vital for computing the removed-api for example, where
        // only something like the appearance of a removed method inside an inner class
        // results in the outer class being described in the signature file.
        val candidate = VisitCandidate(this, visitor)
        candidate.accept()
    }

    override fun acceptTypes(visitor: TypeVisitor) {
        if (visitor.skip(this)) {
            return
        }

        val type = toType()
        visitor.visitType(type, this)

        // TODO: Visit type parameter list (at least the bounds types, e.g. View in <T extends View>
        superClass()?.let {
            visitor.visitType(it.toType(), it)
        }

        if (visitor.includeInterfaces) {
            for (itf in interfaceTypes()) {
                val owner = itf.asClass()
                owner?.let { visitor.visitType(itf, it) }
            }
        }

        for (constructor in constructors()) {
            constructor.acceptTypes(visitor)
        }
        for (field in fields()) {
            field.acceptTypes(visitor)
        }
        for (method in methods()) {
            method.acceptTypes(visitor)
        }
        for (cls in innerClasses()) {
            cls.acceptTypes(visitor)
        }

        visitor.afterVisitType(type, this)
    }

    companion object {
        /** Looks up the retention policy for the given class */
        fun findRetention(cls: ClassItem): AnnotationRetention {
            val modifiers = cls.modifiers
            val annotation = modifiers.findAnnotation("java.lang.annotation.Retention")
                ?: modifiers.findAnnotation("kotlin.annotation.Retention")
            val value = annotation?.findAttribute(SdkConstants.ATTR_VALUE)
            val source = value?.value?.toSource()
            return when {
                source == null -> AnnotationRetention.CLASS // default
                source.contains("RUNTIME") -> AnnotationRetention.RUNTIME
                source.contains("SOURCE") -> AnnotationRetention.SOURCE
                else -> AnnotationRetention.CLASS // default
            }
        }

        // Same as doclava1 (modulo the new handling when class names match)
        val comparator: Comparator<in ClassItem> = Comparator { o1, o2 ->
            val delta = o1.fullName().compareTo(o2.fullName())
            if (delta == 0) {
                o1.qualifiedName().compareTo(o2.qualifiedName())
            } else {
                delta
            }
        }

        val nameComparator: Comparator<ClassItem> = Comparator { a, b ->
            a.simpleName().compareTo(b.simpleName())
        }

        val fullNameComparator: Comparator<ClassItem> = Comparator { a, b -> a.fullName().compareTo(b.fullName()) }

        val qualifiedComparator: Comparator<ClassItem> = Comparator { a, b ->
            a.qualifiedName().compareTo(b.qualifiedName())
        }

        fun classNameSorter(): Comparator<in ClassItem> = ClassItem.qualifiedComparator
    }

    fun findMethod(
        template: MethodItem,
        includeSuperClasses: Boolean = false,
        includeInterfaces: Boolean = false
    ): MethodItem? {
        if (template.isConstructor()) {
            return findConstructor(template as ConstructorItem)
        }

        methods().asSequence()
            .filter { it.matches(template) }
            .forEach { return it }

        if (includeSuperClasses) {
            superClass()?.findMethod(template, true, includeInterfaces)?.let { return it }
        }

        if (includeInterfaces) {
            for (itf in interfaceTypes()) {
                val cls = itf.asClass() ?: continue
                cls.findMethod(template, includeSuperClasses, true)?.let { return it }
            }
        }
        return null
    }

    /** Finds a given method in this class matching the VM name signature */
    fun findMethodByDesc(
        name: String,
        desc: String,
        includeSuperClasses: Boolean = false,
        includeInterfaces: Boolean = false
    ): MethodItem? {
        if (desc.startsWith("<init>")) {
            constructors().asSequence()
                .filter { it.internalDesc() == desc }
                .forEach { return it }
            return null
        } else {
            methods().asSequence()
                .filter { it.name() == name && it.internalDesc() == desc }
                .forEach { return it }
        }

        if (includeSuperClasses) {
            superClass()?.findMethodByDesc(name, desc, true, includeInterfaces)?.let { return it }
        }

        if (includeInterfaces) {
            for (itf in interfaceTypes()) {
                val cls = itf.asClass() ?: continue
                cls.findMethodByDesc(name, desc, includeSuperClasses, true)?.let { return it }
            }
        }
        return null
    }

    fun findConstructor(template: ConstructorItem): ConstructorItem? {
        constructors().asSequence()
            .filter { it.matches(template) }
            .forEach { return it }
        return null
    }

    fun findField(
        fieldName: String,
        includeSuperClasses: Boolean = false,
        includeInterfaces: Boolean = false
    ): FieldItem? {
        val field = fields().firstOrNull { it.name() == fieldName }
        if (field != null) {
            return field
        }

        if (includeSuperClasses) {
            superClass()?.findField(fieldName, true, includeInterfaces)?.let { return it }
        }

        if (includeInterfaces) {
            for (itf in interfaceTypes()) {
                val cls = itf.asClass() ?: continue
                cls.findField(fieldName, includeSuperClasses, true)?.let { return it }
            }
        }
        return null
    }

    fun findMethod(methodName: String, parameters: String): MethodItem? {
        if (methodName == simpleName()) {
            // Constructor
            constructors()
                .filter { parametersMatch(it, parameters) }
                .forEach { return it }
        } else {
            methods()
                .filter { it.name() == methodName && parametersMatch(it, parameters) }
                .forEach { return it }
        }

        return null
    }

    private fun parametersMatch(method: MethodItem, description: String): Boolean {
        val parameterStrings = Splitter.on(",").trimResults().omitEmptyStrings().splitToList(description)
        val parameters = method.parameters()
        if (parameters.size != parameterStrings.size) {
            return false
        }
        for (i in 0 until parameters.size) {
            var parameterString = parameterStrings[i]
            val index = parameterString.indexOf('<')
            if (index != -1) {
                parameterString = parameterString.substring(0, index)
            }
            val parameter = parameters[i].type().toErasedTypeString(method)
            if (parameter != parameterString) {
                return false
            }
        }

        return true
    }

    /** Returns the corresponding compilation unit, if any */
    fun getCompilationUnit(): CompilationUnit? = null

    /** If this class is an annotation type, returns the retention of this class */
    fun getRetention(): AnnotationRetention

    /**
     * Return superclass matching the given predicate. When a superclass doesn't
     * match, we'll keep crawling up the tree until we find someone who matches.
     */
    fun filteredSuperclass(predicate: Predicate<Item>): ClassItem? {
        val superClass = superClass() ?: return null
        return if (predicate.test(superClass)) {
            superClass
        } else {
            superClass.filteredSuperclass(predicate)
        }
    }

    fun filteredSuperClassType(predicate: Predicate<Item>): TypeItem? {
        var superClassType: TypeItem? = superClassType() ?: return null
        var prev: ClassItem? = null
        while (superClassType != null) {
            val superClass = superClassType.asClass() ?: return null
            if (predicate.test(superClass)) {
                if (prev == null || superClass == superClass()) {
                    // Direct reference; no need to map type variables
                    return superClassType
                }
                if (!superClassType.hasTypeArguments()) {
                    // No type variables - also no need for mapping
                    return superClassType
                }

                return superClassType.convertType(this, prev)
            }

            prev = superClass
            superClassType = superClass.superClassType()
        }

        return null
    }

    /**
     * Return methods matching the given predicate. Forcibly includes local
     * methods that override a matching method in an ancestor class.
     */
    fun filteredMethods(predicate: Predicate<Item>): Collection<MethodItem> {
        val methods = LinkedHashSet<MethodItem>()
        for (method in methods()) {
            if (predicate.test(method) || method.findPredicateSuperMethod(predicate) != null) {
                // val duplicated = method.duplicate(this)
                // methods.add(duplicated)
                methods.remove(method)
                methods.add(method)
            }
        }
        return methods
    }

    /** Returns the constructors that match the given predicate */
    fun filteredConstructors(predicate: Predicate<Item>): Sequence<ConstructorItem> {
        return constructors().asSequence().filter { predicate.test(it) }
    }

    /**
     * Return fields matching the given predicate. Also clones fields from
     * ancestors that would match had they been defined in this class.
     */
    fun filteredFields(predicate: Predicate<Item>, showUnannotated: Boolean): List<FieldItem> {
        val fields = LinkedHashSet<FieldItem>()
        if (showUnannotated) {
            for (clazz in allInterfaces()) {
                if (!clazz.isInterface()) {
                    continue
                }
                for (field in clazz.fields()) {
                    if (!predicate.test(field)) {
                        val duplicated = field.duplicate(this)
                        if (predicate.test(duplicated)) {
                            fields.remove(duplicated)
                            fields.add(duplicated)
                        }
                    }
                }
            }

            val superClass = superClass()
            if (superClass != null && !predicate.test(superClass) && predicate.test(this)) {
                // Include constants from hidden super classes.
                for (field in superClass.fields()) {
                    val fieldModifiers = field.modifiers
                    if (!fieldModifiers.isStatic() || !fieldModifiers.isFinal() || !fieldModifiers.isPublic()) {
                        continue
                    }
                    if (!field.originallyHidden) {
                        val duplicated = field.duplicate(this)
                        if (predicate.test(duplicated)) {
                            duplicated.inheritedField = true
                            fields.remove(duplicated)
                            fields.add(duplicated)
                        }
                    }
                }
            }
        }
        for (field in fields()) {
            if (predicate.test(field)) {
                fields.remove(field)
                fields.add(field)
            }
        }
        if (fields.isEmpty()) {
            return emptyList()
        }
        val list = fields.toMutableList()
        list.sortWith(FieldItem.comparator)
        return list
    }

    fun filteredInterfaceTypes(predicate: Predicate<Item>): Collection<TypeItem> {
        val interfaceTypes = filteredInterfaceTypes(
            predicate, LinkedHashSet(),
            includeSelf = false, includeParents = false, target = this
        )
        if (interfaceTypes.isEmpty()) {
            return interfaceTypes
        }

        return interfaceTypes
    }

    fun allInterfaceTypes(predicate: Predicate<Item>): Collection<TypeItem> {
        val interfaceTypes = filteredInterfaceTypes(
            predicate, LinkedHashSet(),
            includeSelf = false, includeParents = true, target = this
        )
        if (interfaceTypes.isEmpty()) {
            return interfaceTypes
        }

        return interfaceTypes
    }

    private fun filteredInterfaceTypes(
        predicate: Predicate<Item>,
        types: LinkedHashSet<TypeItem>,
        includeSelf: Boolean,
        includeParents: Boolean,
        target: ClassItem
    ): LinkedHashSet<TypeItem> {
        val superClassType = superClassType()
        if (superClassType != null) {
            val superClass = superClassType.asClass()
            if (superClass != null) {
                if (!predicate.test(superClass)) {
                    superClass.filteredInterfaceTypes(predicate, types, true, includeParents, target)
                } else if (includeSelf && superClass.isInterface()) {
                    types.add(superClassType)
                    if (includeParents) {
                        superClass.filteredInterfaceTypes(predicate, types, true, includeParents, target)
                    }
                }
            }
        }
        for (type in interfaceTypes()) {
            val cls = type.asClass() ?: continue
            if (predicate.test(cls)) {
                if (hasTypeVariables() && type.hasTypeArguments()) {
                    val replacementMap = target.mapTypeVariables(this)
                    if (replacementMap.isNotEmpty()) {
                        val mapped = type.convertType(replacementMap)
                        types.add(mapped)
                        continue
                    }
                }
                types.add(type)
                if (includeParents) {
                    cls.filteredInterfaceTypes(predicate, types, true, includeParents, target)
                }
            } else {
                cls.filteredInterfaceTypes(predicate, types, true, includeParents, target)
            }
        }
        return types
    }

    fun allInnerClasses(includeSelf: Boolean = false): Sequence<ClassItem> {
        if (!includeSelf && innerClasses().isEmpty()) {
            return emptySequence()
        }

        val list = ArrayList<ClassItem>()
        if (includeSelf) {
            list.add(this)
        }
        addInnerClasses(list, this)
        return list.asSequence()
    }

    private fun addInnerClasses(list: MutableList<ClassItem>, cls: ClassItem) {
        for (innerClass in cls.innerClasses()) {
            list.add(innerClass)
            addInnerClasses(list, innerClass)
        }
    }

    /**
     * The default constructor to invoke on this class from subclasses; initially null
     * but populated by [ApiAnalyzer.addConstructors]. (Note that in some cases
     * [defaultConstructor] may not be in [constructors], e.g. when we need to
     * create a constructor to match a public parent class with a non-default constructor
     * and the one in the code is not a match, e.g. is marked @hide etc.)
     */
    var defaultConstructor: ConstructorItem?

    /**
     * Creates a map of type variables from this class to the given target class.
     * If class A<X,Y> extends B<X,Y>, and B is declared as class B<M,N>,
     * this returns the map {"X"->"M", "Y"->"N"}. There could be multiple intermediate
     * classes between this class and the target class, and in some cases we could
     * be substituting in a concrete class, e.g. class MyClass extends B<String,Number>
     * would return the map {"java.lang.String"->"M", "java.lang.Number"->"N"}.
     *
     * If [reverse] is true, compute the reverse map: keys are the variables in
     * the target and the values are the variables in the source.
     */
    fun mapTypeVariables(target: ClassItem): Map<String, String> = codebase.unsupported()

    /**
     * Creates a constructor in this class
     */
    fun createDefaultConstructor(): ConstructorItem = codebase.unsupported()

    /**
     * Creates a method corresponding to the given method signature in this class
     */
    fun createMethod(template: MethodItem): MethodItem = codebase.unsupported()

    fun addMethod(method: MethodItem): Unit = codebase.unsupported()
}

class VisitCandidate(val cls: ClassItem, private val visitor: ApiVisitor) {
    public val innerClasses: Sequence<VisitCandidate>
    private val constructors: Sequence<MethodItem>
    private val methods: Sequence<MethodItem>
    private val fields: Sequence<FieldItem>
    private val enums: Sequence<FieldItem>
    private val properties: Sequence<PropertyItem>

    init {
        val filterEmit = visitor.filterEmit

        constructors = cls.constructors().asSequence()
            .filter { filterEmit.test(it) }
            .sortedWith(MethodItem.comparator)

        methods = cls.methods().asSequence()
            .filter { filterEmit.test(it) }
            .sortedWith(MethodItem.comparator)

        val fieldSequence =
            if (visitor.inlineInheritedFields) {
                cls.filteredFields(filterEmit, visitor.showUnannotated).asSequence()
            } else {
                cls.fields().asSequence()
                    .filter { filterEmit.test(it) }
            }
        if (cls.isEnum()) {
            fields = fieldSequence
                .filter { !it.isEnumConstant() }
                .sortedWith(FieldItem.comparator)
            enums = fieldSequence
                .filter { it.isEnumConstant() }
                .filter { filterEmit.test(it) }
                .sortedWith(FieldItem.comparator)
        } else {
            fields = fieldSequence.sortedWith(FieldItem.comparator)
            enums = emptySequence()
        }

        properties = if (cls.properties().isEmpty()) {
            emptySequence()
        } else {
            cls.properties().asSequence()
                .filter { filterEmit.test(it) }
                .sortedWith(PropertyItem.comparator)
        }

        innerClasses = cls.innerClasses()
            .asSequence()
            .sortedWith(ClassItem.classNameSorter())
            .map { VisitCandidate(it, visitor) }
    }

    /** Whether the class body contains any Item's (other than inner Classes) */
    public fun nonEmpty(): Boolean {
        return !(constructors.none() && methods.none() && enums.none() && fields.none() && properties.none())
    }

    fun accept() {
        if (!visitor.include(this)) {
            return
        }

        val emitThis = visitor.shouldEmitClass(this)
        if (emitThis) {
            if (!visitor.visitingPackage) {
                visitor.visitingPackage = true
                val pkg = cls.containingPackage()
                visitor.visitItem(pkg)
                visitor.visitPackage(pkg)
            }

            visitor.visitItem(cls)
            visitor.visitClass(cls)

            val sortedConstructors = if (visitor.methodComparator != null) {
                constructors.sortedWith(visitor.methodComparator)
            } else {
                constructors
            }
            val sortedMethods = if (visitor.methodComparator != null) {
                methods.sortedWith(visitor.methodComparator)
            } else {
                methods
            }
            val sortedFields = if (visitor.fieldComparator != null) {
                fields.sortedWith(visitor.fieldComparator)
            } else {
                fields
            }

            for (constructor in sortedConstructors) {
                constructor.accept(visitor)
            }

            for (method in sortedMethods) {
                method.accept(visitor)
            }

            for (property in properties) {
                property.accept(visitor)
            }
            for (enumConstant in enums) {
                enumConstant.accept(visitor)
            }
            for (field in sortedFields) {
                field.accept(visitor)
            }
        }

        if (visitor.nestInnerClasses) { // otherwise done below
            innerClasses.forEach { it.accept() }
        }

        if (emitThis) {
            visitor.afterVisitClass(cls)
            visitor.afterVisitItem(cls)
        }

        if (!visitor.nestInnerClasses) {
            innerClasses.forEach { it.accept() }
        }
    }
}
