// 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.naming;

import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType;
import static com.android.tools.r8.utils.DescriptorUtils.isValidJavaType;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.containsString;
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.ToolHelper;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.ConstStringInstructionSubject;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.InstructionSubject.JumboStringMode;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.Sets;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.stream.Stream;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class IdentifierMinifierTest extends TestBase {

  private final TestParameters parameters;
  private final String appFileName;
  private final List<String> keepRulesFiles;
  private final BiConsumer<TestParameters, CodeInspector> inspection;
  private final String test;

  public IdentifierMinifierTest(
      TestParameters parameters,
      String test,
      List<String> keepRulesFiles,
      BiConsumer<TestParameters, CodeInspector> inspection) {
    this.parameters = parameters;
    this.appFileName = ToolHelper.EXAMPLES_BUILD_DIR + test + FileUtils.JAR_EXTENSION;
    this.keepRulesFiles = keepRulesFiles;
    this.inspection = inspection;
    this.test = test;
  }

  @Test
  public void identiferMinifierTest() throws Exception {
    boolean hasWarning =
        test.equals("identifiernamestring") && keepRulesFiles.get(0).endsWith("keep-rules-2.txt");
    CodeInspector codeInspector =
        testForR8(parameters.getBackend())
            .addProgramFiles(Paths.get(appFileName))
            .addKeepRuleFiles(ListUtils.map(keepRulesFiles, Paths::get))
            .allowDiagnosticWarningMessages(hasWarning)
            .enableProguardTestOptions()
            .setMinApi(parameters.getApiLevel())
            .compile()
            .applyIf(
                hasWarning,
                result ->
                    result.assertAllWarningMessagesMatch(
                        containsString("Cannot determine what identifier string flows to")))
            .inspector();
    inspection.accept(parameters, codeInspector);
  }

  @Parameters(name = "{0} test: {1} keep: {2}")
  public static Collection<Object[]> data() {
    List<String> tests = Arrays.asList(
        "adaptclassstrings",
        "atomicfieldupdater",
        "forname",
        "getmembers",
        "identifiernamestring");

    Map<String, BiConsumer<TestParameters, CodeInspector>> inspections = new HashMap<>();
    inspections.put("adaptclassstrings:keep-rules-1.txt", IdentifierMinifierTest::test1_rule1);
    inspections.put("adaptclassstrings:keep-rules-2.txt", IdentifierMinifierTest::test1_rule2);
    inspections.put("adaptclassstrings:keep-rules-3.txt", IdentifierMinifierTest::test1_rule3);
    inspections.put(
        "atomicfieldupdater:keep-rules.txt", IdentifierMinifierTest::test_atomicfieldupdater);
    inspections.put("forname:keep-rules.txt", IdentifierMinifierTest::test_forname);
    inspections.put("getmembers:keep-rules.txt", IdentifierMinifierTest::test_getmembers);
    inspections.put("identifiernamestring:keep-rules-1.txt", IdentifierMinifierTest::test2_rule1);
    inspections.put("identifiernamestring:keep-rules-2.txt", IdentifierMinifierTest::test2_rule2);
    inspections.put("identifiernamestring:keep-rules-3.txt", IdentifierMinifierTest::test2_rule3);
    Collection<Object[]> parameters = NamingTestBase.createTests(tests, inspections);

    List<Object[]> parametersWithBackend = new ArrayList<>();
    for (TestParameters testParameter : getTestParameters().withAllRuntimesAndApiLevels().build()) {
      for (Object[] row : parameters) {
        Object[] newRow = new Object[row.length + 1];
        newRow[0] = testParameter;
        System.arraycopy(row, 0, newRow, 1, row.length);
        parametersWithBackend.add(newRow);
      }
    }

    return parametersWithBackend;
  }

  // Without -adaptclassstrings
  private static void test1_rule1(TestParameters parameters, CodeInspector inspector) {
    int expectedRenamedIdentifierInMain = parameters.isCfRuntime() ? 0 : 0;
    test1_rules(inspector, expectedRenamedIdentifierInMain, 0, 0);
  }

  // With -adaptclassstrings *.*A
  private static void test1_rule2(TestParameters parameters, CodeInspector inspector) {
    int expectedRenamedIdentifierInMain = parameters.isCfRuntime() ? 0 : 0;
    test1_rules(inspector, expectedRenamedIdentifierInMain, 1, 1);
  }

  // With -adaptclassstrings (no filter)
  private static void test1_rule3(TestParameters parameters, CodeInspector inspector) {
    int expectedRenamedIdentifierInMain = parameters.isCfRuntime() ? 1 : 1;
    test1_rules(inspector, expectedRenamedIdentifierInMain, 1, 1);
  }

  private static void test1_rules(
      CodeInspector inspector, int countInMain, int countInABar, int countInAFields) {
    ClassSubject mainClass = inspector.clazz("adaptclassstrings.Main");
    MethodSubject main = mainClass.mainMethod();
    assertThat(main, isPresent());
    verifyPresenceOfConstString(main);
    int renamedYetFoundIdentifierCount = countRenamedClassIdentifier(inspector, main);
    assertEquals(countInMain, renamedYetFoundIdentifierCount);

    ClassSubject aClass = inspector.clazz("adaptclassstrings.A");
    MethodSubject bar = aClass.uniqueMethodWithOriginalName("bar");
    assertThat(bar, isPresent());
    verifyPresenceOfConstString(bar);
    renamedYetFoundIdentifierCount = countRenamedClassIdentifier(inspector, bar);
    assertEquals(countInABar, renamedYetFoundIdentifierCount);

    renamedYetFoundIdentifierCount =
        countRenamedClassIdentifier(inspector, aClass.getDexProgramClass().staticFields());
    assertEquals(countInAFields, renamedYetFoundIdentifierCount);
  }

  private static void test_atomicfieldupdater(TestParameters parameters, CodeInspector inspector) {
    ClassSubject mainClass = inspector.clazz("atomicfieldupdater.Main");
    MethodSubject main = mainClass.mainMethod();
    assertThat(main, isPresent());
    verifyPresenceOfConstString(main);

    ClassSubject a = inspector.clazz("atomicfieldupdater.A");
    Set<InstructionSubject> constStringInstructions =
        getRenamedMemberIdentifierConstStrings(a, main);
    assertEquals(3, constStringInstructions.size());
  }

  private static void test_forname(TestParameters parameters, CodeInspector inspector) {
    ClassSubject mainClass = inspector.clazz("forname.Main");
    MethodSubject main = mainClass.mainMethod();
    assertThat(main, isPresent());
    verifyPresenceOfConstString(main);
    int renamedYetFoundIdentifierCount = countRenamedClassIdentifier(inspector, main);
    assertEquals(1, renamedYetFoundIdentifierCount);
  }

  private static void test_getmembers(TestParameters parameters, CodeInspector inspector) {
    ClassSubject mainClass = inspector.clazz("getmembers.Main");
    MethodSubject main = mainClass.mainMethod();
    assertThat(main, isPresent());
    verifyPresenceOfConstString(main);

    ClassSubject a = inspector.clazz("getmembers.A");
    Set<InstructionSubject> constStringInstructions =
        getRenamedMemberIdentifierConstStrings(a, main);
    assertEquals(2, constStringInstructions.size());

    ClassSubject b = inspector.clazz("getmembers.B");
    MethodSubject inliner = b.uniqueMethodWithOriginalName("inliner");
    assertThat(inliner, isPresent());
    constStringInstructions = getRenamedMemberIdentifierConstStrings(a, inliner);
    assertEquals(1, constStringInstructions.size());
  }

  // Without -identifiernamestring
  private static void test2_rule1(TestParameters parameters, CodeInspector inspector) {
    ClassSubject mainClass = inspector.clazz("identifiernamestring.Main");
    MethodSubject main = mainClass.mainMethod();
    assertThat(main, isPresent());
    verifyPresenceOfConstString(main);
    int renamedYetFoundIdentifierCount = countRenamedClassIdentifier(inspector, main);
    assertEquals(1, renamedYetFoundIdentifierCount);

    ClassSubject aClass = inspector.clazz("identifiernamestring.A");
    MethodSubject aInit = aClass.init();
    assertThat(aInit, isPresent());
    verifyPresenceOfConstString(aInit);
    renamedYetFoundIdentifierCount = countRenamedClassIdentifier(inspector, aInit);
    assertEquals(0, renamedYetFoundIdentifierCount);

    renamedYetFoundIdentifierCount =
        countRenamedClassIdentifier(inspector, aClass.getDexProgramClass().staticFields());
    assertEquals(0, renamedYetFoundIdentifierCount);
  }

  // With -identifiernamestring for annotations and name-based filters
  private static void test2_rule2(TestParameters parameters, CodeInspector inspector) {
    ClassSubject mainClass = inspector.clazz("identifiernamestring.Main");
    MethodSubject main = mainClass.mainMethod();
    assertThat(main, isPresent());
    verifyPresenceOfConstString(main);
    int renamedYetFoundIdentifierCount = countRenamedClassIdentifier(inspector, main);
    assertEquals(parameters.isCfRuntime() ? 2 : 1, renamedYetFoundIdentifierCount);

    ClassSubject aClass = inspector.clazz("identifiernamestring.A");
    MethodSubject aInit = aClass.init();
    assertThat(aInit, isPresent());
    verifyPresenceOfConstString(aInit);
    renamedYetFoundIdentifierCount = countRenamedClassIdentifier(inspector, aInit);
    assertEquals(1, renamedYetFoundIdentifierCount);

    renamedYetFoundIdentifierCount =
        countRenamedClassIdentifier(inspector, aClass.getDexProgramClass().staticFields());
    assertEquals(2, renamedYetFoundIdentifierCount);
  }

  // With -identifiernamestring for reflective methods in testing class R.
  private static void test2_rule3(TestParameters parameters, CodeInspector inspector) {
    ClassSubject mainClass = inspector.clazz("identifiernamestring.Main");
    MethodSubject main = mainClass.mainMethod();
    assertThat(main, isPresent());
    verifyPresenceOfConstString(main);

    ClassSubject b = inspector.clazz("identifiernamestring.B");
    Set<InstructionSubject> constStringInstructions =
        getRenamedMemberIdentifierConstStrings(b, main);
    assertEquals(2, constStringInstructions.size());
  }

  private static void verifyPresenceOfConstString(MethodSubject method) {
    assertTrue(
        method
            .iterateInstructions(instruction -> instruction.isConstString(JumboStringMode.ALLOW))
            .hasNext());
  }

  private static Stream<InstructionSubject> getConstStringInstructions(MethodSubject method) {
    return method.streamInstructions()
        .filter(instr -> instr.isConstString(JumboStringMode.ALLOW));
  }

  private static int countRenamedClassIdentifier(
      CodeInspector inspector, MethodSubject method) {
    return getConstStringInstructions(method)
        .reduce(
            0,
            (cnt, instr) -> {
              assert (instr instanceof ConstStringInstructionSubject);
              String cnstString =
                  ((ConstStringInstructionSubject) instr).getString().toSourceString();
              if (isValidJavaType(cnstString)) {
                ClassSubject classSubject = inspector.clazz(cnstString);
                if (classSubject.isPresent()
                    && classSubject.isRenamed()
                    && descriptorToJavaType(classSubject.getFinalDescriptor()).equals(cnstString)) {
                  return cnt + 1;
                }
              }
              return cnt;
            },
            Integer::sum);
  }

  private static int countRenamedClassIdentifier(
      CodeInspector inspector, List<DexEncodedField> fields) {
    return fields.stream()
        .filter(encodedField -> encodedField.getStaticValue().isDexValueString())
        .reduce(
            0,
            (cnt, encodedField) -> {
              String cnstString =
                  encodedField.getStaticValue().asDexValueString().getValue().toString();
              if (isValidJavaType(cnstString)) {
                ClassSubject classSubject = inspector.clazz(cnstString);
                if (classSubject.isRenamed()
                    && descriptorToJavaType(classSubject.getFinalDescriptor()).equals(cnstString)) {
                  return cnt + 1;
                }
              }
              return cnt;
            },
            Integer::sum);
  }

  private static Set<InstructionSubject> getRenamedMemberIdentifierConstStrings(
      ClassSubject clazz, MethodSubject method) {
    Set<InstructionSubject> result = Sets.newIdentityHashSet();
    getConstStringInstructions(method)
        .forEach(
            instr -> {
              String cnstString =
                  ((ConstStringInstructionSubject) instr).getString().toSourceString();
              clazz.forAllMethods(
                  foundMethodSubject -> {
                    if (foundMethodSubject.getFinalSignature().name.equals(cnstString)) {
                      result.add(instr);
                    }
                  });
              clazz.forAllFields(
                  foundFieldSubject -> {
                    if (foundFieldSubject.getFinalSignature().name.equals(cnstString)) {
                      result.add(instr);
                    }
                  });
            });
    return result;
  }
}
