diff --git a/wire-kotlin-generator/api/wire-kotlin-generator.api b/wire-kotlin-generator/api/wire-kotlin-generator.api index a10f6bc8c5..5357198de6 100644 --- a/wire-kotlin-generator/api/wire-kotlin-generator.api +++ b/wire-kotlin-generator/api/wire-kotlin-generator.api @@ -1,6 +1,6 @@ public final class com/squareup/wire/kotlin/KotlinGenerator { public static final field Companion Lcom/squareup/wire/kotlin/KotlinGenerator$Companion; - public synthetic fun (Lcom/squareup/wire/schema/Schema;Ljava/util/Map;Ljava/util/Map;Lcom/squareup/wire/schema/Profile;ZZZZLcom/squareup/wire/kotlin/RpcCallStyle;Lcom/squareup/wire/kotlin/RpcRole;ILjava/lang/String;ZZLkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Lcom/squareup/wire/schema/Schema;Ljava/util/Map;Ljava/util/Map;Lcom/squareup/wire/schema/Profile;ZZZZLcom/squareup/wire/kotlin/RpcCallStyle;Lcom/squareup/wire/kotlin/RpcRole;ILjava/lang/String;ZZZLkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun generateOptionType (Lcom/squareup/wire/schema/Extend;Lcom/squareup/wire/schema/Field;)Lcom/squareup/kotlinpoet/TypeSpec; public final fun generateServiceTypeSpecs (Lcom/squareup/wire/schema/Service;Lcom/squareup/wire/schema/Rpc;)Ljava/util/Map; public static synthetic fun generateServiceTypeSpecs$default (Lcom/squareup/wire/kotlin/KotlinGenerator;Lcom/squareup/wire/schema/Service;Lcom/squareup/wire/schema/Rpc;ILjava/lang/Object;)Ljava/util/Map; @@ -9,14 +9,14 @@ public final class com/squareup/wire/kotlin/KotlinGenerator { public static synthetic fun generatedServiceName$default (Lcom/squareup/wire/kotlin/KotlinGenerator;Lcom/squareup/wire/schema/Service;Lcom/squareup/wire/schema/Rpc;ZILjava/lang/Object;)Lcom/squareup/kotlinpoet/ClassName; public final fun generatedTypeName (Lcom/squareup/wire/schema/ProtoMember;)Lcom/squareup/kotlinpoet/ClassName; public final fun generatedTypeName (Lcom/squareup/wire/schema/Type;)Lcom/squareup/kotlinpoet/ClassName; - public static final fun get (Lcom/squareup/wire/schema/Schema;Lcom/squareup/wire/schema/Profile;ZZZZLcom/squareup/wire/kotlin/RpcCallStyle;Lcom/squareup/wire/kotlin/RpcRole;ILjava/lang/String;ZZ)Lcom/squareup/wire/kotlin/KotlinGenerator; + public static final fun get (Lcom/squareup/wire/schema/Schema;Lcom/squareup/wire/schema/Profile;ZZZZLcom/squareup/wire/kotlin/RpcCallStyle;Lcom/squareup/wire/kotlin/RpcRole;ILjava/lang/String;ZZZ)Lcom/squareup/wire/kotlin/KotlinGenerator; public final fun getSchema ()Lcom/squareup/wire/schema/Schema; } public final class com/squareup/wire/kotlin/KotlinGenerator$Companion { public final fun builtInType (Lcom/squareup/wire/schema/ProtoType;)Z - public final fun get (Lcom/squareup/wire/schema/Schema;Lcom/squareup/wire/schema/Profile;ZZZZLcom/squareup/wire/kotlin/RpcCallStyle;Lcom/squareup/wire/kotlin/RpcRole;ILjava/lang/String;ZZ)Lcom/squareup/wire/kotlin/KotlinGenerator; - public static synthetic fun get$default (Lcom/squareup/wire/kotlin/KotlinGenerator$Companion;Lcom/squareup/wire/schema/Schema;Lcom/squareup/wire/schema/Profile;ZZZZLcom/squareup/wire/kotlin/RpcCallStyle;Lcom/squareup/wire/kotlin/RpcRole;ILjava/lang/String;ZZILjava/lang/Object;)Lcom/squareup/wire/kotlin/KotlinGenerator; + public final fun get (Lcom/squareup/wire/schema/Schema;Lcom/squareup/wire/schema/Profile;ZZZZLcom/squareup/wire/kotlin/RpcCallStyle;Lcom/squareup/wire/kotlin/RpcRole;ILjava/lang/String;ZZZ)Lcom/squareup/wire/kotlin/KotlinGenerator; + public static synthetic fun get$default (Lcom/squareup/wire/kotlin/KotlinGenerator$Companion;Lcom/squareup/wire/schema/Schema;Lcom/squareup/wire/schema/Profile;ZZZZLcom/squareup/wire/kotlin/RpcCallStyle;Lcom/squareup/wire/kotlin/RpcRole;ILjava/lang/String;ZZZILjava/lang/Object;)Lcom/squareup/wire/kotlin/KotlinGenerator; } public final class com/squareup/wire/kotlin/KotlinSchemaHandler : com/squareup/wire/schema/SchemaHandler { diff --git a/wire-kotlin-generator/src/main/java/com/squareup/wire/kotlin/KotlinGenerator.kt b/wire-kotlin-generator/src/main/java/com/squareup/wire/kotlin/KotlinGenerator.kt index 54b90fe019..366b8be857 100644 --- a/wire-kotlin-generator/src/main/java/com/squareup/wire/kotlin/KotlinGenerator.kt +++ b/wire-kotlin-generator/src/main/java/com/squareup/wire/kotlin/KotlinGenerator.kt @@ -129,6 +129,11 @@ class KotlinGenerator private constructor( private val nameSuffix: String?, private val buildersOnly: Boolean, private val escapeKotlinKeywords: Boolean, + /** + * If true, generated enums will have an extra `UNRECOGNIZED` constant with a value of `-1`. This + * only applies to enum which syntax is proto3. + */ + private val generateUnrecognizedEnumConstant: Boolean, ) { private val nameAllocatorStore = mutableMapOf() @@ -2214,6 +2219,25 @@ class KotlinGenerator private constructor( * } */ private fun generateEnum(enum: EnumType): TypeSpec { + @Suppress("NAME_SHADOWING") + val enum = + if (enum.syntax == Syntax.PROTO_3 && generateUnrecognizedEnumConstant) { + // We mutate the constant by inserting `UNRECOGNIZED(-1)` at the front of the list. + enum.copy( + constants = listOf( + EnumConstant( + location = enum.location, + name = "UNRECOGNIZED", + tag = -1, + documentation = "", + options = Options(optionType = ENUM_OPTIONS, optionElements = listOf()), + ), + ) + enum.constants, + ) + } else { + enum + } + val type = enum.type val nameAllocator = nameAllocator(enum) @@ -2886,6 +2910,7 @@ class KotlinGenerator private constructor( nameSuffix: String? = null, buildersOnly: Boolean = false, escapeKotlinKeywords: Boolean = false, + generateUnrecognizedEnumConstant: Boolean = false, ): KotlinGenerator { val typeToKotlinName = mutableMapOf() val memberToKotlinName = mutableMapOf() @@ -2934,6 +2959,7 @@ class KotlinGenerator private constructor( nameSuffix = nameSuffix, buildersOnly = buildersOnly, escapeKotlinKeywords = escapeKotlinKeywords, + generateUnrecognizedEnumConstant = generateUnrecognizedEnumConstant, ) } diff --git a/wire-kotlin-generator/src/test/java/com/squareup/wire/kotlin/KotlinGeneratorTest.kt b/wire-kotlin-generator/src/test/java/com/squareup/wire/kotlin/KotlinGeneratorTest.kt index e6212fc2c4..69d8f9f3ed 100644 --- a/wire-kotlin-generator/src/test/java/com/squareup/wire/kotlin/KotlinGeneratorTest.kt +++ b/wire-kotlin-generator/src/test/java/com/squareup/wire/kotlin/KotlinGeneratorTest.kt @@ -66,6 +66,50 @@ class KotlinGeneratorTest { assertThat(code).contains("WORK(1),") } + @Test fun generateUnrecognizedEnumConstantIsIgnoredForProto2() { + val schema = buildSchema { + add( + "message.proto".toPath(), + """ + |syntax = "proto2"; + |enum PhoneType { + | HOME = 0; + | WORK = 1; + | MOBILE = 2; + |} + """.trimMargin(), + ) + } + val code = KotlinWithProfilesGenerator(schema) + .generateKotlin("PhoneType", generateUnrecognizedEnumConstant = true) + assertThat(code).contains("HOME(0),") + assertThat(code).contains("WORK(1),") + assertThat(code).contains("MOBILE(2),") + assertThat(code).doesNotContain("UNRECOGNIZED(-1),") + } + + @Test fun generateUnrecognizedEnumConstantIsAppliedForProto3() { + val schema = buildSchema { + add( + "message.proto".toPath(), + """ + |syntax = "proto3"; + |enum PhoneType { + | HOME = 0; + | WORK = 1; + | MOBILE = 2; + |} + """.trimMargin(), + ) + } + val code = KotlinWithProfilesGenerator(schema) + .generateKotlin("PhoneType", generateUnrecognizedEnumConstant = true) + assertThat(code).contains("HOME(0),") + assertThat(code).contains("WORK(1),") + assertThat(code).contains("MOBILE(2),") + assertThat(code).contains("UNRECOGNIZED(-1),") + } + @Test fun defaultValues() { val schema = buildSchema { add( diff --git a/wire-kotlin-generator/src/test/java/com/squareup/wire/kotlin/KotlinWithProfilesGenerator.kt b/wire-kotlin-generator/src/test/java/com/squareup/wire/kotlin/KotlinWithProfilesGenerator.kt index 838138c59b..5d08101489 100644 --- a/wire-kotlin-generator/src/test/java/com/squareup/wire/kotlin/KotlinWithProfilesGenerator.kt +++ b/wire-kotlin-generator/src/test/java/com/squareup/wire/kotlin/KotlinWithProfilesGenerator.kt @@ -52,6 +52,7 @@ internal class KotlinWithProfilesGenerator(private val schema: Schema) { boxOneOfsMinSize: Int = 5_000, buildersOnly: Boolean = false, javaInterop: Boolean = false, + generateUnrecognizedEnumConstant: Boolean = false, ): String { val kotlinGenerator = KotlinGenerator( schema, @@ -59,6 +60,7 @@ internal class KotlinWithProfilesGenerator(private val schema: Schema) { boxOneOfsMinSize = boxOneOfsMinSize, buildersOnly = buildersOnly, javaInterop = javaInterop, + generateUnrecognizedEnumConstant = generateUnrecognizedEnumConstant, ) val type = schema.getType(typeName)!! val typeSpec = kotlinGenerator.generateType(type)