// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;

import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.kotlin.KotlinInfo;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.base.MoreObjects;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.collect.Sets;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;

public abstract class DexClass extends DexDefinition {

  public interface FieldSetter {
    void setField(int index, DexEncodedField field);
  }

  public interface MethodSetter {
    void setMethod(int index, DexEncodedMethod method);
  }

  private Optional<DexEncodedMethod> cachedClassInitializer = null;

  public final Origin origin;
  public DexType type;
  public final ClassAccessFlags accessFlags;
  public DexType superType;
  public DexTypeList interfaces;
  public DexString sourceFile;

  /** Access has to be synchronized during concurrent collection/writing phase. */
  protected DexEncodedField[] staticFields = DexEncodedField.EMPTY_ARRAY;

  /** Access has to be synchronized during concurrent collection/writing phase. */
  protected DexEncodedField[] instanceFields = DexEncodedField.EMPTY_ARRAY;

  /** Access has to be synchronized during concurrent collection/writing phase. */
  protected DexEncodedMethod[] directMethods = DexEncodedMethod.EMPTY_ARRAY;

  /** Access has to be synchronized during concurrent collection/writing phase. */
  protected DexEncodedMethod[] virtualMethods = DexEncodedMethod.EMPTY_ARRAY;

  /** Enclosing context of this class if it is an inner class, null otherwise. */
  private EnclosingMethodAttribute enclosingMethod;

  /** InnerClasses table. If this class is an inner class, it will have an entry here. */
  private final List<InnerClassAttribute> innerClasses;

  private final NestHostClassAttribute nestHost;
  private final List<NestMemberClassAttribute> nestMembers;

  public DexAnnotationSet annotations;

  public DexClass(
      DexString sourceFile,
      DexTypeList interfaces,
      ClassAccessFlags accessFlags,
      DexType superType,
      DexType type,
      DexEncodedField[] staticFields,
      DexEncodedField[] instanceFields,
      DexEncodedMethod[] directMethods,
      DexEncodedMethod[] virtualMethods,
      NestHostClassAttribute nestHost,
      List<NestMemberClassAttribute> nestMembers,
      EnclosingMethodAttribute enclosingMethod,
      List<InnerClassAttribute> innerClasses,
      DexAnnotationSet annotations,
      Origin origin,
      boolean skipNameValidationForTesting) {
    assert origin != null;
    this.origin = origin;
    this.sourceFile = sourceFile;
    this.interfaces = interfaces;
    this.accessFlags = accessFlags;
    this.superType = superType;
    this.type = type;
    setStaticFields(staticFields);
    setInstanceFields(instanceFields);
    setDirectMethods(directMethods);
    setVirtualMethods(virtualMethods);
    this.nestHost = nestHost;
    this.nestMembers = nestMembers;
    assert nestMembers != null;
    this.enclosingMethod = enclosingMethod;
    this.innerClasses = innerClasses;
    this.annotations = annotations;
    if (type == superType) {
      throw new CompilationError("Class " + type.toString() + " cannot extend itself");
    }
    for (DexType interfaceType : interfaces.values) {
      if (type == interfaceType) {
        throw new CompilationError("Interface " + type.toString() + " cannot implement itself");
      }
    }
    if (!skipNameValidationForTesting && !type.descriptor.isValidClassDescriptor()) {
      throw new CompilationError(
          "Class descriptor '"
              + type.descriptor.toString()
              + "' cannot be represented in dex format.");
    }
  }

  public Iterable<DexEncodedField> fields() {
    return fields(Predicates.alwaysTrue());
  }

  public Iterable<DexEncodedField> fields(final Predicate<? super DexEncodedField> predicate) {
    return Iterables.concat(
        Iterables.filter(Arrays.asList(instanceFields), predicate::test),
        Iterables.filter(Arrays.asList(staticFields), predicate::test));
  }

  public Iterable<DexEncodedMethod> methods() {
    return methods(Predicates.alwaysTrue());
  }

  public Iterable<DexEncodedMethod> methods(Predicate<? super DexEncodedMethod> predicate) {
    return Iterables.concat(
        Iterables.filter(Arrays.asList(directMethods), predicate::test),
        Iterables.filter(Arrays.asList(virtualMethods), predicate::test));
  }

