// Copyright (c) 2018, 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.ir.optimize.uninstantiatedtypes;

import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertEquals;

import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NoMethodStaticizing;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Streams;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;

/**
 * Similar to {@link InvokeMethodWithReceiverOptimizationTest}, except that all calls to A.method()
 * have a non-null receiver. Instead, this tests checks that the calls to A.method() are rewritten
 * to throw null when the argument passed to A.method() is null, since A.method() throws a Null-
 * PointerException before any other side-effects when its argument is null.
 *
 * <p>See {@link com.android.tools.r8.graph.DexEncodedMethod.OptimizationInfo#nonNullParamHints}.
 */
@RunWith(Parameterized.class)
public class InvokeMethodWithNonNullParamCheckTest extends TestBase {

  @Parameter(0)
  public TestParameters parameters;

  @Parameters(name = "{0}")
  public static TestParametersCollection data() {
    return getTestParameters().withAllRuntimesAndApiLevels().build();
  }

  @Test
  public void test() throws Exception {
    String expected =
        StringUtils.joinLines(
            "Caught NullPointerException from testRewriteInvokeStaticToThrowNull",
            "Caught NullPointerException from testRewriteInvokeVirtualToThrowNull",
            "In TestClass.live(): Static.throwIfFirstIsNull()",
            "In TestClass.live(): Virtual.throwIfFirstIsNull()",
            "Caught NullPointerException from testRewriteInvokeStaticToThrowNull"
                + "WithMultipleArguments",
            "Caught NullPointerException from testRewriteInvokeVirtualToThrowNull"
                + "WithMultipleArguments",
            "In TestClass.live(): Static.throwIfSecondIsNull()",
            "In TestClass.live(): Virtual.throwIfFirstIsNull()",
            "Caught NullPointerException from testRewriteInvokeStaticToThrowNull"
                + "WithCatchHandlers",
            "Caught NullPointerException from testRewriteInvokeVirtualToThrowNull"
                + "WithCatchHandlers",
            "Caught NullPointerException from testRewriteInvokeStaticToThrowNull"
                + "WithDeadCatchHandler",
            "Caught NullPointerException from testRewriteInvokeVirtualToThrowNull"
                + "WithDeadCatchHandler");

    if (parameters.isCfRuntime()) {
      testForJvm(parameters)
          .addTestClasspath()
          .run(parameters.getRuntime(), TestClass.class)
          .assertSuccessWithOutput(expected);
    }

    CodeInspector inspector =
        testForR8(parameters.getBackend())
            .addInnerClasses(InvokeMethodWithNonNullParamCheckTest.class)
            .addKeepMainRule(TestClass.class)
            .enableInliningAnnotations()
            .enableNoMethodStaticizingAnnotations()
            .addOptionsModification(
                options -> {
                  // Avoid that the class inliner inlines testRewriteInvokeVirtualToThrowNullWith-
                  // CatchHandlers(new A()).
                  options.enableClassInlining = false;
                })
            .setMinApi(parameters)
            .run(parameters.getRuntime(), TestClass.class)
            .assertSuccessWithOutput(expected)
            .inspector();

    ClassSubject testClassSubject = inspector.clazz(TestClass.class);
    assertThat(testClassSubject, isPresent());

    ClassSubject staticClassSubject = inspector.clazz(Static.class);
    assertThat(staticClassSubject, isPresent());

    ClassSubject virtualClassSubject = inspector.clazz(Virtual.class);
    assertThat(virtualClassSubject, isPresent());

    // Check that a throw instruction has been inserted into each of the testRewriteInvoke* methods.
    int found = 0;
    for (FoundMethodSubject methodSubject : testClassSubject.allMethods()) {
      if (methodSubject.getOriginalMethodName().startsWith("testRewriteInvoke")) {
        boolean shouldHaveThrow =
            !methodSubject.getOriginalMethodName().contains("NonNullArgument");
        assertEquals(
            shouldHaveThrow,
            Streams.stream(methodSubject.iterateInstructions())
                .anyMatch(InstructionSubject::isThrow));

        if (shouldHaveThrow) {
          // TODO(b/157427150): Check that there are no invoke instructions targeting the methods on
          //  `Static` and `Virtual`. This requires that we know that their methods throw
          //  NullPointerExceptions without messages.
          Streams.stream(methodSubject.iterateInstructions())
              .filter(InstructionSubject::isInvoke)
              .forEach(
                  ins -> {
                    ClassSubject clazz = inspector.clazz(ins.getMethod().holder.toSourceString());
                    // assertNotEquals(clazz.getOriginalName(), Static.class.getTypeName());
                    // assertNotEquals(clazz.getOriginalName(), Virtual.class.getTypeName());
                  });
        }

        found++;
      }
    }
    assertEquals(12, found);

    // Check that the method live() has been kept and that dead() has been removed.
    assertThat(testClassSubject.uniqueMethodWithOriginalName("live"), isPresent());
    assertThat(testClassSubject.uniqueMethodWithOriginalName("dead"), not(isPresent()));

    // Check that the catch handlers for NullPointerException and RuntimeException have not been
    // removed.
    List<String> methodNames =
        ImmutableList.of(
            "handleNullPointerExceptionForInvokeStatic",
            "handleNullPointerExceptionForInvokeVirtual",
            "handleRuntimeExceptionForInvokeStatic",
            "handleRuntimeExceptionForInvokeVirtual");
    for (String methodName : methodNames) {
      assertThat(testClassSubject.uniqueMethodWithOriginalName(methodName), isPresent());
    }
  }

