1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 // Author: kenton@google.com (Kenton Varda)
9 // Based on original Protocol Buffers design by
10 // Sanjay Ghemawat, Jeff Dean, and others.
11
12 #include "google/protobuf/compiler/cpp/extension.h"
13
14 #include <string>
15 #include <vector>
16
17 #include "absl/log/absl_check.h"
18 #include "absl/strings/str_cat.h"
19 #include "absl/strings/str_replace.h"
20 #include "google/protobuf/compiler/cpp/helpers.h"
21 #include "google/protobuf/compiler/cpp/options.h"
22 #include "google/protobuf/descriptor.h"
23 #include "google/protobuf/descriptor.pb.h"
24 #include "google/protobuf/io/printer.h"
25
26 namespace google {
27 namespace protobuf {
28 namespace compiler {
29 namespace cpp {
30
ExtensionGenerator(const FieldDescriptor * descriptor,const Options & options,MessageSCCAnalyzer * scc_analyzer)31 ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor,
32 const Options& options,
33 MessageSCCAnalyzer* scc_analyzer)
34 : descriptor_(descriptor), options_(options), scc_analyzer_(scc_analyzer) {
35 // Construct type_traits_.
36 if (descriptor_->is_repeated()) {
37 type_traits_ = "Repeated";
38 }
39
40 switch (descriptor_->cpp_type()) {
41 case FieldDescriptor::CPPTYPE_ENUM:
42 type_traits_.append("EnumTypeTraits< ");
43 type_traits_.append(ClassName(descriptor_->enum_type(), true));
44 type_traits_.append(", ");
45 type_traits_.append(ClassName(descriptor_->enum_type(), true));
46 type_traits_.append("_IsValid>");
47 break;
48 case FieldDescriptor::CPPTYPE_STRING:
49 type_traits_.append("StringTypeTraits");
50 break;
51 case FieldDescriptor::CPPTYPE_MESSAGE:
52 type_traits_.append("MessageTypeTraits< ");
53 type_traits_.append(ClassName(descriptor_->message_type(), true));
54 type_traits_.append(" >");
55 break;
56 default:
57 type_traits_.append("PrimitiveTypeTraits< ");
58 type_traits_.append(PrimitiveTypeName(options_, descriptor_->cpp_type()));
59 type_traits_.append(" >");
60 break;
61 }
62 SetCommonMessageDataVariables(descriptor_->containing_type(), &variables_);
63 variables_["extendee"] =
64 QualifiedClassName(descriptor_->containing_type(), options_);
65 variables_["type_traits"] = type_traits_;
66 variables_["name"] = ResolveKeyword(descriptor_->name());
67 variables_["constant_name"] = FieldConstantName(descriptor_);
68 variables_["field_type"] =
69 absl::StrCat(static_cast<int>(descriptor_->type()));
70 variables_["repeated"] = descriptor_->is_repeated() ? "true" : "false";
71 variables_["packed"] = descriptor_->is_packed() ? "true" : "false";
72 variables_["dllexport_decl"] = options.dllexport_decl;
73
74 std::string scope;
75 if (IsScoped()) {
76 scope =
77 absl::StrCat(ClassName(descriptor_->extension_scope(), false), "::");
78 }
79
80 variables_["scope"] = scope;
81 variables_["scoped_name"] = ExtensionName(descriptor_);
82 variables_["number"] = absl::StrCat(descriptor_->number());
83 }
84
85 ExtensionGenerator::~ExtensionGenerator() = default;
86
IsScoped() const87 bool ExtensionGenerator::IsScoped() const {
88 return descriptor_->extension_scope() != nullptr;
89 }
90
GenerateDeclaration(io::Printer * p) const91 void ExtensionGenerator::GenerateDeclaration(io::Printer* p) const {
92 auto var = p->WithVars(variables_);
93 auto annotate = p->WithAnnotations({{"name", descriptor_}});
94
95 p->Emit({{"qualifier",
96 // If this is a class member, it needs to be declared "static".
97 // Otherwise, it needs to be "extern". In the latter case, it
98 // also needs the DLL export/import specifier.
99 IsScoped() ? "static"
100 : options_.dllexport_decl.empty()
101 ? "extern"
102 : absl::StrCat(options_.dllexport_decl, " extern")}},
103 R"cc(
104 static const int $constant_name$ = $number$;
105 $qualifier$ ::$proto_ns$::internal::ExtensionIdentifier<
106 $extendee$, ::$proto_ns$::internal::$type_traits$, $field_type$,
107 $packed$>
108 $name$;
109 )cc");
110 }
111
GenerateDefinition(io::Printer * p)112 void ExtensionGenerator::GenerateDefinition(io::Printer* p) {
113 auto vars = p->WithVars(variables_);
114 auto generate_default_string = [&] {
115 if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
116 // We need to declare a global string which will contain the default
117 // value. We cannot declare it at class scope because that would require
118 // exposing it in the header which would be annoying for other reasons. So
119 // we replace :: with _ in the name and declare it as a global.
120 return absl::StrReplaceAll(variables_["scoped_name"], {{"::", "_"}}) +
121 "_default";
122 } else if (descriptor_->message_type()) {
123 // We have to initialize the default instance for extensions at
124 // registration time.
125 return absl::StrCat("&", QualifiedDefaultInstanceName(
126 descriptor_->message_type(), options_));
127 } else {
128 return DefaultValue(options_, descriptor_);
129 }
130 };
131
132 auto local_var = p->WithVars({
133 {"default_str", generate_default_string()},
134 {"default_val", DefaultValue(options_, descriptor_)},
135 {"message_type", descriptor_->message_type() != nullptr
136 ? FieldMessageTypeName(descriptor_, options_)
137 : ""},
138 });
139 p->Emit(
140 {
141 {"declare_default_str",
142 [&] {
143 if (descriptor_->cpp_type() != FieldDescriptor::CPPTYPE_STRING)
144 return;
145
146 // If this is a class member, it needs to be declared in its class
147 // scope.
148 p->Emit(R"cc(
149 const std::string $default_str$($default_val$);
150 )cc");
151 }},
152 {"declare_const_var",
153 [&] {
154 if (!IsScoped()) return;
155 // Likewise, class members need to declare the field constant
156 // variable.
157 p->Emit(R"cc(
158 #if !defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)
159 const int $scope$$constant_name$;
160 #endif
161 )cc");
162 }},
163 {"define_extension_id",
164 [&] {
165 p->Emit(R"cc(
166 PROTOBUF_CONSTINIT$ dllexport_decl$
167 PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 ::_pbi::
168 ExtensionIdentifier<$extendee$, ::_pbi::$type_traits$,
169 $field_type$, $packed$>
170 $scoped_name$($constant_name$, $default_str$);
171 )cc");
172 }},
173 },
174 R"cc(
175 $declare_default_str$;
176 $declare_const_var$;
177 $define_extension_id$;
178 )cc");
179 }
180
WillGenerateRegistration(InitPriority priority)181 bool ExtensionGenerator::WillGenerateRegistration(InitPriority priority) {
182 // When not using weak descriptors we initialize everything on priority 102.
183 if (!UsingImplicitWeakDescriptor(descriptor_->file(), options_)) {
184 return priority == kInitPriority102;
185 }
186 return true;
187 }
188
GenerateRegistration(io::Printer * p,InitPriority priority)189 void ExtensionGenerator::GenerateRegistration(io::Printer* p,
190 InitPriority priority) {
191 ABSL_CHECK(WillGenerateRegistration(priority));
192 const bool using_implicit_weak_descriptors =
193 UsingImplicitWeakDescriptor(descriptor_->file(), options_);
194 const auto find_index = [](auto* desc) {
195 const std::vector<const Descriptor*> msgs =
196 FlattenMessagesInFile(desc->file());
197 return absl::c_find(msgs, desc) - msgs.begin();
198 };
199 auto vars = p->WithVars(variables_);
200 auto vars2 = p->WithVars({{
201 {"extendee_table",
202 DescriptorTableName(descriptor_->containing_type()->file(), options_)},
203 {"extendee_index", find_index(descriptor_->containing_type())},
204 {"preregister", priority == kInitPriority101},
205 }});
206 switch (descriptor_->cpp_type()) {
207 case FieldDescriptor::CPPTYPE_ENUM:
208 if (using_implicit_weak_descriptors) {
209 p->Emit({{"enum_name", ClassName(descriptor_->enum_type(), true)}},
210 R"cc(
211 (::_pbi::ExtensionSet::ShouldRegisterAtThisTime(
212 {{&$extendee_table$, $extendee_index$}}, $preregister$)
213 ? ::_pbi::ExtensionSet::RegisterEnumExtension(
214 ::_pbi::GetPrototypeForWeakDescriptor(
215 &$extendee_table$, $extendee_index$, true),
216 $number$, $field_type$, $repeated$, $packed$,
217 $enum_name$_IsValid)
218 : (void)0),
219 )cc");
220 } else if (priority == kInitPriority102) {
221 p->Emit({{"enum_name", ClassName(descriptor_->enum_type(), true)}},
222 R"cc(
223 ::_pbi::ExtensionSet::RegisterEnumExtension(
224 &$extendee$::default_instance(), $number$, $field_type$,
225 $repeated$, $packed$, $enum_name$_IsValid),
226 )cc");
227 }
228
229 break;
230 case FieldDescriptor::CPPTYPE_MESSAGE: {
231 const bool should_verify =
232 // Only verify msgs.
233 descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
234 // Options say to verify.
235 ShouldVerify(descriptor_->message_type(), options_, scc_analyzer_) &&
236 ShouldVerify(descriptor_->containing_type(), options_, scc_analyzer_);
237 const auto message_type = FieldMessageTypeName(descriptor_, options_);
238 auto v = p->WithVars(
239 {{"verify", should_verify
240 ? absl::StrCat("&", message_type, "::InternalVerify")
241 : "nullptr"},
242 {"message_type", message_type},
243 {"lazy", descriptor_->options().has_lazy()
244 ? descriptor_->options().lazy() ? "kLazy" : "kEager"
245 : "kUndefined"}});
246 if (using_implicit_weak_descriptors) {
247 p->Emit(
248 {
249 {"extension_table",
250 DescriptorTableName(descriptor_->message_type()->file(),
251 options_)},
252 {"extension_index", find_index(descriptor_->message_type())},
253 },
254 R"cc(
255 (::_pbi::ExtensionSet::ShouldRegisterAtThisTime(
256 {{&$extendee_table$, $extendee_index$},
257 {&$extension_table$, $extension_index$}},
258 $preregister$)
259 ? ::_pbi::ExtensionSet::RegisterMessageExtension(
260 ::_pbi::GetPrototypeForWeakDescriptor(
261 &$extendee_table$, $extendee_index$, true),
262 $number$, $field_type$, $repeated$, $packed$,
263 ::_pbi::GetPrototypeForWeakDescriptor(
264 &$extension_table$, $extension_index$, true),
265 $verify$, ::_pbi::LazyAnnotation::$lazy$)
266 : (void)0),
267 )cc");
268 } else if (priority == kInitPriority102) {
269 p->Emit(R"cc(
270 ::_pbi::ExtensionSet::RegisterMessageExtension(
271 &$extendee$::default_instance(), $number$, $field_type$,
272 $repeated$, $packed$, &$message_type$::default_instance(),
273 $verify$, ::_pbi::LazyAnnotation::$lazy$),
274 )cc");
275 }
276 break;
277 }
278
279 default:
280 if (using_implicit_weak_descriptors) {
281 p->Emit(R"cc(
282 (::_pbi::ExtensionSet::ShouldRegisterAtThisTime(
283 {{&$extendee_table$, $extendee_index$}}, $preregister$)
284 ? ::_pbi::ExtensionSet::RegisterExtension(
285 ::_pbi::GetPrototypeForWeakDescriptor(&$extendee_table$,
286 $extendee_index$,
287 true),
288 $number$, $field_type$, $repeated$, $packed$)
289 : (void)0),
290 )cc");
291 } else if (priority == kInitPriority102) {
292 p->Emit(
293 R"cc(
294 ::_pbi::ExtensionSet::RegisterExtension(
295 &$extendee$::default_instance(), $number$, $field_type$,
296 $repeated$, $packed$),
297 )cc");
298 }
299
300 break;
301 }
302 }
303
304 } // namespace cpp
305 } // namespace compiler
306 } // namespace protobuf
307 } // namespace google
308