1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31#include <iostream>
32
33#include <google/protobuf/compiler/objectivec/objectivec_field.h>
34#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
35#include <google/protobuf/compiler/objectivec/objectivec_enum_field.h>
36#include <google/protobuf/compiler/objectivec/objectivec_map_field.h>
37#include <google/protobuf/compiler/objectivec/objectivec_message_field.h>
38#include <google/protobuf/compiler/objectivec/objectivec_primitive_field.h>
39#include <google/protobuf/io/printer.h>
40#include <google/protobuf/stubs/strutil.h>
41
42namespace google {
43namespace protobuf {
44namespace compiler {
45namespace objectivec {
46
47namespace {
48
49void SetCommonFieldVariables(const FieldDescriptor* descriptor,
50 std::map<std::string, std::string>* variables) {
51 std::string camel_case_name = FieldName(field: descriptor);
52 std::string raw_field_name;
53 if (descriptor->type() == FieldDescriptor::TYPE_GROUP) {
54 raw_field_name = descriptor->message_type()->name();
55 } else {
56 raw_field_name = descriptor->name();
57 }
58 // The logic here has to match -[GGPBFieldDescriptor textFormatName].
59 const std::string un_camel_case_name(
60 UnCamelCaseFieldName(name: camel_case_name, field: descriptor));
61 const bool needs_custom_name = (raw_field_name != un_camel_case_name);
62
63 SourceLocation location;
64 if (descriptor->GetSourceLocation(out_location: &location)) {
65 (*variables)["comments"] = BuildCommentsString(location, prefer_single_line: true);
66 } else {
67 (*variables)["comments"] = "\n";
68 }
69 const std::string& classname = ClassName(descriptor: descriptor->containing_type());
70 (*variables)["classname"] = classname;
71 (*variables)["name"] = camel_case_name;
72 const std::string& capitalized_name = FieldNameCapitalized(field: descriptor);
73 (*variables)["capitalized_name"] = capitalized_name;
74 (*variables)["raw_field_name"] = raw_field_name;
75 (*variables)["field_number_name"] =
76 classname + "_FieldNumber_" + capitalized_name;
77 (*variables)["field_number"] = StrCat(a: descriptor->number());
78 (*variables)["field_type"] = GetCapitalizedType(field: descriptor);
79 (*variables)["deprecated_attribute"] = GetOptionalDeprecatedAttribute(descriptor);
80 std::vector<std::string> field_flags;
81 if (descriptor->is_repeated()) field_flags.push_back(x: "GPBFieldRepeated");
82 if (descriptor->is_required()) field_flags.push_back(x: "GPBFieldRequired");
83 if (descriptor->is_optional()) field_flags.push_back(x: "GPBFieldOptional");
84 if (descriptor->is_packed()) field_flags.push_back(x: "GPBFieldPacked");
85
86 // ObjC custom flags.
87 if (descriptor->has_default_value())
88 field_flags.push_back(x: "GPBFieldHasDefaultValue");
89 if (needs_custom_name) field_flags.push_back(x: "GPBFieldTextFormatNameCustom");
90 if (descriptor->type() == FieldDescriptor::TYPE_ENUM) {
91 field_flags.push_back(x: "GPBFieldHasEnumDescriptor");
92 }
93 // It will clear on a zero value if...
94 // - not repeated/map
95 // - doesn't have presence
96 bool clear_on_zero =
97 (!descriptor->is_repeated() && !descriptor->has_presence());
98 if (clear_on_zero) {
99 field_flags.push_back(x: "GPBFieldClearHasIvarOnZero");
100 }
101
102 (*variables)["fieldflags"] = BuildFlagsString(type: FLAGTYPE_FIELD, strings: field_flags);
103
104 (*variables)["default"] = DefaultValue(field: descriptor);
105 (*variables)["default_name"] = GPBGenericValueFieldName(field: descriptor);
106
107 (*variables)["dataTypeSpecific_name"] = "clazz";
108 (*variables)["dataTypeSpecific_value"] = "Nil";
109
110 (*variables)["storage_offset_value"] =
111 "(uint32_t)offsetof(" + classname + "__storage_, " + camel_case_name + ")";
112 (*variables)["storage_offset_comment"] = "";
113
114 // Clear some common things so they can be set just when needed.
115 (*variables)["storage_attribute"] = "";
116}
117
118} // namespace
119
120FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field) {
121 FieldGenerator* result = NULL;
122 if (field->is_repeated()) {
123 switch (GetObjectiveCType(field)) {
124 case OBJECTIVECTYPE_MESSAGE: {
125 if (field->is_map()) {
126 result = new MapFieldGenerator(field);
127 } else {
128 result = new RepeatedMessageFieldGenerator(field);
129 }
130 break;
131 }
132 case OBJECTIVECTYPE_ENUM:
133 result = new RepeatedEnumFieldGenerator(field);
134 break;
135 default:
136 result = new RepeatedPrimitiveFieldGenerator(field);
137 break;
138 }
139 } else {
140 switch (GetObjectiveCType(field)) {
141 case OBJECTIVECTYPE_MESSAGE: {
142 result = new MessageFieldGenerator(field);
143 break;
144 }
145 case OBJECTIVECTYPE_ENUM:
146 result = new EnumFieldGenerator(field);
147 break;
148 default:
149 if (IsReferenceType(field)) {
150 result = new PrimitiveObjFieldGenerator(field);
151 } else {
152 result = new PrimitiveFieldGenerator(field);
153 }
154 break;
155 }
156 }
157 result->FinishInitialization();
158 return result;
159}
160
161FieldGenerator::FieldGenerator(const FieldDescriptor* descriptor)
162 : descriptor_(descriptor) {
163 SetCommonFieldVariables(descriptor, variables: &variables_);
164}
165
166FieldGenerator::~FieldGenerator() {}
167
168void FieldGenerator::GenerateFieldNumberConstant(io::Printer* printer) const {
169 printer->Print(
170 variables: variables_,
171 text: "$field_number_name$ = $field_number$,\n");
172}
173
174void FieldGenerator::GenerateCFunctionDeclarations(
175 io::Printer* printer) const {
176 // Nothing
177}
178
179void FieldGenerator::GenerateCFunctionImplementations(
180 io::Printer* printer) const {
181 // Nothing
182}
183
184void FieldGenerator::DetermineForwardDeclarations(
185 std::set<std::string>* fwd_decls,
186 bool include_external_types) const {
187 // Nothing
188}
189
190void FieldGenerator::DetermineObjectiveCClassDefinitions(
191 std::set<std::string>* fwd_decls) const {
192 // Nothing
193}
194
195void FieldGenerator::GenerateFieldDescription(
196 io::Printer* printer, bool include_default) const {
197 // Printed in the same order as the structure decl.
198 if (include_default) {
199 printer->Print(
200 variables: variables_,
201 text: "{\n"
202 " .defaultValue.$default_name$ = $default$,\n"
203 " .core.name = \"$name$\",\n"
204 " .core.dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n"
205 " .core.number = $field_number_name$,\n"
206 " .core.hasIndex = $has_index$,\n"
207 " .core.offset = $storage_offset_value$,$storage_offset_comment$\n"
208 " .core.flags = $fieldflags$,\n"
209 " .core.dataType = GPBDataType$field_type$,\n"
210 "},\n");
211 } else {
212 printer->Print(
213 variables: variables_,
214 text: "{\n"
215 " .name = \"$name$\",\n"
216 " .dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n"
217 " .number = $field_number_name$,\n"
218 " .hasIndex = $has_index$,\n"
219 " .offset = $storage_offset_value$,$storage_offset_comment$\n"
220 " .flags = $fieldflags$,\n"
221 " .dataType = GPBDataType$field_type$,\n"
222 "},\n");
223 }
224}
225
226void FieldGenerator::SetRuntimeHasBit(int has_index) {
227 variables_["has_index"] = StrCat(a: has_index);
228}
229
230void FieldGenerator::SetNoHasBit(void) {
231 variables_["has_index"] = "GPBNoHasBit";
232}
233
234int FieldGenerator::ExtraRuntimeHasBitsNeeded(void) const {
235 return 0;
236}
237
238void FieldGenerator::SetExtraRuntimeHasBitsBase(int index_base) {
239 // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
240 // error cases, so it seems to be ok to use as a back door for errors.
241 std::cerr << "Error: should have overridden SetExtraRuntimeHasBitsBase()." << std::endl;
242 std::cerr.flush();
243 abort();
244}
245
246void FieldGenerator::SetOneofIndexBase(int index_base) {
247 const OneofDescriptor* oneof = descriptor_->real_containing_oneof();
248 if (oneof != NULL) {
249 int index = oneof->index() + index_base;
250 // Flip the sign to mark it as a oneof.
251 variables_["has_index"] = StrCat(a: -index);
252 }
253}
254
255bool FieldGenerator::WantsHasProperty(void) const {
256 return descriptor_->has_presence() && !descriptor_->real_containing_oneof();
257}
258
259void FieldGenerator::FinishInitialization(void) {
260 // If "property_type" wasn't set, make it "storage_type".
261 if ((variables_.find(x: "property_type") == variables_.end()) &&
262 (variables_.find(x: "storage_type") != variables_.end())) {
263 variables_["property_type"] = variable(key: "storage_type");
264 }
265}
266
267SingleFieldGenerator::SingleFieldGenerator(const FieldDescriptor* descriptor)
268 : FieldGenerator(descriptor) {
269 // Nothing
270}
271
272SingleFieldGenerator::~SingleFieldGenerator() {}
273
274void SingleFieldGenerator::GenerateFieldStorageDeclaration(
275 io::Printer* printer) const {
276 printer->Print(variables: variables_, text: "$storage_type$ $name$;\n");
277}
278
279void SingleFieldGenerator::GeneratePropertyDeclaration(
280 io::Printer* printer) const {
281 printer->Print(variables: variables_, text: "$comments$");
282 printer->Print(
283 variables: variables_,
284 text: "@property(nonatomic, readwrite) $property_type$ $name$$deprecated_attribute$;\n"
285 "\n");
286 if (WantsHasProperty()) {
287 printer->Print(
288 variables: variables_,
289 text: "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n");
290 }
291}
292
293void SingleFieldGenerator::GeneratePropertyImplementation(
294 io::Printer* printer) const {
295 if (WantsHasProperty()) {
296 printer->Print(variables: variables_, text: "@dynamic has$capitalized_name$, $name$;\n");
297 } else {
298 printer->Print(variables: variables_, text: "@dynamic $name$;\n");
299 }
300}
301
302bool SingleFieldGenerator::RuntimeUsesHasBit(void) const {
303 if (descriptor_->real_containing_oneof()) {
304 // The oneof tracks what is set instead.
305 return false;
306 }
307 return true;
308}
309
310ObjCObjFieldGenerator::ObjCObjFieldGenerator(const FieldDescriptor* descriptor)
311 : SingleFieldGenerator(descriptor) {
312 variables_["property_storage_attribute"] = "strong";
313 if (IsRetainedName(name: variables_["name"])) {
314 variables_["storage_attribute"] = " NS_RETURNS_NOT_RETAINED";
315 }
316}
317
318ObjCObjFieldGenerator::~ObjCObjFieldGenerator() {}
319
320void ObjCObjFieldGenerator::GenerateFieldStorageDeclaration(
321 io::Printer* printer) const {
322 printer->Print(variables: variables_, text: "$storage_type$ *$name$;\n");
323}
324
325void ObjCObjFieldGenerator::GeneratePropertyDeclaration(
326 io::Printer* printer) const {
327
328 // Differs from SingleFieldGenerator::GeneratePropertyDeclaration() in that
329 // it uses pointers and deals with Objective C's rules around storage name
330 // conventions (init*, new*, etc.)
331
332 printer->Print(variables: variables_, text: "$comments$");
333 printer->Print(
334 variables: variables_,
335 text: "@property(nonatomic, readwrite, $property_storage_attribute$, null_resettable) $property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n");
336 if (WantsHasProperty()) {
337 printer->Print(
338 variables: variables_,
339 text: "/** Test to see if @c $name$ has been set. */\n"
340 "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n");
341 }
342 if (IsInitName(name: variables_.find(x: "name")->second)) {
343 // If property name starts with init we need to annotate it to get past ARC.
344 // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227
345 printer->Print(variables: variables_,
346 text: "- ($property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n");
347 }
348 printer->Print(text: "\n");
349}
350
351RepeatedFieldGenerator::RepeatedFieldGenerator(
352 const FieldDescriptor* descriptor)
353 : ObjCObjFieldGenerator(descriptor) {
354 // Default to no comment and let the cases needing it fill it in.
355 variables_["array_comment"] = "";
356}
357
358RepeatedFieldGenerator::~RepeatedFieldGenerator() {}
359
360void RepeatedFieldGenerator::FinishInitialization(void) {
361 FieldGenerator::FinishInitialization();
362 if (variables_.find(x: "array_property_type") == variables_.end()) {
363 variables_["array_property_type"] = variable(key: "array_storage_type");
364 }
365}
366
367void RepeatedFieldGenerator::GenerateFieldStorageDeclaration(
368 io::Printer* printer) const {
369 printer->Print(variables: variables_, text: "$array_storage_type$ *$name$;\n");
370}
371
372void RepeatedFieldGenerator::GeneratePropertyImplementation(
373 io::Printer* printer) const {
374 printer->Print(variables: variables_, text: "@dynamic $name$, $name$_Count;\n");
375}
376
377void RepeatedFieldGenerator::GeneratePropertyDeclaration(
378 io::Printer* printer) const {
379
380 // Repeated fields don't need the has* properties, but they do expose a
381 // *Count (to check without autocreation). So for the field property we need
382 // the same logic as ObjCObjFieldGenerator::GeneratePropertyDeclaration() for
383 // dealing with needing Objective C's rules around storage name conventions
384 // (init*, new*, etc.)
385
386 printer->Print(
387 variables: variables_,
388 text: "$comments$"
389 "$array_comment$"
390 "@property(nonatomic, readwrite, strong, null_resettable) $array_property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n"
391 "/** The number of items in @c $name$ without causing the array to be created. */\n"
392 "@property(nonatomic, readonly) NSUInteger $name$_Count$deprecated_attribute$;\n");
393 if (IsInitName(name: variables_.find(x: "name")->second)) {
394 // If property name starts with init we need to annotate it to get past ARC.
395 // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227
396 printer->Print(variables: variables_,
397 text: "- ($array_property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n");
398 }
399 printer->Print(text: "\n");
400}
401
402bool RepeatedFieldGenerator::RuntimeUsesHasBit(void) const {
403 return false; // The array (or map/dict) having anything is what is used.
404}
405
406FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor)
407 : descriptor_(descriptor),
408 field_generators_(descriptor->field_count()),
409 extension_generators_(descriptor->extension_count()) {
410 // Construct all the FieldGenerators.
411 for (int i = 0; i < descriptor->field_count(); i++) {
412 field_generators_[i].reset(
413 p: FieldGenerator::Make(field: descriptor->field(index: i)));
414 }
415 for (int i = 0; i < descriptor->extension_count(); i++) {
416 extension_generators_[i].reset(
417 p: FieldGenerator::Make(field: descriptor->extension(index: i)));
418 }
419}
420
421FieldGeneratorMap::~FieldGeneratorMap() {}
422
423const FieldGenerator& FieldGeneratorMap::get(
424 const FieldDescriptor* field) const {
425 GOOGLE_CHECK_EQ(field->containing_type(), descriptor_);
426 return *field_generators_[field->index()];
427}
428
429const FieldGenerator& FieldGeneratorMap::get_extension(int index) const {
430 return *extension_generators_[index];
431}
432
433int FieldGeneratorMap::CalculateHasBits(void) {
434 int total_bits = 0;
435 for (int i = 0; i < descriptor_->field_count(); i++) {
436 if (field_generators_[i]->RuntimeUsesHasBit()) {
437 field_generators_[i]->SetRuntimeHasBit(total_bits);
438 ++total_bits;
439 } else {
440 field_generators_[i]->SetNoHasBit();
441 }
442 int extra_bits = field_generators_[i]->ExtraRuntimeHasBitsNeeded();
443 if (extra_bits) {
444 field_generators_[i]->SetExtraRuntimeHasBitsBase(total_bits);
445 total_bits += extra_bits;
446 }
447 }
448 return total_bits;
449}
450
451void FieldGeneratorMap::SetOneofIndexBase(int index_base) {
452 for (int i = 0; i < descriptor_->field_count(); i++) {
453 field_generators_[i]->SetOneofIndexBase(index_base);
454 }
455}
456
457bool FieldGeneratorMap::DoesAnyFieldHaveNonZeroDefault(void) const {
458 for (int i = 0; i < descriptor_->field_count(); i++) {
459 if (HasNonZeroDefaultValue(field: descriptor_->field(index: i))) {
460 return true;
461 }
462 }
463
464 return false;
465}
466
467} // namespace objectivec
468} // namespace compiler
469} // namespace protobuf
470} // namespace google
471