[ObjCExport] Analysis Api: Implement initial support for exporting 'MustBeDocumented' annotations
^KT-64869 Fixed
This commit is contained in:
committed by
Space Team
parent
cdcb3e4dcd
commit
80d9933543
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.objcexport.analysisApiUtils
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationWithArgumentsInfo
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationsList
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.annotationClassIds
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtAnnotatedSymbol
|
||||
import org.jetbrains.kotlin.backend.konan.KonanFqNames
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
|
||||
/**
|
||||
* Returns the list of annotations which shall be documented for ObjC export.
|
||||
* Usually annotations that are marked with `@MustBeDocumented` are important and shall be retained for users.
|
||||
* However, some annotations e.g. [kotlin.native.ObjCName], whilst annotated with `@MustBeDocumented` shall not be exported for ObjC
|
||||
* documentation.
|
||||
*/
|
||||
context(KtAnalysisSession)
|
||||
internal fun KtAnnotatedSymbol.getObjCDocumentedAnnotations(): List<KtAnnotationApplicationWithArgumentsInfo> {
|
||||
return annotationsList.getObjCDocumentedAnnotations()
|
||||
}
|
||||
|
||||
/**
|
||||
* See [getObjCDocumentedAnnotations]
|
||||
*/
|
||||
context(KtAnalysisSession)
|
||||
internal fun KtAnnotationsList.getObjCDocumentedAnnotations(): List<KtAnnotationApplicationWithArgumentsInfo> {
|
||||
return annotations
|
||||
.filter { annotation ->
|
||||
val annotationClassId = annotation.classId ?: return@filter false
|
||||
if (annotationClassId.asSingleFqName() in mustBeDocumentedAnnotationsStopList) return@filter false
|
||||
val annotationClassSymbol = getClassOrObjectSymbolByClassId(annotationClassId) ?: return@filter false
|
||||
StandardClassIds.Annotations.MustBeDocumented in annotationClassSymbol.annotationClassIds
|
||||
}
|
||||
}
|
||||
|
||||
private val mustBeDocumentedAnnotationsStopList = setOf(
|
||||
StandardNames.FqNames.deprecated,
|
||||
KonanFqNames.objCName,
|
||||
KonanFqNames.shouldRefineInSwift
|
||||
)
|
||||
+1
-17
@@ -1,13 +1,10 @@
|
||||
package org.jetbrains.kotlin.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationsList
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtClassKind
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithModality
|
||||
import org.jetbrains.kotlin.backend.konan.KonanFqNames
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.*
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getDefaultSuperClassOrProtocolName
|
||||
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getSuperClassSymbolNotAny
|
||||
@@ -27,7 +24,7 @@ fun KtClassOrObjectSymbol.translateToObjCClass(): ObjCClass? {
|
||||
val attributes = if (enumKind || final) listOf(OBJC_SUBCLASSING_RESTRICTED) else emptyList()
|
||||
|
||||
val name = getObjCClassOrProtocolName()
|
||||
val comment: ObjCComment? = annotationsList.toComment()
|
||||
val comment: ObjCComment? = annotationsList.translateToObjCComment()
|
||||
val origin: ObjCExportStubOrigin = getObjCStubOrigin()
|
||||
val superProtocols: List<String> = superProtocols()
|
||||
val members: List<ObjCExportStub> = members().flatMap { it.translateToObjCExportStubs() }
|
||||
@@ -59,16 +56,3 @@ private fun abbreviate(name: String): String {
|
||||
|
||||
return normalizedName
|
||||
}
|
||||
|
||||
/**
|
||||
* Not implemented
|
||||
*/
|
||||
private fun KtAnnotationsList.toComment(): ObjCComment? {
|
||||
return null
|
||||
}
|
||||
|
||||
private val mustBeDocumentedAnnotationsStopList = setOf(
|
||||
StandardNames.FqNames.deprecated,
|
||||
KonanFqNames.objCName,
|
||||
KonanFqNames.shouldRefineInSwift
|
||||
)
|
||||
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationWithArgumentsInfo
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationsList
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionLikeSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithVisibility
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.MethodBridge
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCComment
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCParameter
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.plus
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getObjCDocumentedAnnotations
|
||||
|
||||
|
||||
context(KtAnalysisSession)
|
||||
internal fun KtAnnotationsList.translateToObjCComment(): ObjCComment? {
|
||||
val annotations = getObjCDocumentedAnnotations()
|
||||
.mapNotNull { annotation -> renderAnnotation(annotation) }
|
||||
|
||||
if (annotations.isEmpty()) return null
|
||||
return ObjCComment(listOf("@note annotations") + annotations.map { " $it" })
|
||||
}
|
||||
|
||||
/**
|
||||
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.buildComment]
|
||||
*/
|
||||
context(KtAnalysisSession)
|
||||
internal fun KtFunctionLikeSymbol.translateToObjCComment(bridge: MethodBridge, parameters: List<ObjCParameter>): ObjCComment? {
|
||||
val isSuspend: Boolean = if (this is KtFunctionSymbol) this.isSuspend else false
|
||||
|
||||
val throwsComments = if (isSuspend || bridge.returnsError) {
|
||||
val effectiveThrows = getEffectiveThrows(this).toSet()
|
||||
when {
|
||||
effectiveThrows.contains(StandardClassIds.Throwable) -> {
|
||||
listOf("@note This method converts all Kotlin exceptions to errors.")
|
||||
}
|
||||
|
||||
effectiveThrows.isNotEmpty() -> {
|
||||
listOf(
|
||||
buildString {
|
||||
append("@note This method converts instances of ")
|
||||
effectiveThrows.joinTo(this) { it.relativeClassName.asString() }
|
||||
append(" to errors.")
|
||||
},
|
||||
"Other uncaught Kotlin exceptions are fatal."
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
// Shouldn't happen though.
|
||||
listOf("@warning All uncaught Kotlin exceptions are fatal.")
|
||||
}
|
||||
}
|
||||
} else emptyList()
|
||||
|
||||
val visibilityComments = buildObjCVisibilityComment("method")
|
||||
|
||||
val paramComments = valueParameters.mapNotNull { parameterSymbol ->
|
||||
parameters.find { parameter -> parameter.origin?.name == parameterSymbol.name }
|
||||
?.renderedObjCDocumentedParamAnnotations(parameterSymbol)
|
||||
}
|
||||
val annotationsComments = annotationsList.translateToObjCComment()
|
||||
return annotationsComments + paramComments + throwsComments + visibilityComments
|
||||
}
|
||||
|
||||
/**
|
||||
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.mustBeDocumentedParamAttributeList]
|
||||
*/
|
||||
context(KtAnalysisSession)
|
||||
private fun ObjCParameter.renderedObjCDocumentedParamAnnotations(parameterSymbol: KtValueParameterSymbol): String? {
|
||||
val renderedAnnotationsString = parameterSymbol.getObjCDocumentedAnnotations()
|
||||
.mapNotNull { annotation -> renderAnnotation(annotation) }
|
||||
.ifEmpty { return null }
|
||||
.joinToString(" ")
|
||||
return "@param $name annotations $renderedAnnotationsString"
|
||||
}
|
||||
|
||||
|
||||
private fun renderAnnotation(annotation: KtAnnotationApplicationWithArgumentsInfo): String? {
|
||||
return renderAnnotation(annotation.classId ?: return null, annotation.arguments)
|
||||
}
|
||||
|
||||
private fun renderAnnotation(clazz: ClassId, arguments: List<KtNamedAnnotationValue>): String {
|
||||
return buildString {
|
||||
append(clazz.asSingleFqName())
|
||||
if (arguments.isNotEmpty()) {
|
||||
append('(')
|
||||
arguments.joinTo(this)
|
||||
append(')')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Not implemented [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.getEffectiveThrows]
|
||||
*/
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
private fun getEffectiveThrows(method: KtFunctionLikeSymbol): Sequence<ClassId> {
|
||||
return emptySequence()
|
||||
}
|
||||
|
||||
/**
|
||||
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.visibilityComments]
|
||||
*/
|
||||
private fun KtSymbol.buildObjCVisibilityComment(kind: String): ObjCComment? {
|
||||
return when ((this as? KtSymbolWithVisibility)?.visibility ?: return null) {
|
||||
Visibilities.Protected -> ObjCComment("@note This $kind has protected visibility in Kotlin source and is intended only for use by subclasses.")
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
+1
-106
@@ -4,18 +4,12 @@ package org.jetbrains.kotlin.objcexport
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationWithArgumentsInfo
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.annotationInfos
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.annotations
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.*
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||
import org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi
|
||||
import org.jetbrains.kotlin.backend.konan.KonanFqNames
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.*
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.NameUtils
|
||||
import org.jetbrains.kotlin.objcexport.Predefined.anyMethodSelectors
|
||||
@@ -62,7 +56,7 @@ internal fun KtFunctionLikeSymbol.buildObjCMethod(
|
||||
val swiftName = getSwiftName(bridge)
|
||||
val attributes = mutableListOf<String>()
|
||||
val returnBridge = bridge.returnBridge
|
||||
val comment = buildComment(this, bridge, parameters)
|
||||
val comment = this.translateToObjCComment(bridge, parameters)
|
||||
|
||||
attributes += getSwiftPrivateAttribute() ?: swiftNameAttribute(swiftName)
|
||||
|
||||
@@ -109,105 +103,6 @@ internal fun String.toValidObjCSwiftIdentifier(): String {
|
||||
.let { if (it == "_") "__" else it }
|
||||
}
|
||||
|
||||
private val throwableClassId = ClassId.topLevel(StandardNames.FqNames.throwable)
|
||||
|
||||
/**
|
||||
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.buildComment]
|
||||
*/
|
||||
private fun buildComment(method: KtFunctionLikeSymbol, bridge: MethodBridge, parameters: List<ObjCParameter>): ObjCComment? {
|
||||
|
||||
val visibility: Visibility
|
||||
val isSuspend: Boolean
|
||||
|
||||
if (method is KtFunctionSymbol) {
|
||||
isSuspend = method.isSuspend
|
||||
visibility = method.visibility
|
||||
} else if (method is KtConstructorSymbol) {
|
||||
isSuspend = false
|
||||
visibility = Visibilities.Public //check constructor
|
||||
} else {
|
||||
TODO("Unsupported type for comment building: $method")
|
||||
}
|
||||
|
||||
val throwsComments = if (isSuspend || bridge.returnsError) {
|
||||
val effectiveThrows = getEffectiveThrows(method).toSet()
|
||||
when {
|
||||
effectiveThrows.contains(throwableClassId) -> {
|
||||
listOf("@note This method converts all Kotlin exceptions to errors.")
|
||||
}
|
||||
|
||||
effectiveThrows.isNotEmpty() -> {
|
||||
listOf(
|
||||
buildString {
|
||||
append("@note This method converts instances of ")
|
||||
effectiveThrows.joinTo(this) { it.relativeClassName.asString() }
|
||||
append(" to errors.")
|
||||
},
|
||||
"Other uncaught Kotlin exceptions are fatal."
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
// Shouldn't happen though.
|
||||
listOf("@warning All uncaught Kotlin exceptions are fatal.")
|
||||
}
|
||||
}
|
||||
} else emptyList()
|
||||
|
||||
val visibilityComments = visibilityComments(visibility, "method")
|
||||
|
||||
val paramComments = method.valueParameters.flatMap { parameterDescriptor ->
|
||||
parameters.find { parameter -> parameter.origin?.name == parameterDescriptor.name }?.let { parameter ->
|
||||
mustBeDocumentedParamAttributeList(parameter, descriptor = parameterDescriptor)
|
||||
} ?: emptyList()
|
||||
}
|
||||
val annotationsComments = mustBeDocumentedAttributeList(method.annotations)
|
||||
val commentLines = annotationsComments + paramComments + throwsComments + visibilityComments
|
||||
return if (commentLines.isNotEmpty()) ObjCComment(commentLines) else null
|
||||
}
|
||||
|
||||
/**
|
||||
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.mustBeDocumentedParamAttributeList]
|
||||
*/
|
||||
private fun mustBeDocumentedParamAttributeList(parameter: ObjCParameter, descriptor: KtValueParameterSymbol): List<String> {
|
||||
|
||||
descriptor.annotationsList.annotations
|
||||
|
||||
val mbdAnnotations = mustBeDocumentedAnnotations(descriptor.annotations).joinToString(" ")
|
||||
return if (mbdAnnotations.isNotEmpty()) listOf("@param ${parameter.name} annotations $mbdAnnotations") else emptyList()
|
||||
}
|
||||
|
||||
/**
|
||||
* Not implemented [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.mustBeDocumentedAnnotations]
|
||||
*/
|
||||
private fun mustBeDocumentedAnnotations(annotations: List<KtAnnotationApplicationWithArgumentsInfo>): List<String> {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
private fun mustBeDocumentedAttributeList(annotations: List<KtAnnotationApplicationWithArgumentsInfo>): List<String> {
|
||||
val mustBeDocumentedAnnotations = mustBeDocumentedAnnotations(annotations)
|
||||
return if (mustBeDocumentedAnnotations.isNotEmpty()) {
|
||||
listOf("@note annotations") + mustBeDocumentedAnnotations.map { " $it" }
|
||||
} else emptyList()
|
||||
}
|
||||
|
||||
/**
|
||||
* [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.visibilityComments]
|
||||
*/
|
||||
private fun visibilityComments(visibility: Visibility, kind: String): List<String> {
|
||||
return when (visibility) {
|
||||
Visibilities.Protected -> listOf("@note This $kind has protected visibility in Kotlin source and is intended only for use by subclasses.")
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Not implemented [org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportTranslatorImpl.getEffectiveThrows]
|
||||
*/
|
||||
private fun getEffectiveThrows(method: KtFunctionLikeSymbol): Sequence<ClassId> {
|
||||
return emptySequence()
|
||||
}
|
||||
|
||||
internal fun KtCallableSymbol.getSwiftPrivateAttribute(): String? =
|
||||
if (isRefinedInSwift()) "swift_private" else null
|
||||
|
||||
|
||||
+1
-2
@@ -28,8 +28,7 @@ fun KtClassOrObjectSymbol.translateToObjCProtocol(): ObjCProtocol? {
|
||||
|
||||
val members = members().flatMap { it.translateToObjCExportStubs() }
|
||||
|
||||
// TODO: Resolve comment
|
||||
val comment: ObjCComment? = null
|
||||
val comment: ObjCComment? = annotationsList.translateToObjCComment()
|
||||
|
||||
return ObjCProtocolImpl(
|
||||
name = name.objCName,
|
||||
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.objcexport.tests
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.analyze
|
||||
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getObjCDocumentedAnnotations
|
||||
import org.jetbrains.kotlin.objcexport.testUtils.InlineSourceCodeAnalysis
|
||||
import org.jetbrains.kotlin.objcexport.testUtils.getClassOrFail
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.fail
|
||||
|
||||
class GetObjCDocumentedAnnotationsTest(
|
||||
private val inlineSourceCodeAnalysis: InlineSourceCodeAnalysis,
|
||||
) {
|
||||
@Test
|
||||
fun `test - no annotation present`() {
|
||||
val file = inlineSourceCodeAnalysis.createKtFile("class Foo")
|
||||
analyze(file) {
|
||||
val foo = file.getClassOrFail("Foo")
|
||||
val objCDocumentedAnnotations = foo.getObjCDocumentedAnnotations()
|
||||
if (objCDocumentedAnnotations.isNotEmpty())
|
||||
fail("Expected no 'ObjC Documented Annotation present, Found. $objCDocumentedAnnotations")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - simple Important annotation`() {
|
||||
val file = inlineSourceCodeAnalysis.createKtFile(
|
||||
"""
|
||||
@MustBeDocumented
|
||||
annotation class ImportantAnnotation
|
||||
annotation class OtherAnnotation
|
||||
|
||||
@ImportantAnnotation @OtherAnnotation
|
||||
class Foo
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
analyze(file) {
|
||||
val foo = file.getClassOrFail("Foo")
|
||||
val objCDocumentedAnnotations = foo.getObjCDocumentedAnnotations()
|
||||
if (objCDocumentedAnnotations.size != 1)
|
||||
fail("Expected single documented annotation. Found: $objCDocumentedAnnotations")
|
||||
|
||||
val objCDocumentedAnnotation = objCDocumentedAnnotations.single()
|
||||
assertEquals("ImportantAnnotation", objCDocumentedAnnotation.classId?.shortClassName?.asString())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - special ObjC annotations are not documented for export`() {
|
||||
val file = inlineSourceCodeAnalysis.createKtFile(
|
||||
"""
|
||||
@MustBeDocumented
|
||||
annotation class ImportantAnnotation
|
||||
|
||||
@kotlin.native.ObjCName("ObjCFoo")
|
||||
@kotlin.native.ShouldRefineInSwift
|
||||
@Deprecated("Deprecations shall also not be shown")
|
||||
@ImportantAnnotation
|
||||
class Foo
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
analyze(file) {
|
||||
val foo = file.getClassOrFail("Foo")
|
||||
val objCDocumentedAnnotations = foo.getObjCDocumentedAnnotations()
|
||||
if (objCDocumentedAnnotations.size != 1)
|
||||
fail("Expected single documented annotation. Found: $objCDocumentedAnnotations")
|
||||
|
||||
val objCDocumentedAnnotation = objCDocumentedAnnotations.single()
|
||||
assertEquals("ImportantAnnotation", objCDocumentedAnnotation.classId?.shortClassName?.asString())
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan.objcexport
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi
|
||||
|
||||
@InternalKotlinNativeApi
|
||||
operator fun ObjCComment?.plus(other: ObjCComment?): ObjCComment? {
|
||||
val lines = this?.contentLines.orEmpty() + other?.contentLines.orEmpty()
|
||||
if (lines.isEmpty()) return null
|
||||
return ObjCComment(lines)
|
||||
}
|
||||
|
||||
@InternalKotlinNativeApi
|
||||
operator fun ObjCComment?.plus(lines: Iterable<String>): ObjCComment? {
|
||||
val newLines = this?.contentLines.orEmpty() + lines
|
||||
if (newLines.isEmpty()) return null
|
||||
return ObjCComment(newLines)
|
||||
}
|
||||
+5
@@ -120,6 +120,11 @@ class ObjCExportHeaderGeneratorTest(val generator: HeaderGenerator) {
|
||||
doTest(headersTestDataDir.resolve("classWithMustBeDocumentedAnnotation"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - interfaceWithMustBeDocumentedAnnotation`() {
|
||||
doTest(headersTestDataDir.resolve("interfaceWithMustBeDocumentedAnnotation"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - functionWithMustBeDocumentedAnnotation`() {
|
||||
doTest(headersTestDataDir.resolve("functionWithMustBeDocumentedAnnotation"))
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSError.h>
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <Foundation/NSSet.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunknown-warning-option"
|
||||
#pragma clang diagnostic ignored "-Wincompatible-property-type"
|
||||
#pragma clang diagnostic ignored "-Wnullability"
|
||||
|
||||
#pragma push_macro("_Nullable_result")
|
||||
#if !__has_feature(nullability_nullable_result)
|
||||
#undef _Nullable_result
|
||||
#define _Nullable_result _Nullable
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @note annotations
|
||||
* ImportantAnnotation
|
||||
* AnotherImportantAnnotation
|
||||
*/
|
||||
@protocol Foo
|
||||
@required
|
||||
@end
|
||||
|
||||
#pragma pop_macro("_Nullable_result")
|
||||
#pragma clang diagnostic pop
|
||||
NS_ASSUME_NONNULL_END
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
@kotlin.annotation.MustBeDocumented
|
||||
annotation class ImportantAnnotation
|
||||
|
||||
@kotlin.annotation.MustBeDocumented
|
||||
annotation class AnotherImportantAnnotation
|
||||
|
||||
@ImportantAnnotation @AnotherImportantAnnotation
|
||||
interface Foo
|
||||
Reference in New Issue
Block a user