diff --git a/java/core/src/test/java/com/google/protobuf/kotlin/AndroidManifest.xml b/java/core/src/test/java/com/google/protobuf/kotlin/AndroidManifest.xml
new file mode 100644
index 0000000000..56a4551aa3
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/kotlin/AndroidManifest.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/java/core/src/test/java/com/google/protobuf/kotlin/BUILD b/java/core/src/test/java/com/google/protobuf/kotlin/BUILD
new file mode 100644
index 0000000000..f81b7f3905
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/kotlin/BUILD
@@ -0,0 +1,248 @@
+# Tests for the Kotlin proto runtime.
+load("//tools/build_defs/android:rules.bzl", "android_binary")
+load("//tools/build_defs/kotlin:rules.bzl", "kt_jvm_library")
+load("//testing/build_defs:junit_test_suites.bzl", "junit_test_suites")
+load(
+ "//third_party/protobuf/build_defs:kt_jvm_proto_library.bzl",
+ "kt_jvm_lite_proto_library",
+ "kt_jvm_proto_library",
+)
+
+proto_library(
+ name = "test_proto",
+ srcs = ["test.proto"],
+)
+
+java_proto_library(
+ name = "test_java_proto",
+ deps = [":test_proto"],
+)
+
+java_lite_proto_library(
+ name = "test_java_proto_lite",
+ deps = [":test_proto"],
+)
+
+kt_jvm_library(
+ name = "shared_tests",
+ srcs = [
+ "DslListTest.kt",
+ "DslMapTest.kt",
+ "ExtensionListTest.kt",
+ ],
+ kotlincopts = ["-Xopt-in=kotlin.RequiresOptIn"],
+ deps = [
+ ":test_java_proto_lite",
+ "//java/com/google/common/testing",
+ "//java/com/google/protobuf/kotlin",
+ "//java/com/google/protobuf/kotlin:only_for_use_in_proto_generated_code_its_generator_and_tests",
+ "//java/com/google/protobuf/kotlin:shared_runtime",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ "//third_party/kotlin/kotlin:kotlin_test",
+ ],
+)
+
+junit_test_suites(
+ name = "shared_test_suite",
+ sizes = ["small"],
+ suffix = "Shared",
+ deps = [":shared_tests"],
+)
+
+proto_library(
+ name = "evil_names_proto2",
+ srcs = ["evil_names_proto2.proto"],
+)
+
+proto_library(
+ name = "evil_names_proto3",
+ srcs = ["evil_names_proto3.proto"],
+)
+
+proto_library(
+ name = "multiple_files_proto3",
+ srcs = ["multiple_files_proto3.proto"],
+)
+
+kt_jvm_lite_proto_library(
+ name = "proto2_unittest_kt_jvm_proto_lite",
+ deps = [
+ ":evil_names_proto2",
+ "//net/proto2/internal:unittest_lite_proto",
+ ],
+)
+
+kt_jvm_proto_library(
+ name = "proto2_unittest_kt_jvm_proto",
+ deps = [
+ ":evil_names_proto2",
+ "//net/proto2/internal:unittest_proto",
+ ],
+)
+
+kt_jvm_lite_proto_library(
+ name = "proto3_unittest_kt_jvm_proto_lite",
+ deps = [
+ ":evil_names_proto3",
+ ":multiple_files_proto3",
+ "//net/proto2/internal:unittest_proto3",
+ ],
+)
+
+kt_jvm_proto_library(
+ name = "proto3_unittest_kt_jvm_proto",
+ deps = [
+ ":evil_names_proto3",
+ ":multiple_files_proto3",
+ "//net/proto2/internal:unittest_proto3",
+ ],
+)
+
+kt_jvm_library(
+ name = "proto2_lite_test",
+ srcs = ["Proto2LiteTest.kt"],
+ constraints = ["android"],
+ kotlincopts = [
+ "-language-version",
+ "1.3",
+ ],
+ deps = [
+ ":proto2_unittest_kt_jvm_proto_lite",
+ "//java/com/google/protobuf/kotlin:shared_runtime",
+ "//javatests/com/google/protobuf:test_util-android",
+ "//third_party/java/junit:junit-android",
+ "//third_party/java/truth:truth-android",
+ "//third_party/kotlin/kotlin:kotlin_test",
+ ],
+)
+
+kt_jvm_library(
+ name = "proto2_test",
+ srcs = ["Proto2Test.kt"],
+ kotlincopts = [
+ "-language-version",
+ "1.3",
+ ],
+ deps = [
+ "proto2_unittest_kt_jvm_proto",
+ "//java/com/google/protobuf/kotlin:shared_runtime",
+ "//javatests/com/google/protobuf:test_util",
+ "//net/proto2/internal:unittest_java_proto",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ "//third_party/kotlin/kotlin:kotlin_test",
+ ],
+)
+
+kt_jvm_library(
+ name = "proto3_lite_test",
+ srcs = ["Proto3Test.kt"],
+ kotlincopts = [
+ "-language-version",
+ "1.3",
+ ],
+ deps = [
+ ":proto3_unittest_kt_jvm_proto_lite",
+ "//java/com/google/protobuf/kotlin:shared_runtime",
+ "//net/proto2/internal:unittest_proto3_java_proto_lite",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ "//third_party/kotlin/kotlin:kotlin_test",
+ ],
+)
+
+kt_jvm_library(
+ name = "proto3_test",
+ srcs = ["Proto3Test.kt"],
+ kotlincopts = [
+ "-language-version",
+ "1.3",
+ ],
+ deps = [
+ ":proto3_unittest_kt_jvm_proto",
+ "//java/com/google/protobuf/kotlin:shared_runtime",
+ "//net/proto2/internal:unittest_proto3_java_proto",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ "//third_party/kotlin/kotlin:kotlin_test",
+ ],
+)
+
+junit_test_suites(
+ name = "proto2_lite_tests_junit",
+ sizes = ["small"],
+ suffix = "Proto2LiteGeneratedCode",
+ deps = [":proto2_lite_test"],
+)
+
+junit_test_suites(
+ name = "proto2_tests_junit",
+ sizes = ["small"],
+ suffix = "Proto2GeneratedCode",
+ deps = [":proto2_test"],
+)
+
+junit_test_suites(
+ name = "generated_proto3_lite",
+ sizes = ["small"],
+ suffix = "Proto3LiteGeneratedCode",
+ deps = ["proto3_lite_test"],
+)
+
+junit_test_suites(
+ name = "generated_full_protos",
+ sizes = ["small"],
+ suffix = "Proto3GeneratedCode",
+ deps = [":proto3_test"],
+)
+
+kt_jvm_library(
+ name = "lite_runtime_tests_lib",
+ srcs = ["ExtendableMessageLiteExtensionsTest.kt"],
+ constraints = ["android"],
+ deps = [
+ ":test_java_proto_lite",
+ "//java/com/google/protobuf/kotlin:kotlin_lite",
+ "//third_party/java/junit:junit-android",
+ "//third_party/java/truth:truth-android",
+ ],
+)
+
+junit_test_suites(
+ name = "lite_runtime_tests",
+ sizes = ["small"],
+ suffix = "LiteRuntime",
+ deps = [":lite_runtime_tests_lib"],
+)
+
+kt_jvm_library(
+ name = "full_runtime_tests_lib",
+ srcs = ["ExtendableMessageExtensionsTest.kt"],
+ deps = [
+ ":test_java_proto",
+ "//java/com/google/protobuf/kotlin",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ ],
+)
+
+junit_test_suites(
+ name = "full_runtime_tests",
+ sizes = ["small"],
+ suffix = "FullRuntime",
+ deps = [":full_runtime_tests_lib"],
+)
+
+# Generate a binary with AppReduce run on it, to verify no choking. The proto runtime includes
+# kt_proto.pgcfg, which enforces that the DSLs are stripped out, so we just want to make sure
+# that's run.
+android_binary(
+ name = "Proto2LiteTestBinary",
+ manifest = "AndroidManifest.xml",
+ proguard_specs = [
+ "//java/com/google/android/apps/common/proguard:base.pgcfg",
+ "//java/com/google/android/apps/common/proguard:dev_optimize.pgcfg",
+ ],
+ deps = [":proto2_lite_test"],
+)
diff --git a/java/core/src/test/java/com/google/protobuf/kotlin/DslListTest.kt b/java/core/src/test/java/com/google/protobuf/kotlin/DslListTest.kt
new file mode 100644
index 0000000000..e5e6017c06
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/kotlin/DslListTest.kt
@@ -0,0 +1,98 @@
+package com.google.protobuf.kotlin
+
+import com.google.common.testing.EqualsTester
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+/** Tests for [DslList]. */
+@RunWith(JUnit4::class)
+@OptIn(OnlyForUseByGeneratedProtoCode::class)
+class DslListTest {
+ class DummyProxy private constructor() : DslProxy()
+
+ @Test
+ fun matchesList() {
+ assertThat(DslList(listOf(1, 2, 3))).containsExactly(1, 2, 3).inOrder()
+ }
+
+ @Test
+ fun reflectsChangesInList() {
+ val mutableList = mutableListOf(1, 2, 3)
+ val dslList = DslList(mutableList)
+ mutableList.add(4)
+ assertThat(dslList).containsExactly(1, 2, 3, 4).inOrder()
+ }
+
+ @Test
+ fun dslListIsNotMutable() {
+ val dslList = DslList(mutableListOf(1, 2, 3))
+ assertThat(dslList is MutableList<*>).isFalse()
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslListIsNotEvenSecretlyMutable() {
+ val dslList = DslList(mutableListOf(1, 2, 3))
+ val dslListAsJavaUtil = dslList as java.util.List
+ assertFailsWith {
+ dslListAsJavaUtil.add(4)
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslList_IteratorIsNotEvenSecretlyMutable() {
+ val dslList = DslList(mutableListOf(1, 2, 3))
+ val iterator = dslList.iterator() as java.util.Iterator
+ iterator.next()
+
+ assertFailsWith {
+ iterator.remove()
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslList_ListIteratorIsNotEvenSecretlyMutable() {
+ val dslList = DslList(mutableListOf(1, 2, 3))
+ val iterator = dslList.listIterator() as java.util.ListIterator
+ iterator.next()
+
+ assertFailsWith {
+ iterator.remove()
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslList_ListIteratorIndexIsNotEvenSecretlyMutable() {
+ val dslList = DslList(mutableListOf(1, 2, 3))
+ val iterator = dslList.listIterator(1) as java.util.ListIterator
+ iterator.next()
+
+ assertFailsWith {
+ iterator.remove()
+ }
+ }
+
+ @Test
+ fun expectedToString() {
+ assertThat(DslList(listOf(1, 2)).toString()).isEqualTo("[1, 2]")
+ }
+
+ @Test
+ fun equality() {
+ EqualsTester()
+ .addEqualityGroup(DslList(listOf(1, 2)), listOf(1, 2))
+ .addEqualityGroup(DslList(listOf(2, 2)), listOf(2, 2))
+ .addEqualityGroup(
+ DslList(emptyList()),
+ DslList(emptyList()),
+ emptyList()
+ )
+ .testEquals()
+ }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/kotlin/DslMapTest.kt b/java/core/src/test/java/com/google/protobuf/kotlin/DslMapTest.kt
new file mode 100644
index 0000000000..470e42e48a
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/kotlin/DslMapTest.kt
@@ -0,0 +1,164 @@
+package com.google.protobuf.kotlin
+
+import com.google.common.testing.EqualsTester
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+@OptIn(OnlyForUseByGeneratedProtoCode::class)
+class DslMapTest {
+ class DummyProxy private constructor() : DslProxy()
+
+ @Test
+ fun matchesMap() {
+ assertThat(DslMap(mapOf(1 to -1, 2 to -2)))
+ .containsExactly(1, -1, 2, -2)
+ }
+
+ @Test
+ fun reflectsChangesInMap() {
+ val mutableMap = mutableMapOf(1 to -1, 2 to -2)
+ val dslMap = DslMap(mutableMap)
+ mutableMap[3] = -3
+ assertThat(dslMap).containsExactly(1, -1, 2, -2, 3, -3).inOrder()
+ }
+
+ @Test
+ fun dslMapIsNotMutable() {
+ val dslMap = DslMap(mutableMapOf(1 to -1))
+ assertThat(dslMap is MutableMap<*, *>).isFalse()
+ }
+
+ @Test
+ fun dslMapKeysAreNotMutable() {
+ val dslMap = DslMap(mutableMapOf(1 to -1))
+ assertThat(dslMap.keys is MutableSet<*>).isFalse()
+ }
+
+ @Test
+ fun dslMapValuesAreNotMutable() {
+ val dslMap = DslMap(mutableMapOf(1 to -1))
+ assertThat(dslMap.values is MutableSet<*>).isFalse()
+ }
+
+ @Test
+ fun dslMapEntriesAreNotMutable() {
+ val dslMap = DslMap(mutableMapOf(1 to -1))
+ assertThat(dslMap.entries is MutableSet<*>).isFalse()
+ }
+
+ @Test
+ fun dslMapEntryObjectsAreNotMutable() {
+ val dslMap = DslMap(mutableMapOf(1 to -1))
+ assertThat(dslMap.entries.single() is MutableMap.MutableEntry<*, *>).isFalse()
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslMapIsNotEvenSecretlyMutable() {
+ val dslMap = DslMap(mutableMapOf(1 to -1))
+ val dslMapAsJavaUtilMap = dslMap as java.util.Map
+ assertFailsWith {
+ dslMapAsJavaUtilMap.put(2, -2)
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslMapKeysAreNotEvenSecretlyMutable() {
+ val dslMap = DslMap(mutableMapOf(1 to -1))
+ val dslMapKeysAsJavaUtilSet = dslMap.keys as java.util.Set
+ assertFailsWith {
+ dslMapKeysAsJavaUtilSet.remove(1)
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslMapKeysIteratorIsNotEvenSecretlyMutable() {
+ val dslMap = DslMap(mutableMapOf(1 to -1))
+ val dslMapKeysAsJavaUtilSet = dslMap.keys as java.util.Set
+ val itr = dslMapKeysAsJavaUtilSet.iterator()
+ itr.next()
+ assertFailsWith {
+ itr.remove()
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslMapValuesAreNotEvenSecretlyMutable() {
+ val dslMap = DslMap(mutableMapOf(1 to -1))
+ val dslMapValuesAsJavaUtilCollection = dslMap.values as java.util.Collection
+ assertFailsWith {
+ dslMapValuesAsJavaUtilCollection.remove(1)
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslMapValuesIteratorIsNotEvenSecretlyMutable() {
+ val dslMap = DslMap(mutableMapOf(1 to -1))
+ val dslMapValuesAsJavaUtilCollection = dslMap.values as java.util.Collection
+ val itr = dslMapValuesAsJavaUtilCollection.iterator()
+ itr.next()
+ assertFailsWith {
+ itr.remove()
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslMapEntriesAreNotEvenSecretlyMutable() {
+ val dslMap = DslMap(mutableMapOf(1 to -1))
+ val dslMapEntriesAsJavaUtilSet = dslMap.entries as java.util.Set>
+ val entry = dslMap.entries.single()
+ assertFailsWith {
+ dslMapEntriesAsJavaUtilSet.remove(entry)
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslMapEntriesIteratorIsNotEvenSecretlyMutable() {
+ val dslMap = DslMap(mutableMapOf(1 to -1))
+ val dslMapEntriesAsJavaUtilSet = dslMap.entries as java.util.Set>
+ val itr = dslMapEntriesAsJavaUtilSet.iterator()
+ itr.next()
+ assertFailsWith {
+ itr.remove()
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun dslMapEntryObjectsAreNotEvenSecretlyMutable() {
+ val dslMap = DslMap(mutableMapOf(1 to -1))
+ val dslMapEntryAsJavaUtilMapEntry = dslMap.entries.single() as java.util.Map.Entry
+ assertFailsWith {
+ dslMapEntryAsJavaUtilMapEntry.value = 2
+ }
+ }
+
+ @Test
+ fun expectedToString() {
+ assertThat(DslMap(mapOf(1 to 2, 2 to 3)).toString())
+ .isEqualTo("{1=2, 2=3}")
+ }
+
+ @Test
+ fun equality() {
+ EqualsTester()
+ .addEqualityGroup(DslMap(mapOf(1 to 2, 2 to 3)), mapOf(1 to 2, 2 to 3))
+ .addEqualityGroup(DslMap(mapOf(1 to 3, 2 to 3)), mapOf(1 to 3, 2 to 3))
+ .addEqualityGroup(
+ DslMap(emptyMap()),
+ DslMap(emptyMap()),
+ emptyMap()
+ )
+ .testEquals()
+ }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/kotlin/ExtendableMessageExtensionsTest.kt b/java/core/src/test/java/com/google/protobuf/kotlin/ExtendableMessageExtensionsTest.kt
new file mode 100644
index 0000000000..f4c7e4e3f0
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/kotlin/ExtendableMessageExtensionsTest.kt
@@ -0,0 +1,60 @@
+package com.google.protobuf.kotlin
+
+import com.google.common.truth.Truth.assertThat
+import com.google.protobuf.kotlin.test.ExampleExtensibleMessage
+import com.google.protobuf.kotlin.test.Test as TestProto
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class ExtendableMessageExtensionsTest {
+ @Test
+ fun setOnBuilder() {
+ val builder = ExampleExtensibleMessage.newBuilder()
+ builder[TestProto.int32Extension] = 5
+ assertThat(builder.build().getExtension(TestProto.int32Extension)).isEqualTo(5)
+ }
+
+ @Test
+ fun getOnBuilder() {
+ val builder = ExampleExtensibleMessage.newBuilder()
+ .setExtension(TestProto.int32Extension, 6)
+ assertThat(builder[TestProto.int32Extension]).isEqualTo(6)
+ }
+
+ @Test
+ fun getOnMessage() {
+ val message = ExampleExtensibleMessage.newBuilder()
+ .setExtension(TestProto.int32Extension, 6)
+ .build()
+ assertThat(message[TestProto.int32Extension]).isEqualTo(6)
+ }
+
+ @Test
+ fun containsPositiveOnMessage() {
+ val message = ExampleExtensibleMessage.newBuilder()
+ .setExtension(TestProto.int32Extension, 6)
+ .build()
+ assertThat(TestProto.int32Extension in message).isTrue()
+ }
+
+ @Test
+ fun containsPositiveOnBuilder() {
+ val builder = ExampleExtensibleMessage.newBuilder()
+ .setExtension(TestProto.int32Extension, 6)
+ assertThat(TestProto.int32Extension in builder).isTrue()
+ }
+
+ @Test
+ fun containsNegativeOnMessage() {
+ val message = ExampleExtensibleMessage.newBuilder().build()
+ assertThat(TestProto.int32Extension in message).isFalse()
+ }
+
+ @Test
+ fun containsNegativeOnBuilder() {
+ val builder = ExampleExtensibleMessage.newBuilder()
+ assertThat(TestProto.int32Extension in builder).isFalse()
+ }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/kotlin/ExtendableMessageLiteExtensionsTest.kt b/java/core/src/test/java/com/google/protobuf/kotlin/ExtendableMessageLiteExtensionsTest.kt
new file mode 100644
index 0000000000..9cf8c5975f
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/kotlin/ExtendableMessageLiteExtensionsTest.kt
@@ -0,0 +1,60 @@
+package com.google.protobuf.kotlin
+
+import com.google.common.truth.Truth.assertThat
+import com.google.protobuf.kotlin.test.ExampleExtensibleMessage
+import com.google.protobuf.kotlin.test.Test as TestProto
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class ExtendableMessageLiteExtensionsTest {
+ @Test
+ fun setOnBuilder() {
+ val builder = ExampleExtensibleMessage.newBuilder()
+ builder[TestProto.int32Extension] = 5
+ assertThat(builder.build().getExtension(TestProto.int32Extension)).isEqualTo(5)
+ }
+
+ @Test
+ fun getOnBuilder() {
+ val builder = ExampleExtensibleMessage.newBuilder()
+ .setExtension(TestProto.int32Extension, 6)
+ assertThat(builder[TestProto.int32Extension]).isEqualTo(6)
+ }
+
+ @Test
+ fun getOnMessage() {
+ val message = ExampleExtensibleMessage.newBuilder()
+ .setExtension(TestProto.int32Extension, 6)
+ .build()
+ assertThat(message[TestProto.int32Extension]).isEqualTo(6)
+ }
+
+ @Test
+ fun containsPositiveOnMessage() {
+ val message = ExampleExtensibleMessage.newBuilder()
+ .setExtension(TestProto.int32Extension, 6)
+ .build()
+ assertThat(TestProto.int32Extension in message).isTrue()
+ }
+
+ @Test
+ fun containsPositiveOnBuilder() {
+ val builder = ExampleExtensibleMessage.newBuilder()
+ .setExtension(TestProto.int32Extension, 6)
+ assertThat(TestProto.int32Extension in builder).isTrue()
+ }
+
+ @Test
+ fun containsNegativeOnMessage() {
+ val message = ExampleExtensibleMessage.newBuilder().build()
+ assertThat(TestProto.int32Extension in message).isFalse()
+ }
+
+ @Test
+ fun containsNegativeOnBuilder() {
+ val builder = ExampleExtensibleMessage.newBuilder()
+ assertThat(TestProto.int32Extension in builder).isFalse()
+ }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/kotlin/ExtensionListTest.kt b/java/core/src/test/java/com/google/protobuf/kotlin/ExtensionListTest.kt
new file mode 100644
index 0000000000..9a82a5cddb
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/kotlin/ExtensionListTest.kt
@@ -0,0 +1,125 @@
+package com.google.protobuf.kotlin
+
+import com.google.common.testing.EqualsTester
+import com.google.common.truth.Truth.assertThat
+import com.google.protobuf.kotlin.test.ExampleExtensibleMessage
+import com.google.protobuf.kotlin.test.Test as TestProto
+import kotlin.test.assertFailsWith
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+/** Tests for [DslList]. */
+@RunWith(JUnit4::class)
+@OptIn(OnlyForUseByGeneratedProtoCode::class)
+class ExtensionListTest {
+ class DummyProxy private constructor() : DslProxy()
+
+ @Test
+ fun matchesList() {
+ assertThat(
+ ExtensionList(
+ TestProto.repeatedExtension, listOf(1, 2, 3)
+ )
+ ).containsExactly(1, 2, 3).inOrder()
+ }
+
+ @Test
+ fun reflectsChangesInList() {
+ val mutableList = mutableListOf(1, 2, 3)
+ val extensionList = ExtensionList(
+ TestProto.repeatedExtension, mutableList
+ )
+ mutableList.add(4)
+ assertThat(extensionList).containsExactly(1, 2, 3, 4).inOrder()
+ }
+
+ @Test
+ fun extensionListIsNotMutable() {
+ val extensionList = ExtensionList(
+ TestProto.repeatedExtension, mutableListOf(1, 2, 3)
+ )
+ assertThat(extensionList is MutableList<*>).isFalse()
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun extensionListIsNotEvenSecretlyMutable() {
+ val extensionList = ExtensionList(
+ TestProto.repeatedExtension, mutableListOf(1, 2, 3)
+ )
+ val extensionListAsJavaUtil = extensionList as java.util.List
+ assertFailsWith {
+ extensionListAsJavaUtil.add(4)
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun extensionList_IteratorIsNotEvenSecretlyMutable() {
+ val extensionList = ExtensionList(
+ TestProto.repeatedExtension, mutableListOf(1, 2, 3)
+ )
+ val iterator = extensionList.iterator() as java.util.Iterator
+ iterator.next()
+
+ assertFailsWith {
+ iterator.remove()
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun extensionList_ListIteratorIsNotEvenSecretlyMutable() {
+ val extensionList = ExtensionList(
+ TestProto.repeatedExtension, mutableListOf(1, 2, 3)
+ )
+ val iterator = extensionList.listIterator() as java.util.ListIterator
+ iterator.next()
+
+ assertFailsWith {
+ iterator.remove()
+ }
+ }
+
+ @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
+ @Test
+ fun extensionList_ListIteratorIndexIsNotEvenSecretlyMutable() {
+ val extensionList = ExtensionList(
+ TestProto.repeatedExtension, mutableListOf(1, 2, 3)
+ )
+ val iterator = extensionList.listIterator(1) as java.util.ListIterator
+ iterator.next()
+
+ assertFailsWith {
+ iterator.remove()
+ }
+ }
+
+ @Test
+ fun expectedToString() {
+ assertThat(
+ ExtensionList(TestProto.repeatedExtension, listOf(1, 2))
+ .toString()
+ ).isEqualTo("[1, 2]")
+ }
+
+ @Test
+ fun equality() {
+ EqualsTester()
+ .addEqualityGroup(
+ ExtensionList(TestProto.repeatedExtension, listOf(1, 2)),
+ ExtensionList(TestProto.differentExtension, listOf(1, 2)),
+ listOf(1, 2)
+ )
+ .addEqualityGroup(
+ ExtensionList(TestProto.repeatedExtension, listOf(2, 2)),
+ listOf(2, 2)
+ )
+ .addEqualityGroup(
+ ExtensionList(TestProto.repeatedExtension, emptyList()),
+ emptyList()
+ )
+ .testEquals()
+ }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/kotlin/Proto2LiteTest.kt b/java/core/src/test/java/com/google/protobuf/kotlin/Proto2LiteTest.kt
new file mode 100644
index 0000000000..470d978353
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/kotlin/Proto2LiteTest.kt
@@ -0,0 +1,988 @@
+package com.google.protobuf.kotlin
+
+import com.google.common.truth.Truth.assertThat
+import com.google.protobuf.TestAllTypesLiteKt
+import com.google.protobuf.TestAllTypesLiteKt.nestedMessage
+import com.google.protobuf.TestUtilLite
+import com.google.protobuf.TestUtilLite.toBytes
+import com.google.protobuf.UnittestImportLite.ImportEnumLite
+import com.google.protobuf.UnittestImportLite.ImportMessageLite
+import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite
+import com.google.protobuf.UnittestLite
+import com.google.protobuf.UnittestLite.ForeignEnumLite
+import com.google.protobuf.UnittestLite.TestAllTypesLite
+import com.google.protobuf.UnittestLite.TestAllTypesLite.NestedEnum
+import com.google.protobuf.UnittestLite.TestEmptyMessageLite
+import com.google.protobuf.UnittestLite.TestEmptyMessageWithExtensionsLite
+import com.google.protobuf.copy
+import com.google.protobuf.foreignMessageLite
+import com.google.protobuf.kotlin.generator.EvilNamesProto2OuterClass.EvilNamesProto2
+import com.google.protobuf.kotlin.generator.EvilNamesProto2OuterClass.HardKeywordsAllTypes
+import com.google.protobuf.kotlin.generator.EvilNamesProto2OuterClass.Interface
+import com.google.protobuf.kotlin.generator.HardKeywordsAllTypesKt
+import com.google.protobuf.kotlin.generator.evilNamesProto2
+import com.google.protobuf.kotlin.generator.hardKeywordsAllTypes
+import com.google.protobuf.kotlin.generator.interface_
+import com.google.protobuf.optionalGroupExtensionLite
+import com.google.protobuf.repeatedGroupExtensionLite
+import com.google.protobuf.testAllExtensionsLite
+import com.google.protobuf.testAllTypesLite
+import com.google.protobuf.testEmptyMessageLite
+import com.google.protobuf.testEmptyMessageWithExtensionsLite
+import com.google.protos.proto2_unittest.MapLiteUnittest.MapEnumLite
+import com.google.protos.proto2_unittest.MapLiteUnittest.TestMapLite
+import com.google.protos.proto2_unittest.testMapLite
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class Proto2LiteTest {
+ @Test
+ fun testSetters() {
+ assertThat(
+ testAllTypesLite {
+ optionalInt32 = 101
+ optionalInt64 = 102
+ optionalUint32 = 103
+ optionalUint64 = 104
+ optionalSint32 = 105
+ optionalSint64 = 106
+ optionalFixed32 = 107
+ optionalFixed64 = 108
+ optionalSfixed32 = 109
+ optionalSfixed64 = 110
+ optionalFloat = 111.0f
+ optionalDouble = 112.0
+ optionalBool = true
+ optionalString = "115"
+ optionalBytes = toBytes("116")
+ optionalGroup =
+ TestAllTypesLiteKt.optionalGroup { a = 117 }
+ optionalNestedMessage = nestedMessage { bb = 118 }
+ optionalForeignMessage =
+ foreignMessageLite { c = 119 }
+ optionalImportMessage =
+ ImportMessageLite.newBuilder().setD(120).build()
+ optionalPublicImportMessage =
+ PublicImportMessageLite.newBuilder().setE(126).build()
+ optionalLazyMessage = nestedMessage { bb = 127 }
+ optionalNestedEnum = NestedEnum.BAZ
+ optionalForeignEnum = ForeignEnumLite.FOREIGN_LITE_BAZ
+ optionalImportEnum = ImportEnumLite.IMPORT_LITE_BAZ
+ optionalStringPiece = "124"
+ optionalCord = "125"
+ repeatedInt32.add(201)
+ repeatedInt64.add(202)
+ repeatedUint32.add(203)
+ repeatedUint64.add(204)
+ repeatedSint32.add(205)
+ repeatedSint64.add(206)
+ repeatedFixed32.add(207)
+ repeatedFixed64.add(208)
+ repeatedSfixed32.add(209)
+ repeatedSfixed64.add(210)
+ repeatedFloat.add(211f)
+ repeatedDouble.add(212.0)
+ repeatedBool.add(true)
+ repeatedString.add("215")
+ repeatedBytes.add(toBytes("216"))
+ repeatedGroup.add(TestAllTypesLiteKt.repeatedGroup { a = 217 })
+ repeatedNestedMessage.add(nestedMessage { bb = 218 })
+ repeatedForeignMessage.add(
+ foreignMessageLite { c = 219 }
+ )
+ repeatedImportMessage.add(
+ ImportMessageLite.newBuilder().setD(220).build()
+ )
+ repeatedLazyMessage.add(nestedMessage { bb = 227 })
+ repeatedNestedEnum.add(NestedEnum.BAR)
+ repeatedForeignEnum.add(ForeignEnumLite.FOREIGN_LITE_BAR)
+ repeatedImportEnum.add(ImportEnumLite.IMPORT_LITE_BAR)
+ repeatedStringPiece.add("224")
+ repeatedCord.add("225")
+ repeatedInt32 += 301
+ repeatedInt64 += 302
+ repeatedUint32 += 303
+ repeatedUint64 += 304
+ repeatedSint32 += 305
+ repeatedSint64 += 306
+ repeatedFixed32 += 307
+ repeatedFixed64 += 308
+ repeatedSfixed32 += 309
+ repeatedSfixed64 += 310
+ repeatedFloat += 311f
+ repeatedDouble += 312.0
+ repeatedBool += false
+ repeatedString += "315"
+ repeatedBytes += toBytes("316")
+ repeatedGroup += TestAllTypesLiteKt.repeatedGroup { a = 317 }
+ repeatedNestedMessage += nestedMessage { bb = 318 }
+ repeatedForeignMessage +=
+ foreignMessageLite { c = 319 }
+ repeatedImportMessage +=
+ ImportMessageLite.newBuilder().setD(320).build()
+ repeatedLazyMessage +=
+ TestAllTypesLiteKt.nestedMessage { bb = 327 }
+ repeatedNestedEnum += NestedEnum.BAZ
+ repeatedForeignEnum += ForeignEnumLite.FOREIGN_LITE_BAZ
+ repeatedImportEnum += ImportEnumLite.IMPORT_LITE_BAZ
+ repeatedStringPiece += "324"
+ repeatedCord += "325"
+ defaultInt32 = 401
+ defaultInt64 = 402
+ defaultUint32 = 403
+ defaultUint64 = 404
+ defaultSint32 = 405
+ defaultSint64 = 406
+ defaultFixed32 = 407
+ defaultFixed64 = 408
+ defaultSfixed32 = 409
+ defaultSfixed64 = 410
+ defaultFloat = 411f
+ defaultDouble = 412.0
+ defaultBool = false
+ defaultString = "415"
+ defaultBytes = toBytes("416")
+ defaultNestedEnum = NestedEnum.FOO
+ defaultForeignEnum = ForeignEnumLite.FOREIGN_LITE_FOO
+ defaultImportEnum = ImportEnumLite.IMPORT_LITE_FOO
+ defaultStringPiece = "424"
+ defaultCord = "425"
+ oneofUint32 = 601
+ oneofNestedMessage =
+ TestAllTypesLiteKt.nestedMessage { bb = 602 }
+ oneofString = "603"
+ oneofBytes = toBytes("604")
+ }
+ ).isEqualTo(
+ TestUtilLite.getAllLiteSetBuilder().build()
+ )
+ }
+
+ @Test
+ fun testGetters() {
+ testAllTypesLite {
+ optionalInt32 = 101
+ assertThat(optionalInt32).isEqualTo(101)
+ optionalString = "115"
+ assertThat(optionalString).isEqualTo("115")
+ optionalGroup = TestAllTypesLiteKt.optionalGroup { a = 117 }
+ assertThat(optionalGroup).isEqualTo(TestAllTypesLiteKt.optionalGroup { a = 117 })
+ optionalNestedMessage = TestAllTypesLiteKt.nestedMessage { bb = 118 }
+ assertThat(optionalNestedMessage).isEqualTo(TestAllTypesLiteKt.nestedMessage { bb = 118 })
+ optionalNestedEnum = NestedEnum.BAZ
+ assertThat(optionalNestedEnum).isEqualTo(NestedEnum.BAZ)
+ defaultInt32 = 401
+ assertThat(defaultInt32).isEqualTo(401)
+ oneofUint32 = 601
+ assertThat(oneofUint32).isEqualTo(601)
+ }
+ }
+
+ @Test
+ fun testDefaultGetters() {
+ testAllTypesLite {
+ assertThat(defaultInt32).isEqualTo(41)
+ assertThat(defaultString).isEqualTo("hello")
+ assertThat(defaultNestedEnum).isEqualTo(NestedEnum.BAR)
+ assertThat(defaultStringPiece).isEqualTo("abc")
+ }
+ }
+
+ @Test
+ fun testRepeatedGettersAndSetters() {
+ testAllTypesLite {
+ repeatedInt32.addAll(listOf(1, 2))
+ assertThat(repeatedInt32).isEqualTo(listOf(1, 2))
+ repeatedInt32 += listOf(3, 4)
+ assertThat(repeatedInt32).isEqualTo(listOf(1, 2, 3, 4))
+ repeatedInt32[0] = 5
+ assertThat(repeatedInt32).isEqualTo(listOf(5, 2, 3, 4))
+
+ repeatedString.addAll(listOf("1", "2"))
+ assertThat(repeatedString).isEqualTo(listOf("1", "2"))
+ repeatedString += listOf("3", "4")
+ assertThat(repeatedString).isEqualTo(listOf("1", "2", "3", "4"))
+ repeatedString[0] = "5"
+ assertThat(repeatedString).isEqualTo(listOf("5", "2", "3", "4"))
+
+ repeatedGroup.addAll(
+ listOf(
+ TestAllTypesLiteKt.repeatedGroup { a = 1 },
+ TestAllTypesLiteKt.repeatedGroup { a = 2 }
+ )
+ )
+ assertThat(repeatedGroup).isEqualTo(
+ listOf(
+ TestAllTypesLiteKt.repeatedGroup { a = 1 },
+ TestAllTypesLiteKt.repeatedGroup { a = 2 }
+ )
+ )
+ repeatedGroup +=
+ listOf(
+ TestAllTypesLiteKt.repeatedGroup { a = 3 },
+ TestAllTypesLiteKt.repeatedGroup { a = 4 }
+ )
+ assertThat(repeatedGroup).isEqualTo(
+ listOf(
+ TestAllTypesLiteKt.repeatedGroup { a = 1 },
+ TestAllTypesLiteKt.repeatedGroup { a = 2 },
+ TestAllTypesLiteKt.repeatedGroup { a = 3 },
+ TestAllTypesLiteKt.repeatedGroup { a = 4 }
+ )
+ )
+ repeatedGroup[0] = TestAllTypesLiteKt.repeatedGroup { a = 5 }
+ assertThat(repeatedGroup).isEqualTo(
+ listOf(
+ TestAllTypesLiteKt.repeatedGroup { a = 5 },
+ TestAllTypesLiteKt.repeatedGroup { a = 2 },
+ TestAllTypesLiteKt.repeatedGroup { a = 3 },
+ TestAllTypesLiteKt.repeatedGroup { a = 4 }
+ )
+ )
+
+ repeatedNestedMessage.addAll(listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 }))
+ assertThat(repeatedNestedMessage).isEqualTo(
+ listOf(
+ nestedMessage { bb = 1 },
+ nestedMessage { bb = 2 }
+ )
+ )
+ repeatedNestedMessage += listOf(nestedMessage { bb = 3 }, nestedMessage { bb = 4 })
+ assertThat(repeatedNestedMessage).isEqualTo(
+ listOf(
+ nestedMessage { bb = 1 },
+ nestedMessage { bb = 2 },
+ nestedMessage { bb = 3 },
+ nestedMessage { bb = 4 }
+ )
+ )
+ repeatedNestedMessage[0] = nestedMessage { bb = 5 }
+ assertThat(repeatedNestedMessage).isEqualTo(
+ listOf(
+ nestedMessage { bb = 5 },
+ nestedMessage { bb = 2 },
+ nestedMessage { bb = 3 },
+ nestedMessage { bb = 4 }
+ )
+ )
+
+ repeatedNestedEnum.addAll(listOf(NestedEnum.FOO, NestedEnum.BAR))
+ assertThat(repeatedNestedEnum).isEqualTo(listOf(NestedEnum.FOO, NestedEnum.BAR))
+ repeatedNestedEnum += listOf(NestedEnum.BAZ, NestedEnum.FOO)
+ assertThat(repeatedNestedEnum).isEqualTo(
+ listOf(NestedEnum.FOO, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
+ )
+ repeatedNestedEnum[0] = NestedEnum.BAR
+ assertThat(repeatedNestedEnum).isEqualTo(
+ listOf(NestedEnum.BAR, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
+ )
+ }
+ }
+
+ @Test
+ fun testHazzers() {
+ testAllTypesLite {
+ optionalInt32 = 101
+ assertThat(hasOptionalInt32()).isTrue()
+ assertThat(hasOptionalString()).isFalse()
+ optionalGroup = TestAllTypesLiteKt.optionalGroup { a = 117 }
+ assertThat(hasOptionalGroup()).isTrue()
+ assertThat(hasOptionalNestedMessage()).isFalse()
+ optionalNestedEnum = NestedEnum.BAZ
+ assertThat(hasOptionalNestedEnum()).isTrue()
+ assertThat(hasDefaultInt32()).isFalse()
+ oneofUint32 = 601
+ assertThat(hasOneofUint32()).isTrue()
+ }
+
+ testAllTypesLite {
+ assertThat(hasOptionalInt32()).isFalse()
+ optionalString = "115"
+ assertThat(hasOptionalString()).isTrue()
+ assertThat(hasOptionalGroup()).isFalse()
+ optionalNestedMessage = TestAllTypesLiteKt.nestedMessage { bb = 118 }
+ assertThat(hasOptionalNestedMessage()).isTrue()
+ assertThat(hasOptionalNestedEnum()).isFalse()
+ defaultInt32 = 401
+ assertThat(hasDefaultInt32()).isTrue()
+ assertThat(hasOneofUint32()).isFalse()
+ }
+ }
+
+ @Test
+ fun testClears() {
+ testAllTypesLite {
+ optionalInt32 = 101
+ clearOptionalInt32()
+ assertThat(hasOptionalInt32()).isFalse()
+
+ optionalString = "115"
+ clearOptionalString()
+ assertThat(hasOptionalString()).isFalse()
+
+ optionalGroup = TestAllTypesLiteKt.optionalGroup { a = 117 }
+ clearOptionalGroup()
+ assertThat(hasOptionalGroup()).isFalse()
+
+ optionalNestedMessage = TestAllTypesLiteKt.nestedMessage { bb = 118 }
+ clearOptionalNestedMessage()
+ assertThat(hasOptionalNestedMessage()).isFalse()
+
+ optionalNestedEnum = NestedEnum.BAZ
+ clearOptionalNestedEnum()
+ assertThat(hasOptionalNestedEnum()).isFalse()
+
+ defaultInt32 = 401
+ clearDefaultInt32()
+ assertThat(hasDefaultInt32()).isFalse()
+
+ oneofUint32 = 601
+ clearOneofUint32()
+ assertThat(hasOneofUint32()).isFalse()
+ }
+ }
+
+ @Test
+ fun testCopy() {
+ val message = testAllTypesLite {
+ optionalInt32 = 101
+ optionalString = "115"
+ }
+ val modifiedMessage = message.copy {
+ optionalInt32 = 201
+ }
+
+ assertThat(message).isEqualTo(
+ TestAllTypesLite.newBuilder()
+ .setOptionalInt32(101)
+ .setOptionalString("115")
+ .build()
+ )
+ assertThat(modifiedMessage).isEqualTo(
+ TestAllTypesLite.newBuilder()
+ .setOptionalInt32(201)
+ .setOptionalString("115")
+ .build()
+ )
+ }
+
+ @Test
+ fun testOneof() {
+ val message = testAllTypesLite {
+ oneofString = "foo"
+ assertThat(oneofFieldCase)
+ .isEqualTo(TestAllTypesLite.OneofFieldCase.ONEOF_STRING)
+ assertThat(oneofString).isEqualTo("foo")
+ clearOneofField()
+ assertThat(hasOneofUint32()).isFalse()
+ assertThat(oneofFieldCase)
+ .isEqualTo(TestAllTypesLite.OneofFieldCase.ONEOFFIELD_NOT_SET)
+ oneofUint32 = 5
+ }
+
+ assertThat(message.getOneofFieldCase())
+ .isEqualTo(TestAllTypesLite.OneofFieldCase.ONEOF_UINT32)
+ assertThat(message.getOneofUint32()).isEqualTo(5)
+ }
+
+ @Test
+ fun testExtensionsSet() {
+ assertThat(
+ testAllExtensionsLite {
+ this[UnittestLite.optionalInt32ExtensionLite] = 101
+ this[UnittestLite.optionalInt64ExtensionLite] = 102L
+ this[UnittestLite.optionalUint32ExtensionLite] = 103
+ this[UnittestLite.optionalUint64ExtensionLite] = 104L
+ this[UnittestLite.optionalSint32ExtensionLite] = 105
+ this[UnittestLite.optionalSint64ExtensionLite] = 106L
+ this[UnittestLite.optionalFixed32ExtensionLite] = 107
+ this[UnittestLite.optionalFixed64ExtensionLite] = 108L
+ this[UnittestLite.optionalSfixed32ExtensionLite] = 109
+ this[UnittestLite.optionalSfixed64ExtensionLite] = 110L
+ this[UnittestLite.optionalFloatExtensionLite] = 111F
+ this[UnittestLite.optionalDoubleExtensionLite] = 112.0
+ this[UnittestLite.optionalBoolExtensionLite] = true
+ this[UnittestLite.optionalStringExtensionLite] = "115"
+ this[UnittestLite.optionalBytesExtensionLite] = toBytes("116")
+ this[UnittestLite.optionalGroupExtensionLite] = optionalGroupExtensionLite { a = 117 }
+ this[UnittestLite.optionalNestedMessageExtensionLite] =
+ TestAllTypesLiteKt.nestedMessage { bb = 118 }
+ this[UnittestLite.optionalForeignMessageExtensionLite] = foreignMessageLite { c = 119 }
+ this[UnittestLite.optionalImportMessageExtensionLite] =
+ ImportMessageLite.newBuilder().setD(120).build()
+ this[UnittestLite.optionalPublicImportMessageExtensionLite] =
+ PublicImportMessageLite.newBuilder().setE(126).build()
+ this[UnittestLite.optionalLazyMessageExtensionLite] =
+ TestAllTypesLiteKt.nestedMessage { bb = 127 }
+ this[UnittestLite.optionalNestedEnumExtensionLite] = NestedEnum.BAZ
+ this[UnittestLite.optionalForeignEnumExtensionLite] = ForeignEnumLite.FOREIGN_LITE_BAZ
+ this[UnittestLite.optionalImportEnumExtensionLite] = ImportEnumLite.IMPORT_LITE_BAZ
+ this[UnittestLite.optionalStringPieceExtensionLite] = "124"
+ this[UnittestLite.optionalCordExtensionLite] = "125"
+ this[UnittestLite.repeatedInt32ExtensionLite].add(201)
+ this[UnittestLite.repeatedInt64ExtensionLite].add(202L)
+ this[UnittestLite.repeatedUint32ExtensionLite].add(203)
+ this[UnittestLite.repeatedUint64ExtensionLite].add(204L)
+ this[UnittestLite.repeatedSint32ExtensionLite].add(205)
+ this[UnittestLite.repeatedSint64ExtensionLite].add(206L)
+ this[UnittestLite.repeatedFixed32ExtensionLite].add(207)
+ this[UnittestLite.repeatedFixed64ExtensionLite].add(208L)
+ this[UnittestLite.repeatedSfixed32ExtensionLite].add(209)
+ this[UnittestLite.repeatedSfixed64ExtensionLite].add(210L)
+ this[UnittestLite.repeatedFloatExtensionLite].add(211F)
+ this[UnittestLite.repeatedDoubleExtensionLite].add(212.0)
+ this[UnittestLite.repeatedBoolExtensionLite].add(true)
+ this[UnittestLite.repeatedStringExtensionLite].add("215")
+ this[UnittestLite.repeatedBytesExtensionLite].add(toBytes("216"))
+ this[UnittestLite.repeatedGroupExtensionLite].add(repeatedGroupExtensionLite { a = 217 })
+ this[UnittestLite.repeatedNestedMessageExtensionLite].add(
+ TestAllTypesLiteKt.nestedMessage { bb = 218 }
+ )
+ this[UnittestLite.repeatedForeignMessageExtensionLite].add(foreignMessageLite { c = 219 })
+ this[UnittestLite.repeatedImportMessageExtensionLite].add(
+ ImportMessageLite.newBuilder().setD(220).build()
+ )
+ this[UnittestLite.repeatedLazyMessageExtensionLite].add(
+ TestAllTypesLiteKt.nestedMessage { bb = 227 }
+ )
+ this[UnittestLite.repeatedNestedEnumExtensionLite].add(NestedEnum.BAR)
+ this[UnittestLite.repeatedForeignEnumExtensionLite].add(ForeignEnumLite.FOREIGN_LITE_BAR)
+ this[UnittestLite.repeatedImportEnumExtensionLite].add(ImportEnumLite.IMPORT_LITE_BAR)
+ this[UnittestLite.repeatedStringPieceExtensionLite].add("224")
+ this[UnittestLite.repeatedCordExtensionLite].add("225")
+ this[UnittestLite.repeatedInt32ExtensionLite] += 301
+ this[UnittestLite.repeatedInt64ExtensionLite] += 302L
+ this[UnittestLite.repeatedUint32ExtensionLite] += 303
+ this[UnittestLite.repeatedUint64ExtensionLite] += 304L
+ this[UnittestLite.repeatedSint32ExtensionLite] += 305
+ this[UnittestLite.repeatedSint64ExtensionLite] += 306L
+ this[UnittestLite.repeatedFixed32ExtensionLite] += 307
+ this[UnittestLite.repeatedFixed64ExtensionLite] += 308L
+ this[UnittestLite.repeatedSfixed32ExtensionLite] += 309
+ this[UnittestLite.repeatedSfixed64ExtensionLite] += 310L
+ this[UnittestLite.repeatedFloatExtensionLite] += 311F
+ this[UnittestLite.repeatedDoubleExtensionLite] += 312.0
+ this[UnittestLite.repeatedBoolExtensionLite] += false
+ this[UnittestLite.repeatedStringExtensionLite] += "315"
+ this[UnittestLite.repeatedBytesExtensionLite] += toBytes("316")
+ this[UnittestLite.repeatedGroupExtensionLite] += repeatedGroupExtensionLite { a = 317 }
+ this[UnittestLite.repeatedNestedMessageExtensionLite] +=
+ TestAllTypesLiteKt.nestedMessage { bb = 318 }
+ this[UnittestLite.repeatedForeignMessageExtensionLite] += foreignMessageLite { c = 319 }
+ this[UnittestLite.repeatedImportMessageExtensionLite] +=
+ ImportMessageLite.newBuilder().setD(320).build()
+ this[UnittestLite.repeatedLazyMessageExtensionLite] +=
+ TestAllTypesLiteKt.nestedMessage { bb = 327 }
+ this[UnittestLite.repeatedNestedEnumExtensionLite] += NestedEnum.BAZ
+ this[UnittestLite.repeatedForeignEnumExtensionLite] += ForeignEnumLite.FOREIGN_LITE_BAZ
+ this[UnittestLite.repeatedImportEnumExtensionLite] += ImportEnumLite.IMPORT_LITE_BAZ
+ this[UnittestLite.repeatedStringPieceExtensionLite] += "324"
+ this[UnittestLite.repeatedCordExtensionLite] += "325"
+ this[UnittestLite.defaultInt32ExtensionLite] = 401
+ this[UnittestLite.defaultInt64ExtensionLite] = 402L
+ this[UnittestLite.defaultUint32ExtensionLite] = 403
+ this[UnittestLite.defaultUint64ExtensionLite] = 404L
+ this[UnittestLite.defaultSint32ExtensionLite] = 405
+ this[UnittestLite.defaultSint64ExtensionLite] = 406L
+ this[UnittestLite.defaultFixed32ExtensionLite] = 407
+ this[UnittestLite.defaultFixed64ExtensionLite] = 408L
+ this[UnittestLite.defaultSfixed32ExtensionLite] = 409
+ this[UnittestLite.defaultSfixed64ExtensionLite] = 410L
+ this[UnittestLite.defaultFloatExtensionLite] = 411F
+ this[UnittestLite.defaultDoubleExtensionLite] = 412.0
+ this[UnittestLite.defaultBoolExtensionLite] = false
+ this[UnittestLite.defaultStringExtensionLite] = "415"
+ this[UnittestLite.defaultBytesExtensionLite] = toBytes("416")
+ this[UnittestLite.defaultNestedEnumExtensionLite] = NestedEnum.FOO
+ this[UnittestLite.defaultForeignEnumExtensionLite] = ForeignEnumLite.FOREIGN_LITE_FOO
+ this[UnittestLite.defaultImportEnumExtensionLite] = ImportEnumLite.IMPORT_LITE_FOO
+ this[UnittestLite.defaultStringPieceExtensionLite] = "424"
+ this[UnittestLite.defaultCordExtensionLite] = "425"
+ this[UnittestLite.oneofUint32ExtensionLite] = 601
+ this[UnittestLite.oneofNestedMessageExtensionLite] =
+ TestAllTypesLiteKt.nestedMessage { bb = 602 }
+ this[UnittestLite.oneofStringExtensionLite] = "603"
+ this[UnittestLite.oneofBytesExtensionLite] = toBytes("604")
+ }
+ ).isEqualTo(
+ TestUtilLite.getAllLiteExtensionsSet()
+ )
+ }
+
+ @Test
+ fun testExtensionGetters() {
+ testAllExtensionsLite {
+ this[UnittestLite.optionalInt32ExtensionLite] = 101
+ assertThat(this[UnittestLite.optionalInt32ExtensionLite]).isEqualTo(101)
+ this[UnittestLite.optionalStringExtensionLite] = "115"
+ assertThat(this[UnittestLite.optionalStringExtensionLite]).isEqualTo("115")
+ this[UnittestLite.optionalGroupExtensionLite] = optionalGroupExtensionLite { a = 117 }
+ assertThat(this[UnittestLite.optionalGroupExtensionLite])
+ .isEqualTo(optionalGroupExtensionLite { a = 117 })
+ this[UnittestLite.optionalNestedMessageExtensionLite] =
+ TestAllTypesLiteKt.nestedMessage { bb = 118 }
+ assertThat(this[UnittestLite.optionalNestedMessageExtensionLite])
+ .isEqualTo(TestAllTypesLiteKt.nestedMessage { bb = 118 })
+ this[UnittestLite.optionalNestedEnumExtensionLite] = NestedEnum.BAZ
+ assertThat(this[UnittestLite.optionalNestedEnumExtensionLite]).isEqualTo(NestedEnum.BAZ)
+ this[UnittestLite.defaultInt32ExtensionLite] = 401
+ assertThat(this[UnittestLite.defaultInt32ExtensionLite]).isEqualTo(401)
+ this[UnittestLite.oneofUint32ExtensionLite] = 601
+ assertThat(this[UnittestLite.oneofUint32ExtensionLite]).isEqualTo(601)
+ }
+ }
+
+ @Test
+ fun testRepeatedExtensionGettersAndSetters() {
+ testAllExtensionsLite {
+ this[UnittestLite.repeatedInt32ExtensionLite].addAll(listOf(1, 2))
+ assertThat(this[UnittestLite.repeatedInt32ExtensionLite]).isEqualTo(listOf(1, 2))
+ this[UnittestLite.repeatedInt32ExtensionLite] += listOf(3, 4)
+ assertThat(this[UnittestLite.repeatedInt32ExtensionLite]).isEqualTo(listOf(1, 2, 3, 4))
+ this[UnittestLite.repeatedInt32ExtensionLite][0] = 5
+ assertThat(this[UnittestLite.repeatedInt32ExtensionLite]).isEqualTo(listOf(5, 2, 3, 4))
+
+ this[UnittestLite.repeatedStringExtensionLite].addAll(listOf("1", "2"))
+ assertThat(this[UnittestLite.repeatedStringExtensionLite]).isEqualTo(listOf("1", "2"))
+ this[UnittestLite.repeatedStringExtensionLite] += listOf("3", "4")
+ assertThat(this[UnittestLite.repeatedStringExtensionLite])
+ .isEqualTo(listOf("1", "2", "3", "4"))
+ this[UnittestLite.repeatedStringExtensionLite][0] = "5"
+ assertThat(this[UnittestLite.repeatedStringExtensionLite])
+ .isEqualTo(listOf("5", "2", "3", "4"))
+
+ this[UnittestLite.repeatedGroupExtensionLite].addAll(
+ listOf(
+ repeatedGroupExtensionLite { a = 1 },
+ repeatedGroupExtensionLite { a = 2 }
+ )
+ )
+ assertThat(this[UnittestLite.repeatedGroupExtensionLite]).isEqualTo(
+ listOf(
+ repeatedGroupExtensionLite { a = 1 },
+ repeatedGroupExtensionLite { a = 2 }
+ )
+ )
+ this[UnittestLite.repeatedGroupExtensionLite] +=
+ listOf(
+ repeatedGroupExtensionLite { a = 3 },
+ repeatedGroupExtensionLite { a = 4 }
+ )
+ assertThat(this[UnittestLite.repeatedGroupExtensionLite]).isEqualTo(
+ listOf(
+ repeatedGroupExtensionLite { a = 1 },
+ repeatedGroupExtensionLite { a = 2 },
+ repeatedGroupExtensionLite { a = 3 },
+ repeatedGroupExtensionLite { a = 4 }
+ )
+ )
+ this[UnittestLite.repeatedGroupExtensionLite][0] = repeatedGroupExtensionLite { a = 5 }
+ assertThat(this[UnittestLite.repeatedGroupExtensionLite]).isEqualTo(
+ listOf(
+ repeatedGroupExtensionLite { a = 5 },
+ repeatedGroupExtensionLite { a = 2 },
+ repeatedGroupExtensionLite { a = 3 },
+ repeatedGroupExtensionLite { a = 4 }
+ )
+ )
+
+ this[UnittestLite.repeatedNestedMessageExtensionLite].addAll(
+ listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 })
+ )
+ assertThat(this[UnittestLite.repeatedNestedMessageExtensionLite]).isEqualTo(
+ listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 })
+ )
+ this[UnittestLite.repeatedNestedMessageExtensionLite] +=
+ listOf(nestedMessage { bb = 3 }, nestedMessage { bb = 4 })
+ assertThat(this[UnittestLite.repeatedNestedMessageExtensionLite]).isEqualTo(
+ listOf(
+ nestedMessage { bb = 1 },
+ nestedMessage { bb = 2 },
+ nestedMessage { bb = 3 },
+ nestedMessage { bb = 4 }
+ )
+ )
+ this[UnittestLite.repeatedNestedMessageExtensionLite][0] = nestedMessage { bb = 5 }
+ assertThat(this[UnittestLite.repeatedNestedMessageExtensionLite]).isEqualTo(
+ listOf(
+ nestedMessage { bb = 5 },
+ nestedMessage { bb = 2 },
+ nestedMessage { bb = 3 },
+ nestedMessage { bb = 4 }
+ )
+ )
+
+ this[UnittestLite.repeatedNestedEnumExtensionLite]
+ .addAll(listOf(NestedEnum.FOO, NestedEnum.BAR))
+ assertThat(this[UnittestLite.repeatedNestedEnumExtensionLite])
+ .isEqualTo(listOf(NestedEnum.FOO, NestedEnum.BAR))
+ this[UnittestLite.repeatedNestedEnumExtensionLite] += listOf(NestedEnum.BAZ, NestedEnum.FOO)
+ assertThat(this[UnittestLite.repeatedNestedEnumExtensionLite]).isEqualTo(
+ listOf(NestedEnum.FOO, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
+ )
+ this[UnittestLite.repeatedNestedEnumExtensionLite][0] = NestedEnum.BAR
+ assertThat(this[UnittestLite.repeatedNestedEnumExtensionLite]).isEqualTo(
+ listOf(NestedEnum.BAR, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
+ )
+ }
+ }
+
+ @Test
+ fun testExtensionContains() {
+ testAllExtensionsLite {
+ this[UnittestLite.optionalInt32ExtensionLite] = 101
+ assertThat(contains(UnittestLite.optionalInt32ExtensionLite)).isTrue()
+ assertThat(contains(UnittestLite.optionalStringExtensionLite)).isFalse()
+ this[UnittestLite.optionalGroupExtensionLite] = optionalGroupExtensionLite { a = 117 }
+ assertThat(contains(UnittestLite.optionalGroupExtensionLite)).isTrue()
+ assertThat(contains(UnittestLite.optionalNestedMessageExtensionLite)).isFalse()
+ this[UnittestLite.optionalNestedEnumExtensionLite] = NestedEnum.BAZ
+ assertThat(contains(UnittestLite.optionalNestedEnumExtensionLite)).isTrue()
+ assertThat(contains(UnittestLite.defaultInt32ExtensionLite)).isFalse()
+ this[UnittestLite.oneofUint32ExtensionLite] = 601
+ assertThat(contains(UnittestLite.oneofUint32ExtensionLite)).isTrue()
+ }
+
+ testAllExtensionsLite {
+ assertThat(contains(UnittestLite.optionalInt32ExtensionLite)).isFalse()
+ this[UnittestLite.optionalStringExtensionLite] = "115"
+ assertThat(contains(UnittestLite.optionalStringExtensionLite)).isTrue()
+ assertThat(contains(UnittestLite.optionalGroupExtensionLite)).isFalse()
+ this[UnittestLite.optionalNestedMessageExtensionLite] =
+ TestAllTypesLiteKt.nestedMessage { bb = 118 }
+ assertThat(contains(UnittestLite.optionalNestedMessageExtensionLite)).isTrue()
+ assertThat(contains(UnittestLite.optionalNestedEnumExtensionLite)).isFalse()
+ this[UnittestLite.defaultInt32ExtensionLite] = 401
+ assertThat(contains(UnittestLite.defaultInt32ExtensionLite)).isTrue()
+ assertThat(contains(UnittestLite.oneofUint32ExtensionLite)).isFalse()
+ }
+ }
+
+ @Test
+ fun testExtensionClears() {
+ testAllExtensionsLite {
+ this[UnittestLite.optionalInt32ExtensionLite] = 101
+ clear(UnittestLite.optionalInt32ExtensionLite)
+ assertThat(contains(UnittestLite.optionalInt32ExtensionLite)).isFalse()
+
+ this[UnittestLite.optionalStringExtensionLite] = "115"
+ clear(UnittestLite.optionalStringExtensionLite)
+ assertThat(contains(UnittestLite.optionalStringExtensionLite)).isFalse()
+
+ this[UnittestLite.optionalGroupExtensionLite] = optionalGroupExtensionLite { a = 117 }
+ clear(UnittestLite.optionalGroupExtensionLite)
+ assertThat(contains(UnittestLite.optionalGroupExtensionLite)).isFalse()
+
+ this[UnittestLite.optionalNestedMessageExtensionLite] =
+ TestAllTypesLiteKt.nestedMessage { bb = 118 }
+ clear(UnittestLite.optionalNestedMessageExtensionLite)
+ assertThat(contains(UnittestLite.optionalNestedMessageExtensionLite)).isFalse()
+
+ this[UnittestLite.optionalNestedEnumExtensionLite] = NestedEnum.BAZ
+ clear(UnittestLite.optionalNestedEnumExtensionLite)
+ assertThat(contains(UnittestLite.optionalNestedEnumExtensionLite)).isFalse()
+
+ this[UnittestLite.defaultInt32ExtensionLite] = 401
+ clear(UnittestLite.defaultInt32ExtensionLite)
+ assertThat(contains(UnittestLite.defaultInt32ExtensionLite)).isFalse()
+
+ this[UnittestLite.oneofUint32ExtensionLite] = 601
+ clear(UnittestLite.oneofUint32ExtensionLite)
+ assertThat(contains(UnittestLite.oneofUint32ExtensionLite)).isFalse()
+ }
+ }
+
+ @Test
+ fun testEmptyMessages() {
+ assertThat(
+ testEmptyMessageLite {}
+ ).isEqualTo(
+ TestEmptyMessageLite.newBuilder().build()
+ )
+
+ assertThat(
+ testEmptyMessageWithExtensionsLite {}
+ ).isEqualTo(
+ TestEmptyMessageWithExtensionsLite.newBuilder().build()
+ )
+ }
+
+ @Test
+ fun testMapSetters() {
+ assertThat(
+ testMapLite {
+ mapInt32Int32[1] = 2
+ mapInt64Int64[1L] = 2L
+ mapUint32Uint32[1] = 2
+ mapUint64Uint64[1L] = 2L
+ mapSint32Sint32[1] = 2
+ mapSint64Sint64[1L] = 2L
+ mapFixed32Fixed32[1] = 2
+ mapFixed64Fixed64[1L] = 2L
+ mapSfixed32Sfixed32[1] = 2
+ mapSfixed64Sfixed64[1L] = 2L
+ mapInt32Float[1] = 2F
+ mapInt32Double[1] = 2.0
+ mapBoolBool[true] = true
+ mapStringString["1"] = "2"
+ mapInt32Bytes[1] = toBytes("2")
+ mapInt32Enum[1] = MapEnumLite.MAP_ENUM_FOO_LITE
+ mapInt32ForeignMessage[1] = foreignMessageLite { c = 1 }
+ }
+ ).isEqualTo(
+ TestMapLite.newBuilder()
+ .putMapInt32Int32(1, 2)
+ .putMapInt64Int64(1L, 2L)
+ .putMapUint32Uint32(1, 2)
+ .putMapUint64Uint64(1L, 2L)
+ .putMapSint32Sint32(1, 2)
+ .putMapSint64Sint64(1L, 2L)
+ .putMapFixed32Fixed32(1, 2)
+ .putMapFixed64Fixed64(1L, 2L)
+ .putMapSfixed32Sfixed32(1, 2)
+ .putMapSfixed64Sfixed64(1L, 2L)
+ .putMapInt32Float(1, 2F)
+ .putMapInt32Double(1, 2.0)
+ .putMapBoolBool(true, true)
+ .putMapStringString("1", "2")
+ .putMapInt32Bytes(1, toBytes("2"))
+ .putMapInt32Enum(1, MapEnumLite.MAP_ENUM_FOO_LITE)
+ .putMapInt32ForeignMessage(1, foreignMessageLite { c = 1 })
+ .build()
+ )
+ }
+
+ @Test
+ fun testMapGettersAndSetters() {
+ testMapLite {
+ mapInt32Int32.put(1, 2)
+ assertThat(mapInt32Int32).isEqualTo(mapOf(1 to 2))
+ mapInt32Int32[3] = 4
+ assertThat(mapInt32Int32).isEqualTo(mapOf(1 to 2, 3 to 4))
+ mapInt32Int32.putAll(mapOf(5 to 6, 7 to 8))
+ assertThat(mapInt32Int32).isEqualTo(mapOf(1 to 2, 3 to 4, 5 to 6, 7 to 8))
+
+ mapStringString.put("1", "2")
+ assertThat(mapStringString).isEqualTo(mapOf("1" to "2"))
+ mapStringString["3"] = "4"
+ assertThat(mapStringString).isEqualTo(mapOf("1" to "2", "3" to "4"))
+ mapStringString.putAll(mapOf("5" to "6", "7" to "8"))
+ assertThat(mapStringString).isEqualTo(mapOf("1" to "2", "3" to "4", "5" to "6", "7" to "8"))
+
+ mapInt32Enum.put(1, MapEnumLite.MAP_ENUM_FOO_LITE)
+ assertThat(mapInt32Enum).isEqualTo(mapOf(1 to MapEnumLite.MAP_ENUM_FOO_LITE))
+ mapInt32Enum[2] = MapEnumLite.MAP_ENUM_BAR_LITE
+ assertThat(mapInt32Enum).isEqualTo(
+ mapOf(1 to MapEnumLite.MAP_ENUM_FOO_LITE, 2 to MapEnumLite.MAP_ENUM_BAR_LITE)
+ )
+ mapInt32Enum.putAll(
+ mapOf(3 to MapEnumLite.MAP_ENUM_BAZ_LITE, 4 to MapEnumLite.MAP_ENUM_FOO_LITE)
+ )
+ assertThat(mapInt32Enum).isEqualTo(
+ mapOf(
+ 1 to MapEnumLite.MAP_ENUM_FOO_LITE,
+ 2 to MapEnumLite.MAP_ENUM_BAR_LITE,
+ 3 to MapEnumLite.MAP_ENUM_BAZ_LITE,
+ 4 to MapEnumLite.MAP_ENUM_FOO_LITE
+ )
+ )
+
+ mapInt32ForeignMessage.put(1, foreignMessageLite { c = 1 })
+ assertThat(mapInt32ForeignMessage).isEqualTo(mapOf(1 to foreignMessageLite { c = 1 }))
+ mapInt32ForeignMessage[2] = foreignMessageLite { c = 2 }
+ assertThat(mapInt32ForeignMessage).isEqualTo(
+ mapOf(1 to foreignMessageLite { c = 1 }, 2 to foreignMessageLite { c = 2 })
+ )
+ mapInt32ForeignMessage.putAll(
+ mapOf(3 to foreignMessageLite { c = 3 }, 4 to foreignMessageLite { c = 4 })
+ )
+ assertThat(mapInt32ForeignMessage).isEqualTo(
+ mapOf(
+ 1 to foreignMessageLite { c = 1 },
+ 2 to foreignMessageLite { c = 2 },
+ 3 to foreignMessageLite { c = 3 },
+ 4 to foreignMessageLite { c = 4 }
+ )
+ )
+ }
+ }
+
+ @Test
+ fun testMapRemove() {
+ testMapLite {
+ mapInt32Int32.putAll(mapOf(1 to 2, 3 to 4))
+ mapInt32Int32.remove(1)
+ assertThat(mapInt32Int32).isEqualTo(mapOf(3 to 4))
+
+ mapStringString.putAll(mapOf("1" to "2", "3" to "4"))
+ mapStringString.remove("1")
+ assertThat(mapStringString).isEqualTo(mapOf("3" to "4"))
+
+ mapInt32Enum.putAll(
+ mapOf(1 to MapEnumLite.MAP_ENUM_FOO_LITE, 2 to MapEnumLite.MAP_ENUM_BAR_LITE)
+ )
+ mapInt32Enum.remove(1)
+ assertThat(mapInt32Enum).isEqualTo(mapOf(2 to MapEnumLite.MAP_ENUM_BAR_LITE))
+
+ mapInt32ForeignMessage.putAll(
+ mapOf(1 to foreignMessageLite { c = 1 }, 2 to foreignMessageLite { c = 2 })
+ )
+ mapInt32ForeignMessage.remove(1)
+ assertThat(mapInt32ForeignMessage).isEqualTo(mapOf(2 to foreignMessageLite { c = 2 }))
+ }
+ }
+
+ @Test
+ fun testMapClear() {
+ testMapLite {
+ mapInt32Int32.putAll(mapOf(1 to 2, 3 to 4))
+ mapInt32Int32.clear()
+ assertThat(mapInt32Int32.isEmpty()).isTrue()
+
+ mapStringString.putAll(mapOf("1" to "2", "3" to "4"))
+ mapStringString.clear()
+ assertThat(mapStringString.isEmpty()).isTrue()
+
+ mapInt32Enum.putAll(
+ mapOf(1 to MapEnumLite.MAP_ENUM_FOO_LITE, 2 to MapEnumLite.MAP_ENUM_BAR_LITE)
+ )
+ mapInt32Enum.clear()
+ assertThat(mapInt32Enum.isEmpty()).isTrue()
+
+ mapInt32ForeignMessage.putAll(
+ mapOf(1 to foreignMessageLite { c = 1 }, 2 to foreignMessageLite { c = 2 })
+ )
+ mapInt32ForeignMessage.clear()
+ assertThat(mapInt32ForeignMessage.isEmpty()).isTrue()
+ }
+ }
+
+ @Test
+ fun testEvilNames() {
+ assertThat(
+ evilNamesProto2 {
+ initialized = true
+ hasFoo = true
+ bar = "foo"
+ isInitialized = true
+ fooBar = "foo"
+ aLLCAPS += "foo"
+ aLLCAPSMAP[1] = true
+ hasUnderbarPrecedingNumeric1Foo = true
+ hasUnderbarPrecedingNumeric42Bar = true
+ hasUnderbarPrecedingNumeric123Foo42BarBaz = true
+ extension += "foo"
+ class_ += 1
+ int = 1.0
+ long = true
+ boolean = 1L
+ sealed = "foo"
+ interface_ = 1F
+ in_ = 1
+ object_ = "foo"
+ cachedSize_ = "foo"
+ serializedSize_ = true
+ by = "foo"
+ }
+ ).isEqualTo(
+ EvilNamesProto2.newBuilder()
+ .setInitialized(true)
+ .setHasFoo(true)
+ .setBar("foo")
+ .setIsInitialized(true)
+ .setFooBar("foo")
+ .addALLCAPS("foo")
+ .putALLCAPSMAP(1, true)
+ .setHasUnderbarPrecedingNumeric1Foo(true)
+ .setHasUnderbarPrecedingNumeric42Bar(true)
+ .setHasUnderbarPrecedingNumeric123Foo42BarBaz(true)
+ .addExtension("foo")
+ .addClass_(1)
+ .setInt(1.0)
+ .setLong(true)
+ .setBoolean(1L)
+ .setSealed("foo")
+ .setInterface(1F)
+ .setIn(1)
+ .setObject("foo")
+ .setCachedSize_("foo")
+ .setSerializedSize_(true)
+ .setBy("foo")
+ .build()
+ )
+
+ assertThat(interface_ {}).isEqualTo(Interface.newBuilder().build())
+ }
+
+ @Test
+ fun testHardKeywordGettersAndSetters() {
+ hardKeywordsAllTypes {
+ as_ = 1
+ assertThat(as_).isEqualTo(1)
+
+ in_ = "foo"
+ assertThat(in_).isEqualTo("foo")
+
+ break_ = HardKeywordsAllTypes.NestedEnum.FOO
+ assertThat(break_).isEqualTo(HardKeywordsAllTypes.NestedEnum.FOO)
+
+ do_ = HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ assertThat(do_).isEqualTo(HardKeywordsAllTypesKt.nestedMessage { while_ = 1 })
+
+ continue_[1] = 1
+ assertThat(continue_[1]).isEqualTo(1)
+
+ else_ += 1
+ assertThat(else_).isEqualTo(listOf(1))
+
+ for_ += "foo"
+ assertThat(for_).isEqualTo(listOf("foo"))
+
+ fun_ += HardKeywordsAllTypes.NestedEnum.FOO
+ assertThat(fun_).isEqualTo(listOf(HardKeywordsAllTypes.NestedEnum.FOO))
+
+ if_ += HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ assertThat(if_).isEqualTo(listOf(HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }))
+ }
+ }
+
+ @Test
+ fun testHardKeywordHazzers() {
+ hardKeywordsAllTypes {
+ as_ = 1
+ assertThat(hasAs_()).isTrue()
+
+ in_ = "foo"
+ assertThat(hasIn_()).isTrue()
+
+ break_ = HardKeywordsAllTypes.NestedEnum.FOO
+ assertThat(hasBreak_()).isTrue()
+
+ do_ = HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ assertThat(hasDo_()).isTrue()
+ }
+ }
+
+ @Test
+ fun testHardKeywordClears() {
+ hardKeywordsAllTypes {
+ as_ = 1
+ clearAs_()
+ assertThat(hasAs_()).isFalse()
+
+ in_ = "foo"
+ clearIn_()
+ assertThat(hasIn_()).isFalse()
+
+ break_ = HardKeywordsAllTypes.NestedEnum.FOO
+ clearBreak_()
+ assertThat(hasBreak_()).isFalse()
+
+ do_ = HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ clearDo_()
+ assertThat(hasDo_()).isFalse()
+ }
+ }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/kotlin/Proto2Test.kt b/java/core/src/test/java/com/google/protobuf/kotlin/Proto2Test.kt
new file mode 100644
index 0000000000..e2c471ba59
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/kotlin/Proto2Test.kt
@@ -0,0 +1,980 @@
+package com.google.protobuf.kotlin
+
+import com.google.common.truth.Truth.assertThat
+import com.google.protobuf.TestUtil
+import com.google.protobuf.TestUtil.toBytes
+import com.google.protobuf.kotlin.generator.EvilNamesProto2OuterClass.EvilNamesProto2
+import com.google.protobuf.kotlin.generator.EvilNamesProto2OuterClass.HardKeywordsAllTypes
+import com.google.protobuf.kotlin.generator.EvilNamesProto2OuterClass.Interface
+import com.google.protobuf.kotlin.generator.HardKeywordsAllTypesKt
+import com.google.protobuf.kotlin.generator.evilNamesProto2
+import com.google.protobuf.kotlin.generator.hardKeywordsAllTypes
+import com.google.protobuf.kotlin.generator.interface_
+import com.google.protobuf.test.UnittestImport.ImportEnum
+import com.google.protobuf.test.UnittestImport.ImportMessage
+import com.google.protobuf.test.UnittestImportPublic.PublicImportMessage
+import com.google.protos.proto2_unittest.MapProto2Unittest.Proto2MapEnum
+import com.google.protos.proto2_unittest.MapProto2Unittest.TestEnumMap
+import com.google.protos.proto2_unittest.MapProto2Unittest.TestIntIntMap
+import com.google.protos.proto2_unittest.MapProto2Unittest.TestMaps
+import com.google.protos.proto2_unittest.TestAllTypesKt
+import com.google.protos.proto2_unittest.TestAllTypesKt.nestedMessage
+import com.google.protos.proto2_unittest.UnittestProto
+import com.google.protos.proto2_unittest.UnittestProto.ForeignEnum
+import com.google.protos.proto2_unittest.UnittestProto.TestAllTypes
+import com.google.protos.proto2_unittest.UnittestProto.TestAllTypes.NestedEnum
+import com.google.protos.proto2_unittest.UnittestProto.TestEmptyMessage
+import com.google.protos.proto2_unittest.UnittestProto.TestEmptyMessageWithExtensions
+import com.google.protos.proto2_unittest.copy
+import com.google.protos.proto2_unittest.foreignMessage
+import com.google.protos.proto2_unittest.optionalGroupExtension
+import com.google.protos.proto2_unittest.repeatedGroupExtension
+import com.google.protos.proto2_unittest.testAllExtensions
+import com.google.protos.proto2_unittest.testAllTypes
+import com.google.protos.proto2_unittest.testEmptyMessage
+import com.google.protos.proto2_unittest.testEmptyMessageWithExtensions
+import com.google.protos.proto2_unittest.testEnumMap
+import com.google.protos.proto2_unittest.testIntIntMap
+import com.google.protos.proto2_unittest.testMaps
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class Proto2Test {
+ @Test
+ fun testSetters() {
+ assertThat(
+ testAllTypes {
+ optionalInt32 = 101
+ optionalInt64 = 102
+ optionalUint32 = 103
+ optionalUint64 = 104
+ optionalSint32 = 105
+ optionalSint64 = 106
+ optionalFixed32 = 107
+ optionalFixed64 = 108
+ optionalSfixed32 = 109
+ optionalSfixed64 = 110
+ optionalFloat = 111.0f
+ optionalDouble = 112.0
+ optionalBool = true
+ optionalString = "115"
+ optionalBytes = toBytes("116")
+ optionalGroup =
+ TestAllTypesKt.optionalGroup { a = 117 }
+ optionalNestedMessage = nestedMessage { bb = 118 }
+ optionalForeignMessage = foreignMessage { c = 119 }
+ optionalImportMessage =
+ ImportMessage.newBuilder().setD(120).build()
+ optionalPublicImportMessage =
+ PublicImportMessage.newBuilder().setE(126).build()
+ optionalLazyMessage = nestedMessage { bb = 127 }
+ optionalNestedEnum = NestedEnum.BAZ
+ optionalForeignEnum = ForeignEnum.FOREIGN_BAZ
+ optionalImportEnum = ImportEnum.IMPORT_BAZ
+ optionalStringPiece = "124"
+ optionalCord = "125"
+ repeatedInt32.add(201)
+ repeatedInt64.add(202)
+ repeatedUint32.add(203)
+ repeatedUint64.add(204)
+ repeatedSint32.add(205)
+ repeatedSint64.add(206)
+ repeatedFixed32.add(207)
+ repeatedFixed64.add(208)
+ repeatedSfixed32.add(209)
+ repeatedSfixed64.add(210)
+ repeatedFloat.add(211f)
+ repeatedDouble.add(212.0)
+ repeatedBool.add(true)
+ repeatedString.add("215")
+ repeatedBytes.add(toBytes("216"))
+ repeatedGroup.add(TestAllTypesKt.repeatedGroup { a = 217 })
+ repeatedNestedMessage.add(nestedMessage { bb = 218 })
+ repeatedForeignMessage.add(foreignMessage { c = 219 })
+ repeatedImportMessage.add(
+ ImportMessage.newBuilder().setD(220).build()
+ )
+ repeatedLazyMessage.add(nestedMessage { bb = 227 })
+ repeatedNestedEnum.add(NestedEnum.BAR)
+ repeatedForeignEnum.add(ForeignEnum.FOREIGN_BAR)
+ repeatedImportEnum.add(ImportEnum.IMPORT_BAR)
+ repeatedStringPiece.add("224")
+ repeatedCord.add("225")
+ repeatedInt32 += 301
+ repeatedInt64 += 302
+ repeatedUint32 += 303
+ repeatedUint64 += 304
+ repeatedSint32 += 305
+ repeatedSint64 += 306
+ repeatedFixed32 += 307
+ repeatedFixed64 += 308
+ repeatedSfixed32 += 309
+ repeatedSfixed64 += 310
+ repeatedFloat += 311f
+ repeatedDouble += 312.0
+ repeatedBool += false
+ repeatedString += "315"
+ repeatedBytes += toBytes("316")
+ repeatedGroup += TestAllTypesKt.repeatedGroup { a = 317 }
+ repeatedNestedMessage += nestedMessage { bb = 318 }
+ repeatedForeignMessage += foreignMessage { c = 319 }
+ repeatedImportMessage +=
+ ImportMessage.newBuilder().setD(320).build()
+ repeatedLazyMessage +=
+ TestAllTypesKt.nestedMessage { bb = 327 }
+ repeatedNestedEnum += NestedEnum.BAZ
+ repeatedForeignEnum += ForeignEnum.FOREIGN_BAZ
+ repeatedImportEnum += ImportEnum.IMPORT_BAZ
+ repeatedStringPiece += "324"
+ repeatedCord += "325"
+ defaultInt32 = 401
+ defaultInt64 = 402
+ defaultUint32 = 403
+ defaultUint64 = 404
+ defaultSint32 = 405
+ defaultSint64 = 406
+ defaultFixed32 = 407
+ defaultFixed64 = 408
+ defaultSfixed32 = 409
+ defaultSfixed64 = 410
+ defaultFloat = 411f
+ defaultDouble = 412.0
+ defaultBool = false
+ defaultString = "415"
+ defaultBytes = toBytes("416")
+ defaultNestedEnum = NestedEnum.FOO
+ defaultForeignEnum = ForeignEnum.FOREIGN_FOO
+ defaultImportEnum = ImportEnum.IMPORT_FOO
+ defaultStringPiece = "424"
+ defaultCord = "425"
+ oneofUint32 = 601
+ oneofNestedMessage =
+ TestAllTypesKt.nestedMessage { bb = 602 }
+ oneofString = "603"
+ oneofBytes = toBytes("604")
+ }
+ ).isEqualTo(
+ TestUtil.getAllSetBuilder().build()
+ )
+ }
+
+ @Test
+ fun testGetters() {
+ testAllTypes {
+ optionalInt32 = 101
+ assertThat(optionalInt32).isEqualTo(101)
+ optionalString = "115"
+ assertThat(optionalString).isEqualTo("115")
+ optionalGroup = TestAllTypesKt.optionalGroup { a = 117 }
+ assertThat(optionalGroup).isEqualTo(TestAllTypesKt.optionalGroup { a = 117 })
+ optionalNestedMessage = TestAllTypesKt.nestedMessage { bb = 118 }
+ assertThat(optionalNestedMessage).isEqualTo(TestAllTypesKt.nestedMessage { bb = 118 })
+ optionalNestedEnum = NestedEnum.BAZ
+ assertThat(optionalNestedEnum).isEqualTo(NestedEnum.BAZ)
+ defaultInt32 = 401
+ assertThat(defaultInt32).isEqualTo(401)
+ oneofUint32 = 601
+ assertThat(oneofUint32).isEqualTo(601)
+ }
+ }
+
+ @Test
+ fun testDefaultGetters() {
+ testAllTypes {
+ assertThat(defaultInt32).isEqualTo(41)
+ assertThat(defaultString).isEqualTo("hello")
+ assertThat(defaultNestedEnum).isEqualTo(NestedEnum.BAR)
+ assertThat(defaultStringPiece).isEqualTo("abc")
+ }
+ }
+
+ @Test
+ fun testRepeatedGettersAndSetters() {
+ testAllTypes {
+ repeatedInt32.addAll(listOf(1, 2))
+ assertThat(repeatedInt32).isEqualTo(listOf(1, 2))
+ repeatedInt32 += listOf(3, 4)
+ assertThat(repeatedInt32).isEqualTo(listOf(1, 2, 3, 4))
+ repeatedInt32[0] = 5
+ assertThat(repeatedInt32).isEqualTo(listOf(5, 2, 3, 4))
+
+ repeatedString.addAll(listOf("1", "2"))
+ assertThat(repeatedString).isEqualTo(listOf("1", "2"))
+ repeatedString += listOf("3", "4")
+ assertThat(repeatedString).isEqualTo(listOf("1", "2", "3", "4"))
+ repeatedString[0] = "5"
+ assertThat(repeatedString).isEqualTo(listOf("5", "2", "3", "4"))
+
+ repeatedGroup.addAll(
+ listOf(
+ TestAllTypesKt.repeatedGroup { a = 1 },
+ TestAllTypesKt.repeatedGroup { a = 2 }
+ )
+ )
+ assertThat(repeatedGroup).isEqualTo(
+ listOf(
+ TestAllTypesKt.repeatedGroup { a = 1 },
+ TestAllTypesKt.repeatedGroup { a = 2 }
+ )
+ )
+ repeatedGroup +=
+ listOf(
+ TestAllTypesKt.repeatedGroup { a = 3 },
+ TestAllTypesKt.repeatedGroup { a = 4 }
+ )
+ assertThat(repeatedGroup).isEqualTo(
+ listOf(
+ TestAllTypesKt.repeatedGroup { a = 1 },
+ TestAllTypesKt.repeatedGroup { a = 2 },
+ TestAllTypesKt.repeatedGroup { a = 3 },
+ TestAllTypesKt.repeatedGroup { a = 4 }
+ )
+ )
+ repeatedGroup[0] = TestAllTypesKt.repeatedGroup { a = 5 }
+ assertThat(repeatedGroup).isEqualTo(
+ listOf(
+ TestAllTypesKt.repeatedGroup { a = 5 },
+ TestAllTypesKt.repeatedGroup { a = 2 },
+ TestAllTypesKt.repeatedGroup { a = 3 },
+ TestAllTypesKt.repeatedGroup { a = 4 }
+ )
+ )
+
+ repeatedNestedMessage.addAll(listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 }))
+ assertThat(repeatedNestedMessage).isEqualTo(
+ listOf(
+ nestedMessage { bb = 1 },
+ nestedMessage { bb = 2 }
+ )
+ )
+ repeatedNestedMessage += listOf(nestedMessage { bb = 3 }, nestedMessage { bb = 4 })
+ assertThat(repeatedNestedMessage).isEqualTo(
+ listOf(
+ nestedMessage { bb = 1 },
+ nestedMessage { bb = 2 },
+ nestedMessage { bb = 3 },
+ nestedMessage { bb = 4 }
+ )
+ )
+ repeatedNestedMessage[0] = nestedMessage { bb = 5 }
+ assertThat(repeatedNestedMessage).isEqualTo(
+ listOf(
+ nestedMessage { bb = 5 },
+ nestedMessage { bb = 2 },
+ nestedMessage { bb = 3 },
+ nestedMessage { bb = 4 }
+ )
+ )
+
+ repeatedNestedEnum.addAll(listOf(NestedEnum.FOO, NestedEnum.BAR))
+ assertThat(repeatedNestedEnum).isEqualTo(listOf(NestedEnum.FOO, NestedEnum.BAR))
+ repeatedNestedEnum += listOf(NestedEnum.BAZ, NestedEnum.FOO)
+ assertThat(repeatedNestedEnum).isEqualTo(
+ listOf(NestedEnum.FOO, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
+ )
+ repeatedNestedEnum[0] = NestedEnum.BAR
+ assertThat(repeatedNestedEnum).isEqualTo(
+ listOf(NestedEnum.BAR, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
+ )
+ }
+ }
+
+ @Test
+ fun testHazzers() {
+ testAllTypes {
+ optionalInt32 = 101
+ assertThat(hasOptionalInt32()).isTrue()
+ assertThat(hasOptionalString()).isFalse()
+ optionalGroup = TestAllTypesKt.optionalGroup { a = 117 }
+ assertThat(hasOptionalGroup()).isTrue()
+ assertThat(hasOptionalNestedMessage()).isFalse()
+ optionalNestedEnum = NestedEnum.BAZ
+ assertThat(hasOptionalNestedEnum()).isTrue()
+ assertThat(hasDefaultInt32()).isFalse()
+ oneofUint32 = 601
+ assertThat(hasOneofUint32()).isTrue()
+ }
+
+ testAllTypes {
+ assertThat(hasOptionalInt32()).isFalse()
+ optionalString = "115"
+ assertThat(hasOptionalString()).isTrue()
+ assertThat(hasOptionalGroup()).isFalse()
+ optionalNestedMessage = TestAllTypesKt.nestedMessage { bb = 118 }
+ assertThat(hasOptionalNestedMessage()).isTrue()
+ assertThat(hasOptionalNestedEnum()).isFalse()
+ defaultInt32 = 401
+ assertThat(hasDefaultInt32()).isTrue()
+ assertThat(hasOneofUint32()).isFalse()
+ }
+ }
+
+ @Test
+ fun testClears() {
+ testAllTypes {
+ optionalInt32 = 101
+ clearOptionalInt32()
+ assertThat(hasOptionalInt32()).isFalse()
+
+ optionalString = "115"
+ clearOptionalString()
+ assertThat(hasOptionalString()).isFalse()
+
+ optionalGroup = TestAllTypesKt.optionalGroup { a = 117 }
+ clearOptionalGroup()
+ assertThat(hasOptionalGroup()).isFalse()
+
+ optionalNestedMessage = TestAllTypesKt.nestedMessage { bb = 118 }
+ clearOptionalNestedMessage()
+ assertThat(hasOptionalNestedMessage()).isFalse()
+
+ optionalNestedEnum = NestedEnum.BAZ
+ clearOptionalNestedEnum()
+ assertThat(hasOptionalNestedEnum()).isFalse()
+
+ defaultInt32 = 401
+ clearDefaultInt32()
+ assertThat(hasDefaultInt32()).isFalse()
+
+ oneofUint32 = 601
+ clearOneofUint32()
+ assertThat(hasOneofUint32()).isFalse()
+ }
+ }
+
+ @Test
+ fun testCopy() {
+ val message = testAllTypes {
+ optionalInt32 = 101
+ optionalString = "115"
+ }
+ val modifiedMessage = message.copy {
+ optionalInt32 = 201
+ }
+
+ assertThat(message).isEqualTo(
+ TestAllTypes.newBuilder()
+ .setOptionalInt32(101)
+ .setOptionalString("115")
+ .build()
+ )
+ assertThat(modifiedMessage).isEqualTo(
+ TestAllTypes.newBuilder()
+ .setOptionalInt32(201)
+ .setOptionalString("115")
+ .build()
+ )
+ }
+
+ @Test
+ fun testOneof() {
+ val message = testAllTypes {
+ oneofString = "foo"
+ assertThat(oneofFieldCase)
+ .isEqualTo(TestAllTypes.OneofFieldCase.ONEOF_STRING)
+ assertThat(oneofString).isEqualTo("foo")
+ clearOneofField()
+ assertThat(hasOneofUint32()).isFalse()
+ assertThat(oneofFieldCase)
+ .isEqualTo(TestAllTypes.OneofFieldCase.ONEOFFIELD_NOT_SET)
+ oneofUint32 = 5
+ }
+
+ assertThat(message.getOneofFieldCase())
+ .isEqualTo(TestAllTypes.OneofFieldCase.ONEOF_UINT32)
+ assertThat(message.getOneofUint32()).isEqualTo(5)
+ }
+
+ @Test
+ fun testExtensionsSet() {
+ assertThat(
+ testAllExtensions {
+ this[UnittestProto.optionalInt32Extension] = 101
+ this[UnittestProto.optionalInt64Extension] = 102L
+ this[UnittestProto.optionalUint32Extension] = 103
+ this[UnittestProto.optionalUint64Extension] = 104L
+ this[UnittestProto.optionalSint32Extension] = 105
+ this[UnittestProto.optionalSint64Extension] = 106L
+ this[UnittestProto.optionalFixed32Extension] = 107
+ this[UnittestProto.optionalFixed64Extension] = 108L
+ this[UnittestProto.optionalSfixed32Extension] = 109
+ this[UnittestProto.optionalSfixed64Extension] = 110L
+ this[UnittestProto.optionalFloatExtension] = 111F
+ this[UnittestProto.optionalDoubleExtension] = 112.0
+ this[UnittestProto.optionalBoolExtension] = true
+ this[UnittestProto.optionalStringExtension] = "115"
+ this[UnittestProto.optionalBytesExtension] = toBytes("116")
+ this[UnittestProto.optionalGroupExtension] = optionalGroupExtension { a = 117 }
+ this[UnittestProto.optionalNestedMessageExtension] =
+ TestAllTypesKt.nestedMessage { bb = 118 }
+ this[UnittestProto.optionalForeignMessageExtension] = foreignMessage { c = 119 }
+ this[UnittestProto.optionalImportMessageExtension] =
+ ImportMessage.newBuilder().setD(120).build()
+ this[UnittestProto.optionalPublicImportMessageExtension] =
+ PublicImportMessage.newBuilder().setE(126).build()
+ this[UnittestProto.optionalLazyMessageExtension] = TestAllTypesKt.nestedMessage { bb = 127 }
+ this[UnittestProto.optionalNestedEnumExtension] = NestedEnum.BAZ
+ this[UnittestProto.optionalForeignEnumExtension] = ForeignEnum.FOREIGN_BAZ
+ this[UnittestProto.optionalImportEnumExtension] = ImportEnum.IMPORT_BAZ
+ this[UnittestProto.optionalStringPieceExtension] = "124"
+ this[UnittestProto.optionalCordExtension] = "125"
+ this[UnittestProto.repeatedInt32Extension].add(201)
+ this[UnittestProto.repeatedInt64Extension].add(202L)
+ this[UnittestProto.repeatedUint32Extension].add(203)
+ this[UnittestProto.repeatedUint64Extension].add(204L)
+ this[UnittestProto.repeatedSint32Extension].add(205)
+ this[UnittestProto.repeatedSint64Extension].add(206L)
+ this[UnittestProto.repeatedFixed32Extension].add(207)
+ this[UnittestProto.repeatedFixed64Extension].add(208L)
+ this[UnittestProto.repeatedSfixed32Extension].add(209)
+ this[UnittestProto.repeatedSfixed64Extension].add(210L)
+ this[UnittestProto.repeatedFloatExtension].add(211F)
+ this[UnittestProto.repeatedDoubleExtension].add(212.0)
+ this[UnittestProto.repeatedBoolExtension].add(true)
+ this[UnittestProto.repeatedStringExtension].add("215")
+ this[UnittestProto.repeatedBytesExtension].add(toBytes("216"))
+ this[UnittestProto.repeatedGroupExtension].add(repeatedGroupExtension { a = 217 })
+ this[UnittestProto.repeatedNestedMessageExtension]
+ .add(TestAllTypesKt.nestedMessage { bb = 218 })
+ this[UnittestProto.repeatedForeignMessageExtension].add(foreignMessage { c = 219 })
+ this[UnittestProto.repeatedImportMessageExtension]
+ .add(ImportMessage.newBuilder().setD(220).build())
+ this[UnittestProto.repeatedLazyMessageExtension]
+ .add(TestAllTypesKt.nestedMessage { bb = 227 })
+ this[UnittestProto.repeatedNestedEnumExtension].add(NestedEnum.BAR)
+ this[UnittestProto.repeatedForeignEnumExtension].add(ForeignEnum.FOREIGN_BAR)
+ this[UnittestProto.repeatedImportEnumExtension].add(ImportEnum.IMPORT_BAR)
+ this[UnittestProto.repeatedStringPieceExtension].add("224")
+ this[UnittestProto.repeatedCordExtension].add("225")
+ this[UnittestProto.repeatedInt32Extension] += 301
+ this[UnittestProto.repeatedInt64Extension] += 302L
+ this[UnittestProto.repeatedUint32Extension] += 303
+ this[UnittestProto.repeatedUint64Extension] += 304L
+ this[UnittestProto.repeatedSint32Extension] += 305
+ this[UnittestProto.repeatedSint64Extension] += 306L
+ this[UnittestProto.repeatedFixed32Extension] += 307
+ this[UnittestProto.repeatedFixed64Extension] += 308L
+ this[UnittestProto.repeatedSfixed32Extension] += 309
+ this[UnittestProto.repeatedSfixed64Extension] += 310L
+ this[UnittestProto.repeatedFloatExtension] += 311F
+ this[UnittestProto.repeatedDoubleExtension] += 312.0
+ this[UnittestProto.repeatedBoolExtension] += false
+ this[UnittestProto.repeatedStringExtension] += "315"
+ this[UnittestProto.repeatedBytesExtension] += toBytes("316")
+ this[UnittestProto.repeatedGroupExtension] += repeatedGroupExtension { a = 317 }
+ this[UnittestProto.repeatedNestedMessageExtension] +=
+ TestAllTypesKt.nestedMessage { bb = 318 }
+ this[UnittestProto.repeatedForeignMessageExtension] += foreignMessage { c = 319 }
+ this[UnittestProto.repeatedImportMessageExtension] +=
+ ImportMessage.newBuilder().setD(320).build()
+ this[UnittestProto.repeatedLazyMessageExtension] +=
+ TestAllTypesKt.nestedMessage { bb = 327 }
+ this[UnittestProto.repeatedNestedEnumExtension] += NestedEnum.BAZ
+ this[UnittestProto.repeatedForeignEnumExtension] += ForeignEnum.FOREIGN_BAZ
+ this[UnittestProto.repeatedImportEnumExtension] += ImportEnum.IMPORT_BAZ
+ this[UnittestProto.repeatedStringPieceExtension] += "324"
+ this[UnittestProto.repeatedCordExtension] += "325"
+ this[UnittestProto.defaultInt32Extension] = 401
+ this[UnittestProto.defaultInt64Extension] = 402L
+ this[UnittestProto.defaultUint32Extension] = 403
+ this[UnittestProto.defaultUint64Extension] = 404L
+ this[UnittestProto.defaultSint32Extension] = 405
+ this[UnittestProto.defaultSint64Extension] = 406L
+ this[UnittestProto.defaultFixed32Extension] = 407
+ this[UnittestProto.defaultFixed64Extension] = 408L
+ this[UnittestProto.defaultSfixed32Extension] = 409
+ this[UnittestProto.defaultSfixed64Extension] = 410L
+ this[UnittestProto.defaultFloatExtension] = 411F
+ this[UnittestProto.defaultDoubleExtension] = 412.0
+ this[UnittestProto.defaultBoolExtension] = false
+ this[UnittestProto.defaultStringExtension] = "415"
+ this[UnittestProto.defaultBytesExtension] = toBytes("416")
+ this[UnittestProto.defaultNestedEnumExtension] = NestedEnum.FOO
+ this[UnittestProto.defaultForeignEnumExtension] = ForeignEnum.FOREIGN_FOO
+ this[UnittestProto.defaultImportEnumExtension] = ImportEnum.IMPORT_FOO
+ this[UnittestProto.defaultStringPieceExtension] = "424"
+ this[UnittestProto.defaultCordExtension] = "425"
+ this[UnittestProto.oneofUint32Extension] = 601
+ this[UnittestProto.oneofNestedMessageExtension] = TestAllTypesKt.nestedMessage { bb = 602 }
+ this[UnittestProto.oneofStringExtension] = "603"
+ this[UnittestProto.oneofBytesExtension] = toBytes("604")
+ }
+ ).isEqualTo(
+ TestUtil.getAllExtensionsSet()
+ )
+ }
+
+ @Test
+ fun testExtensionGetters() {
+ testAllExtensions {
+ this[UnittestProto.optionalInt32Extension] = 101
+ assertThat(this[UnittestProto.optionalInt32Extension]).isEqualTo(101)
+ this[UnittestProto.optionalStringExtension] = "115"
+ assertThat(this[UnittestProto.optionalStringExtension]).isEqualTo("115")
+ this[UnittestProto.optionalGroupExtension] = optionalGroupExtension { a = 117 }
+ assertThat(this[UnittestProto.optionalGroupExtension])
+ .isEqualTo(optionalGroupExtension { a = 117 })
+ this[UnittestProto.optionalNestedMessageExtension] =
+ TestAllTypesKt.nestedMessage { bb = 118 }
+ assertThat(this[UnittestProto.optionalNestedMessageExtension])
+ .isEqualTo(TestAllTypesKt.nestedMessage { bb = 118 })
+ this[UnittestProto.optionalNestedEnumExtension] = NestedEnum.BAZ
+ assertThat(this[UnittestProto.optionalNestedEnumExtension]).isEqualTo(NestedEnum.BAZ)
+ this[UnittestProto.defaultInt32Extension] = 401
+ assertThat(this[UnittestProto.defaultInt32Extension]).isEqualTo(401)
+ this[UnittestProto.oneofUint32Extension] = 601
+ assertThat(this[UnittestProto.oneofUint32Extension]).isEqualTo(601)
+ }
+ }
+
+ @Test
+ fun testRepeatedExtensionGettersAndSetters() {
+ testAllExtensions {
+ this[UnittestProto.repeatedInt32Extension].addAll(listOf(1, 2))
+ assertThat(this[UnittestProto.repeatedInt32Extension]).isEqualTo(listOf(1, 2))
+ this[UnittestProto.repeatedInt32Extension] += listOf(3, 4)
+ assertThat(this[UnittestProto.repeatedInt32Extension]).isEqualTo(listOf(1, 2, 3, 4))
+ this[UnittestProto.repeatedInt32Extension][0] = 5
+ assertThat(this[UnittestProto.repeatedInt32Extension]).isEqualTo(listOf(5, 2, 3, 4))
+
+ this[UnittestProto.repeatedStringExtension].addAll(listOf("1", "2"))
+ assertThat(this[UnittestProto.repeatedStringExtension]).isEqualTo(listOf("1", "2"))
+ this[UnittestProto.repeatedStringExtension] += listOf("3", "4")
+ assertThat(this[UnittestProto.repeatedStringExtension]).isEqualTo(listOf("1", "2", "3", "4"))
+ this[UnittestProto.repeatedStringExtension][0] = "5"
+ assertThat(this[UnittestProto.repeatedStringExtension]).isEqualTo(listOf("5", "2", "3", "4"))
+
+ this[UnittestProto.repeatedGroupExtension].addAll(
+ listOf(
+ repeatedGroupExtension { a = 1 },
+ repeatedGroupExtension { a = 2 }
+ )
+ )
+ assertThat(this[UnittestProto.repeatedGroupExtension]).isEqualTo(
+ listOf(
+ repeatedGroupExtension { a = 1 },
+ repeatedGroupExtension { a = 2 }
+ )
+ )
+ this[UnittestProto.repeatedGroupExtension] +=
+ listOf(
+ repeatedGroupExtension { a = 3 },
+ repeatedGroupExtension { a = 4 }
+ )
+ assertThat(this[UnittestProto.repeatedGroupExtension]).isEqualTo(
+ listOf(
+ repeatedGroupExtension { a = 1 },
+ repeatedGroupExtension { a = 2 },
+ repeatedGroupExtension { a = 3 },
+ repeatedGroupExtension { a = 4 }
+ )
+ )
+ this[UnittestProto.repeatedGroupExtension][0] = repeatedGroupExtension { a = 5 }
+ assertThat(this[UnittestProto.repeatedGroupExtension]).isEqualTo(
+ listOf(
+ repeatedGroupExtension { a = 5 },
+ repeatedGroupExtension { a = 2 },
+ repeatedGroupExtension { a = 3 },
+ repeatedGroupExtension { a = 4 }
+ )
+ )
+
+ this[UnittestProto.repeatedNestedMessageExtension].addAll(
+ listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 })
+ )
+ assertThat(this[UnittestProto.repeatedNestedMessageExtension]).isEqualTo(
+ listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 })
+ )
+ this[UnittestProto.repeatedNestedMessageExtension] +=
+ listOf(nestedMessage { bb = 3 }, nestedMessage { bb = 4 })
+ assertThat(this[UnittestProto.repeatedNestedMessageExtension]).isEqualTo(
+ listOf(
+ nestedMessage { bb = 1 },
+ nestedMessage { bb = 2 },
+ nestedMessage { bb = 3 },
+ nestedMessage { bb = 4 }
+ )
+ )
+ this[UnittestProto.repeatedNestedMessageExtension][0] = nestedMessage { bb = 5 }
+ assertThat(this[UnittestProto.repeatedNestedMessageExtension]).isEqualTo(
+ listOf(
+ nestedMessage { bb = 5 },
+ nestedMessage { bb = 2 },
+ nestedMessage { bb = 3 },
+ nestedMessage { bb = 4 }
+ )
+ )
+
+ this[UnittestProto.repeatedNestedEnumExtension]
+ .addAll(listOf(NestedEnum.FOO, NestedEnum.BAR))
+ assertThat(this[UnittestProto.repeatedNestedEnumExtension])
+ .isEqualTo(listOf(NestedEnum.FOO, NestedEnum.BAR))
+ this[UnittestProto.repeatedNestedEnumExtension] += listOf(NestedEnum.BAZ, NestedEnum.FOO)
+ assertThat(this[UnittestProto.repeatedNestedEnumExtension]).isEqualTo(
+ listOf(NestedEnum.FOO, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
+ )
+ }
+ }
+
+ @Test
+ fun testExtensionContains() {
+ testAllExtensions {
+ this[UnittestProto.optionalInt32Extension] = 101
+ assertThat(contains(UnittestProto.optionalInt32Extension)).isTrue()
+ assertThat(contains(UnittestProto.optionalStringExtension)).isFalse()
+ this[UnittestProto.optionalGroupExtension] = optionalGroupExtension { a = 117 }
+ assertThat(contains(UnittestProto.optionalGroupExtension)).isTrue()
+ assertThat(contains(UnittestProto.optionalNestedMessageExtension)).isFalse()
+ this[UnittestProto.optionalNestedEnumExtension] = NestedEnum.BAZ
+ assertThat(contains(UnittestProto.optionalNestedEnumExtension)).isTrue()
+ assertThat(contains(UnittestProto.defaultInt32Extension)).isFalse()
+ this[UnittestProto.oneofUint32Extension] = 601
+ assertThat(contains(UnittestProto.optionalInt32Extension)).isTrue()
+ }
+
+ testAllExtensions {
+ assertThat(contains(UnittestProto.optionalInt32Extension)).isFalse()
+ this[UnittestProto.optionalStringExtension] = "115"
+ assertThat(contains(UnittestProto.optionalStringExtension)).isTrue()
+ assertThat(contains(UnittestProto.optionalGroupExtension)).isFalse()
+ this[UnittestProto.optionalNestedMessageExtension] =
+ TestAllTypesKt.nestedMessage { bb = 118 }
+ assertThat(contains(UnittestProto.optionalNestedMessageExtension)).isTrue()
+ assertThat(contains(UnittestProto.optionalNestedEnumExtension)).isFalse()
+ this[UnittestProto.defaultInt32Extension] = 401
+ assertThat(contains(UnittestProto.defaultInt32Extension)).isTrue()
+ assertThat(contains(UnittestProto.oneofUint32Extension)).isFalse()
+ }
+ }
+
+ @Test
+ fun testExtensionClears() {
+ testAllExtensions {
+ this[UnittestProto.optionalInt32Extension] = 101
+ clear(UnittestProto.optionalInt32Extension)
+ assertThat(contains(UnittestProto.optionalInt32Extension)).isFalse()
+
+ this[UnittestProto.optionalStringExtension] = "115"
+ clear(UnittestProto.optionalStringExtension)
+ assertThat(contains(UnittestProto.optionalStringExtension)).isFalse()
+
+ this[UnittestProto.optionalGroupExtension] = optionalGroupExtension { a = 117 }
+ clear(UnittestProto.optionalGroupExtension)
+ assertThat(contains(UnittestProto.optionalGroupExtension)).isFalse()
+
+ this[UnittestProto.optionalNestedMessageExtension] =
+ TestAllTypesKt.nestedMessage { bb = 118 }
+ clear(UnittestProto.optionalNestedMessageExtension)
+ assertThat(contains(UnittestProto.optionalNestedMessageExtension)).isFalse()
+
+ this[UnittestProto.optionalNestedEnumExtension] = NestedEnum.BAZ
+ clear(UnittestProto.optionalNestedEnumExtension)
+ assertThat(contains(UnittestProto.optionalNestedEnumExtension)).isFalse()
+
+ this[UnittestProto.defaultInt32Extension] = 401
+ clear(UnittestProto.defaultInt32Extension)
+ assertThat(contains(UnittestProto.oneofUint32Extension)).isFalse()
+ }
+ }
+
+ @Test
+ fun testEmptyMessages() {
+ assertThat(
+ testEmptyMessage {}
+ ).isEqualTo(
+ TestEmptyMessage.newBuilder().build()
+ )
+
+ assertThat(
+ testEmptyMessageWithExtensions {}
+ ).isEqualTo(
+ TestEmptyMessageWithExtensions.newBuilder().build()
+ )
+ }
+
+ @Test
+ fun testMapSetters() {
+ val intMap = testIntIntMap { m[1] = 2 }
+ assertThat(intMap).isEqualTo(
+ TestIntIntMap.newBuilder().putM(1, 2).build()
+ )
+
+ assertThat(
+ testMaps {
+ mInt32[1] = intMap
+ mInt64[1L] = intMap
+ mUint32[1] = intMap
+ mUint64[1L] = intMap
+ mSint32[1] = intMap
+ mSint64[1L] = intMap
+ mFixed32[1] = intMap
+ mFixed64[1L] = intMap
+ mSfixed32[1] = intMap
+ mSfixed64[1] = intMap
+ mBool[true] = intMap
+ mString["1"] = intMap
+ }
+ ).isEqualTo(
+ TestMaps.newBuilder()
+ .putMInt32(1, intMap)
+ .putMInt64(1L, intMap)
+ .putMUint32(1, intMap)
+ .putMUint64(1L, intMap)
+ .putMSint32(1, intMap)
+ .putMSint64(1L, intMap)
+ .putMFixed32(1, intMap)
+ .putMFixed64(1L, intMap)
+ .putMSfixed32(1, intMap)
+ .putMSfixed64(1L, intMap)
+ .putMBool(true, intMap)
+ .putMString("1", intMap)
+ .build()
+ )
+
+ assertThat(
+ testEnumMap {
+ knownMapField[1] = Proto2MapEnum.PROTO2_MAP_ENUM_FOO
+ }
+ ).isEqualTo(
+ TestEnumMap.newBuilder()
+ .putKnownMapField(1, Proto2MapEnum.PROTO2_MAP_ENUM_FOO)
+ .build()
+ )
+ }
+
+ @Test
+ fun testMapGettersAndSetters() {
+ val intMap =
+ testIntIntMap {
+ m.put(1, 2)
+ assertThat(m).isEqualTo(mapOf(1 to 2))
+ m[3] = 4
+ assertThat(m).isEqualTo(mapOf(1 to 2, 3 to 4))
+ m.putAll(mapOf(5 to 6, 7 to 8))
+ assertThat(m).isEqualTo(mapOf(1 to 2, 3 to 4, 5 to 6, 7 to 8))
+ }
+
+ testMaps {
+ mInt32.put(1, intMap)
+ assertThat(mInt32).isEqualTo(mapOf(1 to intMap))
+ mInt32[2] = intMap
+ assertThat(mInt32).isEqualTo(mapOf(1 to intMap, 2 to intMap))
+ mInt32.putAll(mapOf(3 to intMap, 4 to intMap))
+ assertThat(mInt32).isEqualTo(mapOf(1 to intMap, 2 to intMap, 3 to intMap, 4 to intMap))
+
+ mString.put("1", intMap)
+ assertThat(mString).isEqualTo(mapOf("1" to intMap))
+ mString["2"] = intMap
+ assertThat(mString).isEqualTo(mapOf("1" to intMap, "2" to intMap))
+ mString.putAll(mapOf("3" to intMap, "4" to intMap))
+ assertThat(mString).isEqualTo(
+ mapOf("1" to intMap, "2" to intMap, "3" to intMap, "4" to intMap)
+ )
+ }
+
+ testEnumMap {
+ knownMapField.put(1, Proto2MapEnum.PROTO2_MAP_ENUM_FOO)
+ assertThat(knownMapField).isEqualTo(mapOf(1 to Proto2MapEnum.PROTO2_MAP_ENUM_FOO))
+ knownMapField[2] = Proto2MapEnum.PROTO2_MAP_ENUM_BAR
+ assertThat(knownMapField).isEqualTo(
+ mapOf(1 to Proto2MapEnum.PROTO2_MAP_ENUM_FOO, 2 to Proto2MapEnum.PROTO2_MAP_ENUM_BAR)
+ )
+ knownMapField.putAll(
+ mapOf(3 to Proto2MapEnum.PROTO2_MAP_ENUM_BAZ, 4 to Proto2MapEnum.PROTO2_MAP_ENUM_FOO)
+ )
+ assertThat(knownMapField).isEqualTo(
+ mapOf(
+ 1 to Proto2MapEnum.PROTO2_MAP_ENUM_FOO,
+ 2 to Proto2MapEnum.PROTO2_MAP_ENUM_BAR,
+ 3 to Proto2MapEnum.PROTO2_MAP_ENUM_BAZ,
+ 4 to Proto2MapEnum.PROTO2_MAP_ENUM_FOO
+ )
+ )
+ }
+ }
+
+ @Test
+ fun testMapRemove() {
+ val intMap =
+ testIntIntMap {
+ m.putAll(mapOf(1 to 2, 3 to 4))
+ m.remove(1)
+ assertThat(m).isEqualTo(mapOf(3 to 4))
+ }
+
+ testMaps {
+ mInt32.putAll(mapOf(1 to intMap, 2 to intMap))
+ mInt32.remove(1)
+ assertThat(mInt32).isEqualTo(mapOf(2 to intMap))
+
+ mString.putAll(mapOf("1" to intMap, "2" to intMap))
+ mString.remove("1")
+ assertThat(mString).isEqualTo(mapOf("2" to intMap))
+ }
+
+ testEnumMap {
+ knownMapField.putAll(
+ mapOf(1 to Proto2MapEnum.PROTO2_MAP_ENUM_FOO, 2 to Proto2MapEnum.PROTO2_MAP_ENUM_BAR)
+ )
+ knownMapField.remove(1)
+ assertThat(knownMapField).isEqualTo(mapOf(2 to Proto2MapEnum.PROTO2_MAP_ENUM_BAR))
+ }
+ }
+
+ @Test
+ fun testMapClear() {
+ val intMap =
+ testIntIntMap {
+ m.putAll(mapOf(1 to 2, 3 to 4))
+ m.clear()
+ assertThat(m.isEmpty()).isTrue()
+ }
+
+ testMaps {
+ mInt32.putAll(mapOf(1 to intMap, 2 to intMap))
+ mInt32.clear()
+ assertThat(mInt32.isEmpty()).isTrue()
+
+ mString.putAll(mapOf("1" to intMap, "2" to intMap))
+ mString.clear()
+ assertThat(mString.isEmpty()).isTrue()
+ }
+
+ testEnumMap {
+ knownMapField.putAll(
+ mapOf(1 to Proto2MapEnum.PROTO2_MAP_ENUM_FOO, 2 to Proto2MapEnum.PROTO2_MAP_ENUM_BAR)
+ )
+ knownMapField.clear()
+ assertThat(knownMapField.isEmpty()).isTrue()
+ }
+ }
+
+ @Test
+ fun testEvilNames() {
+ assertThat(
+ evilNamesProto2 {
+ initialized = true
+ hasFoo = true
+ bar = "foo"
+ isInitialized = true
+ fooBar = "foo"
+ aLLCAPS += "foo"
+ aLLCAPSMAP[1] = true
+ hasUnderbarPrecedingNumeric1Foo = true
+ hasUnderbarPrecedingNumeric42Bar = true
+ hasUnderbarPrecedingNumeric123Foo42BarBaz = true
+ extension += "foo"
+ class_ += 1
+ int = 1.0
+ long = true
+ boolean = 1L
+ sealed = "foo"
+ interface_ = 1F
+ in_ = 1
+ object_ = "foo"
+ cachedSize_ = "foo"
+ serializedSize_ = true
+ by = "foo"
+ }
+ ).isEqualTo(
+ EvilNamesProto2.newBuilder()
+ .setInitialized(true)
+ .setHasFoo(true)
+ .setBar("foo")
+ .setIsInitialized(true)
+ .setFooBar("foo")
+ .addALLCAPS("foo")
+ .putALLCAPSMAP(1, true)
+ .setHasUnderbarPrecedingNumeric1Foo(true)
+ .setHasUnderbarPrecedingNumeric42Bar(true)
+ .setHasUnderbarPrecedingNumeric123Foo42BarBaz(true)
+ .addExtension("foo")
+ .addClass_(1)
+ .setInt(1.0)
+ .setLong(true)
+ .setBoolean(1L)
+ .setSealed("foo")
+ .setInterface(1F)
+ .setIn(1)
+ .setObject("foo")
+ .setCachedSize_("foo")
+ .setSerializedSize_(true)
+ .setBy("foo")
+ .build()
+ )
+
+ assertThat(interface_ {}).isEqualTo(Interface.newBuilder().build())
+ }
+
+ @Test
+ fun testHardKeywordGettersAndSetters() {
+ hardKeywordsAllTypes {
+ as_ = 1
+ assertThat(as_).isEqualTo(1)
+
+ in_ = "foo"
+ assertThat(in_).isEqualTo("foo")
+
+ break_ = HardKeywordsAllTypes.NestedEnum.FOO
+ assertThat(break_).isEqualTo(HardKeywordsAllTypes.NestedEnum.FOO)
+
+ do_ = HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ assertThat(do_).isEqualTo(HardKeywordsAllTypesKt.nestedMessage { while_ = 1 })
+
+ continue_[1] = 1
+ assertThat(continue_[1]).isEqualTo(1)
+
+ else_ += 1
+ assertThat(else_).isEqualTo(listOf(1))
+
+ for_ += "foo"
+ assertThat(for_).isEqualTo(listOf("foo"))
+
+ fun_ += HardKeywordsAllTypes.NestedEnum.FOO
+ assertThat(fun_).isEqualTo(listOf(HardKeywordsAllTypes.NestedEnum.FOO))
+
+ if_ += HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ assertThat(if_).isEqualTo(listOf(HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }))
+ }
+ }
+
+ @Test
+ fun testHardKeywordHazzers() {
+ hardKeywordsAllTypes {
+ as_ = 1
+ assertThat(hasAs_()).isTrue()
+
+ in_ = "foo"
+ assertThat(hasIn_()).isTrue()
+
+ break_ = HardKeywordsAllTypes.NestedEnum.FOO
+ assertThat(hasBreak_()).isTrue()
+
+ do_ = HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ assertThat(hasDo_()).isTrue()
+ }
+ }
+
+ @Test
+ fun testHardKeywordClears() {
+ hardKeywordsAllTypes {
+ as_ = 1
+ clearAs_()
+ assertThat(hasAs_()).isFalse()
+
+ in_ = "foo"
+ clearIn_()
+ assertThat(hasIn_()).isFalse()
+
+ break_ = HardKeywordsAllTypes.NestedEnum.FOO
+ clearBreak_()
+ assertThat(hasBreak_()).isFalse()
+
+ do_ = HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ clearDo_()
+ assertThat(hasDo_()).isFalse()
+ }
+ }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/kotlin/Proto3Test.kt b/java/core/src/test/java/com/google/protobuf/kotlin/Proto3Test.kt
new file mode 100644
index 0000000000..b134307ce0
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/kotlin/Proto3Test.kt
@@ -0,0 +1,335 @@
+package com.google.protobuf.kotlin
+
+import com.google.common.truth.Truth.assertThat
+import com.google.protobuf.kotlin.generator.EvilNamesProto3OuterClass.Class
+import com.google.protobuf.kotlin.generator.EvilNamesProto3OuterClass.EvilNamesProto3
+import com.google.protobuf.kotlin.generator.EvilNamesProto3OuterClass.HardKeywordsAllTypes
+import com.google.protobuf.kotlin.generator.HardKeywordsAllTypesKt
+import com.google.protobuf.kotlin.generator.class_
+import com.google.protobuf.kotlin.generator.evilNamesProto3
+import com.google.protobuf.kotlin.generator.hardKeywordsAllTypes
+import com.google.protos.proto3_unittest.TestAllTypesKt
+import com.google.protos.proto3_unittest.TestAllTypesKt.nestedMessage
+import com.google.protos.proto3_unittest.UnittestProto3.TestAllTypes
+import com.google.protos.proto3_unittest.UnittestProto3.TestAllTypes.NestedEnum
+import com.google.protos.proto3_unittest.UnittestProto3.TestEmptyMessage
+import com.google.protos.proto3_unittest.copy
+import com.google.protos.proto3_unittest.testAllTypes
+import com.google.protos.proto3_unittest.testEmptyMessage
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class Proto3Test {
+ @Test
+ fun testGettersAndSetters() {
+ testAllTypes {
+ optionalInt32 = 101
+ assertThat(optionalInt32).isEqualTo(101)
+ optionalString = "115"
+ assertThat(optionalString).isEqualTo("115")
+ optionalNestedMessage = TestAllTypesKt.nestedMessage { bb = 118 }
+ assertThat(optionalNestedMessage).isEqualTo(TestAllTypesKt.nestedMessage { bb = 118 })
+ optionalNestedEnum = NestedEnum.BAZ
+ assertThat(optionalNestedEnum).isEqualTo(NestedEnum.BAZ)
+ oneofUint32 = 601
+ assertThat(oneofUint32).isEqualTo(601)
+ }
+ }
+
+ @Test
+ fun testRepeatedGettersAndSetters() {
+ testAllTypes {
+ repeatedInt32.addAll(listOf(1, 2))
+ assertThat(repeatedInt32).isEqualTo(listOf(1, 2))
+ repeatedInt32 += listOf(3, 4)
+ assertThat(repeatedInt32).isEqualTo(listOf(1, 2, 3, 4))
+ repeatedInt32[0] = 5
+ assertThat(repeatedInt32).isEqualTo(listOf(5, 2, 3, 4))
+
+ repeatedString.addAll(listOf("1", "2"))
+ assertThat(repeatedString).isEqualTo(listOf("1", "2"))
+ repeatedString += listOf("3", "4")
+ assertThat(repeatedString).isEqualTo(listOf("1", "2", "3", "4"))
+ repeatedString[0] = "5"
+ assertThat(repeatedString).isEqualTo(listOf("5", "2", "3", "4"))
+
+ repeatedNestedMessage.addAll(listOf(nestedMessage { bb = 1 }, nestedMessage { bb = 2 }))
+ assertThat(repeatedNestedMessage).isEqualTo(
+ listOf(
+ nestedMessage { bb = 1 },
+ nestedMessage { bb = 2 }
+ )
+ )
+ repeatedNestedMessage += listOf(nestedMessage { bb = 3 }, nestedMessage { bb = 4 })
+ assertThat(repeatedNestedMessage).isEqualTo(
+ listOf(
+ nestedMessage { bb = 1 },
+ nestedMessage { bb = 2 },
+ nestedMessage { bb = 3 },
+ nestedMessage { bb = 4 }
+ )
+ )
+ repeatedNestedMessage[0] = nestedMessage { bb = 5 }
+ assertThat(repeatedNestedMessage).isEqualTo(
+ listOf(
+ nestedMessage { bb = 5 },
+ nestedMessage { bb = 2 },
+ nestedMessage { bb = 3 },
+ nestedMessage { bb = 4 }
+ )
+ )
+
+ repeatedNestedEnum.addAll(listOf(NestedEnum.FOO, NestedEnum.BAR))
+ assertThat(repeatedNestedEnum).isEqualTo(listOf(NestedEnum.FOO, NestedEnum.BAR))
+ repeatedNestedEnum += listOf(NestedEnum.BAZ, NestedEnum.FOO)
+ assertThat(repeatedNestedEnum).isEqualTo(
+ listOf(NestedEnum.FOO, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
+ )
+ repeatedNestedEnum[0] = NestedEnum.BAR
+ assertThat(repeatedNestedEnum).isEqualTo(
+ listOf(NestedEnum.BAR, NestedEnum.BAR, NestedEnum.BAZ, NestedEnum.FOO)
+ )
+ }
+ }
+
+ @Test
+ fun testClears() {
+ assertThat(
+ testAllTypes {
+ optionalInt32 = 101
+ clearOptionalInt32()
+
+ optionalString = "115"
+ clearOptionalString()
+
+ optionalNestedMessage = TestAllTypesKt.nestedMessage { bb = 118 }
+ clearOptionalNestedMessage()
+
+ optionalNestedEnum = NestedEnum.BAZ
+ clearOptionalNestedEnum()
+
+ oneofUint32 = 601
+ clearOneofUint32()
+ }
+ ).isEqualTo(
+ TestAllTypes.newBuilder().build()
+ )
+ }
+
+ @Test
+ fun testCopy() {
+ val message = testAllTypes {
+ optionalInt32 = 101
+ optionalString = "115"
+ }
+ val modifiedMessage = message.copy {
+ optionalInt32 = 201
+ }
+
+ assertThat(message).isEqualTo(
+ TestAllTypes.newBuilder()
+ .setOptionalInt32(101)
+ .setOptionalString("115")
+ .build()
+ )
+ assertThat(modifiedMessage).isEqualTo(
+ TestAllTypes.newBuilder()
+ .setOptionalInt32(201)
+ .setOptionalString("115")
+ .build()
+ )
+ }
+
+ @Test
+ fun testOneof() {
+ val message = testAllTypes {
+ oneofString = "foo"
+ assertThat(oneofFieldCase)
+ .isEqualTo(TestAllTypes.OneofFieldCase.ONEOF_STRING)
+ assertThat(oneofString).isEqualTo("foo")
+ clearOneofField()
+ assertThat(oneofFieldCase)
+ .isEqualTo(TestAllTypes.OneofFieldCase.ONEOFFIELD_NOT_SET)
+ oneofUint32 = 5
+ }
+
+ assertThat(message.getOneofFieldCase())
+ .isEqualTo(TestAllTypes.OneofFieldCase.ONEOF_UINT32)
+ assertThat(message.getOneofUint32()).isEqualTo(5)
+ }
+
+ @Test
+ fun testEmptyMessages() {
+ assertThat(
+ testEmptyMessage {}
+ ).isEqualTo(
+ TestEmptyMessage.newBuilder().build()
+ )
+ }
+
+ @Test
+ fun testEvilNames() {
+ assertThat(
+ evilNamesProto3 {
+ initialized = true
+ hasFoo = true
+ bar = "foo"
+ isInitialized = true
+ fooBar = "foo"
+ aLLCAPS += "foo"
+ aLLCAPSMAP[1] = true
+ hasUnderbarPrecedingNumeric1Foo = true
+ hasUnderbarPrecedingNumeric42Bar = true
+ hasUnderbarPrecedingNumeric123Foo42BarBaz = true
+ extension += "foo"
+ class_ = "foo"
+ int = 1.0
+ long = true
+ boolean = 1L
+ sealed = "foo"
+ interface_ = 1F
+ in_ = 1
+ object_ = "foo"
+ cachedSize_ = "foo"
+ serializedSize_ = true
+ value = "foo"
+ index = 1L
+ values += "foo"
+ newValues += "foo"
+ builder = true
+ k[1] = 1
+ v["foo"] = "foo"
+ key["foo"] = 1
+ map[1] = "foo"
+ pairs["foo"] = 1
+ LeadingUnderscore = "foo"
+ option = 1
+ }
+ ).isEqualTo(
+ EvilNamesProto3.newBuilder()
+ .setInitialized(true)
+ .setHasFoo(true)
+ .setBar("foo")
+ .setIsInitialized(true)
+ .setFooBar("foo")
+ .addALLCAPS("foo")
+ .putALLCAPSMAP(1, true)
+ .setHasUnderbarPrecedingNumeric1Foo(true)
+ .setHasUnderbarPrecedingNumeric42Bar(true)
+ .setHasUnderbarPrecedingNumeric123Foo42BarBaz(true)
+ .addExtension("foo")
+ .setClass_("foo")
+ .setInt(1.0)
+ .setLong(true)
+ .setBoolean(1L)
+ .setSealed("foo")
+ .setInterface(1F)
+ .setIn(1)
+ .setObject("foo")
+ .setCachedSize_("foo")
+ .setSerializedSize_(true)
+ .setValue("foo")
+ .setIndex(1L)
+ .addValues("foo")
+ .addNewValues("foo")
+ .setBuilder(true)
+ .putK(1, 1)
+ .putV("foo", "foo")
+ .putKey("foo", 1)
+ .putMap(1, "foo")
+ .putPairs("foo", 1)
+ .setLeadingUnderscore("foo")
+ .setOption(1)
+ .build()
+ )
+
+ assertThat(class_ {}).isEqualTo(Class.newBuilder().build())
+ }
+
+ @Test
+ fun testHardKeywordGettersAndSetters() {
+ hardKeywordsAllTypes {
+ as_ = 1
+ assertThat(as_).isEqualTo(1)
+
+ in_ = "foo"
+ assertThat(in_).isEqualTo("foo")
+
+ break_ = HardKeywordsAllTypes.NestedEnum.FOO
+ assertThat(break_).isEqualTo(HardKeywordsAllTypes.NestedEnum.FOO)
+
+ do_ = HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ assertThat(do_).isEqualTo(HardKeywordsAllTypesKt.nestedMessage { while_ = 1 })
+
+ continue_[1] = 1
+ assertThat(continue_[1]).isEqualTo(1)
+
+ else_ += 1
+ assertThat(else_).isEqualTo(listOf(1))
+
+ for_ += "foo"
+ assertThat(for_).isEqualTo(listOf("foo"))
+
+ fun_ += HardKeywordsAllTypes.NestedEnum.FOO
+ assertThat(fun_).isEqualTo(listOf(HardKeywordsAllTypes.NestedEnum.FOO))
+
+ if_ += HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ assertThat(if_).isEqualTo(listOf(HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }))
+ }
+ }
+
+ @Test
+ fun testHardKeywordHazzers() {
+ hardKeywordsAllTypes {
+ as_ = 1
+ assertThat(hasAs_()).isTrue()
+
+ in_ = "foo"
+ assertThat(hasIn_()).isTrue()
+
+ break_ = HardKeywordsAllTypes.NestedEnum.FOO
+ assertThat(hasBreak_()).isTrue()
+
+ do_ = HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ assertThat(hasDo_()).isTrue()
+ }
+ }
+
+ @Test
+ fun testHardKeywordClears() {
+ hardKeywordsAllTypes {
+ as_ = 1
+ clearAs_()
+ assertThat(hasAs_()).isFalse()
+
+ in_ = "foo"
+ clearIn_()
+ assertThat(hasIn_()).isFalse()
+
+ break_ = HardKeywordsAllTypes.NestedEnum.FOO
+ clearBreak_()
+ assertThat(hasBreak_()).isFalse()
+
+ do_ = HardKeywordsAllTypesKt.nestedMessage { while_ = 1 }
+ clearDo_()
+ assertThat(hasDo_()).isFalse()
+ }
+ }
+
+ @Test
+ fun testMultipleFiles() {
+ assertThat(
+ com.google.protobuf.kotlin.generator.multipleFilesMessageA {}
+ ).isEqualTo(
+ com.google.protobuf.kotlin.generator.MultipleFilesMessageA.newBuilder().build()
+ )
+
+ assertThat(
+ com.google.protobuf.kotlin.generator.multipleFilesMessageB {}
+ ).isEqualTo(
+ com.google.protobuf.kotlin.generator.MultipleFilesMessageB.newBuilder().build()
+ )
+ }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/kotlin/evil_names_proto2.proto b/java/core/src/test/java/com/google/protobuf/kotlin/evil_names_proto2.proto
new file mode 100644
index 0000000000..a462abd827
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/kotlin/evil_names_proto2.proto
@@ -0,0 +1,63 @@
+// LINT: LEGACY_NAMES
+syntax = "proto2";
+
+package protobuf.kotlin.generator;
+
+option java_package = "com.google.protobuf.kotlin.generator";
+
+message EvilNamesProto2 {
+ optional bool initialized = 1;
+ optional bool has_foo = 2;
+ optional string Bar = 3;
+ optional bool is_initialized = 4;
+
+ oneof camelCase {
+ string fooBar = 5;
+ }
+
+ repeated string ALL_CAPS = 7;
+ map ALL_CAPS_MAP = 8;
+
+ optional bool has_underbar_preceding_numeric_1foo = 9;
+ optional bool has_underbar_preceding_numeric_42bar = 13;
+ optional bool has_underbar_preceding_numeric_123foo42bar_baz = 14;
+
+ extensions 100 to max;
+
+ repeated string extension = 12;
+ repeated int32 class = 15;
+ optional double int = 16;
+ optional bool long = 17;
+ optional int64 boolean = 18;
+ optional string sealed = 19;
+ optional float interface = 20;
+ optional int32 in = 21;
+ optional string object = 22;
+ optional string cached_size = 23;
+ optional bool serialized_size = 24;
+ optional string by = 25;
+}
+
+message HardKeywordsAllTypes {
+ message NestedMessage {
+ optional int32 while = 1;
+ }
+
+ enum NestedEnum {
+ FOO = 1;
+ BAR = 2;
+ }
+
+ optional int32 as = 1;
+ optional string in = 2;
+ optional NestedEnum break = 3;
+ map continue = 4;
+ optional NestedMessage do = 5;
+
+ repeated int32 else = 6;
+ repeated string for = 7;
+ repeated NestedEnum fun = 8;
+ repeated NestedMessage if = 9;
+}
+
+message Interface {}
diff --git a/java/core/src/test/java/com/google/protobuf/kotlin/evil_names_proto3.proto b/java/core/src/test/java/com/google/protobuf/kotlin/evil_names_proto3.proto
new file mode 100644
index 0000000000..f0faa1c10c
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/kotlin/evil_names_proto3.proto
@@ -0,0 +1,77 @@
+// LINT: LEGACY_NAMES
+syntax = "proto3";
+
+package protobuf.kotlin.generator;
+
+option java_package = "com.google.protobuf.kotlin.generator";
+
+message EvilNamesProto3 {
+ bool initialized = 1;
+ bool has_foo = 2;
+ string Bar = 3;
+ bool is_initialized = 4;
+
+ oneof camelCase {
+ string fooBar = 5;
+ }
+
+ repeated string ALL_CAPS = 7;
+ map ALL_CAPS_MAP = 8;
+
+ bool has_underbar_preceding_numeric_1foo = 9;
+ bool has_underbar_preceding_numeric_42bar = 10;
+ bool has_underbar_preceding_numeric_123foo42bar_baz = 11;
+
+ repeated string extension = 12;
+
+ string class = 13;
+ double int = 14;
+ bool long = 15;
+ int64 boolean = 16;
+ string sealed = 17;
+ float interface = 18;
+ int32 in = 19;
+ string object = 20;
+ string cached_size = 21;
+ bool serialized_size = 22;
+ string value = 23;
+ int64 index = 24;
+ repeated string values = 25;
+ repeated string new_values = 26;
+ bool builder = 27;
+ map k = 28;
+ map v = 29;
+ map key = 30;
+ map map = 31;
+ map pairs = 32;
+
+ string _leading_underscore = 33;
+ oneof _leading_underscore_oneof {
+ int32 option = 34;
+ }
+}
+
+message HardKeywordsAllTypes {
+ message NestedMessage {
+ optional int32 while = 1;
+ }
+
+ enum NestedEnum {
+ ZERO = 0;
+ FOO = 1;
+ BAR = 2;
+ }
+
+ optional int32 as = 1;
+ optional string in = 2;
+ optional NestedEnum break = 3;
+ map continue = 4;
+ optional NestedMessage do = 5;
+
+ repeated int32 else = 6;
+ repeated string for = 7;
+ repeated NestedEnum fun = 8;
+ repeated NestedMessage if = 9;
+}
+
+message Class {}
diff --git a/java/core/src/test/java/com/google/protobuf/kotlin/multiple_files_proto3.proto b/java/core/src/test/java/com/google/protobuf/kotlin/multiple_files_proto3.proto
new file mode 100644
index 0000000000..1b14213291
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/kotlin/multiple_files_proto3.proto
@@ -0,0 +1,12 @@
+syntax = "proto3";
+
+package protobuf.kotlin.generator;
+
+option java_package = "com.google.protobuf.kotlin.generator";
+option java_multiple_files = true;
+
+enum NestedEnum { FOO = 0; }
+
+message MultipleFilesMessageA {}
+
+message MultipleFilesMessageB {}
diff --git a/java/core/src/test/java/com/google/protobuf/kotlin/test.proto b/java/core/src/test/java/com/google/protobuf/kotlin/test.proto
new file mode 100644
index 0000000000..7416eb45a8
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/kotlin/test.proto
@@ -0,0 +1,16 @@
+syntax = "proto2";
+
+package protobuf.kotlin.test;
+
+option java_package = "com.google.protobuf.kotlin.test";
+option java_multiple_files = true;
+
+message ExampleExtensibleMessage {
+ extensions 10 to 20;
+}
+
+extend ExampleExtensibleMessage {
+ repeated int32 repeated_extension = 10;
+ repeated int32 different_extension = 11;
+ optional int32 int32_extension = 12;
+}
diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc
index 9706c6d027..2ebfd67dc7 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field.cc
@@ -61,6 +61,7 @@ void SetEnumVariables(const FieldDescriptor* descriptor, int messageBitIndex,
(*variables)["type"] =
name_resolver->GetImmutableClassName(descriptor->enum_type());
+ (*variables)["kt_type"] = (*variables)["type"];
(*variables)["mutable_type"] =
name_resolver->GetMutableClassName(descriptor->enum_type());
(*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
@@ -74,6 +75,11 @@ void SetEnumVariables(const FieldDescriptor* descriptor, int messageBitIndex,
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
(*variables)["on_changed"] = "onChanged();";
// Use deprecated valueOf() method to be compatible with old generated code
// for v2.5.0/v2.6.1.
@@ -268,6 +274,34 @@ void ImmutableEnumFieldGenerator::GenerateBuilderMembers(
printer->Annotate("{", "}", descriptor_);
}
+void ImmutableEnumFieldGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$var $kt_name$: $kt_type$\n"
+ " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+ " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+ " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+ " set(value) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+ " }\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "fun ${$clear$kt_capitalized_name$$}$() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}\n");
+
+ if (HasHazzer(descriptor_)) {
+ WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+ printer->Print(variables_,
+ "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+ " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+ "}\n");
+ }
+}
+
void ImmutableEnumFieldGenerator::GenerateFieldBuilderInitializationCode(
io::Printer* printer) const {
// noop for enums
@@ -1035,6 +1069,98 @@ void RepeatedImmutableEnumFieldGenerator::GenerateHashCode(
"}\n");
}
+void RepeatedImmutableEnumFieldGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$ val $kt_name$: "
+ "com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " get() = com.google.protobuf.kotlin.DslList(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+ " )\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "add(value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(value: $kt_type$) {\n"
+ " add(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " addAll(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "set(index: kotlin.Int, value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}");
+}
+
std::string RepeatedImmutableEnumFieldGenerator::GetBoxedType() const {
return name_resolver_->GetImmutableClassName(descriptor_->enum_type());
}
diff --git a/src/google/protobuf/compiler/java/java_enum_field.h b/src/google/protobuf/compiler/java/java_enum_field.h
index 95c7db578f..a8cd033cf1 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.h
+++ b/src/google/protobuf/compiler/java/java_enum_field.h
@@ -80,6 +80,7 @@ class ImmutableEnumFieldGenerator : public ImmutableFieldGenerator {
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCode(io::Printer* printer) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
@@ -138,6 +139,7 @@ class RepeatedImmutableEnumFieldGenerator : public ImmutableFieldGenerator {
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCode(io::Printer* printer) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
index dfa051c16d..b78469d1b6 100644
--- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
@@ -68,6 +68,7 @@ void SetEnumVariables(const FieldDescriptor* descriptor, int messageBitIndex,
(*variables)["type"] =
name_resolver->GetImmutableClassName(descriptor->enum_type());
+ (*variables)["kt_type"] = (*variables)["type"];
(*variables)["mutable_type"] =
name_resolver->GetMutableClassName(descriptor->enum_type());
(*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
@@ -81,6 +82,11 @@ void SetEnumVariables(const FieldDescriptor* descriptor, int messageBitIndex,
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
(*variables)["required"] = descriptor->is_required() ? "true" : "false";
if (HasHasbit(descriptor)) {
@@ -273,6 +279,34 @@ void ImmutableEnumFieldLiteGenerator::GenerateBuilderMembers(
printer->Annotate("{", "}", descriptor_);
}
+void ImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$var $kt_name$: $kt_type$\n"
+ " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+ " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+ " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+ " set(value) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+ " }\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "fun ${$clear$kt_capitalized_name$$}$() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}\n");
+
+ if (HasHazzer(descriptor_)) {
+ WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+ printer->Print(variables_,
+ "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+ " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+ "}\n");
+ }
+}
+
void ImmutableEnumFieldLiteGenerator::GenerateInitializationCode(
io::Printer* printer) const {
if (!IsDefaultValueJavaDefault(descriptor_)) {
@@ -772,6 +806,98 @@ void RepeatedImmutableEnumFieldLiteGenerator::GenerateInitializationCode(
printer->Print(variables_, "$name$_ = emptyIntList();\n");
}
+void RepeatedImmutableEnumFieldLiteGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$ val $kt_name$: "
+ "com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " get() = com.google.protobuf.kotlin.DslList(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+ " )\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "add(value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(value: $kt_type$) {\n"
+ " add(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " addAll(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "set(index: kotlin.Int, value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}");
+}
+
std::string RepeatedImmutableEnumFieldLiteGenerator::GetBoxedType() const {
return name_resolver_->GetImmutableClassName(descriptor_->enum_type());
}
diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.h b/src/google/protobuf/compiler/java/java_enum_field_lite.h
index b5e9807728..75760ecaef 100644
--- a/src/google/protobuf/compiler/java/java_enum_field_lite.h
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.h
@@ -71,6 +71,7 @@ class ImmutableEnumFieldLiteGenerator : public ImmutableFieldLiteGenerator {
void GenerateInitializationCode(io::Printer* printer) const;
void GenerateFieldInfo(io::Printer* printer,
std::vector* output) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
@@ -116,6 +117,7 @@ class RepeatedImmutableEnumFieldLiteGenerator
void GenerateInitializationCode(io::Printer* printer) const;
void GenerateFieldInfo(io::Printer* printer,
std::vector* output) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc
index 2f775a68a6..db5a332d8b 100644
--- a/src/google/protobuf/compiler/java/java_field.cc
+++ b/src/google/protobuf/compiler/java/java_field.cc
@@ -258,6 +258,11 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor,
// empty string.
(*variables)["{"] = "";
(*variables)["}"] = "";
+ (*variables)["kt_name"] =
+ IsForbiddenKotlin(info->name) ? info->name + "_" : info->name;
+ (*variables)["kt_capitalized_name"] = IsForbiddenKotlin(info->name)
+ ? info->capitalized_name + "_"
+ : info->capitalized_name;
}
void SetCommonOneofVariables(const FieldDescriptor* descriptor,
diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h
index 9d04dc8455..2e125dccfc 100644
--- a/src/google/protobuf/compiler/java/java_field.h
+++ b/src/google/protobuf/compiler/java/java_field.h
@@ -83,6 +83,7 @@ class ImmutableFieldGenerator {
virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
virtual void GenerateFieldBuilderInitializationCode(
io::Printer* printer) const = 0;
+ virtual void GenerateKotlinDslMembers(io::Printer* printer) const = 0;
virtual void GenerateEqualsCode(io::Printer* printer) const = 0;
virtual void GenerateHashCode(io::Printer* printer) const = 0;
@@ -105,6 +106,7 @@ class ImmutableFieldLiteGenerator {
virtual void GenerateInitializationCode(io::Printer* printer) const = 0;
virtual void GenerateFieldInfo(io::Printer* printer,
std::vector* output) const = 0;
+ virtual void GenerateKotlinDslMembers(io::Printer* printer) const = 0;
virtual std::string GetBoxedType() const = 0;
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index 5cdb00d5c1..e8801a10b9 100644
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -675,6 +675,53 @@ void FileGenerator::GenerateSiblings(
}
}
+std::string FileGenerator::GetKotlinClassname() {
+ return name_resolver_->GetFileClassName(file_, immutable_api_, true);
+}
+
+void FileGenerator::GenerateKotlinSiblings(
+ const std::string& package_dir, GeneratorContext* context,
+ std::vector* file_list,
+ std::vector* annotation_list) {
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ const Descriptor* descriptor = file_->message_type(i);
+ MessageGenerator* generator = message_generators_[i].get();
+ auto open_file = [context](const string& filename) {
+ return std::unique_ptr(context->Open(filename));
+ };
+ std::string filename = package_dir + descriptor->name() + "Kt.kt";
+ file_list->push_back(filename);
+ std::string info_full_path = filename + ".pb.meta";
+ GeneratedCodeInfo annotations;
+ io::AnnotationProtoCollector annotation_collector(
+ &annotations);
+ auto output = open_file(filename);
+ io::Printer printer(
+ output.get(), '$',
+ options_.annotate_code ? &annotation_collector : nullptr);
+
+ printer.Print(
+ "//Generated by the protocol buffer compiler. DO NOT EDIT!\n"
+ "// source: $filename$\n"
+ "\n",
+ "filename", descriptor->file()->name());
+ if (!java_package_.empty()) {
+ printer.Print(
+ "package $package$;\n"
+ "\n",
+ "package", java_package_);
+ }
+
+ generator->GenerateKotlinMembers(&printer);
+ generator->GenerateTopLevelKotlinMembers(&printer);
+
+ if (options_.annotate_code) {
+ auto info_output = open_file(info_full_path);
+ annotations.SerializeToZeroCopyStream(info_output.get());
+ annotation_list->push_back(info_full_path);
+ }
+ }
+}
bool FileGenerator::ShouldIncludeDependency(const FileDescriptor* descriptor,
bool immutable_api) {
diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h
index 9f1f719237..71ee3e8557 100644
--- a/src/google/protobuf/compiler/java/java_file.h
+++ b/src/google/protobuf/compiler/java/java_file.h
@@ -78,6 +78,11 @@ class FileGenerator {
void Generate(io::Printer* printer);
+ std::string GetKotlinClassname();
+ void GenerateKotlinSiblings(const std::string& package_dir,
+ GeneratorContext* generator_context,
+ std::vector* file_list,
+ std::vector* annotation_list);
// If we aren't putting everything into one file, this will write all the
// files other than the outer file (i.e. one for each message, enum, and
diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc
index 3aebf72c7e..16e297af12 100644
--- a/src/google/protobuf/compiler/java/java_helpers.cc
+++ b/src/google/protobuf/compiler/java/java_helpers.cc
@@ -90,6 +90,17 @@ const std::unordered_set* kReservedNames =
"transient", "try", "void", "volatile", "while",
});
+// Names that should be avoided as field names in Kotlin.
+// All Kotlin hard keywords are in this list.
+const std::unordered_set* kKotlinForbiddenNames =
+ new std::unordered_set({
+ "as", "as?", "break", "class", "continue", "do", "else",
+ "false", "for", "fun", "if", "in", "!in", "interface",
+ "is", "!is", "null", "object", "package", "return", "super",
+ "this", "throw", "true", "try", "typealias", "typeof", "val",
+ "var", "when", "while",
+ });
+
bool IsForbidden(const std::string& field_name) {
for (int i = 0; i < GOOGLE_ARRAYSIZE(kForbiddenWordList); ++i) {
if (field_name == kForbiddenWordList[i]) {
@@ -216,6 +227,10 @@ std::string UnderscoresToCamelCaseCheckReserved(const FieldDescriptor* field) {
return name;
}
+bool IsForbiddenKotlin(const std::string& field_name) {
+ return kKotlinForbiddenNames->find(field_name) !=
+ kKotlinForbiddenNames->end();
+}
std::string UniqueFileScopeIdentifier(const Descriptor* descriptor) {
return "static_" + StringReplace(descriptor->full_name(), ".", "_", true);
@@ -422,6 +437,35 @@ const char* BoxedPrimitiveTypeName(const FieldDescriptor* descriptor) {
return BoxedPrimitiveTypeName(GetJavaType(descriptor));
}
+const char* KotlinTypeName(JavaType type) {
+ switch (type) {
+ case JAVATYPE_INT:
+ return "kotlin.Int";
+ case JAVATYPE_LONG:
+ return "kotlin.Long";
+ case JAVATYPE_FLOAT:
+ return "kotlin.Float";
+ case JAVATYPE_DOUBLE:
+ return "kotlin.Double";
+ case JAVATYPE_BOOLEAN:
+ return "kotlin.Boolean";
+ case JAVATYPE_STRING:
+ return "kotlin.String";
+ case JAVATYPE_BYTES:
+ return "com.google.protobuf.ByteString";
+ case JAVATYPE_ENUM:
+ return NULL;
+ case JAVATYPE_MESSAGE:
+ return NULL;
+
+ // No default because we want the compiler to complain if any new
+ // JavaTypes are added.
+ }
+
+ LOG(FATAL) << "Can't get here.";
+ return NULL;
+}
+
std::string GetOneofStoredType(const FieldDescriptor* field) {
const JavaType javaType = GetJavaType(field);
diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h
index 8cc2f5af80..4a925ba0db 100644
--- a/src/google/protobuf/compiler/java/java_helpers.h
+++ b/src/google/protobuf/compiler/java/java_helpers.h
@@ -51,6 +51,7 @@ namespace java {
extern const char kThickSeparator[];
extern const char kThinSeparator[];
+bool IsForbiddenKotlin(const std::string& field_name);
// If annotation_file is non-empty, prints a javax.annotation.Generated
// annotation to the given Printer. annotation_file will be referenced in the
@@ -214,6 +215,9 @@ const char* PrimitiveTypeName(JavaType type);
// types.
const char* BoxedPrimitiveTypeName(JavaType type);
+// Kotlin source does not distinguish between primitives and non-primitives,
+// but does use Kotlin-specific qualified types for them.
+const char* KotlinTypeName(JavaType type);
// Get the name of the java enum constant representing this type. E.g.,
// "INT32" for FieldDescriptor::TYPE_INT32. The enum constant's full
diff --git a/src/google/protobuf/compiler/java/java_kotlin_generator.cc b/src/google/protobuf/compiler/java/java_kotlin_generator.cc
new file mode 100644
index 0000000000..fce3a8cf93
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_kotlin_generator.cc
@@ -0,0 +1,130 @@
+#include "net/proto2/compiler/java/public/kotlin_generator.h"
+
+#include "net/proto2/compiler/java/internal/file.h"
+#include "net/proto2/compiler/java/internal/helpers.h"
+#include "net/proto2/compiler/java/internal/options.h"
+#include "net/proto2/compiler/java/public/generator.h"
+#include "net/proto2/compiler/public/code_generator.h"
+
+namespace proto2 {
+namespace compiler {
+namespace java {
+
+KotlinGenerator::KotlinGenerator() {}
+KotlinGenerator::~KotlinGenerator() {}
+
+uint64_t KotlinGenerator::GetSupportedFeatures() const {
+ return CodeGenerator::Feature::FEATURE_PROTO3_OPTIONAL;
+}
+
+bool KotlinGenerator::Generate(const FileDescriptor* file,
+ const std::string& parameter,
+ GeneratorContext* context,
+ std::string* error) const {
+ // -----------------------------------------------------------------
+ // parse generator options
+
+ std::vector > options;
+ ParseGeneratorParameter(parameter, &options);
+ Options file_options;
+
+ for (auto& option : options) {
+ if (option.first == "output_list_file") {
+ file_options.output_list_file = option.second;
+ } else if (option.first == "immutable") {
+ file_options.generate_immutable_code = true;
+ } else if (option.first == "mutable") {
+ *error = "Mutable not supported by Kotlin generator";
+ return false;
+ } else if (option.first == "shared") {
+ file_options.generate_shared_code = true;
+ } else if (option.first == "lite") {
+ file_options.enforce_lite = true;
+ } else if (option.first == "annotate_code") {
+ file_options.annotate_code = true;
+ } else if (option.first == "annotation_list_file") {
+ file_options.annotation_list_file = option.second;
+ } else {
+ *error = "Unknown generator option: " + option.first;
+ return false;
+ }
+ }
+
+ // By default we generate immutable code and shared code for immutable API.
+ if (!file_options.generate_immutable_code &&
+ !file_options.generate_shared_code) {
+ file_options.generate_immutable_code = true;
+ file_options.generate_shared_code = true;
+ }
+
+ std::vector all_files;
+ std::vector all_annotations;
+
+ std::unique_ptr file_generator;
+ if (file_options.generate_immutable_code) {
+ file_generator = absl::make_unique(
+ file, file_options, /* immutable_api = */ true);
+ }
+
+ if (!file_generator->Validate(error)) {
+ return false;
+ }
+
+ auto open_file = [context](const string& filename) {
+ return std::unique_ptr(context->Open(filename));
+ };
+ std::string package_dir = JavaPackageToDir(file_generator->java_package());
+ std::string kotlin_filename = package_dir;
+ kotlin_filename += file_generator->GetKotlinClassname();
+ kotlin_filename += ".kt";
+ all_files.push_back(kotlin_filename);
+ std::string info_full_path = kotlin_filename + ".pb.meta";
+ if (file_options.annotate_code) {
+ all_annotations.push_back(info_full_path);
+ }
+
+ // Generate main kotlin file.
+ auto output = open_file(kotlin_filename);
+ GeneratedCodeInfo annotations;
+ io::AnnotationProtoCollector annotation_collector(
+ &annotations);
+ io::Printer printer(
+ output.get(), '$',
+ file_options.annotate_code ? &annotation_collector : nullptr);
+
+ file_generator->GenerateKotlinSiblings(package_dir, context, &all_files,
+ &all_annotations);
+
+ if (file_options.annotate_code) {
+ auto info_output = open_file(info_full_path);
+ annotations.SerializeToZeroCopyStream(info_output.get());
+ }
+
+ // Generate output list if requested.
+ if (!file_options.output_list_file.empty()) {
+ // Generate output list. This is just a simple text file placed in a
+ // deterministic location which lists the .kt files being generated.
+ auto srclist_raw_output = open_file(file_options.output_list_file);
+ io::Printer srclist_printer(srclist_raw_output.get(), '$');
+ for (auto& all_file : all_files) {
+ srclist_printer.Print("$filename$\n", "filename", all_file);
+ }
+ }
+
+ if (!file_options.annotation_list_file.empty()) {
+ // Generate output list. This is just a simple text file placed in a
+ // deterministic location which lists the .kt files being generated.
+ auto annotation_list_raw_output =
+ open_file(file_options.annotation_list_file);
+ io::Printer annotation_list_printer(annotation_list_raw_output.get(), '$');
+ for (auto& all_annotation : all_annotations) {
+ annotation_list_printer.Print("$filename$\n", "filename", all_annotation);
+ }
+ }
+
+ return true;
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace proto2
diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc
index 5db199d38f..a4ec2ffad7 100644
--- a/src/google/protobuf/compiler/java/java_map_field.cc
+++ b/src/google/protobuf/compiler/java/java_map_field.cc
@@ -69,6 +69,17 @@ std::string TypeName(const FieldDescriptor* field,
}
}
+std::string KotlinTypeName(const FieldDescriptor* field,
+ ClassNameResolver* name_resolver) {
+ if (GetJavaType(field) == JAVATYPE_MESSAGE) {
+ return name_resolver->GetImmutableClassName(field->message_type());
+ } else if (GetJavaType(field) == JAVATYPE_ENUM) {
+ return name_resolver->GetImmutableClassName(field->enum_type());
+ } else {
+ return KotlinTypeName(GetJavaType(field));
+ }
+}
+
std::string WireType(const FieldDescriptor* field) {
return "com.google.protobuf.WireFormat.FieldType." +
std::string(FieldTypeName(field->type()));
@@ -91,6 +102,8 @@ void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex,
(*variables)["key_type"] = TypeName(key, name_resolver, false);
std::string boxed_key_type = TypeName(key, name_resolver, true);
(*variables)["boxed_key_type"] = boxed_key_type;
+ (*variables)["kt_key_type"] = KotlinTypeName(key, name_resolver);
+ (*variables)["kt_value_type"] = KotlinTypeName(value, name_resolver);
// Used for calling the serialization function.
(*variables)["short_key_type"] =
boxed_key_type.substr(boxed_key_type.rfind('.') + 1);
@@ -136,6 +149,11 @@ void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex,
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
(*variables)["on_changed"] = "onChanged();";
// For repeated fields, one bit is used for whether the array is immutable
@@ -651,6 +669,87 @@ void ImmutableMapFieldGenerator::GenerateMapGetters(
}
}
+void ImmutableMapFieldGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$kt_deprecation$ val $kt_name$: "
+ "com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " @JvmName(\"get$kt_capitalized_name$Map\")\n"
+ " get() = com.google.protobuf.kotlin.DslMap(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$Map$}$()\n"
+ " )\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@JvmName(\"put$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .put(key: $kt_key_type$, value: $kt_value_type$) {\n"
+ " $kt_dsl_builder$.${$put$capitalized_name$$}$(key, value)\n"
+ " }\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@JvmName(\"set$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .set(key: $kt_key_type$, value: $kt_value_type$) {\n"
+ " put(key, value)\n"
+ " }\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@JvmName(\"remove$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .remove(key: $kt_key_type$) {\n"
+ " $kt_dsl_builder$.${$remove$capitalized_name$$}$(key)\n"
+ " }\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@JvmName(\"putAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .putAll(map: kotlin.collections.Map<$kt_key_type$, $kt_value_type$>) "
+ "{\n"
+ " $kt_dsl_builder$.${$putAll$capitalized_name$$}$(map)\n"
+ " }\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ " }\n");
+}
+
void ImmutableMapFieldGenerator::GenerateFieldBuilderInitializationCode(
io::Printer* printer) const {
// Nothing to initialize.
diff --git a/src/google/protobuf/compiler/java/java_map_field.h b/src/google/protobuf/compiler/java/java_map_field.h
index 2ff1f7673e..63b2577003 100644
--- a/src/google/protobuf/compiler/java/java_map_field.h
+++ b/src/google/protobuf/compiler/java/java_map_field.h
@@ -62,6 +62,7 @@ class ImmutableMapFieldGenerator : public ImmutableFieldGenerator {
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCode(io::Printer* printer) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc
index 4fa939f3b8..11b85b2757 100644
--- a/src/google/protobuf/compiler/java/java_map_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc
@@ -69,6 +69,17 @@ std::string TypeName(const FieldDescriptor* field,
}
}
+std::string KotlinTypeName(const FieldDescriptor* field,
+ ClassNameResolver* name_resolver) {
+ if (GetJavaType(field) == JAVATYPE_MESSAGE) {
+ return name_resolver->GetImmutableClassName(field->message_type());
+ } else if (GetJavaType(field) == JAVATYPE_ENUM) {
+ return name_resolver->GetImmutableClassName(field->enum_type());
+ } else {
+ return KotlinTypeName(GetJavaType(field));
+ }
+}
+
std::string WireType(const FieldDescriptor* field) {
return "com.google.protobuf.WireFormat.FieldType." +
std::string(FieldTypeName(field->type()));
@@ -90,6 +101,8 @@ void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex,
(*variables)["key_type"] = TypeName(key, name_resolver, false);
(*variables)["boxed_key_type"] = TypeName(key, name_resolver, true);
+ (*variables)["kt_key_type"] = KotlinTypeName(key, name_resolver);
+ (*variables)["kt_value_type"] = KotlinTypeName(value, name_resolver);
(*variables)["key_wire_type"] = WireType(key);
(*variables)["key_default_value"] = DefaultValue(key, true, name_resolver);
// We use `x.getClass()` as a null check because it generates less bytecode
@@ -131,6 +144,11 @@ void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex,
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
(*variables)["default_entry"] =
(*variables)["capitalized_name"] + "DefaultEntryHolder.defaultEntry";
@@ -788,6 +806,87 @@ void ImmutableMapFieldLiteGenerator::GenerateBuilderMembers(
}
}
+void ImmutableMapFieldLiteGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "$kt_deprecation$ val $kt_name$: "
+ "com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " @JvmName(\"get$kt_capitalized_name$Map\")\n"
+ " get() = com.google.protobuf.kotlin.DslMap(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$Map$}$()\n"
+ " )\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@JvmName(\"put$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .put(key: $kt_key_type$, value: $kt_value_type$) {\n"
+ " $kt_dsl_builder$.${$put$capitalized_name$$}$(key, value)\n"
+ " }\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@JvmName(\"set$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .set(key: $kt_key_type$, value: $kt_value_type$) {\n"
+ " put(key, value)\n"
+ " }\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@JvmName(\"remove$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .remove(key: $kt_key_type$) {\n"
+ " $kt_dsl_builder$.${$remove$capitalized_name$$}$(key)\n"
+ " }\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@JvmName(\"putAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .putAll(map: kotlin.collections.Map<$kt_key_type$, $kt_value_type$>) "
+ "{\n"
+ " $kt_dsl_builder$.${$putAll$capitalized_name$$}$(map)\n"
+ " }\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslMap"
+ "<$kt_key_type$, $kt_value_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " .clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ " }\n");
+}
+
void ImmutableMapFieldLiteGenerator::GenerateInitializationCode(
io::Printer* printer) const {
// Nothing to initialize.
diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.h b/src/google/protobuf/compiler/java/java_map_field_lite.h
index 49cbf6cca7..2d59fdc64f 100644
--- a/src/google/protobuf/compiler/java/java_map_field_lite.h
+++ b/src/google/protobuf/compiler/java/java_map_field_lite.h
@@ -53,6 +53,7 @@ class ImmutableMapFieldLiteGenerator : public ImmutableFieldLiteGenerator {
void GenerateInitializationCode(io::Printer* printer) const;
void GenerateFieldInfo(io::Printer* printer,
std::vector* output) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index f9d4e43ff8..c0fc49945c 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -1356,6 +1356,243 @@ void ImmutableMessageGenerator::GenerateInitializers(io::Printer* printer) {
}
}
+void ImmutableMessageGenerator::GenerateKotlinDsl(io::Printer* printer) const {
+ printer->Print(
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "@com.google.protobuf.kotlin.ProtoDslMarker\n");
+ printer->Print(
+ "class Dsl private constructor(\n"
+ " @kotlin.jvm.JvmField private val _builder: $message$.Builder\n"
+ ") {\n"
+ " companion object {\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " @kotlin.PublishedApi\n"
+ " internal fun _create(builder: $message$.Builder): Dsl = "
+ "Dsl(builder)\n"
+ " }\n"
+ "\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " @kotlin.PublishedApi\n"
+ " internal fun _build(): $message$ = _builder.build()\n",
+ "message", name_resolver_->GetClassName(descriptor_, true));
+
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ printer->Print("\n");
+ field_generators_.get(descriptor_->field(i))
+ .GenerateKotlinDslMembers(printer);
+ }
+
+ for (auto oneof : oneofs_) {
+ printer->Print(
+ "val $oneof_name$Case: $message$.$oneof_capitalized_name$Case\n"
+ " @JvmName(\"get$oneof_capitalized_name$Case\")\n"
+ " get() = _builder.get$oneof_capitalized_name$Case()\n\n"
+ "fun clear$oneof_capitalized_name$() {\n"
+ " _builder.clear$oneof_capitalized_name$()\n"
+ "}\n",
+ "oneof_name", context_->GetOneofGeneratorInfo(oneof)->name,
+ "oneof_capitalized_name",
+ context_->GetOneofGeneratorInfo(oneof)->capitalized_name, "message",
+ name_resolver_->GetClassName(descriptor_, true));
+ }
+
+ if (descriptor_->extension_range_count() > 0) {
+ GenerateKotlinExtensions(printer);
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void ImmutableMessageGenerator::GenerateKotlinMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> Unit): "
+ "$message$ "
+ "=\n"
+ " $message_kt$.Dsl._create($message$.newBuilder()).apply { block() "
+ "}._build()\n",
+ "camelcase_name", name_resolver_->GetKotlinFactoryName(descriptor_),
+ "message_kt", name_resolver_->GetKotlinExtensionsClassName(descriptor_),
+ "message", name_resolver_->GetClassName(descriptor_, true));
+
+ printer->Print("object $name$Kt {\n", "name", descriptor_->name());
+ printer->Indent();
+ GenerateKotlinDsl(printer);
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ if (IsMapEntry(descriptor_->nested_type(i))) continue;
+ ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
+ .GenerateKotlinMembers(printer);
+ }
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void ImmutableMessageGenerator::GenerateTopLevelKotlinMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline fun $message$.copy(block: $message_kt$.Dsl.() -> Unit): "
+ "$message$ =\n"
+ " $message_kt$.Dsl._create(this.toBuilder()).apply { block() "
+ "}._build()\n",
+ "message", name_resolver_->GetClassName(descriptor_, true), "message_kt",
+ name_resolver_->GetKotlinExtensionsClassName(descriptor_));
+
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ if (IsMapEntry(descriptor_->nested_type(i))) continue;
+ ImmutableMessageGenerator(descriptor_->nested_type(i), context_)
+ .GenerateTopLevelKotlinMembers(printer);
+ }
+}
+
+void ImmutableMessageGenerator::GenerateKotlinExtensions(
+ io::Printer* printer) const {
+ std::string message_name = name_resolver_->GetClassName(descriptor_, true);
+
+ printer->Print(
+ "@Suppress(\"UNCHECKED_CAST\")\n"
+ "@kotlin.jvm.JvmSynthetic\n"
+ "operator fun get(extension: "
+ "com.google.protobuf.ExtensionLite<$message$, T>): T {\n"
+ " return if (extension.isRepeated) {\n"
+ " get(extension as com.google.protobuf.ExtensionLite<$message$, "
+ "List<*>>) as T\n"
+ " } else {\n"
+ " _builder.getExtension(extension)\n"
+ " }\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "@kotlin.jvm.JvmName(\"-getRepeatedExtension\")\n"
+ "operator fun get(\n"
+ " extension: com.google.protobuf.ExtensionLite<$message$, List>\n"
+ "): com.google.protobuf.kotlin.ExtensionList {\n"
+ " return com.google.protobuf.kotlin.ExtensionList(extension, "
+ "_builder.getExtension(extension))\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "operator fun contains(extension: "
+ "com.google.protobuf.ExtensionLite<$message$, *>): "
+ "Boolean {\n"
+ " return _builder.hasExtension(extension)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "fun clear(extension: com.google.protobuf.ExtensionLite<$message$, *>) "
+ "{\n"
+ " _builder.clearExtension(extension)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.PublishedApi\n"
+ "internal fun setExtension(extension: "
+ "com.google.protobuf.ExtensionLite<$message$, T>, "
+ "value: T) {\n"
+ " _builder.setExtension(extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun > set(\n"
+ " extension: com.google.protobuf.ExtensionLite<$message$, T>,\n"
+ " value: T\n"
+ ") {\n"
+ " setExtension(extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun set(\n"
+ " extension: com.google.protobuf.ExtensionLite<$message$, "
+ "com.google.protobuf.ByteString>,\n"
+ " value: com.google.protobuf.ByteString\n"
+ ") {\n"
+ " setExtension(extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun set(\n"
+ " extension: com.google.protobuf.ExtensionLite<$message$, T>,\n"
+ " value: T\n"
+ ") {\n"
+ " setExtension(extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "fun com.google.protobuf.kotlin.ExtensionList.add(value: E) {\n"
+ " _builder.addExtension(this.extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun com.google.protobuf.kotlin.ExtensionList.plusAssign"
+ "(value: E) {\n"
+ " add(value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "fun com.google.protobuf.kotlin.ExtensionList.addAll(values: Iterable) {\n"
+ " for (value in values) {\n"
+ " add(value)\n"
+ " }\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun com.google.protobuf.kotlin.ExtensionList.plusAssign(values: "
+ "Iterable) {\n"
+ " addAll(values)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "operator fun com.google.protobuf.kotlin.ExtensionList.set(index: Int, value: "
+ "E) {\n"
+ " _builder.setExtension(this.extension, index, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline fun com.google.protobuf.kotlin.ExtensionList<*, "
+ "$message$>.clear() {\n"
+ " clear(extension)\n"
+ "}\n\n",
+ "message", message_name);
+}
+
void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) {
printer->Print(
"private static String getTypeUrl(\n"
diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h
index 87b9df5e59..50d718039a 100644
--- a/src/google/protobuf/compiler/java/java_message.h
+++ b/src/google/protobuf/compiler/java/java_message.h
@@ -85,6 +85,9 @@ class MessageGenerator {
// Generate code to register all contained extensions with an
// ExtensionRegistry.
virtual void GenerateExtensionRegistrationCode(io::Printer* printer) = 0;
+ virtual void GenerateKotlinDsl(io::Printer* printer) const = 0;
+ virtual void GenerateKotlinMembers(io::Printer* printer) const = 0;
+ virtual void GenerateTopLevelKotlinMembers(io::Printer* printer) const = 0;
protected:
const Descriptor* descriptor_;
@@ -107,6 +110,9 @@ class ImmutableMessageGenerator : public MessageGenerator {
// Returns an estimate of the number of bytes the printed code will compile to
virtual int GenerateStaticVariableInitializers(io::Printer* printer);
+ void GenerateKotlinDsl(io::Printer* printer) const override;
+ void GenerateKotlinMembers(io::Printer* printer) const override;
+ void GenerateTopLevelKotlinMembers(io::Printer* printer) const override;
private:
void GenerateFieldAccessorTable(io::Printer* printer, int* bytecode_estimate);
@@ -128,6 +134,7 @@ class ImmutableMessageGenerator : public MessageGenerator {
void GenerateEqualsAndHashCode(io::Printer* printer);
void GenerateParser(io::Printer* printer);
void GenerateParsingConstructor(io::Printer* printer);
+ void GenerateKotlinExtensions(io::Printer* printer) const;
void GenerateAnyMethods(io::Printer* printer);
Context* context_;
diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc
index 96c0c11276..ad49586f38 100644
--- a/src/google/protobuf/compiler/java/java_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
@@ -59,6 +59,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex,
(*variables)["type"] =
name_resolver->GetImmutableClassName(descriptor->message_type());
+ (*variables)["kt_type"] = (*variables)["type"];
(*variables)["mutable_type"] =
name_resolver->GetMutableClassName(descriptor->message_type());
(*variables)["group_or_message"] =
@@ -68,6 +69,11 @@ void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex,
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
(*variables)["on_changed"] = "onChanged();";
(*variables)["ver"] = GeneratedCodeVersionSuffix();
(*variables)["get_parser"] =
@@ -406,6 +412,32 @@ void ImmutableMessageFieldGenerator::GenerateBuilderMembers(
"}\n");
}
+void ImmutableMessageFieldGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$var $kt_name$: $kt_type$\n"
+ " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+ " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+ " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+ " set(value) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+ " }\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "fun ${$clear$kt_capitalized_name$$}$() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+ printer->Print(variables_,
+ "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+ " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+ "}\n");
+}
+
void ImmutableMessageFieldGenerator::GenerateFieldBuilderInitializationCode(
io::Printer* printer) const {
if (HasHasbit(descriptor_)) {
@@ -1360,6 +1392,98 @@ std::string RepeatedImmutableMessageFieldGenerator::GetBoxedType() const {
return name_resolver_->GetImmutableClassName(descriptor_->message_type());
}
+void RepeatedImmutableMessageFieldGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$ val $kt_name$: "
+ "com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " get() = com.google.protobuf.kotlin.DslList(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+ " )\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "add(value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(value: $kt_type$) {\n"
+ " add(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " addAll(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "set(index: kotlin.Int, value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}");
+}
+
} // namespace java
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_message_field.h b/src/google/protobuf/compiler/java/java_message_field.h
index 36fa49208c..08c5e91bb2 100644
--- a/src/google/protobuf/compiler/java/java_message_field.h
+++ b/src/google/protobuf/compiler/java/java_message_field.h
@@ -81,6 +81,7 @@ class ImmutableMessageFieldGenerator : public ImmutableFieldGenerator {
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCode(io::Printer* printer) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
@@ -146,6 +147,7 @@ class RepeatedImmutableMessageFieldGenerator : public ImmutableFieldGenerator {
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCode(io::Printer* printer) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.cc b/src/google/protobuf/compiler/java/java_message_field_lite.cc
index b17859d6b3..35897ea650 100644
--- a/src/google/protobuf/compiler/java/java_message_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc
@@ -59,6 +59,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex,
(*variables)["type"] =
name_resolver->GetImmutableClassName(descriptor->message_type());
+ (*variables)["kt_type"] = (*variables)["type"];
(*variables)["mutable_type"] =
name_resolver->GetMutableClassName(descriptor->message_type());
(*variables)["group_or_message"] =
@@ -68,6 +69,11 @@ void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex,
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
(*variables)["required"] = descriptor->is_required() ? "true" : "false";
if (HasHasbit(descriptor)) {
@@ -275,6 +281,32 @@ void ImmutableMessageFieldLiteGenerator::GenerateBuilderMembers(
printer->Annotate("{", "}", descriptor_);
}
+void ImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$var $kt_name$: $kt_type$\n"
+ " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+ " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+ " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+ " set(value) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+ " }\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "fun ${$clear$kt_capitalized_name$$}$() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+ printer->Print(variables_,
+ "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+ " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+ "}\n");
+}
+
void ImmutableMessageFieldLiteGenerator::GenerateFieldInfo(
io::Printer* printer, std::vector* output) const {
WriteIntToUtf16CharSequence(descriptor_->number(), output);
@@ -749,6 +781,98 @@ std::string RepeatedImmutableMessageFieldLiteGenerator::GetBoxedType() const {
return name_resolver_->GetImmutableClassName(descriptor_->message_type());
}
+void RepeatedImmutableMessageFieldLiteGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$ val $kt_name$: "
+ "com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " get() = com.google.protobuf.kotlin.DslList(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+ " )\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "add(value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(value: $kt_type$) {\n"
+ " add(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " addAll(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "set(index: kotlin.Int, value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}");
+}
+
} // namespace java
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.h b/src/google/protobuf/compiler/java/java_message_field_lite.h
index c0a9b37f4f..51b53dcb53 100644
--- a/src/google/protobuf/compiler/java/java_message_field_lite.h
+++ b/src/google/protobuf/compiler/java/java_message_field_lite.h
@@ -71,6 +71,7 @@ class ImmutableMessageFieldLiteGenerator : public ImmutableFieldLiteGenerator {
void GenerateInitializationCode(io::Printer* printer) const;
void GenerateFieldInfo(io::Printer* printer,
std::vector* output) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
@@ -116,6 +117,7 @@ class RepeatedImmutableMessageFieldLiteGenerator
void GenerateInitializationCode(io::Printer* printer) const;
void GenerateFieldInfo(io::Printer* printer,
std::vector* output) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc
index 4afffdc7a9..6431540b63 100644
--- a/src/google/protobuf/compiler/java/java_message_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_lite.cc
@@ -723,6 +723,242 @@ void ImmutableMessageLiteGenerator::GenerateInitializers(io::Printer* printer) {
}
}
+void ImmutableMessageLiteGenerator::GenerateKotlinDsl(
+ io::Printer* printer) const {
+ printer->Print(
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "@com.google.protobuf.kotlin.ProtoDslMarker\n");
+ printer->Print(
+ "class Dsl private constructor(\n"
+ " @kotlin.jvm.JvmField private val _builder: $message$.Builder\n"
+ ") {\n"
+ " companion object {\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " @kotlin.PublishedApi\n"
+ " internal fun _create(builder: $message$.Builder): Dsl = "
+ "Dsl(builder)\n"
+ " }\n"
+ "\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " @kotlin.PublishedApi\n"
+ " internal fun _build(): $message$ = _builder.build()\n",
+ "message", name_resolver_->GetClassName(descriptor_, true));
+
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ printer->Print("\n");
+ field_generators_.get(descriptor_->field(i))
+ .GenerateKotlinDslMembers(printer);
+ }
+
+ for (auto oneof : oneofs_) {
+ printer->Print(
+ "val $oneof_name$Case: $message$.$oneof_capitalized_name$Case\n"
+ " @JvmName(\"get$oneof_capitalized_name$Case\")\n"
+ " get() = _builder.get$oneof_capitalized_name$Case()\n\n"
+ "fun clear$oneof_capitalized_name$() {\n"
+ " _builder.clear$oneof_capitalized_name$()\n"
+ "}\n",
+ "oneof_name", context_->GetOneofGeneratorInfo(oneof)->name,
+ "oneof_capitalized_name",
+ context_->GetOneofGeneratorInfo(oneof)->capitalized_name, "message",
+ name_resolver_->GetClassName(descriptor_, true));
+ }
+
+ if (descriptor_->extension_range_count() > 0) {
+ GenerateKotlinExtensions(printer);
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void ImmutableMessageLiteGenerator::GenerateKotlinMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> Unit): "
+ "$message$ =\n"
+ " $message_kt$.Dsl._create($message$.newBuilder()).apply { block() "
+ "}._build()\n",
+ "camelcase_name", name_resolver_->GetKotlinFactoryName(descriptor_),
+ "message_kt", name_resolver_->GetKotlinExtensionsClassName(descriptor_),
+ "message", name_resolver_->GetClassName(descriptor_, true));
+
+ printer->Print("object $name$Kt {\n", "name", descriptor_->name());
+ printer->Indent();
+ GenerateKotlinDsl(printer);
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ if (IsMapEntry(descriptor_->nested_type(i))) continue;
+ ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
+ .GenerateKotlinMembers(printer);
+ }
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void ImmutableMessageLiteGenerator::GenerateTopLevelKotlinMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ "inline fun $message$.copy(block: $message_kt$.Dsl.() -> Unit): "
+ "$message$ =\n"
+ " $message_kt$.Dsl._create(this.toBuilder()).apply { block() "
+ "}._build()\n",
+ "message", name_resolver_->GetClassName(descriptor_, true), "message_kt",
+ name_resolver_->GetKotlinExtensionsClassName(descriptor_));
+
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ if (IsMapEntry(descriptor_->nested_type(i))) continue;
+ ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_)
+ .GenerateTopLevelKotlinMembers(printer);
+ }
+}
+
+void ImmutableMessageLiteGenerator::GenerateKotlinExtensions(
+ io::Printer* printer) const {
+ std::string message_name = name_resolver_->GetClassName(descriptor_, true);
+
+ printer->Print(
+ "@Suppress(\"UNCHECKED_CAST\")\n"
+ "@kotlin.jvm.JvmSynthetic\n"
+ "operator fun get(extension: "
+ "com.google.protobuf.ExtensionLite<$message$, T>): T {\n"
+ " return if (extension.isRepeated) {\n"
+ " get(extension as com.google.protobuf.ExtensionLite<$message$, "
+ "List<*>>) as T\n"
+ " } else {\n"
+ " _builder.getExtension(extension)\n"
+ " }\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "@kotlin.jvm.JvmName(\"-getRepeatedExtension\")\n"
+ "operator fun get(\n"
+ " extension: com.google.protobuf.ExtensionLite<$message$, List>\n"
+ "): com.google.protobuf.kotlin.ExtensionList {\n"
+ " return com.google.protobuf.kotlin.ExtensionList(extension, "
+ "_builder.getExtension(extension))\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "operator fun contains(extension: "
+ "com.google.protobuf.ExtensionLite<$message$, *>): "
+ "Boolean {\n"
+ " return _builder.hasExtension(extension)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "fun clear(extension: com.google.protobuf.ExtensionLite<$message$, *>) "
+ "{\n"
+ " _builder.clearExtension(extension)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.PublishedApi\n"
+ "internal fun setExtension(extension: "
+ "com.google.protobuf.ExtensionLite<$message$, T>, "
+ "value: T) {\n"
+ " _builder.setExtension(extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun > set(\n"
+ " extension: com.google.protobuf.ExtensionLite<$message$, T>,\n"
+ " value: T\n"
+ ") {\n"
+ " setExtension(extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun set(\n"
+ " extension: com.google.protobuf.ExtensionLite<$message$, "
+ "com.google.protobuf.ByteString>,\n"
+ " value: com.google.protobuf.ByteString\n"
+ ") {\n"
+ " setExtension(extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun set(\n"
+ " extension: com.google.protobuf.ExtensionLite<$message$, T>,\n"
+ " value: T\n"
+ ") {\n"
+ " setExtension(extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "fun com.google.protobuf.kotlin.ExtensionList.add(value: E) {\n"
+ " _builder.addExtension(this.extension, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun com.google.protobuf.kotlin.ExtensionList.plusAssign"
+ "(value: E) {\n"
+ " add(value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "fun com.google.protobuf.kotlin.ExtensionList.addAll(values: Iterable) {\n"
+ " for (value in values) {\n"
+ " add(value)\n"
+ " }\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline operator fun com.google.protobuf.kotlin.ExtensionList.plusAssign(values: "
+ "Iterable) {\n"
+ " addAll(values)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "operator fun com.google.protobuf.kotlin.ExtensionList.set(index: Int, value: "
+ "E) {\n"
+ " _builder.setExtension(this.extension, index, value)\n"
+ "}\n\n",
+ "message", message_name);
+
+ printer->Print(
+ "@kotlin.jvm.JvmSynthetic\n"
+ "inline fun com.google.protobuf.kotlin.ExtensionList<*, "
+ "$message$>.clear() {\n"
+ " clear(extension)\n"
+ "}\n\n",
+ "message", message_name);
+}
+
} // namespace java
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_message_lite.h b/src/google/protobuf/compiler/java/java_message_lite.h
index 5290b1e641..4dfa291314 100644
--- a/src/google/protobuf/compiler/java/java_message_lite.h
+++ b/src/google/protobuf/compiler/java/java_message_lite.h
@@ -56,6 +56,9 @@ class ImmutableMessageLiteGenerator : public MessageGenerator {
virtual void GenerateStaticVariables(io::Printer* printer,
int* bytecode_estimate);
virtual int GenerateStaticVariableInitializers(io::Printer* printer);
+ void GenerateKotlinDsl(io::Printer* printer) const override;
+ void GenerateKotlinMembers(io::Printer* printer) const override;
+ void GenerateTopLevelKotlinMembers(io::Printer* printer) const override;
private:
void GenerateParseFromMethods(io::Printer* printer);
@@ -66,6 +69,7 @@ class ImmutableMessageLiteGenerator : public MessageGenerator {
void GenerateParser(io::Printer* printer);
void GenerateConstructor(io::Printer* printer);
void GenerateDynamicMethodNewBuildMessageInfo(io::Printer* printer);
+ void GenerateKotlinExtensions(io::Printer* printer) const;
Context* context_;
ClassNameResolver* name_resolver_;
diff --git a/src/google/protobuf/compiler/java/java_name_resolver.cc b/src/google/protobuf/compiler/java/java_name_resolver.cc
index ed33dae5ff..43c7db53cc 100644
--- a/src/google/protobuf/compiler/java/java_name_resolver.cc
+++ b/src/google/protobuf/compiler/java/java_name_resolver.cc
@@ -69,6 +69,16 @@ std::string ClassNameWithoutPackage(const Descriptor* descriptor,
return StripPackageName(descriptor->full_name(), descriptor->file());
}
+std::string ClassNameWithoutPackageKotlin(const Descriptor* descriptor) {
+ std::string result = descriptor->name();
+ const Descriptor* temp = descriptor->containing_type();
+
+ while (temp) {
+ result = temp->name() + "Kt." + result;
+ temp = temp->containing_type();
+ }
+ return result;
+}
// Get the name of an enum's Java class without package name prefix.
std::string ClassNameWithoutPackage(const EnumDescriptor* descriptor,
@@ -316,6 +326,12 @@ std::string ClassNameResolver::GetExtensionIdentifierName(
descriptor->name();
}
+std::string ClassNameResolver::GetKotlinFactoryName(
+ const Descriptor* descriptor) {
+ std::string name = ToCamelCase(descriptor->name(), /* lower_first = */ true);
+ return IsForbiddenKotlin(name) ? name + "_" : name;
+}
+
std::string ClassNameResolver::GetJavaImmutableClassName(
const Descriptor* descriptor) {
return GetJavaClassFullName(ClassNameWithoutPackage(descriptor, true),
@@ -328,6 +344,12 @@ std::string ClassNameResolver::GetJavaImmutableClassName(
descriptor->file(), true);
}
+std::string ClassNameResolver::GetKotlinExtensionsClassName(
+ const Descriptor* descriptor) {
+ return GetClassFullName(ClassNameWithoutPackageKotlin(descriptor),
+ descriptor->file(), true, true, true);
+}
+
} // namespace java
} // namespace compiler
diff --git a/src/google/protobuf/compiler/java/java_name_resolver.h b/src/google/protobuf/compiler/java/java_name_resolver.h
index 8461df9009..9717d92327 100644
--- a/src/google/protobuf/compiler/java/java_name_resolver.h
+++ b/src/google/protobuf/compiler/java/java_name_resolver.h
@@ -115,6 +115,8 @@ class ClassNameResolver {
// com.package.OuterClass$OuterMessage$InnerMessage
std::string GetJavaImmutableClassName(const Descriptor* descriptor);
std::string GetJavaImmutableClassName(const EnumDescriptor* descriptor);
+ std::string GetKotlinFactoryName(const Descriptor* descriptor);
+ std::string GetKotlinExtensionsClassName(const Descriptor* descriptor);
private:
// Get the full name of a Java class by prepending the Java package name
// or outer class name.
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
index 8bc68b7b22..6f0efeffd3 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
@@ -66,6 +66,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
(*variables)["type"] = PrimitiveTypeName(javaType);
(*variables)["boxed_type"] = BoxedPrimitiveTypeName(javaType);
+ (*variables)["kt_type"] = KotlinTypeName(javaType);
(*variables)["field_type"] = (*variables)["type"];
if (javaType == JAVATYPE_BOOLEAN || javaType == JAVATYPE_DOUBLE ||
@@ -127,6 +128,11 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
int fixed_size = FixedSize(GetType(descriptor));
if (fixed_size != -1) {
(*variables)["fixed_size"] = StrCat(fixed_size);
@@ -296,6 +302,33 @@ void ImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
"}\n");
}
+void ImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$var $kt_name$: $kt_type$\n"
+ " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+ " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+ " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+ " set(value) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+ " }\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "fun ${$clear$kt_capitalized_name$$}$() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}\n");
+
+ if (HasHazzer(descriptor_)) {
+ WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+ printer->Print(variables_,
+ "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+ " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+ "}\n");
+ }
+}
void ImmutablePrimitiveFieldGenerator::GenerateFieldBuilderInitializationCode(
io::Printer* printer) const {
@@ -791,6 +824,98 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
printer->Annotate("{", "}", descriptor_);
}
+void RepeatedImmutablePrimitiveFieldGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$ val $kt_name$: "
+ "com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " get() = com.google.protobuf.kotlin.DslList(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+ " )\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "add(value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(value: $kt_type$) {\n"
+ " add(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " addAll(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "set(index: kotlin.Int, value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}");
+}
+
void RepeatedImmutablePrimitiveFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
// noop for primitives
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.h b/src/google/protobuf/compiler/java/java_primitive_field.h
index db20750e26..56be916e2e 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.h
+++ b/src/google/protobuf/compiler/java/java_primitive_field.h
@@ -81,6 +81,7 @@ class ImmutablePrimitiveFieldGenerator : public ImmutableFieldGenerator {
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCode(io::Printer* printer) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
@@ -139,6 +140,7 @@ class RepeatedImmutablePrimitiveFieldGenerator
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCode(io::Printer* printer) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
index e807066247..58be7446ce 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
@@ -73,6 +73,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
JavaType javaType = GetJavaType(descriptor);
(*variables)["type"] = PrimitiveTypeName(javaType);
(*variables)["boxed_type"] = BoxedPrimitiveTypeName(javaType);
+ (*variables)["kt_type"] = KotlinTypeName(javaType);
(*variables)["field_type"] = (*variables)["type"];
(*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
(*variables)["capitalized_type"] =
@@ -135,6 +136,11 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
int fixed_size = FixedSize(GetType(descriptor));
if (fixed_size != -1) {
(*variables)["fixed_size"] = StrCat(fixed_size);
@@ -301,6 +307,33 @@ void ImmutablePrimitiveFieldLiteGenerator::GenerateBuilderMembers(
printer->Annotate("{", "}", descriptor_);
}
+void ImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$var $kt_name$: $kt_type$\n"
+ " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+ " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+ " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+ " set(value) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+ " }\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "fun ${$clear$kt_capitalized_name$$}$() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}\n");
+
+ if (HasHazzer(descriptor_)) {
+ WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+ printer->Print(variables_,
+ "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+ " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+ "}\n");
+ }
+}
void ImmutablePrimitiveFieldLiteGenerator::GenerateFieldInfo(
io::Printer* printer, std::vector* output) const {
@@ -613,6 +646,98 @@ void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateBuilderMembers(
printer->Annotate("{", "}", descriptor_);
}
+void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$ val $kt_name$: "
+ "com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>\n"
+ " @kotlin.jvm.JvmSynthetic\n"
+ " get() = com.google.protobuf.kotlin.DslList(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+ " )\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "add(value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(value: $kt_type$) {\n"
+ " add(value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "addAll(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "plusAssign(values: kotlin.collections.Iterable<$kt_type$>) {\n"
+ " addAll(values)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "set(index: kotlin.Int, value: $kt_type$) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "<$kt_type$, ${$$kt_capitalized_name$Proxy$}$>."
+ "clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}");
+}
+
void RepeatedImmutablePrimitiveFieldLiteGenerator::GenerateFieldInfo(
io::Printer* printer, std::vector* output) const {
WriteIntToUtf16CharSequence(descriptor_->number(), output);
diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.h b/src/google/protobuf/compiler/java/java_primitive_field_lite.h
index 5867cee746..fcdee9c452 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field_lite.h
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.h
@@ -71,6 +71,7 @@ class ImmutablePrimitiveFieldLiteGenerator
void GenerateInitializationCode(io::Printer* printer) const;
void GenerateFieldInfo(io::Printer* printer,
std::vector* output) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
@@ -117,6 +118,7 @@ class RepeatedImmutablePrimitiveFieldLiteGenerator
void GenerateInitializationCode(io::Printer* printer) const;
void GenerateFieldInfo(io::Printer* printer,
std::vector* output) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
index 485fcf812e..c3bf45d171 100644
--- a/src/google/protobuf/compiler/java/java_string_field.cc
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
@@ -88,6 +88,11 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
(*variables)["on_changed"] = "onChanged();";
if (HasHasbit(descriptor)) {
@@ -365,6 +370,34 @@ void ImmutableStringFieldGenerator::GenerateBuilderMembers(
"}\n");
}
+void ImmutableStringFieldGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$var $kt_name$: kotlin.String\n"
+ " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+ " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+ " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+ " set(value) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+ " }\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "fun ${$clear$kt_capitalized_name$$}$() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}\n");
+
+ if (HasHazzer(descriptor_)) {
+ WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+ printer->Print(variables_,
+ "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+ " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+ "}\n");
+ }
+}
+
void ImmutableStringFieldGenerator::GenerateFieldBuilderInitializationCode(
io::Printer* printer) const {
// noop for primitives
@@ -914,6 +947,107 @@ void RepeatedImmutableStringFieldGenerator::GenerateBuilderMembers(
"}\n");
}
+void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ // property for List
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+ printer->Print(
+ variables_,
+ "val $kt_name$: "
+ "com.google.protobuf.kotlin.DslList"
+ "\n"
+ " @kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ " get() = com.google.protobuf.kotlin.DslList(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+ " )\n");
+
+ // List.add(String)
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "."
+ "add(value: kotlin.String) {\n"
+ " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+ "}\n");
+
+ // List += String
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "."
+ "plusAssign(value: kotlin.String) {\n"
+ " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+ "}\n");
+
+ // List.addAll(Iterable)
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "."
+ "addAll(values: kotlin.collections.Iterable) {\n"
+ " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+ "}\n");
+
+ // List += Iterable
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "."
+ "plusAssign(values: kotlin.collections.Iterable) {\n"
+ " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+ "}\n");
+
+ // List[Int] = String
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "."
+ "set(index: kotlin.Int, value: kotlin.String) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "."
+ "clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}");
+}
+
void RepeatedImmutableStringFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
// noop for primitives
diff --git a/src/google/protobuf/compiler/java/java_string_field.h b/src/google/protobuf/compiler/java/java_string_field.h
index 1c00ae81c2..6cc91260cf 100644
--- a/src/google/protobuf/compiler/java/java_string_field.h
+++ b/src/google/protobuf/compiler/java/java_string_field.h
@@ -81,6 +81,7 @@ class ImmutableStringFieldGenerator : public ImmutableFieldGenerator {
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCode(io::Printer* printer) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
@@ -137,6 +138,7 @@ class RepeatedImmutableStringFieldGenerator : public ImmutableFieldGenerator {
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const;
void GenerateEqualsCode(io::Printer* printer) const;
void GenerateHashCode(io::Printer* printer) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.cc b/src/google/protobuf/compiler/java/java_string_field_lite.cc
index 25bfedcae2..5f6e27af67 100644
--- a/src/google/protobuf/compiler/java/java_string_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc
@@ -83,6 +83,11 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
// by the proto compiler
(*variables)["deprecation"] =
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
+ (*variables)["kt_deprecation"] =
+ descriptor->options().deprecated()
+ ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name"] +
+ " is deprecated\") "
+ : "";
(*variables)["required"] = descriptor->is_required() ? "true" : "false";
if (HasHasbit(descriptor)) {
@@ -301,6 +306,34 @@ void ImmutableStringFieldLiteGenerator::GenerateBuilderMembers(
printer->Annotate("{", "}", descriptor_);
}
+void ImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ WriteFieldDocComment(printer, descriptor_);
+ printer->Print(variables_,
+ "$kt_deprecation$var $kt_name$: kotlin.String\n"
+ " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n"
+ " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n"
+ " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n"
+ " set(value) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
+ " }\n");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "fun ${$clear$kt_capitalized_name$$}$() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}\n");
+
+ if (HasHazzer(descriptor_)) {
+ WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
+ printer->Print(variables_,
+ "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n"
+ " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n"
+ "}\n");
+ }
+}
+
void ImmutableStringFieldLiteGenerator::GenerateFieldInfo(
io::Printer* printer, std::vector* output) const {
WriteIntToUtf16CharSequence(descriptor_->number(), output);
@@ -701,6 +734,107 @@ void RepeatedImmutableStringFieldLiteGenerator::GenerateBuilderMembers(
printer->Annotate("{", "}", descriptor_);
}
+void RepeatedImmutableStringFieldLiteGenerator::GenerateKotlinDslMembers(
+ io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "/**\n"
+ " * An uninstantiable, behaviorless type to represent the field in\n"
+ " * generics.\n"
+ " */\n"
+ "@kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ "class ${$$kt_capitalized_name$Proxy$}$ private constructor()"
+ " : com.google.protobuf.kotlin.DslProxy()\n");
+
+ // property for List
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
+ printer->Print(
+ variables_,
+ "val $kt_name$: "
+ "com.google.protobuf.kotlin.DslList"
+ "\n"
+ " @kotlin.OptIn"
+ "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
+ " get() = com.google.protobuf.kotlin.DslList(\n"
+ " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n"
+ " )\n");
+
+ // List.add(String)
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "."
+ "add(value: kotlin.String) {\n"
+ " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n"
+ "}\n");
+
+ // List += String
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "."
+ "plusAssign(value: kotlin.String) {\n"
+ " add(value)\n"
+ "}\n");
+
+ // List.addAll(Iterable)
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "."
+ "addAll(values: kotlin.collections.Iterable) {\n"
+ " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n"
+ "}\n");
+
+ // List += Iterable
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n"
+ "inline operator fun com.google.protobuf.kotlin.DslList"
+ "."
+ "plusAssign(values: kotlin.collections.Iterable) {\n"
+ " addAll(values)\n"
+ "}\n");
+
+ // List[Int] = String
+ WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
+ /* builder */ false);
+ printer->Print(
+ variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n"
+ "operator fun com.google.protobuf.kotlin.DslList"
+ "."
+ "set(index: kotlin.Int, value: kotlin.String) {\n"
+ " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n"
+ "}");
+
+ WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
+ /* builder */ false);
+ printer->Print(variables_,
+ "@kotlin.jvm.JvmSynthetic\n"
+ "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n"
+ "fun com.google.protobuf.kotlin.DslList"
+ "."
+ "clear() {\n"
+ " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
+ "}");
+}
+
void RepeatedImmutableStringFieldLiteGenerator::GenerateFieldInfo(
io::Printer* printer, std::vector* output) const {
WriteIntToUtf16CharSequence(descriptor_->number(), output);
diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.h b/src/google/protobuf/compiler/java/java_string_field_lite.h
index b67135cd81..1f3dafc50f 100644
--- a/src/google/protobuf/compiler/java/java_string_field_lite.h
+++ b/src/google/protobuf/compiler/java/java_string_field_lite.h
@@ -72,6 +72,7 @@ class ImmutableStringFieldLiteGenerator : public ImmutableFieldLiteGenerator {
void GenerateInitializationCode(io::Printer* printer) const;
void GenerateFieldInfo(io::Printer* printer,
std::vector* output) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
@@ -116,6 +117,7 @@ class RepeatedImmutableStringFieldLiteGenerator
void GenerateInitializationCode(io::Printer* printer) const;
void GenerateFieldInfo(io::Printer* printer,
std::vector* output) const;
+ void GenerateKotlinDslMembers(io::Printer* printer) const;
std::string GetBoxedType() const;
diff --git a/third_party/build_defs/BUILD b/third_party/build_defs/BUILD
new file mode 100644
index 0000000000..15cf88cca6
--- /dev/null
+++ b/third_party/build_defs/BUILD
@@ -0,0 +1,20 @@
+load("//tools/build_defs/testing:bzl_library.bzl", "bzl_library")
+
+licenses(["notice"])
+
+bzl_library(
+ name = "kt_jvm_proto_library_helper",
+ srcs = ["kt_jvm_proto_library.internal.bzl"],
+ visibility = ["//visibility:private"],
+ deps = [
+ "//tools/build_defs/kotlin/release/rules:android_jvm_compile_bzl",
+ "//tools/build_defs/kotlin/release/toolchains/kotlin_jvm:toolchain_bzl",
+ ],
+)
+
+bzl_library(
+ name = "kt_jvm_proto_library",
+ srcs = ["kt_jvm_proto_library.bzl"],
+ visibility = ["//visibility:private"],
+ deps = [":kt_jvm_proto_library_helper"],
+)
diff --git a/third_party/build_defs/kt_jvm_proto_library.bzl b/third_party/build_defs/kt_jvm_proto_library.bzl
new file mode 100644
index 0000000000..5e5115fe28
--- /dev/null
+++ b/third_party/build_defs/kt_jvm_proto_library.bzl
@@ -0,0 +1,140 @@
+"""Definitions for Kotlin proto libraries."""
+
+load(":kt_jvm_proto_library.internal.bzl", _kt_proto_library_helper = "kt_proto_library_helper")
+load("//devtools/build_cleaner/skylark:build_defs.bzl", "register_extension_info")
+
+def _lite_proto_name(name):
+ return ":%s_DO_NOT_DEPEND_java_lite_proto" % name
+
+def _proto_name(name):
+ return ":%s_DO_NOT_DEPEND_java_proto" % name
+
+def kt_jvm_lite_proto_library(
+ name,
+ deps = None,
+ tags = None,
+ testonly = None,
+ compatible_with = None,
+ restricted_to = None,
+ visibility = None,
+ deprecation = None,
+ features = []):
+ """
+ This rule generates and compiles lite Java and Kotlin APIs for a specified proto_library.
+
+ Args:
+ name: A name for the target
+ deps: One or more proto_library targets
+ tags: List of string tags passed to generated targets.
+ testonly: Whether this target is intended only for tests.
+ compatible_with: Standard attribute, see http://go/be-common#common.compatible_with
+ restricted_to: Standard attribute, see http://go/be-common#common.restricted_to
+ visibility: A list of targets allowed to depend on this rule.
+ deprecation: Standard attribute, see http://go/be-common#common.deprecation
+ features: Features enabled.
+ """
+
+ tags = (tags or []) + ["kt_jvm_lite_proto_library"]
+
+ native.java_lite_proto_library(
+ name = _lite_proto_name(name)[1:],
+ deps = deps,
+ testonly = testonly,
+ compatible_with = compatible_with,
+ visibility = ["//visibility:private"],
+ restricted_to = restricted_to,
+ tags = tags + ["avoid_dep"],
+ deprecation = deprecation,
+ features = features,
+ )
+
+ _kt_proto_library_helper(
+ name = name,
+ proto_deps = deps,
+ deps = [
+ _lite_proto_name(name),
+ "//java/com/google/protobuf:protobuf_lite",
+ "//java/com/google/protobuf/kotlin:only_for_use_in_proto_generated_code_its_generator_and_tests",
+ "//java/com/google/protobuf/kotlin:shared_runtime",
+ ],
+ exports = [_lite_proto_name(name)],
+ testonly = testonly,
+ compatible_with = compatible_with,
+ restricted_to = restricted_to,
+ constraints = ["android"],
+ tags = tags,
+ variant = "lite",
+ visibility = visibility,
+ deprecation = deprecation,
+ features = features,
+ )
+
+def kt_jvm_proto_library(
+ name,
+ deps = None,
+ tags = None,
+ testonly = None,
+ compatible_with = None,
+ restricted_to = None,
+ visibility = None,
+ deprecation = None,
+ features = []):
+ """
+ This rule generates and compiles full Java and Kotlin APIs for a specified proto_library.
+
+ Args:
+ name: A name for the target
+ deps: One or more proto_library targets
+ tags: List of string tags passed to generated targets.
+ testonly: Whether this target is intended only for tests.
+ compatible_with: Standard attribute, see http://go/be-common#common.compatible_with
+ restricted_to: Standard attribute, see http://go/be-common#common.restricted_to
+ visibility: A list of targets allowed to depend on this rule.
+ deprecation: Standard attribute, see http://go/be-common#common.deprecation
+ features: Features enabled.
+ """
+
+ tags = (tags or []) + ["kt_jvm_proto_library"]
+
+ native.java_proto_library(
+ name = _proto_name(name)[1:],
+ deps = deps,
+ testonly = testonly,
+ compatible_with = compatible_with,
+ visibility = ["//visibility:private"],
+ restricted_to = restricted_to,
+ tags = tags + ["avoid_dep"],
+ deprecation = deprecation,
+ features = features,
+ )
+
+ _kt_proto_library_helper(
+ name = name,
+ proto_deps = deps,
+ deps = [
+ _proto_name(name),
+ "//java/com/google/protobuf",
+ "//java/com/google/protobuf/kotlin:only_for_use_in_proto_generated_code_its_generator_and_tests",
+ "//java/com/google/protobuf/kotlin:shared_runtime",
+ ],
+ exports = [_proto_name(name)],
+ testonly = testonly,
+ compatible_with = compatible_with,
+ constraints = [],
+ restricted_to = restricted_to,
+ tags = tags,
+ variant = "full",
+ visibility = visibility,
+ deprecation = deprecation,
+ features = features,
+ )
+
+register_extension_info(
+ extension = kt_jvm_proto_library,
+ label_regex_for_dep = "{extension_name}",
+)
+
+register_extension_info(
+ extension = kt_jvm_lite_proto_library,
+ label_regex_for_dep = "{extension_name}",
+)
diff --git a/third_party/build_defs/kt_jvm_proto_library.internal.bzl b/third_party/build_defs/kt_jvm_proto_library.internal.bzl
new file mode 100644
index 0000000000..fcb2cd1537
--- /dev/null
+++ b/third_party/build_defs/kt_jvm_proto_library.internal.bzl
@@ -0,0 +1,177 @@
+"""Definitions for internals of Kotlin proto libraries."""
+
+load("//tools/build_defs/kotlin/release/rules:common.bzl", "common")
+load(
+ "//tools/build_defs/kotlin/release/rules:dep_checks_aspect.bzl",
+ "KtForbiddenInfo",
+ "dep_checks_aspect",
+)
+load(
+ "//tools/build_defs/kotlin/release/toolchains/kotlin_jvm:toolchain.bzl",
+ _toolchain = "toolchain",
+)
+
+def _get_real_short_path(file):
+ """Returns the correct short path file name to be used by protoc."""
+ short_path = file.short_path
+ if short_path.startswith("../"):
+ second_slash = short_path.index("/", 3)
+ short_path = short_path[second_slash + 1:]
+
+ virtual_imports = "_virtual_imports/"
+ if virtual_imports in short_path:
+ short_path = short_path.split(virtual_imports)[1].split("/", 1)[1]
+ return short_path
+
+def _kt_proto_extensions_impl(ctx):
+ for dep in ctx.attr.proto_deps + ctx.attr.deps + ctx.attr.exports:
+ if dep[KtForbiddenInfo].forbidden:
+ fail("""Not allowed to depend on %s from Kotlin code, see go/kotlin/build-rules#restrictions:
+ %s""" % (dep.label, "\n".join(dep[KtForbiddenInfo].forbidden)))
+
+ transitive_set = depset(
+ transitive =
+ [dep[ProtoInfo].transitive_descriptor_sets for dep in ctx.attr.proto_deps],
+ )
+ proto_sources = []
+ for dep in ctx.attr.proto_deps:
+ for file in dep[ProtoInfo].direct_sources:
+ proto_sources.append(_get_real_short_path(file))
+
+ gen_src_dir = ctx.actions.declare_directory(ctx.label.name + "/ktproto")
+ codegen_params = "lite:" if ctx.attr.variant == "lite" else ""
+
+ protoc_args = ctx.actions.args()
+ protoc_args.add("--kotlin_out=" + codegen_params + gen_src_dir.path)
+ protoc_args.add_joined(
+ transitive_set,
+ join_with = ctx.configuration.host_path_separator,
+ format_joined = "--descriptor_set_in=%s",
+ )
+ protoc_args.add_all(proto_sources)
+
+ ctx.actions.run(
+ inputs = depset(transitive = [transitive_set]),
+ outputs = [gen_src_dir],
+ executable = ctx.executable._protoc,
+ arguments = [protoc_args],
+ progress_message = "Generating kotlin proto extensions for " +
+ ", ".join([
+ str(dep.label)
+ for dep in ctx.attr.proto_deps
+ ]),
+ )
+
+ kt_toolchain = _toolchain.get(ctx)
+ compiler_plugins = [
+ kt_toolchain.marker_plugin,
+ kt_toolchain.strictdeps_plugin,
+ ]
+ result = common.kt_jvm_library(
+ ctx,
+ srcs = [gen_src_dir],
+ output = ctx.outputs.jar,
+ deps = [dep[JavaInfo] for dep in ctx.attr.deps],
+ exports = [dep[JavaInfo] for dep in ctx.attr.exports],
+ kotlincopts = ["-Xopt-in=kotlin.RequiresOptIn", "-nowarn"],
+ kt_toolchain = kt_toolchain,
+ java_toolchain = ctx.attr._java_toolchain,
+ compiler_plugins = compiler_plugins,
+ android_compatible = "android" in ctx.attr.constraints,
+ enforce_strict_deps = False,
+ )
+ java_info = java_common.add_constraints(
+ result.java_info,
+ constraints = ctx.attr.constraints,
+ )
+
+ transitive_runfiles = []
+ for p in common.collect_providers(DefaultInfo, ctx.attr.deps + ctx.attr.exports):
+ transitive_runfiles.append(p.data_runfiles.files)
+ transitive_runfiles.append(p.default_runfiles.files)
+ runfiles = ctx.runfiles(
+ files = [ctx.outputs.jar],
+ transitive_files = depset(transitive = transitive_runfiles),
+ collect_default = True,
+ )
+
+ return [
+ java_info,
+ OutputGroupInfo(_validation = depset(result.validations)),
+ DefaultInfo(
+ files = depset([ctx.outputs.jar]),
+ runfiles = runfiles,
+ ),
+ ProguardSpecProvider(depset(ctx.files._proguard_specs)),
+ ]
+
+kt_proto_library_helper = rule(
+ doc = """
+ This is a helper rule to combine the kotlin code generation work
+ of kt_jvm_proto_library and kt_jvm_lite_proto_library.
+
+ It generates Kotlin proto code with the protoc compiler using the
+ --kotlin_out flag and compiles that Kotlin code. It requires as a dependency
+ a proto_library and either a java_proto_library or java_lite_proto_library.
+ """,
+ attrs = dict(
+ proto_deps = attr.label_list(
+ providers = [ProtoInfo],
+ aspects = [dep_checks_aspect],
+ ),
+ deps = attr.label_list(
+ providers = [JavaInfo],
+ aspects = [dep_checks_aspect],
+ ),
+ exports = attr.label_list(
+ allow_rules = ["java_proto_library", "java_lite_proto_library"],
+ aspects = [dep_checks_aspect],
+ ),
+ constraints = attr.string_list(
+ doc = """Extra constraints imposed on this library, most commonly, 'android'. Constraints
+ typically indicate that the library may be used in binaries running outside of
+ Google production services. See go/be-java#java_library.constraints for details on
+ supported constraints and what they mean. Note that all Java and Kotlin `deps` are
+ required to carry compatible constraints.""",
+ ),
+ variant = attr.string(
+ mandatory = True,
+ values = ["lite", "full"],
+ doc = """Indicator of which Kotlin proto runtime to use.""",
+ ),
+ _protoc = attr.label(
+ default = Label("//net/proto2/compiler/public:protocol_compiler"),
+ cfg = "host",
+ executable = True,
+ ),
+ _java_toolchain = attr.label(
+ default = Label(
+ "//tools/jdk:current_java_toolchain",
+ ),
+ ),
+ _coverage_instrumenter = attr.label(
+ default = Label("//tools/build_defs/kotlin/release/rules:kt_coverage_instrumenter"),
+ cfg = "host",
+ executable = True,
+ ),
+ _coverage_runtime = attr.label(
+ default = Label("//third_party/java/jacoco:blaze-agent"),
+ ),
+ _toolchain = attr.label(
+ default = Label(
+ "//tools/build_defs/kotlin/release/toolchains/kotlin_jvm:kt_jvm_toolchain_internal_DO_NOT_USE",
+ ),
+ ),
+ _proguard_specs = attr.label_list(
+ allow_files = [".pgcfg"],
+ default = ["//java/com/google/protobuf/kotlin:kt_proto.pgcfg"],
+ ),
+ ),
+ fragments = ["java"],
+ outputs = dict(
+ jar = "lib%{name}.ktproto.jar",
+ ),
+ provides = [JavaInfo],
+ implementation = _kt_proto_extensions_impl,
+ toolchains = [_toolchain.type],
+)