| // Protocol Buffers - Google's data interchange format |
| // Copyright 2008 Google Inc. All rights reserved. |
| // https://developers.google.com/protocol-buffers/ |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #include <iostream> |
| |
| #include <google/protobuf/compiler/objectivec/objectivec_field.h> |
| #include <google/protobuf/compiler/objectivec/objectivec_helpers.h> |
| #include <google/protobuf/compiler/objectivec/objectivec_enum_field.h> |
| #include <google/protobuf/compiler/objectivec/objectivec_map_field.h> |
| #include <google/protobuf/compiler/objectivec/objectivec_message_field.h> |
| #include <google/protobuf/compiler/objectivec/objectivec_primitive_field.h> |
| #include <google/protobuf/io/printer.h> |
| #include <google/protobuf/wire_format.h> |
| #include <google/protobuf/stubs/common.h> |
| #include <google/protobuf/stubs/strutil.h> |
| |
| namespace google { |
| namespace protobuf { |
| namespace compiler { |
| namespace objectivec { |
| |
| namespace { |
| |
| void SetCommonFieldVariables(const FieldDescriptor* descriptor, |
| map<string, string>* variables) { |
| string camel_case_name = FieldName(descriptor); |
| string raw_field_name; |
| if (descriptor->type() == FieldDescriptor::TYPE_GROUP) { |
| raw_field_name = descriptor->message_type()->name(); |
| } else { |
| raw_field_name = descriptor->name(); |
| } |
| // The logic here has to match -[GGPBFieldDescriptor textFormatName]. |
| const string un_camel_case_name( |
| UnCamelCaseFieldName(camel_case_name, descriptor)); |
| const bool needs_custom_name = (raw_field_name != un_camel_case_name); |
| |
| SourceLocation location; |
| if (descriptor->GetSourceLocation(&location)) { |
| (*variables)["comments"] = BuildCommentsString(location); |
| } else { |
| (*variables)["comments"] = "\n"; |
| } |
| const string& classname = ClassName(descriptor->containing_type()); |
| (*variables)["classname"] = classname; |
| (*variables)["name"] = camel_case_name; |
| const string& capitalized_name = FieldNameCapitalized(descriptor); |
| (*variables)["capitalized_name"] = capitalized_name; |
| (*variables)["raw_field_name"] = raw_field_name; |
| (*variables)["field_number_name"] = |
| classname + "_FieldNumber_" + capitalized_name; |
| (*variables)["field_number"] = SimpleItoa(descriptor->number()); |
| (*variables)["field_type"] = GetCapitalizedType(descriptor); |
| (*variables)["deprecated_attribute"] = GetOptionalDeprecatedAttribute(descriptor); |
| std::vector<string> field_flags; |
| if (descriptor->is_repeated()) field_flags.push_back("GPBFieldRepeated"); |
| if (descriptor->is_required()) field_flags.push_back("GPBFieldRequired"); |
| if (descriptor->is_optional()) field_flags.push_back("GPBFieldOptional"); |
| if (descriptor->is_packed()) field_flags.push_back("GPBFieldPacked"); |
| |
| // ObjC custom flags. |
| if (descriptor->has_default_value()) |
| field_flags.push_back("GPBFieldHasDefaultValue"); |
| if (needs_custom_name) field_flags.push_back("GPBFieldTextFormatNameCustom"); |
| if (descriptor->type() == FieldDescriptor::TYPE_ENUM) { |
| field_flags.push_back("GPBFieldHasEnumDescriptor"); |
| } |
| |
| (*variables)["fieldflags"] = BuildFlagsString(field_flags); |
| |
| (*variables)["default"] = DefaultValue(descriptor); |
| (*variables)["default_name"] = GPBGenericValueFieldName(descriptor); |
| |
| (*variables)["dataTypeSpecific_name"] = "className"; |
| (*variables)["dataTypeSpecific_value"] = "NULL"; |
| |
| (*variables)["storage_offset_value"] = |
| "(uint32_t)offsetof(" + classname + "__storage_, " + camel_case_name + ")"; |
| (*variables)["storage_offset_comment"] = ""; |
| |
| // Clear some common things so they can be set just when needed. |
| (*variables)["storage_attribute"] = ""; |
| } |
| |
| } // namespace |
| |
| FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field, |
| const Options& options) { |
| FieldGenerator* result = NULL; |
| if (field->is_repeated()) { |
| switch (GetObjectiveCType(field)) { |
| case OBJECTIVECTYPE_MESSAGE: { |
| if (field->is_map()) { |
| result = new MapFieldGenerator(field, options); |
| } else { |
| result = new RepeatedMessageFieldGenerator(field, options); |
| } |
| break; |
| } |
| case OBJECTIVECTYPE_ENUM: |
| result = new RepeatedEnumFieldGenerator(field, options); |
| break; |
| default: |
| result = new RepeatedPrimitiveFieldGenerator(field, options); |
| break; |
| } |
| } else { |
| switch (GetObjectiveCType(field)) { |
| case OBJECTIVECTYPE_MESSAGE: { |
| result = new MessageFieldGenerator(field, options); |
| break; |
| } |
| case OBJECTIVECTYPE_ENUM: |
| result = new EnumFieldGenerator(field, options); |
| break; |
| default: |
| if (IsReferenceType(field)) { |
| result = new PrimitiveObjFieldGenerator(field, options); |
| } else { |
| result = new PrimitiveFieldGenerator(field, options); |
| } |
| break; |
| } |
| } |
| result->FinishInitialization(); |
| return result; |
| } |
| |
| FieldGenerator::FieldGenerator(const FieldDescriptor* descriptor, |
| const Options& options) |
| : descriptor_(descriptor) { |
| SetCommonFieldVariables(descriptor, &variables_); |
| } |
| |
| FieldGenerator::~FieldGenerator() {} |
| |
| void FieldGenerator::GenerateFieldNumberConstant(io::Printer* printer) const { |
| printer->Print( |
| variables_, |
| "$field_number_name$ = $field_number$,\n"); |
| } |
| |
| void FieldGenerator::GenerateCFunctionDeclarations( |
| io::Printer* printer) const { |
| // Nothing |
| } |
| |
| void FieldGenerator::GenerateCFunctionImplementations( |
| io::Printer* printer) const { |
| // Nothing |
| } |
| |
| void FieldGenerator::DetermineForwardDeclarations( |
| set<string>* fwd_decls) const { |
| // Nothing |
| } |
| |
| void FieldGenerator::GenerateFieldDescription( |
| io::Printer* printer, bool include_default) const { |
| // Printed in the same order as the structure decl. |
| if (include_default) { |
| printer->Print( |
| variables_, |
| "{\n" |
| " .defaultValue.$default_name$ = $default$,\n" |
| " .core.name = \"$name$\",\n" |
| " .core.dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n" |
| " .core.number = $field_number_name$,\n" |
| " .core.hasIndex = $has_index$,\n" |
| " .core.offset = $storage_offset_value$,$storage_offset_comment$\n" |
| " .core.flags = $fieldflags$,\n" |
| " .core.dataType = GPBDataType$field_type$,\n" |
| "},\n"); |
| } else { |
| printer->Print( |
| variables_, |
| "{\n" |
| " .name = \"$name$\",\n" |
| " .dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n" |
| " .number = $field_number_name$,\n" |
| " .hasIndex = $has_index$,\n" |
| " .offset = $storage_offset_value$,$storage_offset_comment$\n" |
| " .flags = $fieldflags$,\n" |
| " .dataType = GPBDataType$field_type$,\n" |
| "},\n"); |
| } |
| } |
| |
| void FieldGenerator::SetRuntimeHasBit(int has_index) { |
| variables_["has_index"] = SimpleItoa(has_index); |
| } |
| |
| void FieldGenerator::SetNoHasBit(void) { |
| variables_["has_index"] = "GPBNoHasBit"; |
| } |
| |
| int FieldGenerator::ExtraRuntimeHasBitsNeeded(void) const { |
| return 0; |
| } |
| |
| void FieldGenerator::SetExtraRuntimeHasBitsBase(int index_base) { |
| // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some |
| // error cases, so it seems to be ok to use as a back door for errors. |
| cerr << "Error: should have overriden SetExtraRuntimeHasBitsBase()." << endl; |
| cerr.flush(); |
| abort(); |
| } |
| |
| void FieldGenerator::SetOneofIndexBase(int index_base) { |
| if (descriptor_->containing_oneof() != NULL) { |
| int index = descriptor_->containing_oneof()->index() + index_base; |
| // Flip the sign to mark it as a oneof. |
| variables_["has_index"] = SimpleItoa(-index); |
| } |
| } |
| |
| void FieldGenerator::FinishInitialization(void) { |
| // If "property_type" wasn't set, make it "storage_type". |
| if ((variables_.find("property_type") == variables_.end()) && |
| (variables_.find("storage_type") != variables_.end())) { |
| variables_["property_type"] = variable("storage_type"); |
| } |
| } |
| |
| SingleFieldGenerator::SingleFieldGenerator(const FieldDescriptor* descriptor, |
| const Options& options) |
| : FieldGenerator(descriptor, options) { |
| // Nothing |
| } |
| |
| SingleFieldGenerator::~SingleFieldGenerator() {} |
| |
| void SingleFieldGenerator::GenerateFieldStorageDeclaration( |
| io::Printer* printer) const { |
| printer->Print(variables_, "$storage_type$ $name$;\n"); |
| } |
| |
| void SingleFieldGenerator::GeneratePropertyDeclaration( |
| io::Printer* printer) const { |
| printer->Print(variables_, "$comments$"); |
| printer->Print( |
| variables_, |
| "@property(nonatomic, readwrite) $property_type$ $name$$deprecated_attribute$;\n" |
| "\n"); |
| if (WantsHasProperty()) { |
| printer->Print( |
| variables_, |
| "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n"); |
| } |
| } |
| |
| void SingleFieldGenerator::GeneratePropertyImplementation( |
| io::Printer* printer) const { |
| if (WantsHasProperty()) { |
| printer->Print(variables_, "@dynamic has$capitalized_name$, $name$;\n"); |
| } else { |
| printer->Print(variables_, "@dynamic $name$;\n"); |
| } |
| } |
| |
| bool SingleFieldGenerator::WantsHasProperty(void) const { |
| if (descriptor_->containing_oneof() != NULL) { |
| // If in a oneof, it uses the oneofcase instead of a has bit. |
| return false; |
| } |
| if (HasFieldPresence(descriptor_->file())) { |
| // In proto1/proto2, every field has a has_$name$() method. |
| return true; |
| } |
| return false; |
| } |
| |
| bool SingleFieldGenerator::RuntimeUsesHasBit(void) const { |
| if (descriptor_->containing_oneof() != NULL) { |
| // The oneof tracks what is set instead. |
| return false; |
| } |
| return true; |
| } |
| |
| ObjCObjFieldGenerator::ObjCObjFieldGenerator(const FieldDescriptor* descriptor, |
| const Options& options) |
| : SingleFieldGenerator(descriptor, options) { |
| variables_["property_storage_attribute"] = "strong"; |
| if (IsRetainedName(variables_["name"])) { |
| variables_["storage_attribute"] = " NS_RETURNS_NOT_RETAINED"; |
| } |
| } |
| |
| ObjCObjFieldGenerator::~ObjCObjFieldGenerator() {} |
| |
| void ObjCObjFieldGenerator::GenerateFieldStorageDeclaration( |
| io::Printer* printer) const { |
| printer->Print(variables_, "$storage_type$ *$name$;\n"); |
| } |
| |
| void ObjCObjFieldGenerator::GeneratePropertyDeclaration( |
| io::Printer* printer) const { |
| |
| // Differs from SingleFieldGenerator::GeneratePropertyDeclaration() in that |
| // it uses pointers and deals with Objective C's rules around storage name |
| // conventions (init*, new*, etc.) |
| |
| printer->Print(variables_, "$comments$"); |
| printer->Print( |
| variables_, |
| "@property(nonatomic, readwrite, $property_storage_attribute$, null_resettable) $property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n"); |
| if (WantsHasProperty()) { |
| printer->Print( |
| variables_, |
| "/// Test to see if @c $name$ has been set.\n" |
| "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n"); |
| } |
| if (IsInitName(variables_.find("name")->second)) { |
| // 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->Print(variables_, |
| "- ($property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n"); |
| } |
| printer->Print("\n"); |
| } |
| |
| RepeatedFieldGenerator::RepeatedFieldGenerator( |
| const FieldDescriptor* descriptor, const Options& options) |
| : ObjCObjFieldGenerator(descriptor, options) { |
| // Default to no comment and let the cases needing it fill it in. |
| variables_["array_comment"] = ""; |
| } |
| |
| RepeatedFieldGenerator::~RepeatedFieldGenerator() {} |
| |
| void RepeatedFieldGenerator::FinishInitialization(void) { |
| FieldGenerator::FinishInitialization(); |
| if (variables_.find("array_property_type") == variables_.end()) { |
| variables_["array_property_type"] = variable("array_storage_type"); |
| } |
| } |
| |
| void RepeatedFieldGenerator::GenerateFieldStorageDeclaration( |
| io::Printer* printer) const { |
| printer->Print(variables_, "$array_storage_type$ *$name$;\n"); |
| } |
| |
| void RepeatedFieldGenerator::GeneratePropertyImplementation( |
| io::Printer* printer) const { |
| printer->Print(variables_, "@dynamic $name$, $name$_Count;\n"); |
| } |
| |
| void RepeatedFieldGenerator::GeneratePropertyDeclaration( |
| io::Printer* printer) const { |
| |
| // Repeated fields don't need the has* properties, but they do expose a |
| // *Count (to check without autocreation). So for the field property we need |
| // the same logic as ObjCObjFieldGenerator::GeneratePropertyDeclaration() for |
| // dealing with needing Objective C's rules around storage name conventions |
| // (init*, new*, etc.) |
| |
| printer->Print( |
| variables_, |
| "$comments$" |
| "$array_comment$" |
| "@property(nonatomic, readwrite, strong, null_resettable) $array_property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n" |
| "/// The number of items in @c $name$ without causing the array to be created.\n" |
| "@property(nonatomic, readonly) NSUInteger $name$_Count$deprecated_attribute$;\n"); |
| if (IsInitName(variables_.find("name")->second)) { |
| // 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->Print(variables_, |
| "- ($array_property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n"); |
| } |
| printer->Print("\n"); |
| } |
| |
| bool RepeatedFieldGenerator::WantsHasProperty(void) const { |
| // Consumer check the array size/existance rather than a has bit. |
| return false; |
| } |
| |
| bool RepeatedFieldGenerator::RuntimeUsesHasBit(void) const { |
| return false; // The array having anything is what is used. |
| } |
| |
| FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, |
| const Options& options) |
| : descriptor_(descriptor), |
| field_generators_( |
| new scoped_ptr<FieldGenerator>[descriptor->field_count()]), |
| extension_generators_( |
| new scoped_ptr<FieldGenerator>[descriptor->extension_count()]) { |
| // Construct all the FieldGenerators. |
| for (int i = 0; i < descriptor->field_count(); i++) { |
| field_generators_[i].reset( |
| FieldGenerator::Make(descriptor->field(i), options)); |
| } |
| for (int i = 0; i < descriptor->extension_count(); i++) { |
| extension_generators_[i].reset( |
| FieldGenerator::Make(descriptor->extension(i), options)); |
| } |
| } |
| |
| FieldGeneratorMap::~FieldGeneratorMap() {} |
| |
| const FieldGenerator& FieldGeneratorMap::get( |
| const FieldDescriptor* field) const { |
| GOOGLE_CHECK_EQ(field->containing_type(), descriptor_); |
| return *field_generators_[field->index()]; |
| } |
| |
| const FieldGenerator& FieldGeneratorMap::get_extension(int index) const { |
| return *extension_generators_[index]; |
| } |
| |
| int FieldGeneratorMap::CalculateHasBits(void) { |
| int total_bits = 0; |
| for (int i = 0; i < descriptor_->field_count(); i++) { |
| if (field_generators_[i]->RuntimeUsesHasBit()) { |
| field_generators_[i]->SetRuntimeHasBit(total_bits); |
| ++total_bits; |
| } else { |
| field_generators_[i]->SetNoHasBit(); |
| } |
| int extra_bits = field_generators_[i]->ExtraRuntimeHasBitsNeeded(); |
| if (extra_bits) { |
| field_generators_[i]->SetExtraRuntimeHasBitsBase(total_bits); |
| total_bits += extra_bits; |
| } |
| } |
| return total_bits; |
| } |
| |
| void FieldGeneratorMap::SetOneofIndexBase(int index_base) { |
| for (int i = 0; i < descriptor_->field_count(); i++) { |
| field_generators_[i]->SetOneofIndexBase(index_base); |
| } |
| } |
| |
| bool FieldGeneratorMap::DoesAnyFieldHaveNonZeroDefault(void) const { |
| for (int i = 0; i < descriptor_->field_count(); i++) { |
| if (HasNonZeroDefaultValue(descriptor_->field(i))) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| } // namespace objectivec |
| } // namespace compiler |
| } // namespace protobuf |
| } // namespace google |