Skip to content

@property backtick predicate is narrower than Kotlin's identifier grammar #247

Description

formatAsKdocPropertyReference decides whether an @property name needs backticks using a regex narrower than Kotlin's identifier grammar, so some names get backticked that do not need it.

generator/src/main/kotlin/norm/generator/TypeRepository.kt:665,676-677

private val PLAIN_KOTLIN_IDENTIFIER = Regex("[A-Za-z_][A-Za-z0-9_]*")

private fun String.formatAsKdocPropertyReference(): String =
  if (PLAIN_KOTLIN_IDENTIFIER.matches(this)) this else "`$this`"

Kotlin identifiers accept Unicode letters, so a column named café is a perfectly plain identifier. The regex rejects it, and the KDoc tag comes out as @property `café` while the property declaration KotlinPoet emits right below it is plain café. The two disagree for no reason.

Cosmetic only. The tag still binds — KDocName.getNameTextRange strips a surrounding backtick pair — so this is inconsistent output, not broken output. No existing golden is affected; every scenario's column names are ASCII.

Introduced alongside the @property backticking added in #243 (needed because a space-containing name previously emitted two bare tokens and corrupted the tag). The backticking itself is correct; only the "does this need it" test is too strict.

Fix is to widen the predicate to Kotlin's actual identifier rule — Character.isJavaIdentifierStart/isJavaIdentifierPart is close enough, or a regex over Unicode letter categories.

Related, and deliberately not fixed

A name containing a literal backtick breaks the tag: a`b becomes `a`b`, which lexes as KDOC_MARKDOWN_LINK(a) plus a stray b`. This is unreachable in practice — such a name is not a valid Kotlin identifier, so the declaration KotlinPoet emits is already invalid and the file would not compile regardless of the KDoc. Worth noting only so nobody "fixes" the KDoc path in isolation and concludes the case is handled; if backtick-containing column names are ever to be supported, the declaration is the thing that needs addressing first.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions