Merge "Ignore option -mergeinterfacesaggressively"
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 8a46d57..9d6e40d 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -237,7 +237,7 @@
         Path path,
         OutputMode mode,
         boolean consumeDataResources) {
-      return super.createProgramOutputConsumer(path, mode, true);
+      return super.createProgramOutputConsumer(path, mode, false);
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 124bccc..98ed5e9 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
 
   // This field is accessed from release scripts using simple pattern matching.
   // Therefore, changing this field could break our release scripts.
-  public static final String LABEL = "1.2.16-dev";
+  public static final String LABEL = "1.2.17-dev";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/utils/Reporter.java b/src/main/java/com/android/tools/r8/utils/Reporter.java
index 63b95b3..ebb7ce6 100644
--- a/src/main/java/com/android/tools/r8/utils/Reporter.java
+++ b/src/main/java/com/android/tools/r8/utils/Reporter.java
@@ -8,6 +8,8 @@
 import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
 import java.util.ArrayList;
 import java.util.Collection;
 
@@ -80,7 +82,15 @@
       if (errorCount != 0) {
         AbortException abort;
         if (lastError != null && lastError.getDiagnosticMessage() != null) {
-          abort = new AbortException("Error: " + lastError.getDiagnosticMessage());
+          StringBuilder builder = new StringBuilder("Error: ");
+          if (lastError.getOrigin() != Origin.unknown()) {
+            builder.append(lastError.getOrigin()).append(", ");
+          }
+          if (lastError.getPosition() != Position.UNKNOWN) {
+            builder.append(lastError.getPosition()).append(", ");
+          }
+          builder.append(lastError.getDiagnosticMessage());
+          abort = new AbortException(builder.toString());
         } else {
           abort = new AbortException();
         }
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
index cb3820e..73d70e1 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
@@ -57,6 +57,28 @@
           .addProperty("internalLateInitProp", JAVA_LANG_STRING, Visibility.INTERNAL)
           .addProperty("publicLateInitProp", JAVA_LANG_STRING, Visibility.PUBLIC);
 
+  private static final TestKotlinClass OBJECT_PROPERTY_CLASS =
+      new TestKotlinClass("properties.ObjectProperties")
+          .addProperty("privateProp", JAVA_LANG_STRING, Visibility.PRIVATE)
+          .addProperty("protectedProp", JAVA_LANG_STRING, Visibility.PROTECTED)
+          .addProperty("internalProp", JAVA_LANG_STRING, Visibility.INTERNAL)
+          .addProperty("publicProp", JAVA_LANG_STRING, Visibility.PUBLIC)
+          .addProperty("primitiveProp", "int", Visibility.PUBLIC)
+          .addProperty("privateLateInitProp", JAVA_LANG_STRING, Visibility.PRIVATE)
+          .addProperty("internalLateInitProp", JAVA_LANG_STRING, Visibility.INTERNAL)
+          .addProperty("publicLateInitProp", JAVA_LANG_STRING, Visibility.PUBLIC);
+
+  private static final TestFileLevelKotlinClass FILE_PROPERTY_CLASS =
+      new TestFileLevelKotlinClass("properties.FilePropertiesKt")
+          .addProperty("privateProp", JAVA_LANG_STRING, Visibility.PRIVATE)
+          .addProperty("protectedProp", JAVA_LANG_STRING, Visibility.PROTECTED)
+          .addProperty("internalProp", JAVA_LANG_STRING, Visibility.INTERNAL)
+          .addProperty("publicProp", JAVA_LANG_STRING, Visibility.PUBLIC)
+          .addProperty("primitiveProp", "int", Visibility.PUBLIC)
+          .addProperty("privateLateInitProp", JAVA_LANG_STRING, Visibility.PRIVATE)
+          .addProperty("internalLateInitProp", JAVA_LANG_STRING, Visibility.INTERNAL)
+          .addProperty("publicLateInitProp", JAVA_LANG_STRING, Visibility.PUBLIC);
+
   @Test
   public void testMutableProperty_getterAndSetterAreRemoveIfNotUsed() throws Exception {
     String mainClass = addMainToClasspath("properties/MutablePropertyKt",
@@ -537,4 +559,363 @@
       assertTrue(fieldSubject.getField().accessFlags.isPublic());
     });
   }
+
+  @Test
+  public void testObjectClass_primitivePropertyCannotBeInlined() throws Exception {
+    final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath(
+        "properties.ObjectPropertiesKt", "objectProperties_usePrimitiveProp");
+    runTest(PACKAGE_NAME, mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+      String propertyName = "primitiveProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(objectClass, "int", propertyName);
+      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+
+      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+
+      // Getter and setter cannot be inlined when we don't know if null check semantic is
+      // preserved.
+      checkMethodIsPresent(objectClass, getter);
+      checkMethodIsPresent(objectClass, setter);
+      if (allowAccessModification) {
+        assertTrue(fieldSubject.getField().accessFlags.isPublic());
+      } else {
+        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+      }
+    });
+  }
+
+  @Test
+  public void testObjectClass_privatePropertyIsAlwaysInlined() throws Exception {
+    final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath(
+        "properties.ObjectPropertiesKt", "objectProperties_usePrivateProp");
+    runTest(PACKAGE_NAME, mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+      String propertyName = "privateProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+
+      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+
+      // A private property has no getter/setter.
+      checkMethodIsAbsent(objectClass, getter);
+      checkMethodIsAbsent(objectClass, setter);
+
+      if (allowAccessModification) {
+        assertTrue(fieldSubject.getField().accessFlags.isPublic());
+      } else {
+        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+      }
+    });
+  }
+
+  @Test
+  public void testObjectClass_internalPropertyCannotBeInlined() throws Exception {
+    final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath(
+        "properties.ObjectPropertiesKt", "objectProperties_useInternalProp");
+    runTest(PACKAGE_NAME, mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+      String propertyName = "internalProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+
+      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+
+      // Getter and setter cannot be inlined when we don't know if null check semantic is
+      // preserved.
+      checkMethodIsPresent(objectClass, getter);
+      checkMethodIsPresent(objectClass, setter);
+      if (allowAccessModification) {
+        assertTrue(fieldSubject.getField().accessFlags.isPublic());
+      } else {
+        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+      }
+    });
+  }
+
+  @Test
+  public void testObjectClass_publicPropertyCannotBeInlined() throws Exception {
+    final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath(
+        "properties.ObjectPropertiesKt", "objectProperties_usePublicProp");
+    runTest(PACKAGE_NAME, mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+      String propertyName = "publicProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+
+      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+
+      // Getter and setter cannot be inlined when we don't know if null check semantic is
+      // preserved.
+      checkMethodIsPresent(objectClass, getter);
+      checkMethodIsPresent(objectClass, setter);
+      if (allowAccessModification) {
+        assertTrue(fieldSubject.getField().accessFlags.isPublic());
+      } else {
+        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+      }
+    });
+  }
+
+  @Test
+  public void testObjectClass_privateLateInitPropertyIsAlwaysInlined() throws Exception {
+    final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath(
+        "properties.ObjectPropertiesKt", "objectProperties_useLateInitPrivateProp");
+    runTest(PACKAGE_NAME, mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+      String propertyName = "privateLateInitProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+
+      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+
+      // A private property has no getter/setter.
+      checkMethodIsAbsent(objectClass, getter);
+      checkMethodIsAbsent(objectClass, setter);
+
+      if (allowAccessModification) {
+        assertTrue(fieldSubject.getField().accessFlags.isPublic());
+      } else {
+        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+      }
+    });
+  }
+
+  @Test
+  public void testObjectClass_internalLateInitPropertyCannotBeInlined() throws Exception {
+    final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath(
+        "properties.ObjectPropertiesKt", "objectProperties_useLateInitInternalProp");
+    runTest(PACKAGE_NAME, mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+      String propertyName = "internalLateInitProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+
+      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+
+      // Getter and setter cannot be inlined when we don't know if null check semantic is
+      // preserved.
+      checkMethodIsPresent(objectClass, getter);
+      checkMethodIsPresent(objectClass, setter);
+      assertTrue(fieldSubject.getField().accessFlags.isPublic());
+    });
+  }
+
+  @Test
+  public void testObjectClass_publicLateInitPropertyCannotBeInlined() throws Exception {
+    final TestKotlinClass testedClass = OBJECT_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath(
+        "properties.ObjectPropertiesKt", "objectProperties_useLateInitPublicProp");
+    runTest(PACKAGE_NAME, mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+      String propertyName = "publicLateInitProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+
+      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+
+      // Getter and setter cannot be inlined when we don't know if null check semantic is
+      // preserved.
+      checkMethodIsPresent(objectClass, getter);
+      checkMethodIsPresent(objectClass, setter);
+      assertTrue(fieldSubject.getField().accessFlags.isPublic());
+    });
+  }
+
+  @Test
+  public void testFileLevel_primitivePropertyIsInlinedIfAccessIsRelaxed() throws Exception {
+    final TestKotlinClass testedClass = FILE_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath(
+        "properties.FilePropertiesKt", "fileProperties_usePrimitiveProp");
+    runTest(PACKAGE_NAME, mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+      String propertyName = "primitiveProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(objectClass, "int", propertyName);
+      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+
+      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+
+      if (allowAccessModification) {
+        assertTrue(fieldSubject.getField().accessFlags.isPublic());
+        checkMethodIsAbsent(objectClass, getter);
+        checkMethodIsAbsent(objectClass, setter);
+      } else {
+        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+        checkMethodIsPresent(objectClass, getter);
+        checkMethodIsPresent(objectClass, setter);
+      }
+    });
+  }
+
+  @Test
+  public void testFileLevel_privatePropertyIsAlwaysInlined() throws Exception {
+    final TestKotlinClass testedClass = FILE_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath(
+        "properties.FilePropertiesKt", "fileProperties_usePrivateProp");
+    runTest(PACKAGE_NAME, mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+      String propertyName = "privateProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+
+      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+
+      // A private property has no getter/setter.
+      checkMethodIsAbsent(objectClass, getter);
+      checkMethodIsAbsent(objectClass, setter);
+      if (allowAccessModification) {
+        assertTrue(fieldSubject.getField().accessFlags.isPublic());
+      } else {
+        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+      }
+    });
+  }
+
+  @Test
+  public void testFileLevel_internalPropertyGetterIsInlinedIfAccessIsRelaxed() throws Exception {
+    final TestKotlinClass testedClass = FILE_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath(
+        "properties.FilePropertiesKt", "fileProperties_useInternalProp");
+    runTest(PACKAGE_NAME, mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+      String propertyName = "internalProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+
+      // We expect getter to be inlined when access (of the backing field) is relaxed to public.
+      // Note: the setter is considered as a regular method (because of KotlinC adding extra null
+      // checks), thus we cannot say if the setter would be inlined or not by R8.
+      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+      if (allowAccessModification) {
+        assertTrue(fieldSubject.getField().accessFlags.isPublic());
+        checkMethodIsAbsent(objectClass, getter);
+      } else {
+        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+        checkMethodIsPresent(objectClass, getter);
+      }
+    });
+  }
+
+  @Test
+  public void testFileLevel_publicPropertyGetterIsInlinedIfAccessIsRelaxed() throws Exception {
+    final TestKotlinClass testedClass = FILE_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath(
+        "properties.FilePropertiesKt", "fileProperties_usePublicProp");
+    runTest(PACKAGE_NAME, mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+      String propertyName = "publicProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+
+      // We expect getter to be inlined when access (of the backing field) is relaxed to public.
+      // On the other hand, the setter is considered as a regular method (because of null checks),
+      // thus we cannot say if it can be inlined or not.
+      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+
+      if (allowAccessModification) {
+        assertTrue(fieldSubject.getField().accessFlags.isPublic());
+        checkMethodIsAbsent(objectClass, getter);
+      } else {
+        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+        checkMethodIsPresent(objectClass, getter);
+      }
+    });
+  }
+
+  @Test
+  public void testFileLevel_privateLateInitPropertyIsAlwaysInlined() throws Exception {
+    final TestKotlinClass testedClass = FILE_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath(
+        "properties.FilePropertiesKt", "fileProperties_useLateInitPrivateProp");
+    runTest(PACKAGE_NAME, mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject fileClass = checkClassExists(dexInspector, testedClass.getClassName());
+      String propertyName = "privateLateInitProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(fileClass, JAVA_LANG_STRING, propertyName);
+      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+
+      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+
+      // A private property has no getter/setter.
+      checkMethodIsAbsent(fileClass, getter);
+      checkMethodIsAbsent(fileClass, setter);
+      if (allowAccessModification) {
+        assertTrue(fieldSubject.getField().accessFlags.isPublic());
+      } else {
+        assertTrue(fieldSubject.getField().accessFlags.isPrivate());
+      }
+    });
+  }
+
+  @Test
+  public void testFileLevel_internalLateInitPropertyCannotBeInlined() throws Exception {
+    final TestKotlinClass testedClass = FILE_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath(
+        "properties.FilePropertiesKt", "fileProperties_useLateInitInternalProp");
+    runTest(PACKAGE_NAME, mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+      String propertyName = "internalLateInitProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+      assertTrue(fieldSubject.getField().accessFlags.isPublic());
+
+      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+
+      // Field is public and getter is small so we expect to always inline it.
+      checkMethodIsAbsent(objectClass, getter);
+
+      // Setter has null check of new value, thus may not be inlined.
+      checkMethodIsPresent(objectClass, setter);
+    });
+  }
+
+  @Test
+  public void testFileLevel_publicLateInitPropertyCannotBeInlined() throws Exception {
+    final TestKotlinClass testedClass = FILE_PROPERTY_CLASS;
+    String mainClass = addMainToClasspath(
+        "properties.FilePropertiesKt", "fileProperties_useLateInitPublicProp");
+    runTest(PACKAGE_NAME, mainClass, (app) -> {
+      DexInspector dexInspector = new DexInspector(app);
+      ClassSubject objectClass = checkClassExists(dexInspector, testedClass.getClassName());
+      String propertyName = "publicLateInitProp";
+      FieldSubject fieldSubject = checkFieldIsPresent(objectClass, JAVA_LANG_STRING, propertyName);
+      assertTrue(fieldSubject.getField().accessFlags.isStatic());
+
+      MemberNaming.MethodSignature getter = testedClass.getGetterForProperty(propertyName);
+      MemberNaming.MethodSignature setter = testedClass.getSetterForProperty(propertyName);
+
+      checkMethodIsAbsent(objectClass, getter);
+      checkMethodIsPresent(objectClass, setter);
+      assertTrue(fieldSubject.getField().accessFlags.isPublic());
+    });
+  }
+
 }
