| // Copyright (c) 2020, 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.desugar; |
| |
| import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getCompanionClassNameSuffix; |
| import static org.junit.Assume.assumeTrue; |
| |
| import com.android.tools.r8.DesugarTestConfiguration; |
| 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.google.common.collect.ImmutableList; |
| import java.util.List; |
| import java.util.concurrent.Callable; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| |
| @RunWith(Parameterized.class) |
| public class DesugarInnerClassesInInterfaces extends TestBase { |
| |
| private final List<String> EXPECTED_RESULT_WITHOUT_DESUGARING = |
| ImmutableList.of( |
| WithAnonymousInner.class.getName(), "true", WithLocalInner.class.getName(), "true"); |
| |
| private final List<String> EXPECTED_RESULT_WITH_DESUGARING = |
| ImmutableList.of( |
| WithAnonymousInner.class.getName() + getCompanionClassNameSuffix(), |
| "true", |
| WithLocalInner.class.getName() + getCompanionClassNameSuffix(), |
| "true"); |
| |
| @Parameterized.Parameters(name = "{0}") |
| public static TestParametersCollection data() { |
| return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(); |
| } |
| |
| private final TestParameters parameters; |
| |
| public DesugarInnerClassesInInterfaces(TestParameters parameters) { |
| this.parameters = parameters; |
| } |
| |
| @Test |
| public void testDesugar() throws Exception { |
| testForDesugaring(parameters) |
| .addInnerClasses(DesugarInnerClassesInInterfaces.class) |
| .run(parameters.getRuntime(), TestClass.class) |
| .applyIf( |
| DesugarTestConfiguration::isNotDesugared, |
| r -> r.assertSuccessWithOutputLines(EXPECTED_RESULT_WITHOUT_DESUGARING)) |
| .applyIf( |
| DesugarTestConfiguration::isDesugared, |
| r -> |
| r.assertSuccessWithOutputLines( |
| parameters |
| .getApiLevel() |
| .isGreaterThanOrEqualTo(apiLevelWithDefaultInterfaceMethodsSupport()) |
| ? EXPECTED_RESULT_WITHOUT_DESUGARING |
| : EXPECTED_RESULT_WITH_DESUGARING)); |
| } |
| |
| @Test |
| public void testR8Compat() throws Exception { |
| assumeTrue(parameters.isDexRuntime() || parameters.getApiLevel() == AndroidApiLevel.B); |
| testForR8Compat(parameters.getBackend()) |
| .addInnerClasses(DesugarInnerClassesInInterfaces.class) |
| .setMinApi(parameters.getApiLevel()) |
| .addKeepAllClassesRule() |
| .addKeepAttributeInnerClassesAndEnclosingMethod() |
| .noHorizontalClassMergingOfSynthetics() |
| .compile() |
| .run(parameters.getRuntime(), TestClass.class) |
| .applyIf( |
| parameters.isCfRuntime() || parameters.canUseDefaultAndStaticInterfaceMethods(), |
| result -> result.assertSuccessWithOutputLines(EXPECTED_RESULT_WITHOUT_DESUGARING), |
| result -> result.assertSuccessWithOutputLines(EXPECTED_RESULT_WITH_DESUGARING)); |
| } |
| |
| @Test |
| public void testR8Full() throws Exception { |
| assumeTrue(parameters.isDexRuntime() || parameters.getApiLevel() == AndroidApiLevel.B); |
| testForR8(parameters.getBackend()) |
| .addInnerClasses(DesugarInnerClassesInInterfaces.class) |
| .setMinApi(parameters.getApiLevel()) |
| .addKeepAllClassesRule() |
| .addKeepAttributeInnerClassesAndEnclosingMethod() |
| .compile() |
| .run(parameters.getRuntime(), TestClass.class) |
| .applyIf( |
| parameters.isCfRuntime() || parameters.canUseDefaultAndStaticInterfaceMethods(), |
| result -> result.assertSuccessWithOutputLines(EXPECTED_RESULT_WITHOUT_DESUGARING), |
| result -> result.assertSuccessWithOutputLines(EXPECTED_RESULT_WITH_DESUGARING)); |
| } |
| |
| interface WithAnonymousInner { |
| static Callable<Class<?>> staticOuter() { |
| return new Callable<Class<?>>() { |
| @Override |
| public Class<?> call() { |
| return getClass().getEnclosingClass(); |
| } |
| }; |
| } |
| |
| default Callable<Class<?>> defaultOuter() { |
| return new Callable<Class<?>>() { |
| @Override |
| public Class<?> call() { |
| return getClass().getEnclosingClass(); |
| } |
| }; |
| } |
| } |
| |
| interface WithLocalInner { |
| static Callable<Class<?>> staticOuter() { |
| class Local implements Callable<Class<?>> { |
| @Override |
| public Class<?> call() { |
| return getClass().getEnclosingClass(); |
| } |
| } |
| return new Local(); |
| } |
| |
| default Callable<Class<?>> defaultOuter() { |
| class Local implements Callable<Class<?>> { |
| @Override |
| public Class<?> call() { |
| return getClass().getEnclosingClass(); |
| } |
| } |
| return new Local(); |
| } |
| } |
| |
| public static class TestClass { |
| |
| public static void main(String[] args) throws Exception { |
| System.out.println(new WithAnonymousInner() {}.defaultOuter().call().getName()); |
| System.out.println( |
| new WithAnonymousInner() {}.defaultOuter() |
| .call() |
| .equals(WithAnonymousInner.staticOuter().call())); |
| System.out.println(new WithLocalInner() {}.defaultOuter().call().getName()); |
| System.out.println( |
| new WithLocalInner() {}.defaultOuter() |
| .call() |
| .equals(WithLocalInner.staticOuter().call())); |
| } |
| } |
| } |