  @Override
  void collectMixedSectionItems(MixedSectionCollection mixedItems) {
    throw new Unreachable();
  }

  public List<DexEncodedMethod> directMethods() {
    assert directMethods != null;
    if (InternalOptions.assertionsEnabled()) {
      return Collections.unmodifiableList(Arrays.asList(directMethods));
    }
    return Arrays.asList(directMethods);
  }

  public void appendDirectMethod(DexEncodedMethod method) {
    cachedClassInitializer = null;
    DexEncodedMethod[] newMethods = new DexEncodedMethod[directMethods.length + 1];
    System.arraycopy(directMethods, 0, newMethods, 0, directMethods.length);
    newMethods[directMethods.length] = method;
    directMethods = newMethods;
    assert verifyCorrectnessOfMethodHolder(method);
    assert verifyNoDuplicateMethods();
  }

  public void appendDirectMethods(Collection<DexEncodedMethod> methods) {
    cachedClassInitializer = null;
    DexEncodedMethod[] newMethods = new DexEncodedMethod[directMethods.length + methods.size()];
    System.arraycopy(directMethods, 0, newMethods, 0, directMethods.length);
    int i = directMethods.length;
    for (DexEncodedMethod method : methods) {
      newMethods[i] = method;
      i++;
    }
    directMethods = newMethods;
    assert verifyCorrectnessOfMethodHolders(methods);
    assert verifyNoDuplicateMethods();
  }

  public void removeDirectMethod(int index) {
    cachedClassInitializer = null;
    DexEncodedMethod[] newMethods = new DexEncodedMethod[directMethods.length - 1];
    System.arraycopy(directMethods, 0, newMethods, 0, index);
    System.arraycopy(directMethods, index + 1, newMethods, index, directMethods.length - index - 1);
    directMethods = newMethods;
  }

  public void setDirectMethod(int index, DexEncodedMethod method) {
    cachedClassInitializer = null;
    directMethods[index] = method;
    assert verifyCorrectnessOfMethodHolder(method);
    assert verifyNoDuplicateMethods();
  }

  public void setDirectMethods(DexEncodedMethod[] methods) {
    cachedClassInitializer = null;
    directMethods = MoreObjects.firstNonNull(methods, DexEncodedMethod.EMPTY_ARRAY);
    assert verifyCorrectnessOfMethodHolders(directMethods());
    assert verifyNoDuplicateMethods();
  }

  public List<DexEncodedMethod> virtualMethods() {
    assert virtualMethods != null;
    if (InternalOptions.assertionsEnabled()) {
      return Collections.unmodifiableList(Arrays.asList(virtualMethods));
    }
    return Arrays.asList(virtualMethods);
  }

  public void appendVirtualMethod(DexEncodedMethod method) {
    DexEncodedMethod[] newMethods = new DexEncodedMethod[virtualMethods.length + 1];
    System.arraycopy(virtualMethods, 0, newMethods, 0, virtualMethods.length);
    newMethods[virtualMethods.length] = method;
    virtualMethods = newMethods;
    assert verifyCorrectnessOfMethodHolder(method);
    assert verifyNoDuplicateMethods();
  }

  public void appendVirtualMethods(Collection<DexEncodedMethod> methods) {
    DexEncodedMethod[] newMethods = new DexEncodedMethod[virtualMethods.length + methods.size()];
    System.arraycopy(virtualMethods, 0, newMethods, 0, virtualMethods.length);
    int i = virtualMethods.length;
    for (DexEncodedMethod method : methods) {
      newMethods[i] = method;
      i++;
    }
    virtualMethods = newMethods;
    assert verifyCorrectnessOfMethodHolders(methods);
    assert verifyNoDuplicateMethods();
  }

  public void removeVirtualMethod(int index) {
    DexEncodedMethod[] newMethods = new DexEncodedMethod[virtualMethods.length - 1];
    System.arraycopy(virtualMethods, 0, newMethods, 0, index);
    System.arraycopy(
        virtualMethods, index + 1, newMethods, index, virtualMethods.length - index - 1);
    virtualMethods = newMethods;
  }

  public void setVirtualMethod(int index, DexEncodedMethod method) {
    virtualMethods[index] = method;
    assert verifyCorrectnessOfMethodHolder(method);
    assert verifyNoDuplicateMethods();
  }

