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