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
39namespace google {
40namespace protobuf {
41namespace compiler {
42namespace objectivec {
43
44ExtensionGenerator::ExtensionGenerator(const std::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
59ExtensionGenerator::~ExtensionGenerator() {}
60
61void ExtensionGenerator::GenerateMembersHeader(io::Printer* printer) {
62 std::map<std::string, std::string> vars;
63 vars["method_name"] = method_name_;
64 if (IsRetainedName(name: method_name_)) {
65 vars["storage_attribute"] = " NS_RETURNS_NOT_RETAINED";
66 } else {
67 vars["storage_attribute"] = "";
68 }
69 SourceLocation location;
70 if (descriptor_->GetSourceLocation(out_location: &location)) {
71 vars["comments"] = BuildCommentsString(location, prefer_single_line: 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: descriptor_->file());
78 printer->Print(variables: vars,
79 text: "$comments$"
80 "+ (GPBExtensionDescriptor *)$method_name$$storage_attribute$$deprecated_attribute$;\n");
81}
82
83void ExtensionGenerator::GenerateStaticVariablesInitialization(
84 io::Printer* printer) {
85 std::map<std::string, std::string> vars;
86 vars["root_class_and_method_name"] = root_class_and_method_name_;
87 const std::string containing_type = ClassName(descriptor: descriptor_->containing_type());
88 vars["extended_type"] = ObjCClass(class_name: containing_type);
89 vars["number"] = StrCat(a: descriptor_->number());
90
91 std::vector<std::string> options;
92 if (descriptor_->is_repeated()) options.push_back(x: "GPBExtensionRepeated");
93 if (descriptor_->is_packed()) options.push_back(x: "GPBExtensionPacked");
94 if (descriptor_->containing_type()->options().message_set_wire_format()) {
95 options.push_back(x: "GPBExtensionSetWireFormat");
96 }
97 vars["options"] = BuildFlagsString(type: FLAGTYPE_EXTENSION, strings: options);
98
99 ObjectiveCType objc_type = GetObjectiveCType(field: descriptor_);
100 if (objc_type == OBJECTIVECTYPE_MESSAGE) {
101 std::string message_type = ClassName(descriptor: descriptor_->message_type());
102 vars["type"] = ObjCClass(class_name: message_type);
103 } else {
104 vars["type"] = "Nil";
105 }
106
107 vars["default_name"] = GPBGenericValueFieldName(field: descriptor_);
108 if (descriptor_->is_repeated()) {
109 vars["default"] = "nil";
110 } else {
111 vars["default"] = DefaultValue(field: descriptor_);
112 }
113 std::string type = GetCapitalizedType(field: descriptor_);
114 vars["extension_type"] = std::string("GPBDataType") + type;
115
116 if (objc_type == OBJECTIVECTYPE_ENUM) {
117 vars["enum_desc_func_name"] =
118 EnumName(descriptor: descriptor_->enum_type()) + "_EnumDescriptor";
119 } else {
120 vars["enum_desc_func_name"] = "NULL";
121 }
122
123 printer->Print(variables: vars,
124 text: "{\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
136void ExtensionGenerator::DetermineObjectiveCClassDefinitions(
137 std::set<std::string>* fwd_decls) {
138 std::string extended_type = ClassName(descriptor: descriptor_->containing_type());
139 fwd_decls->insert(x: ObjCClassDeclaration(class_name: extended_type));
140 ObjectiveCType objc_type = GetObjectiveCType(field: descriptor_);
141 if (objc_type == OBJECTIVECTYPE_MESSAGE) {
142 std::string message_type = ClassName(descriptor: descriptor_->message_type());
143 fwd_decls->insert(x: ObjCClassDeclaration(class_name: message_type));
144 }
145}
146
147void ExtensionGenerator::GenerateRegistrationSource(io::Printer* printer) {
148 printer->Print(
149 text: "[registry addExtension:$root_class_and_method_name$];\n",
150 args: "root_class_and_method_name", args: root_class_and_method_name_);
151}
152
153} // namespace objectivec
154} // namespace compiler
155} // namespace protobuf
156} // namespace google
157