  public void setVirtualMethods(DexEncodedMethod[] methods) {
    virtualMethods = MoreObjects.firstNonNull(methods, DexEncodedMethod.EMPTY_ARRAY);
    assert verifyCorrectnessOfMethodHolders(virtualMethods());
    assert verifyNoDuplicateMethods();
  }

  private boolean verifyCorrectnessOfMethodHolder(DexEncodedMethod method) {
    assert method.method.holder == type
        : "Expected method `"
            + method.method.toSourceString()
            + "` to have holder `"
            + type.toSourceString()
            + "`";
    return true;
  }

  private boolean verifyCorrectnessOfMethodHolders(Iterable<DexEncodedMethod> methods) {
    for (DexEncodedMethod method : methods) {
      assert verifyCorrectnessOfMethodHolder(method);
    }
    return true;
  }

  private boolean verifyNoAbstractMethodsOnNonAbstractClasses(
      Iterable<DexEncodedMethod> methods, InternalOptions options) {
    if (options.canHaveDalvikAbstractMethodOnNonAbstractClassVerificationBug()) {
      if (!isAbstract()) {
        for (DexEncodedMethod method : methods) {
          assert !method.isAbstract()
              : "Non-abstract method on abstract class: `" + method.method.toSourceString() + "`";
        }
      }
    }
    return true;
  }

  private boolean verifyNoDuplicateMethods() {
    Set<DexMethod> unique = Sets.newIdentityHashSet();
    for (DexEncodedMethod method : methods()) {
      boolean changed = unique.add(method.method);
      assert changed : "Duplicate method `" + method.method.toSourceString() + "`";
    }
    return true;
  }

  public void forEachMethod(Consumer<DexEncodedMethod> consumer) {
    for (DexEncodedMethod method : directMethods()) {
      consumer.accept(method);
    }
    for (DexEncodedMethod method : virtualMethods()) {
      consumer.accept(method);
    }
  }

  public DexEncodedMethod[] allMethodsSorted() {
    int vLen = virtualMethods.length;
    int dLen = directMethods.length;
    DexEncodedMethod[] result = new DexEncodedMethod[vLen + dLen];
    System.arraycopy(virtualMethods, 0, result, 0, vLen);
    System.arraycopy(directMethods, 0, result, vLen, dLen);
    Arrays.sort(result,
        (DexEncodedMethod a, DexEncodedMethod b) -> a.method.slowCompareTo(b.method));
    return result;
  }

  public DexEncodedMethod[] directMethodsSorted() {
    DexEncodedMethod[] result = new DexEncodedMethod[directMethods.length];
    System.arraycopy(directMethods, 0, result, 0, directMethods.length);
    Arrays.sort(
        result, (DexEncodedMethod a, DexEncodedMethod b) -> a.method.slowCompareTo(b.method));
    return result;
  }

  public DexEncodedMethod[] virtualMethodsSorted() {
    DexEncodedMethod[] result = new DexEncodedMethod[virtualMethods.length];
    System.arraycopy(virtualMethods, 0, result, 0, virtualMethods.length);
    Arrays.sort(
        result, (DexEncodedMethod a, DexEncodedMethod b) -> a.method.slowCompareTo(b.method));
    return result;
  }

  public void virtualizeMethods(Set<DexEncodedMethod> privateInstanceMethods) {
    int vLen = virtualMethods.length;
    int dLen = directMethods.length;
    int mLen = privateInstanceMethods.size();
    assert mLen <= dLen;

    DexEncodedMethod[] newDirectMethods = new DexEncodedMethod[dLen - mLen];
    int index = 0;
    for (int i = 0; i < dLen; i++) {
      DexEncodedMethod encodedMethod = directMethods[i];
      if (!privateInstanceMethods.contains(encodedMethod)) {
        newDirectMethods[index++] = encodedMethod;
      }
    }
    assert index == dLen - mLen;
    setDirectMethods(newDirectMethods);

    DexEncodedMethod[] newVirtualMethods = new DexEncodedMethod[vLen + mLen];
    System.arraycopy(virtualMethods, 0, newVirtualMethods, 0, vLen);
    index = vLen;
    for (DexEncodedMethod encodedMethod : privateInstanceMethods) {
      newVirtualMethods[index++] = encodedMethod;
    }
    setVirtualMethods(newVirtualMethods);
  }

