// 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.ir.analysis.type;

import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
import static com.android.tools.r8.ir.analysis.type.TypeElement.fromDexType;
import static com.android.tools.r8.ir.analysis.type.TypeElement.stringClassType;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.code.Argument;
import com.android.tools.r8.ir.code.ArrayGet;
import com.android.tools.r8.ir.code.Assume;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InstanceGet;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InvokeMethodWithReceiver;
import com.android.tools.r8.ir.code.InvokeVirtual;
import com.android.tools.r8.ir.code.NewInstance;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.optimize.NonNullTracker;
import com.android.tools.r8.ir.optimize.NonNullTrackerTestBase;
import com.android.tools.r8.ir.optimize.nonnull.FieldAccessTest;
import com.android.tools.r8.ir.optimize.nonnull.NonNullAfterArrayAccess;
import com.android.tools.r8.ir.optimize.nonnull.NonNullAfterFieldAccess;
import com.android.tools.r8.ir.optimize.nonnull.NonNullAfterInvoke;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import java.util.function.BiConsumer;
import org.junit.Test;

public class NullabilityTest extends NonNullTrackerTestBase {
  private void buildAndTest(
      Class<?> mainClass,
      MethodSignature signature,
      boolean npeCaught,
      BiConsumer<AppView<?>, IRCode> inspector)
      throws Exception {
    AppView<?> appView = build(mainClass);
    CodeInspector codeInspector = new CodeInspector(appView.appInfo().app());
    MethodSubject fooSubject = codeInspector.clazz(mainClass.getName()).method(signature);
    IRCode irCode = fooSubject.buildIR();
    new NonNullTracker(appView).insertAssumeInstructions(irCode);
    inspector.accept(appView, irCode);
    verifyLastInvoke(irCode, npeCaught);
  }

  private static void verifyClassTypeLattice(
      Map<Class<? extends Instruction>, TypeElement> expectedLattices,
      DexType receiverType,
      Value v,
      TypeElement l) {
    // Due to the last invocation that will check nullability of the argument,
    // there is one exceptional mapping to PRIMITIVE.
    if (l.isPrimitiveType()) {
      return;
    }
    assertTrue(l.isClassType());
    ClassTypeElement lattice = l.asClassType();
    // Receiver
    if (lattice.getClassType().equals(receiverType)) {
      assertFalse(l.isNullable());
    } else {
      Instruction definition = v.definition;
      if (definition != null) {
        TypeElement expected = expectedLattices.get(v.definition.getClass());
        if (expected != null) {
          assertEquals(expected, l);
        }
      }
    }
  }

  private void verifyLastInvoke(IRCode code, boolean npeCaught) {
    boolean metInvokeVirtual = false;
    for (Instruction instruction : code.instructions()) {
      if (instruction.isInvokeMethodWithReceiver()) {
        InvokeMethodWithReceiver invoke = instruction.asInvokeMethodWithReceiver();
        if (invoke.getInvokedMethod().name.toString().contains("hash")) {
          metInvokeVirtual = true;
          TypeElement l = invoke.getReceiver().getType();
          assertEquals(npeCaught, l.isNullable());
        }
      }
    }
    assertTrue(metInvokeVirtual);
  }

  private void forEachOutValue(IRCode irCode, BiConsumer<Value, TypeElement> consumer) {
    irCode
        .instructionIterator()
        .forEachRemaining(
            instruction -> {
              Value outValue = instruction.outValue();
              if (outValue != null) {
                TypeElement element = outValue.getType();
                consumer.accept(outValue, element);
              }
            });
  }

