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/file.h> |
36 | |
37 | #include <iostream> |
38 | #include <map> |
39 | #include <memory> |
40 | #include <set> |
41 | #include <unordered_map> |
42 | #include <unordered_set> |
43 | #include <vector> |
44 | |
45 | #include <google/protobuf/compiler/scc.h> |
46 | #include <google/protobuf/io/printer.h> |
47 | #include <google/protobuf/stubs/strutil.h> |
48 | #include <google/protobuf/compiler/cpp/enum.h> |
49 | #include <google/protobuf/compiler/cpp/extension.h> |
50 | #include <google/protobuf/compiler/cpp/field.h> |
51 | #include <google/protobuf/compiler/cpp/helpers.h> |
52 | #include <google/protobuf/compiler/cpp/message.h> |
53 | #include <google/protobuf/compiler/cpp/service.h> |
54 | #include <google/protobuf/descriptor.pb.h> |
55 | |
56 | // Must be last. |
57 | #include <google/protobuf/port_def.inc> |
58 | |
59 | namespace google { |
60 | namespace protobuf { |
61 | namespace compiler { |
62 | namespace cpp { |
63 | |
64 | namespace { |
65 | |
66 | // When we forward-declare things, we want to create a sorted order so our |
67 | // output is deterministic and minimizes namespace changes. |
68 | template <class T> |
69 | std::string GetSortKey(const T& val) { |
70 | return val.full_name(); |
71 | } |
72 | |
73 | template <> |
74 | std::string GetSortKey<FileDescriptor>(const FileDescriptor& val) { |
75 | return val.name(); |
76 | } |
77 | |
78 | template <class T> |
79 | bool CompareSortKeys(const T* a, const T* b) { |
80 | return GetSortKey(*a) < GetSortKey(*b); |
81 | } |
82 | |
83 | template <class T> |
84 | std::vector<const T*> Sorted(const std::unordered_set<const T*>& vals) { |
85 | std::vector<const T*> sorted(vals.begin(), vals.end()); |
86 | std::sort(sorted.begin(), sorted.end(), CompareSortKeys<T>); |
87 | return sorted; |
88 | } |
89 | |
90 | // TODO(b/203101078): remove pragmas that suppresses uninitialized warnings when |
91 | // clang bug is fixed. |
92 | inline void MuteWuninitialized(Formatter& format) { |
93 | format( |
94 | "#if defined(__llvm__)\n" |
95 | " #pragma clang diagnostic push\n" |
96 | " #pragma clang diagnostic ignored \"-Wuninitialized\"\n" |
97 | "#endif // __llvm__\n" ); |
98 | } |
99 | |
100 | inline void UnmuteWuninitialized(Formatter& format) { |
101 | format( |
102 | "#if defined(__llvm__)\n" |
103 | " #pragma clang diagnostic pop\n" |
104 | "#endif // __llvm__\n" ); |
105 | } |
106 | |
107 | } // namespace |
108 | |
109 | FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) |
110 | : file_(file), options_(options), scc_analyzer_(options) { |
111 | // These variables are the same on a file level |
112 | SetCommonVars(options, variables: &variables_); |
113 | variables_["dllexport_decl" ] = options.dllexport_decl; |
114 | variables_["tablename" ] = UniqueName(name: "TableStruct" , d: file_, options: options_); |
115 | variables_["file_level_metadata" ] = |
116 | UniqueName(name: "file_level_metadata" , d: file_, options: options_); |
117 | variables_["desc_table" ] = DescriptorTableName(file: file_, options: options_); |
118 | variables_["file_level_enum_descriptors" ] = |
119 | UniqueName(name: "file_level_enum_descriptors" , d: file_, options: options_); |
120 | variables_["file_level_service_descriptors" ] = |
121 | UniqueName(name: "file_level_service_descriptors" , d: file_, options: options_); |
122 | variables_["filename" ] = file_->name(); |
123 | variables_["package_ns" ] = Namespace(d: file_, options); |
124 | |
125 | std::vector<const Descriptor*> msgs = FlattenMessagesInFile(file); |
126 | for (int i = 0; i < msgs.size(); i++) { |
127 | // Deleted in destructor |
128 | MessageGenerator* msg_gen = |
129 | new MessageGenerator(msgs[i], variables_, i, options, &scc_analyzer_); |
130 | message_generators_.emplace_back(args&: msg_gen); |
131 | msg_gen->AddGenerators(enum_generators: &enum_generators_, extension_generators: &extension_generators_); |
132 | } |
133 | |
134 | for (int i = 0; i < file->enum_type_count(); i++) { |
135 | enum_generators_.emplace_back( |
136 | args: new EnumGenerator(file->enum_type(index: i), variables_, options)); |
137 | } |
138 | |
139 | for (int i = 0; i < file->service_count(); i++) { |
140 | service_generators_.emplace_back( |
141 | args: new ServiceGenerator(file->service(index: i), variables_, options)); |
142 | } |
143 | if (HasGenericServices(file: file_, options: options_)) { |
144 | for (int i = 0; i < service_generators_.size(); i++) { |
145 | service_generators_[i]->index_in_metadata_ = i; |
146 | } |
147 | } |
148 | for (int i = 0; i < file->extension_count(); i++) { |
149 | extension_generators_.emplace_back( |
150 | args: new ExtensionGenerator(file->extension(index: i), options, &scc_analyzer_)); |
151 | } |
152 | for (int i = 0; i < file->weak_dependency_count(); ++i) { |
153 | weak_deps_.insert(x: file->weak_dependency(index: i)); |
154 | } |
155 | } |
156 | |
157 | FileGenerator::~FileGenerator() = default; |
158 | |
159 | void FileGenerator::GenerateMacroUndefs(io::Printer* printer) { |
160 | Formatter format(printer, variables_); |
161 | // Only do this for protobuf's own types. There are some google3 protos using |
162 | // macros as field names and the generated code compiles after the macro |
163 | // expansion. Undefing these macros actually breaks such code. |
164 | if (file_->name() != "net/proto2/compiler/proto/plugin.proto" && |
165 | file_->name() != "google/protobuf/compiler/plugin.proto" ) { |
166 | return; |
167 | } |
168 | std::vector<std::string> names_to_undef; |
169 | std::vector<const FieldDescriptor*> fields; |
170 | ListAllFields(d: file_, fields: &fields); |
171 | for (int i = 0; i < fields.size(); i++) { |
172 | const std::string& name = fields[i]->name(); |
173 | static const char* kMacroNames[] = {"major" , "minor" }; |
174 | for (int j = 0; j < GOOGLE_ARRAYSIZE(kMacroNames); ++j) { |
175 | if (name == kMacroNames[j]) { |
176 | names_to_undef.push_back(x: name); |
177 | break; |
178 | } |
179 | } |
180 | } |
181 | for (int i = 0; i < names_to_undef.size(); ++i) { |
182 | format( |
183 | "#ifdef $1$\n" |
184 | "#undef $1$\n" |
185 | "#endif\n" , |
186 | names_to_undef[i]); |
187 | } |
188 | } |
189 | |
190 | void FileGenerator::(io::Printer* printer) { |
191 | Formatter format(printer, variables_); |
192 | |
193 | // port_def.inc must be included after all other includes. |
194 | IncludeFile(google3_name: "net/proto2/public/port_def.inc" , printer); |
195 | format("#define $1$$ dllexport_decl$\n" , FileDllExport(file: file_, options: options_)); |
196 | GenerateMacroUndefs(printer); |
197 | |
198 | // For Any support with lite protos, we need to friend AnyMetadata, so we |
199 | // forward-declare it here. |
200 | format( |
201 | "PROTOBUF_NAMESPACE_OPEN\n" |
202 | "namespace internal {\n" |
203 | "class AnyMetadata;\n" |
204 | "} // namespace internal\n" |
205 | "PROTOBUF_NAMESPACE_CLOSE\n" ); |
206 | |
207 | GenerateGlobalStateFunctionDeclarations(printer); |
208 | |
209 | GenerateForwardDeclarations(printer); |
210 | |
211 | { |
212 | NamespaceOpener ns(Namespace(d: file_, options: options_), format); |
213 | |
214 | format("\n" ); |
215 | |
216 | GenerateEnumDefinitions(printer); |
217 | |
218 | format(kThickSeparator); |
219 | format("\n" ); |
220 | |
221 | GenerateMessageDefinitions(printer); |
222 | |
223 | format("\n" ); |
224 | format(kThickSeparator); |
225 | format("\n" ); |
226 | |
227 | GenerateServiceDefinitions(printer); |
228 | |
229 | GenerateExtensionIdentifiers(printer); |
230 | |
231 | format("\n" ); |
232 | format(kThickSeparator); |
233 | format("\n" ); |
234 | |
235 | GenerateInlineFunctionDefinitions(printer); |
236 | |
237 | format( |
238 | "\n" |
239 | "// @@protoc_insertion_point(namespace_scope)\n" |
240 | "\n" ); |
241 | } |
242 | |
243 | // We need to specialize some templates in the ::google::protobuf namespace: |
244 | GenerateProto2NamespaceEnumSpecializations(printer); |
245 | |
246 | format( |
247 | "\n" |
248 | "// @@protoc_insertion_point(global_scope)\n" |
249 | "\n" ); |
250 | IncludeFile(google3_name: "net/proto2/public/port_undef.inc" , printer); |
251 | } |
252 | |
253 | void FileGenerator::(io::Printer* printer, |
254 | const std::string& info_path) { |
255 | Formatter format(printer, variables_); |
256 | if (!options_.proto_h) { |
257 | return; |
258 | } |
259 | |
260 | GenerateTopHeaderGuard(printer, pb_h: false); |
261 | |
262 | if (!options_.opensource_runtime) { |
263 | format( |
264 | "#ifdef SWIG\n" |
265 | "#error \"Do not SWIG-wrap protobufs.\"\n" |
266 | "#endif // SWIG\n" |
267 | "\n" ); |
268 | } |
269 | |
270 | if (IsBootstrapProto(options: options_, file: file_)) { |
271 | format("// IWYU pragma: private, include \"$1$.proto.h\"\n\n" , |
272 | StripProto(filename: file_->name())); |
273 | } |
274 | |
275 | GenerateLibraryIncludes(printer); |
276 | |
277 | for (int i = 0; i < file_->public_dependency_count(); i++) { |
278 | const FileDescriptor* dep = file_->public_dependency(index: i); |
279 | format("#include \"$1$.proto.h\"\n" , StripProto(filename: dep->name())); |
280 | } |
281 | |
282 | format("// @@protoc_insertion_point(includes)\n" ); |
283 | |
284 | GenerateMetadataPragma(printer, info_path); |
285 | |
286 | GenerateHeader(printer); |
287 | |
288 | GenerateBottomHeaderGuard(printer, pb_h: false); |
289 | } |
290 | |
291 | void FileGenerator::(io::Printer* printer, |
292 | const std::string& info_path) { |
293 | Formatter format(printer, variables_); |
294 | GenerateTopHeaderGuard(printer, pb_h: true); |
295 | |
296 | if (options_.proto_h) { |
297 | std::string target_basename = StripProto(filename: file_->name()); |
298 | if (!options_.opensource_runtime) { |
299 | GetBootstrapBasename(options: options_, basename: target_basename, bootstrap_basename: &target_basename); |
300 | } |
301 | format("#include \"$1$.proto.h\" // IWYU pragma: export\n" , |
302 | target_basename); |
303 | } else { |
304 | GenerateLibraryIncludes(printer); |
305 | } |
306 | |
307 | if (options_.transitive_pb_h) { |
308 | GenerateDependencyIncludes(printer); |
309 | } |
310 | |
311 | // This is unfortunately necessary for some plugins. I don't see why we |
312 | // need two of the same insertion points. |
313 | // TODO(gerbens) remove this. |
314 | format("// @@protoc_insertion_point(includes)\n" ); |
315 | |
316 | GenerateMetadataPragma(printer, info_path); |
317 | |
318 | if (!options_.proto_h) { |
319 | GenerateHeader(printer); |
320 | } else { |
321 | { |
322 | NamespaceOpener ns(Namespace(d: file_, options: options_), format); |
323 | format( |
324 | "\n" |
325 | "// @@protoc_insertion_point(namespace_scope)\n" ); |
326 | } |
327 | format( |
328 | "\n" |
329 | "// @@protoc_insertion_point(global_scope)\n" |
330 | "\n" ); |
331 | } |
332 | |
333 | GenerateBottomHeaderGuard(printer, pb_h: true); |
334 | } |
335 | |
336 | void FileGenerator::DoIncludeFile(const std::string& google3_name, |
337 | bool do_export, io::Printer* printer) { |
338 | Formatter format(printer, variables_); |
339 | const std::string prefix = "net/proto2/" ; |
340 | GOOGLE_CHECK(google3_name.find(prefix) == 0) << google3_name; |
341 | |
342 | if (options_.opensource_runtime) { |
343 | std::string path = google3_name.substr(pos: prefix.size()); |
344 | |
345 | path = StringReplace(s: path, oldsub: "internal/" , newsub: "" , replace_all: false); |
346 | path = StringReplace(s: path, oldsub: "proto/" , newsub: "" , replace_all: false); |
347 | path = StringReplace(s: path, oldsub: "public/" , newsub: "" , replace_all: false); |
348 | if (options_.runtime_include_base.empty()) { |
349 | format("#include <google/protobuf/$1$>" , path); |
350 | } else { |
351 | format("#include \"$1$google/protobuf/$2$\"" , |
352 | options_.runtime_include_base, path); |
353 | } |
354 | } else { |
355 | std::string path = google3_name; |
356 | // The bootstrapped proto generated code needs to use the |
357 | // third_party/protobuf header paths to avoid circular dependencies. |
358 | if (options_.bootstrap) { |
359 | path = StringReplace(s: google3_name, oldsub: "net/proto2/public" , |
360 | newsub: "third_party/protobuf" , replace_all: false); |
361 | } |
362 | format("#include \"$1$\"" , path); |
363 | } |
364 | |
365 | if (do_export) { |
366 | format(" // IWYU pragma: export" ); |
367 | } |
368 | |
369 | format("\n" ); |
370 | } |
371 | |
372 | std::string FileGenerator::(const std::string& basename, |
373 | const FileDescriptor* file) { |
374 | bool use_system_include = false; |
375 | std::string name = basename; |
376 | |
377 | if (options_.opensource_runtime) { |
378 | if (IsWellKnownMessage(descriptor: file)) { |
379 | if (options_.runtime_include_base.empty()) { |
380 | use_system_include = true; |
381 | } else { |
382 | name = options_.runtime_include_base + basename; |
383 | } |
384 | } |
385 | } |
386 | |
387 | std::string left = "\"" ; |
388 | std::string right = "\"" ; |
389 | if (use_system_include) { |
390 | left = "<" ; |
391 | right = ">" ; |
392 | } |
393 | return left + name + right; |
394 | } |
395 | |
396 | void FileGenerator::GenerateSourceIncludes(io::Printer* printer) { |
397 | Formatter format(printer, variables_); |
398 | std::string target_basename = StripProto(filename: file_->name()); |
399 | if (!options_.opensource_runtime) { |
400 | GetBootstrapBasename(options: options_, basename: target_basename, bootstrap_basename: &target_basename); |
401 | } |
402 | target_basename += options_.proto_h ? ".proto.h" : ".pb.h" ; |
403 | format( |
404 | "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" |
405 | "// source: $filename$\n" |
406 | "\n" |
407 | "#include $1$\n" |
408 | "\n" |
409 | "#include <algorithm>\n" // for swap() |
410 | "\n" , |
411 | CreateHeaderInclude(basename: target_basename, file: file_)); |
412 | |
413 | IncludeFile(google3_name: "net/proto2/io/public/coded_stream.h" , printer); |
414 | // TODO(gerbens) This is to include parse_context.h, we need a better way |
415 | IncludeFile(google3_name: "net/proto2/public/extension_set.h" , printer); |
416 | IncludeFile(google3_name: "net/proto2/public/wire_format_lite.h" , printer); |
417 | |
418 | // Unknown fields implementation in lite mode uses StringOutputStream |
419 | if (!UseUnknownFieldSet(file: file_, options: options_) && !message_generators_.empty()) { |
420 | IncludeFile(google3_name: "net/proto2/io/public/zero_copy_stream_impl_lite.h" , printer); |
421 | } |
422 | |
423 | if (HasDescriptorMethods(file: file_, options: options_)) { |
424 | IncludeFile(google3_name: "net/proto2/public/descriptor.h" , printer); |
425 | IncludeFile(google3_name: "net/proto2/public/generated_message_reflection.h" , printer); |
426 | IncludeFile(google3_name: "net/proto2/public/reflection_ops.h" , printer); |
427 | IncludeFile(google3_name: "net/proto2/public/wire_format.h" , printer); |
428 | } |
429 | |
430 | if (HasGeneratedMethods(file: file_, options: options_) && |
431 | options_.tctable_mode != Options::kTCTableNever) { |
432 | IncludeFile(google3_name: "net/proto2/public/generated_message_tctable_impl.h" , printer); |
433 | } |
434 | |
435 | if (options_.proto_h) { |
436 | // Use the smaller .proto.h files. |
437 | for (int i = 0; i < file_->dependency_count(); i++) { |
438 | const FileDescriptor* dep = file_->dependency(index: i); |
439 | // Do not import weak deps. |
440 | if (!options_.opensource_runtime && IsDepWeak(dep)) continue; |
441 | std::string basename = StripProto(filename: dep->name()); |
442 | if (IsBootstrapProto(options: options_, file: file_)) { |
443 | GetBootstrapBasename(options: options_, basename, bootstrap_basename: &basename); |
444 | } |
445 | format("#include \"$1$.proto.h\"\n" , basename); |
446 | } |
447 | } |
448 | if (HasCordFields(file: file_, options: options_)) { |
449 | format( |
450 | "#include \"third_party/absl/strings/internal/string_constant.h\"\n" ); |
451 | } |
452 | |
453 | format("// @@protoc_insertion_point(includes)\n" ); |
454 | IncludeFile(google3_name: "net/proto2/public/port_def.inc" , printer); |
455 | } |
456 | |
457 | void FileGenerator::GenerateSourcePrelude(io::Printer* printer) { |
458 | Formatter format(printer, variables_); |
459 | |
460 | // For MSVC builds, we use #pragma init_seg to move the initialization of our |
461 | // libraries to happen before the user code. |
462 | // This worksaround the fact that MSVC does not do constant initializers when |
463 | // required by the standard. |
464 | format("\nPROTOBUF_PRAGMA_INIT_SEG\n" ); |
465 | |
466 | // Generate convenience aliases. |
467 | format( |
468 | "\n" |
469 | "namespace _pb = ::$1$;\n" |
470 | "namespace _pbi = _pb::internal;\n" , |
471 | ProtobufNamespace(options_)); |
472 | if (HasGeneratedMethods(file: file_, options: options_) && |
473 | options_.tctable_mode != Options::kTCTableNever) { |
474 | format("namespace _fl = _pbi::field_layout;\n" ); |
475 | } |
476 | format("\n" ); |
477 | } |
478 | |
479 | void FileGenerator::GenerateSourceDefaultInstance(int idx, |
480 | io::Printer* printer) { |
481 | Formatter format(printer, variables_); |
482 | MessageGenerator* generator = message_generators_[idx].get(); |
483 | // Generate the split instance first because it's needed in the constexpr |
484 | // constructor. |
485 | if (ShouldSplit(desc: generator->descriptor_, options: options_)) { |
486 | // Use a union to disable the destructor of the _instance member. |
487 | // We can constant initialize, but the object will still have a non-trivial |
488 | // destructor that we need to elide. |
489 | format( |
490 | "struct $1$ {\n" |
491 | " PROTOBUF_CONSTEXPR $1$()\n" |
492 | " : _instance{" , |
493 | DefaultInstanceType(descriptor: generator->descriptor_, options: options_, |
494 | /*split=*/true)); |
495 | generator->GenerateInitDefaultSplitInstance(printer); |
496 | format( |
497 | "} {}\n" |
498 | " ~$1$() {}\n" |
499 | " union {\n" |
500 | " $2$ _instance;\n" |
501 | " };\n" |
502 | "};\n" , |
503 | DefaultInstanceType(descriptor: generator->descriptor_, options: options_, /*split=*/true), |
504 | StrCat(a: generator->classname_, b: "::Impl_::Split" )); |
505 | // NO_DESTROY is not necessary for correctness. The empty destructor is |
506 | // enough. However, the empty destructor fails to be elided in some |
507 | // configurations (like non-opt or with certain sanitizers). NO_DESTROY is |
508 | // there just to improve performance and binary size in these builds. |
509 | format( |
510 | "PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT " |
511 | "PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $1$ $2$;\n" , |
512 | DefaultInstanceType(descriptor: generator->descriptor_, options: options_, /*split=*/true), |
513 | DefaultInstanceName(descriptor: generator->descriptor_, options: options_, /*split=*/true)); |
514 | } |
515 | |
516 | generator->GenerateConstexprConstructor(printer); |
517 | format( |
518 | "struct $1$ {\n" |
519 | " PROTOBUF_CONSTEXPR $1$()\n" |
520 | " : _instance(::_pbi::ConstantInitialized{}) {}\n" |
521 | " ~$1$() {}\n" |
522 | " union {\n" |
523 | " $2$ _instance;\n" |
524 | " };\n" |
525 | "};\n" , |
526 | DefaultInstanceType(descriptor: generator->descriptor_, options: options_), |
527 | generator->classname_); |
528 | format( |
529 | "PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT " |
530 | "PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $1$ $2$;\n" , |
531 | DefaultInstanceType(descriptor: generator->descriptor_, options: options_), |
532 | DefaultInstanceName(descriptor: generator->descriptor_, options: options_)); |
533 | |
534 | for (int i = 0; i < generator->descriptor_->field_count(); i++) { |
535 | const FieldDescriptor* field = generator->descriptor_->field(index: i); |
536 | if (IsStringInlined(descriptor: field, options: options_)) { |
537 | // Force the initialization of the inlined string in the default instance. |
538 | format( |
539 | "PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 std::true_type " |
540 | "$1$::Impl_::_init_inline_$2$_ = " |
541 | "($3$._instance.$4$.Init(), std::true_type{});\n" , |
542 | ClassName(descriptor: generator->descriptor_), FieldName(field), |
543 | DefaultInstanceName(descriptor: generator->descriptor_, options: options_), |
544 | FieldMemberName(field, split: ShouldSplit(field, options: options_))); |
545 | } |
546 | } |
547 | |
548 | if (options_.lite_implicit_weak_fields) { |
549 | format( |
550 | "PROTOBUF_CONSTINIT const void* $1$ =\n" |
551 | " &$2$;\n" , |
552 | DefaultInstancePtr(descriptor: generator->descriptor_, options: options_), |
553 | DefaultInstanceName(descriptor: generator->descriptor_, options: options_)); |
554 | } |
555 | } |
556 | |
557 | // A list of things defined in one .pb.cc file that we need to reference from |
558 | // another .pb.cc file. |
559 | struct FileGenerator::CrossFileReferences { |
560 | // Populated if we are referencing from messages or files. |
561 | std::unordered_set<const Descriptor*> weak_default_instances; |
562 | |
563 | // Only if we are referencing from files. |
564 | std::unordered_set<const FileDescriptor*> strong_reflection_files; |
565 | std::unordered_set<const FileDescriptor*> weak_reflection_files; |
566 | }; |
567 | |
568 | void FileGenerator::GetCrossFileReferencesForField(const FieldDescriptor* field, |
569 | CrossFileReferences* refs) { |
570 | const Descriptor* msg = field->message_type(); |
571 | if (msg == nullptr) return; |
572 | |
573 | if (IsImplicitWeakField(field, options: options_, scc_analyzer: &scc_analyzer_) || |
574 | IsWeak(field, options: options_)) { |
575 | refs->weak_default_instances.insert(x: msg); |
576 | } |
577 | } |
578 | |
579 | void FileGenerator::GetCrossFileReferencesForFile(const FileDescriptor* file, |
580 | CrossFileReferences* refs) { |
581 | ForEachField(d: file, func: [this, refs](const FieldDescriptor* field) { |
582 | GetCrossFileReferencesForField(field, refs); |
583 | }); |
584 | |
585 | if (!HasDescriptorMethods(file, options: options_)) return; |
586 | |
587 | for (int i = 0; i < file->dependency_count(); i++) { |
588 | const FileDescriptor* dep = file->dependency(index: i); |
589 | if (IsDepWeak(dep)) { |
590 | refs->weak_reflection_files.insert(x: dep); |
591 | } else { |
592 | refs->strong_reflection_files.insert(x: dep); |
593 | } |
594 | } |
595 | } |
596 | |
597 | // Generates references to variables defined in other files. |
598 | void FileGenerator::GenerateInternalForwardDeclarations( |
599 | const CrossFileReferences& refs, io::Printer* printer) { |
600 | Formatter format(printer, variables_); |
601 | |
602 | { |
603 | NamespaceOpener ns(format); |
604 | for (auto instance : Sorted(vals: refs.weak_default_instances)) { |
605 | ns.ChangeTo(name: Namespace(d: instance, options: options_)); |
606 | if (options_.lite_implicit_weak_fields) { |
607 | format( |
608 | "PROTOBUF_CONSTINIT __attribute__((weak)) const void* $1$ =\n" |
609 | " &::_pbi::implicit_weak_message_default_instance;\n" , |
610 | DefaultInstancePtr(descriptor: instance, options: options_)); |
611 | } else { |
612 | format("extern __attribute__((weak)) $1$ $2$;\n" , |
613 | DefaultInstanceType(descriptor: instance, options: options_), |
614 | DefaultInstanceName(descriptor: instance, options: options_)); |
615 | } |
616 | } |
617 | } |
618 | |
619 | for (auto file : Sorted(vals: refs.weak_reflection_files)) { |
620 | format( |
621 | "extern __attribute__((weak)) const ::_pbi::DescriptorTable $1$;\n" , |
622 | DescriptorTableName(file, options: options_)); |
623 | } |
624 | } |
625 | |
626 | void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) { |
627 | Formatter format(printer, variables_); |
628 | GenerateSourceIncludes(printer); |
629 | GenerateSourcePrelude(printer); |
630 | |
631 | if (IsAnyMessage(descriptor: file_, options: options_)) MuteWuninitialized(format); |
632 | |
633 | CrossFileReferences refs; |
634 | ForEachField(d: message_generators_[idx]->descriptor_, |
635 | func: [this, &refs](const FieldDescriptor* field) { |
636 | GetCrossFileReferencesForField(field, refs: &refs); |
637 | }); |
638 | GenerateInternalForwardDeclarations(refs, printer); |
639 | |
640 | { // package namespace |
641 | NamespaceOpener ns(Namespace(d: file_, options: options_), format); |
642 | |
643 | // Define default instances |
644 | GenerateSourceDefaultInstance(idx, printer); |
645 | |
646 | // Generate classes. |
647 | format("\n" ); |
648 | message_generators_[idx]->GenerateClassMethods(printer); |
649 | |
650 | format( |
651 | "\n" |
652 | "// @@protoc_insertion_point(namespace_scope)\n" ); |
653 | } // end package namespace |
654 | |
655 | { |
656 | NamespaceOpener proto_ns(ProtobufNamespace(options_), format); |
657 | message_generators_[idx]->GenerateSourceInProto2Namespace(printer); |
658 | } |
659 | |
660 | if (IsAnyMessage(descriptor: file_, options: options_)) UnmuteWuninitialized(format); |
661 | |
662 | format( |
663 | "\n" |
664 | "// @@protoc_insertion_point(global_scope)\n" ); |
665 | } |
666 | |
667 | void FileGenerator::GenerateSourceForExtension(int idx, io::Printer* printer) { |
668 | Formatter format(printer, variables_); |
669 | GenerateSourceIncludes(printer); |
670 | GenerateSourcePrelude(printer); |
671 | NamespaceOpener ns(Namespace(d: file_, options: options_), format); |
672 | extension_generators_[idx]->GenerateDefinition(printer); |
673 | } |
674 | |
675 | void FileGenerator::GenerateGlobalSource(io::Printer* printer) { |
676 | Formatter format(printer, variables_); |
677 | GenerateSourceIncludes(printer); |
678 | GenerateSourcePrelude(printer); |
679 | |
680 | { |
681 | // Define the code to initialize reflection. This code uses a global |
682 | // constructor to register reflection data with the runtime pre-main. |
683 | if (HasDescriptorMethods(file: file_, options: options_)) { |
684 | GenerateReflectionInitializationCode(printer); |
685 | } |
686 | } |
687 | |
688 | NamespaceOpener ns(Namespace(d: file_, options: options_), format); |
689 | |
690 | // Generate enums. |
691 | for (int i = 0; i < enum_generators_.size(); i++) { |
692 | enum_generators_[i]->GenerateMethods(idx: i, printer); |
693 | } |
694 | } |
695 | |
696 | void FileGenerator::GenerateSource(io::Printer* printer) { |
697 | Formatter format(printer, variables_); |
698 | GenerateSourceIncludes(printer); |
699 | GenerateSourcePrelude(printer); |
700 | CrossFileReferences refs; |
701 | GetCrossFileReferencesForFile(file: file_, refs: &refs); |
702 | GenerateInternalForwardDeclarations(refs, printer); |
703 | |
704 | if (IsAnyMessage(descriptor: file_, options: options_)) MuteWuninitialized(format); |
705 | |
706 | { |
707 | NamespaceOpener ns(Namespace(d: file_, options: options_), format); |
708 | |
709 | // Define default instances |
710 | for (int i = 0; i < message_generators_.size(); i++) { |
711 | GenerateSourceDefaultInstance(idx: i, printer); |
712 | } |
713 | } |
714 | |
715 | { |
716 | if (HasDescriptorMethods(file: file_, options: options_)) { |
717 | // Define the code to initialize reflection. This code uses a global |
718 | // constructor to register reflection data with the runtime pre-main. |
719 | GenerateReflectionInitializationCode(printer); |
720 | } |
721 | } |
722 | |
723 | { |
724 | NamespaceOpener ns(Namespace(d: file_, options: options_), format); |
725 | |
726 | // Actually implement the protos |
727 | |
728 | // Generate enums. |
729 | for (int i = 0; i < enum_generators_.size(); i++) { |
730 | enum_generators_[i]->GenerateMethods(idx: i, printer); |
731 | } |
732 | |
733 | // Generate classes. |
734 | for (int i = 0; i < message_generators_.size(); i++) { |
735 | format("\n" ); |
736 | format(kThickSeparator); |
737 | format("\n" ); |
738 | message_generators_[i]->GenerateClassMethods(printer); |
739 | } |
740 | |
741 | if (HasGenericServices(file: file_, options: options_)) { |
742 | // Generate services. |
743 | for (int i = 0; i < service_generators_.size(); i++) { |
744 | if (i == 0) format("\n" ); |
745 | format(kThickSeparator); |
746 | format("\n" ); |
747 | service_generators_[i]->GenerateImplementation(printer); |
748 | } |
749 | } |
750 | |
751 | // Define extensions. |
752 | for (int i = 0; i < extension_generators_.size(); i++) { |
753 | extension_generators_[i]->GenerateDefinition(printer); |
754 | } |
755 | |
756 | format( |
757 | "\n" |
758 | "// @@protoc_insertion_point(namespace_scope)\n" ); |
759 | } |
760 | |
761 | { |
762 | NamespaceOpener proto_ns(ProtobufNamespace(options_), format); |
763 | for (int i = 0; i < message_generators_.size(); i++) { |
764 | message_generators_[i]->GenerateSourceInProto2Namespace(printer); |
765 | } |
766 | } |
767 | |
768 | format( |
769 | "\n" |
770 | "// @@protoc_insertion_point(global_scope)\n" ); |
771 | |
772 | if (IsAnyMessage(descriptor: file_, options: options_)) UnmuteWuninitialized(format); |
773 | |
774 | IncludeFile(google3_name: "net/proto2/public/port_undef.inc" , printer); |
775 | } |
776 | |
777 | void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { |
778 | Formatter format(printer, variables_); |
779 | |
780 | if (!message_generators_.empty()) { |
781 | format("static ::_pb::Metadata $file_level_metadata$[$1$];\n" , |
782 | message_generators_.size()); |
783 | } |
784 | if (!enum_generators_.empty()) { |
785 | format( |
786 | "static const ::_pb::EnumDescriptor* " |
787 | "$file_level_enum_descriptors$[$1$];\n" , |
788 | enum_generators_.size()); |
789 | } else { |
790 | format( |
791 | "static " |
792 | "constexpr ::_pb::EnumDescriptor const** " |
793 | "$file_level_enum_descriptors$ = nullptr;\n" ); |
794 | } |
795 | if (HasGenericServices(file: file_, options: options_) && file_->service_count() > 0) { |
796 | format( |
797 | "static " |
798 | "const ::_pb::ServiceDescriptor* " |
799 | "$file_level_service_descriptors$[$1$];\n" , |
800 | file_->service_count()); |
801 | } else { |
802 | format( |
803 | "static " |
804 | "constexpr ::_pb::ServiceDescriptor const** " |
805 | "$file_level_service_descriptors$ = nullptr;\n" ); |
806 | } |
807 | |
808 | if (!message_generators_.empty()) { |
809 | format( |
810 | "\n" |
811 | "const $uint32$ $tablename$::offsets[] " |
812 | "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n" ); |
813 | format.Indent(); |
814 | std::vector<std::pair<size_t, size_t> > pairs; |
815 | pairs.reserve(n: message_generators_.size()); |
816 | for (int i = 0; i < message_generators_.size(); i++) { |
817 | pairs.push_back(x: message_generators_[i]->GenerateOffsets(printer)); |
818 | } |
819 | format.Outdent(); |
820 | format( |
821 | "};\n" |
822 | "static const ::_pbi::MigrationSchema schemas[] " |
823 | "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n" ); |
824 | format.Indent(); |
825 | { |
826 | int offset = 0; |
827 | for (int i = 0; i < message_generators_.size(); i++) { |
828 | message_generators_[i]->GenerateSchema(printer, offset, |
829 | has_offset: pairs[i].second); |
830 | offset += pairs[i].first; |
831 | } |
832 | } |
833 | format.Outdent(); |
834 | format( |
835 | "};\n" |
836 | "\nstatic const ::_pb::Message* const file_default_instances[] = {\n" ); |
837 | format.Indent(); |
838 | for (int i = 0; i < message_generators_.size(); i++) { |
839 | const Descriptor* descriptor = message_generators_[i]->descriptor_; |
840 | format("&$1$::_$2$_default_instance_._instance,\n" , |
841 | Namespace(d: descriptor, options: options_), // 1 |
842 | ClassName(descriptor)); // 2 |
843 | } |
844 | format.Outdent(); |
845 | format( |
846 | "};\n" |
847 | "\n" ); |
848 | } else { |
849 | // we still need these symbols to exist |
850 | format( |
851 | // MSVC doesn't like empty arrays, so we add a dummy. |
852 | "const $uint32$ $tablename$::offsets[1] = {};\n" |
853 | "static constexpr ::_pbi::MigrationSchema* schemas = nullptr;\n" |
854 | "static constexpr ::_pb::Message* const* " |
855 | "file_default_instances = nullptr;\n" |
856 | "\n" ); |
857 | } |
858 | |
859 | // --------------------------------------------------------------- |
860 | |
861 | // Embed the descriptor. We simply serialize the entire |
862 | // FileDescriptorProto/ and embed it as a string literal, which is parsed and |
863 | // built into real descriptors at initialization time. |
864 | const std::string protodef_name = |
865 | UniqueName(name: "descriptor_table_protodef" , d: file_, options: options_); |
866 | format("const char $1$[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =\n" , |
867 | protodef_name); |
868 | format.Indent(); |
869 | FileDescriptorProto file_proto; |
870 | file_->CopyTo(proto: &file_proto); |
871 | std::string file_data; |
872 | file_proto.SerializeToString(output: &file_data); |
873 | |
874 | { |
875 | if (file_data.size() > 65535) { |
876 | // Workaround for MSVC: "Error C1091: compiler limit: string exceeds |
877 | // 65535 bytes in length". Declare a static array of chars rather than |
878 | // use a string literal. Only write 25 bytes per line. |
879 | static const int kBytesPerLine = 25; |
880 | format("{ " ); |
881 | for (int i = 0; i < file_data.size();) { |
882 | for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) { |
883 | format("'$1$', " , CEscape(src: file_data.substr(pos: i, n: 1))); |
884 | } |
885 | format("\n" ); |
886 | } |
887 | format("'\\0' }" ); // null-terminate |
888 | } else { |
889 | // Only write 40 bytes per line. |
890 | static const int kBytesPerLine = 40; |
891 | for (int i = 0; i < file_data.size(); i += kBytesPerLine) { |
892 | format( |
893 | "\"$1$\"\n" , |
894 | EscapeTrigraphs(to_escape: CEscape(src: file_data.substr(pos: i, n: kBytesPerLine)))); |
895 | } |
896 | } |
897 | format(";\n" ); |
898 | } |
899 | format.Outdent(); |
900 | |
901 | CrossFileReferences refs; |
902 | GetCrossFileReferencesForFile(file: file_, refs: &refs); |
903 | int num_deps = |
904 | refs.strong_reflection_files.size() + refs.weak_reflection_files.size(); |
905 | |
906 | // Build array of DescriptorTable deps. |
907 | if (num_deps > 0) { |
908 | format( |
909 | "static const ::_pbi::DescriptorTable* const " |
910 | "$desc_table$_deps[$1$] = {\n" , |
911 | num_deps); |
912 | |
913 | for (auto dep : Sorted(vals: refs.strong_reflection_files)) { |
914 | format(" &::$1$,\n" , DescriptorTableName(file: dep, options: options_)); |
915 | } |
916 | for (auto dep : Sorted(vals: refs.weak_reflection_files)) { |
917 | format(" &::$1$,\n" , DescriptorTableName(file: dep, options: options_)); |
918 | } |
919 | |
920 | format("};\n" ); |
921 | } |
922 | |
923 | // The DescriptorTable itself. |
924 | // Should be "bool eager = NeedsEagerDescriptorAssignment(file_, options_);" |
925 | // however this might cause a tsan failure in superroot b/148382879, |
926 | // so disable for now. |
927 | bool eager = false; |
928 | format( |
929 | "static ::_pbi::once_flag $desc_table$_once;\n" |
930 | "const ::_pbi::DescriptorTable $desc_table$ = {\n" |
931 | " false, $1$, $2$, $3$,\n" |
932 | " \"$filename$\",\n" |
933 | " &$desc_table$_once, $4$, $5$, $6$,\n" |
934 | " schemas, file_default_instances, $tablename$::offsets,\n" |
935 | " $7$, $file_level_enum_descriptors$,\n" |
936 | " $file_level_service_descriptors$,\n" |
937 | "};\n" |
938 | // This function exists to be marked as weak. |
939 | // It can significantly speed up compilation by breaking up LLVM's SCC in |
940 | // the .pb.cc translation units. Large translation units see a reduction |
941 | // of more than 35% of walltime for optimized builds. |
942 | // Without the weak attribute all the messages in the file, including all |
943 | // the vtables and everything they use become part of the same SCC through |
944 | // a cycle like: |
945 | // GetMetadata -> descriptor table -> default instances -> |
946 | // vtables -> GetMetadata |
947 | // By adding a weak function here we break the connection from the |
948 | // individual vtables back into the descriptor table. |
949 | "PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* " |
950 | "$desc_table$_getter() {\n" |
951 | " return &$desc_table$;\n" |
952 | "}\n" |
953 | "\n" , |
954 | eager ? "true" : "false" , file_data.size(), protodef_name, |
955 | num_deps == 0 ? "nullptr" : variables_["desc_table" ] + "_deps" , num_deps, |
956 | message_generators_.size(), |
957 | message_generators_.empty() ? "nullptr" |
958 | : variables_["file_level_metadata" ]); |
959 | |
960 | // For descriptor.proto we want to avoid doing any dynamic initialization, |
961 | // because in some situations that would otherwise pull in a lot of |
962 | // unnecessary code that can't be stripped by --gc-sections. Descriptor |
963 | // initialization will still be performed lazily when it's needed. |
964 | if (file_->name() != "net/proto2/proto/descriptor.proto" ) { |
965 | format( |
966 | "// Force running AddDescriptors() at dynamic initialization time.\n" |
967 | "PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 " |
968 | "static ::_pbi::AddDescriptorsRunner $1$(&$desc_table$);\n" , |
969 | UniqueName(name: "dynamic_init_dummy" , d: file_, options: options_)); |
970 | } |
971 | } |
972 | |
973 | class FileGenerator::ForwardDeclarations { |
974 | public: |
975 | void AddMessage(const Descriptor* d) { classes_[ClassName(descriptor: d)] = d; } |
976 | void AddEnum(const EnumDescriptor* d) { enums_[ClassName(enum_descriptor: d)] = d; } |
977 | void AddSplit(const Descriptor* d) { splits_[ClassName(descriptor: d)] = d; } |
978 | |
979 | void Print(const Formatter& format, const Options& options) const { |
980 | for (const auto& p : enums_) { |
981 | const std::string& enumname = p.first; |
982 | const EnumDescriptor* enum_desc = p.second; |
983 | format( |
984 | "enum ${1$$2$$}$ : int;\n" |
985 | "bool $2$_IsValid(int value);\n" , |
986 | enum_desc, enumname); |
987 | } |
988 | for (const auto& p : classes_) { |
989 | const std::string& classname = p.first; |
990 | const Descriptor* class_desc = p.second; |
991 | format( |
992 | "class ${1$$2$$}$;\n" |
993 | "struct $3$;\n" |
994 | "$dllexport_decl $extern $3$ $4$;\n" , |
995 | class_desc, classname, DefaultInstanceType(descriptor: class_desc, options), |
996 | DefaultInstanceName(descriptor: class_desc, options)); |
997 | } |
998 | for (const auto& p : splits_) { |
999 | const Descriptor* class_desc = p.second; |
1000 | format( |
1001 | "struct $1$;\n" |
1002 | "$dllexport_decl $extern $1$ $2$;\n" , |
1003 | DefaultInstanceType(descriptor: class_desc, options, /*split=*/true), |
1004 | DefaultInstanceName(descriptor: class_desc, options, /*split=*/true)); |
1005 | } |
1006 | } |
1007 | |
1008 | void PrintTopLevelDecl(const Formatter& format, |
1009 | const Options& options) const { |
1010 | for (const auto& pair : classes_) { |
1011 | format( |
1012 | "template<> $dllexport_decl $" |
1013 | "$1$* Arena::CreateMaybeMessage<$1$>(Arena*);\n" , |
1014 | QualifiedClassName(d: pair.second, options)); |
1015 | } |
1016 | } |
1017 | |
1018 | private: |
1019 | std::map<std::string, const Descriptor*> classes_; |
1020 | std::map<std::string, const EnumDescriptor*> enums_; |
1021 | std::map<std::string, const Descriptor*> splits_; |
1022 | }; |
1023 | |
1024 | static void PublicImportDFS(const FileDescriptor* fd, |
1025 | std::unordered_set<const FileDescriptor*>* fd_set) { |
1026 | for (int i = 0; i < fd->public_dependency_count(); i++) { |
1027 | const FileDescriptor* dep = fd->public_dependency(index: i); |
1028 | if (fd_set->insert(x: dep).second) PublicImportDFS(fd: dep, fd_set); |
1029 | } |
1030 | } |
1031 | |
1032 | void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) { |
1033 | Formatter format(printer, variables_); |
1034 | std::vector<const Descriptor*> classes; |
1035 | std::vector<const EnumDescriptor*> enums; |
1036 | |
1037 | FlattenMessagesInFile(file: file_, result: &classes); // All messages need forward decls. |
1038 | |
1039 | if (options_.proto_h) { // proto.h needs extra forward declarations. |
1040 | // All classes / enums referred to as field members |
1041 | std::vector<const FieldDescriptor*> fields; |
1042 | ListAllFields(d: file_, fields: &fields); |
1043 | for (int i = 0; i < fields.size(); i++) { |
1044 | classes.push_back(x: fields[i]->containing_type()); |
1045 | classes.push_back(x: fields[i]->message_type()); |
1046 | enums.push_back(x: fields[i]->enum_type()); |
1047 | } |
1048 | ListAllTypesForServices(fd: file_, types: &classes); |
1049 | } |
1050 | |
1051 | // Calculate the set of files whose definitions we get through include. |
1052 | // No need to forward declare types that are defined in these. |
1053 | std::unordered_set<const FileDescriptor*> public_set; |
1054 | PublicImportDFS(fd: file_, fd_set: &public_set); |
1055 | |
1056 | std::map<std::string, ForwardDeclarations> decls; |
1057 | for (int i = 0; i < classes.size(); i++) { |
1058 | const Descriptor* d = classes[i]; |
1059 | if (d && !public_set.count(x: d->file())) |
1060 | decls[Namespace(d, options: options_)].AddMessage(d); |
1061 | } |
1062 | for (int i = 0; i < enums.size(); i++) { |
1063 | const EnumDescriptor* d = enums[i]; |
1064 | if (d && !public_set.count(x: d->file())) |
1065 | decls[Namespace(d, options: options_)].AddEnum(d); |
1066 | } |
1067 | for (const auto& mg : message_generators_) { |
1068 | const Descriptor* d = mg->descriptor_; |
1069 | if ((d != nullptr) && (public_set.count(x: d->file()) == 0u) && |
1070 | ShouldSplit(desc: mg->descriptor_, options: options_)) |
1071 | decls[Namespace(d, options: options_)].AddSplit(d); |
1072 | } |
1073 | |
1074 | { |
1075 | NamespaceOpener ns(format); |
1076 | for (const auto& pair : decls) { |
1077 | ns.ChangeTo(name: pair.first); |
1078 | pair.second.Print(format, options: options_); |
1079 | } |
1080 | } |
1081 | format("PROTOBUF_NAMESPACE_OPEN\n" ); |
1082 | for (const auto& pair : decls) { |
1083 | pair.second.PrintTopLevelDecl(format, options: options_); |
1084 | } |
1085 | format("PROTOBUF_NAMESPACE_CLOSE\n" ); |
1086 | } |
1087 | |
1088 | void FileGenerator::(io::Printer* printer, bool pb_h) { |
1089 | Formatter format(printer, variables_); |
1090 | // Generate top of header. |
1091 | format( |
1092 | "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" |
1093 | "// source: $filename$\n" |
1094 | "\n" |
1095 | "#ifndef $1$\n" |
1096 | "#define $1$\n" |
1097 | "\n" |
1098 | "#include <limits>\n" |
1099 | "#include <string>\n" , |
1100 | IncludeGuard(file: file_, pb_h, options: options_)); |
1101 | if (!options_.opensource_runtime && !enum_generators_.empty()) { |
1102 | // Add header to provide std::is_integral for safe Enum_Name() function. |
1103 | format("#include <type_traits>\n" ); |
1104 | } |
1105 | format("\n" ); |
1106 | } |
1107 | |
1108 | void FileGenerator::(io::Printer* printer, bool pb_h) { |
1109 | Formatter format(printer, variables_); |
1110 | format("#endif // $GOOGLE_PROTOBUF$_INCLUDED_$1$\n" , |
1111 | IncludeGuard(file: file_, pb_h, options: options_)); |
1112 | } |
1113 | |
1114 | void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { |
1115 | Formatter format(printer, variables_); |
1116 | if (UsingImplicitWeakFields(file: file_, options: options_)) { |
1117 | IncludeFile(google3_name: "net/proto2/public/implicit_weak_message.h" , printer); |
1118 | } |
1119 | if (HasWeakFields(desc: file_, options: options_)) { |
1120 | GOOGLE_CHECK(!options_.opensource_runtime); |
1121 | IncludeFile(google3_name: "net/proto2/public/weak_field_map.h" , printer); |
1122 | } |
1123 | if (HasLazyFields(file: file_, options: options_, scc_analyzer: &scc_analyzer_)) { |
1124 | GOOGLE_CHECK(!options_.opensource_runtime); |
1125 | IncludeFile(google3_name: "net/proto2/public/lazy_field.h" , printer); |
1126 | } |
1127 | if (ShouldVerify(file: file_, options: options_, scc_analyzer: &scc_analyzer_)) { |
1128 | IncludeFile(google3_name: "net/proto2/public/wire_format_verify.h" , printer); |
1129 | } |
1130 | |
1131 | if (options_.opensource_runtime) { |
1132 | // Verify the protobuf library header version is compatible with the protoc |
1133 | // version before going any further. |
1134 | IncludeFile(google3_name: "net/proto2/public/port_def.inc" , printer); |
1135 | format( |
1136 | "#if PROTOBUF_VERSION < $1$\n" |
1137 | "#error This file was generated by a newer version of protoc which is\n" |
1138 | "#error incompatible with your Protocol Buffer headers. Please update\n" |
1139 | "#error your headers.\n" |
1140 | "#endif\n" |
1141 | "#if $2$ < PROTOBUF_MIN_PROTOC_VERSION\n" |
1142 | "#error This file was generated by an older version of protoc which " |
1143 | "is\n" |
1144 | "#error incompatible with your Protocol Buffer headers. Please\n" |
1145 | "#error regenerate this file with a newer version of protoc.\n" |
1146 | "#endif\n" |
1147 | "\n" , |
1148 | PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC, // 1 |
1149 | PROTOBUF_VERSION); // 2 |
1150 | IncludeFile(google3_name: "net/proto2/public/port_undef.inc" , printer); |
1151 | } |
1152 | |
1153 | // OK, it's now safe to #include other files. |
1154 | IncludeFile(google3_name: "net/proto2/io/public/coded_stream.h" , printer); |
1155 | IncludeFile(google3_name: "net/proto2/public/arena.h" , printer); |
1156 | IncludeFile(google3_name: "net/proto2/public/arenastring.h" , printer); |
1157 | if ((options_.force_inline_string || options_.profile_driven_inline_string) && |
1158 | !options_.opensource_runtime) { |
1159 | IncludeFile(google3_name: "net/proto2/public/inlined_string_field.h" , printer); |
1160 | } |
1161 | if (HasSimpleBaseClasses(file: file_, options: options_)) { |
1162 | IncludeFile(google3_name: "net/proto2/public/generated_message_bases.h" , printer); |
1163 | } |
1164 | if (HasGeneratedMethods(file: file_, options: options_) && |
1165 | options_.tctable_mode != Options::kTCTableNever) { |
1166 | IncludeFile(google3_name: "net/proto2/public/generated_message_tctable_decl.h" , printer); |
1167 | } |
1168 | IncludeFile(google3_name: "net/proto2/public/generated_message_util.h" , printer); |
1169 | IncludeFile(google3_name: "net/proto2/public/metadata_lite.h" , printer); |
1170 | |
1171 | if (HasDescriptorMethods(file: file_, options: options_)) { |
1172 | IncludeFile(google3_name: "net/proto2/public/generated_message_reflection.h" , printer); |
1173 | } |
1174 | |
1175 | if (!message_generators_.empty()) { |
1176 | if (HasDescriptorMethods(file: file_, options: options_)) { |
1177 | IncludeFile(google3_name: "net/proto2/public/message.h" , printer); |
1178 | } else { |
1179 | IncludeFile(google3_name: "net/proto2/public/message_lite.h" , printer); |
1180 | } |
1181 | } |
1182 | if (options_.opensource_runtime) { |
1183 | // Open-source relies on unconditional includes of these. |
1184 | IncludeFileAndExport(google3_name: "net/proto2/public/repeated_field.h" , printer); |
1185 | IncludeFileAndExport(google3_name: "net/proto2/public/extension_set.h" , printer); |
1186 | } else { |
1187 | // Google3 includes these files only when they are necessary. |
1188 | if (HasExtensionsOrExtendableMessage(file: file_)) { |
1189 | IncludeFileAndExport(google3_name: "net/proto2/public/extension_set.h" , printer); |
1190 | } |
1191 | if (HasRepeatedFields(file: file_)) { |
1192 | IncludeFileAndExport(google3_name: "net/proto2/public/repeated_field.h" , printer); |
1193 | } |
1194 | if (HasStringPieceFields(file: file_, options: options_)) { |
1195 | IncludeFile(google3_name: "net/proto2/public/string_piece_field_support.h" , printer); |
1196 | } |
1197 | if (HasCordFields(file: file_, options: options_)) { |
1198 | format("#include \"third_party/absl/strings/cord.h\"\n" ); |
1199 | } |
1200 | } |
1201 | if (HasMapFields(file: file_)) { |
1202 | IncludeFileAndExport(google3_name: "net/proto2/public/map.h" , printer); |
1203 | if (HasDescriptorMethods(file: file_, options: options_)) { |
1204 | IncludeFile(google3_name: "net/proto2/public/map_entry.h" , printer); |
1205 | IncludeFile(google3_name: "net/proto2/public/map_field_inl.h" , printer); |
1206 | } else { |
1207 | IncludeFile(google3_name: "net/proto2/public/map_entry_lite.h" , printer); |
1208 | IncludeFile(google3_name: "net/proto2/public/map_field_lite.h" , printer); |
1209 | } |
1210 | } |
1211 | |
1212 | if (HasEnumDefinitions(file: file_)) { |
1213 | if (HasDescriptorMethods(file: file_, options: options_)) { |
1214 | IncludeFile(google3_name: "net/proto2/public/generated_enum_reflection.h" , printer); |
1215 | } else { |
1216 | IncludeFile(google3_name: "net/proto2/public/generated_enum_util.h" , printer); |
1217 | } |
1218 | } |
1219 | |
1220 | if (HasGenericServices(file: file_, options: options_)) { |
1221 | IncludeFile(google3_name: "net/proto2/public/service.h" , printer); |
1222 | } |
1223 | |
1224 | if (UseUnknownFieldSet(file: file_, options: options_) && !message_generators_.empty()) { |
1225 | IncludeFile(google3_name: "net/proto2/public/unknown_field_set.h" , printer); |
1226 | } |
1227 | } |
1228 | |
1229 | void FileGenerator::GenerateMetadataPragma(io::Printer* printer, |
1230 | const std::string& info_path) { |
1231 | Formatter format(printer, variables_); |
1232 | if (!info_path.empty() && !options_.annotation_pragma_name.empty() && |
1233 | !options_.annotation_guard_name.empty()) { |
1234 | format.Set(key: "guard" , value: options_.annotation_guard_name); |
1235 | format.Set(key: "pragma" , value: options_.annotation_pragma_name); |
1236 | format.Set(key: "info_path" , value: info_path); |
1237 | format( |
1238 | "#ifdef $guard$\n" |
1239 | "#pragma $pragma$ \"$info_path$\"\n" |
1240 | "#endif // $guard$\n" ); |
1241 | } |
1242 | } |
1243 | |
1244 | void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { |
1245 | Formatter format(printer, variables_); |
1246 | for (int i = 0; i < file_->dependency_count(); i++) { |
1247 | std::string basename = StripProto(filename: file_->dependency(index: i)->name()); |
1248 | |
1249 | // Do not import weak deps. |
1250 | if (IsDepWeak(dep: file_->dependency(index: i))) continue; |
1251 | |
1252 | if (IsBootstrapProto(options: options_, file: file_)) { |
1253 | GetBootstrapBasename(options: options_, basename, bootstrap_basename: &basename); |
1254 | } |
1255 | |
1256 | format("#include $1$\n" , |
1257 | CreateHeaderInclude(basename: basename + ".pb.h" , file: file_->dependency(index: i))); |
1258 | } |
1259 | } |
1260 | |
1261 | void FileGenerator::GenerateGlobalStateFunctionDeclarations( |
1262 | io::Printer* printer) { |
1263 | Formatter format(printer, variables_); |
1264 | // Forward-declare the DescriptorTable because this is referenced by .pb.cc |
1265 | // files depending on this file. |
1266 | // |
1267 | // The TableStruct is also outputted in weak_message_field.cc, because the |
1268 | // weak fields must refer to table struct but cannot include the header. |
1269 | // Also it annotates extra weak attributes. |
1270 | // TODO(gerbens) make sure this situation is handled better. |
1271 | format( |
1272 | "\n" |
1273 | "// Internal implementation detail -- do not use these members.\n" |
1274 | "struct $dllexport_decl $$tablename$ {\n" |
1275 | " static const $uint32$ offsets[];\n" |
1276 | "};\n" ); |
1277 | if (HasDescriptorMethods(file: file_, options: options_)) { |
1278 | format( |
1279 | "$dllexport_decl $extern const ::$proto_ns$::internal::DescriptorTable " |
1280 | "$desc_table$;\n" ); |
1281 | } |
1282 | } |
1283 | |
1284 | void FileGenerator::GenerateMessageDefinitions(io::Printer* printer) { |
1285 | Formatter format(printer, variables_); |
1286 | // Generate class definitions. |
1287 | for (int i = 0; i < message_generators_.size(); i++) { |
1288 | if (i > 0) { |
1289 | format("\n" ); |
1290 | format(kThinSeparator); |
1291 | format("\n" ); |
1292 | } |
1293 | message_generators_[i]->GenerateClassDefinition(printer); |
1294 | } |
1295 | } |
1296 | |
1297 | void FileGenerator::GenerateEnumDefinitions(io::Printer* printer) { |
1298 | // Generate enum definitions. |
1299 | for (int i = 0; i < enum_generators_.size(); i++) { |
1300 | enum_generators_[i]->GenerateDefinition(printer); |
1301 | } |
1302 | } |
1303 | |
1304 | void FileGenerator::GenerateServiceDefinitions(io::Printer* printer) { |
1305 | Formatter format(printer, variables_); |
1306 | if (HasGenericServices(file: file_, options: options_)) { |
1307 | // Generate service definitions. |
1308 | for (int i = 0; i < service_generators_.size(); i++) { |
1309 | if (i > 0) { |
1310 | format("\n" ); |
1311 | format(kThinSeparator); |
1312 | format("\n" ); |
1313 | } |
1314 | service_generators_[i]->GenerateDeclarations(printer); |
1315 | } |
1316 | |
1317 | format("\n" ); |
1318 | format(kThickSeparator); |
1319 | format("\n" ); |
1320 | } |
1321 | } |
1322 | |
1323 | void FileGenerator::GenerateExtensionIdentifiers(io::Printer* printer) { |
1324 | // Declare extension identifiers. These are in global scope and so only |
1325 | // the global scope extensions. |
1326 | for (auto& extension_generator : extension_generators_) { |
1327 | if (extension_generator->IsScoped()) continue; |
1328 | extension_generator->GenerateDeclaration(printer); |
1329 | } |
1330 | } |
1331 | |
1332 | void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { |
1333 | Formatter format(printer, variables_); |
1334 | // TODO(gerbens) remove pragmas when gcc is no longer used. Current version |
1335 | // of gcc fires a bogus error when compiled with strict-aliasing. |
1336 | format( |
1337 | "#ifdef __GNUC__\n" |
1338 | " #pragma GCC diagnostic push\n" |
1339 | " #pragma GCC diagnostic ignored \"-Wstrict-aliasing\"\n" |
1340 | "#endif // __GNUC__\n" ); |
1341 | // Generate class inline methods. |
1342 | for (int i = 0; i < message_generators_.size(); i++) { |
1343 | if (i > 0) { |
1344 | format(kThinSeparator); |
1345 | format("\n" ); |
1346 | } |
1347 | message_generators_[i]->GenerateInlineMethods(printer); |
1348 | } |
1349 | format( |
1350 | "#ifdef __GNUC__\n" |
1351 | " #pragma GCC diagnostic pop\n" |
1352 | "#endif // __GNUC__\n" ); |
1353 | |
1354 | for (int i = 0; i < message_generators_.size(); i++) { |
1355 | if (i > 0) { |
1356 | format(kThinSeparator); |
1357 | format("\n" ); |
1358 | } |
1359 | } |
1360 | } |
1361 | |
1362 | void FileGenerator::GenerateProto2NamespaceEnumSpecializations( |
1363 | io::Printer* printer) { |
1364 | Formatter format(printer, variables_); |
1365 | // Emit GetEnumDescriptor specializations into google::protobuf namespace: |
1366 | if (HasEnumDefinitions(file: file_)) { |
1367 | format("\n" ); |
1368 | { |
1369 | NamespaceOpener proto_ns(ProtobufNamespace(options_), format); |
1370 | format("\n" ); |
1371 | for (int i = 0; i < enum_generators_.size(); i++) { |
1372 | enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); |
1373 | } |
1374 | format("\n" ); |
1375 | } |
1376 | } |
1377 | } |
1378 | |
1379 | } // namespace cpp |
1380 | } // namespace compiler |
1381 | } // namespace protobuf |
1382 | } // namespace google |
1383 | |