// 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()
          .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.getApiLevel())
            .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.getOriginalName().startsWith("testRewriteInvoke")) {
        boolean shouldHaveThrow = !methodSubject.getOriginalName().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.uniqueMethodWithName("live"), isPresent());
    assertThat(testClassSubject.uniqueMethodWithName("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.uniqueMethodWithName(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 {}
}
