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.
ExtendeeClassName(const FieldDescriptor * descriptor)52 string ExtendeeClassName(const FieldDescriptor* descriptor) {
53   const Descriptor* extendee = descriptor->containing_type();
54   return ClassName(extendee, true);
55 }
56 
57 }  // anonymous namespace
58 
ExtensionGenerator(const FieldDescriptor * descriptor,const Options & options)59 ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor,
60                                        const Options& options)
61   : descriptor_(descriptor),
62     options_(options) {
63   // Construct type_traits_.
64   if (descriptor_->is_repeated()) {
65     type_traits_ = "Repeated";
66   }
67 
68   switch (descriptor_->cpp_type()) {
69     case FieldDescriptor::CPPTYPE_ENUM:
70       type_traits_.append("EnumTypeTraits< ");
71       type_traits_.append(ClassName(descriptor_->enum_type(), true));
72       type_traits_.append(", ");
73       type_traits_.append(ClassName(descriptor_->enum_type(), true));
74       type_traits_.append("_IsValid>");
75       break;
76     case FieldDescriptor::CPPTYPE_STRING:
77       type_traits_.append("StringTypeTraits");
78       break;
79     case FieldDescriptor::CPPTYPE_MESSAGE:
80       type_traits_.append("MessageTypeTraits< ");
81       type_traits_.append(ClassName(descriptor_->message_type(), true));
82       type_traits_.append(" >");
83       break;
84     default:
85       type_traits_.append("PrimitiveTypeTraits< ");
86       type_traits_.append(PrimitiveTypeName(descriptor_->cpp_type()));
87       type_traits_.append(" >");
88       break;
89   }
90 }
91 
~ExtensionGenerator()92 ExtensionGenerator::~ExtensionGenerator() {}
93 
GenerateDeclaration(io::Printer * printer)94 void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) {
95   map<string, string> vars;
96   vars["extendee"     ] = ExtendeeClassName(descriptor_);
97   vars["number"       ] = SimpleItoa(descriptor_->number());
98   vars["type_traits"  ] = type_traits_;
99   vars["name"         ] = descriptor_->name();
100   vars["field_type"   ] = SimpleItoa(static_cast<int>(descriptor_->type()));
101   vars["packed"       ] = descriptor_->options().packed() ? "true" : "false";
102   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   if (descriptor_->extension_scope() == NULL) {
108     vars["qualifier"] = "extern";
109     if (!options_.dllexport_decl.empty()) {
110       vars["qualifier"] = options_.dllexport_decl + " " + vars["qualifier"];
111     }
112   } else {
113     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     );
122 
123 }
124 
GenerateDefinition(io::Printer * printer)125 void ExtensionGenerator::GenerateDefinition(io::Printer* printer) {
126   // If this is a class member, it needs to be declared in its class scope.
127   string scope = (descriptor_->extension_scope() == NULL) ? "" :
128     ClassName(descriptor_->extension_scope(), false) + "::";
129   string name = scope + descriptor_->name();
130 
131   map<string, string> vars;
132   vars["extendee"     ] = ExtendeeClassName(descriptor_);
133   vars["type_traits"  ] = type_traits_;
134   vars["name"         ] = name;
135   vars["constant_name"] = FieldConstantName(descriptor_);
136   vars["default"      ] = DefaultValue(descriptor_);
137   vars["field_type"   ] = SimpleItoa(static_cast<int>(descriptor_->type()));
138   vars["packed"       ] = descriptor_->options().packed() ? "true" : "false";
139   vars["scope"        ] = scope;
140 
141   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     string global_name = StringReplace(name, "::", "_", true);
147     vars["global_name"] = global_name;
148     printer->Print(vars,
149       "const ::std::string $global_name$_default($default$);\n");
150 
151     // Update the default to refer to the string global.
152     vars["default"] = global_name + "_default";
153   }
154 
155   // Likewise, class members need to declare the field constant variable.
156   if (descriptor_->extension_scope() != NULL) {
157     printer->Print(vars,
158       "#ifndef _MSC_VER\n"
159       "const int $scope$$constant_name$;\n"
160       "#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     "  $name$($constant_name$, $default$);\n");
167 }
168 
GenerateRegistration(io::Printer * printer)169 void ExtensionGenerator::GenerateRegistration(io::Printer* printer) {
170   map<string, string> vars;
171   vars["extendee"   ] = ExtendeeClassName(descriptor_);
172   vars["number"     ] = SimpleItoa(descriptor_->number());
173   vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type()));
174   vars["is_repeated"] = descriptor_->is_repeated() ? "true" : "false";
175   vars["is_packed"  ] = (descriptor_->is_repeated() &&
176                          descriptor_->options().packed())
177                         ? "true" : "false";
178 
179   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         "  $number$, $field_type$, $is_repeated$, $is_packed$,\n");
185       printer->Print(
186         "  &$type$_IsValid);\n",
187         "type", ClassName(descriptor_->enum_type(), true));
188       break;
189     case FieldDescriptor::CPPTYPE_MESSAGE:
190       printer->Print(vars,
191         "::google::protobuf::internal::ExtensionSet::RegisterMessageExtension(\n"
192         "  &$extendee$::default_instance(),\n"
193         "  $number$, $field_type$, $is_repeated$, $is_packed$,\n");
194       printer->Print(
195         "  &$type$::default_instance());\n",
196         "type", ClassName(descriptor_->message_type(), true));
197       break;
198     default:
199       printer->Print(vars,
200         "::google::protobuf::internal::ExtensionSet::RegisterExtension(\n"
201         "  &$extendee$::default_instance(),\n"
202         "  $number$, $field_type$, $is_repeated$, $is_packed$);\n");
203       break;
204   }
205 }
206 
207 }  // namespace cpp
208 }  // namespace compiler
209 }  // namespace protobuf
210 }  // namespace google
211