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