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