|  | // Copyright (c) 2021, 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.repackage; | 
|  |  | 
|  | import static org.hamcrest.MatcherAssert.assertThat; | 
|  | import static org.junit.Assert.assertEquals; | 
|  | import static org.junit.Assume.assumeTrue; | 
|  |  | 
|  | import com.android.tools.r8.R8TestCompileResult; | 
|  | import com.android.tools.r8.TestParameters; | 
|  | import com.android.tools.r8.references.Reference; | 
|  | import com.android.tools.r8.utils.StringUtils; | 
|  | import com.google.common.collect.ImmutableList; | 
|  | import java.util.List; | 
|  | import org.junit.Test; | 
|  | import org.junit.runner.RunWith; | 
|  | import org.junit.runners.Parameterized; | 
|  |  | 
|  | @RunWith(Parameterized.class) | 
|  | public class RepackageFeatureWithSyntheticsTest extends RepackageTestBase { | 
|  |  | 
|  | public RepackageFeatureWithSyntheticsTest( | 
|  | String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) { | 
|  | super(flattenPackageHierarchyOrRepackageClasses, parameters); | 
|  | } | 
|  |  | 
|  | private static final Class<?> FIRST_FOO = | 
|  | com.android.tools.r8.repackage.testclasses.repackagefeaturewithsynthetics.first.Foo.class; | 
|  |  | 
|  | private static final Class<?> FIRST_PKG_PRIVATE = | 
|  | com.android.tools.r8.repackage.testclasses.repackagefeaturewithsynthetics.first | 
|  | .PkgProtectedMethod.class; | 
|  |  | 
|  | private static final List<Class<?>> FIRST_CLASSES = | 
|  | ImmutableList.of(FIRST_FOO, FIRST_PKG_PRIVATE); | 
|  |  | 
|  | private static final Class<?> FIRST_FIRST_FOO = | 
|  | com.android.tools.r8.repackage.testclasses.repackagefeaturewithsynthetics.first.first.Foo | 
|  | .class; | 
|  |  | 
|  | private static final Class<?> FIRST_FIRST_PKG_PRIVATE = | 
|  | com.android.tools.r8.repackage.testclasses.repackagefeaturewithsynthetics.first.first | 
|  | .PkgProtectedMethod.class; | 
|  |  | 
|  | private static final List<Class<?>> FIRST_FIRST_CLASSES = | 
|  | ImmutableList.of(FIRST_FIRST_FOO, FIRST_FIRST_PKG_PRIVATE); | 
|  |  | 
|  | private static List<Class<?>> getTestClasses() { | 
|  | return ImmutableList.<Class<?>>builder() | 
|  | .addAll(getBaseClasses()) | 
|  | .add(TestClass.class) | 
|  | .add(I.class) | 
|  | .build(); | 
|  | } | 
|  |  | 
|  | private static List<Class<?>> getBaseClasses() { | 
|  | return FIRST_CLASSES; | 
|  | } | 
|  |  | 
|  | private static List<Class<?>> getFeatureClasses() { | 
|  | return FIRST_FIRST_CLASSES; | 
|  | } | 
|  |  | 
|  | private static String EXPECTED = StringUtils.lines("first.Foo", "first.first.Foo"); | 
|  |  | 
|  | @Override | 
|  | public String getRepackagePackage() { | 
|  | return "dest"; | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void testReference() throws Exception { | 
|  | testForRuntime(parameters) | 
|  | .addProgramClasses(getTestClasses()) | 
|  | .addProgramClasses(getFeatureClasses()) | 
|  | .run(parameters.getRuntime(), TestClass.class) | 
|  | .assertSuccessWithOutput(EXPECTED); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void test() throws Exception { | 
|  | assumeTrue("Feature splits require DEX output.", parameters.isDexRuntime()); | 
|  | R8TestCompileResult compileResult = | 
|  | testForR8(parameters.getBackend()) | 
|  | .addProgramClasses(getTestClasses()) | 
|  | .addFeatureSplit(getFeatureClasses().toArray(new Class<?>[0])) | 
|  | .addKeepMainRule(TestClass.class) | 
|  | .addKeepClassAndMembersRules(FIRST_PKG_PRIVATE, FIRST_FIRST_PKG_PRIVATE) | 
|  | .addKeepClassAndMembersRules(I.class) | 
|  | .addKeepMethodRules( | 
|  | Reference.methodFromMethod(TestClass.class.getDeclaredMethod("run", I.class))) | 
|  | .addKeepAttributeInnerClassesAndEnclosingMethod() | 
|  | .apply(this::configureRepackaging) | 
|  | .enableNeverClassInliningAnnotations() | 
|  | .setMinApi(parameters.getApiLevel()) | 
|  | .compile(); | 
|  |  | 
|  | // Each Foo class will give rise to a single lambda. | 
|  | int expectedSyntheticsInBase = 1; | 
|  | int expectedSyntheticsInFeature = 1; | 
|  |  | 
|  | // Check that the first.Foo is repackaged but that the pkg private access class is not. | 
|  | // The implies that the lambda which is doing a package private access cannot be repackaged. | 
|  | // If it is, the access will fail resulting in a runtime exception. | 
|  | compileResult.inspect( | 
|  | baseInspector -> { | 
|  | assertThat(FIRST_FOO, isRepackagedAsExpected(baseInspector, "a")); | 
|  | assertThat(FIRST_PKG_PRIVATE, isNotRepackaged(baseInspector)); | 
|  | assertEquals( | 
|  | getTestClasses().size() + expectedSyntheticsInBase, | 
|  | baseInspector.allClasses().size()); | 
|  | }, | 
|  | featureInspector -> { | 
|  | assertThat(FIRST_FIRST_FOO, isRepackagedAsExpected(featureInspector, "b")); | 
|  | assertThat(FIRST_FIRST_PKG_PRIVATE, isNotRepackaged(featureInspector)); | 
|  | assertEquals( | 
|  | getFeatureClasses().size() + expectedSyntheticsInFeature, | 
|  | featureInspector.allClasses().size()); | 
|  | }); | 
|  |  | 
|  | compileResult | 
|  | .addFeatureSplitsToRunClasspathFiles() | 
|  | .run(parameters.getRuntime(), TestClass.class) | 
|  | .assertSuccessWithOutputLines("first.Foo", "first.first.Foo"); | 
|  | } | 
|  |  | 
|  | public interface I { | 
|  | void run(); | 
|  | } | 
|  |  | 
|  | public static class TestClass { | 
|  |  | 
|  | // Public kept run method to accept a lambda ensuring desugaring which cannot be optimized out. | 
|  | public static void run(I i) { | 
|  | i.run(); | 
|  | } | 
|  |  | 
|  | public static void main(String[] args) { | 
|  | new com.android.tools.r8.repackage.testclasses.repackagefeaturewithsynthetics.first.Foo(); | 
|  | new com.android.tools.r8.repackage.testclasses.repackagefeaturewithsynthetics.first.first | 
|  | .Foo(); | 
|  | } | 
|  | } | 
|  | } |