  /**
   * For all annotations on the class and all annotations on its methods and fields apply the
   * specified consumer.
   */
  public void forEachAnnotation(Consumer<DexAnnotation> consumer) {
    for (DexAnnotation annotation : annotations.annotations) {
      consumer.accept(annotation);
    }
    for (DexEncodedMethod method : directMethods()) {
      for (DexAnnotation annotation : method.annotations.annotations) {
        consumer.accept(annotation);
      }
      method.parameterAnnotationsList.forEachAnnotation(consumer);
    }
    for (DexEncodedMethod method : virtualMethods()) {
      for (DexAnnotation annotation : method.annotations.annotations) {
        consumer.accept(annotation);
      }
      method.parameterAnnotationsList.forEachAnnotation(consumer);
    }
    for (DexEncodedField field : instanceFields()) {
      for (DexAnnotation annotation : field.annotations.annotations) {
        consumer.accept(annotation);
      }
    }
    for (DexEncodedField field : staticFields()) {
      for (DexAnnotation annotation : field.annotations.annotations) {
        consumer.accept(annotation);
      }
    }
  }

  public void forEachField(Consumer<DexEncodedField> consumer) {
    for (DexEncodedField field : staticFields()) {
      consumer.accept(field);
    }
    for (DexEncodedField field : instanceFields()) {
      consumer.accept(field);
    }
  }

  public List<DexEncodedField> staticFields() {
    assert staticFields != null;
    if (InternalOptions.assertionsEnabled()) {
      return Collections.unmodifiableList(Arrays.asList(staticFields));
    }
    return Arrays.asList(staticFields);
  }

  public void appendStaticField(DexEncodedField field) {
    DexEncodedField[] newFields = new DexEncodedField[staticFields.length + 1];
    System.arraycopy(staticFields, 0, newFields, 0, staticFields.length);
    newFields[staticFields.length] = field;
    staticFields = newFields;
    assert verifyCorrectnessOfFieldHolder(field);
    assert verifyNoDuplicateFields();
  }

  public void appendStaticFields(Collection<DexEncodedField> fields) {
    DexEncodedField[] newFields = new DexEncodedField[staticFields.length + fields.size()];
    System.arraycopy(staticFields, 0, newFields, 0, staticFields.length);
    int i = staticFields.length;
    for (DexEncodedField field : fields) {
      newFields[i] = field;
      i++;
    }
    staticFields = newFields;
    assert verifyCorrectnessOfFieldHolders(fields);
    assert verifyNoDuplicateFields();
  }

  public void removeStaticField(int index) {
    DexEncodedField[] newFields = new DexEncodedField[staticFields.length - 1];
    System.arraycopy(staticFields, 0, newFields, 0, index);
    System.arraycopy(staticFields, index + 1, newFields, index, staticFields.length - index - 1);
    staticFields = newFields;
  }

  public void setStaticField(int index, DexEncodedField field) {
    staticFields[index] = field;
    assert verifyCorrectnessOfFieldHolder(field);
    assert verifyNoDuplicateFields();
  }

  public void setStaticFields(DexEncodedField[] fields) {
    staticFields = MoreObjects.firstNonNull(fields, DexEncodedField.EMPTY_ARRAY);
    assert verifyCorrectnessOfFieldHolders(staticFields());
    assert verifyNoDuplicateFields();
  }

  public boolean definesStaticField(DexField field) {
    for (DexEncodedField encodedField : staticFields()) {
      if (encodedField.field == field) {
        return true;
      }
    }
    return false;
  }

  public List<DexEncodedField> instanceFields() {
    assert instanceFields != null;
    if (InternalOptions.assertionsEnabled()) {
      return Collections.unmodifiableList(Arrays.asList(instanceFields));
    }
    return Arrays.asList(instanceFields);
  }

  public void appendInstanceField(DexEncodedField field) {
    DexEncodedField[] newFields = new DexEncodedField[instanceFields.length + 1];
    System.arraycopy(instanceFields, 0, newFields, 0, instanceFields.length);
    newFields[instanceFields.length] = field;
    instanceFields = newFields;
    assert verifyCorrectnessOfFieldHolder(field);
    assert verifyNoDuplicateFields();
  }