diff --git a/src/test/java/com/android/tools/r8/kotlin/TestFileLevelKotlinClass.java b/src/test/java/com/android/tools/r8/kotlin/TestFileLevelKotlinClass.java
new file mode 100644
index 0000000..db35897
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/TestFileLevelKotlinClass.java
@@ -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 com.android.tools.r8.kotlin;
+
+import com.android.tools.r8.naming.MemberNaming.MethodSignature;
+
+public class TestFileLevelKotlinClass extends TestKotlinClass {
+
+  public TestFileLevelKotlinClass(String className) {
+    super(className);
+  }
+
+  @Override
+  public TestFileLevelKotlinClass addProperty(String name, String type, Visibility visibility) {
+    return (TestFileLevelKotlinClass) super.addProperty(name, type, visibility);
+  }
+
+  @Override
+  public MethodSignature getGetterForProperty(String propertyName) {
+    KotlinProperty property = getProperty(propertyName);
+    // File-level properties accessor do not apply mangling.
+    return getGetterForProperty(property, false);
+  }
+
+  @Override
+  public MethodSignature getSetterForProperty(String propertyName) {
+    KotlinProperty property = getProperty(propertyName);
+    // File-level properties accessor do not apply mangling.
+    return getSetterForProperty(property, false);
+  }
+}
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 0ec0f64..685df6a 100644
--- a/src/test/java/com/android/tools/r8/kotlin/TestKotlinClass.java
+++ b/src/test/java/com/android/tools/r8/kotlin/TestKotlinClass.java
@@ -104,22 +104,12 @@
 
   public MemberNaming.MethodSignature getGetterForProperty(String propertyName) {
     KotlinProperty property = getProperty(propertyName);
-    String type = property.type;
-    String getterName = computeGetterName(propertyName);
-    if (property.getVisibility() == Visibility.INTERNAL) {
-      getterName = appendInternalSuffix(getterName);
-    }
-    return new MemberNaming.MethodSignature(getterName, type, Collections.emptyList());
+    return getGetterForProperty(property, property.getVisibility() == Visibility.INTERNAL);
   }
 
   public MemberNaming.MethodSignature getSetterForProperty(String propertyName) {
     KotlinProperty property = getProperty(propertyName);
-    String setterName = computeSetterName(propertyName);
-    if (property.getVisibility() == Visibility.INTERNAL) {
-      setterName = appendInternalSuffix(setterName);
-    }
-    return new MemberNaming.MethodSignature(setterName, "void",
-        Collections.singleton(property.getType()));
+    return getSetterForProperty(property, property.getVisibility() == Visibility.INTERNAL);
   }
 
   public MemberNaming.MethodSignature getGetterAccessorForProperty(String propertyName,
@@ -152,6 +142,26 @@
     return new MemberNaming.MethodSignature(setterName, "void", argumentTypes);
   }
 
