|  | // 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.shaking.ifrule; | 
|  |  | 
|  | import com.android.tools.r8.shaking.forceproguardcompatibility.ProguardCompatibilityTestBase; | 
|  | import com.android.tools.r8.utils.InternalOptions; | 
|  | import com.android.tools.r8.utils.codeinspector.CodeInspector; | 
|  | import com.google.common.collect.ImmutableList; | 
|  | import java.util.ArrayList; | 
|  | import java.util.Collection; | 
|  | import java.util.List; | 
|  | import java.util.function.Consumer; | 
|  | 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 IfOnFieldTest extends ProguardCompatibilityTestBase { | 
|  | private static final List<Class<?>> CLASSES = | 
|  | ImmutableList.of( | 
|  | D.class, | 
|  | D1.class, | 
|  | D2.class, | 
|  | R.class, | 
|  | R1.class, | 
|  | R2.class, | 
|  | MainWithInner.InnerR.class, | 
|  | MainWithInner.InnerD.class, | 
|  | I.class, | 
|  | Impl.class, | 
|  | MainUsesR.class, | 
|  | MainWithIf.class, | 
|  | MainWithInner.class, | 
|  | MainUsesImpl.class); | 
|  |  | 
|  | private final Shrinker shrinker; | 
|  |  | 
|  | public IfOnFieldTest(Shrinker shrinker) { | 
|  | this.shrinker = shrinker; | 
|  | } | 
|  |  | 
|  | @Parameters(name = "shrinker: {0}") | 
|  | public static Collection<Object> data() { | 
|  | return ImmutableList.of(Shrinker.PROGUARD6, Shrinker.R8, Shrinker.R8_CF); | 
|  | } | 
|  |  | 
|  | private String adaptConfiguration(String proguardConfig) { | 
|  | List<String> configWithPrecondition = new ArrayList<>(); | 
|  | configWithPrecondition.add(proguardConfig); | 
|  | configWithPrecondition.add("-dontobfuscate"); | 
|  | return String.join(System.lineSeparator(), configWithPrecondition); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | protected CodeInspector inspectR8Result( | 
|  | List<Class<?>> programClasses, | 
|  | String proguardConfig, | 
|  | Consumer<InternalOptions> config, | 
|  | Backend backend) | 
|  | throws Exception { | 
|  | return super.inspectR8Result( | 
|  | programClasses, adaptConfiguration(proguardConfig), config, backend); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | protected CodeInspector inspectProguard6Result( | 
|  | List<Class<?>> programClasses, String proguardConfig) throws Exception { | 
|  | return super.inspectProguard6Result(programClasses, adaptConfiguration(proguardConfig)); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void ifOnField_withoutNthWildcard() throws Exception { | 
|  | List<String> config = ImmutableList.of( | 
|  | "-keep class **.MainUsesR {", | 
|  | "  public static void main(java.lang.String[]);", | 
|  | "}", | 
|  | // R.id1 -> D1 | 
|  | "-if class **.R {", | 
|  | "  public static int id1;", | 
|  | "}", | 
|  | "-keep class **.D1", | 
|  | // R.id2 -> D2 | 
|  | "-if class **.R {", | 
|  | "  public static int id2;", | 
|  | "}", | 
|  | "-keep class **.D2", | 
|  | // R.id1 && R.id2 -> D | 
|  | "-if class **.R {", | 
|  | "  public static int id1;", | 
|  | "  public static int id2;", | 
|  | "}", | 
|  | "-keep class **.D" | 
|  | ); | 
|  |  | 
|  | CodeInspector codeInspector = inspectAfterShrinking(shrinker, CLASSES, config); | 
|  | verifyClassesAbsent(codeInspector, | 
|  | R1.class, R2.class, D.class, D2.class); | 
|  | verifyClassesPresent(codeInspector, | 
|  | R.class, D1.class); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void ifOnField_withNthWildcard() throws Exception { | 
|  | List<String> config = ImmutableList.of( | 
|  | "-keep class **.MainUsesR {", | 
|  | "  public static void main(java.lang.String[]);", | 
|  | "}", | 
|  | "-if class **.R {", | 
|  | "  public static int id?;", | 
|  | "}", | 
|  | "-keep class **.D<2>" | 
|  | ); | 
|  |  | 
|  | CodeInspector codeInspector = inspectAfterShrinking(shrinker, CLASSES, config); | 
|  | verifyClassesAbsent(codeInspector, | 
|  | R1.class, R2.class, D.class, D2.class); | 
|  | verifyClassesPresent(codeInspector, | 
|  | R.class, D1.class); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void ifOnFieldWithCapture_withoutNthWildcard() throws Exception { | 
|  | List<String> config = ImmutableList.of( | 
|  | "-keep class **.MainWithIf {", | 
|  | "  public static void main(java.lang.String[]);", | 
|  | "}", | 
|  | "-if class **.R1 {", | 
|  | "  public static int id*;", | 
|  | "}", | 
|  | "-keep class **.D1", | 
|  | "-if class **.R2 {", | 
|  | "  public static int id*;", | 
|  | "}", | 
|  | "-keep class **.D2" | 
|  | ); | 
|  |  | 
|  | CodeInspector codeInspector = inspectAfterShrinking(shrinker, CLASSES, config); | 
|  | verifyClassesAbsent(codeInspector, | 
|  | R.class, D.class, R1.class, D1.class); | 
|  | verifyClassesPresent(codeInspector, | 
|  | R2.class, D2.class); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void ifOnFieldWithCapture_withNthWildcard() throws Exception { | 
|  | List<String> config = ImmutableList.of( | 
|  | "-keep class **.MainWithIf {", | 
|  | "  public static void main(java.lang.String[]);", | 
|  | "}", | 
|  | "-if class **.R* {", | 
|  | "  public static int id*;", | 
|  | "}", | 
|  | "-keep class **.D<2>" | 
|  | ); | 
|  |  | 
|  | CodeInspector codeInspector = inspectAfterShrinking(shrinker, CLASSES, config); | 
|  | verifyClassesAbsent(codeInspector, | 
|  | R.class, D.class, R1.class, D1.class); | 
|  | verifyClassesPresent(codeInspector, | 
|  | R2.class, D2.class); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void ifOnFieldWithInner_withoutNthWildcard() throws Exception { | 
|  | List<String> config = ImmutableList.of( | 
|  | "-keep class **.MainWithInner {", | 
|  | "  public static void main(java.lang.String[]);", | 
|  | "}", | 
|  | "-if class **$*R {", | 
|  | "  public static int id1;", | 
|  | "  public static int id2;", | 
|  | "}", | 
|  | "-keep class **$*D" | 
|  | ); | 
|  |  | 
|  | CodeInspector codeInspector = inspectAfterShrinking(shrinker, CLASSES, config); | 
|  | verifyClassesAbsent(codeInspector, | 
|  | R.class, D.class, R1.class, D1.class, R2.class, D2.class); | 
|  | verifyClassesPresent(codeInspector, | 
|  | MainWithInner.InnerR.class, MainWithInner.InnerD.class); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void ifOnFieldWithInner_withNthWildcard() throws Exception { | 
|  | List<String> config = ImmutableList.of( | 
|  | "-keep class **.MainWithInner {", | 
|  | "  public static void main(java.lang.String[]);", | 
|  | "}", | 
|  | "-if class **$*R {", | 
|  | "  public static int id1;", | 
|  | "  public static int id2;", | 
|  | "}", | 
|  | "-keep class <1>$<2>D" | 
|  | ); | 
|  |  | 
|  | CodeInspector codeInspector = inspectAfterShrinking(shrinker, CLASSES, config); | 
|  | verifyClassesAbsent(codeInspector, | 
|  | R.class, D.class, R1.class, D1.class, R2.class, D2.class); | 
|  | verifyClassesPresent(codeInspector, | 
|  | MainWithInner.InnerR.class, MainWithInner.InnerD.class); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void ifOnFieldInImplementer_withoutNthWildcard() throws Exception { | 
|  | List<String> config = | 
|  | ImmutableList.of( | 
|  | "-keep class **.MainUsesImpl {", | 
|  | "  public static void main(java.lang.String[]);", | 
|  | "}", | 
|  | "-keep class **.I", // Prevent I from being merged into Impl. | 
|  | "-if class ** implements **.I {", | 
|  | "  private <fields>;", | 
|  | "}", | 
|  | "-keep class **.D1", | 
|  | "-if class ** implements **.I {", | 
|  | "  public <fields>;", | 
|  | "}", | 
|  | "-keep class **.D2"); | 
|  |  | 
|  | CodeInspector codeInspector = inspectAfterShrinking(shrinker, CLASSES, config); | 
|  | verifyClassesAbsent(codeInspector, D2.class); | 
|  | verifyClassesPresent(codeInspector, | 
|  | I.class, Impl.class, D1.class); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void ifOnFieldInImplementer_withNthWildcard() throws Exception { | 
|  | List<String> config = | 
|  | ImmutableList.of( | 
|  | "-keep class **.MainUsesImpl {", | 
|  | "  public static void main(java.lang.String[]);", | 
|  | "}", | 
|  | "-keep class **.I", // Prevent I from being merged into Impl. | 
|  | "-if class ** implements **.I {", | 
|  | "  private <fields>;", | 
|  | "}", | 
|  | "-keep class <2>.D1", | 
|  | "-if class ** implements **.I {", | 
|  | "  public <fields>;", | 
|  | "}", | 
|  | "-keep class <2>.D2"); | 
|  |  | 
|  | CodeInspector codeInspector = inspectAfterShrinking(shrinker, CLASSES, config); | 
|  | verifyClassesAbsent(codeInspector, D2.class); | 
|  | verifyClassesPresent(codeInspector, I.class, Impl.class, D1.class); | 
|  | } | 
|  |  | 
|  | } |