  public void appendInstanceFields(Collection<DexEncodedField> fields) {
    DexEncodedField[] newFields = new DexEncodedField[instanceFields.length + fields.size()];
    System.arraycopy(instanceFields, 0, newFields, 0, instanceFields.length);
    int i = instanceFields.length;
    for (DexEncodedField field : fields) {
      newFields[i] = field;
      i++;
    }
    instanceFields = newFields;
    assert verifyCorrectnessOfFieldHolders(fields);
    assert verifyNoDuplicateFields();
  }

  public void removeInstanceField(int index) {
    DexEncodedField[] newFields = new DexEncodedField[instanceFields.length - 1];
    System.arraycopy(instanceFields, 0, newFields, 0, index);
    System.arraycopy(
        instanceFields, index + 1, newFields, index, instanceFields.length - index - 1);
    instanceFields = newFields;
  }

  public void setInstanceField(int index, DexEncodedField field) {
    instanceFields[index] = field;
    assert verifyCorrectnessOfFieldHolder(field);
    assert verifyNoDuplicateFields();
  }

  public void setInstanceFields(DexEncodedField[] fields) {
    instanceFields = MoreObjects.firstNonNull(fields, DexEncodedField.EMPTY_ARRAY);
    assert verifyCorrectnessOfFieldHolders(instanceFields());
    assert verifyNoDuplicateFields();
  }

  private boolean verifyCorrectnessOfFieldHolder(DexEncodedField field) {
    assert field.field.holder == type
        : "Expected field `"
            + field.field.toSourceString()
            + "` to have holder `"
            + type.toSourceString()
            + "`";
    return true;
  }

  private boolean verifyCorrectnessOfFieldHolders(Iterable<DexEncodedField> fields) {
    for (DexEncodedField field : fields) {
      assert verifyCorrectnessOfFieldHolder(field);
    }
    return true;
  }

  private boolean verifyNoDuplicateFields() {
    Set<DexField> unique = Sets.newIdentityHashSet();
    for (DexEncodedField field : fields()) {
      boolean changed = unique.add(field.field);
      assert changed : "Duplicate field `" + field.field.toSourceString() + "`";
    }
    return true;
  }

  public DexEncodedField[] allFieldsSorted() {
    int iLen = instanceFields.length;
    int sLen = staticFields.length;
    DexEncodedField[] result = new DexEncodedField[iLen + sLen];
    System.arraycopy(instanceFields, 0, result, 0, iLen);
    System.arraycopy(staticFields, 0, result, iLen, sLen);
    Arrays.sort(result,
        (DexEncodedField a, DexEncodedField b) -> a.field.slowCompareTo(b.field));
    return result;
  }

  /**
   * Find static field in this class matching field
   */
  public DexEncodedField lookupStaticField(DexField field) {
    return lookupTarget(staticFields, field);
  }

  /**
   * Find instance field in this class matching field.
   */
  public DexEncodedField lookupInstanceField(DexField field) {
    return lookupTarget(instanceFields, field);
  }

  /**
   * Find field in this class matching field.
   */
  public DexEncodedField lookupField(DexField field) {
    DexEncodedField result = lookupInstanceField(field);
    return result == null ? lookupStaticField(field) : result;
  }

  /**
   * Find direct method in this class matching method.
   */
  public DexEncodedMethod lookupDirectMethod(DexMethod method) {
    return lookupTarget(directMethods, method);
  }

  /**
   * Find virtual method in this class matching method.
   */
  public DexEncodedMethod lookupVirtualMethod(DexMethod method) {
    return lookupTarget(virtualMethods, method);
  }

  /**
   * Find method in this class matching method.
   */
  public DexEncodedMethod lookupMethod(DexMethod method) {
    DexEncodedMethod result = lookupDirectMethod(method);
    return result == null ? lookupVirtualMethod(method) : result;
  }

  private <T extends DexItem, S extends Descriptor<T, S>> T lookupTarget(T[] items, S descriptor) {
    for (T entry : items) {
      if (descriptor.match(entry)) {
        return entry;
      }
    }
    return null;
  }

