Line data Source code
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 : // Author: kenton@google.com (Kenton Varda)
32 : // Based on original Protocol Buffers design by
33 : // Sanjay Ghemawat, Jeff Dean, and others.
34 :
35 : #include <google/protobuf/compiler/cpp/cpp_extension.h>
36 : #include <map>
37 : #include <google/protobuf/compiler/cpp/cpp_helpers.h>
38 : #include <google/protobuf/stubs/strutil.h>
39 : #include <google/protobuf/io/printer.h>
40 : #include <google/protobuf/descriptor.pb.h>
41 :
42 : namespace google {
43 : namespace protobuf {
44 : namespace compiler {
45 : namespace cpp {
46 :
47 : namespace {
48 :
49 : // Returns the fully-qualified class name of the message that this field
50 : // extends. This function is used in the Google-internal code to handle some
51 : // legacy cases.
52 765 : string ExtendeeClassName(const FieldDescriptor* descriptor) {
53 765 : const Descriptor* extendee = descriptor->containing_type();
54 765 : return ClassName(extendee, true);
55 : }
56 :
57 : } // anonymous namespace
58 :
59 255 : ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor,
60 : const Options& options)
61 : : descriptor_(descriptor),
62 510 : options_(options) {
63 : // Construct type_traits_.
64 1010 : if (descriptor_->is_repeated()) {
65 97 : type_traits_ = "Repeated";
66 : }
67 :
68 765 : switch (descriptor_->cpp_type()) {
69 : case FieldDescriptor::CPPTYPE_ENUM:
70 23 : type_traits_.append("EnumTypeTraits< ");
71 69 : type_traits_.append(ClassName(descriptor_->enum_type(), true));
72 23 : type_traits_.append(", ");
73 69 : type_traits_.append(ClassName(descriptor_->enum_type(), true));
74 23 : type_traits_.append("_IsValid>");
75 : break;
76 : case FieldDescriptor::CPPTYPE_STRING:
77 33 : type_traits_.append("StringTypeTraits");
78 : break;
79 : case FieldDescriptor::CPPTYPE_MESSAGE:
80 52 : type_traits_.append("MessageTypeTraits< ");
81 156 : type_traits_.append(ClassName(descriptor_->message_type(), true));
82 52 : type_traits_.append(" >");
83 : break;
84 : default:
85 147 : type_traits_.append("PrimitiveTypeTraits< ");
86 441 : type_traits_.append(PrimitiveTypeName(descriptor_->cpp_type()));
87 147 : type_traits_.append(" >");
88 : break;
89 : }
90 255 : }
91 :
92 765 : ExtensionGenerator::~ExtensionGenerator() {}
93 :
94 255 : void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) {
95 : map<string, string> vars;
96 2295 : vars["extendee" ] = ExtendeeClassName(descriptor_);
97 1020 : vars["number" ] = SimpleItoa(descriptor_->number());
98 510 : vars["type_traits" ] = type_traits_;
99 765 : vars["name" ] = descriptor_->name();
100 1020 : vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type()));
101 765 : vars["packed" ] = descriptor_->options().packed() ? "true" : "false";
102 765 : vars["constant_name"] = FieldConstantName(descriptor_);
103 :
104 : // If this is a class member, it needs to be declared "static". Otherwise,
105 : // it needs to be "extern". In the latter case, it also needs the DLL
106 : // export/import specifier.
107 510 : if (descriptor_->extension_scope() == NULL) {
108 472 : vars["qualifier"] = "extern";
109 472 : if (!options_.dllexport_decl.empty()) {
110 0 : vars["qualifier"] = options_.dllexport_decl + " " + vars["qualifier"];
111 : }
112 : } else {
113 38 : vars["qualifier"] = "static";
114 : }
115 :
116 : printer->Print(vars,
117 : "static const int $constant_name$ = $number$;\n"
118 : "$qualifier$ ::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n"
119 : " ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n"
120 : " $name$;\n"
121 255 : );
122 :
123 255 : }
124 :
125 255 : void ExtensionGenerator::GenerateDefinition(io::Printer* printer) {
126 : // If this is a class member, it needs to be declared in its class scope.
127 1530 : string scope = (descriptor_->extension_scope() == NULL) ? "" :
128 274 : ClassName(descriptor_->extension_scope(), false) + "::";
129 510 : string name = scope + descriptor_->name();
130 :
131 : map<string, string> vars;
132 1020 : vars["extendee" ] = ExtendeeClassName(descriptor_);
133 510 : vars["type_traits" ] = type_traits_;
134 510 : vars["name" ] = name;
135 765 : vars["constant_name"] = FieldConstantName(descriptor_);
136 765 : vars["default" ] = DefaultValue(descriptor_);
137 1020 : vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type()));
138 765 : vars["packed" ] = descriptor_->options().packed() ? "true" : "false";
139 510 : vars["scope" ] = scope;
140 :
141 765 : if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
142 : // We need to declare a global string which will contain the default value.
143 : // We cannot declare it at class scope because that would require exposing
144 : // it in the header which would be annoying for other reasons. So we
145 : // replace :: with _ in the name and declare it as a global.
146 99 : string global_name = StringReplace(name, "::", "_", true);
147 66 : vars["global_name"] = global_name;
148 : printer->Print(vars,
149 33 : "const ::std::string $global_name$_default($default$);\n");
150 :
151 : // Update the default to refer to the string global.
152 99 : vars["default"] = global_name + "_default";
153 : }
154 :
155 : // Likewise, class members need to declare the field constant variable.
156 510 : if (descriptor_->extension_scope() != NULL) {
157 : printer->Print(vars,
158 : "#ifndef _MSC_VER\n"
159 : "const int $scope$$constant_name$;\n"
160 19 : "#endif\n");
161 : }
162 :
163 : printer->Print(vars,
164 : "::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n"
165 : " ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n"
166 255 : " $name$($constant_name$, $default$);\n");
167 255 : }
168 :
169 255 : void ExtensionGenerator::GenerateRegistration(io::Printer* printer) {
170 : map<string, string> vars;
171 1957 : vars["extendee" ] = ExtendeeClassName(descriptor_);
172 1020 : vars["number" ] = SimpleItoa(descriptor_->number());
173 1020 : vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type()));
174 765 : vars["is_repeated"] = descriptor_->is_repeated() ? "true" : "false";
175 862 : vars["is_packed" ] = (descriptor_->is_repeated() &&
176 97 : descriptor_->options().packed())
177 : ? "true" : "false";
178 :
179 765 : switch (descriptor_->cpp_type()) {
180 : case FieldDescriptor::CPPTYPE_ENUM:
181 : printer->Print(vars,
182 : "::google::protobuf::internal::ExtensionSet::RegisterEnumExtension(\n"
183 : " &$extendee$::default_instance(),\n"
184 23 : " $number$, $field_type$, $is_repeated$, $is_packed$,\n");
185 : printer->Print(
186 : " &$type$_IsValid);\n",
187 69 : "type", ClassName(descriptor_->enum_type(), true));
188 23 : break;
189 : case FieldDescriptor::CPPTYPE_MESSAGE:
190 : printer->Print(vars,
191 : "::google::protobuf::internal::ExtensionSet::RegisterMessageExtension(\n"
192 : " &$extendee$::default_instance(),\n"
193 52 : " $number$, $field_type$, $is_repeated$, $is_packed$,\n");
194 : printer->Print(
195 : " &$type$::default_instance());\n",
196 156 : "type", ClassName(descriptor_->message_type(), true));
197 52 : break;
198 : default:
199 : printer->Print(vars,
200 : "::google::protobuf::internal::ExtensionSet::RegisterExtension(\n"
201 : " &$extendee$::default_instance(),\n"
202 180 : " $number$, $field_type$, $is_repeated$, $is_packed$);\n");
203 : break;
204 : }
205 255 : }
206 :
207 : } // namespace cpp
208 : } // namespace compiler
209 : } // namespace protobuf
210 : } // namespace google
|