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