Add more Kotlin accessor tests

Adds tests for accessor methods to regular properties and
user-defined properties using lambdas.

Bug: 70158739
Bug: 74103342
Change-Id: Id39ef5c7d2cdbd546a000066d13b727095da5d1a
diff --git a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
index 85f2eb5..1419b95 100644
--- a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
@@ -119,8 +119,8 @@
   protected static FieldSubject checkFieldIsPresent(ClassSubject classSubject, String fieldType,
       String fieldName) {
     FieldSubject fieldSubject = classSubject.field(fieldType, fieldName);
-    assertNotNull(fieldSubject);
-    assertTrue(fieldSubject.isPresent());
+    assertTrue("No field " + fieldName + " in " + classSubject.getOriginalName(),
+        fieldSubject.isPresent());
     return fieldSubject;
   }
 
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
index fbb14f1..254899d 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
@@ -4,12 +4,15 @@
 
 package com.android.tools.r8.kotlin;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.jasmin.JasminBuilder;
 import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
+import com.android.tools.r8.kotlin.TestKotlinClass.AccessorKind;
 import com.android.tools.r8.kotlin.TestKotlinClass.Visibility;
 import com.android.tools.r8.naming.MemberNaming;
 import com.android.tools.r8.utils.AndroidApp;
@@ -19,6 +22,7 @@
 import java.nio.file.Path;
 import java.util.Collections;
 import org.junit.Assert;
