diff options
author | Egor Andreevich <egor@squareup.com> | 2024-01-12 13:06:36 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-12 19:06:36 +0100 |
commit | 848e6cf743e8327e28f64aa04cffa311a4d6eaa8 (patch) | |
tree | 675cabfc888c6fe35d050b0f0939fee07df3a630 | |
parent | 291a300f00d85d4f5f49bd653d91579f02cde897 (diff) | |
download | kotlinpoet-848e6cf743e8327e28f64aa04cffa311a4d6eaa8.tar.gz |
Add NameAllocator API to control keyword pre-allocation (#1803)
* Add NameAllocator API to control keyword pre-allocation
* Update API dump
* preAllocate to preallocate
* Clarify documentation
4 files changed, 42 insertions, 3 deletions
diff --git a/kotlinpoet/api/kotlinpoet.api b/kotlinpoet/api/kotlinpoet.api index 62b6afbe..4e92873d 100644 --- a/kotlinpoet/api/kotlinpoet.api +++ b/kotlinpoet/api/kotlinpoet.api @@ -561,6 +561,7 @@ public final class com/squareup/kotlinpoet/MemberName$Companion { public final class com/squareup/kotlinpoet/NameAllocator { public fun <init> ()V + public fun <init> (Z)V public final fun copy ()Lcom/squareup/kotlinpoet/NameAllocator; public final fun get (Ljava/lang/Object;)Ljava/lang/String; public final fun newName (Ljava/lang/String;)Ljava/lang/String; diff --git a/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/NameAllocator.kt b/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/NameAllocator.kt index cda10042..a6c570b9 100644 --- a/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/NameAllocator.kt +++ b/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/NameAllocator.kt @@ -77,7 +77,39 @@ public class NameAllocator private constructor( private val allocatedNames: MutableSet<String>, private val tagToName: MutableMap<Any, String>, ) { - public constructor() : this(mutableSetOf(), mutableMapOf()) + public constructor() : this(preallocateKeywords = true) + + /** + * @param preallocateKeywords If true, all Kotlin keywords will be preallocated. Requested names which + * collide with keywords will be suffixed with underscores to avoid being used as identifiers: + * + * ```kotlin + * val nameAllocator = NameAllocator(preallocateKeywords = true) + * println(nameAllocator.newName("when")) // prints "when_" + * ``` + * + * If false, keywords will not get any special treatment: + * + * ```kotlin + * val nameAllocator = NameAllocator(preallocateKeywords = false) + * println(nameAllocator.newName("when")) // prints "when" + * ``` + * + * Note that you can use the `%N` placeholder when emitting a name produced by [NameAllocator] to + * ensure it's properly escaped for use as an identifier: + * + * ```kotlin + * val nameAllocator = NameAllocator(preallocateKeywords = false) + * println(CodeBlock.of("%N", nameAllocator.newName("when"))) // prints "`when`" + * ``` + * + * The default behaviour of [NameAllocator] is to preallocate keywords - this is the behaviour you'll + * get when using the no-arg constructor. + */ + public constructor(preallocateKeywords: Boolean) : this( + allocatedNames = if (preallocateKeywords) KEYWORDS.toMutableSet() else mutableSetOf(), + tagToName = mutableMapOf(), + ) /** * Return a new name using `suggestion` that will not be a Java identifier or clash with other @@ -89,7 +121,7 @@ public class NameAllocator private constructor( tag: Any = UUID.randomUUID().toString(), ): String { var result = toJavaIdentifier(suggestion) - while (result.isKeyword || !allocatedNames.add(result)) { + while (!allocatedNames.add(result)) { result += "_" } diff --git a/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/Util.kt b/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/Util.kt index 16a443dd..c226f397 100644 --- a/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/Util.kt +++ b/kotlinpoet/src/commonMain/kotlin/com/squareup/kotlinpoet/Util.kt @@ -169,7 +169,7 @@ private val IDENTIFIER_REGEX = internal val String.isIdentifier get() = IDENTIFIER_REGEX.matches(this) // https://kotlinlang.org/docs/reference/keyword-reference.html -private val KEYWORDS = setOf( +internal val KEYWORDS = setOf( // Hard keywords "as", "break", diff --git a/kotlinpoet/src/commonTest/kotlin/com/squareup/kotlinpoet/NameAllocatorTest.kt b/kotlinpoet/src/commonTest/kotlin/com/squareup/kotlinpoet/NameAllocatorTest.kt index 28c7d34d..a61877c0 100644 --- a/kotlinpoet/src/commonTest/kotlin/com/squareup/kotlinpoet/NameAllocatorTest.kt +++ b/kotlinpoet/src/commonTest/kotlin/com/squareup/kotlinpoet/NameAllocatorTest.kt @@ -70,6 +70,12 @@ class NameAllocatorTest { assertThat(nameAllocator[1]).isEqualTo("when_") } + @Test fun kotlinKeywordNotPreAllocated() { + val nameAllocator = NameAllocator(preallocateKeywords = false) + assertThat(nameAllocator.newName("when", 1)).isEqualTo("when") + assertThat(nameAllocator[1]).isEqualTo("when") + } + @Test fun tagReuseForbidden() { val nameAllocator = NameAllocator() nameAllocator.newName("foo", 1) |