blob: c1957f46c3888668a99f58a876aaf3fe63294821 [file] [log] [blame]
// Copyright (c) 2021, 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.ir.optimize.logging;
import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.AssumeNoClassInitializationSideEffects;
import com.android.tools.r8.AssumeNoSideEffects;
import com.android.tools.r8.AssumeNotNull;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class CustomLoggingFrameworkRemovalTest extends TestBase {
private final TestParameters parameters;
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters()
.withAllRuntimes()
.withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
.build();
}
public CustomLoggingFrameworkRemovalTest(TestParameters parameters) {
this.parameters = parameters;
}
@Test
public void test() throws Exception {
testForR8(parameters.getBackend())
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addKeepRules("-assumenosideeffects class java.lang.StringBuilder { void <init>(int); }")
.enableAssumeNotNullAnnotations()
.enableAssumeNoClassInitializationSideEffectsAnnotations()
.enableAssumeNoSideEffectsAnnotations()
.enableInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.addDontObfuscate()
.compile()
.inspect(
inspector -> {
ClassSubject mainClassSubject = inspector.clazz(Main.class);
assertThat(mainClassSubject, isPresent());
MethodSubject mainMethodSubject = mainClassSubject.mainMethod();
assertThat(mainMethodSubject, isPresent());
assertTrue(
mainMethodSubject
.streamInstructions()
.allMatch(InstructionSubject::isReturnVoid));
MethodSubject clinitMethodSubject = mainClassSubject.clinit();
assertThat(clinitMethodSubject, isAbsent());
assertThat(inspector.clazz(Logger.class), isAbsent());
assertThat(inspector.clazz(LoggerFactory.class), isAbsent());
})
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithEmptyOutput();
}
public static class Main {
@AssumeNotNull private static final Logger logger = LoggerFactory.getLogger("MainActivity");
public static void main(String[] args) {
logger.print(new StringBuilder(getInt(5)).append("Hello").toString());
logger.print(Objects.toString(new StringBuilder(getInt(6)).append(" world")));
logger.print(String.valueOf(new StringBuilder(getInt(1)).append("!")));
}
@AssumeNoSideEffects
@NeverInline
private static int getInt(int value) {
return System.currentTimeMillis() > 0 ? value : -1;
}
}
public static class Logger {
private Logger() {}
@AssumeNoSideEffects
public void print(String message) {
System.out.print(message);
}
}
@AssumeNoClassInitializationSideEffects
public static class LoggerFactory {
private static final Map<String, Logger> loggers = new HashMap<>();
@AssumeNoSideEffects
static synchronized Logger getLogger(String key) {
return loggers.computeIfAbsent(key, ignore -> new Logger());
}
}
}