Skip to content

Commit

Permalink
Objectivec: Refactor to use io::Printer::Sub.
Browse files Browse the repository at this point in the history
This allows us to use `io::Printer::Sub`'s more advanced features, like automatically adding references to symbols in output metadata. We need a new utility class because a lot of code in this generator depends on overwriting placeholders, as well as looking up existing ones.

PiperOrigin-RevId: 719268162
  • Loading branch information
protobuf-github-bot authored and copybara-github committed Jan 24, 2025
1 parent b9ec7e0 commit ca29ed1
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 93 deletions.
33 changes: 16 additions & 17 deletions src/google/protobuf/compiler/objectivec/enum_field.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
#include <string>

#include "absl/container/btree_set.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/compiler/objectivec/field.h"
#include "google/protobuf/compiler/objectivec/helpers.h"
#include "google/protobuf/compiler/objectivec/names.h"
#include "google/protobuf/compiler/objectivec/options.h"
#include "google/protobuf/descriptor.h"
Expand All @@ -27,38 +27,37 @@ namespace objectivec {

namespace {

void SetEnumVariables(
const FieldDescriptor* descriptor,
const GenerationOptions& generation_options,
absl::flat_hash_map<absl::string_view, std::string>* variables) {
void SetEnumVariables(const FieldDescriptor* descriptor,
const GenerationOptions& generation_options,
SubstitutionMap& variables) {
const std::string type = EnumName(descriptor->enum_type());
const std::string enum_desc_func = absl::StrCat(type, "_EnumDescriptor");
(*variables)["enum_name"] = type;
variables.Set("enum_name", type);
// When using fwd decls, for non repeated fields, if it was defined in a
// different file, the property decls need to use "enum NAME" rather than just
// "NAME" to support the forward declaration of the enums.
if (generation_options.headers_use_forward_declarations &&
!descriptor->is_repeated() &&
!IsProtobufLibraryBundledProtoFile(descriptor->enum_type()->file()) &&
(descriptor->file() != descriptor->enum_type()->file())) {
(*variables)["property_type"] = absl::StrCat("enum ", type, " ");
variables.Set("property_type", absl::StrCat("enum ", type, " "));
}
(*variables)["enum_verifier"] = absl::StrCat(type, "_IsValidValue");
(*variables)["enum_desc_func"] = enum_desc_func;
variables.Set("enum_verifier", absl::StrCat(type, "_IsValidValue"));
variables.Set("enum_desc_func", enum_desc_func);

(*variables)["dataTypeSpecific_name"] = "enumDescFunc";
(*variables)["dataTypeSpecific_value"] = enum_desc_func;
variables.Set("dataTypeSpecific_name", "enumDescFunc");
variables.Set("dataTypeSpecific_value", enum_desc_func);

const Descriptor* msg_descriptor = descriptor->containing_type();
(*variables)["owning_message_class"] = ClassName(msg_descriptor);
variables.Set("owning_message_class", ClassName(msg_descriptor));
}
} // namespace

EnumFieldGenerator::EnumFieldGenerator(
const FieldDescriptor* descriptor,
const GenerationOptions& generation_options)
: SingleFieldGenerator(descriptor, generation_options) {
SetEnumVariables(descriptor, generation_options, &variables_);
SetEnumVariables(descriptor, generation_options, variables_);
}

void EnumFieldGenerator::GenerateCFunctionDeclarations(
Expand All @@ -67,7 +66,7 @@ void EnumFieldGenerator::GenerateCFunctionDeclarations(
return;
}

auto vars = printer->WithVars(variables_);
auto vars = variables_.Install(printer);
printer->Emit(R"objc(
/**
* Fetches the raw value of a @c $owning_message_class$'s @c $name$ property, even
Expand All @@ -90,7 +89,7 @@ void EnumFieldGenerator::GenerateCFunctionImplementations(
return;
}

auto vars = printer->WithVars(variables_);
auto vars = variables_.Install(printer);
printer->Emit(R"objc(
int32_t $owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message) {
GPBDescriptor *descriptor = [$owning_message_class$ descriptor];
Expand Down Expand Up @@ -134,11 +133,11 @@ RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator(
const FieldDescriptor* descriptor,
const GenerationOptions& generation_options)
: RepeatedFieldGenerator(descriptor, generation_options) {
SetEnumVariables(descriptor, generation_options, &variables_);
SetEnumVariables(descriptor, generation_options, variables_);
}

void RepeatedEnumFieldGenerator::EmitArrayComment(io::Printer* printer) const {
auto vars = printer->WithVars(variables_);
auto vars = variables_.Install(printer);
printer->Emit(R"objc(
// |$name$| contains |$enum_name$|
)objc");
Expand Down
108 changes: 57 additions & 51 deletions src/google/protobuf/compiler/objectivec/field.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#include <vector>

#include "absl/container/btree_set.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
Expand All @@ -35,9 +34,8 @@ namespace objectivec {

namespace {

void SetCommonFieldVariables(
const FieldDescriptor* descriptor,
absl::flat_hash_map<absl::string_view, std::string>* variables) {
void SetCommonFieldVariables(const FieldDescriptor* descriptor,
SubstitutionMap& variables) {
std::string camel_case_name = FieldName(descriptor);
std::string raw_field_name;
if (internal::cpp::IsGroupLike(*descriptor)) {
Expand All @@ -51,26 +49,31 @@ void SetCommonFieldVariables(
const bool needs_custom_name = (raw_field_name != un_camel_case_name);

const std::string& classname = ClassName(descriptor->containing_type());
(*variables)["classname"] = classname;
(*variables)["name"] = camel_case_name;
variables.Set("classname", classname);
variables.Set("name", camel_case_name);

const std::string& capitalized_name = FieldNameCapitalized(descriptor);
(*variables)["capitalized_name"] = capitalized_name;
(*variables)["raw_field_name"] = raw_field_name;
(*variables)["field_number_name"] =
absl::StrCat(classname, "_FieldNumber_", capitalized_name);
(*variables)["field_number"] = absl::StrCat(descriptor->number());
(*variables)["property_type"] = FieldObjCType(
descriptor, static_cast<FieldObjCTypeOptions>(
kFieldObjCTypeOptions_IncludeSpaceAfterBasicTypes |
kFieldObjCTypeOptions_IncludeSpaceBeforeStar));
(*variables)["storage_type"] = FieldObjCType(
descriptor, static_cast<FieldObjCTypeOptions>(
kFieldObjCTypeOptions_IncludeSpaceAfterBasicTypes |
kFieldObjCTypeOptions_OmitLightweightGenerics |
kFieldObjCTypeOptions_IncludeSpaceBeforeStar));
(*variables)["field_type"] = GetCapitalizedType(descriptor);
(*variables)["deprecated_attribute"] =
GetOptionalDeprecatedAttribute(descriptor);
variables.Set("capitalized_name", capitalized_name);
variables.Set("raw_field_name", raw_field_name);
variables.Set("field_number_name",
absl::StrCat(classname, "_FieldNumber_", capitalized_name));
variables.Set("field_number", absl::StrCat(descriptor->number()));
variables.Set(
"property_type",
FieldObjCType(descriptor,
static_cast<FieldObjCTypeOptions>(
kFieldObjCTypeOptions_IncludeSpaceAfterBasicTypes |
kFieldObjCTypeOptions_IncludeSpaceBeforeStar)));
variables.Set(
"storage_type",
FieldObjCType(descriptor,
static_cast<FieldObjCTypeOptions>(
kFieldObjCTypeOptions_IncludeSpaceAfterBasicTypes |
kFieldObjCTypeOptions_OmitLightweightGenerics |
kFieldObjCTypeOptions_IncludeSpaceBeforeStar)));
variables.Set("field_type", GetCapitalizedType(descriptor));
variables.Set("deprecated_attribute",
GetOptionalDeprecatedAttribute(descriptor));
std::vector<std::string> field_flags;
if (descriptor->is_repeated()) field_flags.push_back("GPBFieldRepeated");
if (descriptor->is_required()) field_flags.push_back("GPBFieldRequired");
Expand All @@ -96,20 +99,21 @@ void SetCommonFieldVariables(
field_flags.push_back("GPBFieldClearHasIvarOnZero");
}

(*variables)["fieldflags"] = BuildFlagsString(FLAGTYPE_FIELD, field_flags);
variables.Set("fieldflags", BuildFlagsString(FLAGTYPE_FIELD, field_flags));

(*variables)["default"] = DefaultValue(descriptor);
(*variables)["default_name"] = GPBGenericValueFieldName(descriptor);
variables.Set("default", DefaultValue(descriptor));
variables.Set("default_name", GPBGenericValueFieldName(descriptor));

(*variables)["dataTypeSpecific_name"] = "clazz";
(*variables)["dataTypeSpecific_value"] = "Nil";
variables.Set("dataTypeSpecific_name", "clazz");
variables.Set("dataTypeSpecific_value", "Nil");

(*variables)["storage_offset_value"] = absl::StrCat(
"(uint32_t)offsetof(", classname, "__storage_, ", camel_case_name, ")");
(*variables)["storage_offset_comment"] = "";
variables.Set("storage_offset_value",
absl::StrCat("(uint32_t)offsetof(", classname, "__storage_, ",
camel_case_name, ")"));
variables.Set("storage_offset_comment", "");

// Clear some common things so they can be set just when needed.
(*variables)["storage_attribute"] = "";
variables.Set("storage_attribute", "");
}

bool HasNonZeroDefaultValue(const FieldDescriptor* field) {
Expand Down Expand Up @@ -192,11 +196,11 @@ FieldGenerator* FieldGenerator::Make(
FieldGenerator::FieldGenerator(const FieldDescriptor* descriptor,
const GenerationOptions& generation_options)
: descriptor_(descriptor), generation_options_(generation_options) {
SetCommonFieldVariables(descriptor, &variables_);
SetCommonFieldVariables(descriptor, variables_);
}

void FieldGenerator::GenerateFieldNumberConstant(io::Printer* printer) const {
auto vars = printer->WithVars(variables_);
auto vars = variables_.Install(printer);
printer->Emit("$field_number_name$ = $field_number$,\n");
}

Expand Down Expand Up @@ -228,7 +232,7 @@ void FieldGenerator::DetermineNeededFiles(
void FieldGenerator::GenerateFieldDescription(io::Printer* printer,
bool include_default) const {
// Printed in the same order as the structure decl.
auto vars = printer->WithVars(variables_);
auto vars = variables_.Install(printer);
printer->Emit(
{{"prefix", include_default ? ".core" : ""},
{"maybe_default",
Expand All @@ -252,10 +256,12 @@ void FieldGenerator::GenerateFieldDescription(io::Printer* printer,
}

void FieldGenerator::SetRuntimeHasBit(int has_index) {
variables_["has_index"] = absl::StrCat(has_index);
variables_.Set("has_index", has_index);
}

void FieldGenerator::SetNoHasBit() { variables_["has_index"] = "GPBNoHasBit"; }
void FieldGenerator::SetNoHasBit() {
variables_.Set("has_index", "GPBNoHasBit");
}

int FieldGenerator::ExtraRuntimeHasBitsNeeded() const { return 0; }

Expand All @@ -269,7 +275,7 @@ void FieldGenerator::SetOneofIndexBase(int index_base) {
if (oneof != nullptr) {
int index = oneof->index() + index_base;
// Flip the sign to mark it as a oneof.
variables_["has_index"] = absl::StrCat(-index);
variables_.Set("has_index", -index);
}
}

Expand All @@ -286,13 +292,13 @@ SingleFieldGenerator::SingleFieldGenerator(

void SingleFieldGenerator::GenerateFieldStorageDeclaration(
io::Printer* printer) const {
auto vars = printer->WithVars(variables_);
auto vars = variables_.Install(printer);
printer->Emit("$storage_type$$name$;\n");
}

void SingleFieldGenerator::GeneratePropertyDeclaration(
io::Printer* printer) const {
auto vars = printer->WithVars(variables_);
auto vars = variables_.Install(printer);
printer->Emit({{"comments",
[&] {
EmitCommentsString(printer, generation_options_,
Expand All @@ -312,7 +318,7 @@ void SingleFieldGenerator::GeneratePropertyDeclaration(

void SingleFieldGenerator::GeneratePropertyImplementation(
io::Printer* printer) const {
auto vars = printer->WithVars(variables_);
auto vars = variables_.Install(printer);
if (WantsHasProperty()) {
printer->Emit("@dynamic has$capitalized_name$, $name$;\n");
} else {
Expand All @@ -332,15 +338,15 @@ ObjCObjFieldGenerator::ObjCObjFieldGenerator(
const FieldDescriptor* descriptor,
const GenerationOptions& generation_options)
: SingleFieldGenerator(descriptor, generation_options) {
variables_["property_storage_attribute"] = "strong";
if (IsRetainedName(variables_["name"])) {
variables_["storage_attribute"] = " NS_RETURNS_NOT_RETAINED";
variables_.Set("property_storage_attribute", "strong");
if (IsRetainedName(variable("name"))) {
variables_.Set("storage_attribute", " NS_RETURNS_NOT_RETAINED");
}
}

void ObjCObjFieldGenerator::GenerateFieldStorageDeclaration(
io::Printer* printer) const {
auto vars = printer->WithVars(variables_);
auto vars = variables_.Install(printer);
printer->Emit("$storage_type$$name$;\n");
}

Expand All @@ -350,7 +356,7 @@ void ObjCObjFieldGenerator::GeneratePropertyDeclaration(
// it uses pointers and deals with Objective-C's rules around storage name
// conventions (init*, new*, etc.)

auto vars = printer->WithVars(variables_);
auto vars = variables_.Install(printer);
printer->Emit({{"comments",
[&] {
EmitCommentsString(printer, generation_options_,
Expand All @@ -366,7 +372,7 @@ void ObjCObjFieldGenerator::GeneratePropertyDeclaration(
@property(nonatomic, readwrite) BOOL has$capitalized_name$$ deprecated_attribute$;
)objc");
}
if (IsInitName(variables_.find("name")->second)) {
if (IsInitName(variable("name"))) {
// If property name starts with init we need to annotate it to get past ARC.
// http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227
printer->Emit(R"objc(
Expand All @@ -383,13 +389,13 @@ RepeatedFieldGenerator::RepeatedFieldGenerator(

void RepeatedFieldGenerator::GenerateFieldStorageDeclaration(
io::Printer* printer) const {
auto vars = printer->WithVars(variables_);
auto vars = variables_.Install(printer);
printer->Emit("$storage_type$$name$;\n");
}

void RepeatedFieldGenerator::GeneratePropertyImplementation(
io::Printer* printer) const {
auto vars = printer->WithVars(variables_);
auto vars = variables_.Install(printer);
printer->Emit("@dynamic $name$, $name$_Count;\n");
}

Expand All @@ -401,7 +407,7 @@ void RepeatedFieldGenerator::GeneratePropertyDeclaration(
// dealing with needing Objective-C's rules around storage name conventions
// (init*, new*, etc.)

auto vars = printer->WithVars(variables_);
auto vars = variables_.Install(printer);
printer->Emit(
{{"comments",
[&] { EmitCommentsString(printer, generation_options_, descriptor_); }},
Expand All @@ -413,7 +419,7 @@ void RepeatedFieldGenerator::GeneratePropertyDeclaration(
/** The number of items in @c $name$ without causing the container to be created. */
@property(nonatomic, readonly) NSUInteger $name$_Count$ deprecated_attribute$;
)objc");
if (IsInitName(variables_.find("name")->second)) {
if (IsInitName(variable("name"))) {
// If property name starts with init we need to annotate it to get past ARC.
// http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227
printer->Emit(R"objc(
Expand Down
8 changes: 4 additions & 4 deletions src/google/protobuf/compiler/objectivec/field.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
#include <vector>

#include "absl/container/btree_set.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/strings/match.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/compiler/objectivec/helpers.h"
#include "google/protobuf/compiler/objectivec/options.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/io/printer.h"
Expand Down Expand Up @@ -70,8 +70,8 @@ class FieldGenerator {
virtual void SetExtraRuntimeHasBitsBase(int index_base);
void SetOneofIndexBase(int index_base);

std::string variable(const char* key) const {
return variables_.find(key)->second;
std::string variable(absl::string_view key) const {
return variables_.Value(key);
}

bool needs_textformat_name_support() const {
Expand All @@ -89,7 +89,7 @@ class FieldGenerator {

const FieldDescriptor* descriptor_;
const GenerationOptions& generation_options_;
absl::flat_hash_map<absl::string_view, std::string> variables_;
SubstitutionMap variables_;
};

class SingleFieldGenerator : public FieldGenerator {
Expand Down
Loading

0 comments on commit ca29ed1

Please sign in to comment.