  static class TestClass {

    public static void main(String[] args) {
      try {
        testRewriteInvokeStaticToThrowNull();
      } catch (NullPointerException e) {
        System.out.println("Caught NullPointerException from testRewriteInvokeStaticToThrowNull");
      }

      try {
        testRewriteInvokeVirtualToThrowNull(new Virtual());
      } catch (NullPointerException e) {
        System.out.println("Caught NullPointerException from testRewriteInvokeVirtualToThrowNull");
      }

      testRewriteInvokeStaticToThrowNullWithNonNullArgument();
      testRewriteInvokeVirtualToThrowNullWithNonNullArgument(new Virtual());

      try {
        testRewriteInvokeStaticToThrowNullWithMultipleArguments();
      } catch (NullPointerException e) {
        System.out.println(
            "Caught NullPointerException from testRewriteInvokeStaticToThrowNullWithMultiple"
                + "Arguments");
      }

      try {
        testRewriteInvokeVirtualToThrowNullWithMultipleArguments(new Virtual());
      } catch (NullPointerException e) {
        System.out.println(
            "Caught NullPointerException from testRewriteInvokeVirtualToThrowNullWithMultiple"
                + "Arguments");
      }

      testRewriteInvokeStaticToThrowNullWithMultipleNonNullArguments();
      testRewriteInvokeVirtualToThrowNullWithMultipleNonNullArguments(new Virtual());

      testRewriteInvokeStaticToThrowNullWithCatchHandlers();
      testRewriteInvokeVirtualToThrowNullWithCatchHandlers(new Virtual());

      try {
        testRewriteInvokeStaticToThrowNullWithDeadCatchHandler();
      } catch (NullPointerException e) {
        System.out.println(
            "Caught NullPointerException from "
                + "testRewriteInvokeStaticToThrowNullWithDeadCatchHandler");
      }

      try {
        testRewriteInvokeVirtualToThrowNullWithDeadCatchHandler(new Virtual());
      } catch (NullPointerException e) {
        System.out.print(
            "Caught NullPointerException from "
                + "testRewriteInvokeVirtualToThrowNullWithDeadCatchHandler");
      }
    }

    @NeverInline
    private static void testRewriteInvokeStaticToThrowNull() {
      // Should be rewritten to "throw null".
      String result = Static.throwIfFirstIsNull(null);
      dead(result);
    }

    @NeverInline
    private static void testRewriteInvokeVirtualToThrowNull(Virtual obj) {
      // Should be rewritten to "throw null".
      String result = obj.throwIfFirstIsNull(null);
      dead(result);
    }

    @NeverInline
    private static void testRewriteInvokeStaticToThrowNullWithNonNullArgument() {
      // Should *not* be rewritten to "throw null".
      String result = Static.throwIfFirstIsNull(new Object());
      live(result);
    }

    @NeverInline
    private static void testRewriteInvokeVirtualToThrowNullWithNonNullArgument(Virtual obj) {
      // Should *not* be rewritten to "throw null".
      String result = obj.throwIfFirstIsNull(new Object());
      live(result);
    }

    @NeverInline
    private static void testRewriteInvokeStaticToThrowNullWithMultipleArguments() {
      // Should be rewritten to "throw null".
      String result = Static.throwIfSecondIsNull(new Object(), null, new Object());
      dead(result);
    }

    @NeverInline
    private static void testRewriteInvokeVirtualToThrowNullWithMultipleArguments(Virtual obj) {
      // Should be rewritten to "throw null".
      String result = obj.throwIfSecondIsNull(new Object(), null, new Object());
      dead(result);
    }

    @NeverInline
    private static void testRewriteInvokeStaticToThrowNullWithMultipleNonNullArguments() {
      // Should *not* be rewritten to "throw null".
      String result = Static.throwIfSecondIsNull(new Object(), new Object(), new Object());
      live(result);
    }