+import org.junit.Ignore;
 import org.junit.Test;
 
 public class R8KotlinAccessorTest extends AbstractR8KotlinTestBase {
@@ -39,24 +43,38 @@
           .addProperty("publicProp", JAVA_LANG_STRING, Visibility.PUBLIC)
           .addProperty("primitiveProp", "int", Visibility.PUBLIC);
 
+  private static final TestKotlinCompanionClass COMPANION_LATE_INIT_PROPERTY_CLASS =
+      new TestKotlinCompanionClass("properties.CompanionLateInitProperties")
+          .addProperty("privateLateInitProp", JAVA_LANG_STRING, Visibility.PRIVATE)
+          .addProperty("internalLateInitProp", JAVA_LANG_STRING, Visibility.INTERNAL)
+          .addProperty("publicLateInitProp", JAVA_LANG_STRING, Visibility.PUBLIC);
+
+  private static final TestKotlinClass PROPERTY_ACCESS_FOR_INNER_CLASS =
+      new TestKotlinClass("accessors.PropertyAccessorForInnerClass")
+          .addProperty("privateProp", JAVA_LANG_STRING, Visibility.PRIVATE)
+          .addProperty("privateLateInitProp", JAVA_LANG_STRING, Visibility.PRIVATE);
+
+  private static final TestKotlinClass PROPERTY_ACCESS_FOR_LAMBDA_CLASS =
+      new TestKotlinClass("accessors.PropertyAccessorForLambda")
+          .addProperty("property", JAVA_LANG_STRING, Visibility.PRIVATE)
+          .addProperty("indirectPropertyGetter", JAVA_LANG_STRING, Visibility.PRIVATE);
+
   @Test
   public void testCompanionProperty_primitivePropertyIsAlwaysInlined() throws Exception {
+    final TestKotlinCompanionClass testedClass = COMPANION_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionPropertiesKt",
         "companionProperties_usePrimitiveProp");
     runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> {
       DexInspector dexInspector = new DexInspector(app);
-      ClassSubject outerClass = checkClassExists(dexInspector,
-          COMPANION_PROPERTY_CLASS.getOuterClassName());
+      ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
       String propertyName = "primitiveProp";
       FieldSubject fieldSubject = checkFieldIsPresent(outerClass, "int", propertyName);
       assertTrue(fieldSubject.getField().accessFlags.isStatic());
 
-      MemberNaming.MethodSignature getterAccessor =
-          new MemberNaming.MethodSignature("access$getPrimitiveProp$cp", "int",
-              Collections.emptyList());
-      MemberNaming.MethodSignature setterAccessor =
-          new MemberNaming.MethodSignature("access$setPrimitiveProp$cp", "void",
-              Collections.singletonList("int"));
+      MemberNaming.MethodSignature getterAccessor = testedClass
+          .getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
+      MemberNaming.MethodSignature setterAccessor = testedClass
+          .getSetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
 
       if (allowAccessModification) {
         assertTrue(fieldSubject.getField().accessFlags.isPublic());
@@ -72,22 +90,20 @@
 
   @Test
   public void testCompanionProperty_privatePropertyIsAlwaysInlined() throws Exception {
-    String mainClass = addMainToClasspath(
-        "properties.CompanionPropertiesKt", "companionProperties_usePrivateProp");
+    final TestKotlinCompanionClass testedClass = COMPANION_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath("properties.CompanionPropertiesKt",
+        "companionProperties_usePrivateProp");
     runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> {
       DexInspector dexInspector = new DexInspector(app);
-      ClassSubject outerClass = checkClassExists(dexInspector,
-          COMPANION_PROPERTY_CLASS.getOuterClassName());
+      ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
       String propertyName = "privateProp";
       FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
       assertTrue(fieldSubject.getField().accessFlags.isStatic());
 
-      MemberNaming.MethodSignature getterAccessor =
-          new MemberNaming.MethodSignature("access$getPrivateProp$cp", JAVA_LANG_STRING,
-              Collections.emptyList());
-      MemberNaming.MethodSignature setterAccessor =
-          new MemberNaming.MethodSignature("access$setPrivateProp$cp", "void",
-              Collections.singletonList(JAVA_LANG_STRING));
+      MemberNaming.MethodSignature getterAccessor = testedClass
+          .getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
+      MemberNaming.MethodSignature setterAccessor = testedClass
+          .getSetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
       if (allowAccessModification) {
         assertTrue(fieldSubject.getField().accessFlags.isPublic());
 
@@ -104,22 +120,20 @@
 
   @Test
   public void testCompanionProperty_internalPropertyIsAlwaysInlined() throws Exception {
-    String mainClass = addMainToClasspath(
-        "properties.CompanionPropertiesKt", "companionProperties_useInternalProp");
+    final TestKotlinCompanionClass testedClass = COMPANION_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath("properties.CompanionPropertiesKt",
+        "companionProperties_useInternalProp");
     runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> {
       DexInspector dexInspector = new DexInspector(app);
-      ClassSubject outerClass = checkClassExists(dexInspector,
-          COMPANION_PROPERTY_CLASS.getOuterClassName());
+      ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
       String propertyName = "internalProp";
       FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
       assertTrue(fieldSubject.getField().accessFlags.isStatic());
 
-      MemberNaming.MethodSignature getterAccessor =
-          new MemberNaming.MethodSignature("access$getInternalProp$cp", JAVA_LANG_STRING,
-              Collections.emptyList());
-      MemberNaming.MethodSignature setterAccessor =
-          new MemberNaming.MethodSignature("access$setInternalProp$cp", "void",
-              Collections.singletonList(JAVA_LANG_STRING));
+      MemberNaming.MethodSignature getterAccessor = testedClass
+          .getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
+      MemberNaming.MethodSignature setterAccessor = testedClass
+          .getSetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
 
       if (allowAccessModification) {
         assertTrue(fieldSubject.getField().accessFlags.isPublic());
@@ -135,22 +149,20 @@
 
   @Test
   public void testCompanionProperty_publicPropertyIsAlwaysInlined() throws Exception {
+    final TestKotlinCompanionClass testedClass = COMPANION_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionPropertiesKt",
         "companionProperties_usePublicProp");
     runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> {
       DexInspector dexInspector = new DexInspector(app);
-      ClassSubject outerClass = checkClassExists(dexInspector,
-          COMPANION_PROPERTY_CLASS.getOuterClassName());
+      ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
       String propertyName = "publicProp";
       FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
       assertTrue(fieldSubject.getField().accessFlags.isStatic());
 
-      MemberNaming.MethodSignature getterAccessor =
-          new MemberNaming.MethodSignature("access$getPublicProp$cp", JAVA_LANG_STRING,
-              Collections.emptyList());
-      MemberNaming.MethodSignature setterAccessor =
-          new MemberNaming.MethodSignature("access$setPublicProp$cp", "void",
-              Collections.singletonList(JAVA_LANG_STRING));
+      MemberNaming.MethodSignature getterAccessor = testedClass
+          .getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
+      MemberNaming.MethodSignature setterAccessor = testedClass
+          .getSetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
 
       if (allowAccessModification) {
         assertTrue(fieldSubject.getField().accessFlags.isPublic());
@@ -165,28 +177,98 @@
   }
 
   @Test
+  public void testCompanionLateInitProperty_privatePropertyIsAlwaysInlined() throws Exception {
+    final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt",
+        "companionLateInitProperties_usePrivateLateInitProp");
+    runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
+      String propertyName = "privateLateInitProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
+      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+
+      MemberNaming.MethodSignature getterAccessor = testedClass
+          .getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
+      MemberNaming.MethodSignature setterAccessor = testedClass
+          .getSetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
+      if (allowAccessModification) {
+        assertTrue(fieldSubject.getField().accessFlags.isPublic());
+        checkMethodIsAbsent(outerClass, getterAccessor);
+        checkMethodIsAbsent(outerClass, setterAccessor);
+      } else {
+        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+        checkMethodIsPresent(outerClass, getterAccessor);
+        checkMethodIsPresent(outerClass, setterAccessor);
+      }
+    });
+  }
+
+  @Test
+  public void testCompanionLateInitProperty_internalPropertyIsAlwaysInlined() throws Exception {
+    final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt",
+        "companionLateInitProperties_useInternalLateInitProp");
+    runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
+      String propertyName = "internalLateInitProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
+      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+
+      MemberNaming.MethodSignature getterAccessor = testedClass
+          .getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
+      MemberNaming.MethodSignature setterAccessor = testedClass
+          .getSetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
+
+      assertTrue(fieldSubject.getField().accessFlags.isPublic());
+      checkMethodIsAbsent(outerClass, getterAccessor);
+      checkMethodIsAbsent(outerClass, setterAccessor);
+    });
+  }
+
+  @Test
+  public void testCompanionLateInitProperty_publicPropertyIsAlwaysInlined() throws Exception {
+    final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt",
+        "companionLateInitProperties_usePublicLateInitProp");
+    runTest(PROPERTIES_PACKAGE_NAME, mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
+      String propertyName = "publicLateInitProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
+      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+
+      MemberNaming.MethodSignature getterAccessor = testedClass
+          .getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
+      MemberNaming.MethodSignature setterAccessor = testedClass
+          .getSetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
+
+      assertTrue(fieldSubject.getField().accessFlags.isPublic());
+      checkMethodIsAbsent(outerClass, getterAccessor);
+      checkMethodIsAbsent(outerClass, setterAccessor);
+    });
+  }
+
+  @Test
   public void testAccessor() throws Exception {
+    TestKotlinCompanionClass testedClass = ACCESSOR_COMPANION_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("accessors.AccessorKt",
-        "accessor_accessCompanionPrivate");
+        "accessor_accessPropertyFromCompanionClass");
     runTest("accessors", mainClass, (app) -> {
       DexInspector dexInspector = new DexInspector(app);
-      TestKotlinCompanionClass testedClass = ACCESSOR_COMPANION_PROPERTY_CLASS;
-      ClassSubject outerClass = checkClassExists(dexInspector,
-          testedClass.getOuterClassName());
-      ClassSubject companionClass = checkClassExists(dexInspector,
-          testedClass.getClassName());
+      ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
+      ClassSubject companionClass = checkClassExists(dexInspector, testedClass.getClassName());
       String propertyName = "property";
       FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
       assertTrue(fieldSubject.getField().accessFlags.isStatic());
 
       // The getter is always inlined since it just calls into the accessor.
-      MemberNaming.MethodSignature getter = testedClass
-          .getGetterForProperty(propertyName);
+      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
       checkMethodIsAbsent(companionClass, getter);
 
       MemberNaming.MethodSignature getterAccessor =
-          new MemberNaming.MethodSignature("access$getProperty$cp", JAVA_LANG_STRING,
-              Collections.emptyList());
+          testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_COMPANION);
       if (allowAccessModification) {
         assertTrue(fieldSubject.getField().accessFlags.isPublic());
         checkMethodIsAbsent(outerClass, getterAccessor);
@@ -198,6 +280,169 @@
   }
 
   @Test
+  public void testAccessorFromPrivate() throws Exception {
+    TestKotlinCompanionClass testedClass = ACCESSOR_COMPANION_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath("accessors.AccessorKt",
+        "accessor_accessPropertyFromOuterClass");
+    runTest("accessors", mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject outerClass = checkClassExists(dexInspector, testedClass.getOuterClassName());
+      ClassSubject companionClass = checkClassExists(dexInspector, testedClass.getClassName());
+      String propertyName = "property";
+      FieldSubject fieldSubject = checkFieldIsPresent(outerClass, JAVA_LANG_STRING, propertyName);
+      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+
+      // We cannot inline the getter because we don't know if NPE is preserved.
+      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+      checkMethodIsPresent(companionClass, getter);
+
+      // We should always inline the static accessor method.
+      MemberNaming.MethodSignature getterAccessor =
+          testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER);
+      checkMethodIsAbsent(outerClass, getterAccessor);
+
+      if (allowAccessModification) {
+        assertTrue(fieldSubject.getField().accessFlags.isPublic());
+      } else {
+        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+      }
+    });
+  }
+
+  @Test
+  public void testAccessorForInnerClassIsRemovedWhenNotUsed() throws Exception {
+    TestKotlinClass testedClass = PROPERTY_ACCESS_FOR_INNER_CLASS;
+    String mainClass = addMainToClasspath(testedClass.className + "Kt",
+        "noUseOfPropertyAccessorFromInnerClass");
+    runTest("accessors", mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject classSubject = checkClassExists(dexInspector, testedClass.getClassName());
+
+      for (String propertyName : testedClass.properties.keySet()) {
+        MemberNaming.MethodSignature getterAccessor =
+            testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER);
+        MemberNaming.MethodSignature setterAccessor =
+            testedClass.getSetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER);
+
+        checkMethodIsAbsent(classSubject, getterAccessor);
+        checkMethodIsAbsent(classSubject, setterAccessor);
+      }
+    });
+  }
+
+  @Test
+  @Ignore("b/74103342")
+  public void testPrivatePropertyAccessorForInnerClassCanBeInlined() throws Exception {
+    TestKotlinClass testedClass = PROPERTY_ACCESS_FOR_INNER_CLASS;
+    String mainClass = addMainToClasspath(testedClass.className + "Kt",
+        "usePrivatePropertyAccessorFromInnerClass");
+    runTest("accessors", mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject classSubject = checkClassExists(dexInspector, testedClass.getClassName());
+
+      String propertyName = "privateProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(classSubject, JAVA_LANG_STRING,
+          propertyName);
+      assertFalse(fieldSubject.getField().accessFlags.isStatic());
+
+      MemberNaming.MethodSignature getterAccessor =
+          testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER);
+      MemberNaming.MethodSignature setterAccessor =
+          testedClass.getSetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER);
+      if (allowAccessModification) {
+        assertTrue(fieldSubject.getField().accessFlags.isPublic());
+        checkMethodIsAbsent(classSubject, getterAccessor);
+        checkMethodIsAbsent(classSubject, setterAccessor);
+      } else {
+        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+        checkMethodIsPresent(classSubject, getterAccessor);
+        checkMethodIsPresent(classSubject, setterAccessor);
+      }
+    });
+  }
+
+  @Test
+  @Ignore("b/74103342")
+  public void testPrivateLateInitPropertyAccessorForInnerClassCanBeInlined() throws Exception {
+    TestKotlinClass testedClass = PROPERTY_ACCESS_FOR_INNER_CLASS;
+    String mainClass = addMainToClasspath(testedClass.className + "Kt",
+        "usePrivateLateInitPropertyAccessorFromInnerClass");
+    runTest("accessors", mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject classSubject = checkClassExists(dexInspector, testedClass.getClassName());
+
+      String propertyName = "privateLateInitProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(classSubject, JAVA_LANG_STRING,
+          propertyName);
+      assertFalse(fieldSubject.getField().accessFlags.isStatic());
+
+      MemberNaming.MethodSignature getterAccessor =
+          testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER);
+      MemberNaming.MethodSignature setterAccessor =
+          testedClass.getSetterAccessorForProperty(propertyName, AccessorKind.FROM_INNER);
+      if (allowAccessModification) {
+        assertTrue(fieldSubject.getField().accessFlags.isPublic());
+        checkMethodIsAbsent(classSubject, getterAccessor);
+        checkMethodIsAbsent(classSubject, setterAccessor);
+      } else {
+        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+        checkMethodIsPresent(classSubject, getterAccessor);
+        checkMethodIsPresent(classSubject, setterAccessor);
+      }
+    });
+  }
+
+  @Test
+  @Ignore("b/74103342")
+  public void testAccessorForLambdaIsRemovedWhenNotUsed() throws Exception {
+    TestKotlinClass testedClass = PROPERTY_ACCESS_FOR_LAMBDA_CLASS;
+    String mainClass = addMainToClasspath(testedClass.className + "Kt",
+        "noUseOfPropertyAccessorFromLambda");
+    runTest("accessors", mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject classSubject = checkClassExists(dexInspector, testedClass.getClassName());
+      String propertyName = "property";
+
+      MemberNaming.MethodSignature getterAccessor =
+          testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_LAMBDA);
+      MemberNaming.MethodSignature setterAccessor =
+          testedClass.getSetterAccessorForProperty(propertyName, AccessorKind.FROM_LAMBDA);
+
+      checkMethodIsAbsent(classSubject, getterAccessor);
+      checkMethodIsAbsent(classSubject, setterAccessor);
+    });
+  }
+
+  @Test
+  @Ignore("b/74103342")
+  public void testAccessorForLambdaCanBeInlined() throws Exception {
+    TestKotlinClass testedClass = PROPERTY_ACCESS_FOR_LAMBDA_CLASS;
+    String mainClass = addMainToClasspath(testedClass.className + "Kt",
+        "usePropertyAccessorFromLambda");
+    runTest("accessors", mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject classSubject = checkClassExists(dexInspector, testedClass.getClassName());
+      String propertyName = "property";
+      FieldSubject fieldSubject = checkFieldIsPresent(classSubject, JAVA_LANG_STRING, propertyName);
+      assertFalse(fieldSubject.getField().accessFlags.isStatic());
+
+      MemberNaming.MethodSignature getterAccessor =
+          testedClass.getGetterAccessorForProperty(propertyName, AccessorKind.FROM_LAMBDA);
+      MemberNaming.MethodSignature setterAccessor =
+          testedClass.getSetterAccessorForProperty(propertyName, AccessorKind.FROM_LAMBDA);
+      if (allowAccessModification) {
+        assertTrue(fieldSubject.getField().accessFlags.isPublic());
+        checkMethodIsAbsent(classSubject, getterAccessor);
+        checkMethodIsAbsent(classSubject, setterAccessor);
+      } else {
+        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+        checkMethodIsPresent(classSubject, getterAccessor);
+        checkMethodIsPresent(classSubject, setterAccessor);
+      }
+    });
+  }
+
+  @Test
   public void testStaticFieldAccessorWithJasmin() throws Exception {
     JasminBuilder jasminBuilder = new JasminBuilder();
     ClassBuilder classBuilder = jasminBuilder.addClass("Foo");
@@ -228,13 +473,11 @@
     if (javaResult.exitCode != 0) {
       System.err.println(javaResult.stderr);
       Assert.fail();
-    } else {
-      System.out.println(javaResult.stdout);
     }
 
     AndroidApp app = compileWithR8(jasminBuilder.build(),
         keepMainProguardConfiguration("Foo") + "\ndontobfuscate");
     String artOutput = runOnArt(app, "Foo");
-    System.out.println(artOutput);
+    assertEquals(javaResult.stdout, artOutput);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/kotlin/TestKotlinClass.java b/src/test/java/com/android/tools/r8/kotlin/TestKotlinClass.java
index d364bb8..5de3c43 100644
--- a/src/test/java/com/android/tools/r8/kotlin/TestKotlinClass.java
+++ b/src/test/java/com/android/tools/r8/kotlin/TestKotlinClass.java
@@ -5,8 +5,10 @@
 package com.android.tools.r8.kotlin;
 
 import com.android.tools.r8.naming.MemberNaming;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Maps;
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -32,6 +34,22 @@
     PRIVATE;
   }
 
