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/descriptor.pb.h>
39 #include <google/protobuf/io/printer.h>
40 #include <google/protobuf/stubs/strutil.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 std::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), options_(options) {
62 // Construct type_traits_.
63 if (descriptor_->is_repeated()) {
64 type_traits_ = "Repeated";
65 }
66
67 switch (descriptor_->cpp_type()) {
68 case FieldDescriptor::CPPTYPE_ENUM:
69 type_traits_.append("EnumTypeTraits< ");
70 type_traits_.append(ClassName(descriptor_->enum_type(), true));
71 type_traits_.append(", ");
72 type_traits_.append(ClassName(descriptor_->enum_type(), true));
73 type_traits_.append("_IsValid>");
74 break;
75 case FieldDescriptor::CPPTYPE_STRING:
76 type_traits_.append("StringTypeTraits");
77 break;
78 case FieldDescriptor::CPPTYPE_MESSAGE:
79 type_traits_.append("MessageTypeTraits< ");
80 type_traits_.append(ClassName(descriptor_->message_type(), true));
81 type_traits_.append(" >");
82 break;
83 default:
84 type_traits_.append("PrimitiveTypeTraits< ");
85 type_traits_.append(PrimitiveTypeName(options_, descriptor_->cpp_type()));
86 type_traits_.append(" >");
87 break;
88 }
89 SetCommonVars(options, &variables_);
90 variables_["extendee"] = ExtendeeClassName(descriptor_);
91 variables_["type_traits"] = type_traits_;
92 std::string name = descriptor_->name();
93 variables_["name"] = ResolveKeyword(name);
94 variables_["constant_name"] = FieldConstantName(descriptor_);
95 variables_["field_type"] =
96 StrCat(static_cast<int>(descriptor_->type()));
97 variables_["packed"] = descriptor_->is_packed() ? "true" : "false";
98
99 std::string scope =
100 IsScoped() ? ClassName(descriptor_->extension_scope(), false) + "::" : "";
101 variables_["scope"] = scope;
102 std::string scoped_name = scope + ResolveKeyword(name);
103 variables_["scoped_name"] = scoped_name;
104 variables_["number"] = StrCat(descriptor_->number());
105 }
106
~ExtensionGenerator()107 ExtensionGenerator::~ExtensionGenerator() {}
108
IsScoped() const109 bool ExtensionGenerator::IsScoped() const {
110 return descriptor_->extension_scope() != nullptr;
111 }
112
GenerateDeclaration(io::Printer * printer) const113 void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) const {
114 Formatter format(printer, variables_);
115
116 // If this is a class member, it needs to be declared "static". Otherwise,
117 // it needs to be "extern". In the latter case, it also needs the DLL
118 // export/import specifier.
119 std::string qualifier;
120 if (!IsScoped()) {
121 qualifier = "extern";
122 if (!options_.dllexport_decl.empty()) {
123 qualifier = options_.dllexport_decl + " " + qualifier;
124 }
125 } else {
126 qualifier = "static";
127 }
128
129 format(
130 "static const int $constant_name$ = $number$;\n"
131 "$1$ ::$proto_ns$::internal::ExtensionIdentifier< $extendee$,\n"
132 " ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$ >\n"
133 " ${2$$name$$}$;\n",
134 qualifier, descriptor_);
135 }
136
GenerateDefinition(io::Printer * printer)137 void ExtensionGenerator::GenerateDefinition(io::Printer* printer) {
138 // If we are building for lite with implicit weak fields, we want to skip over
139 // any custom options (i.e. extensions of messages from descriptor.proto).
140 // This prevents the creation of any unnecessary linker references to the
141 // descriptor messages.
142 if (options_.lite_implicit_weak_fields &&
143 descriptor_->containing_type()->file()->name() ==
144 "net/proto2/proto/descriptor.proto") {
145 return;
146 }
147
148 Formatter format(printer, variables_);
149 std::string default_str;
150 // If this is a class member, it needs to be declared in its class scope.
151 if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
152 // We need to declare a global string which will contain the default value.
153 // We cannot declare it at class scope because that would require exposing
154 // it in the header which would be annoying for other reasons. So we
155 // replace :: with _ in the name and declare it as a global.
156 default_str =
157 StringReplace(variables_["scoped_name"], "::", "_", true) + "_default";
158 format("const std::string $1$($2$);\n", default_str,
159 DefaultValue(options_, descriptor_));
160 } else if (descriptor_->message_type()) {
161 // We have to initialize the default instance for extensions at registration
162 // time.
163 default_str =
164 FieldMessageTypeName(descriptor_, options_) + "::default_instance()";
165 } else {
166 default_str = DefaultValue(options_, descriptor_);
167 }
168
169 // Likewise, class members need to declare the field constant variable.
170 if (IsScoped()) {
171 format(
172 "#if !defined(_MSC_VER) || _MSC_VER >= 1900\n"
173 "const int $scope$$constant_name$;\n"
174 "#endif\n");
175 }
176
177 format(
178 "::$proto_ns$::internal::ExtensionIdentifier< $extendee$,\n"
179 " ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$ >\n"
180 " $scoped_name$($constant_name$, $1$);\n",
181 default_str);
182 }
183
184 } // namespace cpp
185 } // namespace compiler
186 } // namespace protobuf
187 } // namespace google
188