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