    @NeverInline
    private static void testRewriteInvokeVirtualToThrowNullWithMultipleNonNullArguments(
        Virtual obj) {
      // Should *not* be rewritten to "throw null".
      String result = obj.throwIfSecondIsNull(new Object(), new Object(), new Object());
      live(result);
    }

    @NeverInline
    private static void testRewriteInvokeStaticToThrowNullWithCatchHandlers() {
      try {
        // Should be rewritten to "throw null".
        String result = Static.throwIfFirstIsNull(null);
        dead(result);
      } catch (NullPointerException e) {
        // This catch handler cannot be removed.
        handleNullPointerExceptionForInvokeStatic();
      } catch (RuntimeException e) {
        // This catch handler cannot be removed.
        handleRuntimeExceptionForInvokeStatic();
      }
    }

    @NeverInline
    private static void handleNullPointerExceptionForInvokeStatic() {
      System.out.println(
          "Caught NullPointerException from testRewriteInvokeStaticToThrowNullWithCatchHandlers");
    }

    @NeverInline
    private static void handleRuntimeExceptionForInvokeStatic() {
      System.out.println(
          "Caught RuntimeException from testRewriteInvokeStaticToThrowNullWithCatchHandlers");
    }

    @NeverInline
    private static void testRewriteInvokeVirtualToThrowNullWithCatchHandlers(Virtual obj) {
      try {
        // Should be rewritten to "throw null".
        String result = obj.throwIfFirstIsNull(null);
        dead(result);
      } catch (NullPointerException e) {
        // This catch handler cannot be removed.
        handleNullPointerExceptionForInvokeVirtual();
      } catch (RuntimeException e) {
        // This catch handler cannot be removed.
        handleRuntimeExceptionForInvokeVirtual();
      }
    }

    @NeverInline
    private static void handleNullPointerExceptionForInvokeVirtual() {
      System.out.println(
          "Caught NullPointerException from testRewriteInvokeVirtualToThrowNullWithCatchHandlers");
    }

    @NeverInline
    private static void handleRuntimeExceptionForInvokeVirtual() {
      System.out.println(
          "Caught RuntimeException from testRewriteInvokeVirtualToThrowNullWithCatchHandlers");
    }

    @NeverInline
    private static void testRewriteInvokeStaticToThrowNullWithDeadCatchHandler() {
      try {
        // Should be rewritten to "throw null".
        String result = Static.throwIfFirstIsNull(null);
        dead(result);
      } catch (CustomException e) {
        // This catch handler should be removed.
        dead("Caught CustomException in testRewriteInvokeStaticToThrowNullWithDeadCatchHandler");
      }
    }

    @NeverInline
    private static void testRewriteInvokeVirtualToThrowNullWithDeadCatchHandler(Virtual obj) {
      try {
        // Should be rewritten to "throw null".
        String result = obj.throwIfFirstIsNull(null);
        dead(result);
      } catch (CustomException e) {
        // This catch handler should be removed.
        dead("Caught CustomException in testRewriteInvokeVirtualToThrowNullWithDeadCatchHandler");
      }
    }

    @NeverInline
    private static void live(String msg) {
      System.out.println("In TestClass.live(): " + msg);
    }

    @NeverInline
    private static void dead(String msg) {
      System.out.println("In TestClass.dead(): " + msg);
    }
  }

  static class Static {

    @NeverInline
    public static String throwIfFirstIsNull(Object first) {
      if (first == null) {
        throw new NullPointerException();
      }
      return "Static.throwIfFirstIsNull()";
    }

    @NeverInline
    public static String throwIfSecondIsNull(Object first, Object second, Object third) {
      if (second == null) {
        throw new NullPointerException();
      }
      // Use `first` and `third` for something to prevent them from being removed.
      if (System.currentTimeMillis() < 0) {
        System.out.println(first);
        System.out.println(third);
      }
      return "Static.throwIfSecondIsNull()";
    }
  }

  static class Virtual {

    @NeverInline
    @NoMethodStaticizing
    public String throwIfFirstIsNull(Object first) {
      if (first == null) {
        throw new NullPointerException();
      }
      return "Virtual.throwIfFirstIsNull()";
    }

    @NeverInline
    @NoMethodStaticizing
    public String throwIfSecondIsNull(Object first, Object second, Object third) {
      if (second == null) {
        throw new NullPointerException();
      }
      // Use `first` and `third` for something to prevent them from being removed.
      if (System.currentTimeMillis() < 0) {
        System.out.println(first);
        System.out.println(third);
      }
      return "Virtual.throwIfFirstIsNull()";
    }
  }

  static class CustomException extends RuntimeException {}
}
