Merge "Allow use of ellipsis in non-argument positions in Proguard rules"
diff --git a/compatibility-faq.md b/compatibility-faq.md
new file mode 100644
index 0000000..8b15be4
--- /dev/null
+++ b/compatibility-faq.md
@@ -0,0 +1,103 @@
+# R8 compatibility FAQ
+
+R8 uses the same configuration specification language as ProGuard, and tries to
+be compatible with ProGuard. However as R8 has different optimizations it can be
+necessary to change the configuration when switching to R8.
+
+This FAQ collects some of the common issues.
+
+## GSON
+
+### Member in a data object is always `null`
+
+For data classes used for serialization all fields that are used in the
+serialization must be kept by the configuration. R8 can decide to replace
+instances of types that are never instantiated with `null`. So if instances of a
+given class are only created through deserialization from JSON, R8 will not see
+that class as instantiated leaving it as always `null`.
+
+If the `@SerializedName` annotation is used consistently for data classes the
+following keep rule can be used:
+
+```
+-keepclassmembers,allowobfuscation class * {
+  @com.google.gson.annotations.SerializedName <fields>;
+}
+```
+
+This will ensure that all fields annotated with `SerializedName` will be
+kept. These fields can still be renamed during obfuscation as the
+`SerializedName` annotation (not the source field name) controls the name in the
+JSON serialization.
+
+If the `@SerializedName` annotation is _not_ used the following conservative
+rule can be used for each data class:
+
+```
+-keepclassmembers class MyDataClass {
+  !transient <fields>;
+}
+```
+
+This will ensure that all fields are kept and not renamed for these
+classes. Fields with modifier `transient` are never serialized and therefore
+keeping these is not needed.
+
+### Error `java.lang.IllegalArgumentException: class <class name> declares multiple JSON fields named <name>`
+
+This can be caused by obfuscation selecting the same name for private fields in
+several classes in a class hierachy. Consider the following example:
+
+```
+class A {
+  private String fieldInA;
+}
+
+class B extends A {
+  private String fieldInB;
+}
+```
+
+Here R8 can choose to rename both `fieldInA` and `fieldInB` to the same name,
+e.g. `a`. This creates a conflict when GSON is used to either serialize an
+instance of class `B` to JSON or create an instance of class `B` from JSON. If
+the fields should _not_ be serialized they should be marked `transient` so that
+they will be ignored by GSON:
+
+```
+class A {
+  private transient String fieldInA;
+}
+
+class B extends A {
+  private transient String fieldInB;
+}
+```
+
+If the fields _are_ to be serialized, the annotation `SerializedName` can be
+used to fix the `IllegalArgumentException` together the rule to keep fields
+annotated with `SerializedName`
+
+```
+class A {
+  @SerializedName("fieldInA")
+  private String fieldInA;
+}
+
+class B extends A {
+  @SerializedName("fieldInB")
+  private String fieldInB;
+}
+```
+
+```
+-keepclassmembers,allowobfuscation class * {
+  @com.google.gson.annotations.SerializedName <fields>;
+}
+```
+
+
+Both the use of `transient` and the use of the annotation `SerializedName` allow
+the fields to be renamed by R8 to the same name, but GSON serialization will
+work as expected.
+
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 863bbbe..5131b19 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -96,8 +96,7 @@
       mixins: "linux"
       execution_timeout_secs: 1800  # 1/2h
       recipe {
-        # TODO(ricow): set archive flag when we flip over
-        # properties: "archive:True"
+        properties: "archive:True"
       }
 
     }
