blob: cd057d298d84d2d45647572c344ee2f4d29c8cdd [file] [log] [blame]
// 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.graph.genericsignature;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
import static com.android.tools.r8.graph.GenericSignature.ClassSignature.NO_CLASS_SIGNATURE;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestDiagnosticMessagesImpl;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.GenericSignature;
import com.android.tools.r8.graph.GenericSignature.ClassSignature;
import com.android.tools.r8.graph.GenericSignaturePrinter;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.Reporter;
import com.google.common.base.Predicates;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class ClassSignatureTest extends TestBase {
private final TestParameters parameters;
@Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withNoneRuntime().build();
}
public ClassSignatureTest(TestParameters parameters) {
this.parameters = parameters;
}
@Test
public void testSuperClass() {
testParsingAndPrintingEqual("Lfoo/bar/baz;");
}
@Test
public void testSuperClassWithInnerClasses() {
testParsingAndPrintingEqual("Lfoo/bar/baz.Foo.Bar;");
}
@Test
public void testSuperClassWithInterfaces1() {
testParsingAndPrintingEqual("Lfoo/bar/baz;Lfoo/bar/qux;");
}
@Test
public void testSuperClassWithInterfaces2() {
testParsingAndPrintingEqual("Lfoo/bar/baz;Lfoo/bar/qux;Lfoo/bar/quux;");
}
@Test
public void testSuperClassWithInterfacesInnerClassesSeparatedByDollar() {
testParsingAndPrintingEqual("Lfoo/bar/baz$Foo$Bar;Lfoo/bar/qux;Lfoo/bar/quux$Foo$Bar;");
}
@Test
public void testSuperClassWithInterfacesInnerClassesSeparatedByPeriod() {
testParsingAndPrintingEqual("Lfoo/bar/baz.Foo.Bar;Lfoo/bar/qux;Lfoo/bar/quux.Foo.Bar;");
}
@Test
public void testInnerClassesWithSeparatorInName1() {
testParsingAndPrintingEqual("Lfoo/bar/baz<*>.Foo$$$<*>.Bar;");
}
@Test
public void testInnerClassesWithSeparatorInName2() {
testParsingAndPrintingEqual("Lfoo/bar/baz<*>.Foo$Bar$$<*>.Qux;");
}
@Test
public void testSuperClassWithInnerClassesGenericArguments2() {
testParsingAndPrintingEqual("Lfoo/bar/baz<LFoo;>.Foo<LFoo;>.Bar<LFoo;>;");
}
@Test
public void testSuperClassWithInterfacesInnerClassesGenericArguments2() {
testParsingAndPrintingEqual(
"Lfoo/bar/baz<LFoo;>.Foo<LFoo;>.Bar<LFoo;>;Lfoo/bar/qux<LFoo;>;Lfoo/bar/quux<LFoo;>.Foo<LFoo;>.Bar<LFoo;>;");
}
@Test
public void testSuperClassWithInterfacesInnerClassesGenericArguments3() {
testParsingAndPrintingEqual(
"Lfoo/bar/baz<LFoo;[[I[[[LBar<LFoo;>;>.Foo<LFoo;>.Bar<LFoo;>;Lfoo/bar/qux<LFoo;>;Lfoo/bar/quux<LFoo;>.Foo<LFoo;>.Bar<LFoo;>;");
}
@Test
public void testWildCards() {
testParsingAndPrintingEqual("Lfoo/Bar<*>;");
}
@Test
public void testWildCardsPositiveNegative() {
testParsingAndPrintingEqual("Lfoo/Bar<*+[I-LFoo<+LBar;>;>;");
}
@Test
public void testSuperClassError() {
TestDiagnosticMessages testDiagnosticMessages = testParsingAndPrintingError("Lfoo/bar/baz");
testDiagnosticMessages.assertAllWarningsMatch(
diagnosticMessage(containsString("Invalid signature 'Lfoo/bar/baz'")));
}
@Test
public void testReferenceToTypeVariable() {
testParsingAndPrintingEqual("Lfoo/bar/baz<TT;>;");
}
@Test
public void testFormalTypeParameters() {
testParsingAndPrintingEqual("<T:Ljava/lang/Object;>Lfoo/bar/baz<TT;>;");
}
@Test
public void testFormalTypeWithEmpty() {
testParsingAndPrintingEqual("<T:>Lfoo/bar/baz<TT;>;");
}
@Test
public void testFormalTypeParametersWithInterfaces() {
testParsingAndPrintingEqual("<T:Ljava/lang/Object;:LI;>Lfoo/bar/baz<TT;>;");
}
@Test
public void testFormalTypeParametersArguments() {
testParsingAndPrintingEqual(
"<T:Ljava/lang/Object;:LI;R:LFoo<TT;[Lfoo/bar<TT;>.Baz<TT;[I>;>;>Lfoo/bar/baz<TT;>;");
}
@Test
public void testFormalTypeParameters2() {}
@Test
public void testFormalTypeParametersEmptyError() {
// TODO(b/169716723): This should throw an error
assertThrows(AssertionError.class, () -> testParsingAndPrintingError("<>Lfoo/bar/baz<TT;>;"));
}
private void testParsingAndPrintingEqual(String signature) {
ClassSignature parsed =
GenericSignature.parseClassSignature(
"A", signature, Origin.unknown(), new DexItemFactory(), new Reporter());
GenericSignaturePrinter genericSignaturePrinter =
new GenericSignaturePrinter(NamingLens.getIdentityLens(), Predicates.alwaysFalse());
genericSignaturePrinter.visitClassSignature(parsed);
String outSignature = genericSignaturePrinter.toString();
assertEquals(signature, outSignature);
}
private TestDiagnosticMessages testParsingAndPrintingError(String signature) {
TestDiagnosticMessagesImpl testDiagnosticMessages = new TestDiagnosticMessagesImpl();
ClassSignature parsed =
GenericSignature.parseClassSignature(
"A",
signature,
Origin.unknown(),
new DexItemFactory(),
new Reporter(testDiagnosticMessages));
assertEquals(NO_CLASS_SIGNATURE, parsed);
return testDiagnosticMessages;
}
}