// Copyright (c) 2017, 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.rewrite.enums;

import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.toList;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.util.List;
import java.util.Objects;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

/**
 * Tests checking that Enum.ordinal() and Enum.name() calls on enum fields are rewritten into a
 * constant integer and string, respectively.
 */
@RunWith(Parameterized.class)
public class EnumOptimizationTest extends TestBase {

  private final boolean enableOptimization;
  private final TestParameters parameters;

  @Parameters(name = "{1}, enable enum optimization: {0}")
  public static List<Object[]> data() {
    return buildParameters(
        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
  }

  public EnumOptimizationTest(boolean enableOptimization, TestParameters parameters) {
    this.enableOptimization = enableOptimization;
    this.parameters = parameters;
  }

  private void configure(InternalOptions options) {
    options.enableEnumValueOptimization = enableOptimization;
    options.enableEnumSwitchMapRemoval = enableOptimization;
    options.enableEnumUnboxing = false;
  }

  @Test
  public void ordinals() throws Exception {
    testForR8(parameters.getBackend())
        .addProgramClassesAndInnerClasses(Ordinals.class)
        .addKeepMainRule(Ordinals.class)
        .enableConstantArgumentAnnotations()
        .enableInliningAnnotations()
        .enableMemberValuePropagationAnnotations()
        .enableSideEffectAnnotations()
        .addOptionsModification(this::configure)
        .setMinApi(parameters.getApiLevel())
        .compile()
        .inspect(this::inspectOrdinals)
        .run(parameters.getRuntime(), Ordinals.class)
        .assertSuccessWithOutputLines("1", "1", "TWO1", "1", "11", "3", "1", "1", "1", "1");
  }

  private void inspectOrdinals(CodeInspector inspector) {
    ClassSubject clazz = inspector.clazz(Ordinals.class);
    assertTrue(clazz.isPresent());

    if (enableOptimization) {
      assertOrdinalReplacedWithConst(clazz.uniqueMethodWithOriginalName("simple"), 1);
      assertOrdinalReplacedWithConst(clazz.uniqueMethodWithOriginalName("local"), 1);
      // Even replaced ordinal is concatenated (and gone).
      assertOrdinalReplacedAndGone(clazz.uniqueMethodWithOriginalName("multipleUsages"));
      assertOrdinalReplacedWithConst(clazz.uniqueMethodWithOriginalName("inlined"), 1);
      assertOrdinalReplacedWithConst(clazz.uniqueMethodWithOriginalName("inSwitch"), 11);
      assertOrdinalReplacedWithConst(
          clazz.uniqueMethodWithOriginalName("differentTypeStaticField"), 1);
      assertOrdinalReplacedWithConst(clazz.uniqueMethodWithOriginalName("nonStaticGet"), 1);
      assertOrdinalReplacedWithConst(clazz.uniqueMethodWithOriginalName("nonValueStaticField"), 1);
    } else {
      assertOrdinalWasNotReplaced(clazz.uniqueMethodWithOriginalName("simple"));
      assertOrdinalWasNotReplaced(clazz.uniqueMethodWithOriginalName("local"));
      assertOrdinalWasNotReplaced(clazz.uniqueMethodWithOriginalName("multipleUsages"));
      assertOrdinalWasNotReplaced(clazz.uniqueMethodWithOriginalName("inlined"));
      assertOrdinalWasNotReplaced(clazz.uniqueMethodWithOriginalName("inSwitch"));
      assertOrdinalWasNotReplaced(clazz.uniqueMethodWithOriginalName("differentTypeStaticField"));
      assertOrdinalWasNotReplaced(clazz.uniqueMethodWithOriginalName("nonStaticGet"));
    }

    assertOrdinalWasNotReplaced(clazz.uniqueMethodWithOriginalName("libraryType"));
    assertOrdinalWasNotReplaced(clazz.uniqueMethodWithOriginalName("phi"));

    assertThat(clazz.uniqueMethodWithOriginalName("inlined2"), isAbsent());
  }

  @Test
  public void names() throws Exception {
    testForR8(parameters.getBackend())
        .addProgramClassesAndInnerClasses(Names.class)
        .addKeepMainRule(Names.class)
        .enableConstantArgumentAnnotations()
        .enableInliningAnnotations()
        .enableMemberValuePropagationAnnotations()
        .enableSideEffectAnnotations()
        .addOptionsModification(this::configure)
        .setMinApi(parameters.getApiLevel())
        .compile()
        .inspect(this::inspectNames)
        .run(parameters.getRuntime(), Names.class)
        .assertSuccessWithOutputLines(
            "TWO", "TWO", "1TWO", "TWO", "SECONDS", "DOWN", "TWO", "TWO", "TWO");
  }

  private void inspectNames(CodeInspector inspector) {
    ClassSubject clazz = inspector.clazz(Names.class);
    assertTrue(clazz.isPresent());

    if (enableOptimization) {
      assertNameReplacedWithConst(clazz.uniqueMethodWithOriginalName("simple"), "TWO");
      assertNameReplacedWithConst(clazz.uniqueMethodWithOriginalName("local"), "TWO");
      assertNameReplacedWithConst(clazz.uniqueMethodWithOriginalName("multipleUsages"), "1TWO");
      assertNameReplacedWithConst(clazz.uniqueMethodWithOriginalName("inlined"), "TWO");
      assertNameReplacedWithConst(
          clazz.uniqueMethodWithOriginalName("differentTypeStaticField"), "DOWN");
      assertNameReplacedWithConst(clazz.uniqueMethodWithOriginalName("nonStaticGet"), "TWO");
      assertNameReplacedWithConst(clazz.uniqueMethodWithOriginalName("nonValueStaticField"), "TWO");
    } else {
      assertNameWasNotReplaced(clazz.uniqueMethodWithOriginalName("simple"));
      assertNameWasNotReplaced(clazz.uniqueMethodWithOriginalName("local"));
      assertNameWasNotReplaced(clazz.uniqueMethodWithOriginalName("multipleUsages"));
      assertNameWasNotReplaced(clazz.uniqueMethodWithOriginalName("inlined"));
      assertNameWasNotReplaced(clazz.uniqueMethodWithOriginalName("differentTypeStaticField"));
      assertNameWasNotReplaced(clazz.uniqueMethodWithOriginalName("nonStaticGet"));
    }

    // TODO(jakew) this should be allowed!
    assertNameWasNotReplaced(clazz.uniqueMethodWithOriginalName("libraryType"));

    assertNameWasNotReplaced(clazz.uniqueMethodWithOriginalName("phi"));

    assertThat(clazz.uniqueMethodWithOriginalName("inlined2"), isAbsent());
  }

  @Test
  public void toStrings() throws Exception {
    testForR8(parameters.getBackend())
        .addProgramClassesAndInnerClasses(ToStrings.class)
        .addKeepMainRule(ToStrings.class)
        .enableConstantArgumentAnnotations()
        .enableInliningAnnotations()
        .enableMemberValuePropagationAnnotations()
        .enableSideEffectAnnotations()
        .addOptionsModification(this::configure)
        .setMinApi(parameters.getApiLevel())
        .compile()
        .inspect(this::inspectToStrings)
        .run(parameters.getRuntime(), ToStrings.class)
        .assertSuccessWithOutputLines(
            "one", "one", "TWO", "TWO", "TWO", "1TWO", "TWO", "SECONDS", "DOWN", "TWO", "TWO",
            "TWO");
  }

  private void inspectToStrings(CodeInspector inspector) {
    ClassSubject clazz = inspector.clazz(ToStrings.class);
    assertTrue(clazz.isPresent());

    assertToStringWasNotReplaced(clazz.uniqueMethodWithOriginalName("typeToString"));
    assertToStringReplacedWithConst(clazz.uniqueMethodWithOriginalName("valueWithToString"), "one");
    assertToStringWasNotReplaced(clazz.uniqueMethodWithOriginalName("valueWithoutToString"));

    if (enableOptimization) {
      assertToStringReplacedWithConst(clazz.uniqueMethodWithOriginalName("noToString"), "TWO");
      assertToStringReplacedWithConst(clazz.uniqueMethodWithOriginalName("local"), "TWO");
      assertToStringReplacedWithConst(clazz.uniqueMethodWithOriginalName("multipleUsages"), "TWO");
      assertToStringReplacedWithConst(clazz.uniqueMethodWithOriginalName("inlined"), "TWO");
      assertToStringReplacedWithConst(
          clazz.uniqueMethodWithOriginalName("nonValueStaticField"), "TWO");
      assertToStringReplacedWithConst(
          clazz.uniqueMethodWithOriginalName("differentTypeStaticField"), "DOWN");
      assertToStringReplacedWithConst(clazz.uniqueMethodWithOriginalName("nonStaticGet"), "TWO");
    } else {
      assertToStringWasNotReplaced(clazz.uniqueMethodWithOriginalName("noToString"));
      assertToStringWasNotReplaced(clazz.uniqueMethodWithOriginalName("local"));
      assertToStringWasNotReplaced(clazz.uniqueMethodWithOriginalName("multipleUsages"));
      assertToStringWasNotReplaced(clazz.uniqueMethodWithOriginalName("inlined"));
      assertToStringWasNotReplaced(clazz.uniqueMethodWithOriginalName("nonValueStaticField"));
      assertToStringWasNotReplaced(clazz.uniqueMethodWithOriginalName("differentTypeStaticField"));
      assertToStringWasNotReplaced(clazz.uniqueMethodWithOriginalName("nonStaticGet"));
    }

    assertToStringWasNotReplaced(clazz.uniqueMethodWithOriginalName("libraryType"));
    assertToStringWasNotReplaced(clazz.uniqueMethodWithOriginalName("phi"));

    assertThat(clazz.uniqueMethodWithOriginalName("inlined2"), isAbsent());
  }

  private static void assertOrdinalReplacedWithConst(MethodSubject method, int expectedConst) {
    assertThat(method, isPresent());
    assertEquals(emptyList(), enumInvokes(method, "ordinal"));

    long[] actualConst = method.streamInstructions()
        .filter(InstructionSubject::isConstNumber)
        .mapToLong(InstructionSubject::getConstNumber)
        .toArray();
    assertEquals(expectedConst, actualConst[0]);
  }

  private static void assertOrdinalReplacedAndGone(MethodSubject method) {
    assertThat(method, isPresent());
    assertEquals(emptyList(), enumInvokes(method, "ordinal"));
    assertTrue(method.streamInstructions().noneMatch(InstructionSubject::isConstNumber));
  }

  private static void assertOrdinalWasNotReplaced(MethodSubject method) {
    assertThat(method, isPresent());
    List<InstructionSubject> invokes = enumInvokes(method, "ordinal");
    assertEquals(invokes.toString(), 1, invokes.size());
  }

  private static List<InstructionSubject> enumInvokes(MethodSubject method, String methodName) {
    return method.streamInstructions()
        .filter(instruction -> instruction.isInvoke()
            && instruction.getMethod().name.toString().equals(methodName))
        .collect(toList());
  }

  private static void assertNameReplacedWithConst(MethodSubject method, String expectedConst) {
    assertThat(method, isPresent());
    assertEquals(emptyList(), enumInvokes(method, "name"));

    List<String> actualConst = method.streamInstructions()
        .map(InstructionSubject::getConstString)
        .filter(Objects::nonNull)
        .collect(toList());
    assertEquals(expectedConst, actualConst.get(0));
  }

  private static void assertNameWasNotReplaced(MethodSubject method) {
    assertThat(method, isPresent());
    List<InstructionSubject> invokes = enumInvokes(method, "name");
    assertEquals(invokes.toString(), 1, invokes.size());
  }

  private static void assertToStringReplacedWithConst(MethodSubject method, String expectedConst) {
    assertThat(method, isPresent());
    assertEquals(emptyList(), enumInvokes(method, "toString"));

    List<String> actualConst = method.streamInstructions()
        .map(InstructionSubject::getConstString)
        .filter(Objects::nonNull)
        .collect(toList());
    assertEquals(expectedConst, actualConst.get(0));
  }

  private static void assertToStringWasNotReplaced(MethodSubject method) {
    assertThat(method, isPresent());
    List<InstructionSubject> invokes = enumInvokes(method, "toString");
    assertEquals(invokes.toString(), 1, invokes.size());
  }
}
