[K/N] Prohibit empty ObjCNames
This commit is contained in:
committed by
SvyatoslavScherbina
parent
0290f09ac2
commit
b406722e20
+1
@@ -55,6 +55,7 @@ object NATIVE_DIAGNOSTICS_LIST : DiagnosticList("FirNativeErrors") {
|
||||
val INVALID_OBJC_NAME_FIRST_CHAR by error<KtElement> {
|
||||
parameter<String>("characters")
|
||||
}
|
||||
val EMPTY_OBJC_NAME by error<KtElement>()
|
||||
val INCOMPATIBLE_OBJC_NAME_OVERRIDE by error<KtElement> {
|
||||
parameter<FirBasedSymbol<*>>("declaration")
|
||||
parameter<Collection<FirRegularClassSymbol>>("containingClasses")
|
||||
|
||||
+1
@@ -40,6 +40,7 @@ object FirNativeErrors {
|
||||
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 EMPTY_OBJC_NAME by error0<KtElement>()
|
||||
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>()
|
||||
|
||||
+2
@@ -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)
|
||||
|
||||
+6
-2
@@ -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 =
|
||||
|
||||
+19
-7
@@ -33,16 +33,22 @@ class KotlinSubClass: KotlinClass() {
|
||||
}
|
||||
|
||||
<!INVALID_OBJC_NAME!>@ObjCName()<!>
|
||||
val invalidObjCNameA: Int = 0
|
||||
val invalidObjCName: Int = 0
|
||||
|
||||
<!INVALID_OBJC_NAME!>@ObjCName("", "")<!>
|
||||
val invalidObjCNameB: Int = 0
|
||||
<!EMPTY_OBJC_NAME!>@ObjCName("", "")<!>
|
||||
val emptyObjCNameA: Int = 0
|
||||
|
||||
@ObjCName("validName", "")
|
||||
val validBlankObjCNameA: Int = 0
|
||||
<!EMPTY_OBJC_NAME!>@ObjCName("validName", "")<!>
|
||||
val emptyObjCNameB: Int = 0
|
||||
|
||||
@ObjCName("", "validName")
|
||||
val validBlankObjCNameB: Int = 0
|
||||
<!EMPTY_OBJC_NAME!>@ObjCName("", "validName")<!>
|
||||
val emptyObjCNameC: Int = 0
|
||||
|
||||
@ObjCName("validName")
|
||||
val validObjCNameA: Int = 0
|
||||
|
||||
@ObjCName(swiftName = "validName")
|
||||
val validObjCNameB: Int = 0
|
||||
|
||||
<!INVALID_OBJC_NAME_CHARS!>@ObjCName("validName", "invalid.name")<!>
|
||||
val invalidCharactersObjCNameA: Int = 0
|
||||
@@ -56,6 +62,12 @@ val invalidFirstCharacterObjCNameA: Int = 0
|
||||
<!INVALID_OBJC_NAME_FIRST_CHAR!>@ObjCName("1validName", "validName1")<!>
|
||||
val invalidFirstCharacterObjCNameB: Int = 0
|
||||
|
||||
<!INVALID_OBJC_NAME_CHARS, INVALID_OBJC_NAME_FIRST_CHAR!>@ObjCName("validName", " ")<!>
|
||||
val blankObjCNameA: Int = 0
|
||||
|
||||
<!INVALID_OBJC_NAME_CHARS, INVALID_OBJC_NAME_FIRST_CHAR!>@ObjCName(" ", "validName")<!>
|
||||
val blankObjCNameB: Int = 0
|
||||
|
||||
<!MISSING_EXACT_OBJC_NAME!>@ObjCName(swiftName = "SwiftMissingExactName", exact = true)<!>
|
||||
class MissingExactName
|
||||
|
||||
|
||||
+19
-7
@@ -33,16 +33,22 @@ class KotlinSubClass: KotlinClass() {
|
||||
}
|
||||
|
||||
<!INVALID_OBJC_NAME!>@ObjCName()<!>
|
||||
val invalidObjCNameA: Int = 0
|
||||
val invalidObjCName: Int = 0
|
||||
|
||||
<!INVALID_OBJC_NAME!>@ObjCName("", "")<!>
|
||||
val invalidObjCNameB: Int = 0
|
||||
<!EMPTY_OBJC_NAME!>@ObjCName("", "")<!>
|
||||
val emptyObjCNameA: Int = 0
|
||||
|
||||
@ObjCName("validName", "")
|
||||
val validBlankObjCNameA: Int = 0
|
||||
<!EMPTY_OBJC_NAME!>@ObjCName("validName", "")<!>
|
||||
val emptyObjCNameB: Int = 0
|
||||
|
||||
@ObjCName("", "validName")
|
||||
val validBlankObjCNameB: Int = 0
|
||||
<!EMPTY_OBJC_NAME!>@ObjCName("", "validName")<!>
|
||||
val emptyObjCNameC: Int = 0
|
||||
|
||||
@ObjCName("validName")
|
||||
val validObjCNameA: Int = 0
|
||||
|
||||
@ObjCName(swiftName = "validName")
|
||||
val validObjCNameB: Int = 0
|
||||
|
||||
<!INVALID_OBJC_NAME_CHARS!>@ObjCName("validName", "invalid.name")<!>
|
||||
val invalidCharactersObjCNameA: Int = 0
|
||||
@@ -56,6 +62,12 @@ val invalidFirstCharacterObjCNameA: Int = 0
|
||||
<!INVALID_OBJC_NAME_FIRST_CHAR!>@ObjCName("1validName", "validName1")<!>
|
||||
val invalidFirstCharacterObjCNameB: Int = 0
|
||||
|
||||
<!INVALID_OBJC_NAME_CHARS, INVALID_OBJC_NAME_FIRST_CHAR!>@ObjCName("validName", " ")<!>
|
||||
val blankObjCNameA: Int = 0
|
||||
|
||||
<!INVALID_OBJC_NAME_CHARS, INVALID_OBJC_NAME_FIRST_CHAR!>@ObjCName(" ", "validName")<!>
|
||||
val blankObjCNameB: Int = 0
|
||||
|
||||
<!MISSING_EXACT_OBJC_NAME!>@ObjCName(swiftName = "SwiftMissingExactName", exact = true)<!>
|
||||
class MissingExactName
|
||||
|
||||
|
||||
+8
-5
@@ -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 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-1
@@ -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
|
||||
|
||||
+1
@@ -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,
|
||||
|
||||
@@ -45,6 +45,8 @@ object ErrorsNative {
|
||||
@JvmField
|
||||
val INVALID_OBJC_NAME_FIRST_CHAR = DiagnosticFactory1.create<KtElement, String>(Severity.ERROR)
|
||||
@JvmField
|
||||
val EMPTY_OBJC_NAME = DiagnosticFactory0.create<KtElement>(Severity.ERROR)
|
||||
@JvmField
|
||||
val INCOMPATIBLE_OBJC_NAME_OVERRIDE = DiagnosticFactory2.create<KtElement, DeclarationDescriptor, Collection<DeclarationDescriptor>>(Severity.ERROR)
|
||||
@JvmField
|
||||
val INAPPLICABLE_EXACT_OBJC_NAME = DiagnosticFactory0.create<KtElement>(Severity.ERROR)
|
||||
|
||||
+5
-2
@@ -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<String>()?.takeIf { it.isNotBlank() }
|
||||
val swiftName: String? = annotation.argumentValue("swiftName")?.value?.safeAs<String>()?.takeIf { it.isNotBlank() }
|
||||
val name: String? = annotation.argumentValue("name")?.value?.safeAs<String>()
|
||||
val swiftName: String? = annotation.argumentValue("swiftName")?.value?.safeAs<String>()
|
||||
val exact: Boolean = annotation.argumentValue("exact")?.value?.safeAs<Boolean>() ?: false
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
|
||||
Reference in New Issue
Block a user