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_extension.h>
34 #include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
35 #include <google/protobuf/descriptor.pb.h>
36 #include <google/protobuf/stubs/strutil.h>
37 #include <google/protobuf/io/printer.h>
38
39 namespace google {
40 namespace protobuf {
41 namespace compiler {
42 namespace objectivec {
43
ExtensionGenerator(const string & root_class_name,const FieldDescriptor * descriptor)44 ExtensionGenerator::ExtensionGenerator(const string& root_class_name,
45 const FieldDescriptor* descriptor)
46 : method_name_(ExtensionMethodName(descriptor)),
47 root_class_and_method_name_(root_class_name + "_" + method_name_),
48 descriptor_(descriptor) {
49 if (descriptor->is_map()) {
50 // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
51 // error cases, so it seems to be ok to use as a back door for errors.
52 std::cerr << "error: Extension is a map<>!"
53 << " That used to be blocked by the compiler." << std::endl;
54 std::cerr.flush();
55 abort();
56 }
57 }
58
~ExtensionGenerator()59 ExtensionGenerator::~ExtensionGenerator() {}
60
GenerateMembersHeader(io::Printer * printer)61 void ExtensionGenerator::GenerateMembersHeader(io::Printer* printer) {
62 std::map<string, string> vars;
63 vars["method_name"] = method_name_;
64 if (IsRetainedName(method_name_)) {
65 vars["storage_attribute"] = " NS_RETURNS_NOT_RETAINED";
66 } else {
67 vars["storage_attribute"] = "";
68 }
69 SourceLocation location;
70 if (descriptor_->GetSourceLocation(&location)) {
71 vars["comments"] = BuildCommentsString(location, true);
72 } else {
73 vars["comments"] = "";
74 }
75 // Unlike normal message fields, check if the file for the extension was
76 // deprecated.
77 vars["deprecated_attribute"] = GetOptionalDeprecatedAttribute(descriptor_, descriptor_->file());
78 printer->Print(vars,
79 "$comments$"
80 "+ (GPBExtensionDescriptor *)$method_name$$storage_attribute$$deprecated_attribute$;\n");
81 }
82
GenerateStaticVariablesInitialization(io::Printer * printer)83 void ExtensionGenerator::GenerateStaticVariablesInitialization(
84 io::Printer* printer) {
85 std::map<string, string> vars;
86 vars["root_class_and_method_name"] = root_class_and_method_name_;
87 const string containing_type = ClassName(descriptor_->containing_type());
88 vars["extended_type"] = ObjCClass(containing_type);
89 vars["number"] = StrCat(descriptor_->number());
90
91 std::vector<string> options;
92 if (descriptor_->is_repeated()) options.push_back("GPBExtensionRepeated");
93 if (descriptor_->is_packed()) options.push_back("GPBExtensionPacked");
94 if (descriptor_->containing_type()->options().message_set_wire_format()) {
95 options.push_back("GPBExtensionSetWireFormat");
96 }
97 vars["options"] = BuildFlagsString(FLAGTYPE_EXTENSION, options);
98
99 ObjectiveCType objc_type = GetObjectiveCType(descriptor_);
100 if (objc_type == OBJECTIVECTYPE_MESSAGE) {
101 std::string message_type = ClassName(descriptor_->message_type());
102 vars["type"] = ObjCClass(message_type);
103 } else {
104 vars["type"] = "Nil";
105 }
106
107 vars["default_name"] = GPBGenericValueFieldName(descriptor_);
108 if (descriptor_->is_repeated()) {
109 vars["default"] = "nil";
110 } else {
111 vars["default"] = DefaultValue(descriptor_);
112 }
113 string type = GetCapitalizedType(descriptor_);
114 vars["extension_type"] = string("GPBDataType") + type;
115
116 if (objc_type == OBJECTIVECTYPE_ENUM) {
117 vars["enum_desc_func_name"] =
118 EnumName(descriptor_->enum_type()) + "_EnumDescriptor";
119 } else {
120 vars["enum_desc_func_name"] = "NULL";
121 }
122
123 printer->Print(vars,
124 "{\n"
125 " .defaultValue.$default_name$ = $default$,\n"
126 " .singletonName = GPBStringifySymbol($root_class_and_method_name$),\n"
127 " .extendedClass.clazz = $extended_type$,\n"
128 " .messageOrGroupClass.clazz = $type$,\n"
129 " .enumDescriptorFunc = $enum_desc_func_name$,\n"
130 " .fieldNumber = $number$,\n"
131 " .dataType = $extension_type$,\n"
132 " .options = $options$,\n"
133 "},\n");
134 }
135
DetermineObjectiveCClassDefinitions(std::set<string> * fwd_decls)136 void ExtensionGenerator::DetermineObjectiveCClassDefinitions(
137 std::set<string>* fwd_decls) {
138 string extended_type = ClassName(descriptor_->containing_type());
139 fwd_decls->insert(ObjCClassDeclaration(extended_type));
140 ObjectiveCType objc_type = GetObjectiveCType(descriptor_);
141 if (objc_type == OBJECTIVECTYPE_MESSAGE) {
142 string message_type = ClassName(descriptor_->message_type());
143 fwd_decls->insert(ObjCClassDeclaration(message_type));
144 }
145 }
146
GenerateRegistrationSource(io::Printer * printer)147 void ExtensionGenerator::GenerateRegistrationSource(io::Printer* printer) {
148 printer->Print(
149 "[registry addExtension:$root_class_and_method_name$];\n",
150 "root_class_and_method_name", root_class_and_method_name_);
151 }
152
153 } // namespace objectivec
154 } // namespace compiler
155 } // namespace protobuf
156 } // namespace google
157