  @Test
  public void nonNullAfterSafeInvokes() throws Exception {
    MethodSignature signature =
        new MethodSignature("foo", "int", new String[]{"java.lang.String"});
    buildAndTest(
        NonNullAfterInvoke.class,
        signature,
        false,
        (appInfo, irCode) -> {
          DexType assertionErrorType =
              appInfo.dexItemFactory().createType("Ljava/lang/AssertionError;");
          DexType mainClass =
              appInfo
                  .dexItemFactory()
                  .createType(
                      DescriptorUtils.javaTypeToDescriptor(
                          NonNullAfterInvoke.class.getCanonicalName()));
          Map<Class<? extends Instruction>, TypeElement> expectedLattices =
              ImmutableMap.of(
                  InvokeVirtual.class, stringClassType(appInfo, maybeNull()),
                  Assume.class, stringClassType(appInfo, definitelyNotNull()),
                  NewInstance.class, fromDexType(assertionErrorType, definitelyNotNull(), appInfo));
          forEachOutValue(
              irCode, (v, l) -> verifyClassTypeLattice(expectedLattices, mainClass, v, l));
        });
  }

  @Test
  public void stillNullAfterExceptionCatch_invoke() throws Exception {
    MethodSignature signature =
        new MethodSignature("bar", "int", new String[]{"java.lang.String"});
    buildAndTest(
        NonNullAfterInvoke.class,
        signature,
        true,
        (appInfo, irCode) -> {
          DexType assertionErrorType =
              appInfo.dexItemFactory().createType("Ljava/lang/AssertionError;");
          DexType mainClass =
              appInfo
                  .dexItemFactory()
                  .createType(
                      DescriptorUtils.javaTypeToDescriptor(
                          NonNullAfterInvoke.class.getCanonicalName()));
          Map<Class<? extends Instruction>, TypeElement> expectedLattices =
              ImmutableMap.of(
                  InvokeVirtual.class, stringClassType(appInfo, maybeNull()),
                  Assume.class, stringClassType(appInfo, definitelyNotNull()),
                  NewInstance.class, fromDexType(assertionErrorType, definitelyNotNull(), appInfo));
          forEachOutValue(
              irCode, (v, l) -> verifyClassTypeLattice(expectedLattices, mainClass, v, l));
        });
  }

  @Test
  public void nonNullAfterSafeArrayAccess() throws Exception {
    MethodSignature signature =
        new MethodSignature("foo", "int", new String[]{"java.lang.String[]"});
    buildAndTest(
        NonNullAfterArrayAccess.class,
        signature,
        false,
        (appInfo, irCode) -> {
          DexType assertionErrorType =
              appInfo.dexItemFactory().createType("Ljava/lang/AssertionError;");
          DexType mainClass =
              appInfo
                  .dexItemFactory()
                  .createType(
                      DescriptorUtils.javaTypeToDescriptor(
                          NonNullAfterArrayAccess.class.getCanonicalName()));
          Map<Class<? extends Instruction>, TypeElement> expectedLattices =
              ImmutableMap.of(
                  // An element inside a non-null array could be null.
                  ArrayGet.class,
                      fromDexType(appInfo.dexItemFactory().stringType, maybeNull(), appInfo),
                  NewInstance.class, fromDexType(assertionErrorType, definitelyNotNull(), appInfo));
          forEachOutValue(
              irCode,
              (v, l) -> {
                if (l.isArrayType()) {
                  ArrayTypeElement lattice = l.asArrayType();
                  assertEquals(1, lattice.getNesting());
                  TypeElement elementType = lattice.getMemberType();
                  assertTrue(elementType.isClassType());
                  assertEquals(
                      appInfo.dexItemFactory().stringType,
                      elementType.asClassType().getClassType());
                  assertEquals(v.definition.isArgument(), l.isNullable());
                } else if (l.isClassType()) {
                  verifyClassTypeLattice(expectedLattices, mainClass, v, l);
                }
              });
        });
  }

