Align generic signature for inner classes to work as in Java

#KT-10397 Fixed

According to JVMS (p. 4.3.4) inner classes should be separated with `$` in generic signature.

Note that in Java, inner types separated with `.` after first parameterized type, and now we preserve the same behaviour. See tests for clarification.
This commit is contained in:
Mikhail Zarechenskiy
2017-04-26 16:23:54 +03:00
parent 14e798a1fc
commit a0d7b703f4
16 changed files with 350 additions and 13 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -530,25 +530,35 @@ public class KotlinTypeMapper {
List<PossiblyInnerType> innerTypesAsList = possiblyInnerType.segments();
if (innerTypesAsList.size() == 1) {
int indexOfParameterizedType = CollectionsKt.indexOfFirst(innerTypesAsList, innerPart -> !innerPart.getArguments().isEmpty());
if (indexOfParameterizedType < 0 || innerTypesAsList.size() == 1) {
signatureVisitor.writeClassBegin(asmType);
writeGenericArguments(signatureVisitor, possiblyInnerType, mode);
}
else {
ClassDescriptor outermostClass = innerTypesAsList.get(0).getClassDescriptor();
signatureVisitor.writeOuterClassBegin(asmType, mapType(outermostClass.getDefaultType()).getInternalName());
}
PossiblyInnerType outerType = innerTypesAsList.get(indexOfParameterizedType);
for (int i = 0; i < innerTypesAsList.size(); i++) {
PossiblyInnerType innerPart = innerTypesAsList.get(i);
if (i > 0) {
signatureVisitor.writeInnerClass(getJvmShortName(innerPart.getClassDescriptor()));
}
writeGenericArguments(signatureVisitor, innerPart, mode);
signatureVisitor.writeOuterClassBegin(asmType, mapType(outerType.getClassDescriptor()).getInternalName());
writeGenericArguments(signatureVisitor, outerType, mode);
writeInnerParts(innerTypesAsList, signatureVisitor, mode, indexOfParameterizedType + 1); // inner parts separated by `.`
}
signatureVisitor.writeClassEnd();
}
private void writeInnerParts(
@NotNull List<PossiblyInnerType> innerTypesAsList,
@NotNull JvmSignatureWriter signatureVisitor,
@NotNull TypeMappingMode mode,
int index
) {
for (PossiblyInnerType innerPart : innerTypesAsList.subList(index, innerTypesAsList.size())) {
signatureVisitor.writeInnerClass(getJvmShortName(innerPart.getClassDescriptor()));
writeGenericArguments(signatureVisitor, innerPart, mode);
}
}
@NotNull
private static String getJvmShortName(@NotNull ClassDescriptor klass) {
ClassId classId = JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(DescriptorUtils.getFqName(klass));
@@ -0,0 +1,23 @@
// WITH_REFLECT
// IGNORE_BACKEND: JS, NATIVE
abstract class Outer {
inner class FirstInner {
inner class SecondInner<A> {
inner class ThirdInnner {
inner class FourthInner<B>
fun <C> foo(): FourthInner<C> = TODO()
}
}
}
}
fun box(): String {
kotlin.test.assertEquals(
"Outer\$FirstInner.Outer\$FirstInner\$SecondInner<A>.ThirdInnner.FourthInner<C>",
Outer.FirstInner.SecondInner.ThirdInnner::class.java.declaredMethods.single().genericReturnType.toString())
return "OK"
}
@@ -0,0 +1,22 @@
// WITH_REFLECT
// IGNORE_BACKEND: JS, NATIVE
abstract class Outer {
inner class FirstInner {
inner class SecondInner<A> {
inner class ThirdInnner {
inner class FourthInner
fun foo(): FourthInner = TODO()
}
}
}
}
fun box(): String {
kotlin.test.assertEquals(
"Outer\$FirstInner.Outer\$FirstInner\$SecondInner<A>.ThirdInnner.FourthInner",
Outer.FirstInner.SecondInner.ThirdInnner::class.java.declaredMethods.single().genericReturnType.toString())
return "OK"
}
@@ -0,0 +1,23 @@
// WITH_REFLECT
// IGNORE_BACKEND: JS, NATIVE
abstract class Outer {
inner class FirstInner {
inner class SecondInner {
inner class ThirdInnner {
inner class FourthInner<A>
fun <B> foo(): FourthInner<B> = TODO()
}
}
}
}
fun box(): String {
kotlin.test.assertEquals(
"Outer\$FirstInner\$SecondInner\$ThirdInnner.Outer\$FirstInner\$SecondInner\$ThirdInnner\$FourthInner<B>",
Outer.FirstInner.SecondInner.ThirdInnner::class.java.declaredMethods.single().genericReturnType.toString())
return "OK"
}
@@ -0,0 +1,15 @@
// WITH_REFLECT
// IGNORE_BACKEND: JS, NATIVE
abstract class Outer<S> {
inner class Inner<R>
fun <R> foo(): Inner<R>? = null
}
fun box(): String {
kotlin.test.assertEquals(
"Outer<S>.Inner<R>",
Outer::class.java.declaredMethods.single().genericReturnType.toString())
return "OK"
}
@@ -0,0 +1,15 @@
// WITH_REFLECT
// IGNORE_BACKEND: JS, NATIVE
abstract class Outer {
inner class Inner<R>
fun <R> foo(): Inner<R>? = null
}
fun box(): String {
kotlin.test.assertEquals(
"Outer.Outer\$Inner<R>",
Outer::class.java.declaredMethods.single().genericReturnType.toString())
return "OK"
}
@@ -0,0 +1,15 @@
// WITH_REFLECT
// IGNORE_BACKEND: JS, NATIVE
abstract class Outer {
inner class Inner
fun foo(): Inner? = null
}
fun box(): String {
kotlin.test.assertEquals(
"class Outer\$Inner",
Outer::class.java.declaredMethods.single().genericReturnType.toString())
return "OK"
}
@@ -0,0 +1,15 @@
abstract class Outer {
inner class FirstInner {
inner class SecondInner<A> {
inner class ThirdInnner {
inner class FourthInner<B>
}
}
}
fun <T, V> foo(): FirstInner.SecondInner<T>.ThirdInnner.FourthInner<V> = TODO()
}
// method: Outer::foo
// jvm signature: ()LOuter$FirstInner$SecondInner$ThirdInnner$FourthInner;
// generic signature: <T:Ljava/lang/Object;V:Ljava/lang/Object;>()LOuter$FirstInner$SecondInner<TT;>.ThirdInnner.FourthInner<TV;>;
@@ -0,0 +1,9 @@
class Outer {
inner class Inner<G>
fun <A> foo(): Inner<A> = TODO()
}
// method: Outer::foo
// jvm signature: ()LOuter$Inner;
// generic signature: <A:Ljava/lang/Object;>()LOuter$Inner<TA;>;
@@ -14514,6 +14514,42 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/kt6106.kt");
doTest(fileName);
}
@TestMetadata("signatureOfDeepGenericInner.kt")
public void testSignatureOfDeepGenericInner() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepGenericInner.kt");
doTest(fileName);
}
@TestMetadata("signatureOfDeepInner.kt")
public void testSignatureOfDeepInner() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepInner.kt");
doTest(fileName);
}
@TestMetadata("signatureOfDeepInnerLastGeneric.kt")
public void testSignatureOfDeepInnerLastGeneric() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepInnerLastGeneric.kt");
doTest(fileName);
}
@TestMetadata("signatureOfGenericInnerGenericOuter.kt")
public void testSignatureOfGenericInnerGenericOuter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfGenericInnerGenericOuter.kt");
doTest(fileName);
}
@TestMetadata("signatureOfGenericInnerSimpleOuter.kt")
public void testSignatureOfGenericInnerSimpleOuter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfGenericInnerSimpleOuter.kt");
doTest(fileName);
}
@TestMetadata("signatureOfSimpleInnerSimpleOuter.kt")
public void testSignatureOfSimpleInnerSimpleOuter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfSimpleInnerSimpleOuter.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/box/reflection/isInstance")
@@ -14514,6 +14514,42 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/kt6106.kt");
doTest(fileName);
}
@TestMetadata("signatureOfDeepGenericInner.kt")
public void testSignatureOfDeepGenericInner() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepGenericInner.kt");
doTest(fileName);
}
@TestMetadata("signatureOfDeepInner.kt")
public void testSignatureOfDeepInner() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepInner.kt");
doTest(fileName);
}
@TestMetadata("signatureOfDeepInnerLastGeneric.kt")
public void testSignatureOfDeepInnerLastGeneric() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepInnerLastGeneric.kt");
doTest(fileName);
}
@TestMetadata("signatureOfGenericInnerGenericOuter.kt")
public void testSignatureOfGenericInnerGenericOuter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfGenericInnerGenericOuter.kt");
doTest(fileName);
}
@TestMetadata("signatureOfGenericInnerSimpleOuter.kt")
public void testSignatureOfGenericInnerSimpleOuter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfGenericInnerSimpleOuter.kt");
doTest(fileName);
}
@TestMetadata("signatureOfSimpleInnerSimpleOuter.kt")
public void testSignatureOfSimpleInnerSimpleOuter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfSimpleInnerSimpleOuter.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/box/reflection/isInstance")
@@ -14514,6 +14514,42 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/kt6106.kt");
doTest(fileName);
}
@TestMetadata("signatureOfDeepGenericInner.kt")
public void testSignatureOfDeepGenericInner() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepGenericInner.kt");
doTest(fileName);
}
@TestMetadata("signatureOfDeepInner.kt")
public void testSignatureOfDeepInner() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepInner.kt");
doTest(fileName);
}
@TestMetadata("signatureOfDeepInnerLastGeneric.kt")
public void testSignatureOfDeepInnerLastGeneric() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepInnerLastGeneric.kt");
doTest(fileName);
}
@TestMetadata("signatureOfGenericInnerGenericOuter.kt")
public void testSignatureOfGenericInnerGenericOuter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfGenericInnerGenericOuter.kt");
doTest(fileName);
}
@TestMetadata("signatureOfGenericInnerSimpleOuter.kt")
public void testSignatureOfGenericInnerSimpleOuter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfGenericInnerSimpleOuter.kt");
doTest(fileName);
}
@TestMetadata("signatureOfSimpleInnerSimpleOuter.kt")
public void testSignatureOfSimpleInnerSimpleOuter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfSimpleInnerSimpleOuter.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/box/reflection/isInstance")
@@ -60,12 +60,24 @@ public class WriteSignatureTestGenerated extends AbstractWriteSignatureTest {
doTest(fileName);
}
@TestMetadata("DeepGenericInnerClass.kt")
public void testDeepGenericInnerClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/DeepGenericInnerClass.kt");
doTest(fileName);
}
@TestMetadata("GenericInnerClass.kt")
public void testGenericInnerClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/GenericInnerClass.kt");
doTest(fileName);
}
@TestMetadata("GenericInnerClassWithSimpleOuter.kt")
public void testGenericInnerClassWithSimpleOuter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/GenericInnerClassWithSimpleOuter.kt");
doTest(fileName);
}
@TestMetadata("Int.kt")
public void testInt() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeSignature/Int.kt");
@@ -17216,6 +17216,78 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("signatureOfDeepGenericInner.kt")
public void testSignatureOfDeepGenericInner() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepGenericInner.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("signatureOfDeepInner.kt")
public void testSignatureOfDeepInner() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepInner.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("signatureOfDeepInnerLastGeneric.kt")
public void testSignatureOfDeepInnerLastGeneric() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfDeepInnerLastGeneric.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("signatureOfGenericInnerGenericOuter.kt")
public void testSignatureOfGenericInnerGenericOuter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfGenericInnerGenericOuter.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("signatureOfGenericInnerSimpleOuter.kt")
public void testSignatureOfGenericInnerSimpleOuter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfGenericInnerSimpleOuter.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("signatureOfSimpleInnerSimpleOuter.kt")
public void testSignatureOfSimpleInnerSimpleOuter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/genericSignature/signatureOfSimpleInnerSimpleOuter.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
}
@TestMetadata("compiler/testData/codegen/box/reflection/isInstance")
@@ -59,5 +59,4 @@ public class OutputPrefixPostfixTestGenerated extends AbstractOutputPrefixPostfi
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/outputPrefixPostfix/simpleWithPrefixAndPostfix.kt");
doTest(fileName);
}
}
@@ -53,5 +53,4 @@ public class SourceMapGenerationSmokeTestGenerated extends AbstractSourceMapGene
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/sourcemap/methodCallInMethod.kt");
doTest(fileName);
}
}