• 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("} $1$;\n", DefaultInstanceName(generator->descriptor_, options_));
445 
446   if (options_.lite_implicit_weak_fields) {
447     format("$1$* $2$ = &$3$;\n",
448            DefaultInstanceType(generator->descriptor_, options_),
449            DefaultInstancePtr(generator->descriptor_, options_),
450            DefaultInstanceName(generator->descriptor_, options_));
451   }
452 }
453 
454 // A list of things defined in one .pb.cc file that we need to reference from
455 // another .pb.cc file.
456 struct FileGenerator::CrossFileReferences {
457   // Populated if we are referencing from messages or files.
458   std::unordered_set<const SCC*> strong_sccs;
459   std::unordered_set<const SCC*> weak_sccs;
460   std::unordered_set<const Descriptor*> weak_default_instances;
461 
462   // Only if we are referencing from files.
463   std::unordered_set<const FileDescriptor*> strong_reflection_files;
464   std::unordered_set<const FileDescriptor*> weak_reflection_files;
465 };
466 
GetCrossFileReferencesForField(const FieldDescriptor * field,CrossFileReferences * refs)467 void FileGenerator::GetCrossFileReferencesForField(const FieldDescriptor* field,
468                                                    CrossFileReferences* refs) {
469   const Descriptor* msg = field->message_type();
470   if (msg == nullptr) return;
471   const SCC* scc = GetSCC(msg);
472 
473   if (IsImplicitWeakField(field, options_, &scc_analyzer_) ||
474       IsWeak(field, options_)) {
475     refs->weak_sccs.insert(scc);
476     refs->weak_default_instances.insert(msg);
477   } else {
478     refs->strong_sccs.insert(scc);
479     // We don't need to declare default instances, because it is declared in the
480     // .proto.h file we imported.
481   }
482 }
483 
GetCrossFileReferencesForFile(const FileDescriptor * file,CrossFileReferences * refs)484 void FileGenerator::GetCrossFileReferencesForFile(const FileDescriptor* file,
485                                                   CrossFileReferences* refs) {
486   ForEachField(file, [this, refs](const FieldDescriptor* field) {
487     GetCrossFileReferencesForField(field, refs);
488   });
489 
490   if (!HasDescriptorMethods(file, options_)) return;
491 
492   for (int i = 0; i < file->dependency_count(); i++) {
493     const FileDescriptor* dep = file->dependency(i);
494     if (IsDepWeak(dep)) {
495       refs->weak_reflection_files.insert(dep);
496     } else {
497       refs->strong_reflection_files.insert(dep);
498     }
499   }
500 }
501 
502 // Generates references to variables defined in other files.
GenerateInternalForwardDeclarations(const CrossFileReferences & refs,io::Printer * printer)503 void FileGenerator::GenerateInternalForwardDeclarations(
504     const CrossFileReferences& refs, io::Printer* printer) {
505   Formatter format(printer, variables_);
506 
507   for (auto scc : Sorted(refs.strong_sccs)) {
508     format("extern $1$ ::$proto_ns$::internal::SCCInfo<$2$> $3$;\n",
509            FileDllExport(scc->GetFile(), options_), scc->children.size(),
510            SccInfoSymbol(scc, options_));
511   }
512 
513   for (auto scc : Sorted(refs.weak_sccs)) {
514     // We do things a little bit differently for proto1-style weak fields versus
515     // lite implicit weak fields, even though they are trying to accomplish
516     // similar things. We need to support implicit weak fields on iOS, and the
517     // Apple linker only supports weak definitions, not weak declarations. For
518     // that reason we need a pointer type which we can weakly define to be null.
519     // However, code size considerations prevent us from using the same approach
520     // for proto1-style weak fields.
521     if (options_.lite_implicit_weak_fields) {
522       format("extern ::$proto_ns$::internal::SCCInfo<$1$> $2$;\n",
523              scc->children.size(), SccInfoSymbol(scc, options_));
524       format(
525           "__attribute__((weak)) ::$proto_ns$::internal::SCCInfo<$1$>*\n"
526           "    $2$ = nullptr;\n",
527           scc->children.size(), SccInfoPtrSymbol(scc, options_));
528     } else {
529       format(
530           "extern __attribute__((weak)) ::$proto_ns$::internal::SCCInfo<$1$> "
531           "$2$;\n",
532           scc->children.size(), SccInfoSymbol(scc, options_));
533     }
534   }
535 
536   {
537     NamespaceOpener ns(format);
538     for (auto instance : Sorted(refs.weak_default_instances)) {
539       ns.ChangeTo(Namespace(instance, options_));
540       if (options_.lite_implicit_weak_fields) {
541         format("extern $1$ $2$;\n", DefaultInstanceType(instance, options_),
542                DefaultInstanceName(instance, options_));
543         format("__attribute__((weak)) $1$* $2$ = nullptr;\n",
544                DefaultInstanceType(instance, options_),
545                DefaultInstancePtr(instance, options_));
546       } else {
547         format("extern __attribute__((weak)) $1$ $2$;\n",
548                DefaultInstanceType(instance, options_),
549                DefaultInstanceName(instance, options_));
550       }
551     }
552   }
553 
554   for (auto file : Sorted(refs.weak_reflection_files)) {
555     format(
556         "extern __attribute__((weak)) const "
557         "::$proto_ns$::internal::DescriptorTable $1$;\n",
558         DescriptorTableName(file, options_));
559   }
560 }
561 
GenerateSourceForMessage(int idx,io::Printer * printer)562 void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) {
563   Formatter format(printer, variables_);
564   GenerateSourceIncludes(printer);
565 
566   // Generate weak declarations. We do this for the whole strongly-connected
567   // component (SCC), because we have a single InitDefaults* function for the
568   // SCC.
569   CrossFileReferences refs;
570   for (const Descriptor* message :
571        scc_analyzer_.GetSCC(message_generators_[idx]->descriptor_)
572            ->descriptors) {
573     ForEachField(message, [this, &refs](const FieldDescriptor* field) {
574       GetCrossFileReferencesForField(field, &refs);
575     });
576   }
577   GenerateInternalForwardDeclarations(refs, printer);
578 
579   if (IsSCCRepresentative(message_generators_[idx]->descriptor_)) {
580     GenerateInitForSCC(GetSCC(message_generators_[idx]->descriptor_), refs,
581                        printer);
582   }
583 
584   {  // package namespace
585     NamespaceOpener ns(Namespace(file_, options_), format);
586 
587     // Define default instances
588     GenerateSourceDefaultInstance(idx, printer);
589 
590     // Generate classes.
591     format("\n");
592     message_generators_[idx]->GenerateClassMethods(printer);
593 
594     format(
595         "\n"
596         "// @@protoc_insertion_point(namespace_scope)\n");
597   }  // end package namespace
598 
599   {
600     NamespaceOpener proto_ns(ProtobufNamespace(options_), format);
601     message_generators_[idx]->GenerateSourceInProto2Namespace(printer);
602   }
603 
604   format(
605       "\n"
606       "// @@protoc_insertion_point(global_scope)\n");
607 }
608 
GenerateGlobalSource(io::Printer * printer)609 void FileGenerator::GenerateGlobalSource(io::Printer* printer) {
610   Formatter format(printer, variables_);
611   GenerateSourceIncludes(printer);
612 
613   {
614     GenerateTables(printer);
615 
616     // Define the code to initialize reflection. This code uses a global
617     // constructor to register reflection data with the runtime pre-main.
618     if (HasDescriptorMethods(file_, options_)) {
619       GenerateReflectionInitializationCode(printer);
620     }
621   }
622 
623   NamespaceOpener ns(Namespace(file_, options_), format);
624 
625   // Generate enums.
626   for (int i = 0; i < enum_generators_.size(); i++) {
627     enum_generators_[i]->GenerateMethods(i, printer);
628   }
629 
630   // Define extensions.
631   for (int i = 0; i < extension_generators_.size(); i++) {
632     extension_generators_[i]->GenerateDefinition(printer);
633   }
634 
635   if (HasGenericServices(file_, options_)) {
636     // Generate services.
637     for (int i = 0; i < service_generators_.size(); i++) {
638       if (i == 0) format("\n");
639       format(kThickSeparator);
640       format("\n");
641       service_generators_[i]->GenerateImplementation(printer);
642     }
643   }
644 }
645 
GenerateSource(io::Printer * printer)646 void FileGenerator::GenerateSource(io::Printer* printer) {
647   Formatter format(printer, variables_);
648   GenerateSourceIncludes(printer);
649   CrossFileReferences refs;
650   GetCrossFileReferencesForFile(file_, &refs);
651   GenerateInternalForwardDeclarations(refs, printer);
652 
653   {
654     NamespaceOpener ns(Namespace(file_, options_), format);
655 
656     // Define default instances
657     for (int i = 0; i < message_generators_.size(); i++) {
658       GenerateSourceDefaultInstance(i, printer);
659     }
660   }
661 
662   {
663     GenerateTables(printer);
664 
665     // Now generate the InitDefaults for each SCC.
666     for (auto scc : sccs_) {
667       GenerateInitForSCC(scc, refs, printer);
668     }
669 
670     if (HasDescriptorMethods(file_, options_)) {
671       // Define the code to initialize reflection. This code uses a global
672       // constructor to register reflection data with the runtime pre-main.
673       GenerateReflectionInitializationCode(printer);
674     }
675   }
676 
677   {
678     NamespaceOpener ns(Namespace(file_, options_), format);
679 
680     // Actually implement the protos
681 
682     // Generate enums.
683     for (int i = 0; i < enum_generators_.size(); i++) {
684       enum_generators_[i]->GenerateMethods(i, printer);
685     }
686 
687     // Generate classes.
688     for (int i = 0; i < message_generators_.size(); i++) {
689       format("\n");
690       format(kThickSeparator);
691       format("\n");
692       message_generators_[i]->GenerateClassMethods(printer);
693     }
694 
695     if (HasGenericServices(file_, options_)) {
696       // Generate services.
697       for (int i = 0; i < service_generators_.size(); i++) {
698         if (i == 0) format("\n");
699         format(kThickSeparator);
700         format("\n");
701         service_generators_[i]->GenerateImplementation(printer);
702       }
703     }
704 
705     // Define extensions.
706     for (int i = 0; i < extension_generators_.size(); i++) {
707       extension_generators_[i]->GenerateDefinition(printer);
708     }
709 
710     format(
711         "\n"
712         "// @@protoc_insertion_point(namespace_scope)\n");
713   }
714 
715   {
716     NamespaceOpener proto_ns(ProtobufNamespace(options_), format);
717     for (int i = 0; i < message_generators_.size(); i++) {
718       message_generators_[i]->GenerateSourceInProto2Namespace(printer);
719     }
720   }
721 
722   format(
723       "\n"
724       "// @@protoc_insertion_point(global_scope)\n");
725 
726   IncludeFile("net/proto2/public/port_undef.inc", printer);
727 }
728 
GenerateReflectionInitializationCode(io::Printer * printer)729 void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) {
730   Formatter format(printer, variables_);
731 
732   if (!message_generators_.empty()) {
733     format("static ::$proto_ns$::Metadata $file_level_metadata$[$1$];\n",
734            message_generators_.size());
735   } else {
736     format(
737         "static "
738         "constexpr ::$proto_ns$::Metadata* $file_level_metadata$ = nullptr;\n");
739   }
740   if (!enum_generators_.empty()) {
741     format(
742         "static "
743         "const ::$proto_ns$::EnumDescriptor* "
744         "$file_level_enum_descriptors$[$1$];\n",
745         enum_generators_.size());
746   } else {
747     format(
748         "static "
749         "constexpr ::$proto_ns$::EnumDescriptor const** "
750         "$file_level_enum_descriptors$ = nullptr;\n");
751   }
752   if (HasGenericServices(file_, options_) && file_->service_count() > 0) {
753     format(
754         "static "
755         "const ::$proto_ns$::ServiceDescriptor* "
756         "$file_level_service_descriptors$[$1$];\n",
757         file_->service_count());
758   } else {
759     format(
760         "static "
761         "constexpr ::$proto_ns$::ServiceDescriptor const** "
762         "$file_level_service_descriptors$ = nullptr;\n");
763   }
764 
765   if (!message_generators_.empty()) {
766     format(
767         "\n"
768         "const $uint32$ $tablename$::offsets[] "
769         "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n");
770     format.Indent();
771     std::vector<std::pair<size_t, size_t> > pairs;
772     pairs.reserve(message_generators_.size());
773     for (int i = 0; i < message_generators_.size(); i++) {
774       pairs.push_back(message_generators_[i]->GenerateOffsets(printer));
775     }
776     format.Outdent();
777     format(
778         "};\n"
779         "static const ::$proto_ns$::internal::MigrationSchema schemas[] "
780         "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n");
781     format.Indent();
782     {
783       int offset = 0;
784       for (int i = 0; i < message_generators_.size(); i++) {
785         message_generators_[i]->GenerateSchema(printer, offset,
786                                                pairs[i].second);
787         offset += pairs[i].first;
788       }
789     }
790     format.Outdent();
791     format(
792         "};\n"
793         "\nstatic "
794         "::$proto_ns$::Message const * const file_default_instances[] = {\n");
795     format.Indent();
796     for (int i = 0; i < message_generators_.size(); i++) {
797       const Descriptor* descriptor = message_generators_[i]->descriptor_;
798       format(
799           "reinterpret_cast<const "
800           "::$proto_ns$::Message*>(&$1$::_$2$_default_instance_),\n",
801           Namespace(descriptor, options_),  // 1
802           ClassName(descriptor));           // 2
803     }
804     format.Outdent();
805     format(
806         "};\n"
807         "\n");
808   } else {
809     // we still need these symbols to exist
810     format(
811         // MSVC doesn't like empty arrays, so we add a dummy.
812         "const $uint32$ $tablename$::offsets[1] = {};\n"
813         "static constexpr ::$proto_ns$::internal::MigrationSchema* schemas = "
814         "nullptr;"
815         "\n"
816         "static constexpr ::$proto_ns$::Message* const* "
817         "file_default_instances = nullptr;\n"
818         "\n");
819   }
820 
821   // ---------------------------------------------------------------
822 
823   // Embed the descriptor.  We simply serialize the entire
824   // FileDescriptorProto/ and embed it as a string literal, which is parsed and
825   // built into real descriptors at initialization time.
826   const std::string protodef_name =
827       UniqueName("descriptor_table_protodef", file_, options_);
828   format("const char $1$[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =\n",
829          protodef_name);
830   format.Indent();
831   FileDescriptorProto file_proto;
832   file_->CopyTo(&file_proto);
833   std::string file_data;
834   file_proto.SerializeToString(&file_data);
835 
836   {
837     if (file_data.size() > 65535) {
838       // Workaround for MSVC: "Error C1091: compiler limit: string exceeds
839       // 65535 bytes in length". Declare a static array of chars rather than
840       // use a string literal. Only write 25 bytes per line.
841       static const int kBytesPerLine = 25;
842       format("{ ");
843       for (int i = 0; i < file_data.size();) {
844         for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) {
845           format("'$1$', ", CEscape(file_data.substr(i, 1)));
846         }
847         format("\n");
848       }
849       format("'\\0' }");  // null-terminate
850     } else {
851       // Only write 40 bytes per line.
852       static const int kBytesPerLine = 40;
853       for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
854         format(
855             "\"$1$\"\n",
856             EscapeTrigraphs(CEscape(file_data.substr(i, kBytesPerLine))));
857       }
858     }
859     format(";\n");
860   }
861   format.Outdent();
862 
863   CrossFileReferences refs;
864   GetCrossFileReferencesForFile(file_, &refs);
865   int num_deps =
866       refs.strong_reflection_files.size() + refs.weak_reflection_files.size();
867 
868   // Build array of DescriptorTable deps.
869   format(
870       "static const ::$proto_ns$::internal::DescriptorTable*const "
871       "$desc_table$_deps[$1$] = {\n",
872       std::max(num_deps, 1));
873 
874   for (auto dep : Sorted(refs.strong_reflection_files)) {
875     format("  &::$1$,\n", DescriptorTableName(dep, options_));
876   }
877   for (auto dep : Sorted(refs.weak_reflection_files)) {
878     format("  &::$1$,\n", DescriptorTableName(dep, options_));
879   }
880 
881   format("};\n");
882 
883   // Build array of SCCs from this file.
884   format(
885       "static ::$proto_ns$::internal::SCCInfoBase*const "
886       "$desc_table$_sccs[$1$] = {\n",
887       std::max<int>(sccs_.size(), 1));
888 
889   for (auto scc : sccs_) {
890     format("  &$1$.base,\n", SccInfoSymbol(scc, options_));
891   }
892 
893   format("};\n");
894 
895   // The DescriptorTable itself.
896   // Should be "bool eager = NeedsEagerDescriptorAssignment(file_, options_);"
897   // however this might cause a tsan failure in superroot b/148382879,
898   // so disable for now.
899   bool eager = false;
900   format(
901       "static ::$proto_ns$::internal::once_flag $desc_table$_once;\n"
902       "const ::$proto_ns$::internal::DescriptorTable $desc_table$ = {\n"
903       "  false, $1$, $2$, \"$filename$\", $3$,\n"
904       "  &$desc_table$_once, $desc_table$_sccs, $desc_table$_deps, $4$, $5$,\n"
905       "  schemas, file_default_instances, $tablename$::offsets,\n"
906       "  $file_level_metadata$, $6$, $file_level_enum_descriptors$, "
907       "$file_level_service_descriptors$,\n"
908       "};\n\n",
909       eager ? "true" : "false", protodef_name, file_data.size(), sccs_.size(),
910       num_deps, message_generators_.size());
911 
912   // For descriptor.proto we want to avoid doing any dynamic initialization,
913   // because in some situations that would otherwise pull in a lot of
914   // unnecessary code that can't be stripped by --gc-sections. Descriptor
915   // initialization will still be performed lazily when it's needed.
916   if (file_->name() != "net/proto2/proto/descriptor.proto") {
917     format(
918         "// Force running AddDescriptors() at dynamic initialization time.\n"
919         "static bool $1$ = (static_cast<void>("
920         "::$proto_ns$::internal::AddDescriptors(&$desc_table$)), true);\n",
921         UniqueName("dynamic_init_dummy", file_, options_));
922   }
923 }
924 
GenerateInitForSCC(const SCC * scc,const CrossFileReferences & refs,io::Printer * printer)925 void FileGenerator::GenerateInitForSCC(const SCC* scc,
926                                        const CrossFileReferences& refs,
927                                        io::Printer* printer) {
928   Formatter format(printer, variables_);
929   // We use static and not anonymous namespace because symbol names are
930   // substantially shorter.
931   format("static void InitDefaults$1$() {\n", SccInfoSymbol(scc, options_));
932 
933   if (options_.opensource_runtime) {
934     format("  GOOGLE_PROTOBUF_VERIFY_VERSION;\n\n");
935   }
936 
937   format.Indent();
938 
939   // First construct all the necessary default instances.
940   for (int i = 0; i < message_generators_.size(); i++) {
941     if (scc_analyzer_.GetSCC(message_generators_[i]->descriptor_) != scc) {
942       continue;
943     }
944     format(
945         "{\n"
946         "  void* ptr = &$1$;\n"
947         "  new (ptr) $2$();\n",
948         QualifiedDefaultInstanceName(message_generators_[i]->descriptor_,
949                                      options_),
950         QualifiedClassName(message_generators_[i]->descriptor_, options_));
951     if (options_.opensource_runtime &&
952         !IsMapEntryMessage(message_generators_[i]->descriptor_)) {
953       format(
954           "  "
955           "::PROTOBUF_NAMESPACE_ID::internal::OnShutdownDestroyMessage(ptr);"
956           "\n");
957     }
958     format("}\n");
959   }
960   format.Outdent();
961   format("}\n\n");
962 
963   // If we are using lite implicit weak fields then we need to distinguish
964   // between regular SCC dependencies and ones that we need to reference weakly
965   // through an extra pointer indirection.
966   std::vector<const SCC*> regular_sccs;
967   std::vector<const SCC*> implicit_weak_sccs;
968   for (const SCC* child : scc->children) {
969     if (options_.lite_implicit_weak_fields &&
970         refs.weak_sccs.find(child) != refs.weak_sccs.end()) {
971       implicit_weak_sccs.push_back(child);
972     } else {
973       regular_sccs.push_back(child);
974     }
975   }
976 
977   format(
978       "$dllexport_decl $::$proto_ns$::internal::SCCInfo<$1$> $2$ =\n"
979       "    "
980       "{{ATOMIC_VAR_INIT(::$proto_ns$::internal::SCCInfoBase::kUninitialized), "
981       "$3$, $4$, InitDefaults$2$}, {",
982       scc->children.size(),  // 1
983       SccInfoSymbol(scc, options_), regular_sccs.size(),
984       implicit_weak_sccs.size());
985   for (const SCC* child : regular_sccs) {
986     format("\n      &$1$.base,", SccInfoSymbol(child, options_));
987   }
988   for (const SCC* child : implicit_weak_sccs) {
989     format(
990         "\n      reinterpret_cast<::$proto_ns$::internal::SCCInfoBase**>("
991         "\n          &$1$),",
992         SccInfoPtrSymbol(child, options_));
993   }
994   format("}};\n\n");
995 
996   if (options_.lite_implicit_weak_fields) {
997     format(
998         "$dllexport_decl $::$proto_ns$::internal::SCCInfo<$1$>*\n"
999         "    $2$ = &$3$;\n\n",
1000         scc->children.size(), SccInfoPtrSymbol(scc, options_),
1001         SccInfoSymbol(scc, options_));
1002   }
1003 }
1004 
GenerateTables(io::Printer * printer)1005 void FileGenerator::GenerateTables(io::Printer* printer) {
1006   Formatter format(printer, variables_);
1007   if (options_.table_driven_parsing) {
1008     // TODO(ckennelly): Gate this with the same options flag to enable
1009     // table-driven parsing.
1010     format(
1011         "PROTOBUF_CONSTEXPR_VAR ::$proto_ns$::internal::ParseTableField\n"
1012         "    const $tablename$::entries[] "
1013         "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n");
1014     format.Indent();
1015 
1016     std::vector<size_t> entries;
1017     size_t count = 0;
1018     for (int i = 0; i < message_generators_.size(); i++) {
1019       size_t value = message_generators_[i]->GenerateParseOffsets(printer);
1020       entries.push_back(value);
1021       count += value;
1022     }
1023 
1024     // We need these arrays to exist, and MSVC does not like empty arrays.
1025     if (count == 0) {
1026       format("{0, 0, 0, ::$proto_ns$::internal::kInvalidMask, 0, 0},\n");
1027     }
1028 
1029     format.Outdent();
1030     format(
1031         "};\n"
1032         "\n"
1033         "PROTOBUF_CONSTEXPR_VAR "
1034         "::$proto_ns$::internal::AuxiliaryParseTableField\n"
1035         "    const $tablename$::aux[] "
1036         "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n");
1037     format.Indent();
1038 
1039     std::vector<size_t> aux_entries;
1040     count = 0;
1041     for (int i = 0; i < message_generators_.size(); i++) {
1042       size_t value = message_generators_[i]->GenerateParseAuxTable(printer);
1043       aux_entries.push_back(value);
1044       count += value;
1045     }
1046 
1047     if (count == 0) {
1048       format("::$proto_ns$::internal::AuxiliaryParseTableField(),\n");
1049     }
1050 
1051     format.Outdent();
1052     format(
1053         "};\n"
1054         "PROTOBUF_CONSTEXPR_VAR ::$proto_ns$::internal::ParseTable const\n"
1055         "    $tablename$::schema[] "
1056         "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n");
1057     format.Indent();
1058 
1059     size_t offset = 0;
1060     size_t aux_offset = 0;
1061     for (int i = 0; i < message_generators_.size(); i++) {
1062       message_generators_[i]->GenerateParseTable(printer, offset, aux_offset);
1063       offset += entries[i];
1064       aux_offset += aux_entries[i];
1065     }
1066 
1067     if (message_generators_.empty()) {
1068       format("{ nullptr, nullptr, 0, -1, -1, false },\n");
1069     }
1070 
1071     format.Outdent();
1072     format(
1073         "};\n"
1074         "\n");
1075   }
1076 
1077   if (!message_generators_.empty() && options_.table_driven_serialization) {
1078     format(
1079         "const ::$proto_ns$::internal::FieldMetadata "
1080         "$tablename$::field_metadata[] "
1081         "= {\n");
1082     format.Indent();
1083     std::vector<int> field_metadata_offsets;
1084     int idx = 0;
1085     for (int i = 0; i < message_generators_.size(); i++) {
1086       field_metadata_offsets.push_back(idx);
1087       idx += message_generators_[i]->GenerateFieldMetadata(printer);
1088     }
1089     field_metadata_offsets.push_back(idx);
1090     format.Outdent();
1091     format(
1092         "};\n"
1093         "const ::$proto_ns$::internal::SerializationTable "
1094         "$tablename$::serialization_table[] = {\n");
1095     format.Indent();
1096     // We rely on the order we layout the tables to match the order we
1097     // calculate them with FlattenMessagesInFile, so we check here that
1098     // these match exactly.
1099     std::vector<const Descriptor*> calculated_order =
1100         FlattenMessagesInFile(file_);
1101     GOOGLE_CHECK_EQ(calculated_order.size(), message_generators_.size());
1102     for (int i = 0; i < message_generators_.size(); i++) {
1103       GOOGLE_CHECK_EQ(calculated_order[i], message_generators_[i]->descriptor_);
1104       format("{$1$, $tablename$::field_metadata + $2$},\n",
1105              field_metadata_offsets[i + 1] - field_metadata_offsets[i],  // 1
1106              field_metadata_offsets[i]);                                 // 2
1107     }
1108     format.Outdent();
1109     format(
1110         "};\n"
1111         "\n");
1112   }
1113 }
1114 
1115 class FileGenerator::ForwardDeclarations {
1116  public:
AddMessage(const Descriptor * d)1117   void AddMessage(const Descriptor* d) { classes_[ClassName(d)] = d; }
AddEnum(const EnumDescriptor * d)1118   void AddEnum(const EnumDescriptor* d) { enums_[ClassName(d)] = d; }
1119 
Print(const Formatter & format,const Options & options) const1120   void Print(const Formatter& format, const Options& options) const {
1121     for (const auto& p : enums_) {
1122       const std::string& enumname = p.first;
1123       const EnumDescriptor* enum_desc = p.second;
1124       format(
1125           "enum ${1$$2$$}$ : int;\n"
1126           "bool $2$_IsValid(int value);\n",
1127           enum_desc, enumname);
1128     }
1129     for (const auto& p : classes_) {
1130       const std::string& classname = p.first;
1131       const Descriptor* class_desc = p.second;
1132       format(
1133           "class ${1$$2$$}$;\n"
1134           "class $3$;\n"
1135           "$dllexport_decl $extern $3$ $4$;\n",
1136           class_desc, classname, DefaultInstanceType(class_desc, options),
1137           DefaultInstanceName(class_desc, options));
1138     }
1139   }
1140 
PrintTopLevelDecl(const Formatter & format,const Options & options) const1141   void PrintTopLevelDecl(const Formatter& format,
1142                          const Options& options) const {
1143     for (const auto& pair : classes_) {
1144       format(
1145           "template<> $dllexport_decl $"
1146           "$1$* Arena::CreateMaybeMessage<$1$>(Arena*);\n",
1147           QualifiedClassName(pair.second, options));
1148     }
1149   }
1150 
1151  private:
1152   std::map<std::string, const Descriptor*> classes_;
1153   std::map<std::string, const EnumDescriptor*> enums_;
1154 };
1155 
PublicImportDFS(const FileDescriptor * fd,std::unordered_set<const FileDescriptor * > * fd_set)1156 static void PublicImportDFS(const FileDescriptor* fd,
1157                             std::unordered_set<const FileDescriptor*>* fd_set) {
1158   for (int i = 0; i < fd->public_dependency_count(); i++) {
1159     const FileDescriptor* dep = fd->public_dependency(i);
1160     if (fd_set->insert(dep).second) PublicImportDFS(dep, fd_set);
1161   }
1162 }
1163 
GenerateForwardDeclarations(io::Printer * printer)1164 void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) {
1165   Formatter format(printer, variables_);
1166   std::vector<const Descriptor*> classes;
1167   std::vector<const EnumDescriptor*> enums;
1168 
1169   FlattenMessagesInFile(file_, &classes);  // All messages need forward decls.
1170 
1171   if (options_.proto_h) {  // proto.h needs extra forward declarations.
1172     // All classes / enums referred to as field members
1173     std::vector<const FieldDescriptor*> fields;
1174     ListAllFields(file_, &fields);
1175     for (int i = 0; i < fields.size(); i++) {
1176       classes.push_back(fields[i]->containing_type());
1177       classes.push_back(fields[i]->message_type());
1178       enums.push_back(fields[i]->enum_type());
1179     }
1180     ListAllTypesForServices(file_, &classes);
1181   }
1182 
1183   // Calculate the set of files whose definitions we get through include.
1184   // No need to forward declare types that are defined in these.
1185   std::unordered_set<const FileDescriptor*> public_set;
1186   PublicImportDFS(file_, &public_set);
1187 
1188   std::map<std::string, ForwardDeclarations> decls;
1189   for (int i = 0; i < classes.size(); i++) {
1190     const Descriptor* d = classes[i];
1191     if (d && !public_set.count(d->file()))
1192       decls[Namespace(d, options_)].AddMessage(d);
1193   }
1194   for (int i = 0; i < enums.size(); i++) {
1195     const EnumDescriptor* d = enums[i];
1196     if (d && !public_set.count(d->file()))
1197       decls[Namespace(d, options_)].AddEnum(d);
1198   }
1199 
1200   {
1201     NamespaceOpener ns(format);
1202     for (const auto& pair : decls) {
1203       ns.ChangeTo(pair.first);
1204       pair.second.Print(format, options_);
1205     }
1206   }
1207   format("PROTOBUF_NAMESPACE_OPEN\n");
1208   for (const auto& pair : decls) {
1209     pair.second.PrintTopLevelDecl(format, options_);
1210   }
1211   format("PROTOBUF_NAMESPACE_CLOSE\n");
1212 }
1213 
GenerateTopHeaderGuard(io::Printer * printer,bool pb_h)1214 void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer, bool pb_h) {
1215   Formatter format(printer, variables_);
1216   // Generate top of header.
1217   format(
1218       "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
1219       "// source: $filename$\n"
1220       "\n"
1221       "#ifndef $1$\n"
1222       "#define $1$\n"
1223       "\n"
1224       "#include <limits>\n"
1225       "#include <string>\n",
1226       IncludeGuard(file_, pb_h, options_));
1227   if (!options_.opensource_runtime && !enum_generators_.empty()) {
1228     // Add header to provide std::is_integral for safe Enum_Name() function.
1229     format("#include <type_traits>\n");
1230   }
1231   format("\n");
1232 }
1233 
GenerateBottomHeaderGuard(io::Printer * printer,bool pb_h)1234 void FileGenerator::GenerateBottomHeaderGuard(io::Printer* printer, bool pb_h) {
1235   Formatter format(printer, variables_);
1236   format("#endif  // $GOOGLE_PROTOBUF$_INCLUDED_$1$\n",
1237          IncludeGuard(file_, pb_h, options_));
1238 }
1239 
GenerateLibraryIncludes(io::Printer * printer)1240 void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) {
1241   Formatter format(printer, variables_);
1242   if (UsingImplicitWeakFields(file_, options_)) {
1243     IncludeFile("net/proto2/public/implicit_weak_message.h", printer);
1244   }
1245   if (HasWeakFields(file_, options_)) {
1246     GOOGLE_CHECK(!options_.opensource_runtime);
1247     IncludeFile("net/proto2/public/weak_field_map.h", printer);
1248   }
1249   if (HasLazyFields(file_, options_)) {
1250     GOOGLE_CHECK(!options_.opensource_runtime);
1251     IncludeFile("net/proto2/public/lazy_field.h", printer);
1252   }
1253 
1254   if (options_.opensource_runtime) {
1255     // Verify the protobuf library header version is compatible with the protoc
1256     // version before going any further.
1257     IncludeFile("net/proto2/public/port_def.inc", printer);
1258     format(
1259         "#if PROTOBUF_VERSION < $1$\n"
1260         "#error This file was generated by a newer version of protoc which is\n"
1261         "#error incompatible with your Protocol Buffer headers. Please update\n"
1262         "#error your headers.\n"
1263         "#endif\n"
1264         "#if $2$ < PROTOBUF_MIN_PROTOC_VERSION\n"
1265         "#error This file was generated by an older version of protoc which "
1266         "is\n"
1267         "#error incompatible with your Protocol Buffer headers. Please\n"
1268         "#error regenerate this file with a newer version of protoc.\n"
1269         "#endif\n"
1270         "\n",
1271         PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC,  // 1
1272         PROTOBUF_VERSION);                       // 2
1273     IncludeFile("net/proto2/public/port_undef.inc", printer);
1274   }
1275 
1276   // OK, it's now safe to #include other files.
1277   IncludeFile("net/proto2/io/public/coded_stream.h", printer);
1278   IncludeFile("net/proto2/public/arena.h", printer);
1279   IncludeFile("net/proto2/public/arenastring.h", printer);
1280   IncludeFile("net/proto2/public/generated_message_table_driven.h", printer);
1281   IncludeFile("net/proto2/public/generated_message_util.h", printer);
1282   IncludeFile("net/proto2/public/metadata_lite.h", printer);
1283 
1284   if (HasDescriptorMethods(file_, options_)) {
1285     IncludeFile("net/proto2/public/generated_message_reflection.h", printer);
1286   }
1287 
1288   if (!message_generators_.empty()) {
1289     if (HasDescriptorMethods(file_, options_)) {
1290       IncludeFile("net/proto2/public/message.h", printer);
1291     } else {
1292       IncludeFile("net/proto2/public/message_lite.h", printer);
1293     }
1294   }
1295   if (options_.opensource_runtime) {
1296     // Open-source relies on unconditional includes of these.
1297     IncludeFileAndExport("net/proto2/public/repeated_field.h", printer);
1298     IncludeFileAndExport("net/proto2/public/extension_set.h", printer);
1299   } else {
1300     // Google3 includes these files only when they are necessary.
1301     if (HasExtensionsOrExtendableMessage(file_)) {
1302       IncludeFileAndExport("net/proto2/public/extension_set.h", printer);
1303     }
1304     if (HasRepeatedFields(file_)) {
1305       IncludeFileAndExport("net/proto2/public/repeated_field.h", printer);
1306     }
1307     if (HasStringPieceFields(file_, options_)) {
1308       IncludeFile("net/proto2/public/string_piece_field_support.h", printer);
1309     }
1310     if (HasCordFields(file_, options_)) {
1311       format("#include \"third_party/absl/strings/cord.h\"\n");
1312     }
1313   }
1314   if (HasMapFields(file_)) {
1315     IncludeFileAndExport("net/proto2/public/map.h", printer);
1316     if (HasDescriptorMethods(file_, options_)) {
1317       IncludeFile("net/proto2/public/map_entry.h", printer);
1318       IncludeFile("net/proto2/public/map_field_inl.h", printer);
1319     } else {
1320       IncludeFile("net/proto2/public/map_entry_lite.h", printer);
1321       IncludeFile("net/proto2/public/map_field_lite.h", printer);
1322     }
1323   }
1324 
1325   if (HasEnumDefinitions(file_)) {
1326     if (HasDescriptorMethods(file_, options_)) {
1327       IncludeFile("net/proto2/public/generated_enum_reflection.h", printer);
1328     } else {
1329       IncludeFile("net/proto2/public/generated_enum_util.h", printer);
1330     }
1331   }
1332 
1333   if (HasGenericServices(file_, options_)) {
1334     IncludeFile("net/proto2/public/service.h", printer);
1335   }
1336 
1337   if (UseUnknownFieldSet(file_, options_) && !message_generators_.empty()) {
1338     IncludeFile("net/proto2/public/unknown_field_set.h", printer);
1339   }
1340 }
1341 
GenerateMetadataPragma(io::Printer * printer,const std::string & info_path)1342 void FileGenerator::GenerateMetadataPragma(io::Printer* printer,
1343                                            const std::string& info_path) {
1344   Formatter format(printer, variables_);
1345   if (!info_path.empty() && !options_.annotation_pragma_name.empty() &&
1346       !options_.annotation_guard_name.empty()) {
1347     format.Set("guard", options_.annotation_guard_name);
1348     format.Set("pragma", options_.annotation_pragma_name);
1349     format.Set("info_path", info_path);
1350     format(
1351         "#ifdef $guard$\n"
1352         "#pragma $pragma$ \"$info_path$\"\n"
1353         "#endif  // $guard$\n");
1354   }
1355 }
1356 
GenerateDependencyIncludes(io::Printer * printer)1357 void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) {
1358   Formatter format(printer, variables_);
1359   for (int i = 0; i < file_->dependency_count(); i++) {
1360     std::string basename = StripProto(file_->dependency(i)->name());
1361 
1362     // Do not import weak deps.
1363     if (IsDepWeak(file_->dependency(i))) continue;
1364 
1365     if (IsBootstrapProto(options_, file_)) {
1366       GetBootstrapBasename(options_, basename, &basename);
1367     }
1368 
1369     format("#include $1$\n",
1370            CreateHeaderInclude(basename + ".pb.h", file_->dependency(i)));
1371   }
1372 }
1373 
GenerateGlobalStateFunctionDeclarations(io::Printer * printer)1374 void FileGenerator::GenerateGlobalStateFunctionDeclarations(
1375     io::Printer* printer) {
1376   Formatter format(printer, variables_);
1377   // Forward-declare the DescriptorTable because this is referenced by .pb.cc
1378   // files depending on this file.
1379   //
1380   // The TableStruct is also outputted in weak_message_field.cc, because the
1381   // weak fields must refer to table struct but cannot include the header.
1382   // Also it annotates extra weak attributes.
1383   // TODO(gerbens) make sure this situation is handled better.
1384   format(
1385       "\n"
1386       "// Internal implementation detail -- do not use these members.\n"
1387       "struct $dllexport_decl $$tablename$ {\n"
1388       // These tables describe how to serialize and parse messages. Used
1389       // for table driven code.
1390       "  static const ::$proto_ns$::internal::ParseTableField entries[]\n"
1391       "    PROTOBUF_SECTION_VARIABLE(protodesc_cold);\n"
1392       "  static const ::$proto_ns$::internal::AuxiliaryParseTableField aux[]\n"
1393       "    PROTOBUF_SECTION_VARIABLE(protodesc_cold);\n"
1394       "  static const ::$proto_ns$::internal::ParseTable schema[$1$]\n"
1395       "    PROTOBUF_SECTION_VARIABLE(protodesc_cold);\n"
1396       "  static const ::$proto_ns$::internal::FieldMetadata field_metadata[];\n"
1397       "  static const ::$proto_ns$::internal::SerializationTable "
1398       "serialization_table[];\n"
1399       "  static const $uint32$ offsets[];\n"
1400       "};\n",
1401       std::max(size_t(1), message_generators_.size()));
1402   if (HasDescriptorMethods(file_, options_)) {
1403     format(
1404         "extern $dllexport_decl $const ::$proto_ns$::internal::DescriptorTable "
1405         "$desc_table$;\n");
1406   }
1407 }
1408 
GenerateMessageDefinitions(io::Printer * printer)1409 void FileGenerator::GenerateMessageDefinitions(io::Printer* printer) {
1410   Formatter format(printer, variables_);
1411   // Generate class definitions.
1412   for (int i = 0; i < message_generators_.size(); i++) {
1413     if (i > 0) {
1414       format("\n");
1415       format(kThinSeparator);
1416       format("\n");
1417     }
1418     message_generators_[i]->GenerateClassDefinition(printer);
1419   }
1420 }
1421 
GenerateEnumDefinitions(io::Printer * printer)1422 void FileGenerator::GenerateEnumDefinitions(io::Printer* printer) {
1423   // Generate enum definitions.
1424   for (int i = 0; i < enum_generators_.size(); i++) {
1425     enum_generators_[i]->GenerateDefinition(printer);
1426   }
1427 }
1428 
GenerateServiceDefinitions(io::Printer * printer)1429 void FileGenerator::GenerateServiceDefinitions(io::Printer* printer) {
1430   Formatter format(printer, variables_);
1431   if (HasGenericServices(file_, options_)) {
1432     // Generate service definitions.
1433     for (int i = 0; i < service_generators_.size(); i++) {
1434       if (i > 0) {
1435         format("\n");
1436         format(kThinSeparator);
1437         format("\n");
1438       }
1439       service_generators_[i]->GenerateDeclarations(printer);
1440     }
1441 
1442     format("\n");
1443     format(kThickSeparator);
1444     format("\n");
1445   }
1446 }
1447 
GenerateExtensionIdentifiers(io::Printer * printer)1448 void FileGenerator::GenerateExtensionIdentifiers(io::Printer* printer) {
1449   // Declare extension identifiers. These are in global scope and so only
1450   // the global scope extensions.
1451   for (auto& extension_generator : extension_generators_) {
1452     if (extension_generator->IsScoped()) continue;
1453     extension_generator->GenerateDeclaration(printer);
1454   }
1455 }
1456 
GenerateInlineFunctionDefinitions(io::Printer * printer)1457 void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) {
1458   Formatter format(printer, variables_);
1459   // TODO(gerbens) remove pragmas when gcc is no longer used. Current version
1460   // of gcc fires a bogus error when compiled with strict-aliasing.
1461   format(
1462       "#ifdef __GNUC__\n"
1463       "  #pragma GCC diagnostic push\n"
1464       "  #pragma GCC diagnostic ignored \"-Wstrict-aliasing\"\n"
1465       "#endif  // __GNUC__\n");
1466   // Generate class inline methods.
1467   for (int i = 0; i < message_generators_.size(); i++) {
1468     if (i > 0) {
1469       format(kThinSeparator);
1470       format("\n");
1471     }
1472     message_generators_[i]->GenerateInlineMethods(printer);
1473   }
1474   format(
1475       "#ifdef __GNUC__\n"
1476       "  #pragma GCC diagnostic pop\n"
1477       "#endif  // __GNUC__\n");
1478 
1479   for (int i = 0; i < message_generators_.size(); i++) {
1480     if (i > 0) {
1481       format(kThinSeparator);
1482       format("\n");
1483     }
1484   }
1485 }
1486 
GenerateProto2NamespaceEnumSpecializations(io::Printer * printer)1487 void FileGenerator::GenerateProto2NamespaceEnumSpecializations(
1488     io::Printer* printer) {
1489   Formatter format(printer, variables_);
1490   // Emit GetEnumDescriptor specializations into google::protobuf namespace:
1491   if (HasEnumDefinitions(file_)) {
1492     format("\n");
1493     {
1494       NamespaceOpener proto_ns(ProtobufNamespace(options_), format);
1495       format("\n");
1496       for (int i = 0; i < enum_generators_.size(); i++) {
1497         enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
1498       }
1499       format("\n");
1500     }
1501   }
1502 }
1503 
1504 }  // namespace cpp
1505 }  // namespace compiler
1506 }  // namespace protobuf
1507 }  // namespace google
1508