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:
@@ -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));
|
||||
|
||||
+23
@@ -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"
|
||||
}
|
||||
+22
@@ -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"
|
||||
}
|
||||
Vendored
+23
@@ -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"
|
||||
}
|
||||
Vendored
+15
@@ -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"
|
||||
}
|
||||
Vendored
+15
@@ -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"
|
||||
}
|
||||
Vendored
+15
@@ -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;>;
|
||||
+36
@@ -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");
|
||||
|
||||
+72
@@ -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")
|
||||
|
||||
-1
@@ -59,5 +59,4 @@ public class OutputPrefixPostfixTestGenerated extends AbstractOutputPrefixPostfi
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/outputPrefixPostfix/simpleWithPrefixAndPostfix.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-1
@@ -53,5 +53,4 @@ public class SourceMapGenerationSmokeTestGenerated extends AbstractSourceMapGene
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/sourcemap/methodCallInMethod.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user