Skip to content

Commit 92d0f2f

Browse files
sbogolepovSpace Team
authored andcommitted
[ObjCExport] Support objcExportBlockExplicitParameterNames in K2 version
^KT-77488 Fixed
1 parent d4510aa commit 92d0f2f

File tree

9 files changed

+109
-11
lines changed

9 files changed

+109
-11
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
3+
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
4+
*/
5+
6+
package org.jetbrains.kotlin.analysis.api.export.utilities
7+
8+
import org.jetbrains.kotlin.analysis.api.annotations.KaAnnotation
9+
import org.jetbrains.kotlin.analysis.api.annotations.KaAnnotationValue
10+
import org.jetbrains.kotlin.analysis.api.types.KaType
11+
import org.jetbrains.kotlin.builtins.StandardNames
12+
import org.jetbrains.kotlin.name.Name
13+
import org.jetbrains.kotlin.name.StandardClassIds
14+
15+
public fun KaType.getValueFromParameterNameAnnotation(): Name? {
16+
val resultingAnnotation = findParameterNameAnnotation() ?: return null
17+
val parameterNameArgument = resultingAnnotation.arguments
18+
.singleOrNull { it.name == StandardClassIds.Annotations.ParameterNames.parameterNameName }
19+
20+
val constantArgumentValue = parameterNameArgument?.expression as? KaAnnotationValue.ConstantValue ?: return null
21+
22+
return (constantArgumentValue.value.value as? String)?.let(Name::identifier)
23+
}
24+
25+
private fun KaType.findParameterNameAnnotation(): KaAnnotation? {
26+
val allParameterNameAnnotations = annotations[StandardNames.FqNames.parameterNameClassId]
27+
val (explicitAnnotations, implicitAnnotations) = allParameterNameAnnotations.partition { it.psi != null }
28+
29+
return explicitAnnotations.firstOrNull() ?: implicitAnnotations.singleOrNull()
30+
}

native/objcexport-header-generator/impl/analysis-api/src/org/jetbrains/kotlin/objcexport/KtObjCExportConfiguration.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,7 @@ data class KtObjCExportConfiguration(
2222
* - [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportNamingHelper.canBeSwiftInner]
2323
*/
2424
val objcGenerics: Boolean = true,
25+
26+
val objcExportBlockExplicitParameterNames: Boolean = true,
2527
)
2628

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
package org.jetbrains.kotlin.objcexport.mangling
22

3+
import org.jetbrains.kotlin.backend.konan.cKeywords
4+
import org.jetbrains.kotlin.objcexport.toValidObjCSwiftIdentifier
5+
36
internal fun String.mangleSelector(postfix: String): String {
47
return if (this.contains(":")) this.replace(":", "$postfix:")
58
else this + postfix
9+
}
10+
11+
internal fun unifyName(initialName: String, usedNames: Set<String>): String {
12+
var unique = initialName.toValidObjCSwiftIdentifier()
13+
while (unique in usedNames || unique in cKeywords) {
14+
unique += "_"
15+
}
16+
return unique
617
}

native/objcexport-header-generator/impl/analysis-api/src/org/jetbrains/kotlin/objcexport/translateToObjCFunctionType.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package org.jetbrains.kotlin.objcexport
22

3+
import org.jetbrains.kotlin.analysis.api.export.utilities.getValueFromParameterNameAnnotation
34
import org.jetbrains.kotlin.analysis.api.types.KaFunctionType
45
import org.jetbrains.kotlin.analysis.api.types.KaType
56
import org.jetbrains.kotlin.backend.konan.objcexport.*
67
import org.jetbrains.kotlin.objcexport.analysisApiUtils.isObjCVoid
8+
import org.jetbrains.kotlin.objcexport.mangling.unifyName
79

