In the Kotlin DSL, access `oneof` discriminators as properties not methods.

If we have a `oneof Foo` in a message `Bar`, we should access the discriminator as `Bar.Builder.fooCase` rather than `Bar.Builder.getFooCase()`.

PiperOrigin-RevId: 644107242
pull/17153/head
Éamonn McManus 9 months ago committed by Copybara-Service
parent 299bb044d5
commit 115b4c4f83
  1. 21
      src/google/protobuf/compiler/java/field_common.cc
  2. 23
      src/google/protobuf/compiler/java/field_common.h
  3. 9
      src/google/protobuf/compiler/java/lite/message.cc

@ -13,8 +13,6 @@ namespace protobuf {
namespace compiler {
namespace java {
std::string GetKotlinPropertyName(std::string capitalized_name);
void SetCommonFieldVariables(
const FieldDescriptor* descriptor, const FieldGeneratorInfo* info,
absl::flat_hash_map<absl::string_view, std::string>* variables) {
@ -68,25 +66,6 @@ static bool IsUpper(char c) {
static char ToLower(char c) { return IsUpper(c) ? c - 'A' + 'a' : c; }
// Returns the name by which the generated Java getters and setters should be
// referenced from Kotlin as properties. In the simplest case, the original name
// is something like `foo_bar`, which gets translated into `getFooBar()` etc,
// and that in turn can be referenced from Kotlin as `fooBar`.
//
// The algorithm for translating proto names into Java getters and setters is
// straightforward. The first letter of each underscore-separated word gets
// uppercased and the underscores are deleted. There are no other changes, so in
// particular if the proto name has a string of capitals then those remain
// as-is.
//
// The algorithm that the Kotlin compiler uses to derive the property name is
// slightly more complicated. If the first character after `get` (etc) is a
// capital and the second isn't, then the property name is just that string with
// its first letter lowercased. So `getFoo` becomes `foo` and `getX` becomes
// `x`. But if there is more than one capital, then all but the last get
// lowercased. So `getHTMLPage` becomes `htmlPage`. If there are only capitals
// then they all get lowercased, so `getID` becomes `id`.
// TODO: move this to a Kotlin-specific location
std::string GetKotlinPropertyName(std::string capitalized_name) {
// Find the first non-capital. If it is the second character, then we just
// need to lowercase the first one. Otherwise we need to lowercase everything

@ -1,6 +1,8 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_COMMON_H__
#define GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_COMMON_H__
#include <string>
#include "google/protobuf/descriptor.h"
namespace google {
@ -36,6 +38,27 @@ void PrintExtraFieldInfo(
const absl::flat_hash_map<absl::string_view, std::string>& variables,
io::Printer* printer);
// Returns the name by which the generated Java getters and setters should be
// referenced from Kotlin as properties. In the simplest case, the original name
// is something like `foo_bar`, which gets translated into `getFooBar()` etc,
// and that in turn can be referenced from Kotlin as `fooBar`.
//
// The algorithm for translating proto names into Java getters and setters is
// straightforward. The first letter of each underscore-separated word gets
// uppercased and the underscores are deleted. There are no other changes, so in
// particular if the proto name has a string of capitals then those remain
// as-is.
//
// The algorithm that the Kotlin compiler uses to derive the property name is
// slightly more complicated. If the first character after `get` (etc) is a
// capital and the second isn't, then the property name is just that string with
// its first letter lowercased. So `getFoo` becomes `foo` and `getX` becomes
// `x`. But if there is more than one capital, then all but the last get
// lowercased. So `getHTMLPage` becomes `htmlPage`. If there are only capitals
// then they all get lowercased, so `getID` becomes `id`.
// TODO: move this to a Kotlin-specific location
std::string GetKotlinPropertyName(std::string capitalized_name);
} // namespace java
} // namespace compiler
} // namespace protobuf

@ -773,16 +773,17 @@ void ImmutableMessageLiteGenerator::GenerateKotlinDsl(
for (auto& kv : oneofs_) {
const OneofDescriptor* oneof = kv.second;
auto oneof_name = context_->GetOneofGeneratorInfo(oneof)->name;
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"
" get() = _builder.$oneof_property_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",
"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)));
}

Loading…
Cancel
Save