// 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()
            .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() ? 2 : 1;
    test1_rules(inspector, expectedRenamedIdentifierInMain, 0, 0);
  }

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

  // With -adaptclassstrings (no filter)
  private static void test1_rule3(TestParameters parameters, CodeInspector inspector) {
    int expectedRenamedIdentifierInMain = parameters.isCfRuntime() ? 3 : 2;
    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.uniqueMethodWithName("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.uniqueMethodWithName("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;
  }
}
