| // Copyright (c) 2017, 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.includedescriptorclasses; |
| |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| |
| import com.android.tools.r8.TestBase; |
| import com.android.tools.r8.ToolHelper; |
| import com.android.tools.r8.utils.codeinspector.CodeInspector; |
| import com.google.common.collect.ImmutableList; |
| import java.nio.file.Path; |
| import java.util.ArrayList; |
| import java.util.List; |
| import org.junit.Test; |
| |
| public class IncludeDescriptorClassesTest extends TestBase { |
| private class Result { |
| final CodeInspector inspector; |
| final CodeInspector proguardedInspector; |
| |
| Result(CodeInspector inspector, CodeInspector proguardedInspector) { |
| this.inspector = inspector; |
| this.proguardedInspector = proguardedInspector; |
| } |
| |
| void assertKept(Class clazz) { |
| assertTrue(inspector.clazz(clazz.getCanonicalName()).isPresent()); |
| assertFalse(inspector.clazz(clazz.getCanonicalName()).isRenamed()); |
| if (proguardedInspector != null) { |
| assertTrue(proguardedInspector.clazz(clazz).isPresent()); |
| } |
| } |
| |
| // NOTE: 'synchronized' is supposed to disable inlining of this method. |
| synchronized void assertRemoved(Class clazz) { |
| assertFalse(inspector.clazz(clazz.getCanonicalName()).isPresent()); |
| if (proguardedInspector != null) { |
| assertFalse(proguardedInspector.clazz(clazz).isPresent()); |
| } |
| } |
| |
| void assertRenamed(Class clazz) { |
| assertTrue(inspector.clazz(clazz.getCanonicalName()).isPresent()); |
| assertTrue(inspector.clazz(clazz.getCanonicalName()).isRenamed()); |
| if (proguardedInspector != null) { |
| assertTrue(proguardedInspector.clazz(clazz).isPresent()); |
| assertTrue(proguardedInspector.clazz(clazz).isRenamed()); |
| } |
| } |
| } |
| |
| private List<Class<?>> applicationClasses = |
| ImmutableList.of( |
| ClassWithNativeMethods.class, |
| NativeArgumentType.class, |
| NativeReturnType.class, |
| StaticFieldType.class, |
| InstanceFieldType.class); |
| private List<Class> mainClasses = ImmutableList.of( |
| MainCallMethod1.class, MainCallMethod2.class, MainCallMethod3.class); |
| |
| Result runTest(Class mainClass, Path proguardConfig) throws Exception { |
| List<Class<?>> classes = new ArrayList<>(applicationClasses); |
| classes.add(mainClass); |
| |
| CodeInspector inspector = new CodeInspector(compileWithR8(classes, proguardConfig)); |
| |
| CodeInspector proguardedInspector = null; |
| // Actually running Proguard should only be during development. |
| if (isRunProguard()) { |
| Path proguardedJar = temp.newFolder().toPath().resolve("proguarded.jar"); |
| Path proguardedMap = temp.newFolder().toPath().resolve("proguarded.map"); |
| ToolHelper.runProguard(jarTestClasses(classes), proguardedJar, proguardConfig, proguardedMap); |
| proguardedInspector = new CodeInspector(readJar(proguardedJar), proguardedMap); |
| } |
| |
| return new Result(inspector, proguardedInspector); |
| } |
| |
| @Test |
| public void testNoIncludesDescriptorClasses() throws Exception { |
| for (Class mainClass : mainClasses) { |
| List<Class> allClasses = new ArrayList<>(applicationClasses); |
| allClasses.add(mainClass); |
| |
| Path proguardConfig = writeTextToTempFile( |
| keepMainProguardConfiguration(mainClass), |
| "-keepclasseswithmembers class * { ", |
| " <fields>; ", |
| " native <methods>; ", |
| "} ", |
| "-allowaccessmodification ", |
| "-printmapping " |
| ); |
| |
| Result result = runTest(mainClass, proguardConfig); |
| |
| result.assertKept(ClassWithNativeMethods.class); |
| // Return types are not removed as they can be needed for verification. |
| // See b/112517039. |
| result.assertRenamed(NativeReturnType.class); |
| // Argument type is not removed due to the concern about the broken type hierarchy. |
| result.assertRenamed(NativeArgumentType.class); |
| // Field type is not removed due to the concern about the broken type hierarchy. |
| result.assertRenamed(InstanceFieldType.class); |
| result.assertRenamed(StaticFieldType.class); |
| } |
| } |
| |
| @Test |
| public void testKeepClassesWithMembers() throws Exception { |
| for (Class mainClass : mainClasses) { |
| Path proguardConfig = writeTextToTempFile( |
| keepMainProguardConfiguration(mainClass), |
| "-keepclasseswithmembers,includedescriptorclasses class * { ", |
| " <fields>; ", |
| " native <methods>; ", |
| "} ", |
| "-allowaccessmodification ", |
| "-printmapping " |
| ); |
| |
| Result result = runTest(mainClass, proguardConfig); |
| |
| // With includedescriptorclasses return type, argument type ad field type are not renamed. |
| result.assertKept(ClassWithNativeMethods.class); |
| result.assertKept(NativeArgumentType.class); |
| result.assertKept(NativeReturnType.class); |
| result.assertKept(InstanceFieldType.class); |
| result.assertKept(StaticFieldType.class); |
| } |
| } |
| |
| @Test |
| public void testKeepClassMembers() throws Exception { |
| for (Class mainClass : mainClasses) { |
| Path proguardConfig = writeTextToTempFile( |
| keepMainProguardConfiguration(mainClass), |
| "-keepclassmembers,includedescriptorclasses class * { ", |
| " <fields>; ", |
| " native <methods>; ", |
| "} ", |
| "-allowaccessmodification ", |
| "-printmapping " |
| ); |
| |
| Result result = runTest(mainClass, proguardConfig); |
| |
| // With includedescriptorclasses return type and argument type are not renamed. |
| result.assertRenamed(ClassWithNativeMethods.class); |
| result.assertKept(NativeArgumentType.class); |
| result.assertKept(NativeReturnType.class); |
| result.assertKept(InstanceFieldType.class); |
| result.assertKept(StaticFieldType.class); |
| } |
| } |
| |
| @Test |
| public void testKeepClassMemberNames() throws Exception { |
| for (Class mainClass : mainClasses) { |
| Path proguardConfig = writeTextToTempFile( |
| keepMainProguardConfiguration(mainClass), |
| // same as -keepclassmembers,allowshrinking,includedescriptorclasses |
| "-keepclassmembernames,includedescriptorclasses class * { ", |
| " <fields>; ", |
| " native <methods>; ", |
| "} ", |
| "-allowaccessmodification ", |
| "-printmapping " |
| ); |
| |
| Result result = runTest(mainClass, proguardConfig); |
| |
| boolean useNativeArgumentType = |
| mainClass == MainCallMethod1.class || mainClass == MainCallMethod3.class; |
| boolean useNativeReturnType = |
| mainClass == MainCallMethod2.class || mainClass == MainCallMethod3.class; |
| |
| result.assertRenamed(ClassWithNativeMethods.class); |
| if (useNativeArgumentType) { |
| result.assertKept(NativeArgumentType.class); |
| } else { |
| result.assertRemoved(NativeArgumentType.class); |
| } |
| |
| if (useNativeReturnType) { |
| result.assertKept(NativeReturnType.class); |
| } else { |
| result.assertRemoved(NativeReturnType.class); |
| } |
| |
| result.assertRemoved(InstanceFieldType.class); |
| result.assertRemoved(StaticFieldType.class); |
| } |
| } |
| } |