Reflection package access

Change-Id: I35d4534766a2076f779e7e7e32baf1b2db704fdf
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
index 0df3c80..3bc0ebe 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
@@ -311,7 +311,6 @@
             DexEncodedField field =
                 appView.appInfo().resolveField(info.getField()).getResolvedField();
             if (field == null) {
-              assert false;
               return;
             }
             if (!info.hasReflectiveAccess() && !info.isWrittenFromMethodHandle()) {
diff --git a/src/test/examplesJava11/annotations/NeverClassInline.java b/src/test/examplesJava11/com/android/tools/r8/NeverClassInline.java
similarity index 89%
rename from src/test/examplesJava11/annotations/NeverClassInline.java
rename to src/test/examplesJava11/com/android/tools/r8/NeverClassInline.java
index 0c8b9d1..19c4504 100644
--- a/src/test/examplesJava11/annotations/NeverClassInline.java
+++ b/src/test/examplesJava11/com/android/tools/r8/NeverClassInline.java
@@ -2,6 +2,6 @@
 // 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 annotations;
+package com.android.tools.r8;
 
 public @interface NeverClassInline {}
diff --git a/src/test/examplesJava11/annotations/NeverInline.java b/src/test/examplesJava11/com/android/tools/r8/NeverInline.java
similarity index 91%
rename from src/test/examplesJava11/annotations/NeverInline.java
rename to src/test/examplesJava11/com/android/tools/r8/NeverInline.java
index 1c22094..cd01ce1 100644
--- a/src/test/examplesJava11/annotations/NeverInline.java
+++ b/src/test/examplesJava11/com/android/tools/r8/NeverInline.java
@@ -2,7 +2,7 @@
 // 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 annotations;
+package com.android.tools.r8;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Target;
diff --git a/src/test/examplesJava11/horizontalclassmerging/BasicNestHostHorizontalClassMerging.java b/src/test/examplesJava11/horizontalclassmerging/BasicNestHostHorizontalClassMerging.java
index 2e24e97..2362165 100644
--- a/src/test/examplesJava11/horizontalclassmerging/BasicNestHostHorizontalClassMerging.java
+++ b/src/test/examplesJava11/horizontalclassmerging/BasicNestHostHorizontalClassMerging.java
@@ -4,8 +4,8 @@
 
 package horizontalclassmerging;
 
-import annotations.NeverClassInline;
-import annotations.NeverInline;
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
 
 public class BasicNestHostHorizontalClassMerging {
   // Prevent merging with BasicNestHostHorizontalClassMerging2.
@@ -17,16 +17,13 @@
 
   @NeverInline
   private void print(String v) {
-    /* if (System.currentTimeMillis() < 0) {
-      name = "never";
-    } */
     System.out.println(name + ": " + v);
   }
 
   public static void main(String[] args) {
     BasicNestHostHorizontalClassMerging host = new BasicNestHostHorizontalClassMerging("1");
-    A a = new A(host);
-    B b = new B(host);
+    new A(host);
+    new B(host);
     BasicNestHostHorizontalClassMerging2.main(args);
   }
 
diff --git a/src/test/examplesJava11/horizontalclassmerging/BasicNestHostHorizontalClassMerging2.java b/src/test/examplesJava11/horizontalclassmerging/BasicNestHostHorizontalClassMerging2.java
index d25b8d2..78718e1 100644
--- a/src/test/examplesJava11/horizontalclassmerging/BasicNestHostHorizontalClassMerging2.java
+++ b/src/test/examplesJava11/horizontalclassmerging/BasicNestHostHorizontalClassMerging2.java
@@ -4,18 +4,14 @@
 
 package horizontalclassmerging;
 
-import annotations.NeverClassInline;
-import annotations.NeverInline;
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
 
 public class BasicNestHostHorizontalClassMerging2 {
   @NeverInline
   public static void main(String[] args) {
-    A a = new A();
-    B b = new B();
-    if (System.currentTimeMillis() < 0) {
-      System.out.println(a);
-      System.out.println(b);
-    }
+    new A();
+    new B();
   }
 
   @NeverInline
diff --git a/src/test/examplesJava11/nesthostexample/BasicNestHostClassMerging.java b/src/test/examplesJava11/nesthostexample/BasicNestHostClassMerging.java
index d1b6a5c..184c201 100644
--- a/src/test/examplesJava11/nesthostexample/BasicNestHostClassMerging.java
+++ b/src/test/examplesJava11/nesthostexample/BasicNestHostClassMerging.java
@@ -4,7 +4,7 @@
 
 package nesthostexample;
 
-import annotations.NeverInline;
+import com.android.tools.r8.NeverInline;
 
 public class BasicNestHostClassMerging {
 
diff --git a/src/test/examplesJava11/nesthostexample/BasicNestHostTreePruning.java b/src/test/examplesJava11/nesthostexample/BasicNestHostTreePruning.java
index 3088ed4..484c81a 100644
--- a/src/test/examplesJava11/nesthostexample/BasicNestHostTreePruning.java
+++ b/src/test/examplesJava11/nesthostexample/BasicNestHostTreePruning.java
@@ -4,7 +4,7 @@
 
 package nesthostexample;
 
-import annotations.NeverInline;
+import com.android.tools.r8.NeverInline;
 
 public class BasicNestHostTreePruning {
 
diff --git a/src/test/examplesJava11/nesthostexample/NestHostInliningSubclasses.java b/src/test/examplesJava11/nesthostexample/NestHostInliningSubclasses.java
index 6185c37..4221307 100644
--- a/src/test/examplesJava11/nesthostexample/NestHostInliningSubclasses.java
+++ b/src/test/examplesJava11/nesthostexample/NestHostInliningSubclasses.java
@@ -4,7 +4,7 @@
 
 package nesthostexample;
 
-import annotations.NeverInline;
+import com.android.tools.r8.NeverInline;
 
 public class NestHostInliningSubclasses {
 
diff --git a/src/test/examplesJava11/nesthostexample/NestPvtMethodCallInlined.java b/src/test/examplesJava11/nesthostexample/NestPvtMethodCallInlined.java
index 7a5f40e..cdbe725 100644
--- a/src/test/examplesJava11/nesthostexample/NestPvtMethodCallInlined.java
+++ b/src/test/examplesJava11/nesthostexample/NestPvtMethodCallInlined.java
@@ -4,7 +4,7 @@
 
 package nesthostexample;
 
-import annotations.NeverInline;
+import com.android.tools.r8.NeverInline;
 
 public class NestPvtMethodCallInlined {
 
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index f9eaa24..c3c51de 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -72,6 +72,8 @@
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.PreloadedClassFileProvider;
+import com.android.tools.r8.utils.ReflectiveBuildPathUtils;
+import com.android.tools.r8.utils.ReflectiveBuildPathUtils.ExamplesClass;
 import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.TestDescriptionWatcher;
@@ -1654,6 +1656,10 @@
     return clazz.getTypeName();
   }
 
+  public static String examplesTypeName(Class<? extends ExamplesClass> clazz) throws Exception {
+    return ReflectiveBuildPathUtils.resolveClassName(clazz);
+  }
+
   public static AndroidApiLevel apiLevelWithDefaultInterfaceMethodsSupport() {
     return AndroidApiLevel.N;
   }
diff --git a/src/test/java/com/android/tools/r8/TestBaseBuilder.java b/src/test/java/com/android/tools/r8/TestBaseBuilder.java
index 1fe43fb..1e75de5 100644
--- a/src/test/java/com/android/tools/r8/TestBaseBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestBaseBuilder.java
@@ -10,6 +10,8 @@
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.ListUtils;
+import com.android.tools.r8.utils.ReflectiveBuildPathUtils;
+import com.android.tools.r8.utils.ReflectiveBuildPathUtils.ExamplesRootPackage;
 import com.google.common.collect.ImmutableMap;
 import java.nio.file.Path;
 import java.util.Arrays;
@@ -54,6 +56,12 @@
     return self();
   }
 
+  public T addExamplesProgramFiles(Class<? extends ExamplesRootPackage> rootPackage)
+      throws Exception {
+    Collection<Path> files = ReflectiveBuildPathUtils.allClassFiles(rootPackage);
+    return addProgramFiles(files);
+  }
+
   public T addLibraryProvider(ClassFileResourceProvider provider) {
     builder.addLibraryResourceProvider(provider);
     return self();
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NestClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NestClassTest.java
index 97ad3ce..5edc29f 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/NestClassTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NestClassTest.java
@@ -7,42 +7,38 @@
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPrivate;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isStatic;
-import static org.hamcrest.CoreMatchers.not;
+import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.desugar.nestaccesscontrol.NestAccessControlTestUtils;
+import com.android.tools.r8.classmerging.horizontal.NestClassTest.R.horizontalclassmerging.BasicNestHostHorizontalClassMerging;
+import com.android.tools.r8.classmerging.horizontal.NestClassTest.R.horizontalclassmerging.BasicNestHostHorizontalClassMerging2;
 import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.ReflectiveBuildPathUtils.ExamplesClass;
+import com.android.tools.r8.utils.ReflectiveBuildPathUtils.ExamplesJava11RootPackage;
+import com.android.tools.r8.utils.ReflectiveBuildPathUtils.ExamplesPackage;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import com.google.common.collect.ImmutableList;
-import java.nio.file.Path;
 import java.util.List;
-import java.util.stream.Collectors;
 import org.junit.Test;
 import org.junit.runners.Parameterized;
 
 public class NestClassTest extends HorizontalClassMergingTestBase {
-  public static final String PACKAGE_NAME = "horizontalclassmerging.";
-  private final String NEST_MAIN_CLASS_1 = PACKAGE_NAME + "BasicNestHostHorizontalClassMerging";
-  private final String NEST_MAIN_CLASS_1A = NEST_MAIN_CLASS_1 + "$A";
-  private final String NEST_MAIN_CLASS_1B = NEST_MAIN_CLASS_1 + "$B";
-  private final String NEST_MAIN_CLASS_2 = PACKAGE_NAME + "BasicNestHostHorizontalClassMerging2";
-  private final String NEST_MAIN_CLASS_2A = NEST_MAIN_CLASS_2 + "$A";
-  private final String NEST_MAIN_CLASS_2B = NEST_MAIN_CLASS_2 + "$B";
+  public static class R extends ExamplesJava11RootPackage {
+    public static class horizontalclassmerging extends ExamplesPackage {
+      public static class BasicNestHostHorizontalClassMerging extends ExamplesClass {
+        public static class A extends ExamplesClass {}
 
-  private List<Path> resolveProgramFiles() {
-    return ImmutableList.of(
-            NEST_MAIN_CLASS_1,
-            NEST_MAIN_CLASS_1A,
-            NEST_MAIN_CLASS_1B,
-            NEST_MAIN_CLASS_2,
-            NEST_MAIN_CLASS_2A,
-            NEST_MAIN_CLASS_2B)
-        .stream()
-        .map(NestAccessControlTestUtils.CLASSES_PATH::resolve)
-        .collect(Collectors.toList());
+        public static class B extends ExamplesClass {}
+      }
+
+      public static class BasicNestHostHorizontalClassMerging2 extends ExamplesClass {
+        public static class A extends ExamplesClass {}
+
+        public static class B extends ExamplesClass {}
+      }
+    }
   }
 
   public NestClassTest(TestParameters parameters, boolean enableHorizontalClassMerging) {
@@ -59,21 +55,27 @@
   @Test
   public void testR8() throws Exception {
     testForR8(parameters.getBackend())
-        .addKeepMainRule(NEST_MAIN_CLASS_1)
-        .addProgramFiles(resolveProgramFiles())
+        .addKeepMainRule(examplesTypeName(BasicNestHostHorizontalClassMerging.class))
+        .addExamplesProgramFiles(R.class)
         .addOptionsModification(
             options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
         .compile()
-        .run(parameters.getRuntime(), NEST_MAIN_CLASS_1)
+        .run(parameters.getRuntime(), examplesTypeName(BasicNestHostHorizontalClassMerging.class))
         .assertSuccessWithOutputLines("1: a", "1: b", "2: a", "2: b")
         .inspect(
             codeInspector -> {
-              ClassSubject class1A = codeInspector.clazz(NEST_MAIN_CLASS_1A);
-              ClassSubject class2A = codeInspector.clazz(NEST_MAIN_CLASS_2A);
-              ClassSubject class1 = codeInspector.clazz(NEST_MAIN_CLASS_1);
-              ClassSubject class2 = codeInspector.clazz(NEST_MAIN_CLASS_2);
+              ClassSubject class1A =
+                  codeInspector.clazz(
+                      examplesTypeName(BasicNestHostHorizontalClassMerging.A.class));
+              ClassSubject class2A =
+                  codeInspector.clazz(
+                      examplesTypeName(BasicNestHostHorizontalClassMerging2.A.class));
+              ClassSubject class1 =
+                  codeInspector.clazz(examplesTypeName(BasicNestHostHorizontalClassMerging.class));
+              ClassSubject class2 =
+                  codeInspector.clazz(examplesTypeName(BasicNestHostHorizontalClassMerging2.class));
               assertThat(class1, isPresent());
               assertThat(class2, isPresent());
               assertThat(class1A, isPresent());
@@ -90,13 +92,16 @@
               assertThat(printClass2MethodSubject, isPrivate());
               assertThat(printClass2MethodSubject, isStatic());
 
-              if (enableHorizontalClassMerging) {
-                assertThat(codeInspector.clazz(NEST_MAIN_CLASS_1B), not(isPresent()));
-                assertThat(codeInspector.clazz(NEST_MAIN_CLASS_2B), not(isPresent()));
-              } else {
-                assertThat(codeInspector.clazz(NEST_MAIN_CLASS_1B), isPresent());
-                assertThat(codeInspector.clazz(NEST_MAIN_CLASS_2B), isPresent());
-              }
+              assertThat(
+                  codeInspector.clazz(
+                      examplesTypeName(BasicNestHostHorizontalClassMerging.B.class)),
+                  notIf(isPresent(), enableHorizontalClassMerging));
+              assertThat(
+                  codeInspector.clazz(
+                      examplesTypeName(BasicNestHostHorizontalClassMerging2.B.class)),
+                  notIf(isPresent(), enableHorizontalClassMerging));
+
+              // TODO(b/165517236): Explicitly check 1.B is merged into 1.A, and 2.B into 2.A.
             });
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java
index b65e764..e45ef92 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java
@@ -96,7 +96,7 @@
                   options.enableClassInlining = false;
                   options.enableNestReduction = false;
                 })
-            .enableInliningAnnotations("nesthostexample")
+            .enableInliningAnnotations()
             .addProgramFiles(bothNestsAndOutsideClassToCompile)
             .compile()
             .inspect(NestAttributesUpdateTest::assertNestAttributesCorrect);
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestMethodInlinedTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestMethodInlinedTest.java
index 4fcfea3..373f6fc 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestMethodInlinedTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestMethodInlinedTest.java
@@ -59,7 +59,7 @@
               options.enableClassInlining = false;
               options.enableVerticalClassMerging = false;
             })
-        .enableInliningAnnotations("nesthostexample")
+        .enableInliningAnnotations()
         .addProgramFiles(toCompile)
         .compile()
         .inspect(this::assertMethodsInlined)
diff --git a/src/test/java/com/android/tools/r8/utils/ReflectiveBuildPathUtils.java b/src/test/java/com/android/tools/r8/utils/ReflectiveBuildPathUtils.java
new file mode 100644
index 0000000..ed991f2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/ReflectiveBuildPathUtils.java
@@ -0,0 +1,168 @@
+// Copyright (c) 2020, 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.utils;
+
+import com.android.tools.r8.ToolHelper;
+import com.google.common.collect.Iterables;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+public class ReflectiveBuildPathUtils {
+
+  public interface PackageUtils {
+    String getPackageName() throws Exception;
+
+    Path getPackagePath() throws Exception;
+
+    PackageUtils getParentPackageUtils() throws Exception;
+
+    Iterable<PackageUtils> getAllPackageUtils();
+  }
+
+  public interface ClassUtils {
+    String getClassName() throws Exception;
+
+    String getSimpleClassName() throws Exception;
+
+    Path getClassPath() throws Exception;
+  }
+
+  public abstract static class ExamplesRootPackage implements PackageUtils {
+    public abstract Path getPackagePath();
+
+    @Override
+    public String getPackageName() {
+      return "";
+    }
+
+    @Override
+    public PackageUtils getParentPackageUtils() {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Iterable<PackageUtils> getAllPackageUtils() {
+      return instantiateAllPackageUtils(getClass());
+    }
+  }
+
+  public abstract static class ExamplesJava11RootPackage extends ExamplesRootPackage {
+    @Override
+    public Path getPackagePath() {
+      return Paths.get(ToolHelper.EXAMPLES_JAVA11_BUILD_DIR);
+    }
+  }
+
+  public abstract static class ExamplesPackage implements PackageUtils {
+    public List<String> getName() {
+      return Collections.singletonList(getClass().getSimpleName());
+    }
+
+    @Override
+    public PackageUtils getParentPackageUtils() throws Exception {
+      return (PackageUtils) getClass().getDeclaringClass().getConstructor().newInstance();
+    }
+
+    @Override
+    public Path getPackagePath() throws Exception {
+      Path path = getParentPackageUtils().getPackagePath();
+      for (String folder : getName()) {
+        path = path.resolve(folder);
+      }
+      return path;
+    }
+
+    @Override
+    public String getPackageName() throws Exception {
+      return getParentPackageUtils().getPackageName() + String.join(".", getName()) + ".";
+    }
+
+    @Override
+    public Iterable<PackageUtils> getAllPackageUtils() {
+      return instantiateAllPackageUtils(getClass());
+    }
+  }
+
+  public static class ExamplesClass implements PackageUtils, ClassUtils {
+    @Override
+    public PackageUtils getParentPackageUtils() throws Exception {
+      return (PackageUtils) getClass().getDeclaringClass().getConstructor().newInstance();
+    }
+
+    public String getSimpleClassName() throws Exception {
+      Object parent = getClass().getDeclaringClass().getConstructor().newInstance();
+      if (parent instanceof ClassUtils) {
+        return ((ClassUtils) parent).getSimpleClassName() + "$" + getClass().getSimpleName();
+      } else {
+        return getClass().getSimpleName();
+      }
+    }
+
+    @Override
+    public String getClassName() throws Exception {
+      return getParentPackageUtils().getPackageName() + getSimpleClassName();
+    }
+
+    @Override
+    public Path getClassPath() throws Exception {
+      return getParentPackageUtils().getPackagePath().resolve(getSimpleClassName() + ".class");
+    }
+
+    @Override
+    public String getPackageName() throws Exception {
+      return getParentPackageUtils().getPackageName();
+    }
+
+    @Override
+    public Path getPackagePath() throws Exception {
+      return getParentPackageUtils().getPackagePath();
+    }
+
+    @Override
+    public Iterable<PackageUtils> getAllPackageUtils() {
+      return instantiateAllPackageUtils(getClass());
+    }
+  }
+
+  public static Iterable<PackageUtils> instantiateAllPackageUtils(Class<?> parentClazz) {
+    Collection<PackageUtils> children = instantiatePackageUtils(parentClazz);
+    return Iterables.concat(
+        children,
+        Iterables.concat(Iterables.transform(children, PackageUtils::getAllPackageUtils)));
+  }
+
+  public static Collection<PackageUtils> instantiatePackageUtils(Class<?> parentClazz) {
+    Collection<PackageUtils> packageUtils = new ArrayList<>();
+    for (Class<?> clazz : parentClazz.getDeclaredClasses()) {
+      try {
+        Object obj = clazz.getConstructor().newInstance();
+        if (obj instanceof PackageUtils) {
+          packageUtils.add((PackageUtils) obj);
+        }
+      } catch (Exception ex) {
+      }
+    }
+    return packageUtils;
+  }
+
+  public static String resolveClassName(Class<? extends ExamplesClass> clazz) throws Exception {
+    return clazz.getConstructor().newInstance().getClassName();
+  }
+
+  public static Collection<Path> allClassFiles(Class<? extends ExamplesRootPackage> clazz)
+      throws Exception {
+    Collection<Path> classFiles = new ArrayList<>();
+    for (PackageUtils util : clazz.getConstructor().newInstance().getAllPackageUtils()) {
+      if (util instanceof ClassUtils) {
+        classFiles.add(((ClassUtils) util).getClassPath());
+      }
+    }
+    return classFiles;
+  }
+}