From b406722e20d40b0ba89c82b3da5fe29ca319466b Mon Sep 17 00:00:00 2001 From: Rick Clephas Date: Sat, 3 Sep 2022 18:56:00 +0200 Subject: [PATCH] [K/N] Prohibit empty ObjCNames --- .../diagnostics/FirNativeDiagnosticsList.kt | 1 + .../diagnostics/native/FirNativeErrors.kt | 1 + .../native/FirNativeErrorsDefaultMessages.kt | 2 ++ .../checkers/FirNativeObjCNameChecker.kt | 8 ++++-- .../diagnostics/nativeTests/objCName.fir.kt | 26 ++++++++++++++----- .../diagnostics/nativeTests/objCName.kt | 26 ++++++++++++++----- .../diagnostics/nativeTests/objCName.txt | 13 ++++++---- .../konan/objcexport/ObjCExportNamer.kt | 1 - .../diagnostics/DefaultErrorMessagesNative.kt | 1 + .../resolve/konan/diagnostics/ErrorsNative.kt | 2 ++ .../diagnostics/NativeObjCNameChecker.kt | 7 +++-- 11 files changed, 64 insertions(+), 24 deletions(-) diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirNativeDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirNativeDiagnosticsList.kt index 1a2ddb96068..4001b2b0adf 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirNativeDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirNativeDiagnosticsList.kt @@ -55,6 +55,7 @@ object NATIVE_DIAGNOSTICS_LIST : DiagnosticList("FirNativeErrors") { val INVALID_OBJC_NAME_FIRST_CHAR by error { parameter("characters") } + val EMPTY_OBJC_NAME by error() val INCOMPATIBLE_OBJC_NAME_OVERRIDE by error { parameter>("declaration") parameter>("containingClasses") diff --git a/compiler/fir/checkers/checkers.native/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrors.kt b/compiler/fir/checkers/checkers.native/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrors.kt index 0250f82993c..c1b598caf93 100644 --- a/compiler/fir/checkers/checkers.native/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrors.kt +++ b/compiler/fir/checkers/checkers.native/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrors.kt @@ -40,6 +40,7 @@ object FirNativeErrors { val INVALID_OBJC_NAME by error0() val INVALID_OBJC_NAME_CHARS by error1() val INVALID_OBJC_NAME_FIRST_CHAR by error1() + val EMPTY_OBJC_NAME by error0() val INCOMPATIBLE_OBJC_NAME_OVERRIDE by error2, Collection>() val INAPPLICABLE_EXACT_OBJC_NAME by error0() val MISSING_EXACT_OBJC_NAME by error0() diff --git a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrorsDefaultMessages.kt b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrorsDefaultMessages.kt index d3684cbf58e..99484378fb0 100644 --- a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/diagnostics/native/FirNativeErrorsDefaultMessages.kt @@ -11,6 +11,7 @@ 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.EMPTY_OBJC_NAME 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 @@ -65,6 +66,7 @@ object FirNativeErrorsDefaultMessages : BaseDiagnosticRendererFactory() { ) 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(EMPTY_OBJC_NAME, "Empty @ObjCName names aren't supported") 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) diff --git a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCNameChecker.kt b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCNameChecker.kt index df280d1173f..c54ef356275 100644 --- a/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCNameChecker.kt +++ b/compiler/fir/checkers/checkers.native/src/org/jetbrains/kotlin/fir/analysis/native/checkers/FirNativeObjCNameChecker.kt @@ -12,6 +12,7 @@ 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.EMPTY_OBJC_NAME 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 @@ -79,6 +80,9 @@ object FirNativeObjCNameChecker : FirBasicDeclarationChecker() { if (invalidFirstChars.isNotEmpty()) { reporter.reportOn(annotationSource, INVALID_OBJC_NAME_FIRST_CHAR, invalidFirstChars.joinToString(""), context) } + if (objCName.name?.isEmpty() == true || objCName.swiftName?.isEmpty() == true) { + reporter.reportOn(annotationSource, EMPTY_OBJC_NAME, context) + } val invalidNameChars = objCName.name?.toSet()?.subtract(validChars) ?: emptySet() val invalidSwiftNameChars = objCName.swiftName?.toSet()?.subtract(validChars) ?: emptySet() val invalidChars = invalidNameChars + invalidSwiftNameChars @@ -96,8 +100,8 @@ object FirNativeObjCNameChecker : FirBasicDeclarationChecker() { class ObjCName( val annotation: FirAnnotation ) { - val name: String? = annotation.getStringArgument(nameName)?.takeIf { it.isNotBlank() } - val swiftName: String? = annotation.getStringArgument(swiftNameName)?.takeIf { it.isNotBlank() } + val name: String? = annotation.getStringArgument(nameName) + val swiftName: String? = annotation.getStringArgument(swiftNameName) val exact: Boolean = annotation.getBooleanArgument(exactName) ?: false override fun equals(other: Any?): Boolean = diff --git a/compiler/testData/diagnostics/nativeTests/objCName.fir.kt b/compiler/testData/diagnostics/nativeTests/objCName.fir.kt index a51f1c1f787..77c604d9513 100644 --- a/compiler/testData/diagnostics/nativeTests/objCName.fir.kt +++ b/compiler/testData/diagnostics/nativeTests/objCName.fir.kt @@ -33,16 +33,22 @@ class KotlinSubClass: KotlinClass() { } @ObjCName() -val invalidObjCNameA: Int = 0 +val invalidObjCName: Int = 0 -@ObjCName("", "") -val invalidObjCNameB: Int = 0 +@ObjCName("", "") +val emptyObjCNameA: Int = 0 -@ObjCName("validName", "") -val validBlankObjCNameA: Int = 0 +@ObjCName("validName", "") +val emptyObjCNameB: Int = 0 -@ObjCName("", "validName") -val validBlankObjCNameB: Int = 0 +@ObjCName("", "validName") +val emptyObjCNameC: Int = 0 + +@ObjCName("validName") +val validObjCNameA: Int = 0 + +@ObjCName(swiftName = "validName") +val validObjCNameB: Int = 0 @ObjCName("validName", "invalid.name") val invalidCharactersObjCNameA: Int = 0 @@ -56,6 +62,12 @@ val invalidFirstCharacterObjCNameA: Int = 0 @ObjCName("1validName", "validName1") val invalidFirstCharacterObjCNameB: Int = 0 +@ObjCName("validName", " ") +val blankObjCNameA: Int = 0 + +@ObjCName(" ", "validName") +val blankObjCNameB: Int = 0 + @ObjCName(swiftName = "SwiftMissingExactName", exact = true) class MissingExactName diff --git a/compiler/testData/diagnostics/nativeTests/objCName.kt b/compiler/testData/diagnostics/nativeTests/objCName.kt index ac3d308954a..ee544b11503 100644 --- a/compiler/testData/diagnostics/nativeTests/objCName.kt +++ b/compiler/testData/diagnostics/nativeTests/objCName.kt @@ -33,16 +33,22 @@ class KotlinSubClass: KotlinClass() { } @ObjCName() -val invalidObjCNameA: Int = 0 +val invalidObjCName: Int = 0 -@ObjCName("", "") -val invalidObjCNameB: Int = 0 +@ObjCName("", "") +val emptyObjCNameA: Int = 0 -@ObjCName("validName", "") -val validBlankObjCNameA: Int = 0 +@ObjCName("validName", "") +val emptyObjCNameB: Int = 0 -@ObjCName("", "validName") -val validBlankObjCNameB: Int = 0 +@ObjCName("", "validName") +val emptyObjCNameC: Int = 0 + +@ObjCName("validName") +val validObjCNameA: Int = 0 + +@ObjCName(swiftName = "validName") +val validObjCNameB: Int = 0 @ObjCName("validName", "invalid.name") val invalidCharactersObjCNameA: Int = 0 @@ -56,6 +62,12 @@ val invalidFirstCharacterObjCNameA: Int = 0 @ObjCName("1validName", "validName1") val invalidFirstCharacterObjCNameB: Int = 0 +@ObjCName("validName", " ") +val blankObjCNameA: Int = 0 + +@ObjCName(" ", "validName") +val blankObjCNameB: Int = 0 + @ObjCName(swiftName = "SwiftMissingExactName", exact = true) class MissingExactName diff --git a/compiler/testData/diagnostics/nativeTests/objCName.txt b/compiler/testData/diagnostics/nativeTests/objCName.txt index b669f60b883..2bdd29d8b96 100644 --- a/compiler/testData/diagnostics/nativeTests/objCName.txt +++ b/compiler/testData/diagnostics/nativeTests/objCName.txt @@ -1,17 +1,21 @@ package +@kotlin.native.ObjCName(name = "validName", swiftName = " ") public val blankObjCNameA: kotlin.Int = 0 +@kotlin.native.ObjCName(name = " ", swiftName = "validName") public val blankObjCNameB: kotlin.Int = 0 +@kotlin.native.ObjCName(name = "", swiftName = "") public val emptyObjCNameA: kotlin.Int = 0 +@kotlin.native.ObjCName(name = "validName", swiftName = "") public val emptyObjCNameB: kotlin.Int = 0 +@kotlin.native.ObjCName(name = "", swiftName = "validName") public val emptyObjCNameC: kotlin.Int = 0 private const val exact: kotlin.Boolean = false @kotlin.native.ObjCName(exact = "not a boolean", name = "invalidArgsObjC", swiftName = false) public val invalidArgs: kotlin.Int = 0 @kotlin.native.ObjCName(name = "validName", swiftName = "invalid.name") public val invalidCharactersObjCNameA: kotlin.Int = 0 @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 invalidObjCNameA: kotlin.Int = 0 -@kotlin.native.ObjCName(name = "", swiftName = "") public val invalidObjCNameB: kotlin.Int = 0 +@kotlin.native.ObjCName public val invalidObjCName: 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 +@kotlin.native.ObjCName(name = "validName") public val validObjCNameA: kotlin.Int = 0 +@kotlin.native.ObjCName(swiftName = "validName") public val validObjCNameB: kotlin.Int = 0 public open class Base { public constructor Base() @@ -164,4 +168,3 @@ package kotlin { } } } - diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportNamer.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportNamer.kt index b0f4c9116e3..0dcf49fcba6 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportNamer.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportNamer.kt @@ -30,7 +30,6 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.propertyIfAccessor import org.jetbrains.kotlin.resolve.source.PsiSourceFile import org.jetbrains.kotlin.utils.addToStdlib.cast -import org.jetbrains.kotlin.utils.addToStdlib.safeAs internal interface ObjCExportNameTranslator { fun getFileClassName(file: KtFile): ObjCExportNamer.ClassOrProtocolName diff --git a/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/DefaultErrorMessagesNative.kt b/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/DefaultErrorMessagesNative.kt index 1d438d7f3a8..dbc2d5a7b8d 100644 --- a/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/DefaultErrorMessagesNative.kt +++ b/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/DefaultErrorMessagesNative.kt @@ -46,6 +46,7 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy { ErrorsNative.INVALID_OBJC_NAME_FIRST_CHAR, "@ObjCName contains illegal first characters: {0}", CommonRenderers.STRING ) + put(ErrorsNative.EMPTY_OBJC_NAME, "Empty @ObjCName names aren't supported") put( ErrorsNative.INCOMPATIBLE_OBJC_NAME_OVERRIDE, "Member \"{0}\" inherits inconsistent @ObjCName from {1}", Renderers.NAME, diff --git a/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/ErrorsNative.kt b/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/ErrorsNative.kt index 595ad92e4f5..460ec90e13c 100644 --- a/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/ErrorsNative.kt +++ b/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/ErrorsNative.kt @@ -45,6 +45,8 @@ object ErrorsNative { @JvmField val INVALID_OBJC_NAME_FIRST_CHAR = DiagnosticFactory1.create(Severity.ERROR) @JvmField + val EMPTY_OBJC_NAME = DiagnosticFactory0.create(Severity.ERROR) + @JvmField val INCOMPATIBLE_OBJC_NAME_OVERRIDE = DiagnosticFactory2.create>(Severity.ERROR) @JvmField val INAPPLICABLE_EXACT_OBJC_NAME = DiagnosticFactory0.create(Severity.ERROR) diff --git a/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/NativeObjCNameChecker.kt b/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/NativeObjCNameChecker.kt index 504e91fc3c8..2b677c4dbe9 100644 --- a/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/NativeObjCNameChecker.kt +++ b/native/frontend/src/org/jetbrains/kotlin/resolve/konan/diagnostics/NativeObjCNameChecker.kt @@ -64,6 +64,9 @@ object NativeObjCNameChecker : DeclarationChecker { if (objCName.name == null && objCName.swiftName == null) { context.trace.report(ErrorsNative.INVALID_OBJC_NAME.on(reportLocation)) } + if (objCName.name?.isEmpty() == true || objCName.swiftName?.isEmpty() == true) { + context.trace.report(ErrorsNative.EMPTY_OBJC_NAME.on(reportLocation)) + } val invalidNameFirstChar = objCName.name?.firstOrNull()?.takeUnless(validFirstChars::contains) val invalidSwiftNameFirstChar = objCName.swiftName?.firstOrNull()?.takeUnless(validFirstChars::contains) val invalidFirstChars = setOfNotNull(invalidNameFirstChar, invalidSwiftNameFirstChar) @@ -87,8 +90,8 @@ object NativeObjCNameChecker : DeclarationChecker { class ObjCName( val annotation: AnnotationDescriptor ) { - val name: String? = annotation.argumentValue("name")?.value?.safeAs()?.takeIf { it.isNotBlank() } - val swiftName: String? = annotation.argumentValue("swiftName")?.value?.safeAs()?.takeIf { it.isNotBlank() } + val name: String? = annotation.argumentValue("name")?.value?.safeAs() + val swiftName: String? = annotation.argumentValue("swiftName")?.value?.safeAs() val exact: Boolean = annotation.argumentValue("exact")?.value?.safeAs() ?: false override fun equals(other: Any?): Boolean =