| // 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); |
| } |
| |
| } |