Temporary use special container mapping logic for IR backend
This commit is contained in:
+2
-1
@@ -17,7 +17,8 @@ class KotlinToJvmSignatureMapperImpl : KotlinToJvmSignatureMapper {
|
|||||||
// We use empty BindingContext, because it is only used by KotlinTypeMapper for purposes irrelevant to the needs of this class
|
// We use empty BindingContext, because it is only used by KotlinTypeMapper for purposes irrelevant to the needs of this class
|
||||||
private val typeMapper = KotlinTypeMapper(
|
private val typeMapper = KotlinTypeMapper(
|
||||||
BindingContext.EMPTY, ClassBuilderMode.LIGHT_CLASSES,
|
BindingContext.EMPTY, ClassBuilderMode.LIGHT_CLASSES,
|
||||||
IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME, false, KotlinTypeMapper.RELEASE_COROUTINES_DEFAULT
|
IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME, false, KotlinTypeMapper.RELEASE_COROUTINES_DEFAULT,
|
||||||
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun mapToJvmMethodSignature(function: FunctionDescriptor) = typeMapper.mapAsmMethod(function)
|
override fun mapToJvmMethodSignature(function: FunctionDescriptor) = typeMapper.mapAsmMethod(function)
|
||||||
|
|||||||
+4
-2
@@ -48,12 +48,14 @@ class BuilderFactoryForDuplicateSignatureDiagnostics(
|
|||||||
private val diagnostics: DiagnosticSink,
|
private val diagnostics: DiagnosticSink,
|
||||||
moduleName: String,
|
moduleName: String,
|
||||||
isReleaseCoroutines: Boolean,
|
isReleaseCoroutines: Boolean,
|
||||||
shouldGenerate: (JvmDeclarationOrigin) -> Boolean
|
shouldGenerate: (JvmDeclarationOrigin) -> Boolean,
|
||||||
|
isIrBackend: Boolean
|
||||||
) : SignatureCollectingClassBuilderFactory(builderFactory, shouldGenerate) {
|
) : SignatureCollectingClassBuilderFactory(builderFactory, shouldGenerate) {
|
||||||
|
|
||||||
// Avoid errors when some classes are not loaded for some reason
|
// Avoid errors when some classes are not loaded for some reason
|
||||||
private val typeMapper = KotlinTypeMapper(
|
private val typeMapper = KotlinTypeMapper(
|
||||||
bindingContext, ClassBuilderMode.LIGHT_CLASSES, IncompatibleClassTracker.DoNothing, moduleName, false, isReleaseCoroutines
|
bindingContext, ClassBuilderMode.LIGHT_CLASSES, IncompatibleClassTracker.DoNothing, moduleName, false, isReleaseCoroutines,
|
||||||
|
isIrBackend
|
||||||
)
|
)
|
||||||
private val reportDiagnosticsTasks = ArrayList<() -> Unit>()
|
private val reportDiagnosticsTasks = ArrayList<() -> Unit>()
|
||||||
|
|
||||||
|
|||||||
@@ -181,13 +181,15 @@ class GenerationState private constructor(
|
|||||||
filter = if (wantsDiagnostics) BindingTraceFilter.ACCEPT_ALL else BindingTraceFilter.NO_DIAGNOSTICS
|
filter = if (wantsDiagnostics) BindingTraceFilter.ACCEPT_ALL else BindingTraceFilter.NO_DIAGNOSTICS
|
||||||
)
|
)
|
||||||
val bindingContext: BindingContext = bindingTrace.bindingContext
|
val bindingContext: BindingContext = bindingTrace.bindingContext
|
||||||
|
private val isIrBackend = configuration.get(JVMConfigurationKeys.IR) ?: false
|
||||||
val typeMapper: KotlinTypeMapper = KotlinTypeMapper(
|
val typeMapper: KotlinTypeMapper = KotlinTypeMapper(
|
||||||
this.bindingContext,
|
this.bindingContext,
|
||||||
classBuilderMode,
|
classBuilderMode,
|
||||||
IncompatibleClassTrackerImpl(extraJvmDiagnosticsTrace),
|
IncompatibleClassTrackerImpl(extraJvmDiagnosticsTrace),
|
||||||
this.moduleName,
|
this.moduleName,
|
||||||
isJvm8Target,
|
isJvm8Target,
|
||||||
configuration.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
|
configuration.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines),
|
||||||
|
isIrBackend
|
||||||
)
|
)
|
||||||
val intrinsics: IntrinsicMethods = run {
|
val intrinsics: IntrinsicMethods = run {
|
||||||
val shouldUseConsistentEquals = languageVersionSettings.supportsFeature(LanguageFeature.ThrowNpeOnExplicitEqualsForBoxedNull) &&
|
val shouldUseConsistentEquals = languageVersionSettings.supportsFeature(LanguageFeature.ThrowNpeOnExplicitEqualsForBoxedNull) &&
|
||||||
@@ -251,7 +253,8 @@ class GenerationState private constructor(
|
|||||||
BuilderFactoryForDuplicateSignatureDiagnostics(
|
BuilderFactoryForDuplicateSignatureDiagnostics(
|
||||||
it, this.bindingContext, diagnostics, this.moduleName,
|
it, this.bindingContext, diagnostics, this.moduleName,
|
||||||
isReleaseCoroutines = languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines),
|
isReleaseCoroutines = languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines),
|
||||||
shouldGenerate = { !shouldOnlyCollectSignatures(it) }
|
shouldGenerate = { !shouldOnlyCollectSignatures(it) },
|
||||||
|
isIrBackend = isIrBackend
|
||||||
).apply { duplicateSignatureFactory = this }
|
).apply { duplicateSignatureFactory = this }
|
||||||
},
|
},
|
||||||
{ BuilderFactoryForDuplicateClassNameDiagnostics(it, diagnostics) },
|
{ BuilderFactoryForDuplicateClassNameDiagnostics(it, diagnostics) },
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import com.intellij.psi.PsiElement;
|
|||||||
import kotlin.Pair;
|
import kotlin.Pair;
|
||||||
import kotlin.Unit;
|
import kotlin.Unit;
|
||||||
import kotlin.collections.CollectionsKt;
|
import kotlin.collections.CollectionsKt;
|
||||||
import kotlin.reflect.KType;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment;
|
import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment;
|
||||||
@@ -87,6 +86,7 @@ public class KotlinTypeMapper {
|
|||||||
private final String moduleName;
|
private final String moduleName;
|
||||||
private final boolean isJvm8Target;
|
private final boolean isJvm8Target;
|
||||||
private final boolean isReleaseCoroutines;
|
private final boolean isReleaseCoroutines;
|
||||||
|
private boolean isIrBackend;
|
||||||
|
|
||||||
private final TypeMappingConfiguration<Type> typeMappingConfiguration = new TypeMappingConfiguration<Type>() {
|
private final TypeMappingConfiguration<Type> typeMappingConfiguration = new TypeMappingConfiguration<Type>() {
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -158,7 +158,7 @@ public class KotlinTypeMapper {
|
|||||||
@NotNull String moduleName,
|
@NotNull String moduleName,
|
||||||
boolean isJvm8Target
|
boolean isJvm8Target
|
||||||
) {
|
) {
|
||||||
this(bindingContext, classBuilderMode, incompatibleClassTracker, moduleName, isJvm8Target, false);
|
this(bindingContext, classBuilderMode, incompatibleClassTracker, moduleName, isJvm8Target, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KotlinTypeMapper(
|
public KotlinTypeMapper(
|
||||||
@@ -167,7 +167,8 @@ public class KotlinTypeMapper {
|
|||||||
@NotNull IncompatibleClassTracker incompatibleClassTracker,
|
@NotNull IncompatibleClassTracker incompatibleClassTracker,
|
||||||
@NotNull String moduleName,
|
@NotNull String moduleName,
|
||||||
boolean isJvm8Target,
|
boolean isJvm8Target,
|
||||||
boolean isReleaseCoroutines
|
boolean isReleaseCoroutines,
|
||||||
|
boolean isIrBackend
|
||||||
) {
|
) {
|
||||||
this.bindingContext = bindingContext;
|
this.bindingContext = bindingContext;
|
||||||
this.classBuilderMode = classBuilderMode;
|
this.classBuilderMode = classBuilderMode;
|
||||||
@@ -175,6 +176,7 @@ public class KotlinTypeMapper {
|
|||||||
this.moduleName = moduleName;
|
this.moduleName = moduleName;
|
||||||
this.isJvm8Target = isJvm8Target;
|
this.isJvm8Target = isJvm8Target;
|
||||||
this.isReleaseCoroutines = isReleaseCoroutines;
|
this.isReleaseCoroutines = isReleaseCoroutines;
|
||||||
|
this.isIrBackend = isIrBackend;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final boolean RELEASE_COROUTINES_DEFAULT = false;
|
public static final boolean RELEASE_COROUTINES_DEFAULT = false;
|
||||||
@@ -505,7 +507,8 @@ public class KotlinTypeMapper {
|
|||||||
(ktType, asmType, typeMappingMode) -> {
|
(ktType, asmType, typeMappingMode) -> {
|
||||||
writeGenericType(ktType, asmType, signatureVisitor, typeMappingMode);
|
writeGenericType(ktType, asmType, signatureVisitor, typeMappingMode);
|
||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
}
|
},
|
||||||
|
isIrBackend
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -541,7 +544,8 @@ public class KotlinTypeMapper {
|
|||||||
) {
|
) {
|
||||||
return TypeSignatureMappingKt.mapType(
|
return TypeSignatureMappingKt.mapType(
|
||||||
kotlinType, AsmTypeFactory.INSTANCE, mode, staticTypeMappingConfiguration, null,
|
kotlinType, AsmTypeFactory.INSTANCE, mode, staticTypeMappingConfiguration, null,
|
||||||
(ktType, asmType, typeMappingMode) -> Unit.INSTANCE
|
(ktType, asmType, typeMappingMode) -> Unit.INSTANCE,
|
||||||
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1677,7 +1681,7 @@ public class KotlinTypeMapper {
|
|||||||
if (recordedType != null) {
|
if (recordedType != null) {
|
||||||
return recordedType.getInternalName();
|
return recordedType.getInternalName();
|
||||||
}
|
}
|
||||||
return TypeSignatureMappingKt.computeInternalName(classDescriptor, typeMappingConfiguration);
|
return TypeSignatureMappingKt.computeInternalName(classDescriptor, typeMappingConfiguration, isIrBackend);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class InternalNameMapper {
|
public static class InternalNameMapper {
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ internal val ClassDescriptor.internalName: String
|
|||||||
return JvmClassName.byClassId(it).internalName
|
return JvmClassName.byClassId(it).internalName
|
||||||
}
|
}
|
||||||
|
|
||||||
return computeInternalName(this)
|
return computeInternalName(this, isIrBackend = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val ClassId.internalName: String
|
internal val ClassId.internalName: String
|
||||||
@@ -89,7 +89,14 @@ private fun StringBuilder.appendErasedType(type: KotlinType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun KotlinType.mapToJvmType() =
|
internal fun KotlinType.mapToJvmType() =
|
||||||
mapType(this, JvmTypeFactoryImpl, TypeMappingMode.DEFAULT, TypeMappingConfigurationImpl, descriptorTypeWriter = null)
|
mapType(
|
||||||
|
this,
|
||||||
|
JvmTypeFactoryImpl,
|
||||||
|
TypeMappingMode.DEFAULT,
|
||||||
|
TypeMappingConfigurationImpl,
|
||||||
|
descriptorTypeWriter = null,
|
||||||
|
isIrBackend = false
|
||||||
|
)
|
||||||
|
|
||||||
sealed class JvmType {
|
sealed class JvmType {
|
||||||
// null means 'void'
|
// null means 'void'
|
||||||
|
|||||||
@@ -51,13 +51,15 @@ fun <T : Any> mapType(
|
|||||||
mode: TypeMappingMode,
|
mode: TypeMappingMode,
|
||||||
typeMappingConfiguration: TypeMappingConfiguration<T>,
|
typeMappingConfiguration: TypeMappingConfiguration<T>,
|
||||||
descriptorTypeWriter: JvmDescriptorTypeWriter<T>?,
|
descriptorTypeWriter: JvmDescriptorTypeWriter<T>?,
|
||||||
writeGenericType: (KotlinType, T, TypeMappingMode) -> Unit = DO_NOTHING_3
|
writeGenericType: (KotlinType, T, TypeMappingMode) -> Unit = DO_NOTHING_3,
|
||||||
|
isIrBackend: Boolean
|
||||||
): T {
|
): T {
|
||||||
if (kotlinType.isSuspendFunctionType) {
|
if (kotlinType.isSuspendFunctionType) {
|
||||||
return mapType(
|
return mapType(
|
||||||
transformSuspendFunctionToRuntimeFunctionType(kotlinType, typeMappingConfiguration.releaseCoroutines()),
|
transformSuspendFunctionToRuntimeFunctionType(kotlinType, typeMappingConfiguration.releaseCoroutines()),
|
||||||
factory, mode, typeMappingConfiguration, descriptorTypeWriter,
|
factory, mode, typeMappingConfiguration, descriptorTypeWriter,
|
||||||
writeGenericType
|
writeGenericType,
|
||||||
|
isIrBackend
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +80,7 @@ fun <T : Any> mapType(
|
|||||||
// It's not very important because such types anyway are prohibited in declarations
|
// It's not very important because such types anyway are prohibited in declarations
|
||||||
return mapType(
|
return mapType(
|
||||||
commonSupertype.replaceArgumentsWithStarProjections(),
|
commonSupertype.replaceArgumentsWithStarProjections(),
|
||||||
factory, mode, typeMappingConfiguration, descriptorTypeWriter, writeGenericType
|
factory, mode, typeMappingConfiguration, descriptorTypeWriter, writeGenericType, isIrBackend
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +118,8 @@ fun <T : Any> mapType(
|
|||||||
mapType(
|
mapType(
|
||||||
memberType, factory,
|
memberType, factory,
|
||||||
mode.toGenericArgumentMode(memberProjection.projectionKind),
|
mode.toGenericArgumentMode(memberProjection.projectionKind),
|
||||||
typeMappingConfiguration, descriptorTypeWriter, writeGenericType
|
typeMappingConfiguration, descriptorTypeWriter, writeGenericType,
|
||||||
|
isIrBackend
|
||||||
)
|
)
|
||||||
|
|
||||||
descriptorTypeWriter?.writeArrayEnd()
|
descriptorTypeWriter?.writeArrayEnd()
|
||||||
@@ -130,7 +133,15 @@ fun <T : Any> mapType(
|
|||||||
val typeForMapping = computeUnderlyingType(kotlinType)
|
val typeForMapping = computeUnderlyingType(kotlinType)
|
||||||
if (typeForMapping != null) {
|
if (typeForMapping != null) {
|
||||||
val newMode = if (typeForMapping.isInlineClassType()) mode else mode.wrapInlineClassesMode()
|
val newMode = if (typeForMapping.isInlineClassType()) mode else mode.wrapInlineClassesMode()
|
||||||
return mapType(typeForMapping, factory, newMode, typeMappingConfiguration, descriptorTypeWriter, writeGenericType)
|
return mapType(
|
||||||
|
typeForMapping,
|
||||||
|
factory,
|
||||||
|
newMode,
|
||||||
|
typeMappingConfiguration,
|
||||||
|
descriptorTypeWriter,
|
||||||
|
writeGenericType,
|
||||||
|
isIrBackend
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +155,13 @@ fun <T : Any> mapType(
|
|||||||
val enumClassIfEnumEntry = if (descriptor.kind == ClassKind.ENUM_ENTRY)
|
val enumClassIfEnumEntry = if (descriptor.kind == ClassKind.ENUM_ENTRY)
|
||||||
descriptor.containingDeclaration as ClassDescriptor
|
descriptor.containingDeclaration as ClassDescriptor
|
||||||
else descriptor
|
else descriptor
|
||||||
factory.createObjectType(computeInternalName(enumClassIfEnumEntry.original, typeMappingConfiguration))
|
factory.createObjectType(
|
||||||
|
computeInternalName(
|
||||||
|
enumClassIfEnumEntry.original,
|
||||||
|
typeMappingConfiguration,
|
||||||
|
isIrBackend
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +173,12 @@ fun <T : Any> mapType(
|
|||||||
descriptor is TypeParameterDescriptor -> {
|
descriptor is TypeParameterDescriptor -> {
|
||||||
val type = mapType(
|
val type = mapType(
|
||||||
getRepresentativeUpperBound(descriptor),
|
getRepresentativeUpperBound(descriptor),
|
||||||
factory, mode, typeMappingConfiguration, writeGenericType = DO_NOTHING_3, descriptorTypeWriter = null
|
factory,
|
||||||
|
mode,
|
||||||
|
typeMappingConfiguration,
|
||||||
|
writeGenericType = DO_NOTHING_3,
|
||||||
|
descriptorTypeWriter = null,
|
||||||
|
isIrBackend = isIrBackend
|
||||||
)
|
)
|
||||||
descriptorTypeWriter?.writeTypeVariable(descriptor.getName(), type)
|
descriptorTypeWriter?.writeTypeVariable(descriptor.getName(), type)
|
||||||
return type
|
return type
|
||||||
@@ -237,9 +259,10 @@ private fun shouldUseUnderlyingType(inlineClassType: KotlinType): Boolean {
|
|||||||
|
|
||||||
fun computeInternalName(
|
fun computeInternalName(
|
||||||
klass: ClassDescriptor,
|
klass: ClassDescriptor,
|
||||||
typeMappingConfiguration: TypeMappingConfiguration<*> = TypeMappingConfigurationImpl
|
typeMappingConfiguration: TypeMappingConfiguration<*> = TypeMappingConfigurationImpl,
|
||||||
|
isIrBackend: Boolean
|
||||||
): String {
|
): String {
|
||||||
val container = klass.containingDeclaration
|
val container = if (isIrBackend) getContainer(klass.containingDeclaration) else klass.containingDeclaration
|
||||||
|
|
||||||
val name = SpecialNames.safeIdentifier(klass.name).identifier
|
val name = SpecialNames.safeIdentifier(klass.name).identifier
|
||||||
if (container is PackageFragmentDescriptor) {
|
if (container is PackageFragmentDescriptor) {
|
||||||
@@ -253,11 +276,16 @@ fun computeInternalName(
|
|||||||
val containerInternalName =
|
val containerInternalName =
|
||||||
typeMappingConfiguration.getPredefinedInternalNameForClass(containerClass) ?: computeInternalName(
|
typeMappingConfiguration.getPredefinedInternalNameForClass(containerClass) ?: computeInternalName(
|
||||||
containerClass,
|
containerClass,
|
||||||
typeMappingConfiguration
|
typeMappingConfiguration,
|
||||||
|
isIrBackend
|
||||||
)
|
)
|
||||||
return containerInternalName + "$" + name
|
return containerInternalName + "$" + name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getContainer(container: DeclarationDescriptor?): DeclarationDescriptor? =
|
||||||
|
container as? ClassDescriptor ?: container as? PackageFragmentDescriptor ?:
|
||||||
|
container?.let { getContainer(it.containingDeclaration) }
|
||||||
|
|
||||||
private fun getRepresentativeUpperBound(descriptor: TypeParameterDescriptor): KotlinType {
|
private fun getRepresentativeUpperBound(descriptor: TypeParameterDescriptor): KotlinType {
|
||||||
val upperBounds = descriptor.upperBounds
|
val upperBounds = descriptor.upperBounds
|
||||||
assert(!upperBounds.isEmpty()) { "Upper bounds should not be empty: " + descriptor }
|
assert(!upperBounds.isEmpty()) { "Upper bounds should not be empty: " + descriptor }
|
||||||
|
|||||||
+2
-1
@@ -185,7 +185,8 @@ class ParcelableDeclarationChecker : DeclarationChecker {
|
|||||||
IncompatibleClassTracker.DoNothing,
|
IncompatibleClassTracker.DoNothing,
|
||||||
descriptor.module.name.asString(),
|
descriptor.module.name.asString(),
|
||||||
/* isJvm8Target */ false,
|
/* isJvm8Target */ false,
|
||||||
/* isReleaseCoroutines */ KotlinTypeMapper.RELEASE_COROUTINES_DEFAULT
|
/* isReleaseCoroutines */ KotlinTypeMapper.RELEASE_COROUTINES_DEFAULT,
|
||||||
|
/* isIrBackend*/false
|
||||||
)
|
)
|
||||||
|
|
||||||
for (parameter in primaryConstructor?.valueParameters.orEmpty()) {
|
for (parameter in primaryConstructor?.valueParameters.orEmpty()) {
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ class IdeaKotlinUastResolveProviderService : KotlinUastResolveProviderService {
|
|||||||
override fun getTypeMapper(element: KtElement): KotlinTypeMapper? {
|
override fun getTypeMapper(element: KtElement): KotlinTypeMapper? {
|
||||||
return KotlinTypeMapper(
|
return KotlinTypeMapper(
|
||||||
getBindingContext(element), ClassBuilderMode.LIGHT_CLASSES,
|
getBindingContext(element), ClassBuilderMode.LIGHT_CLASSES,
|
||||||
IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME, false, KotlinTypeMapper.RELEASE_COROUTINES_DEFAULT
|
IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME, false, KotlinTypeMapper.RELEASE_COROUTINES_DEFAULT,
|
||||||
|
false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -56,7 +56,8 @@ class UastAnalysisHandlerExtension : AnalysisHandlerExtension {
|
|||||||
|
|
||||||
val typeMapper = KotlinTypeMapper(
|
val typeMapper = KotlinTypeMapper(
|
||||||
bindingContext, ClassBuilderMode.LIGHT_CLASSES,
|
bindingContext, ClassBuilderMode.LIGHT_CLASSES,
|
||||||
IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME, false, KotlinTypeMapper.RELEASE_COROUTINES_DEFAULT
|
IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME, false, KotlinTypeMapper.RELEASE_COROUTINES_DEFAULT,
|
||||||
|
false
|
||||||
)
|
)
|
||||||
this.typeMapper = typeMapper
|
this.typeMapper = typeMapper
|
||||||
return typeMapper
|
return typeMapper
|
||||||
|
|||||||
Reference in New Issue
Block a user