blob: 49ba1862e1b1f67d8cbae8eb29e9b3ead5e857cc [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.naming;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.DiagnosticsChecker;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.VmTestRunner;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.KeepingDiagnosticHandler;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
import java.lang.reflect.Method;
import java.nio.file.Path;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
class WarnReflectiveAccessTestMain {
int counter = 0;
WarnReflectiveAccessTestMain() {
}
public void foo() {
System.out.println("TestMain::foo(" + counter++ + ")");
}
public int boo() {
System.out.println("TestMain::boo(" + counter + ")");
return counter;
}
public static void main(String[] args) throws Exception {
WarnReflectiveAccessTestMain instance = new WarnReflectiveAccessTestMain();
StringBuilder builder = new StringBuilder();
builder.append("f");
builder.append("o").append("o");
Method foo = instance.getClass().getDeclaredMethod(builder.toString());
foo.invoke(instance);
}
}
@RunWith(VmTestRunner.class)
public class WarnReflectiveAccessTest extends TestBase {
private KeepingDiagnosticHandler handler;
private Reporter reporter;
@Before
public void reset() {
handler = new KeepingDiagnosticHandler();
reporter = new Reporter(handler);
}
private AndroidApp runR8(
byte[][] classes,
Class main,
Path out,
boolean explicitRule,
boolean enableMinification,
boolean forceProguardCompatibility)
throws Exception {
String minificationModifier = enableMinification ? ",allowobfuscation " : " ";
String reflectionRules = explicitRule
? "-identifiernamestring class java.lang.Class {\n"
+ "static java.lang.Class forName(java.lang.String);\n"
+ "java.lang.reflect.Method getDeclaredMethod(java.lang.String, java.lang.Class[]);\n"
+ "}\n"
: "";
R8Command.Builder commandBuilder =
R8Command.builder(reporter)
.addProguardConfiguration(
ImmutableList.of(
"-keep" + minificationModifier + "class " + main.getCanonicalName() + " {"
+ " <methods>;"
+ "}",
"-printmapping",
reflectionRules),
Origin.unknown())
.setOutput(out, OutputMode.DexIndexed);
for (byte[] clazz : classes) {
commandBuilder.addClassProgramData(clazz, Origin.unknown());
}
commandBuilder.addLibraryFiles(ToolHelper.getDefaultAndroidJar());
return ToolHelper.runR8(commandBuilder.build(), o -> {
o.enableInlining = false;
o.forceProguardCompatibility = forceProguardCompatibility;
});
}
private void reflectionWithBuilder(
boolean explicitRule,
boolean enableMinification,
boolean forceProguardCompatibility) throws Exception {
byte[][] classes = {
ToolHelper.getClassAsBytes(WarnReflectiveAccessTestMain.class)
};
Path out = temp.getRoot().toPath();
AndroidApp processedApp = runR8(classes, WarnReflectiveAccessTestMain.class, out,
explicitRule, enableMinification, forceProguardCompatibility);
String main = WarnReflectiveAccessTestMain.class.getCanonicalName();
CodeInspector codeInspector = new CodeInspector(processedApp);
ClassSubject mainSubject = codeInspector.clazz(main);
assertThat(mainSubject, isPresent());
ProcessResult javaOutput = runOnJavaRaw(main, classes);
assertEquals(0, javaOutput.exitCode);
assertThat(javaOutput.stdout, containsString("TestMain::foo"));
ProcessResult artOutput = runOnArtRaw(processedApp,
enableMinification ? mainSubject.getFinalName() : main);
if (enableMinification) {
assertNotEquals(0, artOutput.exitCode);
assertThat(artOutput.stderr, containsString("NoSuchMethodError"));
} else {
assertEquals(0, artOutput.exitCode);
assertThat(artOutput.stdout, containsString("TestMain::foo"));
}
}
@Test
public void test_explicit_minification_forceProguardCompatibility() throws Exception {
reflectionWithBuilder(true, true, true);
assertFalse(handler.warnings.isEmpty());
DiagnosticsChecker.checkDiagnostic(handler.warnings.get(0), (Path) null, 55, 1,
"Cannot determine", "getDeclaredMethod", "-identifiernamestring", "resolution failure");
}
@Test
public void test_explicit_noMinification_forceProguardCompatibility() throws Exception {
reflectionWithBuilder(true, false, true);
assertFalse(handler.warnings.isEmpty());
DiagnosticsChecker.checkDiagnostic(handler.warnings.get(0), (Path) null, 55, 1,
"Cannot determine", "getDeclaredMethod", "-identifiernamestring", "resolution failure");
}
@Test
public void test_explicit_minification_R8() throws Exception {
reflectionWithBuilder(true, true, false);
assertFalse(handler.warnings.isEmpty());
DiagnosticsChecker.checkDiagnostic(handler.warnings.get(0), (Path) null, 55, 1,
"Cannot determine", "getDeclaredMethod", "-identifiernamestring", "resolution failure");
}
@Test
public void test_explicit_noMinification_R8() throws Exception {
reflectionWithBuilder(true, false, false);
assertFalse(handler.warnings.isEmpty());
DiagnosticsChecker.checkDiagnostic(handler.warnings.get(0), (Path) null, 55, 1,
"Cannot determine", "getDeclaredMethod", "-identifiernamestring", "resolution failure");
}
@Test
public void test_implicit_minification_forceProguardCompatibility() throws Exception {
reflectionWithBuilder(false, true, true);
assertTrue(handler.warnings.isEmpty());
}
@Test
public void test_implicit_noMinification_forceProguardCompatibility() throws Exception {
reflectionWithBuilder(false, false, true);
assertTrue(handler.warnings.isEmpty());
}
@Test
public void test_implicit_minification_R8() throws Exception {
reflectionWithBuilder(false, true, false);
assertTrue(handler.warnings.isEmpty());
}
@Test
public void test_implicit_noMinification_R8() throws Exception {
reflectionWithBuilder(false, false, false);
assertTrue(handler.warnings.isEmpty());
}
}