+  protected final MemberNaming.MethodSignature getGetterForProperty(KotlinProperty property,
+      boolean applyMangling) {
+    String type = property.type;
+    String getterName = computeGetterName(property.name);
+    if (applyMangling) {
+      getterName = appendInternalSuffix(getterName);
+    }
+    return new MemberNaming.MethodSignature(getterName, type, Collections.emptyList());
+  }
+
+  protected final MemberNaming.MethodSignature getSetterForProperty(KotlinProperty property,
+      boolean applyMangling) {
+    String setterName = computeSetterName(property.name);
+    if (applyMangling) {
+      setterName = appendInternalSuffix(setterName);
+    }
+    return new MemberNaming.MethodSignature(setterName, "void",
+        Collections.singleton(property.getType()));
+  }
+
   private static String computeGetterName(String propertyName) {
     if (propertyName.length() > 2 && propertyName.startsWith("is")
         && (propertyName.charAt(2) == '_' || Character.isUpperCase(propertyName.charAt(2)))) {
diff --git a/src/test/java/com/android/tools/r8/resource/DataResourceTest.java b/src/test/java/com/android/tools/r8/resource/DataResourceTest.java
index 167262f..dbd4e23 100644
--- a/src/test/java/com/android/tools/r8/resource/DataResourceTest.java
+++ b/src/test/java/com/android/tools/r8/resource/DataResourceTest.java
@@ -6,7 +6,7 @@
 
 import com.android.tools.r8.CompilationException;
 import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.OutputMode;
+import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ProcessResult;
@@ -35,9 +35,10 @@
     ProcessResult referenceResult = ToolHelper.runJava(inputJar, mainClassName);
 
     Path r8Out = temp.getRoot().toPath().resolve("r8out.jar");
-    R8Command.Builder builder = R8Command.builder()
-        .addProgramFiles(inputJar)
-        .setOutput(r8Out, OutputMode.DexIndexed);
+    R8Command.Builder builder =
+        R8Command.builder()
+            .addProgramFiles(inputJar)
+            .setProgramConsumer(new DexIndexedConsumer.ArchiveConsumer(r8Out, true));
     ToolHelper.runR8(builder.build());
 
     ProcessResult r8Result = ToolHelper.runArtRaw(r8Out.toString(), mainClassName);
diff --git a/src/test/kotlinR8TestResources/properties/FileProperties.kt b/src/test/kotlinR8TestResources/properties/FileProperties.kt
new file mode 100644
index 0000000..4671189
--- /dev/null
+++ b/src/test/kotlinR8TestResources/properties/FileProperties.kt
@@ -0,0 +1,82 @@
+// 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 properties
+
+private var privateProp: String = "privateProp"
+internal var internalProp: String = "internalProp"
+public var publicProp: String = "publicProp"
+
+private lateinit var privateLateInitProp: String
+internal lateinit var internalLateInitProp: String
+public lateinit var publicLateInitProp: String
+
+public var primitiveProp: Int = Int.MAX_VALUE
+
+// Serves as intermediate to make sure the access to a property is done from a separate class.
+private object Intermediate {
+    fun readPrivateProp() = privateProp
+    fun writePrivateProp(s: String) { privateProp = s }
+
+    fun readInternalProp() = internalProp
+    fun writeInternalProp(s: String) { internalProp = s }
+
+    fun readPublicProp() = publicProp
+    fun writePublicProp(s: String) { publicProp = s }
+
+    fun readPrimitiveProp() = primitiveProp
+    fun writePrimitiveProp(i: Int) { primitiveProp = i }
+
+    fun readLateInitPrivateProp() = privateLateInitProp
+    fun writeLateInitPrivateProp(s: String) { privateLateInitProp = s }
+
+    fun readLateInitInternalProp() = internalLateInitProp
+    fun writeLateInitInternalProp(s: String) { internalLateInitProp = s }
+
+    fun readLateInitPublicProp() = publicLateInitProp
+    fun writeLateInitPublicProp(s: String) { publicLateInitProp = s }
+}
+
+fun doNotUseProperties(): String {
+    return "doNotUseProperties"
+}
+
+fun fileProperties_noUseOfProperties() {
+    println(ObjectProperties.doNotUseProperties())
+}
+
+fun fileProperties_usePrivateProp() {
+    Intermediate.writePrivateProp("foo")
+    println(Intermediate.readPrivateProp())
+}
+
+fun fileProperties_useInternalProp() {
+    Intermediate.writeInternalProp("foo")
+    println(Intermediate.readInternalProp())
+}
+
+fun fileProperties_usePublicProp() {
+    Intermediate.writePublicProp("foo")
+    println(Intermediate.readPublicProp())
+}
+
+fun fileProperties_usePrimitiveProp() {
+    Intermediate.writePrimitiveProp(Int.MIN_VALUE)
+    println(Intermediate.readPrimitiveProp())
+}
+
+fun fileProperties_useLateInitPrivateProp() {
+    Intermediate.writeLateInitPrivateProp("foo")
+    println(Intermediate.readLateInitPrivateProp())
+}
+
+fun fileProperties_useLateInitInternalProp() {
+    Intermediate.writeLateInitInternalProp( "foo")
+    println(Intermediate.readLateInitInternalProp())
+}
+
+fun fileProperties_useLateInitPublicProp() {
+    Intermediate.writeLateInitPublicProp("foo")
+    println(Intermediate.readLateInitPublicProp())
+}
diff --git a/src/test/kotlinR8TestResources/properties/ObjectProperties.kt b/src/test/kotlinR8TestResources/properties/ObjectProperties.kt
new file mode 100644
index 0000000..d05e2a6
--- /dev/null
+++ b/src/test/kotlinR8TestResources/properties/ObjectProperties.kt
@@ -0,0 +1,76 @@
+// 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 properties
+
+object ObjectProperties {
+    private var privateProp: String = "privateProp"
+    internal var internalProp: String = "internalProp"
+    public var publicProp: String = "publicProp"
+
+    private lateinit var privateLateInitProp: String
+    internal lateinit var internalLateInitProp: String
+    public lateinit var publicLateInitProp: String
+
+    public var primitiveProp: Int = Int.MAX_VALUE
+
+    fun callSetterPrivateProp(v: String) {
+        privateProp = v
+    }
+
+    fun callGetterPrivateProp(): String {
+        return privateProp
+    }
+
+    fun callSetterLateInitPrivateProp(v: String) {
+        privateLateInitProp = v
+    }
+
+    fun callGetterLateInitPrivateProp(): String {
+        return privateLateInitProp
+    }
+
+    fun doNotUseProperties(): String {
+        return "doNotUseProperties"
+    }
+}
+
+fun objectProperties_noUseOfProperties() {
+    println(ObjectProperties.doNotUseProperties())
+}
+
+fun objectProperties_usePrivateProp() {
+    ObjectProperties.callSetterPrivateProp("foo")
+    println(ObjectProperties.callGetterPrivateProp())
+}
+
+fun objectProperties_useInternalProp() {
+    ObjectProperties.internalProp = "foo"
+    println(ObjectProperties.internalProp)
+}
+
+fun objectProperties_usePublicProp() {
+    ObjectProperties.publicProp = "foo"
+    println(ObjectProperties.publicProp)
+}
+
+fun objectProperties_usePrimitiveProp() {
+    ObjectProperties.primitiveProp = Int.MIN_VALUE
+    println(ObjectProperties.primitiveProp)
+}
+
+fun objectProperties_useLateInitPrivateProp() {
+    ObjectProperties.callSetterLateInitPrivateProp("foo")
+    println(ObjectProperties.callGetterLateInitPrivateProp())
+}
+
+fun objectProperties_useLateInitInternalProp() {
+    ObjectProperties.internalLateInitProp = "foo"
+    println(ObjectProperties.internalLateInitProp)
+}
+
+fun objectProperties_useLateInitPublicProp() {
+    ObjectProperties.publicLateInitProp = "foo"
+    println(ObjectProperties.publicLateInitProp)
+}
diff --git a/tools/golem_build.py b/tools/golem_build.py
new file mode 100755
index 0000000..6d3a9b7
--- /dev/null
+++ b/tools/golem_build.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+# 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.
+
+# Utility script to make it easier to update what golem builds.
+
+import gradle
+import sys
+
+GRADLE_ARGS = ['--no-daemon']
+BUILD_TARGETS = ['R8', 'D8', 'buildExampleJars', 'CompatDx',
+                 'downloadAndroidCts', 'downloadDx']
+
+def Main():
+  gradle.RunGradle(GRADLE_ARGS + BUILD_TARGETS)
+
+if __name__ == '__main__':
+  sys.exit(Main())
diff --git a/tools/minify_tool.py b/tools/minify_tool.py
new file mode 100755
index 0000000..08b2ada
--- /dev/null
+++ b/tools/minify_tool.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python
+# 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.
+
+'''
+Run R8 (with the class-file backend) to optimize a command-line program.
+
+Given an input JAR (default: r8.jar) and a main-class, generates a new input JAR
+with the given main-class in the manifest along with a -keep rule for keeping
+just the main entrypoint, and runs R8 in release+classfile mode on the JAR.
+'''
+
+import argparse
+import os
+import re
+import sys
+import time
+import toolhelper
+import utils
+import zipfile
+
+KEEP = '-keep public class %s { public static void main(...); }\n'
+MANIFEST_PATH = 'META-INF/MANIFEST.MF'
+MANIFEST = 'Manifest-Version: 1.0\nMain-Class: %s\n\n'
+MANIFEST_PATTERN = r'Main-Class:\s*(\S+)'
+RT = os.path.join(utils.REPO_ROOT, 'third_party/openjdk/openjdk-rt-1.8/rt.jar')
+
+parser = argparse.ArgumentParser(description=__doc__.strip(),
+                                 formatter_class=argparse.RawTextHelpFormatter)
+parser.add_argument(
+    '-i', '--input-jar', default=utils.R8_JAR,
+    help='Input JAR to use (default: build/libs/r8.jar)')
+parser.add_argument(
+    '-o', '--output-jar',
+    help='Path to output JAR (default: build/libs/<MainClass>-min.jar)')
+parser.add_argument(
+    '-l', '--lib', default=RT,
+    help='Path to rt.jar to use instead of OpenJDK 1.8')
+parser.add_argument(
+    '-m', '--mainclass',
+    help='Create/overwrite MANIFEST.MF with the given Main-Class')
+parser.add_argument(
+    '-O', '--no-debug', dest='debug', action='store_false',
+    help='Disable assertions when running R8')
+parser.add_argument(
+    '--print-runtimeraw', metavar='BENCHMARKNAME',
+    help='Print "<BENCHMARKNAME>(RunTimeRaw): <elapsed> ms" at the end')
+
+def generate_output_name(input_jar, mainclass):
+  if not mainclass:
+    input_base, input_ext = os.path.splitext(input_jar)
+    return '%s-min%s' % (input_base, input_ext)
+  base = mainclass[mainclass.rindex('.')+1:] if '.' in mainclass else mainclass
+  return os.path.join(utils.LIBS, '%s-min.jar' % base)
+
+def repackage(input_jar, output_jar, mainclass):
+  print("Repackaging %s to %s with Main-Class: %s..." %
+        (input_jar, output_jar, mainclass))
+  manifest = MANIFEST % mainclass
+  with zipfile.ZipFile(input_jar, 'r') as input_zf:
+    with zipfile.ZipFile(output_jar, 'w') as output_zf:
+      for zipinfo in input_zf.infolist():
+        if zipinfo.filename.upper() == MANIFEST_PATH:
+          assert manifest is not None
+          output_zf.writestr(MANIFEST_PATH, manifest)
+          manifest = None
+        else:
+          output_zf.writestr(zipinfo, input_zf.read(zipinfo))
+      if manifest is not None:
+        output_zf.writestr(MANIFEST_PATH, manifest)
+
+def extract_mainclass(input_jar):
+  with zipfile.ZipFile(input_jar, 'r') as input_zf:
+    try:
+      manifest = input_zf.getinfo(MANIFEST_PATH)
+    except KeyError:
+      raise SystemExit('No --mainclass specified and no manifest in input JAR.')
+    mo = re.search(MANIFEST_PATTERN, input_zf.read(manifest))
+    if not mo:
+      raise SystemExit(
+          'No --mainclass specified and no Main-Class in input JAR manifest.')
+    return mo.group(1)
+
+def minify_tool(mainclass=None, input_jar=utils.R8_JAR, output_jar=None, lib=RT,
+                debug=True, build=True, print_runtimeraw=None):
+  if output_jar is None:
+    output_jar = generate_output_name(input_jar, mainclass)
+  with utils.TempDir() as path:
+    if mainclass:
+      tmp_input_path = os.path.join(path, 'input.jar')
+      repackage(input_jar, tmp_input_path, mainclass)
+    else:
+      tmp_input_path = input_jar
+      mainclass = extract_mainclass(input_jar)
+    keep_path = os.path.join(path, 'keep.txt')
+    with open(keep_path, 'w') as fp:
+      fp.write(KEEP % mainclass)
+    args = ('--lib', lib,
+            '--classfile',
+            '--output', output_jar,
+            '--pg-conf', keep_path,
+            '--release',
+            tmp_input_path)
+    start_time = time.time()
+    return_code = toolhelper.run('r8', args, debug=debug, build=build)
+    if print_runtimeraw:
+      elapsed_ms = 1000 * (time.time() - start_time)
+      print('%s-Total(RunTimeRaw): %s ms' % (print_runtimeraw, elapsed_ms))
+    return return_code
+
+if __name__ == '__main__':
+  sys.exit(minify_tool(**vars(parser.parse_args())))
diff --git a/tools/run_bootstrap_benchmark.py b/tools/run_bootstrap_benchmark.py
new file mode 100755
index 0000000..0c608f9
--- /dev/null
+++ b/tools/run_bootstrap_benchmark.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+# 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.
+
+import argparse
+import minify_tool
+import os
+import sys
+import utils
+
+
+PINNED_R8_JAR = os.path.join(utils.REPO_ROOT, 'third_party/r8/r8.jar')
+
+parser = argparse.ArgumentParser()
+parser.add_argument(
+    '--print-runtimeraw', metavar='BENCHMARKNAME',
+    help='Print "<BENCHMARKNAME>(RunTimeRaw): <elapsed> ms" at the end')
+
+
+if __name__ == '__main__':
+  sys.exit(minify_tool.minify_tool(input_jar=PINNED_R8_JAR, debug=False,
+                                   build=False, **vars(parser.parse_args())))
diff --git a/tools/utils.py b/tools/utils.py
index 3b80a88..9f6959f 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -15,8 +15,6 @@
 TOOLS_DIR = os.path.abspath(os.path.normpath(os.path.join(__file__, '..')))
 REPO_ROOT = os.path.realpath(os.path.join(TOOLS_DIR, '..'))
 MEMORY_USE_TMP_FILE = 'memory_use.tmp'
-DEX_SEGMENTS_JAR = os.path.join(REPO_ROOT, 'build', 'libs',
-    'dexsegments.jar')
 DEX_SEGMENTS_RESULT_PATTERN = re.compile('- ([^:]+): ([0-9]+)')
 BUILD = os.path.join(REPO_ROOT, 'build')
 LIBS = os.path.join(BUILD, 'libs')
@@ -189,7 +187,7 @@
 # Return a dictionary: {segment_name -> segments_size}
 def getDexSegmentSizes(dex_files):
   assert len(dex_files) > 0
-  cmd = ['java', '-jar', DEX_SEGMENTS_JAR]
+  cmd = ['java', '-jar', R8_JAR, 'dexsegments']
   cmd.extend(dex_files)
   PrintCmd(cmd)
   output = subprocess.check_output(cmd)