@@ -192,6 +191,7 @@
     builders {
       name: "d8-linux-jctf"
       mixins: "linux"
+      dimensions: "jctf:true"
       execution_timeout_secs: 43200  # 12h
       recipe {
         properties: "tool:d8"
@@ -202,6 +202,7 @@
     builders {
       name: "d8-linux-jctf_release"
       mixins: "linux"
+      dimensions: "jctf:true"
       execution_timeout_secs: 43200  # 12h
       recipe {
         properties: "tool:d8"
@@ -313,16 +314,21 @@
     builders {
       name: "linux-internal"
       mixins: "linux"
-      # TODO(move)
+      recipe {
+        properties: "internal:True"
+      }
     }
     builders {
       name: "linux-internal_release"
       mixins: "linux"
-      # TODO(move)
+      recipe {
+        properties: "internal:True"
+      }
     }
     builders {
       name: "linux-jctf"
       mixins: "linux"
+      dimensions: "jctf:true"
       execution_timeout_secs: 43200  # 12h
       recipe {
         properties: "tool:r8"
@@ -333,6 +339,7 @@
     builders {
       name: "linux-jctf_release"
       mixins: "linux"
+      dimensions: "jctf:true"
       execution_timeout_secs: 43200  # 12h
       recipe {
         properties: "tool:r8"
@@ -343,6 +350,7 @@
     builders {
       name: "r8cf-linux-jctf"
       mixins: "linux"
+      dimensions: "jctf:true"
       execution_timeout_secs: 43200  # 12h
       recipe {
         properties: "tool:r8cf"
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index a329c9e..8dc59cb 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -193,3 +193,182 @@
   #    short_name: "win"
   #  }
 }
+
+consoles {
+  id: "main_all"
+  name: "R8 all"
+  repo_url: "https://r8.googlesource.com/r8"
+  refs: "regexp:refs/heads/.*"
+  manifest_name: "REVISION"
+
+  builders {
+    name: "buildbucket/luci.r8.ci/archive"
+    category: "archive"
+    short_name: "archive"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux"
+    category: "R8"
+    short_name: "linux"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-4.0.4"
+    category: "R8"
+    short_name: "4.0.4"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-4.4.4"
+    category: "R8"
+    short_name: "4.4.4"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-5.1.1"
+    category: "R8"
+    short_name: "5.1.1"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-6.0.1"
+    category: "R8"
+    short_name: "6.0.1"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-7.0.0"
+    category: "R8"
+    short_name: "7.0.0"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-internal"
+    category: "R8"
+    short_name: "internal"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-jctf"
+    category: "R8"
+    short_name: "jctf"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/r8cf-linux-jctf"
+    category: "R8"
+    short_name: "cf-jctf"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/d8-linux"
+    category: "D8"
+    short_name: "linux"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/d8-linux-android-4.0.4"
+    category: "D8"
+    short_name: "4.0.4"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/d8-linux-android-4.4.4"
+    category: "D8"
+    short_name: "4.4.4"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/d8-linux-android-5.1.1"
+    category: "D8"
+    short_name: "5.1.1"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/d8-linux-android-6.0.1"
+    category: "D8"
+    short_name: "6.0.1"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/d8-linux-android-7.0.0"
+    category: "D8"
+    short_name: "7.0.0"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/d8-linux-jctf"
+    category: "D8"
+    short_name: "jctf"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/windows"
+    category: "win"
+    short_name: "win"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/archive_release"
+    category: "release archive"
+    short_name: "archive"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux_release"
+    category: "R8 release"
+    short_name: "linux"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-4.0.4_release"
+    category: "R8 release"
+    short_name: "4.0.4"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-4.4.4_release"
+    category: "R8 release"
+    short_name: "4.4.4"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-5.1.1_release"
+    category: "R8 release"
+    short_name: "5.1.1"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-6.0.1_release"
+    category: "R8 release"
+    short_name: "6.0.1"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-android-7.0.0_release"
+    category: "R8 release"
+    short_name: "7.0.0"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-internal_release"
+    category: "R8 release"
+    short_name: "internal"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/linux-jctf_release"
+    category: "R8 release"
+    short_name: "jctf"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/d8-linux_release"
+    category: "D8 release"
+    short_name: "Linux"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/d8-linux-android-4.0.4_release"
+    category: "D8 release"
+    short_name: "4.0.4"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/d8-linux-android-4.4.4_release"
+    category: "D8 release"
+    short_name: "4.4.4"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/d8-linux-android-5.1.1_release"
+    category: "D8 release"
+    short_name: "5.1.1"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/d8-linux-android-6.0.1_release"
+    category: "D8 release"
+    short_name: "6.0.1"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/d8-linux-android-7.0.0_release"
+    category: "D8 release"
+    short_name: "7.0.0"
+  }
+  builders {
+    name: "buildbucket/luci.r8.ci/d8-linux-jctf_release"
+    category: "D8 release"
+    short_name: "jctf"
+  }
+}
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
index 7c867e5..2b67476 100644
--- a/infra/config/global/luci-scheduler.cfg
+++ b/infra/config/global/luci-scheduler.cfg
@@ -23,7 +23,7 @@
     repo: "https://r8.googlesource.com/r8"
     refs: "refs/heads/master"
   }
-
+  triggers: "archive"
   triggers: "d8-linux"
   triggers: "d8-linux"
   triggers: "d8-linux-android-4.0.4"
@@ -39,13 +39,10 @@
   triggers: "linux-android-5.1.1"
   triggers: "linux-android-6.0.1"
   triggers: "linux-android-7.0.0"
+  triggers: "linux-internal"
+  triggers: "linux-jctf"
+  triggers: "r8cf-linux-jctf"
   triggers: "windows"
-  triggers: "archive"
-
-  # TODO(ricow): enable remaining
-  #  triggers: "linux-internal"
-  #  triggers: "linux-jctf"
-  #  triggers: "r8cf-linux-jctf"
 }
 
 trigger {
@@ -55,28 +52,23 @@
     repo: "https://r8.googlesource.com/r8"
     refs: "regexp:refs/heads/d8.*"
   }
+  triggers: "archive_release"
   triggers: "d8-linux-android-4.0.4_release"
   triggers: "d8-linux-android-4.4.4_release"
   triggers: "d8-linux-android-5.1.1_release"
   triggers: "d8-linux-android-6.0.1_release"
   triggers: "d8-linux-android-7.0.0_release"
+  triggers: "d8-linux-jctf_release"
   triggers: "d8-linux_release"
   triggers: "linux-android-4.0.4_release"
   triggers: "linux-android-4.4.4_release"
   triggers: "linux-android-5.1.1_release"
   triggers: "linux-android-6.0.1_release"
   triggers: "linux-android-7.0.0_release"
+  triggers: "linux-internal_release"
+  triggers: "linux-jctf_release"
   triggers: "linux_release"
-
-  # TODO(ricow): enable remaining
-  #  triggers: "archive_release"
-  #  triggers: "d8-linux-jctf_release"
-  #  triggers: "linux-internal_release"
-  #  triggers: "linux-jctf_release"
-
-  # TODO(ricow): Windows on the release branches currently do not work
-  #              There is no java available.
-  # triggers: "windows_release"
+  triggers: "windows_release"
 }
 
 job {
diff --git a/src/main/java/com/android/tools/r8/graph/DexString.java b/src/main/java/com/android/tools/r8/graph/DexString.java
index b591bab..a89ff39 100644
--- a/src/main/java/com/android/tools/r8/graph/DexString.java
+++ b/src/main/java/com/android/tools/r8/graph/DexString.java
@@ -23,7 +23,7 @@
     this.content = content;
   }
 
-  public DexString(String string) {
+  DexString(String string) {
     this.size = string.length();
     this.content = encodeToMutf8(string);
   }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineStaticInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineStaticInterfaceMethodTest.java
new file mode 100644
index 0000000..af29bc7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineStaticInterfaceMethodTest.java
@@ -0,0 +1,53 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.inliner;
+
+import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.junit.Assert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import org.junit.Test;
+
+public class InlineStaticInterfaceMethodTest extends TestBase {
+
+  @Test
+  public void test() throws Exception {
+    String expectedOutput = StringUtils.lines("Hello world!");
+
+    CodeInspector inspector =
+        testForR8(Backend.DEX)
+            .addInnerClasses(InlineStaticInterfaceMethodTest.class)
+            .addKeepMainRule(TestClass.class)
+            .setMinApi(AndroidApiLevel.M)
+            .run(TestClass.class)
+            .assertSuccessWithOutput(expectedOutput)
+            .inspector();
+
+    // TODO(b/124017330): greet() should have been inlined into main().
+    ClassSubject classSubject =
+        inspector.clazz(I.class.getTypeName() + COMPANION_CLASS_NAME_SUFFIX);
+    assertThat(classSubject, isPresent());
+    assertThat(classSubject.uniqueMethodWithName("greet"), isPresent());
+  }
+
+  static class TestClass {
+
+    public static void main(String[] args) {
+      I.greet();
+    }
+  }
+
+  interface I {
+
+    static void greet() {
+      System.out.println("Hello world!");
+    }
+  }
+}
diff --git a/third_party/android_sdk.tar.gz.sha1 b/third_party/android_sdk.tar.gz.sha1
index ebc2c1d..9a9b464 100644
--- a/third_party/android_sdk.tar.gz.sha1
+++ b/third_party/android_sdk.tar.gz.sha1
@@ -1 +1 @@
-fdbcfa08e6a1772bc9569bf706819a95a15bc3a0
\ No newline at end of file
+acfc4d8ff4def954eb85da4bd5fff3a63764c09d
\ No newline at end of file
diff --git a/tools/archive.py b/tools/archive.py
index f86530a..c842c69 100755
--- a/tools/archive.py
+++ b/tools/archive.py
@@ -26,6 +26,7 @@
   return result.parse_args()
 
 def GetToolVersion(jar_path):
+  # TODO(mkroghj) This would not work for r8-lib, maybe use utils.getR8Version.
   output = subprocess.check_output([
     jdk.GetJavaExecutable(), '-jar', jar_path, '--version'
   ])
@@ -94,8 +95,8 @@
   if not utils.is_bot() and not options.dry_run:
     raise Exception('You are not a bot, don\'t archive builds')
 
-  if utils.is_new_bot():
-    print("Archiving is disabled on new bots.")
+  if utils.is_old_bot():
+    print("Archiving is disabled on old bots.")
     return
 
   # Create maven release which uses a build that exclude dependencies.
@@ -135,7 +136,7 @@
     with open(version_file,'w') as version_writer:
       version_writer.write('version.sha=' + GetGitHash() + '\n')
       version_writer.write(
-          'releaser=go/r8bot (' + os.environ.get('BUILDBOT_SLAVENAME') + ')\n')
+          'releaser=go/r8bot (' + os.environ.get('SWARMING_BOT_ID') + ')\n')
       version_writer.write('version-file.version.code=1\n')
 
     for file in [
diff --git a/tools/internal_test.py b/tools/internal_test.py
index a9a90eb..032f1fe 100755
--- a/tools/internal_test.py
+++ b/tools/internal_test.py
@@ -193,6 +193,9 @@
         print('\n\n%s had value:\n%s' % (to_print, value))
 
 def run_bot():
+  if utils.is_old_bot():
+    print('Not running on on old bot, please see: https://ci.chromium.org/p/r8')
+    return
   print_magic_file_state()
   # Ensure that there is nothing currently scheduled (broken/stopped run)
   for magic in ALL_MAGIC:
diff --git a/tools/run_on_as_app.py b/tools/run_on_as_app.py
index fef337a..d95453f 100755
--- a/tools/run_on_as_app.py
+++ b/tools/run_on_as_app.py
@@ -198,12 +198,15 @@
   assert len(lines) >= 1
   return lines[-1]
 
-def CheckIsBuiltWithExpectedR8(apk, temp_dir, options):
+def CheckIsBuiltWithExpectedR8(apk, temp_dir, shrinker, options):
   marker = ExtractMarker(apk, temp_dir, options)
   expected_version = (
       options.version
       if options.version
-      else create_maven_release.determine_version())
+      else utils.getR8Version(
+          os.path.join(
+              temp_dir,
+              'r8lib.jar' if IsMinifiedR8(shrinker) else 'r8.jar')))
   if marker.startswith('~~R8'):
     actual_version = json.loads(marker[4:]).get('version')
     if actual_version == expected_version:
@@ -509,7 +512,7 @@
     as_utils.MoveFile(unsigned_apk, apk_dest, quiet=options.quiet)
 
   assert ('r8' not in shrinker
-      or CheckIsBuiltWithExpectedR8(apk_dest, temp_dir, options))
+      or CheckIsBuiltWithExpectedR8(apk_dest, temp_dir, shrinker, options))
 
   profile_dest_dir = os.path.join(out_dir, 'profile')
   as_utils.MoveProfileReportTo(profile_dest_dir, stdout, quiet=options.quiet)
diff --git a/tools/test.py b/tools/test.py
index d6753ed..a7e0b98 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -253,6 +253,10 @@
 
   # Now run tests on selected runtime(s).
   vms_to_test = [options.dex_vm] if options.dex_vm != "all" else ALL_ART_VMS
+  # TODO(126683699): remove once we have single run
+  if options.dex_vm == 'all' and options.only_jctf:
+    vms_to_test = ["default",  "5.1.1"]
+
   for art_vm in vms_to_test:
     vm_kind_to_test = "_" + options.dex_vm_kind if art_vm != "default" else ""
     return_code = gradle.RunGradle(gradle_args + ['-Pdex_vm=%s' % (art_vm + vm_kind_to_test)],
diff --git a/tools/utils.py b/tools/utils.py
index 12535be..8c168a6 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -488,8 +488,18 @@
 def is_new_bot():
   return 'SWARMING_BOT_ID' in os.environ
 
+def is_old_bot():
+  return 'BUILDBOT_SLAVENAME' in os.environ
+
 def is_bot():
   return 'USER' in os.environ and os.environ['USER'] == 'chrome-bot'
 
 def uncompressed_size(path):
   return sum(z.file_size for z in zipfile.ZipFile(path).infolist())
+
+def getR8Version(path):
+  cmd = [jdk.GetJavaExecutable(), '-cp', path, 'com.android.tools.r8.R8',
+        '--version']
+  output = subprocess.check_output(cmd, stderr = subprocess.STDOUT)
+  # output is on form 'R8 <version>' so we just strip of 'R8 '.
+  return output.splitlines()[0][3:]
diff --git a/tools/windows/README.dx b/tools/windows/README.dx
index 4d93487..c9f4c54 100644
--- a/tools/windows/README.dx
+++ b/tools/windows/README.dx
@@ -4,6 +4,8 @@
 is removed and replaced by a direct reference to it.

 This is done because this relies on a tool found in the SDK and not present in the

 current package.

+Also, the deprecated java.ext.dirs argument has been removed.

+

 Diff:

 

 26,29c26,29

@@ -19,7 +21,7 @@
 87c87

 < call "%java_exe%" %javaOpts% -Djava.ext.dirs="%frameworkdir%" -jar "%jarpath%" %params%

 ---

-> call java %javaOpts% -Djava.ext.dirs="%frameworkdir%" -jar "%jarpath%" %params%

+> call java %javaOpts% -jar "%jarpath%" %params%

 

 dexmerger.bat has been copied from dx.bat, and the command line has been updated

 according to the SDK dexmerger bash script to call the right class.
\ No newline at end of file
diff --git a/tools/windows/dx.tar.gz.sha1 b/tools/windows/dx.tar.gz.sha1
index 867adab..46c3ee8 100644
--- a/tools/windows/dx.tar.gz.sha1
+++ b/tools/windows/dx.tar.gz.sha1
@@ -1 +1 @@
-47414f7ebc8a8cc14b29fc6732510a20947870aa
\ No newline at end of file
+42495c1c7914814e4cfe7f3c199fbbac6711c37e
\ No newline at end of file