+  enum AccessorKind {
+    FROM_COMPANION("cp"),
+    FROM_INNER("p"),
+    FROM_LAMBDA("lp");
+
+    private final String accessorSuffix;
+
+    AccessorKind(String accessorSuffix) {
+      this.accessorSuffix = accessorSuffix;
+    }
+
+    public String getAccessorSuffix() {
+      return accessorSuffix;
+    }
+  }
+
   protected static class KotlinProperty {
     private final String name;
     private final String type;
@@ -117,4 +135,52 @@
         Collections.singleton(property.getType()));
   }
 
+  // TODO(shertz) refactor to avoid duplicated code with getGetterForProperty.
+  public MemberNaming.MethodSignature getGetterAccessorForProperty(String propertyName,
+      AccessorKind accessorKind) {
+    KotlinProperty property = getProperty(propertyName);
+    String type = property.type;
+    String getterName;
+    if (propertyName.length() > 2 && propertyName.startsWith("is")
+        && (propertyName.charAt(2) == '_' || Character.isUpperCase(propertyName.charAt(2)))) {
+      // Getter for property "isAbc" is "isAbc".
+      getterName = propertyName;
+    } else {
+      // Getter for property "abc" is "getAbc".
+      getterName =
+          "get" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
+    }
+    // Unlike normal getter, module name is not appended for accessor method of internal property.
+    getterName = wrapWithAccessorPrefixAndSuffix(accessorKind, getterName);
+    List<String> argumentTypes;
+    if (accessorKind != AccessorKind.FROM_COMPANION) {
+      argumentTypes = ImmutableList.of(getClassName());
+    } else {
+      argumentTypes = ImmutableList.of();
+    }
+    return new MemberNaming.MethodSignature(getterName, type, argumentTypes);
+  }
+
+  // TODO(shertz) refactor to avoid duplicated code with getSetterForProperty.
+  public MemberNaming.MethodSignature getSetterAccessorForProperty(String propertyName,
+      AccessorKind accessorKind) {
+    KotlinProperty property = getProperty(propertyName);
+    String setterName = "set"
+        + Character.toUpperCase(property.name.charAt(0))
+        + property.name.substring(1);
+    // Unlike normal setter, module name is not appended for accessor method of internal property.
+    setterName = wrapWithAccessorPrefixAndSuffix(accessorKind, setterName);
+    List<String> argumentTypes;
+    if (accessorKind != AccessorKind.FROM_COMPANION) {
+      argumentTypes = ImmutableList.of(getClassName(), property.getType());
+    } else {
+      argumentTypes = ImmutableList.of(property.getType());
+    }
+    return new MemberNaming.MethodSignature(setterName, "void", argumentTypes);
+  }
+
+  private String wrapWithAccessorPrefixAndSuffix(AccessorKind accessorKind, String methodName) {
+    return "access$" + methodName + "$" + accessorKind.getAccessorSuffix();
+  }
+
 }
