1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 #include "google/protobuf/compiler/objectivec/extension.h"
9
10 #include <string>
11 #include <vector>
12
13 #include "absl/container/btree_set.h"
14 #include "absl/container/flat_hash_set.h"
15 #include "absl/log/absl_check.h"
16 #include "absl/strings/str_cat.h"
17 #include "absl/strings/string_view.h"
18 #include "google/protobuf/compiler/objectivec/helpers.h"
19 #include "google/protobuf/compiler/objectivec/names.h"
20 #include "google/protobuf/compiler/objectivec/options.h"
21 #include "google/protobuf/descriptor.h"
22 #include "google/protobuf/descriptor.pb.h"
23 #include "google/protobuf/io/printer.h"
24
25 namespace google {
26 namespace protobuf {
27 namespace compiler {
28 namespace objectivec {
29
ExtensionGenerator(absl::string_view root_or_message_class_name,const FieldDescriptor * descriptor,const GenerationOptions & generation_options)30 ExtensionGenerator::ExtensionGenerator(
31 absl::string_view root_or_message_class_name,
32 const FieldDescriptor* descriptor,
33 const GenerationOptions& generation_options)
34 : root_or_message_class_name_(root_or_message_class_name),
35 method_name_(ExtensionMethodName(descriptor)),
36 descriptor_(descriptor),
37 generation_options_(generation_options) {
38 ABSL_CHECK(!descriptor->is_map())
39 << "error: Extension is a map<>!"
40 << " That used to be blocked by the compiler.";
41 if (descriptor->containing_type()->options().message_set_wire_format()) {
42 ABSL_CHECK(descriptor->type() == FieldDescriptor::TYPE_MESSAGE)
43 << "error: Extension to a message_set_wire_format message and the type "
44 "wasn't a message!";
45 ABSL_CHECK(!descriptor->is_repeated())
46 << "error: Extension to a message_set_wire_format message should not "
47 "be repeated!";
48 }
49 }
50
GenerateMembersHeader(io::Printer * printer) const51 void ExtensionGenerator::GenerateMembersHeader(io::Printer* printer) const {
52 printer->Emit(
53 {{"method_name", method_name_},
54 {"comments",
55 [&] { EmitCommentsString(printer, generation_options_, descriptor_); }},
56 {"storage_attribute",
57 IsRetainedName(method_name_) ? "NS_RETURNS_NOT_RETAINED" : ""},
58 {"deprecated_attribute",
59 // Unlike normal message fields, check if the file for the extension was
60 // deprecated.
61 GetOptionalDeprecatedAttribute(descriptor_, descriptor_->file())}},
62 R"objc(
63 $comments$
64 + (GPBExtensionDescriptor *)$method_name$$ storage_attribute$$ deprecated_attribute$;
65 )objc");
66 }
67
GenerateStaticVariablesInitialization(io::Printer * printer) const68 void ExtensionGenerator::GenerateStaticVariablesInitialization(
69 io::Printer* printer) const {
70 const std::string containing_type = ClassName(descriptor_->containing_type());
71 ObjectiveCType objc_type = GetObjectiveCType(descriptor_);
72
73 std::vector<std::string> options;
74 if (descriptor_->is_repeated()) options.push_back("GPBExtensionRepeated");
75 if (descriptor_->is_packed()) options.push_back("GPBExtensionPacked");
76 if (descriptor_->containing_type()->options().message_set_wire_format()) {
77 options.push_back("GPBExtensionSetWireFormat");
78 }
79
80 printer->Emit(
81 {{"default",
82 descriptor_->is_repeated() ? "nil" : DefaultValue(descriptor_)},
83 {"default_name", GPBGenericValueFieldName(descriptor_)},
84 {"enum_desc_func_name",
85 objc_type == OBJECTIVECTYPE_ENUM
86 ? absl::StrCat(EnumName(descriptor_->enum_type()),
87 "_EnumDescriptor")
88 : "NULL"},
89 {"extended_type", ObjCClass(containing_type)},
90 {"extension_type",
91 absl::StrCat("GPBDataType", GetCapitalizedType(descriptor_))},
92 {"method_name", method_name_},
93 {"number", descriptor_->number()},
94 {"options", BuildFlagsString(FLAGTYPE_EXTENSION, options)},
95 {"root_or_message_class_name", root_or_message_class_name_},
96 {"type", objc_type == OBJECTIVECTYPE_MESSAGE
97 ? ObjCClass(ClassName(descriptor_->message_type()))
98 : "Nil"}},
99 R"objc(
100 {
101 .defaultValue.$default_name$ = $default$,
102 .singletonName = GPBStringifySymbol($root_or_message_class_name$) "_$method_name$",
103 .extendedClass.clazz = $extended_type$,
104 .messageOrGroupClass.clazz = $type$,
105 .enumDescriptorFunc = $enum_desc_func_name$,
106 .fieldNumber = $number$,
107 .dataType = $extension_type$,
108 .options = $options$,
109 },
110 )objc");
111 }
112
DetermineObjectiveCClassDefinitions(absl::btree_set<std::string> * fwd_decls) const113 void ExtensionGenerator::DetermineObjectiveCClassDefinitions(
114 absl::btree_set<std::string>* fwd_decls) const {
115 std::string extended_type = ClassName(descriptor_->containing_type());
116 fwd_decls->insert(ObjCClassDeclaration(extended_type));
117 ObjectiveCType objc_type = GetObjectiveCType(descriptor_);
118 if (objc_type == OBJECTIVECTYPE_MESSAGE) {
119 std::string message_type = ClassName(descriptor_->message_type());
120 fwd_decls->insert(ObjCClassDeclaration(message_type));
121 }
122 }
123
DetermineNeededFiles(absl::flat_hash_set<const FileDescriptor * > * deps) const124 void ExtensionGenerator::DetermineNeededFiles(
125 absl::flat_hash_set<const FileDescriptor*>* deps) const {
126 const Descriptor* extended_type = descriptor_->containing_type();
127 if (descriptor_->file() != extended_type->file()) {
128 deps->insert(extended_type->file());
129 }
130
131 const ObjectiveCType objc_type = GetObjectiveCType(descriptor_);
132 if (objc_type == OBJECTIVECTYPE_MESSAGE) {
133 const Descriptor* value_msg_descriptor = descriptor_->message_type();
134 if (descriptor_->file() != value_msg_descriptor->file()) {
135 deps->insert(value_msg_descriptor->file());
136 }
137 } else if (objc_type == OBJECTIVECTYPE_ENUM) {
138 const EnumDescriptor* value_enum_descriptor = descriptor_->enum_type();
139 if (descriptor_->file() != value_enum_descriptor->file()) {
140 deps->insert(value_enum_descriptor->file());
141 }
142 }
143 }
144
145 } // namespace objectivec
146 } // namespace compiler
147 } // namespace protobuf
148 } // namespace google
149