Moving Kotlin DSL message generators to the kotlin/ directory.

Merge full and lite message generator into one while branching on if generating lite kotlin and/or jvm code.

PiperOrigin-RevId: 680580214
pull/18547/head
Protobuf Team Bot 2 months ago committed by Copybara-Service
parent ea69081412
commit 1c068db518
  1. 5
      src/google/protobuf/compiler/java/BUILD.bazel
  2. 2
      src/google/protobuf/compiler/java/field_common.cc
  3. 2
      src/google/protobuf/compiler/java/full/BUILD.bazel
  4. 1
      src/google/protobuf/compiler/java/full/field_generator.h
  5. 300
      src/google/protobuf/compiler/java/full/message.cc
  6. 5
      src/google/protobuf/compiler/java/full/message.h
  7. 1
      src/google/protobuf/compiler/java/generator_common.h
  8. 3
      src/google/protobuf/compiler/java/generator_factory.h
  9. 7
      src/google/protobuf/compiler/java/helpers.h
  10. 5
      src/google/protobuf/compiler/java/lite/BUILD.bazel
  11. 15
      src/google/protobuf/compiler/java/lite/field_generator.h
  12. 369
      src/google/protobuf/compiler/java/lite/message.cc
  13. 5
      src/google/protobuf/compiler/java/lite/message.h
  14. 18
      src/google/protobuf/compiler/kotlin/BUILD.bazel
  15. 30
      src/google/protobuf/compiler/kotlin/file.cc
  16. 5
      src/google/protobuf/compiler/kotlin/file.h
  17. 444
      src/google/protobuf/compiler/kotlin/message.cc
  18. 58
      src/google/protobuf/compiler/kotlin/message.h

