From e06a60bda5b773c501f53bf8ccf4b81b5336ef57 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Wed, 2 Jun 2021 10:18:32 +0300 Subject: [PATCH] [Native] Clean up nested comment when exporting kdoc to objc header (#4410) * [Native] Clean up nested comment when exporting kdoc to objc header * [kdoc-export] Add test witg nested comment block * Remove redundant assert Co-authored-by: Vladimir Ivanov --- .../backend/konan/objcexport/StubRenderer.kt | 9 ++++- .../tests/objcexport/expectedLazy.h | 38 +++++++++++++++++++ .../tests/objcexport/kdocExport.kt | 37 +++++++++++++++++- 3 files changed, 81 insertions(+), 3 deletions(-) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/StubRenderer.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/StubRenderer.kt index c7f58306363..3145892d491 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/StubRenderer.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/StubRenderer.kt @@ -18,9 +18,14 @@ object StubRenderer { val kDoc = if (shouldExportKDoc) { descriptor?.extractKDocString()?.let { if (it.isNotEmpty()) { // sometimes `findDoc` return empty string; is it a bug? + // Nested comment is allowed inside of preformatted ``` block in kdoc but not in ObjC + val kdocClean = + if (it.startsWith("/**") && it.endsWith("*/")) + "/**${it.substring(3, it.length - 2).replace("*/", "**").replace("/*", "**")}*/" + else it +"" // Probably makes the output more readable. - it.lines().forEach { it.trim().let { - if (it[0] == '*') +" $it" + kdocClean.lines().forEach { it.trim().let { + if (it.isNotEmpty() && it[0] == '*') +" $it" else +"$it" } } diff --git a/kotlin-native/backend.native/tests/objcexport/expectedLazy.h b/kotlin-native/backend.native/tests/objcexport/expectedLazy.h index 2b95f5ecb41..9f28582e86a 100644 --- a/kotlin-native/backend.native/tests/objcexport/expectedLazy.h +++ b/kotlin-native/backend.native/tests/objcexport/expectedLazy.h @@ -548,6 +548,44 @@ __attribute__((swift_name("KDocExport"))) @property int32_t yxxyz __attribute__((swift_name("yxxyz"))); @end; +__attribute__((swift_name("SomeClassWithProperty"))) +@interface KtSomeClassWithProperty : KtBase +- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer)); ++ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead"))); + +/** + * Returns dispatcher that executes coroutines immediately when it is already in the right context + * (e.g. current looper is the same as this handler's looper) without an additional [re-dispatch][CoroutineDispatcher.dispatch]. + * + * Immediate dispatcher is safe from stack overflows and in case of nested invocations forms event-loop similar to [Dispatchers.Unconfined]. + * The event loop is an advanced topic and its implications can be found in [Dispatchers.Unconfined] documentation. + * The formed event-loop is shared with [Unconfined] and other immediate dispatchers, potentially overlapping tasks between them. + * + * Example of usage: + * ``` + * suspend fun updateUiElement(val text: String) { + * ** + * * If it is known that updateUiElement can be invoked both from the Main thread and from other threads, + * * `immediate` dispatcher is used as a performance optimization to avoid unnecessary dispatch. + * * + * * In that case, when `updateUiElement` is invoked from the Main thread, `uiElement.text` will be + * * invoked immediately without any dispatching, otherwise, the `Dispatchers.Main` dispatch cycle will be triggered. + * ** + * withContext(Dispatchers.Main.immediate) { + * uiElement.text = text + * } + * // Do context-independent logic such as logging + * } + * ``` + * + * Method may throw [UnsupportedOperationException] if immediate dispatching is not supported by current dispatcher, + * please refer to specific dispatcher documentation. + * + * [Dispatchers.Main] supports immediate execution for Android, JavaFx and Swing platforms. + */ +@property (readonly) KtSomeClassWithProperty *heavyFormattedKDocFoo __attribute__((swift_name("heavyFormattedKDocFoo"))); +@end; + __attribute__((objc_subclassing_restricted)) __attribute__((swift_name("KdocExportKt"))) @interface KtKdocExportKt : KtBase diff --git a/kotlin-native/backend.native/tests/objcexport/kdocExport.kt b/kotlin-native/backend.native/tests/objcexport/kdocExport.kt index d8b1888caaf..eb117ac2aef 100644 --- a/kotlin-native/backend.native/tests/objcexport/kdocExport.kt +++ b/kotlin-native/backend.native/tests/objcexport/kdocExport.kt @@ -42,4 +42,39 @@ class KDocExport() { * Check for additional comment (note) below */ @Throws(IllegalArgumentException::class) -fun whatever(a:String) = a \ No newline at end of file +fun whatever(a:String) = a + +public abstract class SomeClassWithProperty +{ + /** + * Returns dispatcher that executes coroutines immediately when it is already in the right context + * (e.g. current looper is the same as this handler's looper) without an additional [re-dispatch][CoroutineDispatcher.dispatch]. + * + * Immediate dispatcher is safe from stack overflows and in case of nested invocations forms event-loop similar to [Dispatchers.Unconfined]. + * The event loop is an advanced topic and its implications can be found in [Dispatchers.Unconfined] documentation. + * The formed event-loop is shared with [Unconfined] and other immediate dispatchers, potentially overlapping tasks between them. + * + * Example of usage: + * ``` + * suspend fun updateUiElement(val text: String) { + * /* + * * If it is known that updateUiElement can be invoked both from the Main thread and from other threads, + * * `immediate` dispatcher is used as a performance optimization to avoid unnecessary dispatch. + * * + * * In that case, when `updateUiElement` is invoked from the Main thread, `uiElement.text` will be + * * invoked immediately without any dispatching, otherwise, the `Dispatchers.Main` dispatch cycle will be triggered. + * */ + * withContext(Dispatchers.Main.immediate) { + * uiElement.text = text + * } + * // Do context-independent logic such as logging + * } + * ``` + * + * Method may throw [UnsupportedOperationException] if immediate dispatching is not supported by current dispatcher, + * please refer to specific dispatcher documentation. + * + * [Dispatchers.Main] supports immediate execution for Android, JavaFx and Swing platforms. + */ + public abstract val heavyFormattedKDocFoo: SomeClassWithProperty +} \ No newline at end of file