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