  public boolean isAbstract() {
    return accessFlags.isAbstract();
  }

  public boolean isInterface() {
    return accessFlags.isInterface();
  }

  public boolean isEnum() {
    return accessFlags.isEnum();
  }

  public abstract void addDependencies(MixedSectionCollection collector);

  @Override
  public DexReference toReference() {
    return getType();
  }

  @Override
  public boolean isDexClass() {
    return true;
  }

  @Override
  public DexClass asDexClass() {
    return this;
  }

  public boolean isProgramClass() {
    return false;
  }

  public DexProgramClass asProgramClass() {
    return null;
  }

  public boolean isClasspathClass() {
    return false;
  }

  public DexClasspathClass asClasspathClass() {
    return null;
  }

  public abstract boolean isNotProgramClass();

  public boolean isLibraryClass() {
    return false;
  }

  public DexLibraryClass asLibraryClass() {
    return null;
  }

  @Override
  public boolean isStatic() {
    return accessFlags.isStatic();
  }

  @Override
  public boolean isStaticMember() {
    return false;
  }

  public DexEncodedMethod getClassInitializer() {
    if (cachedClassInitializer == null) {
      cachedClassInitializer = Optional.empty();
      for (DexEncodedMethod directMethod : directMethods) {
        if (directMethod.isClassInitializer()) {
          cachedClassInitializer = Optional.of(directMethod);
          break;
        }
      }
    }
    return cachedClassInitializer.orElse(null);
  }

  public Origin getOrigin() {
    return this.origin;
  }

  public DexType getType() {
    return this.type;
  }

  public boolean hasClassInitializer() {
    return getClassInitializer() != null;
  }

  public boolean hasTrivialClassInitializer() {
    if (isLibraryClass()) {
      // We don't know for library classes in general but assume that java.lang.Object is safe.
      return superType == null;
    }
    DexEncodedMethod clinit = getClassInitializer();
    return clinit != null && clinit.getCode() != null && clinit.getCode().isEmptyVoidMethod();
  }

  public boolean hasNonTrivialClassInitializer() {
    if (isLibraryClass()) {
      // We don't know for library classes in general but assume that java.lang.Object is safe.
      return superType != null;
    }
    DexEncodedMethod clinit = getClassInitializer();
    if (clinit == null || clinit.getCode() == null) {
      return false;
    }
    return !clinit.getCode().isEmptyVoidMethod();
  }

  public boolean hasDefaultInitializer() {
    return getDefaultInitializer() != null;
  }

  public DexEncodedMethod getInitializer(DexType[] parameters) {
    for (DexEncodedMethod method : directMethods()) {
      if (method.isInstanceInitializer()
          && Arrays.equals(method.method.proto.parameters.values, parameters)) {
        return method;
      }
    }
    return null;
  }

  public DexEncodedMethod getDefaultInitializer() {
    return getInitializer(DexType.EMPTY_ARRAY);
  }

  public boolean hasMissingSuperType(AppInfoWithSubtyping appInfo) {
    if (superType != null && appInfo.isMissingOrHasMissingSuperType(superType)) {
      return true;
    }
    for (DexType interfaceType : interfaces.values) {
      if (appInfo.isMissingOrHasMissingSuperType(interfaceType)) {
        return true;
      }
    }
    return false;
  }

  public boolean isSerializable(AppView<? extends AppInfoWithSubtyping> appView) {
    return appView.appInfo().isSerializable(type);
  }

  public boolean isExternalizable(AppView<? extends AppInfoWithSubtyping> appView) {
    return appView.appInfo().isExternalizable(type);
  }

  public boolean classInitializationMayHaveSideEffects(DexDefinitionSupplier definitions) {
    return classInitializationMayHaveSideEffects(definitions, Predicates.alwaysFalse());
  }

  public boolean classInitializationMayHaveSideEffects(
      DexDefinitionSupplier definitions, Predicate<DexType> ignore) {
    if (ignore.test(type)
        || definitions.dexItemFactory().libraryTypesWithoutStaticInitialization.contains(type)) {
      return false;
    }
    if (hasNonTrivialClassInitializer()) {
      return true;
    }
    if (defaultValuesForStaticFieldsMayTriggerAllocation()) {
      return true;
    }
    return initializationOfParentTypesMayHaveSideEffects(definitions, ignore);
  }

