// 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 final boolean hasAccesses() {
    return !isEmpty();
  }

  public boolean isBottom() {
    return false;
  }

  public boolean isConcrete() {
    return false;
  }

  public 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) {
              ProgramMethod newContext = lens.mapProgramMethod(context, definitions);
              assert newContext != null : "Unable to map context: " + context.toSourceString();
              newContexts.add(newContext);
            }
          });
      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;
    }
  }
}
