[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
|
package org.jetbrains.kotlin.objcexport
|
||||||
|
|
||||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
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.KtClassKind
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
|
import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithModality
|
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.backend.konan.objcexport.*
|
||||||
import org.jetbrains.kotlin.builtins.StandardNames
|
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getDefaultSuperClassOrProtocolName
|
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getDefaultSuperClassOrProtocolName
|
||||||
import org.jetbrains.kotlin.objcexport.analysisApiUtils.getSuperClassSymbolNotAny
|
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 attributes = if (enumKind || final) listOf(OBJC_SUBCLASSING_RESTRICTED) else emptyList()
|
||||||
|
|
||||||
val name = getObjCClassOrProtocolName()
|
val name = getObjCClassOrProtocolName()
|
||||||
val comment: ObjCComment? = annotationsList.toComment()
|
val comment: ObjCComment? = annotationsList.translateToObjCComment()
|
||||||
val origin: ObjCExportStubOrigin = getObjCStubOrigin()
|
val origin: ObjCExportStubOrigin = getObjCStubOrigin()
|
||||||
val superProtocols: List<String> = superProtocols()
|
val superProtocols: List<String> = superProtocols()
|
||||||
val members: List<ObjCExportStub> = members().flatMap { it.translateToObjCExportStubs() }
|
val members: List<ObjCExportStub> = members().flatMap { it.translateToObjCExportStubs() }
|
||||||
@@ -59,16 +56,3 @@ private fun abbreviate(name: String): String {
|
|||||||
|
|
||||||
return normalizedName
|
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 com.intellij.openapi.util.io.FileUtil
|
||||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
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.annotationInfos
|
||||||
import org.jetbrains.kotlin.analysis.api.annotations.annotations
|
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.*
|
import org.jetbrains.kotlin.analysis.api.symbols.*
|
||||||
import org.jetbrains.kotlin.analysis.api.types.KtType
|
import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||||
import org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi
|
import org.jetbrains.kotlin.backend.konan.InternalKotlinNativeApi
|
||||||
import org.jetbrains.kotlin.backend.konan.KonanFqNames
|
import org.jetbrains.kotlin.backend.konan.KonanFqNames
|
||||||
import org.jetbrains.kotlin.backend.konan.objcexport.*
|
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.Name
|
||||||
import org.jetbrains.kotlin.name.NameUtils
|
import org.jetbrains.kotlin.name.NameUtils
|
||||||
import org.jetbrains.kotlin.objcexport.Predefined.anyMethodSelectors
|
import org.jetbrains.kotlin.objcexport.Predefined.anyMethodSelectors
|
||||||
@@ -62,7 +56,7 @@ internal fun KtFunctionLikeSymbol.buildObjCMethod(
|
|||||||
val swiftName = getSwiftName(bridge)
|
val swiftName = getSwiftName(bridge)
|
||||||
val attributes = mutableListOf<String>()
|
val attributes = mutableListOf<String>()
|
||||||
val returnBridge = bridge.returnBridge
|
val returnBridge = bridge.returnBridge
|
||||||
val comment = buildComment(this, bridge, parameters)
|
val comment = this.translateToObjCComment(bridge, parameters)
|
||||||
|
|
||||||
attributes += getSwiftPrivateAttribute() ?: swiftNameAttribute(swiftName)
|
attributes += getSwiftPrivateAttribute() ?: swiftNameAttribute(swiftName)
|
||||||
|
|
||||||
@@ -109,105 +103,6 @@ internal fun String.toValidObjCSwiftIdentifier(): String {
|
|||||||
.let { if (it == "_") "__" else it }
|
.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? =
|
internal fun KtCallableSymbol.getSwiftPrivateAttribute(): String? =
|
||||||
if (isRefinedInSwift()) "swift_private" else null
|
if (isRefinedInSwift()) "swift_private" else null
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -28,8 +28,7 @@ fun KtClassOrObjectSymbol.translateToObjCProtocol(): ObjCProtocol? {
|
|||||||
|
|
||||||
val members = members().flatMap { it.translateToObjCExportStubs() }
|
val members = members().flatMap { it.translateToObjCExportStubs() }
|
||||||
|
|
||||||
// TODO: Resolve comment
|
val comment: ObjCComment? = annotationsList.translateToObjCComment()
|
||||||
val comment: ObjCComment? = null
|
|
||||||
|
|
||||||
return ObjCProtocolImpl(
|
return ObjCProtocolImpl(
|
||||||
name = name.objCName,
|
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"))
|
doTest(headersTestDataDir.resolve("classWithMustBeDocumentedAnnotation"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test - interfaceWithMustBeDocumentedAnnotation`() {
|
||||||
|
doTest(headersTestDataDir.resolve("interfaceWithMustBeDocumentedAnnotation"))
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test - functionWithMustBeDocumentedAnnotation`() {
|
fun `test - functionWithMustBeDocumentedAnnotation`() {
|
||||||
doTest(headersTestDataDir.resolve("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