810
internal fun ObjCExportContext.translateToObjCFunctionType(type: KaType, returnsVoid: Boolean): ObjCReferenceType {
911
if (type !is KaFunctionType) return ObjCIdType
12+
val usedNames = mutableSetOf<String>()
1013
val objCBlockPointerType = ObjCBlockPointerType(
1114
returnType = if (returnsVoid) {
1215
ObjCVoidType
@@ -16,8 +19,16 @@ internal fun ObjCExportContext.translateToObjCFunctionType(type: KaType, returns
1619
else translateToObjCReferenceType(returnType)
1720
},
1821
parameters = listOfNotNull(type.receiverType).plus(type.parameterTypes).map { parameterType ->
22+
val name = if (this@translateToObjCFunctionType.exportSession.configuration.objcExportBlockExplicitParameterNames) {
23+
val parameterName = parameterType.getValueFromParameterNameAnnotation()?.asString() ?: ""
24+
val mangledName = unifyName(parameterName, usedNames)
25+
usedNames += mangledName
26+
mangledName
27+
} else {
28+
""
29+
}
1930
ObjCParameter(
20-
"",
31+
name,
2132
null,
2233
type = translateToObjCReferenceType(parameterType),
2334
todo = null,

native/objcexport-header-generator/impl/analysis-api/src/org/jetbrains/kotlin/objcexport/translateToObjCParameters.kt

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,14 @@ package org.jetbrains.kotlin.objcexport
77

88
import org.jetbrains.kotlin.analysis.api.symbols.KaFunctionSymbol
99
import org.jetbrains.kotlin.analysis.api.symbols.KaPropertySetterSymbol
10-
import org.jetbrains.kotlin.backend.konan.cKeywords
1110
import org.jetbrains.kotlin.backend.konan.objcexport.*
1211
import org.jetbrains.kotlin.name.StandardClassIds
1312
import org.jetbrains.kotlin.objcexport.analysisApiUtils.errorParameterName
1413
import org.jetbrains.kotlin.objcexport.extras.objCTypeExtras
1514
import org.jetbrains.kotlin.objcexport.extras.*
15+
import org.jetbrains.kotlin.objcexport.mangling.unifyName
1616

1717
internal fun ObjCExportContext.translateToObjCParameters(symbol: KaFunctionSymbol, baseMethodBridge: MethodBridge): List<ObjCParameter> {
18-
fun unifyName(initialName: String, usedNames: Set<String>): String {
19-
var unique = initialName.toValidObjCSwiftIdentifier()
20-
while (unique in usedNames || unique in cKeywords) {
21-
unique += "_"
22-
}
23-
return unique
24-
}
25-
2618
val valueParametersAssociated = valueParametersAssociated(baseMethodBridge, symbol)
2719
val parameters = mutableListOf<ObjCParameter>()
2820
val usedNames = mutableSetOf<String>()

native/objcexport-header-generator/impl/analysis-api/test/org/jetbrains/kotlin/objcexport/testUtils/AnalysisApiHeaderGenerator.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ object AnalysisApiHeaderGenerator : HeaderGenerator {
5353
withKtObjCExportSession(
5454
KtObjCExportConfiguration(
5555
frameworkName = configuration.frameworkName,
56+
objcExportBlockExplicitParameterNames = configuration.objcExportBlockExplicitParameterNames,
5657
),
5758
moduleClassifier = { module ->
5859
module == useSiteModule || module is KaLibraryModule && module in exportedLibraries

native/objcexport-header-generator/test/org/jetbrains/kotlin/backend/konan/tests/ObjCExportHeaderGeneratorTest.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -650,11 +650,15 @@ class ObjCExportHeaderGeneratorTest(private val generator: HeaderGenerator) {
650650
}
651651

652652
@Test
653-
@TodoAnalysisApi
654653
fun `test - block with explicit parameter names`() {
655654
doTest(headersTestDataDir.resolve("blockWithExplicitParameterNames"))
656655
}
657656

657+
@Test
658+
fun `test - block with no parameter names`() {
659+
doTest(headersTestDataDir.resolve("blockWithNoParameterNames"), Configuration(objcExportBlockExplicitParameterNames = false))
660+
}
661+
658662
@Test
659663
fun `test - release keyword as method name`() {
660664
doTest(headersTestDataDir.resolve("releaseKeywordAsMethodName"))
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#import <Foundation/NSArray.h>
2+
#import <Foundation/NSDictionary.h>
3+
#import <Foundation/NSError.h>
4+
#import <Foundation/NSObject.h>
5+
#import <Foundation/NSSet.h>
6+
#import <Foundation/NSString.h>
7+
#import <Foundation/NSValue.h>
8+
9+
@class Foo;
10+
11+
NS_ASSUME_NONNULL_BEGIN
12+
#pragma clang diagnostic push
13+
#pragma clang diagnostic ignored "-Wunknown-warning-option"
14+
#pragma clang diagnostic ignored "-Wincompatible-property-type"
15+
#pragma clang diagnostic ignored "-Wnullability"
16+
17+
#pragma push_macro("_Nullable_result")
18+
#if !__has_feature(nullability_nullable_result)
19+
#undef _Nullable_result
20+
#define _Nullable_result _Nullable
21+
#endif
22+
23+
__attribute__((objc_subclassing_restricted))
24+
@interface Foo : Base
25+
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
26+
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
27+
- (void)bar0Cb:(void (^)(Int *))cb __attribute__((swift_name("bar0(cb:)")));
28+
- (void)bar1Cb:(void (^)(Int *))cb __attribute__((swift_name("bar1(cb:)")));
29+
- (void)bar2Cb:(void (^)(Int *, Int *, NSString *))cb __attribute__((swift_name("bar2(cb:)")));
30+
- (void)bar3Cb:(void (^)(Int *, Int *, Double *))cb __attribute__((swift_name("bar3(cb:)")));
31+
@end
32+
33+
@interface Foo (Extensions)
34+
- (void)bar4Cb:(void (^)(Int *, NSString *))cb __attribute__((swift_name("bar4(cb:)")));
35+
@end
36+
37+
#pragma pop_macro("_Nullable_result")
38+
#pragma clang diagnostic pop
39+
NS_ASSUME_NONNULL_END
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
class Foo {
2+
fun bar0(cb: (result: Int) -> Unit) = Unit
3+
fun bar1(cb: (result: @ParameterName("a") Int) -> Unit) = Unit
4+
fun bar2(cb: (a: Int, b: Int, c: String) -> Unit) = Unit
5+
fun bar3(cb: (int: Int, int_: Int, double: Double) -> Unit) = Unit
6+
}
7+
8+
fun Foo.bar4(cb: (int: Int, message: String) -> Unit) = Unit

0 commit comments

Comments
 (0)