[FIR] Implement ObjCName checkers

This commit is contained in:
Rick Clephas
2022-08-19 20:34:17 +02:00
committed by teamcity
parent 115db22c12
commit ff1adf596d
9 changed files with 316 additions and 34 deletions
@@ -47,5 +47,20 @@ object NATIVE_DIAGNOSTICS_LIST : DiagnosticList("FirNativeErrors") {
parameter<Collection<FirRegularClassSymbol>>("containingClasses")
}
val INVALID_OBJC_REFINEMENT_TARGETS by error<KtElement>()
val INAPPLICABLE_OBJC_NAME by error<KtElement>()
val INVALID_OBJC_NAME by error<KtElement>()
val INVALID_OBJC_NAME_CHARS by error<KtElement> {
parameter<String>("characters")
}
val INVALID_OBJC_NAME_FIRST_CHAR by error<KtElement> {
parameter<String>("characters")
}
val INCOMPATIBLE_OBJC_NAME_OVERRIDE by error<KtElement> {
parameter<FirBasedSymbol<*>>("declaration")
parameter<Collection<FirRegularClassSymbol>>("containingClasses")
}
val INAPPLICABLE_EXACT_OBJC_NAME by error<KtElement>()
val MISSING_EXACT_OBJC_NAME by error<KtElement>()
val NON_LITERAL_OBJC_NAME_ARG by error<KtElement>()
}
}
@@ -36,6 +36,14 @@ object FirNativeErrors {
val REDUNDANT_SWIFT_REFINEMENT by error0<KtElement>()
val INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE by error2<KtElement, FirBasedSymbol<*>, Collection<FirRegularClassSymbol>>()
val INVALID_OBJC_REFINEMENT_TARGETS by error0<KtElement>()
val INAPPLICABLE_OBJC_NAME by error0<KtElement>()
val INVALID_OBJC_NAME by error0<KtElement>()
val INVALID_OBJC_NAME_CHARS by error1<KtElement, String>()
val INVALID_OBJC_NAME_FIRST_CHAR by error1<KtElement, String>()
val INCOMPATIBLE_OBJC_NAME_OVERRIDE by error2<KtElement, FirBasedSymbol<*>, Collection<FirRegularClassSymbol>>()
val INAPPLICABLE_EXACT_OBJC_NAME by error0<KtElement>()
val MISSING_EXACT_OBJC_NAME by error0<KtElement>()
val NON_LITERAL_OBJC_NAME_ARG by error0<KtElement>()
init {
RootDiagnosticRendererFactory.registerFactory(FirNativeErrorsDefaultMessages)
@@ -11,17 +11,25 @@ import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.SYMBOL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.SYMBOLS
import org.jetbrains.kotlin.fir.analysis.diagnostics.checkMissingMessages
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INAPPLICABLE_EXACT_OBJC_NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INAPPLICABLE_OBJC_NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INAPPLICABLE_SHARED_IMMUTABLE_PROPERTY
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INAPPLICABLE_SHARED_IMMUTABLE_TOP_LEVEL
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INAPPLICABLE_THREAD_LOCAL
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INAPPLICABLE_THREAD_LOCAL_TOP_LEVEL
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INCOMPATIBLE_OBJC_NAME_OVERRIDE
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INCOMPATIBLE_OBJC_REFINEMENT_OVERRIDE
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INCOMPATIBLE_THROWS_INHERITED
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INCOMPATIBLE_THROWS_OVERRIDE
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INVALID_CHARACTERS_NATIVE
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INVALID_OBJC_NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INVALID_OBJC_NAME_CHARS
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INVALID_OBJC_NAME_FIRST_CHAR
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INVALID_OBJC_REFINEMENT_TARGETS
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.MISSING_EXACT_OBJC_NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.MISSING_EXCEPTION_IN_THROWS_ON_SUSPEND
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.REDUNDANT_SWIFT_REFINEMENT
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.NON_LITERAL_OBJC_NAME_ARG
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.THROWS_LIST_EMPTY
object FirNativeErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
@@ -55,6 +63,14 @@ object FirNativeErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
INVALID_OBJC_REFINEMENT_TARGETS,
"Refines annotations are only applicable to annotations with targets FUNCTION and/or PROPERTY"
)
map.put(INAPPLICABLE_OBJC_NAME, "@ObjCName is not applicable on overrides")
map.put(INVALID_OBJC_NAME, "@ObjCName should have a name and/or swiftName")
map.put(INVALID_OBJC_NAME_CHARS, "@ObjCName contains illegal characters: {0}", TO_STRING)
map.put(INVALID_OBJC_NAME_FIRST_CHAR, "@ObjCName contains illegal first characters: {0}", TO_STRING)
map.put(INCOMPATIBLE_OBJC_NAME_OVERRIDE, "Member \"{0}\" inherits inconsistent @ObjCName from {1}", SYMBOL, SYMBOLS)
map.put(INAPPLICABLE_EXACT_OBJC_NAME, "Exact @ObjCName is only applicable to classes, objects and interfaces")
map.put(MISSING_EXACT_OBJC_NAME, "Exact @ObjCName is required to have an ObjC name")
map.put(NON_LITERAL_OBJC_NAME_ARG, "@ObjCName accepts only literal string and boolean values")
map.checkMissingMessages(FirNativeErrors)
}
@@ -0,0 +1,129 @@
/*
* Copyright 2010-2022 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.fir.analysis.native.checkers
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INAPPLICABLE_EXACT_OBJC_NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INAPPLICABLE_OBJC_NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INVALID_OBJC_NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INVALID_OBJC_NAME_CHARS
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INVALID_OBJC_NAME_FIRST_CHAR
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.MISSING_EXACT_OBJC_NAME
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.NON_LITERAL_OBJC_NAME_ARG
import org.jetbrains.kotlin.fir.analysis.native.checkers.FirNativeObjCNameOverridesChecker.check
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isOverride
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
object FirNativeObjCNameChecker : FirBasicDeclarationChecker() {
private val objCNameClassId = ClassId.topLevel(FqName("kotlin.native.ObjCName"))
private val nameName = Name.identifier("name")
private val swiftNameName = Name.identifier("swiftName")
private val exactName = Name.identifier("exact")
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
checkDeclaration(declaration, context, reporter)
if (declaration is FirCallableDeclaration && (declaration is FirSimpleFunction || declaration is FirProperty)) {
val containingClass = context.containingDeclarations.lastOrNull() as? FirClass
if (containingClass != null) {
val firTypeScope = containingClass.unsubstitutedScope(context)
check(firTypeScope, declaration.symbol, declaration, context, reporter)
}
}
}
private fun checkDeclaration(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration is FirValueParameter) return // those are checked with the FirFunction
val objCNames = declaration.symbol.getObjCNames().filterNotNull()
if (objCNames.isEmpty()) return
if (declaration is FirCallableDeclaration && declaration.isOverride) {
for (objCName in objCNames) {
reporter.reportOn(objCName.annotation.source, INAPPLICABLE_OBJC_NAME, context)
}
}
objCNames.forEach { checkObjCName(it, declaration, context, reporter) }
}
// We only allow valid ObjC identifiers (even for Swift names)
private val validFirstChars = ('A'..'Z').toSet() + ('a'..'z').toSet() + '_'
private val validChars = validFirstChars + ('0'..'9').toSet()
private fun checkObjCName(objCName: ObjCName, declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
val annotationSource = objCName.annotation.source
for ((_, argument) in objCName.annotation.argumentMapping.mapping) {
if (argument is FirConstExpression<*>) continue
reporter.reportOn(argument.source, NON_LITERAL_OBJC_NAME_ARG, context)
}
if (objCName.name == null && objCName.swiftName == null) {
reporter.reportOn(annotationSource, INVALID_OBJC_NAME, context)
}
val invalidNameFirstChar = objCName.name?.firstOrNull()?.takeUnless(validFirstChars::contains)
val invalidSwiftNameFirstChar = objCName.swiftName?.firstOrNull()?.takeUnless(validFirstChars::contains)
val invalidFirstChars = setOfNotNull(invalidNameFirstChar, invalidSwiftNameFirstChar)
if (invalidFirstChars.isNotEmpty()) {
reporter.reportOn(annotationSource, INVALID_OBJC_NAME_FIRST_CHAR, invalidFirstChars.joinToString(""), context)
}
val invalidNameChars = objCName.name?.toSet()?.subtract(validChars) ?: emptySet()
val invalidSwiftNameChars = objCName.swiftName?.toSet()?.subtract(validChars) ?: emptySet()
val invalidChars = invalidNameChars + invalidSwiftNameChars
if (invalidChars.isNotEmpty()) {
reporter.reportOn(annotationSource, INVALID_OBJC_NAME_CHARS, invalidFirstChars.joinToString(""), context)
}
if (objCName.exact && (declaration !is FirClass || declaration.classKind == ClassKind.ENUM_ENTRY)) {
reporter.reportOn(annotationSource, INAPPLICABLE_EXACT_OBJC_NAME, context)
}
if (objCName.exact && objCName.name == null) {
reporter.reportOn(annotationSource, MISSING_EXACT_OBJC_NAME, context)
}
}
class ObjCName(
val annotation: FirAnnotation
) {
val name: String? = annotation.getStringArgument(nameName)?.takeIf { it.isNotBlank() }
val swiftName: String? = annotation.getStringArgument(swiftNameName)?.takeIf { it.isNotBlank() }
val exact: Boolean = annotation.getBooleanArgument(exactName) ?: false
override fun equals(other: Any?): Boolean =
other is ObjCName && name == other.name && swiftName == other.swiftName && exact == other.exact
override fun hashCode(): Int {
var result = name.hashCode()
result = 31 * result + swiftName.hashCode()
result = 31 * result + exact.hashCode()
return result
}
}
private fun FirAnnotationContainer.getObjCName(): ObjCName? =
getAnnotationByClassId(objCNameClassId)?.let(::ObjCName)
private fun FirBasedSymbol<*>.getObjCName(): ObjCName? =
getAnnotationByClassId(objCNameClassId)?.let(::ObjCName)
fun FirBasedSymbol<*>.getObjCNames(): List<ObjCName?> = when (this) {
is FirFunctionSymbol<*> -> buildList {
add((this@getObjCNames as FirBasedSymbol<*>).getObjCName())
add(resolvedReceiverTypeRef?.getObjCName())
valueParameterSymbols.forEach { add(it.getObjCName()) }
}
else -> listOf(getObjCName())
}
}
@@ -0,0 +1,90 @@
/*
* Copyright 2010-2022 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.fir.analysis.native.checkers
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INCOMPATIBLE_OBJC_NAME_OVERRIDE
import org.jetbrains.kotlin.fir.analysis.native.checkers.FirNativeObjCNameChecker.getObjCNames
import org.jetbrains.kotlin.fir.containingClass
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.isIntersectionOverride
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
object FirNativeObjCNameOverridesChecker : FirClassChecker() {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
// We just need to check intersection overrides, all other declarations are checked by FirNativeObjCNameChecker
val firTypeScope = declaration.unsubstitutedScope(context)
firTypeScope.processAllFunctions { symbol ->
if (!symbol.isIntersectionOverride) return@processAllFunctions
check(firTypeScope, symbol, declaration, context, reporter)
}
firTypeScope.processAllProperties { symbol ->
if (!symbol.isIntersectionOverride) return@processAllProperties
check(firTypeScope, symbol, declaration, context, reporter)
}
}
fun check(
firTypeScope: FirTypeScope,
memberSymbol: FirCallableSymbol<*>,
declarationToReport: FirDeclaration,
context: CheckerContext,
reporter: DiagnosticReporter
) {
val overriddenSymbols = firTypeScope.getDirectOverriddenSymbols(memberSymbol)
if (overriddenSymbols.isEmpty()) return
val objCNames = overriddenSymbols.map { it.getFirstBaseSymbol(firTypeScope).getObjCNames() }
if (!objCNames.allNamesEquals()) {
val containingDeclarations = overriddenSymbols.mapNotNull { it.containingClass()?.toFirRegularClassSymbol(context.session) }
reporter.reportOn(
declarationToReport.source,
INCOMPATIBLE_OBJC_NAME_OVERRIDE,
declarationToReport.symbol,
containingDeclarations,
context
)
}
}
private fun FirTypeScope.getDirectOverriddenSymbols(memberSymbol: FirCallableSymbol<*>): List<FirCallableSymbol<*>> {
return when (memberSymbol) {
is FirNamedFunctionSymbol -> {
processFunctionsByName(memberSymbol.name) {}
getDirectOverriddenFunctions(memberSymbol)
}
is FirPropertySymbol -> {
processPropertiesByName(memberSymbol.name) {}
getDirectOverriddenProperties(memberSymbol)
}
else -> error("unexpected member kind $memberSymbol")
}
}
private fun FirCallableSymbol<*>.getFirstBaseSymbol(firTypeScope: FirTypeScope): FirCallableSymbol<*> {
val overriddenMemberSymbols = firTypeScope.getDirectOverriddenSymbols(this)
return if (overriddenMemberSymbols.isEmpty()) this else overriddenMemberSymbols.first().getFirstBaseSymbol(firTypeScope)
}
private fun List<List<FirNativeObjCNameChecker.ObjCName?>>.allNamesEquals(): Boolean {
val first = this[0]
for (i in 1 until size) {
if (first != this[i]) return false
}
return true
}
}
@@ -13,7 +13,8 @@ object NativeDeclarationCheckers : DeclarationCheckers() {
FirNativeThrowsChecker,
FirNativeSharedImmutableChecker,
FirNativeThreadLocalChecker,
FirNativeIdentifierChecker
FirNativeIdentifierChecker,
FirNativeObjCNameChecker
)
override val callableDeclarationCheckers: Set<FirCallableDeclarationChecker>
@@ -23,7 +24,8 @@ object NativeDeclarationCheckers : DeclarationCheckers() {
override val classCheckers: Set<FirClassChecker>
get() = setOf(
FirNativeObjCRefinementOverridesChecker
FirNativeObjCRefinementOverridesChecker,
FirNativeObjCNameOverridesChecker
)
override val regularClassCheckers: Set<FirRegularClassChecker>
+39 -30
View File
@@ -24,30 +24,39 @@ open class KotlinClass {
@ObjCName("ObjCSubClass", "SwiftSubClass")
class KotlinSubClass: KotlinClass() {
@ObjCName("objCProperty")
<!INAPPLICABLE_OBJC_NAME!>@ObjCName("objCProperty")<!>
override var kotlinProperty: Int = 1
@ObjCName(swiftName = "swiftFunction")
override fun @receiver:ObjCName("objCReceiver") Int.kotlinFunction(
@ObjCName("objCParam") kotlinParam: Int
<!INAPPLICABLE_OBJC_NAME!>@ObjCName(swiftName = "swiftFunction")<!>
override fun <!INAPPLICABLE_OBJC_NAME!>@receiver:ObjCName("objCReceiver")<!> Int.kotlinFunction(
<!INAPPLICABLE_OBJC_NAME!>@ObjCName("objCParam")<!> kotlinParam: Int
): Int = this + kotlinParam * 2
}
@ObjCName()
val invalidObjCName: Int = 0
<!INVALID_OBJC_NAME!>@ObjCName()<!>
val invalidObjCNameA: Int = 0
@ObjCName("validName", "invalid.name")
<!INVALID_OBJC_NAME!>@ObjCName("", "")<!>
val invalidObjCNameB: Int = 0
@ObjCName("validName", "")
val validBlankObjCNameA: Int = 0
@ObjCName("", "validName")
val validBlankObjCNameB: Int = 0
<!INVALID_OBJC_NAME_CHARS!>@ObjCName("validName", "invalid.name")<!>
val invalidCharactersObjCNameA: Int = 0
@ObjCName("invalid.name", "validName")
<!INVALID_OBJC_NAME_CHARS!>@ObjCName("invalid.name", "validName")<!>
val invalidCharactersObjCNameB: Int = 0
@ObjCName("validName1", "1validName")
<!INVALID_OBJC_NAME_FIRST_CHAR!>@ObjCName("validName1", "1validName")<!>
val invalidFirstCharacterObjCNameA: Int = 0
@ObjCName("1validName", "validName1")
<!INVALID_OBJC_NAME_FIRST_CHAR!>@ObjCName("1validName", "validName1")<!>
val invalidFirstCharacterObjCNameB: Int = 0
@ObjCName(swiftName = "SwiftMissingExactName", exact = true)
<!MISSING_EXACT_OBJC_NAME!>@ObjCName(swiftName = "SwiftMissingExactName", exact = true)<!>
class MissingExactName
interface KotlinInterfaceA {
@@ -118,32 +127,32 @@ interface KotlinInterfaceB {
class KotlinOverrideClass: KotlinInterfaceA, KotlinInterfaceB {
override var kotlinPropertyA: Int = 0
override var kotlinPropertyB: Int = 0
override var kotlinPropertyC: Int = 0
override var kotlinPropertyD: Int = 0
override var kotlinPropertyE: Int = 0
<!INCOMPATIBLE_OBJC_NAME_OVERRIDE!>override var kotlinPropertyB: Int = 0<!>
<!INCOMPATIBLE_OBJC_NAME_OVERRIDE!>override var kotlinPropertyC: Int = 0<!>
<!INCOMPATIBLE_OBJC_NAME_OVERRIDE!>override var kotlinPropertyD: Int = 0<!>
<!INCOMPATIBLE_OBJC_NAME_OVERRIDE!>override var kotlinPropertyE: Int = 0<!>
override var kotlinPropertyF: Int = 0
override fun Int.kotlinFunctionA(kotlinParam: Int): Int = this + kotlinParam
override fun Int.kotlinFunctionB(kotlinParam: Int): Int = this + kotlinParam
override fun Int.kotlinFunctionC(kotlinParam: Int): Int = this + kotlinParam
override fun Int.kotlinFunctionD(kotlinParam: Int): Int = this + kotlinParam
override fun Int.kotlinFunctionE(kotlinParam: Int): Int = this + kotlinParam
<!INCOMPATIBLE_OBJC_NAME_OVERRIDE!>override fun Int.kotlinFunctionB(kotlinParam: Int): Int = this + kotlinParam<!>
<!INCOMPATIBLE_OBJC_NAME_OVERRIDE!>override fun Int.kotlinFunctionC(kotlinParam: Int): Int = this + kotlinParam<!>
<!INCOMPATIBLE_OBJC_NAME_OVERRIDE!>override fun Int.kotlinFunctionD(kotlinParam: Int): Int = this + kotlinParam<!>
<!INCOMPATIBLE_OBJC_NAME_OVERRIDE!>override fun Int.kotlinFunctionE(kotlinParam: Int): Int = this + kotlinParam<!>
}
@ObjCName("ObjCExactChecks", exact = true)
class ExactChecks {
@ObjCName("objCProperty", exact = true)
<!INAPPLICABLE_EXACT_OBJC_NAME!>@ObjCName("objCProperty", exact = true)<!>
var property: Int = 0
@ObjCName("objCFunction", exact = true)
fun @receiver:ObjCName("objCReceiver", exact = true) Int.function(
@ObjCName("objCParam", exact = true) param: Int
<!INAPPLICABLE_EXACT_OBJC_NAME!>@ObjCName("objCFunction", exact = true)<!>
fun <!INAPPLICABLE_EXACT_OBJC_NAME!>@receiver:ObjCName("objCReceiver", exact = true)<!> Int.function(
<!INAPPLICABLE_EXACT_OBJC_NAME!>@ObjCName("objCParam", exact = true)<!> param: Int
): Int = this * param
}
@ObjCName("ObjCEnumExactChecks", exact = true)
enum class EnumExactChecks {
@ObjCName("objCEntryOne", exact = true)
<!INAPPLICABLE_EXACT_OBJC_NAME!>@ObjCName("objCEntryOne", exact = true)<!>
ENTRY_ONE,
@ObjCName("objCEntryTwo")
ENTRY_TWO
@@ -159,7 +168,7 @@ interface I {
fun foo()
}
open class Derived : Base(), I
<!INCOMPATIBLE_OBJC_NAME_OVERRIDE!>open class Derived : Base(), I<!>
open class Derived2 : Derived() {
override fun foo() {}
@@ -168,11 +177,11 @@ open class Derived2 : Derived() {
private const val exact = false
private const val objcName = "nonLiteralArgsObjC"
@ObjCName(
objcName,
"nonLiteralArgs" + "Swift",
exact
)
<!INVALID_OBJC_NAME!>@ObjCName(
<!NON_LITERAL_OBJC_NAME_ARG!>objcName<!>,
<!NON_LITERAL_OBJC_NAME_ARG!>"nonLiteralArgs" + "Swift"<!>,
<!NON_LITERAL_OBJC_NAME_ARG!>exact<!>
)<!>
val nonLiteralArgs: Int = 0
@ObjCName("invalidArgsObjC", <!ARGUMENT_TYPE_MISMATCH!>false<!>, <!ARGUMENT_TYPE_MISMATCH!>"not a boolean"<!>)
+10 -1
View File
@@ -33,7 +33,16 @@ class KotlinSubClass: KotlinClass() {
}
<!INVALID_OBJC_NAME!>@ObjCName()<!>
val invalidObjCName: Int = 0
val invalidObjCNameA: Int = 0
<!INVALID_OBJC_NAME!>@ObjCName("", "")<!>
val invalidObjCNameB: Int = 0
@ObjCName("validName", "")
val validBlankObjCNameA: Int = 0
@ObjCName("", "validName")
val validBlankObjCNameB: Int = 0
<!INVALID_OBJC_NAME_CHARS!>@ObjCName("validName", "invalid.name")<!>
val invalidCharactersObjCNameA: Int = 0
+5 -1
View File
@@ -6,9 +6,12 @@ private const val exact: kotlin.Boolean = false
@kotlin.native.ObjCName(name = "invalid.name", swiftName = "validName") public val invalidCharactersObjCNameB: kotlin.Int = 0
@kotlin.native.ObjCName(name = "validName1", swiftName = "1validName") public val invalidFirstCharacterObjCNameA: kotlin.Int = 0
@kotlin.native.ObjCName(name = "1validName", swiftName = "validName1") public val invalidFirstCharacterObjCNameB: kotlin.Int = 0
@kotlin.native.ObjCName public val invalidObjCName: kotlin.Int = 0
@kotlin.native.ObjCName public val invalidObjCNameA: kotlin.Int = 0
@kotlin.native.ObjCName(name = "", swiftName = "") public val invalidObjCNameB: kotlin.Int = 0
@kotlin.native.ObjCName(exact = false, name = "nonLiteralArgsObjC", swiftName = "nonLiteralArgsSwift") public val nonLiteralArgs: kotlin.Int = 0
private const val objcName: kotlin.String = "nonLiteralArgsObjC"
@kotlin.native.ObjCName(name = "validName", swiftName = "") public val validBlankObjCNameA: kotlin.Int = 0
@kotlin.native.ObjCName(name = "", swiftName = "validName") public val validBlankObjCNameB: kotlin.Int = 0
public open class Base {
public constructor Base()
@@ -161,3 +164,4 @@ package kotlin {
}
}
}