blob: f1d0cdac2b8b1ffb0a773bd24ce61c51bc76c8a2 [file] [log] [blame]
// 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.b113138046;
import static com.android.tools.r8.utils.codeinspector.Matchers.isRenamed;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
import java.util.List;
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 NativeMethodTest extends TestBase {
@Parameters(name = "{0}, compat:{1}")
public static List<Object[]> data() {
return buildParameters(
getTestParameters().withDexRuntimes().withAllApiLevels().build(),
BooleanUtils.values());
}
private final TestParameters parameters;
private final boolean compatMode;
public NativeMethodTest(TestParameters parameters, boolean compatMode) {
this.parameters = parameters;
this.compatMode = compatMode;
}
private void test(List<String> config, boolean expectedFooPresence) throws Exception {
R8TestCompileResult compileResult =
(compatMode ? testForR8Compat(parameters.getBackend()) : testForR8(parameters.getBackend()))
.setMinApi(parameters.getApiLevel())
.addProgramClassesAndInnerClasses(Keep.class, Data.class, Handler.class, Outer.class)
.addKeepRules(config)
.addOptionsModification(options -> options.enableInlining = false)
.compile();
compileResult.runDex2Oat(parameters.getRuntime()).assertNoVerificationErrors();
CodeInspector inspector = compileResult.inspector();
boolean innerFound = false;
for (ClassSubject clazz : inspector.allClasses()) {
innerFound = clazz.getOriginalName().endsWith("Inner");
if (!innerFound) {
continue;
}
MethodSubject nativeFoo = clazz.method(
"void", "foo", ImmutableList.of(Handler.class.getCanonicalName()));
assertEquals(expectedFooPresence, nativeFoo.isPresent());
if (expectedFooPresence) {
assertThat(nativeFoo, not(isRenamed()));
DexEncodedMethod method = nativeFoo.getMethod();
assertTrue(method.accessFlags.isNative());
assertNull(method.getCode());
}
break;
}
assertTrue(innerFound);
}
@Test
public void test_keep_OnEvent() throws Exception {
List<String> config = ImmutableList.of(
"-keepclasseswithmembers,allowshrinking class * {",
" native <methods>;",
"}",
"-keepclassmembers,includedescriptorclasses class * {",
" native <methods>;",
"}",
"-keep class " + Outer.class.getCanonicalName() + " {",
" onEvent(...);",
"}",
"-printmapping",
"-keepattributes InnerClasses,EnclosingMethod,Signature",
"-allowaccessmodification");
test(config, compatMode);
}
@Test
public void test_keep_annotation() throws Exception {
List<String> config = ImmutableList.of(
"-keepclasseswithmembers,allowshrinking class * {",
" native <methods>;",
"}",
"-keepclassmembers,includedescriptorclasses class * {",
" native <methods>;",
"}",
"-keep,allowobfuscation @interface **.Keep",
"-keep @**.Keep class *",
"-keepclassmembers class * {",
" @**.Keep <fields>;",
" @**.Keep <methods>;",
"}",
"-printmapping",
"-keepattributes InnerClasses,EnclosingMethod,Signature",
"-allowaccessmodification");
test(config, true);
}
}