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