  @Test
  public void stillNullAfterExceptionCatch_aget() throws Exception {
    MethodSignature signature =
        new MethodSignature("bar", "int", new String[]{"java.lang.String[]"});
    buildAndTest(
        NonNullAfterArrayAccess.class,
        signature,
        true,
        (appInfo, irCode) -> {
          DexType assertionErrorType =
              appInfo.dexItemFactory().createType("Ljava/lang/AssertionError;");
          DexType mainClass =
              appInfo
                  .dexItemFactory()
                  .createType(
                      DescriptorUtils.javaTypeToDescriptor(
                          NonNullAfterArrayAccess.class.getCanonicalName()));
          Map<Class<? extends Instruction>, TypeElement> expectedLattices =
              ImmutableMap.of(
                  // An element inside a non-null array could be null.
                  ArrayGet.class,
                      fromDexType(appInfo.dexItemFactory().stringType, maybeNull(), appInfo),
                  NewInstance.class, fromDexType(assertionErrorType, definitelyNotNull(), appInfo));
          forEachOutValue(
              irCode,
              (v, l) -> {
                if (l.isArrayType()) {
                  ArrayTypeElement lattice = l.asArrayType();
                  assertEquals(1, lattice.getNesting());
                  TypeElement elementTypeLattice = lattice.getMemberType();
                  assertTrue(elementTypeLattice.isClassType());
                  assertEquals(
                      appInfo.dexItemFactory().stringType,
                      elementTypeLattice.asClassType().getClassType());
                  assertEquals(v.definition.isArgument(), l.isNullable());
                } else if (l.isClassType()) {
                  verifyClassTypeLattice(expectedLattices, mainClass, v, l);
                }
              });
        });
  }

  @Test
  public void nonNullAfterSafeFieldAccess() throws Exception {
    MethodSignature signature = new MethodSignature("foo", "int",
        new String[]{FieldAccessTest.class.getCanonicalName()});
    buildAndTest(
        NonNullAfterFieldAccess.class,
        signature,
        false,
        (appInfo, irCode) -> {
          DexType assertionErrorType =
              appInfo.dexItemFactory().createType("Ljava/lang/AssertionError;");
          DexType mainClass =
              appInfo
                  .dexItemFactory()
                  .createType(
                      DescriptorUtils.javaTypeToDescriptor(
                          NonNullAfterFieldAccess.class.getCanonicalName()));
          DexType testClass =
              appInfo
                  .dexItemFactory()
                  .createType(
                      DescriptorUtils.javaTypeToDescriptor(
                          FieldAccessTest.class.getCanonicalName()));
          Map<Class<? extends Instruction>, TypeElement> expectedLattices =
              ImmutableMap.of(
                  Argument.class, fromDexType(testClass, maybeNull(), appInfo),
                  Assume.class, fromDexType(testClass, definitelyNotNull(), appInfo),
                  // instance may not be initialized.
                  InstanceGet.class,
                      fromDexType(appInfo.dexItemFactory().stringType, maybeNull(), appInfo),
                  NewInstance.class, fromDexType(assertionErrorType, definitelyNotNull(), appInfo));
          forEachOutValue(
              irCode, (v, l) -> verifyClassTypeLattice(expectedLattices, mainClass, v, l));
        });
  }

  @Test
  public void stillNullAfterExceptionCatch_iget() throws Exception {
    MethodSignature signature = new MethodSignature("bar", "int",
        new String[]{FieldAccessTest.class.getCanonicalName()});
    buildAndTest(
        NonNullAfterFieldAccess.class,
        signature,
        true,
        (appInfo, irCode) -> {
          DexType assertionErrorType =
              appInfo.dexItemFactory().createType("Ljava/lang/AssertionError;");
          DexType mainClass =
              appInfo
                  .dexItemFactory()
                  .createType(
                      DescriptorUtils.javaTypeToDescriptor(
                          NonNullAfterFieldAccess.class.getCanonicalName()));
          DexType testClass =
              appInfo
                  .dexItemFactory()
                  .createType(
                      DescriptorUtils.javaTypeToDescriptor(
                          FieldAccessTest.class.getCanonicalName()));
          Map<Class<? extends Instruction>, TypeElement> expectedLattices =
              ImmutableMap.of(
                  Argument.class, fromDexType(testClass, maybeNull(), appInfo),
                  Assume.class, fromDexType(testClass, definitelyNotNull(), appInfo),
                  // instance may not be initialized.
                  InstanceGet.class,
                      fromDexType(appInfo.dexItemFactory().stringType, maybeNull(), appInfo),
                  NewInstance.class, fromDexType(assertionErrorType, definitelyNotNull(), appInfo));
          forEachOutValue(
              irCode, (v, l) -> verifyClassTypeLattice(expectedLattices, mainClass, v, l));
        });
  }
}