diff --git a/src/test/kotlinR8TestResources/accessors/Accessor.kt b/src/test/kotlinR8TestResources/accessors/Accessor.kt
index e88a055..ffd0395 100644
--- a/src/test/kotlinR8TestResources/accessors/Accessor.kt
+++ b/src/test/kotlinR8TestResources/accessors/Accessor.kt
@@ -8,12 +8,20 @@
     companion object {
         private val property = "foo"
 
-        fun printProperty() {
+        fun accessPropertyFromCompanionClass() {
             println(property)
         }
     }
+
+    fun accessPropertyFromOuterClass() {
+        println(property)
+    }
 }
 
-fun accessor_accessCompanionPrivate() {
-    Accessor.printProperty()
+fun accessor_accessPropertyFromCompanionClass() {
+    Accessor.accessPropertyFromCompanionClass()
+}
+
+fun accessor_accessPropertyFromOuterClass() {
+    Accessor().accessPropertyFromOuterClass()
 }
\ No newline at end of file
diff --git a/src/test/kotlinR8TestResources/accessors/PropertyAccessorForInnerClass.kt b/src/test/kotlinR8TestResources/accessors/PropertyAccessorForInnerClass.kt
new file mode 100644
index 0000000..a2dd823
--- /dev/null
+++ b/src/test/kotlinR8TestResources/accessors/PropertyAccessorForInnerClass.kt
@@ -0,0 +1,44 @@
+// 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 accessors
+
+class PropertyAccessorForInnerClass {
+    private var privateProp = "private"
+
+    private lateinit var privateLateInitProp: String
+
+    // Causes a class initializer to be added to the class.
+    companion object {
+        public var companionProperty = "static"
+    }
+
+    inner class Inner {
+        fun accessPrivateProperty() {
+            privateProp = "bar"
+            println(privateProp)
+        }
+
+        fun accessPrivateLateInitPropertyStatus() {
+            println(::privateLateInitProp.isInitialized)
+        }
+    }
+}
+
+fun noUseOfPropertyAccessorFromInnerClass() {
+    // Create instance of class to keep them after tree shaking.
+    PropertyAccessorForInnerClass().Inner()
+}
+
+fun usePrivatePropertyAccessorFromInnerClass() {
+    // Creates a non-trivial class initializer
+    println(PropertyAccessorForInnerClass.companionProperty)
+    PropertyAccessorForInnerClass().Inner().accessPrivateProperty()
+}
+
+fun usePrivateLateInitPropertyAccessorFromInnerClass() {
+    // Creates a non-trivial class initializer
+    println(PropertyAccessorForInnerClass.companionProperty)
+    PropertyAccessorForInnerClass().Inner().accessPrivateLateInitPropertyStatus()
+}
\ No newline at end of file
diff --git a/src/test/kotlinR8TestResources/accessors/PropertyAccessorForLambda.kt b/src/test/kotlinR8TestResources/accessors/PropertyAccessorForLambda.kt
new file mode 100644
index 0000000..28bed0a
--- /dev/null
+++ b/src/test/kotlinR8TestResources/accessors/PropertyAccessorForLambda.kt
@@ -0,0 +1,33 @@
+// 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 accessors
+
+class PropertyAccessorForLambda {
+    private var property: String = "foo"
+        get() = { field }()
+        set(v) = { field = v }()
+
+    // Causes a class initializer to be added to the class.
+    companion object {
+        public var companionProperty = "static"
+    }
+
+    fun accessPropertyOfOuterClass() {
+        // Access to the property requires to go through an accessor method, respectively
+        // named "access$getProperty$lp" for getter and "access$setProperty$lp" for setter).
+        property = "bar"
+        println(property)
+    }
+}
+
+fun noUseOfPropertyAccessorFromLambda() {
+    // Create instance of class to keep them after tree shaking.
+    PropertyAccessorForLambda()
+}
+
+fun usePropertyAccessorFromLambda() {
+    PropertyAccessorForLambda.companionProperty = "fake"
+    PropertyAccessorForLambda().accessPropertyOfOuterClass()
+}
\ No newline at end of file