blob: a6865670542888244d485bb8ccba76c3604b16cb [file] [log] [blame]
// 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);
}
}
}