// Copyright (c) 2019, 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.shaking.array;

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

import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NeverPropagateValue;
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.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

@RunWith(Parameterized.class)
public class DeadArrayLengthTest extends TestBase {
  private static final Class<?> MAIN = TestClass.class;
  private static final String EXPECTED_OUTPUT = StringUtils.lines("1", "Expected NPE", "3");

  private final TestParameters parameters;

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

  public DeadArrayLengthTest(TestParameters parameters) {
    this.parameters = parameters;
  }

  private void inspect(CodeInspector inspector, boolean isR8) {
    ClassSubject main = inspector.clazz(MAIN);
    assertThat(main, isPresent());

    MethodSubject nonNull = main.uniqueMethodWithName("clearlyNonNull");
    assertThat(nonNull, isPresent());
    assertEquals(0, countArrayLength(nonNull));

    MethodSubject nullable = main.uniqueMethodWithName("isNullable");
    if (isR8) {
      // Replaced with null-throwing code at the call site.
      assertThat(nullable, not(isPresent()));
    } else {
      assertThat(nullable, isPresent());
      assertEquals(1, countArrayLength(nullable));
    }

    MethodSubject nullCheck = main.uniqueMethodWithName("afterNullCheck");
    assertThat(nullCheck, isPresent());
    assertEquals(isR8 ? 0 : 1, countArrayLength(nullCheck));
  }

  private long countArrayLength(MethodSubject method) {
    return method.streamInstructions().filter(InstructionSubject::isArrayLength).count();
  }

  @Test
  public void testD8() throws Exception {
    assumeTrue(parameters.isDexRuntime());
    testForD8()
        .release()
        .addProgramClasses(MAIN)
        .setMinApi(parameters.getRuntime())
        .run(parameters.getRuntime(), MAIN)
        .assertSuccessWithOutput(EXPECTED_OUTPUT)
        .inspect(codeInspector -> inspect(codeInspector, false));
  }

  @Test
  public void testR8() throws Exception {
    testForR8(parameters.getBackend())
        .addProgramClasses(MAIN)
        .addKeepMainRule(MAIN)
        .enableInliningAnnotations()
        .enableMemberValuePropagationAnnotations()
        .noMinification()
        .setMinApi(parameters.getRuntime())
        .run(parameters.getRuntime(), MAIN)
        .assertSuccessWithOutput(EXPECTED_OUTPUT)
        .inspect(codeInspector -> inspect(codeInspector, true));
  }

  static class TestClass {
    @NeverInline
    @NeverPropagateValue
    static int clearlyNonNull(int size) {
      int[] array = new int[size];
      int l = array.length;
      return System.currentTimeMillis() > 0 ? 1 : -1;
    }

    @NeverInline
    @NeverPropagateValue
    static int isNullable(int[] args) {
      // Not used, but can't be dead due to the potential NPE.
      int l = args.length;
      return System.currentTimeMillis() > 0 ? 2 : -2;
    }

    @NeverInline
    @NeverPropagateValue
    static int afterNullCheck(int[] args) {
      if (args != null) {
        // Can be removed.
        int l = args.length;
        return System.currentTimeMillis() > 0 ? 8 : -8;
      }
      return System.currentTimeMillis() > 0 ? 3 : -3;
    }

    public static void main(String[] args) {
      System.out.println(clearlyNonNull(args.length));
      try {
        System.out.println(isNullable(null));
        throw new AssertionError("Expect to see NPE");
      } catch (NullPointerException npe) {
        System.out.println("Expected NPE");
      }
      try {
        System.out.println(afterNullCheck(null));
      } catch (NullPointerException npe) {
        throw new AssertionError("Not expect to see NPE");
      }
    }
  }
}
