// Copyright (c) 2020, 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.errors.Unreachable;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
 * For a concrete field, stores the contexts in which the field is accessed.
 *
 * <p>If the concrete field does not have any accesses, then {@link EmptyAccessContexts}.
 *
 * <p>If nothing is nothing about the accesses to the concrete field, then {@link
 * UnknownAccessContexts}.
 *
 * <p>Otherwise, the concrete contexts in which the field is accessed is maintained by {@link
 * ConcreteAccessContexts}. The access contexts are qualified by the field reference they access.
 *
 * <p>Example: If a field `int Foo.field` is accessed directly in `void Main.direct()` and
 * indirectly via a non-rebound reference `int FooSub.field` in `void Main.indirect()`, then the
 * collection is:
 *
 * <pre>
 *   ConcreteAccessContexts {
 *     `int Foo.field` -> { `void Main.direct()` }
 *     `int FooSub.field` -> { `void Main.indirect()` }
 *   }
 * </pre>
 */
public abstract class AbstractAccessContexts {

  abstract void flattenAccessContexts(DexField field);

  abstract void forEachAccessContext(Consumer<ProgramMethod> consumer);

  /**
   * Returns true if this field is written by a method for which {@param predicate} returns true.
   */
  abstract boolean isAccessedInMethodSatisfying(Predicate<ProgramMethod> predicate);

