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