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