  /**
   * Returns true if this field is only written by methods for which {@param predicate} returns
   * true.
   */
  abstract boolean isAccessedOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate);

  /**
   * Returns true if this field is written by a method in the program other than {@param method}.
   */
  abstract boolean isAccessedOutside(DexEncodedMethod method);

  abstract int getNumberOfAccessContexts();

  public boolean isBottom() {
    return false;
  }

  public boolean isConcrete() {
    return false;
  }

  abstract boolean isEmpty();

  public ConcreteAccessContexts asConcrete() {
    return null;
  }

  public boolean isTop() {
    return false;
  }

  abstract AbstractAccessContexts rewrittenWithLens(
      DexDefinitionSupplier definitions, GraphLens lens);

  public static EmptyAccessContexts empty() {
    return EmptyAccessContexts.getInstance();
  }

  public static UnknownAccessContexts unknown() {
    return UnknownAccessContexts.getInstance();
  }

  public abstract AbstractAccessContexts join(AbstractAccessContexts contexts);

  public static class EmptyAccessContexts extends AbstractAccessContexts {

    public static EmptyAccessContexts INSTANCE = new EmptyAccessContexts();

    private EmptyAccessContexts() {}

    public static EmptyAccessContexts getInstance() {
      return INSTANCE;
    }

    @Override
    void flattenAccessContexts(DexField field) {
      // Intentionally empty.
    }

    @Override
    void forEachAccessContext(Consumer<ProgramMethod> consumer) {
      // Intentionally empty.
    }

    @Override
    boolean isAccessedInMethodSatisfying(Predicate<ProgramMethod> predicate) {
      return false;
    }

    @Override
    boolean isAccessedOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate) {
      return true;
    }

    @Override
    boolean isAccessedOutside(DexEncodedMethod method) {
      return false;
    }

    @Override
    int getNumberOfAccessContexts() {
      return 0;
    }

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

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

    @Override
    AbstractAccessContexts rewrittenWithLens(DexDefinitionSupplier definitions, GraphLens lens) {
      return this;
    }

    @Override
    public AbstractAccessContexts join(AbstractAccessContexts contexts) {
      return contexts;
    }
  }

  public static class ConcreteAccessContexts extends AbstractAccessContexts {

    private final Map<DexField, ProgramMethodSet> accessesWithContexts;

    public ConcreteAccessContexts() {
      this(new IdentityHashMap<>());
    }

    public ConcreteAccessContexts(Map<DexField, ProgramMethodSet> accessesWithContexts) {
      this.accessesWithContexts = accessesWithContexts;
    }

    void forEachAccess(Consumer<DexField> consumer, Predicate<DexField> predicate) {
      if (accessesWithContexts != null) {
        accessesWithContexts.forEach(
            (access, contexts) -> {
              if (predicate.test(access)) {
                consumer.accept(access);
              }
            });
      }
    }

    @Override
    void forEachAccessContext(Consumer<ProgramMethod> consumer) {
      // There can be indirect reads and writes of the same field reference, so we need to keep
      // track
      // of the previously-seen indirect accesses to avoid reporting duplicates.
      ProgramMethodSet visited = ProgramMethodSet.create();
      if (accessesWithContexts != null) {
        for (ProgramMethodSet encodedAccessContexts : accessesWithContexts.values()) {
          for (ProgramMethod encodedAccessContext : encodedAccessContexts) {
            if (visited.add(encodedAccessContext)) {
              consumer.accept(encodedAccessContext);
            }
          }
        }
      }
    }

    public Map<DexField, ProgramMethodSet> getAccessesWithContexts() {
      return accessesWithContexts;
    }

    @Override
    int getNumberOfAccessContexts() {
      if (accessesWithContexts.size() == 1) {
        return accessesWithContexts.values().iterator().next().size();
      }
      throw new Unreachable(
          "Should only be querying the number of access contexts after flattening");
    }

    ProgramMethod getUniqueAccessContext() {
      if (accessesWithContexts != null && accessesWithContexts.size() == 1) {
        ProgramMethodSet contexts = accessesWithContexts.values().iterator().next();
        if (contexts.size() == 1) {
          return contexts.iterator().next();
        }
      }
      return null;
    }

    @Override
    void flattenAccessContexts(DexField field) {
      if (accessesWithContexts != null) {
        ProgramMethodSet flattenedAccessContexts =
            accessesWithContexts.computeIfAbsent(field, ignore -> ProgramMethodSet.create());
        accessesWithContexts.forEach(
            (access, contexts) -> {
              if (access != field) {
                flattenedAccessContexts.addAll(contexts);
              }
            });
        accessesWithContexts.clear();
        if (!flattenedAccessContexts.isEmpty()) {
          accessesWithContexts.put(field, flattenedAccessContexts);
        }
        assert accessesWithContexts.size() <= 1;
      }
    }

    /**
     * Returns true if this field is written by a method for which {@param predicate} returns true.
     */
    @Override
    public boolean isAccessedInMethodSatisfying(Predicate<ProgramMethod> predicate) {
      for (ProgramMethodSet encodedWriteContexts : accessesWithContexts.values()) {
        for (ProgramMethod encodedWriteContext : encodedWriteContexts) {
          if (predicate.test(encodedWriteContext)) {
            return true;
          }
        }
      }
      return false;
    }

    /**
     * Returns true if this field is only written by methods for which {@param predicate} returns
     * true.
     */
    @Override
    public boolean isAccessedOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate) {
      for (ProgramMethodSet encodedWriteContexts : accessesWithContexts.values()) {
        for (ProgramMethod encodedWriteContext : encodedWriteContexts) {
          if (!predicate.test(encodedWriteContext)) {
            return false;
          }
        }
      }
      return true;
    }

    /**
     * Returns true if this field is written by a method in the program other than {@param method}.
     */
    @Override
    public boolean isAccessedOutside(DexEncodedMethod method) {
      for (ProgramMethodSet encodedWriteContexts : accessesWithContexts.values()) {
        for (ProgramMethod encodedWriteContext : encodedWriteContexts) {
          if (encodedWriteContext.getDefinition() != method) {
            return true;
          }
        }
      }
      return false;
    }

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

    @Override
    public ConcreteAccessContexts asConcrete() {
      return this;
    }

    @Override
    public boolean isEmpty() {
      return accessesWithContexts.isEmpty();
    }

    public boolean recordAccess(DexField access, ProgramMethod context) {
      return accessesWithContexts
          .computeIfAbsent(access, ignore -> ProgramMethodSet.create())
          .add(context);
    }

    @Override
    ConcreteAccessContexts rewrittenWithLens(DexDefinitionSupplier definitions, GraphLens lens) {
      Map<DexField, ProgramMethodSet> newAccessesWithContexts = new IdentityHashMap<>();
      accessesWithContexts.forEach(
          (access, contexts) -> {
            ProgramMethodSet newContexts =
                newAccessesWithContexts.computeIfAbsent(
                    lens.lookupField(access), ignore -> ProgramMethodSet.create());
            for (ProgramMethod context : contexts) {
              newContexts.add(lens.mapProgramMethod(context, definitions));
            }
          });
      return new ConcreteAccessContexts(newAccessesWithContexts);
    }

    @Override
    public AbstractAccessContexts join(AbstractAccessContexts contexts) {
      if (contexts.isEmpty()) {
        return this;
      }
      if (contexts.isTop()) {
        return contexts;
      }
      Map<DexField, ProgramMethodSet> newAccessesWithContexts = new IdentityHashMap<>();
      accessesWithContexts.forEach(
          (field, methodSet) ->
              newAccessesWithContexts.put(field, ProgramMethodSet.create(methodSet)));

      BiConsumer<DexField, ProgramMethodSet> addAllMethods =
          (field, methodSet) ->
              newAccessesWithContexts
                  .computeIfAbsent(field, ignore -> ProgramMethodSet.create())
                  .addAll(methodSet);
      contexts.asConcrete().accessesWithContexts.forEach(addAllMethods);
      return new ConcreteAccessContexts(newAccessesWithContexts);
    }
  }

  public static class UnknownAccessContexts extends AbstractAccessContexts {

    public static UnknownAccessContexts INSTANCE = new UnknownAccessContexts();

    private UnknownAccessContexts() {}

    public static UnknownAccessContexts getInstance() {
      return INSTANCE;
    }

    @Override
    void flattenAccessContexts(DexField field) {
      // Intentionally empty.
    }

    @Override
    void forEachAccessContext(Consumer<ProgramMethod> consumer) {
      throw new Unreachable("Should never be iterating the access contexts when they are unknown");
    }

    @Override
    boolean isAccessedInMethodSatisfying(Predicate<ProgramMethod> predicate) {
      return true;
    }

    @Override
    boolean isAccessedOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate) {
      return false;
    }

    @Override
    boolean isAccessedOutside(DexEncodedMethod method) {
      return true;
    }

    @Override
    int getNumberOfAccessContexts() {
      throw new Unreachable(
          "Should never be querying the number of access contexts when they are unknown");
    }

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

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

    @Override
    AbstractAccessContexts rewrittenWithLens(DexDefinitionSupplier definitions, GraphLens lens) {
      return this;
    }

    @Override
    public AbstractAccessContexts join(AbstractAccessContexts contexts) {
      return this;
    }
  }
}