  public Iterable<DexType> allImmediateSupertypes() {
    Iterator<DexType> iterator =
        superType != null
            ? Iterators.concat(
                Iterators.singletonIterator(superType), Iterators.forArray(interfaces.values))
            : Iterators.forArray(interfaces.values);
    return () -> iterator;
  }

  public boolean initializationOfParentTypesMayHaveSideEffects(DexDefinitionSupplier definitions) {
    return initializationOfParentTypesMayHaveSideEffects(definitions, Predicates.alwaysFalse());
  }

  public boolean initializationOfParentTypesMayHaveSideEffects(
      DexDefinitionSupplier definitions, Predicate<DexType> ignore) {
    for (DexType iface : interfaces.values) {
      if (iface.classInitializationMayHaveSideEffects(definitions, ignore)) {
        return true;
      }
    }
    if (superType != null && superType.classInitializationMayHaveSideEffects(definitions, ignore)) {
      return true;
    }
    return false;
  }

  public boolean defaultValuesForStaticFieldsMayTriggerAllocation() {
    return staticFields().stream()
        .anyMatch(field -> field.getStaticValue().mayHaveSideEffects());
  }

  public List<InnerClassAttribute> getInnerClasses() {
    return innerClasses;
  }

  public EnclosingMethodAttribute getEnclosingMethod() {
    return enclosingMethod;
  }

  public void clearEnclosingMethod() {
    enclosingMethod = null;
  }

  public void removeEnclosingMethod(Predicate<EnclosingMethodAttribute> predicate) {
    if (enclosingMethod != null && predicate.test(enclosingMethod)) {
      enclosingMethod = null;
    }
  }

  public void clearInnerClasses() {
    innerClasses.clear();
  }

  public void removeInnerClasses(Predicate<InnerClassAttribute> predicate) {
    innerClasses.removeIf(predicate::test);
  }

  public InnerClassAttribute getInnerClassAttributeForThisClass() {
    for (InnerClassAttribute innerClassAttribute : getInnerClasses()) {
      if (type == innerClassAttribute.getInner()) {
        return innerClassAttribute;
      }
    }
    return null;
  }

  public boolean isLocalClass() {
    InnerClassAttribute innerClass = getInnerClassAttributeForThisClass();
    // The corresponding enclosing-method attribute might be not available, e.g., CF version 50.
    return innerClass != null && innerClass.getOuter() == null && innerClass.isNamed();
  }

  public boolean isMemberClass() {
    InnerClassAttribute innerClass = getInnerClassAttributeForThisClass();
    boolean isMember = innerClass != null && innerClass.getOuter() != null && innerClass.isNamed();
    assert !isMember || getEnclosingMethod() == null;
    return isMember;
  }

  public boolean isAnonymousClass() {
    InnerClassAttribute innerClass = getInnerClassAttributeForThisClass();
    // The corresponding enclosing-method attribute might be not available, e.g., CF version 50.
    // We can't rely on outer type either because it's not null prior to 51 and null since 51.
    return innerClass != null && innerClass.isAnonymous();
  }

  public boolean isInANest() {
    assert nestMembers != null;
    return !(nestMembers.isEmpty()) || (nestHost != null);
  }

  public boolean isNestHost() {
    return !nestMembers.isEmpty();
  }

  public NestHostClassAttribute getNestHostClassAttribute() {
    return nestHost;
  }

  public List<NestMemberClassAttribute> getNestMembersClassAttributes() {
    return nestMembers;
  }

  /** Returns kotlin class info if the class is synthesized by kotlin compiler. */
  public abstract KotlinInfo getKotlinInfo();

  public final boolean hasKotlinInfo() {
    return getKotlinInfo() != null;
  }

  public boolean isValid(InternalOptions options) {
    assert verifyNoAbstractMethodsOnNonAbstractClasses(virtualMethods(), options);
    assert !isInterface() || virtualMethods().stream().noneMatch(DexEncodedMethod::isFinal);
    assert verifyCorrectnessOfFieldHolders(fields());
    assert verifyNoDuplicateFields();
    assert verifyCorrectnessOfMethodHolders(methods());
    assert verifyNoDuplicateMethods();
    return true;
  }
}
