Merge "Value-based worklist in type analysis."
diff --git a/build.gradle b/build.gradle
index 8893820..9b8d59b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -25,6 +25,22 @@
     }
 }
 
+ext {
+    androidSupportVersion = '25.4.0'
+    apacheCommonsVersion = '1.12'
+    asmVersion = '6.0'
+    autoValueVersion = '1.5'
+    espressoVersion = '3.0.0'
+    fastutilVersion = '7.2.0'
+    guavaVersion = '23.0'
+    joptSimpleVersion = '4.6'
+    jsonSimpleVersion = '1.1'
+    junitVersion = '4.12'
+    kotlinVersion = '1.2.0'
+    protobufVersion = '3.0.0'
+    smaliVersion = '2.2b4'
+}
+
 def errorProneConfiguration = [
     '-XepDisableAllChecks',
     // D8 want to use reference equality, thus disable the checker explicitly
@@ -192,48 +208,48 @@
 }
 
 dependencies {
-    compile 'net.sf.jopt-simple:jopt-simple:4.6'
-    compile 'com.googlecode.json-simple:json-simple:1.1'
+    compile "net.sf.jopt-simple:jopt-simple:$joptSimpleVersion"
+    compile "com.googlecode.json-simple:json-simple:$jsonSimpleVersion"
     // Include all of guava when compiling the code, but exclude annotations that we don't
     // need from the packaging.
-    compileOnly('com.google.guava:guava:23.0')
-    compile('com.google.guava:guava:23.0', {
+    compileOnly("com.google.guava:guava:$guavaVersion")
+    compile("com.google.guava:guava:$guavaVersion", {
         exclude group: 'com.google.errorprone'
         exclude group: 'com.google.code.findbugs'
         exclude group: 'com.google.j2objc'
         exclude group: 'org.codehaus.mojo'
     })
-    compile group: 'it.unimi.dsi', name: 'fastutil', version: '7.2.0'
-    compile group: 'org.ow2.asm', name: 'asm', version: '6.0'
-    compile group: 'org.ow2.asm', name: 'asm-commons', version: '6.0'
-    compile group: 'org.ow2.asm', name: 'asm-tree', version: '6.0'
-    compile group: 'org.ow2.asm', name: 'asm-analysis', version: '6.0'
-    compile group: 'org.ow2.asm', name: 'asm-util', version: '6.0'
+    compile group: 'it.unimi.dsi', name: 'fastutil', version: fastutilVersion
+    compile group: 'org.ow2.asm', name: 'asm', version: asmVersion
+    compile group: 'org.ow2.asm', name: 'asm-commons', version: asmVersion
+    compile group: 'org.ow2.asm', name: 'asm-tree', version: asmVersion
+    compile group: 'org.ow2.asm', name: 'asm-analysis', version: asmVersion
+    compile group: 'org.ow2.asm', name: 'asm-util', version: asmVersion
     testCompile sourceSets.examples.output
-    testCompile 'junit:junit:4.12'
-    testCompile group: 'org.smali', name: 'smali', version: '2.2b4'
+    testCompile "junit:junit:$junitVersion"
+    testCompile group: 'org.smali', name: 'smali', version: smaliVersion
     testCompile files('third_party/jasmin/jasmin-2.4.jar')
     testCompile files('third_party/jdwp-tests/apache-harmony-jdwp-tests-host.jar')
     testCompile files('third_party/ddmlib/ddmlib.jar')
-    bsPatchCompile group: 'org.apache.commons', name: 'commons-compress', version: '1.12'
-    jctfCommonCompile 'junit:junit:4.12'
-    jctfTestsCompile 'junit:junit:4.12'
+    bsPatchCompile "org.apache.commons:commons-compress:$apacheCommonsVersion"
+    jctfCommonCompile "junit:junit:$junitVersion"
+    jctfTestsCompile "junit:junit:$junitVersion"
     jctfTestsCompile sourceSets.jctfCommon.output
-    examplesAndroidOCompile group: 'org.ow2.asm', name: 'asm', version: '6.0'
-    examplesAndroidPCompile group: 'org.ow2.asm', name: 'asm', version: '6.0'
+    examplesAndroidOCompile group: 'org.ow2.asm', name: 'asm', version: asmVersion
+    examplesAndroidPCompile group: 'org.ow2.asm', name: 'asm', version: asmVersion
     // Import Guava for @Nullable annotation
-    examplesCompile 'com.google.guava:guava:23.0'
-    examplesCompile 'com.google.protobuf:protobuf-lite:3.0.0'
-    examplesCompileOnly "com.google.auto.value:auto-value:1.5"
-    examplesRuntime 'com.google.protobuf:protobuf-lite:3.0.0'
-    supportLibs 'com.android.support:support-v4:25.4.0'
-    supportLibs 'junit:junit:4.12'
-    supportLibs 'com.android.support.test.espresso:espresso-core:3.0.0'
+    examplesCompile "com.google.guava:guava:$guavaVersion"
+    examplesCompile "com.google.protobuf:protobuf-lite:$protobufVersion"
+    examplesCompileOnly "com.google.auto.value:auto-value:$autoValueVersion"
+    examplesRuntime "com.google.protobuf:protobuf-lite:$protobufVersion"
+    supportLibs "com.android.support:support-v4:$androidSupportVersion"
+    supportLibs "junit:junit:$junitVersion"
+    supportLibs "com.android.support.test.espresso:espresso-core:$espressoVersion"
     apiUsageSampleCompile sourceSets.main.output
-    debugTestResourcesKotlinCompileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.2.0'
-    examplesKotlinCompileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.2.0'
-    kotlinR8TestResourcesCompileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.2.0'
-    apt 'com.google.auto.value:auto-value:1.5'
+    debugTestResourcesKotlinCompileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
+    examplesKotlinCompileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
+    kotlinR8TestResourcesCompileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
+    apt "com.google.auto.value:auto-value:$autoValueVersion"
 }
 
 configurations.bsPatchCompile.extendsFrom configurations.compile
@@ -245,11 +261,11 @@
 protobuf {
     protoc {
         // Download from repositories
-        artifact = 'com.google.protobuf:protoc:3.0.0'
+        artifact = "com.google.protobuf:protoc:$protobufVersion"
     }
     plugins {
         javalite {
-            artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0'
+            artifact = "com.google.protobuf:protoc-gen-javalite:$protobufVersion"
         }
     }
     generateProtoTasks {
@@ -1167,13 +1183,17 @@
 task buildKotlinR8TestResources {
     def examplesDir = file("src/test/kotlinR8TestResources")
     examplesDir.eachDir { dir ->
-        def name = dir.getName()
-        def taskName = "jar_kotlinR8TestResources_${name}"
-        task "${taskName}"(type: kotlin.Kotlinc) {
-            source = fileTree(dir: file("${examplesDir}/${name}"), include: '**/*.kt')
-            destination = file("build/test/kotlinR8TestResources/${name}.jar")
+        kotlin.Kotlinc.KotlinTargetVersion.values().each { kotlinTargetVersion ->
+            def name = dir.getName()
+            def taskName = "jar_kotlinR8TestResources_${name}_${kotlinTargetVersion}"
+            def outputFile = "build/test/kotlinR8TestResources/${kotlinTargetVersion}/${name}.jar"
+            task "${taskName}"(type: kotlin.Kotlinc) {
+                source = fileTree(dir: file("${examplesDir}/${name}"), include: '**/*.kt')
+                destination = file(outputFile)
+                targetVersion = kotlinTargetVersion
+            }
+            dependsOn taskName
         }
-        dependsOn taskName
     }
 }
 
diff --git a/buildSrc/src/main/java/kotlin/Kotlinc.java b/buildSrc/src/main/java/kotlin/Kotlinc.java
index 261acc3..0c0a50a 100644
--- a/buildSrc/src/main/java/kotlin/Kotlinc.java
+++ b/buildSrc/src/main/java/kotlin/Kotlinc.java
@@ -19,16 +19,29 @@
 import utils.Utils;
 
 /**
- * Gradle task to compile Kotlin source files.
+ * Gradle task to compile Kotlin source files. By default the generated classes target Java 1.6.
  */
 public class Kotlinc extends DefaultTask {
 
+  enum KotlinTargetVersion {
+    JAVA_6("1.6"),
+    JAVA_8("1.8");
+
+    private final String optionName;
+
+    KotlinTargetVersion(String optionName) {
+      this.optionName = optionName;
+    }
+  }
+
   @InputFiles
   private FileTree source;
 
   @OutputFile
   private File destination;
 
+  private KotlinTargetVersion targetVersion = KotlinTargetVersion.JAVA_6;
+
   public FileTree getSource() {
     return source;
   }
@@ -45,6 +58,14 @@
     this.destination = destination;
   }
 
+  public KotlinTargetVersion getTargetVersion() {
+    return targetVersion;
+  }
+
+  public void setTargetVersion(KotlinTargetVersion targetVersion) {
+    this.targetVersion = targetVersion;
+  }
+
   @TaskAction
   public void compile() {
     getProject().exec(new Action<ExecSpec>() {
@@ -57,6 +78,7 @@
           execSpec.setExecutable(kotlincExecPath.toFile());
           execSpec.args("-include-runtime");
           execSpec.args("-nowarn");
+          execSpec.args("-jvm-target", targetVersion.optionName);
           execSpec.args("-d", destination.getCanonicalPath());
           execSpec.args(source.getFiles());
         } catch (IOException e) {
diff --git a/src/main/java/com/android/tools/r8/dex/VirtualFile.java b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
index 2cdfd76..5369069 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -372,7 +372,7 @@
       classes = sortClassesByPackage(classes, originalNames);
 
       new PackageSplitPopulator(
-          filesForDistribution, classes, originalNames, null, application.dexItemFactory,
+          filesForDistribution, classes, originalNames, application.dexItemFactory,
           fillStrategy, fileIndexOffset, writer.namingLens)
           .call();
       return virtualFiles;
@@ -701,7 +701,6 @@
 
     private final List<DexProgramClass> classes;
     private final Map<DexProgramClass, String> originalNames;
-    private final Set<String> previousPrefixes;
     private final DexItemFactory dexItemFactory;
     private final FillStrategy fillStrategy;
     private final VirtualFileCycler cycler;
@@ -710,14 +709,12 @@
         List<VirtualFile> files,
         Set<DexProgramClass> classes,
         Map<DexProgramClass, String> originalNames,
-        Set<String> previousPrefixes,
         DexItemFactory dexItemFactory,
         FillStrategy fillStrategy,
         int fileIndexOffset,
         NamingLens namingLens) {
       this.classes = new ArrayList<>(classes);
       this.originalNames = originalNames;
-      this.previousPrefixes = previousPrefixes;
       this.dexItemFactory = dexItemFactory;
       this.fillStrategy = fillStrategy;
       this.cycler = new VirtualFileCycler(files, namingLens, fileIndexOffset);
@@ -774,9 +771,7 @@
           // com.android.* and com.android.foo.*.
           do {
             newPrefix = extractPrefixToken(++prefixLength, originalName, false);
-          } while (currentPrefix != null &&
-              (currentPrefix.startsWith(newPrefix)
-              || conflictsWithPreviousPrefix(newPrefix, originalName)));
+          } while (currentPrefix != null && currentPrefix.startsWith(newPrefix));
           // Don't set the current prefix if we did not extract one.
           if (!newPrefix.equals("")) {
             currentPrefix = extractPrefixToken(prefixLength, originalName, true);
@@ -871,28 +866,5 @@
       }
       return current;
     }
-
-    private boolean conflictsWithPreviousPrefix(String newPrefix, String originalName) {
-      if (previousPrefixes == null) {
-        return false;
-      }
-      for (String previous : previousPrefixes) {
-        // Check whether a previous prefix starts with this new prefix and, if so,
-        // whether the new prefix already is maximal. So for example a new prefix of
-        //   foo.bar
-        // would match
-        //   foo.bar.goo.*
-        // However, if the original class is
-        //   foo.bar.X
-        // then this prefix is the best we can do, and will not turn into a .* prefix and
-        // thus does not conflict.
-        if (previous.startsWith(newPrefix)
-            && (originalName.lastIndexOf('.') > newPrefix.length())) {
-          return true;
-        }
-      }
-
-      return false;
-    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java b/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
index dba4842..35108bd 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
@@ -213,8 +213,12 @@
 
     @Override
     public void collectIndexedItems(IndexedItemCollection collection) {
-      name.collectIndexedItems(collection);
-      type.collectIndexedItems(collection);
+      if (name != null) {
+        name.collectIndexedItems(collection);
+      }
+      if (type != null) {
+        type.collectIndexedItems(collection);
+      }
       if (signature != null) {
         signature.collectIndexedItems(collection);
       }
@@ -234,8 +238,8 @@
     public int hashCode() {
       return Constants.DBG_START_LOCAL
           + registerNum * 7
-          + name.hashCode() * 13
-          + type.hashCode() * 17
+          + Objects.hashCode(name) * 13
+          + Objects.hashCode(type) * 17
           + Objects.hashCode(signature) * 19;
     }
 
@@ -248,10 +252,10 @@
       if (registerNum != o.registerNum) {
         return false;
       }
-      if (!name.equals(o.name)) {
+      if (!Objects.equals(name, o.name)) {
         return false;
       }
-      if (!type.equals(o.type)) {
+      if (!Objects.equals(type, o.type)) {
         return false;
       }
       return Objects.equals(signature, o.signature);
diff --git a/src/main/java/com/android/tools/r8/naming/Minifier.java b/src/main/java/com/android/tools/r8/naming/Minifier.java
index 03c4c33..82eb242 100644
--- a/src/main/java/com/android/tools/r8/naming/Minifier.java
+++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -17,7 +17,6 @@
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
 import java.util.IdentityHashMap;
 import java.util.Map;
 import java.util.function.Consumer;
@@ -89,18 +88,19 @@
 
     @Override
     void forAllRenamedTypes(Consumer<DexType> consumer) {
-      Iterables.filter(renaming.keySet(), DexType.class).forEach(consumer);
+      renaming.keySet().stream()
+          .filter(DexType.class::isInstance)
+          .map(DexType.class::cast)
+          .forEach(consumer);
     }
 
     @Override
     <T extends DexItem> Map<String, T> getRenamedItems(
         Class<T> clazz, Predicate<T> predicate, Function<T, String> namer) {
-      return renaming
-          .keySet()
-          .stream()
-          .filter(item -> (item.getClass() == clazz) && predicate.test(clazz.cast(item)))
+      return renaming.keySet().stream()
+          .filter(item -> (clazz.isInstance(item) && predicate.test(clazz.cast(item))))
           .map(clazz::cast)
-          .collect(ImmutableMap.toImmutableMap(namer::apply, i -> i));
+          .collect(ImmutableMap.toImmutableMap(namer, i -> i));
     }
 
     /**
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index d9f10ae..cc325e2 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -1245,4 +1245,19 @@
         options,
         null);
   }
+
+  public enum KotlinTargetVersion {
+    JAVA_6("JAVA_6"),
+    JAVA_8("JAVA_8");
+
+    private final String folderName;
+
+    KotlinTargetVersion(String folderName) {
+      this.folderName = folderName;
+    }
+
+    public String getFolderName() {
+      return folderName;
+    }
+  }
 }
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 15c20c5..9f520a2 100644
--- a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.OutputMode;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
@@ -21,24 +22,35 @@
 import com.android.tools.r8.utils.DexInspector.ClassSubject;
 import com.android.tools.r8.utils.DexInspector.MethodSubject;
 import com.android.tools.r8.utils.FileUtils;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Map;
 import org.junit.Assume;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
-// TODO(shertz) also run with backend 1.8
+@RunWith(Parameterized.class)
 public abstract class AbstractR8KotlinTestBase extends TestBase {
 
-  public static final String KOTLIN_R8_TEST_RESOURCES_BUILD_DIR =
-      ToolHelper.TESTS_BUILD_DIR + "/kotlinR8TestResources";
-
-  protected final boolean allowAccessModification;
-
-  protected AbstractR8KotlinTestBase(boolean allowAccessModification) {
-    this.allowAccessModification = allowAccessModification;
+  @Parameters(name = "{0}_{1}")
+  public static Collection<Object[]> data() {
+    ImmutableList.Builder<Object[]> builder = new Builder<>();
+    for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
+      builder.add(new Object[]{Boolean.TRUE, targetVersion});
+      builder.add(new Object[]{Boolean.FALSE, targetVersion});
+    }
+    return builder.build();
   }
 
+  @Parameter(0) public boolean allowAccessModification;
+  @Parameter(1) public KotlinTargetVersion targetVersion;
+
   protected static void checkMethodIsInvokedAtLeastOnce(DexCode dexCode,
       MethodSignature... methodSignatures) {
     for (MethodSignature methodSignature : methodSignatures) {
@@ -143,8 +155,7 @@
       AndroidAppInspector inspector) throws Exception {
     Assume.assumeTrue(ToolHelper.artSupported());
 
-    Path jarFile =
-        Paths.get(KOTLIN_R8_TEST_RESOURCES_BUILD_DIR, folder + FileUtils.JAR_EXTENSION);
+    Path jarFile = getJarFile(folder);
 
     String proguardRules = buildProguardRules(mainClass);
     if (extraProguardRules != null) {
@@ -176,6 +187,11 @@
     inspector.inspectApp(app);
   }
 
+  private Path getJarFile(String folder) {
+    return Paths.get(ToolHelper.TESTS_BUILD_DIR, "kotlinR8TestResources",
+        targetVersion.getFolderName(), folder + FileUtils.JAR_EXTENSION);
+  }
+
   @FunctionalInterface
   interface AndroidAppInspector {
 
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
index fe0efd1..379579f 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
@@ -9,15 +9,9 @@
 import com.android.tools.r8.utils.DexInspector;
 import com.android.tools.r8.utils.DexInspector.ClassSubject;
 import com.android.tools.r8.utils.DexInspector.MethodSubject;
-import com.google.common.collect.ImmutableList;
-import java.util.Collection;
 import java.util.Collections;
 import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
 
-@RunWith(Parameterized.class)
 public class R8KotlinDataClassTest extends AbstractR8KotlinTestBase {
 
   private static final KotlinDataClass TEST_DATA_CLASS = new KotlinDataClass("dataclass.Person")
@@ -37,15 +31,6 @@
   private static final MethodSignature COPY_DEFAULT_METHOD =
       TEST_DATA_CLASS.getCopyDefaultSignature();
 
-  public R8KotlinDataClassTest(boolean allowAccessModification) {
-    super(allowAccessModification);
-  }
-
-  @Parameters(name = "{0}")
-  public static Collection<Object> data() {
-    return ImmutableList.of(Boolean.TRUE, Boolean.FALSE);
-  }
-
   @Test
   public void test_dataclass_gettersOnly() throws Exception {
     final String mainClassName = "dataclass.MainGettersOnlyKt";
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
index fc2a7bb..b059382 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
@@ -7,15 +7,12 @@
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.utils.DexInspector;
 import com.android.tools.r8.utils.DexInspector.ClassSubject;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
-import java.util.Collection;
 import java.util.Collections;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class R8KotlinIntrinsicsTest extends AbstractR8KotlinTestBase {
@@ -23,15 +20,6 @@
   private static final KotlinDataClass KOTLIN_INTRINSICS_CLASS =
       new KotlinDataClass("kotlin.jvm.internal.Intrinsics");
 
-  @Parameters(name = "{0}")
-  public static Collection<Object> data() {
-    return ImmutableList.of(Boolean.TRUE, Boolean.FALSE);
-  }
-
-  public R8KotlinIntrinsicsTest(boolean allowAccessModification) {
-    super(allowAccessModification);
-  }
-
   @Test
   public void testParameterNullCheckIsInlined() throws Exception {
     final String extraRules = keepClassMethod("intrinsics.IntrinsicsKt",
diff --git a/tools/notify.py b/tools/notify.py
index f7ae50e..f6db21b 100644
--- a/tools/notify.py
+++ b/tools/notify.py
@@ -5,12 +5,13 @@
 
 try:
   import gi
+  gi.require_version('Notify', '0.7')
   from gi.repository import Notify
-  Notify.init("R8 build tools")
+  Notify.init('R8 build tools')
 
   def notify(message):
     try:
-      Notify.Notification.new("R8 build tools", message).show()
+      Notify.Notification.new('R8 build tools', message).show()
     except:
       return