blob: e3b6656940a20629025a822e5562867fa5e441c3 [file]
// Copyright (c) 2025, 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.processkeeprules;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticOrigin;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.fail;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestDiagnosticMessagesImpl;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
import com.google.common.collect.ImmutableMap;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class ProcessKeepRulesCommandTest extends TestBase {
private static final Map<String, String> testRules =
ImmutableMap.<String, String>builder()
.put("-dontoptimize", "-dontoptimize not allowed in library consumer rules.")
.put("-dontobfuscate", "-dontobfuscate not allowed in library consumer rules.")
.put("-dontshrink", "-dontshrink not allowed in library consumer rules.")
.put("-repackageclasses", "-repackageclasses not allowed in library consumer rules.")
.put("-applymapping foo", "-applymapping not allowed in library consumer rules.")
.put("-injars foo", "-injars not allowed in library consumer rules.")
.put("-libraryjars foo", "-libraryjars not allowed in library consumer rules.")
.put("-printconfiguration", "-printconfiguration not allowed in library consumer rules.")
.put("-printmapping", "-printmapping not allowed in library consumer rules.")
.put("-printseeds", "-printseeds not allowed in library consumer rules.")
.put("-printusage", "-printusage not allowed in library consumer rules.")
.put(
"-obfuscationdictionary foo",
"-obfuscationdictionary not allowed in library consumer rules.")
.put(
"-classobfuscationdictionary foo",
"-classobfuscationdictionary not allowed in library consumer rules.")
.put(
"-packageobfuscationdictionary foo",
"-packageobfuscationdictionary not allowed in library consumer rules.")
.put(
"-flattenpackagehierarchy",
"-flattenpackagehierarchy not allowed in library consumer rules.")
.put(
"-allowaccessmodification",
"-allowaccessmodification not allowed in library consumer rules.")
.put(
"-keepattributes LineNumberTable",
"Illegal attempt to keep the attribute 'LineNumberTable' in library consumer rules.")
.put(
"-keepattributes RuntimeInvisibleAnnotations",
"Illegal attempt to keep the attribute 'RuntimeInvisibleAnnotations' in library"
+ " consumer rules.")
.put(
"-keepattributes RuntimeInvisibleTypeAnnotations",
"Illegal attempt to keep the attribute 'RuntimeInvisibleTypeAnnotations' in library"
+ " consumer rules.")
.put(
"-keepattributes RuntimeInvisibleParameterAnnotations",
"Illegal attempt to keep the attribute 'RuntimeInvisibleParameterAnnotations' in"
+ " library consumer rules.")
.put(
"-keepattributes SourceFile",
"Illegal attempt to keep the attribute 'SourceFile' in library consumer rules.")
.put(
"-maximumremovedandroidloglevel 2",
"-maximumremovedandroidloglevel <int> not allowed in library consumer rules.")
.put(
"-renamesourcefileattribute",
"-renamesourcefileattribute not allowed in library consumer rules.")
.put(
"-shrinkunusedprotofields",
"-shrinkunusedprotofields not allowed in library consumer rules.")
.put(
"-whyareyoukeeping class *",
"-whyareyoukeeping not allowed in library consumer rules.")
.put(
"-whyareyounotobfuscating class *",
"-whyareyounotobfuscating not allowed in library consumer rules.")
.put(
"-whyareyounotinlining class * { *; }",
"-whyareyounotinlining not allowed in library consumer rules.")
.put(
"-processkotlinnullchecks",
"-processkotlinnullchecks not allowed in library consumer rules.")
.put(
"-processkotlinnullchecks keep",
"-processkotlinnullchecks not allowed in library consumer rules.")
.put(
"-processkotlinnullchecks remove_message",
"-processkotlinnullchecks not allowed in library consumer rules.")
.put(
"-processkotlinnullchecks remove",
"-processkotlinnullchecks not allowed in library consumer rules.")
.build();
@Parameter(1)
public TestParameters parameters;
@Parameter(0)
public Map.Entry<String, String> configAndExpectedDiagnostic;
@Parameters(name = "{1}, configAndExpectedDiagnostic = {0}")
public static List<Object[]> data() throws IOException {
return buildParameters(testRules.entrySet(), getTestParameters().withNoneRuntime().build());
}
@Test
public void test() throws Exception {
String rules = configAndExpectedDiagnostic.getKey();
Origin origin = new PathOrigin(Paths.get("keep.txt"));
try {
validate(
rules,
origin,
diagnostics ->
diagnostics.assertErrorsMatch(
allOf(
rules.startsWith("-keepattributes")
? diagnosticType(KeepAttributeLibraryConsumerRuleDiagnostic.class)
: diagnosticType(LibraryConsumerRuleDiagnostic.class),
diagnosticOrigin(equalTo(origin)),
diagnosticMessage(equalTo(configAndExpectedDiagnostic.getValue())))));
fail("Expect the compilation to fail.");
} catch (CompilationFailedException e) {
// Expected.
}
// Rerun validation after filtering. This should succeed without diagnostics.
validate(filter(rules, origin), origin, TestDiagnosticMessagesImpl::assertNoMessages);
}
private String filter(String rules, Origin origin) throws CompilationFailedException {
TestDiagnosticMessagesImpl diagnostics = new TestDiagnosticMessagesImpl();
StringBuilder result = new StringBuilder();
ProcessKeepRulesCommand command =
ProcessKeepRulesCommand.builder(diagnostics)
.addKeepRules(rules, origin)
.setFilteredKeepRulesConsumer((s, h) -> result.append(s))
.build();
ProcessKeepRules.run(command);
diagnostics.assertNoMessages();
return result.toString();
}
private void validate(
String rules, Origin origin, Consumer<TestDiagnosticMessagesImpl> diagnosticsInspector)
throws CompilationFailedException {
TestDiagnosticMessagesImpl diagnostics = new TestDiagnosticMessagesImpl();
try {
ProcessKeepRulesCommand command =
ProcessKeepRulesCommand.builder(diagnostics)
.addKeepRules(rules, origin)
.setLibraryConsumerRuleValidation(true)
.build();
ProcessKeepRules.run(command);
diagnosticsInspector.accept(diagnostics);
} catch (CompilationFailedException e) {
diagnosticsInspector.accept(diagnostics);
throw e;
}
}
}