blob: 0cb64c89b06b494c77f7ece8116fa08173ea0134 [file] [log] [blame]
// Copyright (c) 2022, 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.desugaring.interfacemethods;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.errors.InterfaceDesugarMissingTypeDiagnostic;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.StringUtils;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
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 DefaultMethodInvokeSuperOnDefaultLibraryMethodTest extends TestBase {
@Parameter() public TestParameters parameters;
@Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withDexRuntimes().build();
}
private static final String EXPECTED_OUTPUT = StringUtils.lines("1", "2");
private boolean runtimeHasConsumerInterface(TestParameters parameters) {
// java,util.function.Consumer was introduced at API level 24.
return parameters.asDexRuntime().getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N);
}
@Test
public void testD8WithDefaultInterfaceMethodDesugaringWithAPIInLibrary() throws Exception {
testForD8(parameters.getBackend())
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
.addInnerClasses(getClass())
.setMinApi(AndroidApiLevel.I_MR1)
.compileWithExpectedDiagnostics(
diagnostics ->
diagnostics
.assertOnlyWarnings()
.assertWarningsMatch(
allOf(
diagnosticType(StringDiagnostic.class),
diagnosticMessage(
containsString(
"Interface method desugaring has inserted NoSuchMethodError"
+ " replacing a super call in")),
diagnosticMessage(containsString("forEachPrint")))))
.run(parameters.getRuntime(), TestClass.class)
.applyIf(
// If the platform does not have java.util.function.Consumer the lambda instantiation
// will throw NoClassDefFoundError as it implements java.util.function.Consumer.
// Otherwise, the generated code will throw NoSuchMethodError.
runtimeHasConsumerInterface(parameters),
b -> b.assertFailureWithErrorThatThrows(NoSuchMethodError.class),
b -> b.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
}
@Test
public void testD8WithDefaultInterfaceMethodDesugaringWithoutAPIInLibrary() throws Exception {
testForD8(parameters.getBackend())
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.M))
.addInnerClasses(getClass())
.setMinApi(AndroidApiLevel.I_MR1)
.compileWithExpectedDiagnostics(
diagnostics ->
diagnostics
.assertOnlyWarnings()
.assertWarningsMatch(
diagnosticType(InterfaceDesugarMissingTypeDiagnostic.class)))
.run(parameters.getRuntime(), TestClass.class)
.applyIf(
// If the platform does not have java.util.function.Consumer the lambda instantiation
// will throw NoClassDefFoundError as it implements java.util.function.Consumer.
// Otherwise, the generated code will throw NoSuchMethodError.
runtimeHasConsumerInterface(parameters),
b -> b.assertFailureWithErrorThatThrows(NoSuchMethodError.class),
b -> b.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
}
@Test
public void testD8WithDefaultInterfaceMethodSupport() throws Exception {
assumeTrue(
parameters.asDexRuntime().getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N));
testForD8(parameters.getBackend())
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
.addInnerClasses(getClass())
.setMinApi(AndroidApiLevel.N)
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(EXPECTED_OUTPUT);
}
@Test
public void testR8WithDefaultInterfaceMethodDesugaringWithAPIInLibrary() throws Exception {
testForR8(parameters.getBackend())
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
.addInnerClasses(getClass())
.setMinApi(AndroidApiLevel.I_MR1)
.addKeepMainRule(TestClass.class)
.run(parameters.getRuntime(), TestClass.class)
.assertFailureWithErrorThatThrows(NoSuchMethodError.class);
}
@Test
public void testR8WithDefaultInterfaceMethodDesugaringWithoutAPIInLibrary() throws Exception {
testForR8(parameters.getBackend())
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.M))
.addInnerClasses(getClass())
.setMinApi(AndroidApiLevel.I_MR1)
.addKeepMainRule(TestClass.class)
.addDontWarn(Consumer.class)
.run(parameters.getRuntime(), TestClass.class)
.applyIf(
// If the platform does not have java.util.function.Consumer the lambda instantiation
// will throw NoClassDefFoundError as it implements java.util.function.Consumer.
// Otherwise, the generated code will throw NoSuchMethodError.
runtimeHasConsumerInterface(parameters),
b -> b.assertFailureWithErrorThatThrows(NoSuchMethodError.class),
b -> b.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
}
@Test
public void testR8WithDefaultInterfaceMethodSupport() throws Exception {
assumeTrue(
parameters.asDexRuntime().getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N));
testForR8(parameters.getBackend())
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
.addInnerClasses(getClass())
.setMinApi(AndroidApiLevel.N)
.addKeepMainRule(TestClass.class)
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(EXPECTED_OUTPUT);
}
interface IntegerIterable extends Iterable<Integer> {
default void forEachPrint() {
Iterable.super.forEach(System.out::println);
}
}
static class IntegerIterable1And2 implements IntegerIterable {
@Override
public Iterator<Integer> iterator() {
List<Integer> result = new ArrayList<>();
result.add(1);
result.add(2);
return result.iterator();
}
}
static class TestClass {
public static void main(String[] args) {
new IntegerIterable1And2().forEachPrint();
}
}
}