@ -156,7 +156,10 @@ cc_library(
"generator_factory.h",
],
strip_include_prefix = "/src",
visibility = ["//src/google/protobuf/compiler/java:__subpackages__"],
visibility = [
"//src/google/protobuf/compiler/java:__subpackages__",
"//src/google/protobuf/compiler/kotlin:__subpackages__",
],
deps = [
":helpers",
"//src/google/protobuf",

@ -41,7 +41,7 @@ void SetCommonFieldVariables(
(*variables)["kt_capitalized_name"] =
IsForbiddenKotlin(info->name) ? absl::StrCat(info->capitalized_name, "_")
: info->capitalized_name;
(*variables)["jvm_synthetic"] = JvmSynthetic(info->options);
(*variables)["jvm_synthetic"] = JvmSynthetic(info->options.jvm_dsl);
if (!descriptor->is_repeated()) {
(*variables)["annotation_field_type"] =
std::string(FieldTypeName(descriptor->type()));

@ -4,6 +4,7 @@ cc_library(
name = "fg",
hdrs = ["field_generator.h"],
strip_include_prefix = "/src",
visibility = ["//src/google/protobuf/compiler/kotlin:__subpackages__"],
deps = [
"//src/google/protobuf/compiler/java:generator_common",
"//src/google/protobuf/io:printer",
@ -49,6 +50,7 @@ cc_library(
srcs = ["make_field_gens.cc"],
hdrs = ["make_field_gens.h"],
strip_include_prefix = "/src",
visibility = ["//src/google/protobuf/compiler/kotlin:__subpackages__"],
deps = [
":fg",
":fgs",

@ -33,7 +33,6 @@ class ImmutableFieldGenerator : public FieldGenerator {
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 GenerateBuilderParsingCodeFromPacked(
io::Printer* printer) const {

@ -1208,306 +1208,6 @@ void ImmutableMessageGenerator::GenerateMutableCopy(io::Printer* printer) {
"mutable_name", name_resolver_->GetJavaMutableClassName(descriptor_));
}
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(
"public class Dsl private constructor(\n"
" private val _builder: $message$.Builder\n"
") {\n"
" public 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",
EscapeKotlinKeywords(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& kv : oneofs_) {
const OneofDescriptor* oneof = kv.second;
printer->Print(
"public 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"
"public 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",
EscapeKotlinKeywords(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.JvmName(\"-initialize$camelcase_name$\")\n",
"camelcase_name",
name_resolver_->GetKotlinFactoryName(descriptor_));
printer->Print(
"public inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> "
"kotlin.Unit): "
"$message$ "
"=\n"
" $message_kt$.Dsl._create($message$.newBuilder()).apply { block() "
"}._build()\n",
"camelcase_name", name_resolver_->GetKotlinFactoryName(descriptor_),
"message_kt",
EscapeKotlinKeywords(
name_resolver_->GetKotlinExtensionsClassName(descriptor_)),
"message",
EscapeKotlinKeywords(name_resolver_->GetClassName(descriptor_, true)));
WriteMessageDocComment(printer, descriptor_, context_->options(),
/* kdoc */ true);
printer->Emit(
{
io::Printer::Sub{"name_kt", absl::StrCat(descriptor_->name(), "Kt")}
.AnnotatedAs(descriptor_),
{"body",
[&]() {
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);
}
}},
},
R"kt(
public object $name_kt$ {
$body$;
}
)kt");
}
void ImmutableMessageGenerator::GenerateTopLevelKotlinMembers(
io::Printer* printer) const {
printer->Print("@kotlin.jvm.JvmSynthetic\n");
printer->Print(
"public inline fun $message$.copy(block: $message_kt$.Dsl.() -> "
"kotlin.Unit): $message$ =\n"
" $message_kt$.Dsl._create(this.toBuilder()).apply { block() "
"}._build()\n\n",
"message",
EscapeKotlinKeywords(name_resolver_->GetClassName(descriptor_, true)),
"message_kt",
name_resolver_->GetKotlinExtensionsClassNameEscaped(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);
}
GenerateKotlinOrNull(printer);
}
void ImmutableMessageGenerator::GenerateKotlinOrNull(
io::Printer* printer) const {
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
if (field->has_presence() && GetJavaType(field) == JAVATYPE_MESSAGE) {
if (field->options().deprecated()) {
printer->Print(
"@kotlin.Deprecated(message = \"Field $name$ is deprecated\")\n",
"name", context_->GetFieldGeneratorInfo(field)->name);
}
printer->Print(
"public val $full_classname$OrBuilder.$camelcase_name$OrNull: "
"$full_name$?\n"
" get() = if (has$name$()) get$name$() else null\n\n",
"full_classname",
EscapeKotlinKeywords(name_resolver_->GetClassName(descriptor_, true)),
"camelcase_name", context_->GetFieldGeneratorInfo(field)->name,
"full_name",
EscapeKotlinKeywords(
name_resolver_->GetImmutableClassName(field->message_type())),
"name", context_->GetFieldGeneratorInfo(field)->capitalized_name);
}
}
}
void ImmutableMessageGenerator::GenerateKotlinExtensions(
io::Printer* printer) const {
std::string message_name =
EscapeKotlinKeywords(name_resolver_->GetClassName(descriptor_, true));
printer->Print(
"@Suppress(\"UNCHECKED_CAST\")\n"
"@kotlin.jvm.JvmSynthetic\n"
"public operator fun <T : kotlin.Any> get(extension: "
"com.google.protobuf.ExtensionLite<$message$, T>): T {\n"
" return if (extension.isRepeated) {\n"
" get(extension as com.google.protobuf.ExtensionLite<$message$, "
"kotlin.collections.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"
"public operator fun <E : kotlin.Any> get(\n"
" extension: com.google.protobuf.ExtensionLite<$message$, "
"kotlin.collections.List<E>>\n"
"): com.google.protobuf.kotlin.ExtensionList<E, $message$> {\n"
" return com.google.protobuf.kotlin.ExtensionList(extension, "
"_builder.getExtension(extension))\n"
"}\n\n",
"message", message_name);
printer->Print(
"@kotlin.jvm.JvmSynthetic\n"
"public 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"
"public fun clear(extension: "
"com.google.protobuf.ExtensionLite<$message$, *>) "
"{\n"
" _builder.clearExtension(extension)\n"
"}\n\n",
"message", message_name);
printer->Print(
"@kotlin.jvm.JvmSynthetic\n"
"public fun <T : kotlin.Any> 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"
"@Suppress(\"NOTHING_TO_INLINE\")\n"
"public inline operator fun <T : Comparable<T>> 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"
"@Suppress(\"NOTHING_TO_INLINE\")\n"
"public 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"
"@Suppress(\"NOTHING_TO_INLINE\")\n"
"public inline operator fun <T : com.google.protobuf.MessageLite> 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"
"public fun <E : kotlin.Any> com.google.protobuf.kotlin.ExtensionList<E, "
"$message$>.add(value: E) {\n"
" _builder.addExtension(this.extension, value)\n"
"}\n\n",
"message", message_name);
printer->Print(
"@kotlin.jvm.JvmSynthetic\n"
"@Suppress(\"NOTHING_TO_INLINE\")\n"
"public inline operator fun <E : kotlin.Any> "
"com.google.protobuf.kotlin.ExtensionList<E, "
"$message$>.plusAssign"
"(value: E) {\n"
" add(value)\n"
"}\n\n",
"message", message_name);
printer->Print(
"@kotlin.jvm.JvmSynthetic\n"
"public fun <E : kotlin.Any> com.google.protobuf.kotlin.ExtensionList<E, "
"$message$>.addAll(values: Iterable<E>) {\n"
" for (value in values) {\n"
" add(value)\n"
" }\n"
"}\n\n",
"message", message_name);
printer->Print(
"@kotlin.jvm.JvmSynthetic\n"
"@Suppress(\"NOTHING_TO_INLINE\")\n"
"public inline operator fun <E : kotlin.Any> "
"com.google.protobuf.kotlin.ExtensionList<E, "
"$message$>.plusAssign(values: "
"Iterable<E>) {\n"
" addAll(values)\n"
"}\n\n",
"message", message_name);
printer->Print(
"@kotlin.jvm.JvmSynthetic\n"
"public operator fun <E : kotlin.Any> "
"com.google.protobuf.kotlin.ExtensionList<E, "
"$message$>.set(index: Int, value: "
"E) {\n"
" _builder.setExtension(this.extension, index, value)\n"
"}\n\n",
"message", message_name);
printer->Print(
"@kotlin.jvm.JvmSynthetic\n"
"@Suppress(\"NOTHING_TO_INLINE\")\n"
"public 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"

@ -55,9 +55,6 @@ class ImmutableMessageGenerator : public MessageGenerator {
// Returns an estimate of the number of bytes the printed code will compile to
int GenerateStaticVariableInitializers(io::Printer* printer) override;
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);
@ -76,8 +73,6 @@ class ImmutableMessageGenerator : public MessageGenerator {
void GenerateParser(io::Printer* printer);
void GenerateParsingConstructor(io::Printer* printer);
void GenerateMutableCopy(io::Printer* printer);
void GenerateKotlinExtensions(io::Printer* printer) const;
void GenerateKotlinOrNull(io::Printer* printer) const;
void GenerateAnyMethods(io::Printer* printer);
Context* context_;

@ -23,6 +23,7 @@ class FieldGenerator {
public:
virtual ~FieldGenerator() = default;
virtual void GenerateSerializationCode(io::Printer* printer) const = 0;
virtual void GenerateKotlinDslMembers(io::Printer* printer) const = 0;
};
// Convenience class which constructs FieldGenerators for a Descriptor.

@ -51,9 +51,6 @@ 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_;

@ -380,17 +380,18 @@ const FieldDescriptor* MapKeyField(const FieldDescriptor* descriptor);
const FieldDescriptor* MapValueField(const FieldDescriptor* descriptor);
inline std::string JvmSynthetic(const Options& options) {
return options.jvm_dsl ? "@kotlin.jvm.JvmSynthetic\n" : "";
inline std::string JvmSynthetic(bool jvm_dsl) {
return jvm_dsl ? "@kotlin.jvm.JvmSynthetic\n" : "";
}
struct JvmNameContext {
const Options& options;
io::Printer* printer;
bool lite = true;
};
inline void JvmName(absl::string_view name, const JvmNameContext& context) {
if (!context.options.jvm_dsl) return;
if (context.lite && !context.options.jvm_dsl) return;
context.printer->Emit("@kotlin.jvm.JvmName(\"");
// Note: `name` will likely have vars in it that we do want to interpolate.
context.printer->Emit(name);

@ -24,7 +24,10 @@ cc_library(
"string_field.h",
],
strip_include_prefix = "/src",
visibility = ["//src/google/protobuf/compiler/java:__subpackages__"],
visibility = [
"//src/google/protobuf/compiler/java:__subpackages__",
"//src/google/protobuf/compiler/kotlin:__subpackages__",
],
deps = [
"//src/google/protobuf",
"//src/google/protobuf:port",

@ -1,8 +1,10 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_IMMUTABLE_FIELD_GENERATOR_H__
#define GOOGLE_PROTOBUF_COMPILER_JAVA_IMMUTABLE_FIELD_GENERATOR_H__
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_LITE_FIELD_GENERATOR_H__
#define GOOGLE_PROTOBUF_COMPILER_JAVA_LITE_FIELD_GENERATOR_H__
#include <string>
#include "absl/log/absl_log.h"
#include "google/protobuf/compiler/java/generator_common.h"
#include "google/protobuf/io/printer.h"
namespace google {
@ -10,7 +12,7 @@ namespace protobuf {
namespace compiler {
namespace java {
class ImmutableFieldLiteGenerator {
class ImmutableFieldLiteGenerator : public FieldGenerator {
public:
ImmutableFieldLiteGenerator() = default;
ImmutableFieldLiteGenerator(const ImmutableFieldLiteGenerator&) = delete;
@ -25,7 +27,10 @@ class ImmutableFieldLiteGenerator {
virtual void GenerateInitializationCode(io::Printer* printer) const = 0;
virtual void GenerateFieldInfo(io::Printer* printer,
std::vector<uint16_t>* output) const = 0;
virtual void GenerateKotlinDslMembers(io::Printer* printer) const = 0;
void GenerateSerializationCode(io::Printer* printer) const override {
ABSL_LOG(FATAL) << "GenerateSerializationCode is unsupported for lite.";
}
virtual std::string GetBoxedType() const = 0;
};
@ -35,4 +40,4 @@ class ImmutableFieldLiteGenerator {
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_IMMUTABLE_FIELD_GENERATOR_H__
#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_LITE_FIELD_GENERATOR_H__

@ -743,375 +743,6 @@ 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(
"public class Dsl private constructor(\n"
" private val _builder: $message$.Builder\n"
") {\n"
" public companion object {\n"
"$ jvm_synthetic$"
" @kotlin.PublishedApi\n"
" internal fun _create(builder: $message$.Builder): Dsl = "
"Dsl(builder)\n"
" }\n"
"\n"
"$ jvm_synthetic$"
" @kotlin.PublishedApi\n"
" internal fun _build(): $message$ = _builder.build()\n",
"jvm_synthetic", JvmSynthetic(context_->options()), "message",
EscapeKotlinKeywords(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& kv : oneofs_) {
JvmNameContext name_ctx = {context_->options(), printer};
const OneofDescriptor* oneof = kv.second;
auto oneof_name = context_->GetOneofGeneratorInfo(oneof)->name;
printer->Emit(
{
{"jvm_name",
[&] { JvmName("get$oneof_capitalized_name$Case", name_ctx); }},
{"oneof_name", oneof_name},
{"oneof_capitalized_name",
context_->GetOneofGeneratorInfo(oneof)->capitalized_name},
{"oneof_property_name", GetKotlinPropertyName(oneof_name)},
{"message", EscapeKotlinKeywords(
name_resolver_->GetClassName(descriptor_, true))},
},
"public val $oneof_name$Case: $message$.$oneof_capitalized_name$Case\n"
"$jvm_name$"
" get() = _builder.$oneof_property_name$Case\n\n"
"public fun clear$oneof_capitalized_name$() {\n"
" _builder.clear$oneof_capitalized_name$()\n"
"}\n");
}
if (descriptor_->extension_range_count() > 0) {
GenerateKotlinExtensions(printer);
}
printer->Outdent();
printer->Print("}\n");
}
void ImmutableMessageLiteGenerator::GenerateKotlinMembers(
io::Printer* printer) const {
if (context_->options().jvm_dsl) {
printer->Print("@kotlin.jvm.JvmName(\"-initialize$camelcase_name$\")\n",
"camelcase_name",
name_resolver_->GetKotlinFactoryName(descriptor_));
}
printer->Print(
"public inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> "
"kotlin.Unit): $message$ =\n"
" $message_kt$.Dsl._create($message$.newBuilder()).apply { block() "
"}._build()\n",
"camelcase_name", name_resolver_->GetKotlinFactoryName(descriptor_),
"message_kt",
EscapeKotlinKeywords(
name_resolver_->GetKotlinExtensionsClassName(descriptor_)),
"message",
EscapeKotlinKeywords(name_resolver_->GetClassName(descriptor_, true)));
WriteMessageDocComment(printer, descriptor_, context_->options(),
/* kdoc */ true);
printer->Print("public 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(
"public inline fun $message$.copy(block: $message_kt$.Dsl.() -> "
"kotlin.Unit): $message$ =\n"
" $message_kt$.Dsl._create(this.toBuilder()).apply { block() "
"}._build()\n\n",
"message",
EscapeKotlinKeywords(name_resolver_->GetClassName(descriptor_, true)),
"message_kt",
name_resolver_->GetKotlinExtensionsClassNameEscaped(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);
}
GenerateKotlinOrNull(printer);
}
void ImmutableMessageLiteGenerator::GenerateKotlinOrNull(
io::Printer* printer) const {
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
if (!field->has_presence() || GetJavaType(field) != JAVATYPE_MESSAGE) {
continue;
}
if (context_->options().jvm_dsl) {
// On the JVM, we can use `FooOrBuilder`, and it saves code size to
// generate only one method instead of two.
if (field->options().deprecated()) {
printer->Print(
"@kotlin.Deprecated(message = \"Field $name$ is deprecated\")\n",
"name", context_->GetFieldGeneratorInfo(field)->name);
}
printer->Print(
"public val $full_classname$OrBuilder.$camelcase_name$OrNull: "
"$full_name$?\n"
" get() = if (has$name$()) get$name$() else null\n\n",
"full_classname",
EscapeKotlinKeywords(name_resolver_->GetClassName(descriptor_, true)),
"camelcase_name", context_->GetFieldGeneratorInfo(field)->name,
"full_name",
EscapeKotlinKeywords(
name_resolver_->GetImmutableClassName(field->message_type())),
"name", context_->GetFieldGeneratorInfo(field)->capitalized_name);
} else {
// Non-JVM platforms don't have `FooOrBuilder`, so we generate `Foo`
// and `Foo.Builder` methods.
if (field->options().deprecated()) {
printer->Print(
"@kotlin.Deprecated(message = \"Field $name$ is deprecated\")\n",
"name", context_->GetFieldGeneratorInfo(field)->name);
}
printer->Print(
"public val $full_classname$.$camelcase_name$OrNull: "
"$full_name$?\n"
" get() = if (has$capitalized_name$()) this.$name$ else null\n\n",
"full_classname",
EscapeKotlinKeywords(name_resolver_->GetClassName(descriptor_, true)),
"camelcase_name", context_->GetFieldGeneratorInfo(field)->name,
"full_name",
EscapeKotlinKeywords(
name_resolver_->GetImmutableClassName(field->message_type())),
"capitalized_name",
context_->GetFieldGeneratorInfo(field)->capitalized_name, "name",
EscapeKotlinKeywords(GetKotlinPropertyName(
context_->GetFieldGeneratorInfo(field)->capitalized_name)));
if (field->options().deprecated()) {
printer->Print(
"@kotlin.Deprecated(message = \"Field $name$ is deprecated\")\n",
"name", context_->GetFieldGeneratorInfo(field)->name);
}
printer->Print(
"public val $full_classname$.Builder.$camelcase_name$OrNull: "
"$full_name$?\n"
" get() = if (has$capitalized_name$()) this.$name$ else null\n\n",
"full_classname",
EscapeKotlinKeywords(name_resolver_->GetClassName(descriptor_, true)),
"camelcase_name", context_->GetFieldGeneratorInfo(field)->name,
"full_name",
EscapeKotlinKeywords(
name_resolver_->GetImmutableClassName(field->message_type())),
"capitalized_name",
context_->GetFieldGeneratorInfo(field)->capitalized_name, "name",
EscapeKotlinKeywords(GetKotlinPropertyName(
context_->GetFieldGeneratorInfo(field)->capitalized_name)));
}
}
}
void ImmutableMessageLiteGenerator::GenerateKotlinExtensions(
io::Printer* printer) const {
JvmNameContext name_ctx = {context_->options(), printer};
std::string message_name =
EscapeKotlinKeywords(name_resolver_->GetClassName(descriptor_, true));
printer->Print(
"@Suppress(\"UNCHECKED_CAST\")\n"
"$jvm_synthetic$"
"public operator fun <T : kotlin.Any> get(extension: "
"com.google.protobuf.ExtensionLite<$message$, T>): T {\n"
" return if (extension.isRepeated) {\n"
" get(extension as com.google.protobuf.ExtensionLite<$message$, "
"kotlin.collections.List<*>>) as T\n"
" } else {\n"
" _builder.getExtension(extension)\n"
" }\n"
"}\n\n",
"jvm_synthetic", JvmSynthetic(context_->options()), "message",
message_name);
if (context_->options().jvm_dsl) {
// TODO: generate this on Kotlin Native once the [Mutable]List
// issue is resolved.
printer->Emit(
{
{"jvm_name", [&] { JvmName("-getRepeatedExtension", name_ctx); }},
{"jvm_synthetic", JvmSynthetic(context_->options())},
{"message", message_name},
},
"$jvm_synthetic$"
"@kotlin.OptIn"
"(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
"$jvm_name$"
"public operator fun <E : kotlin.Any> get(\n"
" extension: com.google.protobuf.ExtensionLite<$message$, "
"kotlin.collections.List<E>>\n"
"): com.google.protobuf.kotlin.ExtensionList<E, $message$> {\n"
" return com.google.protobuf.kotlin.ExtensionList(extension, "
"_builder.getExtension(extension))\n"
"}\n\n");
}
printer->Print(
"$jvm_synthetic$"
"public operator fun contains(extension: "
"com.google.protobuf.ExtensionLite<$message$, *>): "
"Boolean {\n"
" return _builder.hasExtension(extension)\n"
"}\n\n",
"jvm_synthetic", JvmSynthetic(context_->options()), "message",
message_name);
printer->Print(
"$jvm_synthetic$"
"public fun clear(extension: "
"com.google.protobuf.ExtensionLite<$message$, *>) "
"{\n"
" _builder.clearExtension(extension)\n"
"}\n\n",
"jvm_synthetic", JvmSynthetic(context_->options()), "message",
message_name);
printer->Print(
"$jvm_synthetic$"
"public fun <T : kotlin.Any> setExtension(extension: "
"com.google.protobuf.ExtensionLite<$message$, T>, "
"value: T) {\n"
" _builder.setExtension(extension, value)\n"
"}\n\n",
"jvm_synthetic", JvmSynthetic(context_->options()), "message",
message_name);
printer->Print(
"$jvm_synthetic$"
"@Suppress(\"NOTHING_TO_INLINE\")\n"
"public inline operator fun <T : Comparable<T>> set(\n"
" extension: com.google.protobuf.ExtensionLite<$message$, T>,\n"
" value: T\n"
") {\n"
" setExtension(extension, value)\n"
"}\n\n",
"jvm_synthetic", JvmSynthetic(context_->options()), "message",
message_name);
printer->Print(
"$jvm_synthetic$"
"@Suppress(\"NOTHING_TO_INLINE\")\n"
"public 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",
"jvm_synthetic", JvmSynthetic(context_->options()), "message",
message_name);
printer->Print(
"$jvm_synthetic$"
"@Suppress(\"NOTHING_TO_INLINE\")\n"
"public inline operator fun <T : com.google.protobuf.MessageLite> set(\n"
" extension: com.google.protobuf.ExtensionLite<$message$, T>,\n"
" value: T\n"
") {\n"
" setExtension(extension, value)\n"
"}\n\n",
"jvm_synthetic", JvmSynthetic(context_->options()), "message",
message_name);
// TODO: generate these methods on Kotlin Native once the
// [Mutable]List issue is resolved.
if (!context_->options().jvm_dsl) return;
printer->Print(
"$jvm_synthetic$"
"public fun<E : kotlin.Any> com.google.protobuf.kotlin.ExtensionList<E, "
"$message$>.add(value: E) {\n"
" _builder.addExtension(this.extension, value)\n"
"}\n\n",
"jvm_synthetic", JvmSynthetic(context_->options()), "message",
message_name);
printer->Print(
"$jvm_synthetic$"
"@Suppress(\"NOTHING_TO_INLINE\")\n"
"public inline operator fun <E : kotlin.Any> "
"com.google.protobuf.kotlin.ExtensionList<E, "
"$message$>.plusAssign"
"(value: E) {\n"
" add(value)\n"
"}\n\n",
"jvm_synthetic", JvmSynthetic(context_->options()), "message",
message_name);
printer->Print(
"$jvm_synthetic$"
"public fun<E : kotlin.Any> com.google.protobuf.kotlin.ExtensionList<E, "
"$message$>.addAll(values: Iterable<E>) {\n"
" for (value in values) {\n"
" add(value)\n"
" }\n"
"}\n\n",
"jvm_synthetic", JvmSynthetic(context_->options()), "message",
message_name);
printer->Print(
"$jvm_synthetic$"
"@Suppress(\"NOTHING_TO_INLINE\")\n"
"public inline operator fun <E : kotlin.Any> "
"com.google.protobuf.kotlin.ExtensionList<E, "
"$message$>.plusAssign(values: "
"Iterable<E>) {\n"
" addAll(values)\n"
"}\n\n",
"jvm_synthetic", JvmSynthetic(context_->options()), "message",
message_name);
printer->Print(
"$jvm_synthetic$"
"public operator fun <E : kotlin.Any> "
"com.google.protobuf.kotlin.ExtensionList<E, "
"$message$>.set(index: Int, value: "
"E) {\n"
" _builder.setExtension(this.extension, index, value)\n"
"}\n\n",
"jvm_synthetic", JvmSynthetic(context_->options()), "message",
message_name);
printer->Print(
"$jvm_synthetic$"
"@Suppress(\"NOTHING_TO_INLINE\")\n"
"public inline fun com.google.protobuf.kotlin.ExtensionList<*, "
"$message$>.clear() {\n"
" clear(extension)\n"
"}\n\n",
"jvm_synthetic", JvmSynthetic(context_->options()), "message",
message_name);
}
} // namespace java
} // namespace compiler
} // namespace protobuf

@ -42,9 +42,6 @@ class ImmutableMessageLiteGenerator : public MessageGenerator {
void GenerateStaticVariables(io::Printer* printer,
int* bytecode_estimate) override;
int GenerateStaticVariableInitializers(io::Printer* printer) override;
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);
@ -55,8 +52,6 @@ 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;
void GenerateKotlinOrNull(io::Printer* printer) const;
Context* context_;
ClassNameResolver* name_resolver_;

@ -21,8 +21,14 @@ cc_library(
cc_library(
name = "kotlin_internal",
srcs = ["file.cc"],
hdrs = ["file.h"],
srcs = [
"file.cc",
"message.cc",
],
hdrs = [
"file.h",
"message.h",
],
strip_include_prefix = "/src",
visibility = [
"//pkg:__pkg__",
@ -34,11 +40,15 @@ cc_library(
"//src/google/protobuf:protobuf_lite",
"//src/google/protobuf/compiler:code_generator",
"//src/google/protobuf/compiler/java",
"//src/google/protobuf/compiler/java:generator_common",
"//src/google/protobuf/compiler/java:helpers",
"//src/google/protobuf/compiler/java/full",
"//src/google/protobuf/compiler/java/lite",
"//src/google/protobuf/compiler/java/full:fg",
"//src/google/protobuf/compiler/java/full:mfg",
"//src/google/protobuf/compiler/java/lite:field_generators",
"//src/google/protobuf/io",
"//src/google/protobuf/io:printer",
"@com_google_absl//absl/container:btree",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/strings",
],
)

@ -5,8 +5,6 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
// Generates Kotlin code for a given .proto file.
#include "google/protobuf/compiler/kotlin/file.h"
#include <memory>
@ -16,13 +14,11 @@
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/java/context.h"
#include "google/protobuf/compiler/java/generator_factory.h"
#include "google/protobuf/compiler/java/helpers.h"
#include "google/protobuf/compiler/java/full/generator_factory.h"
#include "google/protobuf/compiler/java/lite/generator_factory.h"
#include "google/protobuf/compiler/java/name_resolver.h"
#include "google/protobuf/compiler/java/names.h"
#include "google/protobuf/compiler/java/options.h"
#include "google/protobuf/compiler/kotlin/message.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/printer.h"
@ -34,30 +30,16 @@ namespace kotlin {
using google::protobuf::compiler::java::Context;
using google::protobuf::compiler::java::Options;
// class LiteGeneratorFactory;
namespace {
std::unique_ptr<java::GeneratorFactory> CreateGeneratorFactory(
const FileDescriptor* file, const Options& options, Context* context) {
if (java::HasDescriptorMethods(file, context->EnforceLite())) {
return java::MakeImmutableGeneratorFactory(context);
} else {
return java::MakeImmutableLiteGeneratorFactory(context);
}
}
} // namespace
FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)
: file_(file),
java_package_(java::FileJavaPackage(file, options)),
message_generators_(file->message_type_count()),
context_(new Context(file, options)),
generator_factory_(CreateGeneratorFactory(file, options, context_.get())),
name_resolver_(context_->GetNameResolver()),
options_(options) {
for (int i = 0; i < file_->message_type_count(); ++i) {
message_generators_[i] =
generator_factory_->NewMessageGenerator(file_->message_type(i));
message_generators_[i] = std::make_unique<MessageGenerator>(
file_->message_type(i), context_.get());
}
}
@ -91,7 +73,7 @@ void FileGenerator::GenerateSiblings(
std::vector<std::string>* annotation_list) {
for (int i = 0; i < file_->message_type_count(); i++) {
const Descriptor* descriptor = file_->message_type(i);
java::MessageGenerator* generator = message_generators_[i].get();
MessageGenerator* generator = message_generators_[i].get();
auto open_file = [context](const std::string& filename) {
return std::unique_ptr<io::ZeroCopyOutputStream>(context->Open(filename));
};
@ -125,8 +107,8 @@ void FileGenerator::GenerateSiblings(
"package", java::EscapeKotlinKeywords(java_package_));
}
generator->GenerateKotlinMembers(&printer);
generator->GenerateTopLevelKotlinMembers(&printer);
generator->GenerateMembers(&printer);
generator->GenerateTopLevelMembers(&printer);
if (options_.annotate_code) {
auto info_output = open_file(info_full_path);

@ -14,8 +14,8 @@
#include <string>
#include <vector>
#include "google/protobuf/compiler/java/generator_factory.h"
#include "google/protobuf/compiler/java/options.h"
#include "google/protobuf/compiler/kotlin/message.h"
namespace google {
namespace protobuf {
@ -64,9 +64,8 @@ class FileGenerator {
const FileDescriptor* file_;
std::string java_package_;
std::vector<std::unique_ptr<java::MessageGenerator>> message_generators_;
std::vector<std::unique_ptr<MessageGenerator>> message_generators_;
std::unique_ptr<java::Context> context_;
std::unique_ptr<java::GeneratorFactory> generator_factory_;
java::ClassNameResolver* name_resolver_;
const java::Options options_;
};

@ -0,0 +1,444 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "google/protobuf/compiler/kotlin/message.h"
#include <string>
#include "absl/log/absl_check.h"
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/java/context.h"
#include "google/protobuf/compiler/java/doc_comment.h"
#include "google/protobuf/compiler/java/field_common.h"
#include "google/protobuf/compiler/java/generator_common.h"
#include "google/protobuf/compiler/java/helpers.h"
#include "google/protobuf/compiler/java/full/field_generator.h"
#include "google/protobuf/compiler/java/full/make_field_gens.h"
#include "google/protobuf/compiler/java/lite/field_generator.h"
#include "google/protobuf/compiler/java/lite/make_field_gens.h"
#include "google/protobuf/compiler/java/name_resolver.h"
#include "google/protobuf/io/printer.h"
// Must be last.
#include "google/protobuf/port_def.inc"
namespace google {
namespace protobuf {
namespace compiler {
namespace kotlin {
MessageGenerator::MessageGenerator(const Descriptor* descriptor,
java::Context* context)
: context_(context),
name_resolver_(context->GetNameResolver()),
descriptor_(descriptor),
lite_(!java::HasDescriptorMethods(descriptor_->file(),
context->EnforceLite())),
jvm_dsl_(!lite_ || context->options().jvm_dsl),
lite_field_generators_(
java::FieldGeneratorMap<java::ImmutableFieldLiteGenerator>(
descriptor_)),
field_generators_(
java::FieldGeneratorMap<java::ImmutableFieldGenerator>(descriptor_)) {
for (int i = 0; i < descriptor_->field_count(); i++) {
if (java::IsRealOneof(descriptor_->field(i))) {
const OneofDescriptor* oneof = descriptor_->field(i)->containing_oneof();
ABSL_CHECK(oneofs_.emplace(oneof->index(), oneof).first->second == oneof);
}
}
if (lite_) {
lite_field_generators_ =
java::MakeImmutableFieldLiteGenerators(descriptor_, context_);
} else {
field_generators_ =
java::MakeImmutableFieldGenerators(descriptor_, context_);
}
}
void MessageGenerator::GenerateFieldMembers(io::Printer* printer) const {
for (int i = 0; i < descriptor_->field_count(); i++) {
printer->Print("\n");
if (lite_) {
lite_field_generators_.get(descriptor_->field(i))
.GenerateKotlinDslMembers(printer);
} else {
field_generators_.get(descriptor_->field(i))
.GenerateKotlinDslMembers(printer);
}
}
}
void MessageGenerator::Generate(io::Printer* printer) const {
printer->Print(
"@kotlin.OptIn"
"(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
"@com.google.protobuf.kotlin.ProtoDslMarker\n");
printer->Print(
"public class Dsl private constructor(\n"
" private val _builder: $message$.Builder\n"
") {\n"
" public companion object {\n"
" $jvm_synthetic$"
" @kotlin.PublishedApi\n"
" internal fun _create(builder: $message$.Builder): Dsl = "
"Dsl(builder)\n"
" }\n"
"\n"
" $jvm_synthetic$"
" @kotlin.PublishedApi\n"
" internal fun _build(): $message$ = _builder.build()\n",
"jvm_synthetic", java::JvmSynthetic(jvm_dsl_), "message",
java::EscapeKotlinKeywords(
name_resolver_->GetClassName(descriptor_, true)));
printer->Indent();
GenerateFieldMembers(printer);
for (auto& kv : oneofs_) {
java::JvmNameContext name_ctx = {context_->options(), printer, lite_};
const OneofDescriptor* oneof = kv.second;
auto oneof_name = context_->GetOneofGeneratorInfo(oneof)->name;
std::string oneof_capitalized_name =
context_->GetOneofGeneratorInfo(oneof)->capitalized_name;
std::string oneof_case_getter =
lite_ ? absl::StrCat(java::GetKotlinPropertyName(oneof_name), "Case")
: absl::StrCat("get", oneof_capitalized_name, "Case()");
printer->Emit(
{
{"jvm_name",
[&] {
java::JvmName("get$oneof_capitalized_name$Case", name_ctx);
}},
{"oneof_name", oneof_name},
{"oneof_capitalized_name", oneof_capitalized_name},
{"oneof_case_getter", oneof_case_getter},
{"message", java::EscapeKotlinKeywords(
name_resolver_->GetClassName(descriptor_, true))},
},
"public val $oneof_name$Case: $message$.$oneof_capitalized_name$Case\n"
"$jvm_name$"
" get() = _builder.$oneof_case_getter$\n\n"
"public fun clear$oneof_capitalized_name$() {\n"
" _builder.clear$oneof_capitalized_name$()\n"
"}\n");
}
if (descriptor_->extension_range_count() > 0) {
GenerateExtensions(printer);
}
printer->Outdent();
printer->Print("}\n");
}
void MessageGenerator::GenerateMembers(io::Printer* printer) const {
if (jvm_dsl_) {
printer->Print("@kotlin.jvm.JvmName(\"-initialize$camelcase_name$\")\n",
"camelcase_name",
name_resolver_->GetKotlinFactoryName(descriptor_));
}
printer->Print(
"public inline fun $camelcase_name$(block: $message_kt$.Dsl.() -> "
"kotlin.Unit): $message$ =\n"
" $message_kt$.Dsl._create($message$.newBuilder()).apply { block() "
"}._build()\n",
"camelcase_name", name_resolver_->GetKotlinFactoryName(descriptor_),
"message_kt",
java::EscapeKotlinKeywords(
name_resolver_->GetKotlinExtensionsClassName(descriptor_)),
"message",
java::EscapeKotlinKeywords(
name_resolver_->GetClassName(descriptor_, true)));
WriteMessageDocComment(printer, descriptor_, context_->options(),
/* kdoc */ true);
printer->Emit(
{
io::Printer::Sub{"name_kt", absl::StrCat(descriptor_->name(), "Kt")}
.AnnotatedAs(descriptor_),
{"body",
[&]() {
Generate(printer);
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
if (java::IsMapEntry(descriptor_->nested_type(i))) continue;
MessageGenerator(descriptor_->nested_type(i), context_)
.GenerateMembers(printer);
}
}},
},
R"kt(
public object $name_kt$ {
$body$;
}
)kt");
}
void MessageGenerator::GenerateTopLevelMembers(io::Printer* printer) const {
if (!lite_) printer->Print("@kotlin.jvm.JvmSynthetic\n");
printer->Print(
"public inline fun $message$.copy(block: $message_kt$.Dsl.() -> "
"kotlin.Unit): $message$ =\n"
" $message_kt$.Dsl._create(this.toBuilder()).apply { block() "
"}._build()\n\n",
"message",
java::EscapeKotlinKeywords(
name_resolver_->GetClassName(descriptor_, true)),
"message_kt",
name_resolver_->GetKotlinExtensionsClassNameEscaped(descriptor_));
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
if (java::IsMapEntry(descriptor_->nested_type(i))) continue;
MessageGenerator(descriptor_->nested_type(i), context_)
.GenerateTopLevelMembers(printer);
}
GenerateOrNull(printer);
}
void MessageGenerator::GenerateOrNull(io::Printer* printer) const {
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
if (!field->has_presence() ||
java::GetJavaType(field) != java::JAVATYPE_MESSAGE) {
continue;
}
if (field->options().deprecated()) {
printer->Print(
"@kotlin.Deprecated(message = \"Field $name$ is deprecated\")\n",
"name", context_->GetFieldGeneratorInfo(field)->name);
}
if (jvm_dsl_) {
// On the JVM, we can use `FooOrBuilder`, and it saves code size to
// generate only one method instead of two.
printer->Print(
"public val $full_classname$OrBuilder.$camelcase_name$OrNull: "
"$full_name$?\n"
" get() = if (has$name$()) get$name$() else null\n\n",
"full_classname",
java::EscapeKotlinKeywords(
name_resolver_->GetClassName(descriptor_, true)),
"camelcase_name", context_->GetFieldGeneratorInfo(field)->name,
"full_name",
java::EscapeKotlinKeywords(
name_resolver_->GetImmutableClassName(field->message_type())),
"name", context_->GetFieldGeneratorInfo(field)->capitalized_name);
} else {
// Non-JVM platforms don't have `FooOrBuilder`, so we generate `Foo`
// and `Foo.Builder` methods.
printer->Print(
"public val $full_classname$.$camelcase_name$OrNull: "
"$full_name$?\n"
" get() = if (has$capitalized_name$()) this.$name$ else null\n\n",
"full_classname",
java::EscapeKotlinKeywords(
name_resolver_->GetClassName(descriptor_, true)),
"camelcase_name", context_->GetFieldGeneratorInfo(field)->name,
"full_name",
java::EscapeKotlinKeywords(
name_resolver_->GetImmutableClassName(field->message_type())),
"capitalized_name",
context_->GetFieldGeneratorInfo(field)->capitalized_name, "name",
java::EscapeKotlinKeywords(java::GetKotlinPropertyName(
context_->GetFieldGeneratorInfo(field)->capitalized_name)));
if (field->options().deprecated()) {
printer->Print(
"@kotlin.Deprecated(message = \"Field $name$ is deprecated\")\n",
"name", context_->GetFieldGeneratorInfo(field)->name);
}
printer->Print(
"public val $full_classname$.Builder.$camelcase_name$OrNull: "
"$full_name$?\n"
" get() = if (has$capitalized_name$()) this.$name$ else null\n\n",
"full_classname",
java::EscapeKotlinKeywords(
name_resolver_->GetClassName(descriptor_, true)),
"camelcase_name", context_->GetFieldGeneratorInfo(field)->name,
"full_name",
java::EscapeKotlinKeywords(
name_resolver_->GetImmutableClassName(field->message_type())),
"capitalized_name",
context_->GetFieldGeneratorInfo(field)->capitalized_name, "name",
java::EscapeKotlinKeywords(java::GetKotlinPropertyName(
context_->GetFieldGeneratorInfo(field)->capitalized_name)));
}
}
}
void MessageGenerator::GenerateExtensions(io::Printer* printer) const {
java::JvmNameContext name_ctx = {context_->options(), printer, lite_};
std::string message_name = java::EscapeKotlinKeywords(
name_resolver_->GetClassName(descriptor_, true));
printer->Print(
"@Suppress(\"UNCHECKED_CAST\")\n"
"$jvm_synthetic$"
"public operator fun <T : kotlin.Any> get(extension: "
"com.google.protobuf.ExtensionLite<$message$, T>): T {\n"
" return if (extension.isRepeated) {\n"
" get(extension as com.google.protobuf.ExtensionLite<$message$, "
"kotlin.collections.List<*>>) as T\n"
" } else {\n"
" _builder.getExtension(extension)\n"
" }\n"
"}\n\n",
"jvm_synthetic", java::JvmSynthetic(jvm_dsl_), "message", message_name);
if (jvm_dsl_) {
// TODO: generate this on Kotlin Native once the [Mutable]List
// issue is resolved.
printer->Emit(
{
{"jvm_name",
[&] { java::JvmName("-getRepeatedExtension", name_ctx); }},
{"jvm_synthetic", java::JvmSynthetic(jvm_dsl_)},
{"message", message_name},
},
"$jvm_synthetic$"
"@kotlin.OptIn"
"(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n"
"$jvm_name$"
"public operator fun <E : kotlin.Any> get(\n"
" extension: com.google.protobuf.ExtensionLite<$message$, "
"kotlin.collections.List<E>>\n"
"): com.google.protobuf.kotlin.ExtensionList<E, $message$> {\n"
" return com.google.protobuf.kotlin.ExtensionList(extension, "
"_builder.getExtension(extension))\n"
"}\n\n");
}
printer->Print(
"$jvm_synthetic$"
"public operator fun contains(extension: "
"com.google.protobuf.ExtensionLite<$message$, *>): "
"Boolean {\n"
" return _builder.hasExtension(extension)\n"
"}\n\n",
"jvm_synthetic", java::JvmSynthetic(jvm_dsl_), "message", message_name);
printer->Print(
"$jvm_synthetic$"
"public fun clear(extension: "
"com.google.protobuf.ExtensionLite<$message$, *>) "
"{\n"
" _builder.clearExtension(extension)\n"
"}\n\n",
"jvm_synthetic", java::JvmSynthetic(jvm_dsl_), "message", message_name);
printer->Print(
"$jvm_synthetic$"
"public fun <T : kotlin.Any> setExtension(extension: "
"com.google.protobuf.ExtensionLite<$message$, T>, "
"value: T) {\n"
" _builder.setExtension(extension, value)\n"
"}\n\n",
"jvm_synthetic", java::JvmSynthetic(jvm_dsl_), "message", message_name);
printer->Print(
"$jvm_synthetic$"
"@Suppress(\"NOTHING_TO_INLINE\")\n"
"public inline operator fun <T : Comparable<T>> set(\n"
" extension: com.google.protobuf.ExtensionLite<$message$, T>,\n"
" value: T\n"
") {\n"
" setExtension(extension, value)\n"
"}\n\n",
"jvm_synthetic", java::JvmSynthetic(jvm_dsl_), "message", message_name);
printer->Print(
"$jvm_synthetic$"
"@Suppress(\"NOTHING_TO_INLINE\")\n"
"public 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",
"jvm_synthetic", java::JvmSynthetic(jvm_dsl_), "message", message_name);
printer->Print(
"$jvm_synthetic$"
"@Suppress(\"NOTHING_TO_INLINE\")\n"
"public inline operator fun <T : com.google.protobuf.MessageLite> set(\n"
" extension: com.google.protobuf.ExtensionLite<$message$, T>,\n"
" value: T\n"
") {\n"
" setExtension(extension, value)\n"
"}\n\n",
"jvm_synthetic", java::JvmSynthetic(jvm_dsl_), "message", message_name);
// TODO: generate these methods on Kotlin Native once the
// [Mutable]List issue is resolved.
if (!jvm_dsl_) return;
printer->Print(
"$jvm_synthetic$"
"public fun <E : kotlin.Any> com.google.protobuf.kotlin.ExtensionList<E, "
"$message$>.add(value: E) {\n"
" _builder.addExtension(this.extension, value)\n"
"}\n\n",
"jvm_synthetic", java::JvmSynthetic(jvm_dsl_), "message", message_name);
printer->Print(
"$jvm_synthetic$"
"@Suppress(\"NOTHING_TO_INLINE\")\n"
"public inline operator fun <E : kotlin.Any> "
"com.google.protobuf.kotlin.ExtensionList<E, "
"$message$>.plusAssign"
"(value: E) {\n"
" add(value)\n"
"}\n\n",
"jvm_synthetic", java::JvmSynthetic(jvm_dsl_), "message", message_name);
printer->Print(
"$jvm_synthetic$"
"public fun <E : kotlin.Any> com.google.protobuf.kotlin.ExtensionList<E, "
"$message$>.addAll(values: Iterable<E>) {\n"
" for (value in values) {\n"
" add(value)\n"
" }\n"
"}\n\n",
"jvm_synthetic", java::JvmSynthetic(jvm_dsl_), "message", message_name);
printer->Print(
"$jvm_synthetic$"
"@Suppress(\"NOTHING_TO_INLINE\")\n"
"public inline operator fun <E : kotlin.Any> "
"com.google.protobuf.kotlin.ExtensionList<E, "
"$message$>.plusAssign(values: "
"Iterable<E>) {\n"
" addAll(values)\n"
"}\n\n",
"jvm_synthetic", java::JvmSynthetic(jvm_dsl_), "message", message_name);
printer->Print(
"$jvm_synthetic$"
"public operator fun <E : kotlin.Any> "
"com.google.protobuf.kotlin.ExtensionList<E, "
"$message$>.set(index: Int, value: "
"E) {\n"
" _builder.setExtension(this.extension, index, value)\n"
"}\n\n",
"jvm_synthetic", java::JvmSynthetic(jvm_dsl_), "message", message_name);
printer->Print(
"$jvm_synthetic$"
"@Suppress(\"NOTHING_TO_INLINE\")\n"
"public inline fun com.google.protobuf.kotlin.ExtensionList<*, "
"$message$>.clear() {\n"
" clear(extension)\n"
"}\n\n",
"jvm_synthetic", java::JvmSynthetic(jvm_dsl_), "message", message_name);
}
} // namespace kotlin
} // namespace compiler
} // namespace protobuf
} // namespace google
#include "google/protobuf/port_undef.inc"

@ -0,0 +1,58 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#ifndef GOOGLE_PROTOBUF_COMPILER_KOTLIN_MESSAGE_H__
#define GOOGLE_PROTOBUF_COMPILER_KOTLIN_MESSAGE_H__
#include "absl/container/btree_map.h"
#include "google/protobuf/compiler/java/context.h"
#include "google/protobuf/compiler/java/generator_common.h"
#include "google/protobuf/compiler/java/full/field_generator.h"
#include "google/protobuf/compiler/java/lite/field_generator.h"
#include "google/protobuf/compiler/java/name_resolver.h"
#include "google/protobuf/descriptor.h"
namespace google {
namespace protobuf {
namespace compiler {
namespace kotlin {
class MessageGenerator {
public:
MessageGenerator(const Descriptor* descriptor, java::Context* context);
MessageGenerator(const MessageGenerator&) = delete;
MessageGenerator& operator=(const MessageGenerator&) = delete;
virtual ~MessageGenerator() = default;
void Generate(io::Printer* printer) const;
void GenerateMembers(io::Printer* printer) const;
void GenerateTopLevelMembers(io::Printer* printer) const;
private:
java::Context* context_;
java::ClassNameResolver* name_resolver_;
const Descriptor* descriptor_;
absl::btree_map<int, const OneofDescriptor*> oneofs_;
bool lite_;
bool jvm_dsl_;
// TODO: b/366047913 - These can be simplified once lite and full field
// generators are unified.
java::FieldGeneratorMap<java::ImmutableFieldLiteGenerator>
lite_field_generators_;
java::FieldGeneratorMap<java::ImmutableFieldGenerator> field_generators_;
void GenerateExtensions(io::Printer* printer) const;
void GenerateOrNull(io::Printer* printer) const;
void GenerateFieldMembers(io::Printer* printer) const;
};
} // namespace kotlin
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_KOTLIN_MESSAGE_H__
Loading…
Cancel
Save