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 #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
36 #define GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
37
38 #include <algorithm>
39 #include <iterator>
40 #include <map>
41 #include <string>
42
43 #include <google/protobuf/compiler/cpp/cpp_options.h>
44 #include <google/protobuf/compiler/scc.h>
45 #include <google/protobuf/compiler/code_generator.h>
46 #include <google/protobuf/descriptor.pb.h>
47 #include <google/protobuf/io/printer.h>
48 #include <google/protobuf/descriptor.h>
49 #include <google/protobuf/port.h>
50 #include <google/protobuf/stubs/strutil.h>
51
52
53 #include <google/protobuf/port_def.inc>
54
55 namespace google {
56 namespace protobuf {
57 namespace compiler {
58 namespace cpp {
59
ProtobufNamespace(const Options & options)60 inline std::string ProtobufNamespace(const Options& options) {
61 return "PROTOBUF_NAMESPACE_ID";
62 }
63
MacroPrefix(const Options & options)64 inline std::string MacroPrefix(const Options& options) {
65 return options.opensource_runtime ? "GOOGLE_PROTOBUF" : "GOOGLE_PROTOBUF";
66 }
67
DeprecatedAttribute(const Options & options,bool deprecated)68 inline std::string DeprecatedAttribute(const Options& options,
69 bool deprecated) {
70 return deprecated ? "PROTOBUF_DEPRECATED " : "";
71 }
72
73 // Commonly-used separator comments. Thick is a line of '=', thin is a line
74 // of '-'.
75 extern const char kThickSeparator[];
76 extern const char kThinSeparator[];
77
78 void SetCommonVars(const Options& options,
79 std::map<std::string, std::string>* variables);
80
81 bool GetBootstrapBasename(const Options& options, const std::string& basename,
82 std::string* bootstrap_basename);
83 bool MaybeBootstrap(const Options& options, GeneratorContext* generator_context,
84 bool bootstrap_flag, std::string* basename);
85 bool IsBootstrapProto(const Options& options, const FileDescriptor* file);
86
87 // Name space of the proto file. This namespace is such that the string
88 // "<namespace>::some_name" is the correct fully qualified namespace.
89 // This means if the package is empty the namespace is "", and otherwise
90 // the namespace is "::foo::bar::...::baz" without trailing semi-colons.
91 std::string Namespace(const FileDescriptor* d, const Options& options);
92 std::string Namespace(const Descriptor* d, const Options& options);
93 std::string Namespace(const FieldDescriptor* d, const Options& options);
94 std::string Namespace(const EnumDescriptor* d, const Options& options);
95
96 // Returns true if it's safe to reset "field" to zero.
97 bool CanInitializeByZeroing(const FieldDescriptor* field);
98
99 std::string ClassName(const Descriptor* descriptor);
100 std::string ClassName(const EnumDescriptor* enum_descriptor);
101
102 std::string QualifiedClassName(const Descriptor* d, const Options& options);
103 std::string QualifiedClassName(const EnumDescriptor* d, const Options& options);
104
105 std::string QualifiedClassName(const Descriptor* d);
106 std::string QualifiedClassName(const EnumDescriptor* d);
107
108 // DEPRECATED just use ClassName or QualifiedClassName, a boolean is very
109 // unreadable at the callsite.
110 // Returns the non-nested type name for the given type. If "qualified" is
111 // true, prefix the type with the full namespace. For example, if you had:
112 // package foo.bar;
113 // message Baz { message Qux {} }
114 // Then the qualified ClassName for Qux would be:
115 // ::foo::bar::Baz_Qux
116 // While the non-qualified version would be:
117 // Baz_Qux
ClassName(const Descriptor * descriptor,bool qualified)118 inline std::string ClassName(const Descriptor* descriptor, bool qualified) {
119 return qualified ? QualifiedClassName(descriptor, Options())
120 : ClassName(descriptor);
121 }
122
ClassName(const EnumDescriptor * descriptor,bool qualified)123 inline std::string ClassName(const EnumDescriptor* descriptor, bool qualified) {
124 return qualified ? QualifiedClassName(descriptor, Options())
125 : ClassName(descriptor);
126 }
127
128 // Type name of default instance.
129 std::string DefaultInstanceType(const Descriptor* descriptor,
130 const Options& options);
131
132 // Non-qualified name of the default_instance of this message.
133 std::string DefaultInstanceName(const Descriptor* descriptor,
134 const Options& options);
135
136 // Fully qualified name of the default_instance of this message.
137 std::string QualifiedDefaultInstanceName(const Descriptor* descriptor,
138 const Options& options);
139
140 // DescriptorTable variable name.
141 std::string DescriptorTableName(const FileDescriptor* file,
142 const Options& options);
143
144 // When declaring symbol externs from another file, this macro will supply the
145 // dllexport needed for the target file, if any.
146 std::string FileDllExport(const FileDescriptor* file, const Options& options);
147
148 // Returns the name of a no-op function that we can call to introduce a linker
149 // dependency on the given message type. This is used to implement implicit weak
150 // fields.
151 std::string ReferenceFunctionName(const Descriptor* descriptor,
152 const Options& options);
153
154 // Name of the base class: google::protobuf::Message or google::protobuf::MessageLite.
155 std::string SuperClassName(const Descriptor* descriptor,
156 const Options& options);
157
158 // Adds an underscore if necessary to prevent conflicting with a keyword.
159 std::string ResolveKeyword(const string& name);
160
161 // Get the (unqualified) name that should be used for this field in C++ code.
162 // The name is coerced to lower-case to emulate proto1 behavior. People
163 // should be using lowercase-with-underscores style for proto field names
164 // anyway, so normally this just returns field->name().
165 std::string FieldName(const FieldDescriptor* field);
166
167 // Get the sanitized name that should be used for the given enum in C++ code.
168 std::string EnumValueName(const EnumValueDescriptor* enum_value);
169
170 // Returns an estimate of the compiler's alignment for the field. This
171 // can't guarantee to be correct because the generated code could be compiled on
172 // different systems with different alignment rules. The estimates below assume
173 // 64-bit pointers.
174 int EstimateAlignmentSize(const FieldDescriptor* field);
175
176 // Get the unqualified name that should be used for a field's field
177 // number constant.
178 std::string FieldConstantName(const FieldDescriptor* field);
179
180 // Returns the scope where the field was defined (for extensions, this is
181 // different from the message type to which the field applies).
FieldScope(const FieldDescriptor * field)182 inline const Descriptor* FieldScope(const FieldDescriptor* field) {
183 return field->is_extension() ? field->extension_scope()
184 : field->containing_type();
185 }
186
187 // Returns the fully-qualified type name field->message_type(). Usually this
188 // is just ClassName(field->message_type(), true);
189 std::string FieldMessageTypeName(const FieldDescriptor* field,
190 const Options& options);
191
192 // Strips ".proto" or ".protodevel" from the end of a filename.
193 PROTOC_EXPORT std::string StripProto(const std::string& filename);
194
195 // Get the C++ type name for a primitive type (e.g. "double", "::google::protobuf::int32", etc.).
196 const char* PrimitiveTypeName(FieldDescriptor::CppType type);
197 std::string PrimitiveTypeName(const Options& options,
198 FieldDescriptor::CppType type);
199
200 // Get the declared type name in CamelCase format, as is used e.g. for the
201 // methods of WireFormat. For example, TYPE_INT32 becomes "Int32".
202 const char* DeclaredTypeMethodName(FieldDescriptor::Type type);
203
204 // Return the code that evaluates to the number when compiled.
205 std::string Int32ToString(int number);
206
207 // Return the code that evaluates to the number when compiled.
208 std::string Int64ToString(const Options& options, int64 number);
209
210 // Get code that evaluates to the field's default value.
211 std::string DefaultValue(const Options& options, const FieldDescriptor* field);
212
213 // Compatibility function for callers outside proto2.
214 std::string DefaultValue(const FieldDescriptor* field);
215
216 // Convert a file name into a valid identifier.
217 std::string FilenameIdentifier(const std::string& filename);
218
219 // For each .proto file generates a unique name. To prevent collisions of
220 // symbols in the global namespace
221 std::string UniqueName(const std::string& name, const std::string& filename,
222 const Options& options);
UniqueName(const std::string & name,const FileDescriptor * d,const Options & options)223 inline std::string UniqueName(const std::string& name, const FileDescriptor* d,
224 const Options& options) {
225 return UniqueName(name, d->name(), options);
226 }
UniqueName(const std::string & name,const Descriptor * d,const Options & options)227 inline std::string UniqueName(const std::string& name, const Descriptor* d,
228 const Options& options) {
229 return UniqueName(name, d->file(), options);
230 }
UniqueName(const std::string & name,const EnumDescriptor * d,const Options & options)231 inline std::string UniqueName(const std::string& name, const EnumDescriptor* d,
232 const Options& options) {
233 return UniqueName(name, d->file(), options);
234 }
UniqueName(const std::string & name,const ServiceDescriptor * d,const Options & options)235 inline std::string UniqueName(const std::string& name,
236 const ServiceDescriptor* d,
237 const Options& options) {
238 return UniqueName(name, d->file(), options);
239 }
240
241 // Versions for call sites that only support the internal runtime (like proto1
242 // support).
InternalRuntimeOptions()243 inline Options InternalRuntimeOptions() {
244 Options options;
245 options.opensource_runtime = false;
246 return options;
247 }
UniqueName(const std::string & name,const std::string & filename)248 inline std::string UniqueName(const std::string& name,
249 const std::string& filename) {
250 return UniqueName(name, filename, InternalRuntimeOptions());
251 }
UniqueName(const std::string & name,const FileDescriptor * d)252 inline std::string UniqueName(const std::string& name,
253 const FileDescriptor* d) {
254 return UniqueName(name, d->name(), InternalRuntimeOptions());
255 }
UniqueName(const std::string & name,const Descriptor * d)256 inline std::string UniqueName(const std::string& name, const Descriptor* d) {
257 return UniqueName(name, d->file(), InternalRuntimeOptions());
258 }
UniqueName(const std::string & name,const EnumDescriptor * d)259 inline std::string UniqueName(const std::string& name,
260 const EnumDescriptor* d) {
261 return UniqueName(name, d->file(), InternalRuntimeOptions());
262 }
UniqueName(const std::string & name,const ServiceDescriptor * d)263 inline std::string UniqueName(const std::string& name,
264 const ServiceDescriptor* d) {
265 return UniqueName(name, d->file(), InternalRuntimeOptions());
266 }
267
268 // Return the qualified C++ name for a file level symbol.
269 std::string QualifiedFileLevelSymbol(const FileDescriptor* file,
270 const std::string& name,
271 const Options& options);
272
273 // Escape C++ trigraphs by escaping question marks to \?
274 std::string EscapeTrigraphs(const std::string& to_escape);
275
276 // Escaped function name to eliminate naming conflict.
277 std::string SafeFunctionName(const Descriptor* descriptor,
278 const FieldDescriptor* field,
279 const std::string& prefix);
280
281 // Returns true if generated messages have public unknown fields accessors
PublicUnknownFieldsAccessors(const Descriptor * message)282 inline bool PublicUnknownFieldsAccessors(const Descriptor* message) {
283 return message->file()->syntax() != FileDescriptor::SYNTAX_PROTO3;
284 }
285
286 // Returns the optimize mode for <file>, respecting <options.enforce_lite>.
287 FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file,
288 const Options& options);
289
290 // Determines whether unknown fields will be stored in an UnknownFieldSet or
291 // a string.
UseUnknownFieldSet(const FileDescriptor * file,const Options & options)292 inline bool UseUnknownFieldSet(const FileDescriptor* file,
293 const Options& options) {
294 return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME;
295 }
296
IsWeak(const FieldDescriptor * field,const Options & options)297 inline bool IsWeak(const FieldDescriptor* field, const Options& options) {
298 if (field->options().weak()) {
299 GOOGLE_CHECK(!options.opensource_runtime);
300 return true;
301 }
302 return false;
303 }
304
305 bool IsStringInlined(const FieldDescriptor* descriptor, const Options& options);
306
307 // For a string field, returns the effective ctype. If the actual ctype is
308 // not supported, returns the default of STRING.
309 FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field,
310 const Options& options);
311
IsCord(const FieldDescriptor * field,const Options & options)312 inline bool IsCord(const FieldDescriptor* field, const Options& options) {
313 return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
314 EffectiveStringCType(field, options) == FieldOptions::CORD;
315 }
316
IsStringPiece(const FieldDescriptor * field,const Options & options)317 inline bool IsStringPiece(const FieldDescriptor* field,
318 const Options& options) {
319 return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
320 EffectiveStringCType(field, options) == FieldOptions::STRING_PIECE;
321 }
322
323 // Does the given FileDescriptor use lazy fields?
324 bool HasLazyFields(const FileDescriptor* file, const Options& options);
325
326 // Is the given field a supported lazy field?
IsLazy(const FieldDescriptor * field,const Options & options)327 inline bool IsLazy(const FieldDescriptor* field, const Options& options) {
328 return field->options().lazy() && !field->is_repeated() &&
329 field->type() == FieldDescriptor::TYPE_MESSAGE &&
330 GetOptimizeFor(field->file(), options) != FileOptions::LITE_RUNTIME &&
331 !options.opensource_runtime;
332 }
333
334 // Does the file contain any definitions that need extension_set.h?
335 bool HasExtensionsOrExtendableMessage(const FileDescriptor* file);
336
337 // Does the file have any repeated fields, necessitating the file to include
338 // repeated_field.h? This does not include repeated extensions, since those are
339 // all stored internally in an ExtensionSet, not a separate RepeatedField*.
340 bool HasRepeatedFields(const FileDescriptor* file);
341
342 // Does the file have any string/bytes fields with ctype=STRING_PIECE? This
343 // does not include extensions, since ctype is ignored for extensions.
344 bool HasStringPieceFields(const FileDescriptor* file, const Options& options);
345
346 // Does the file have any string/bytes fields with ctype=CORD? This does not
347 // include extensions, since ctype is ignored for extensions.
348 bool HasCordFields(const FileDescriptor* file, const Options& options);
349
350 // Does the file have any map fields, necessitating the file to include
351 // map_field_inl.h and map.h.
352 bool HasMapFields(const FileDescriptor* file);
353
354 // Does this file have any enum type definitions?
355 bool HasEnumDefinitions(const FileDescriptor* file);
356
357 // Does this file have generated parsing, serialization, and other
358 // standard methods for which reflection-based fallback implementations exist?
HasGeneratedMethods(const FileDescriptor * file,const Options & options)359 inline bool HasGeneratedMethods(const FileDescriptor* file,
360 const Options& options) {
361 return GetOptimizeFor(file, options) != FileOptions::CODE_SIZE;
362 }
363
364 // Do message classes in this file have descriptor and reflection methods?
HasDescriptorMethods(const FileDescriptor * file,const Options & options)365 inline bool HasDescriptorMethods(const FileDescriptor* file,
366 const Options& options) {
367 return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME;
368 }
369
370 // Should we generate generic services for this file?
HasGenericServices(const FileDescriptor * file,const Options & options)371 inline bool HasGenericServices(const FileDescriptor* file,
372 const Options& options) {
373 return file->service_count() > 0 &&
374 GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME &&
375 file->options().cc_generic_services();
376 }
377
378 // Should we generate a separate, super-optimized code path for serializing to
379 // flat arrays? We don't do this in Lite mode because we'd rather reduce code
380 // size.
HasFastArraySerialization(const FileDescriptor * file,const Options & options)381 inline bool HasFastArraySerialization(const FileDescriptor* file,
382 const Options& options) {
383 return GetOptimizeFor(file, options) == FileOptions::SPEED;
384 }
385
IsProto2MessageSet(const Descriptor * descriptor,const Options & options)386 inline bool IsProto2MessageSet(const Descriptor* descriptor,
387 const Options& options) {
388 return !options.opensource_runtime &&
389 options.enforce_mode != EnforceOptimizeMode::kLiteRuntime &&
390 !options.lite_implicit_weak_fields &&
391 descriptor->options().message_set_wire_format() &&
392 descriptor->full_name() == "google.protobuf.bridge.MessageSet";
393 }
394
IsProto2MessageSetFile(const FileDescriptor * file,const Options & options)395 inline bool IsProto2MessageSetFile(const FileDescriptor* file,
396 const Options& options) {
397 return !options.opensource_runtime &&
398 options.enforce_mode != EnforceOptimizeMode::kLiteRuntime &&
399 !options.lite_implicit_weak_fields &&
400 file->name() == "net/proto2/bridge/proto/message_set.proto";
401 }
402
IsMapEntryMessage(const Descriptor * descriptor)403 inline bool IsMapEntryMessage(const Descriptor* descriptor) {
404 return descriptor->options().map_entry();
405 }
406
407 // Returns true if the field's CPPTYPE is string or message.
408 bool IsStringOrMessage(const FieldDescriptor* field);
409
410 std::string UnderscoresToCamelCase(const std::string& input,
411 bool cap_next_letter);
412
HasFieldPresence(const FileDescriptor * file)413 inline bool HasFieldPresence(const FileDescriptor* file) {
414 return file->syntax() != FileDescriptor::SYNTAX_PROTO3;
415 }
416
417 // Returns true if 'enum' semantics are such that unknown values are preserved
418 // in the enum field itself, rather than going to the UnknownFieldSet.
HasPreservingUnknownEnumSemantics(const FieldDescriptor * field)419 inline bool HasPreservingUnknownEnumSemantics(const FieldDescriptor* field) {
420 return field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3;
421 }
422
SupportsArenas(const FileDescriptor * file)423 inline bool SupportsArenas(const FileDescriptor* file) {
424 return file->options().cc_enable_arenas();
425 }
426
SupportsArenas(const Descriptor * desc)427 inline bool SupportsArenas(const Descriptor* desc) {
428 return SupportsArenas(desc->file());
429 }
430
SupportsArenas(const FieldDescriptor * field)431 inline bool SupportsArenas(const FieldDescriptor* field) {
432 return SupportsArenas(field->file());
433 }
434
IsCrossFileMessage(const FieldDescriptor * field)435 inline bool IsCrossFileMessage(const FieldDescriptor* field) {
436 return field->type() == FieldDescriptor::TYPE_MESSAGE &&
437 field->message_type()->file() != field->file();
438 }
439
MessageCreateFunction(const Descriptor * d)440 inline std::string MessageCreateFunction(const Descriptor* d) {
441 return SupportsArenas(d) ? "CreateMessage" : "Create";
442 }
443
MakeDefaultName(const FieldDescriptor * field)444 inline std::string MakeDefaultName(const FieldDescriptor* field) {
445 return "_i_give_permission_to_break_this_code_default_" + FieldName(field) +
446 "_";
447 }
448
449 bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options);
450 bool IsAnyMessage(const Descriptor* descriptor, const Options& options);
451
452 bool IsWellKnownMessage(const FileDescriptor* descriptor);
453
IncludeGuard(const FileDescriptor * file,bool pb_h,const Options & options)454 inline std::string IncludeGuard(const FileDescriptor* file, bool pb_h,
455 const Options& options) {
456 // If we are generating a .pb.h file and the proto_h option is enabled, then
457 // the .pb.h gets an extra suffix.
458 std::string filename_identifier = FilenameIdentifier(
459 file->name() + (pb_h && options.proto_h ? ".pb.h" : ""));
460
461 if (IsWellKnownMessage(file)) {
462 // For well-known messages we need third_party/protobuf and net/proto2 to
463 // have distinct include guards, because some source files include both and
464 // both need to be defined (the third_party copies will be in the
465 // google::protobuf_opensource namespace).
466 return MacroPrefix(options) + "_INCLUDED_" + filename_identifier;
467 } else {
468 // Ideally this case would use distinct include guards for opensource and
469 // google3 protos also. (The behavior of "first #included wins" is not
470 // ideal). But unfortunately some legacy code includes both and depends on
471 // the identical include guards to avoid compile errors.
472 //
473 // We should clean this up so that this case can be removed.
474 return "GOOGLE_PROTOBUF_INCLUDED_" + filename_identifier;
475 }
476 }
477
GetOptimizeFor(const FileDescriptor * file,const Options & options)478 inline FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file,
479 const Options& options) {
480 switch (options.enforce_mode) {
481 case EnforceOptimizeMode::kSpeed:
482 return FileOptions::SPEED;
483 case EnforceOptimizeMode::kLiteRuntime:
484 return FileOptions::LITE_RUNTIME;
485 case EnforceOptimizeMode::kNoEnforcement:
486 default:
487 return file->options().optimize_for();
488 }
489 }
490
491 // This orders the messages in a .pb.cc as it's outputted by file.cc
492 void FlattenMessagesInFile(const FileDescriptor* file,
493 std::vector<const Descriptor*>* result);
FlattenMessagesInFile(const FileDescriptor * file)494 inline std::vector<const Descriptor*> FlattenMessagesInFile(
495 const FileDescriptor* file) {
496 std::vector<const Descriptor*> result;
497 FlattenMessagesInFile(file, &result);
498 return result;
499 }
500
501 bool HasWeakFields(const Descriptor* desc, const Options& options);
502 bool HasWeakFields(const FileDescriptor* desc, const Options& options);
503
504 // Returns true if the "required" restriction check should be ignored for the
505 // given field.
ShouldIgnoreRequiredFieldCheck(const FieldDescriptor * field,const Options & options)506 inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field,
507 const Options& options) {
508 // Do not check "required" for lazy fields.
509 return IsLazy(field, options);
510 }
511
512 struct MessageAnalysis {
513 bool is_recursive;
514 bool contains_cord;
515 bool contains_extension;
516 bool contains_required;
517 bool constructor_requires_initialization;
518 };
519
520 // This class is used in FileGenerator, to ensure linear instead of
521 // quadratic performance, if we do this per message we would get O(V*(V+E)).
522 // Logically this is just only used in message.cc, but in the header for
523 // FileGenerator to help share it.
524 class PROTOC_EXPORT MessageSCCAnalyzer {
525 public:
MessageSCCAnalyzer(const Options & options)526 explicit MessageSCCAnalyzer(const Options& options) : options_(options) {}
527
528 MessageAnalysis GetSCCAnalysis(const SCC* scc);
529
HasRequiredFields(const Descriptor * descriptor)530 bool HasRequiredFields(const Descriptor* descriptor) {
531 MessageAnalysis result = GetSCCAnalysis(GetSCC(descriptor));
532 return result.contains_required || result.contains_extension;
533 }
GetSCC(const Descriptor * descriptor)534 const SCC* GetSCC(const Descriptor* descriptor) {
535 return analyzer_.GetSCC(descriptor);
536 }
537
538 private:
539 struct DepsGenerator {
operatorDepsGenerator540 std::vector<const Descriptor*> operator()(const Descriptor* desc) const {
541 std::vector<const Descriptor*> deps;
542 for (int i = 0; i < desc->field_count(); i++) {
543 if (desc->field(i)->message_type()) {
544 deps.push_back(desc->field(i)->message_type());
545 }
546 }
547 return deps;
548 }
549 };
550 SCCAnalyzer<DepsGenerator> analyzer_;
551 Options options_;
552 std::map<const SCC*, MessageAnalysis> analysis_cache_;
553 };
554
SccInfoSymbol(const SCC * scc,const Options & options)555 inline std::string SccInfoSymbol(const SCC* scc, const Options& options) {
556 return UniqueName("scc_info_" + ClassName(scc->GetRepresentative()),
557 scc->GetRepresentative(), options);
558 }
559
560 void ListAllFields(const Descriptor* d,
561 std::vector<const FieldDescriptor*>* fields);
562 void ListAllFields(const FileDescriptor* d,
563 std::vector<const FieldDescriptor*>* fields);
564
565 template <class T>
ForEachField(const Descriptor * d,T && func)566 void ForEachField(const Descriptor* d, T&& func) {
567 for (int i = 0; i < d->nested_type_count(); i++) {
568 ForEachField(d->nested_type(i), std::forward<T&&>(func));
569 }
570 for (int i = 0; i < d->extension_count(); i++) {
571 func(d->extension(i));
572 }
573 for (int i = 0; i < d->field_count(); i++) {
574 func(d->field(i));
575 }
576 }
577
578 template <class T>
ForEachField(const FileDescriptor * d,T && func)579 void ForEachField(const FileDescriptor* d, T&& func) {
580 for (int i = 0; i < d->message_type_count(); i++) {
581 ForEachField(d->message_type(i), std::forward<T&&>(func));
582 }
583 for (int i = 0; i < d->extension_count(); i++) {
584 func(d->extension(i));
585 }
586 }
587
588 void ListAllTypesForServices(const FileDescriptor* fd,
589 std::vector<const Descriptor*>* types);
590
591 // Indicates whether we should use implicit weak fields for this file.
592 bool UsingImplicitWeakFields(const FileDescriptor* file,
593 const Options& options);
594
595 // Indicates whether to treat this field as implicitly weak.
596 bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options,
597 MessageSCCAnalyzer* scc_analyzer);
598
599 // Formatter is a functor class which acts as a closure around printer and
600 // the variable map. It's much like printer->Print except it supports both named
601 // variables that are substituted using a key value map and direct arguments. In
602 // the format string $1$, $2$, etc... are substituted for the first, second, ...
603 // direct argument respectively in the format call, it accepts both strings and
604 // integers. The implementation verifies all arguments are used and are "first"
605 // used in order of appearance in the argument list. For example,
606 //
607 // Format("return array[$1$];", 3) -> "return array[3];"
608 // Format("array[$2$] = $1$;", "Bla", 3) -> FATAL error (wrong order)
609 // Format("array[$1$] = $2$;", 3, "Bla") -> "array[3] = Bla;"
610 //
611 // The arguments can be used more than once like
612 //
613 // Format("array[$1$] = $2$; // Index = $1$", 3, "Bla") ->
614 // "array[3] = Bla; // Index = 3"
615 //
616 // If you use more arguments use the following style to help the reader,
617 //
618 // Format("int $1$() {\n"
619 // " array[$2$] = $3$;\n"
620 // " return $4$;"
621 // "}\n",
622 // funname, // 1
623 // idx, // 2
624 // varname, // 3
625 // retval); // 4
626 //
627 // but consider using named variables. Named variables like $foo$, with some
628 // identifier foo, are looked up in the map. One additional feature is that
629 // spaces are accepted between the '$' delimiters, $ foo$ will
630 // substiture to " bar" if foo stands for "bar", but in case it's empty
631 // will substitute to "". Hence, for example,
632 //
633 // Format(vars, "$dllexport $void fun();") -> "void fun();"
634 // "__declspec(export) void fun();"
635 //
636 // which is convenient to prevent double, leading or trailing spaces.
637 class PROTOC_EXPORT Formatter {
638 public:
Formatter(io::Printer * printer)639 explicit Formatter(io::Printer* printer) : printer_(printer) {}
Formatter(io::Printer * printer,const std::map<std::string,std::string> & vars)640 Formatter(io::Printer* printer,
641 const std::map<std::string, std::string>& vars)
642 : printer_(printer), vars_(vars) {}
643
644 template <typename T>
Set(const std::string & key,const T & value)645 void Set(const std::string& key, const T& value) {
646 vars_[key] = ToString(value);
647 }
648
AddMap(const std::map<std::string,std::string> & vars)649 void AddMap(const std::map<std::string, std::string>& vars) {
650 for (const auto& keyval : vars) vars_[keyval.first] = keyval.second;
651 }
652
653 template <typename... Args>
operator()654 void operator()(const char* format, const Args&... args) const {
655 printer_->FormatInternal({ToString(args)...}, vars_, format);
656 }
657
Indent()658 void Indent() const { printer_->Indent(); }
Outdent()659 void Outdent() const { printer_->Outdent(); }
printer()660 io::Printer* printer() const { return printer_; }
661
662 class PROTOC_EXPORT SaveState {
663 public:
SaveState(Formatter * format)664 explicit SaveState(Formatter* format)
665 : format_(format), vars_(format->vars_) {}
~SaveState()666 ~SaveState() { format_->vars_.swap(vars_); }
667
668 private:
669 Formatter* format_;
670 std::map<std::string, std::string> vars_;
671 };
672
673 private:
674 io::Printer* printer_;
675 std::map<std::string, std::string> vars_;
676
677 // Convenience overloads to accept different types as arguments.
ToString(const std::string & s)678 static std::string ToString(const std::string& s) { return s; }
679 template <typename I, typename = typename std::enable_if<
680 std::is_integral<I>::value>::type>
ToString(I x)681 static std::string ToString(I x) {
682 return StrCat(x);
683 }
ToString(strings::Hex x)684 static std::string ToString(strings::Hex x) { return StrCat(x); }
ToString(const FieldDescriptor * d)685 static std::string ToString(const FieldDescriptor* d) { return Payload(d); }
ToString(const Descriptor * d)686 static std::string ToString(const Descriptor* d) { return Payload(d); }
ToString(const EnumDescriptor * d)687 static std::string ToString(const EnumDescriptor* d) { return Payload(d); }
ToString(const EnumValueDescriptor * d)688 static std::string ToString(const EnumValueDescriptor* d) {
689 return Payload(d);
690 }
ToString(const OneofDescriptor * d)691 static std::string ToString(const OneofDescriptor* d) { return Payload(d); }
692
693 template <typename Descriptor>
Payload(const Descriptor * descriptor)694 static std::string Payload(const Descriptor* descriptor) {
695 std::vector<int> path;
696 descriptor->GetLocationPath(&path);
697 GeneratedCodeInfo::Annotation annotation;
698 for (int i = 0; i < path.size(); ++i) {
699 annotation.add_path(path[i]);
700 }
701 annotation.set_source_file(descriptor->file()->name());
702 return annotation.SerializeAsString();
703 }
704 };
705
706 class PROTOC_EXPORT NamespaceOpener {
707 public:
NamespaceOpener(const Formatter & format)708 explicit NamespaceOpener(const Formatter& format)
709 : printer_(format.printer()) {}
NamespaceOpener(const std::string & name,const Formatter & format)710 NamespaceOpener(const std::string& name, const Formatter& format)
711 : NamespaceOpener(format) {
712 ChangeTo(name);
713 }
~NamespaceOpener()714 ~NamespaceOpener() { ChangeTo(""); }
715
ChangeTo(const std::string & name)716 void ChangeTo(const std::string& name) {
717 std::vector<std::string> new_stack_ =
718 Split(name, "::", true);
719 int len = std::min(name_stack_.size(), new_stack_.size());
720 int common_idx = 0;
721 while (common_idx < len) {
722 if (name_stack_[common_idx] != new_stack_[common_idx]) break;
723 common_idx++;
724 }
725 for (int i = name_stack_.size() - 1; i >= common_idx; i--) {
726 if (name_stack_[i] == "PROTOBUF_NAMESPACE_ID") {
727 printer_->Print("PROTOBUF_NAMESPACE_CLOSE\n");
728 } else {
729 printer_->Print("} // namespace $ns$\n", "ns", name_stack_[i]);
730 }
731 }
732 name_stack_.swap(new_stack_);
733 for (int i = common_idx; i < name_stack_.size(); i++) {
734 if (name_stack_[i] == "PROTOBUF_NAMESPACE_ID") {
735 printer_->Print("PROTOBUF_NAMESPACE_OPEN\n");
736 } else {
737 printer_->Print("namespace $ns$ {\n", "ns", name_stack_[i]);
738 }
739 }
740 }
741
742 private:
743 io::Printer* printer_;
744 std::vector<std::string> name_stack_;
745 };
746
747 std::string GetUtf8Suffix(const FieldDescriptor* field, const Options& options);
748 void GenerateUtf8CheckCodeForString(const FieldDescriptor* field,
749 const Options& options, bool for_parse,
750 const char* parameters,
751 const Formatter& format);
752
753 void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field,
754 const Options& options, bool for_parse,
755 const char* parameters,
756 const Formatter& format);
757
758 template <typename T>
759 struct FieldRangeImpl {
760 struct Iterator {
761 using iterator_category = std::forward_iterator_tag;
762 using value_type = const FieldDescriptor*;
763 using difference_type = int;
764
765 value_type operator*() { return descriptor->field(idx); }
766
767 friend bool operator==(const Iterator& a, const Iterator& b) {
768 GOOGLE_DCHECK(a.descriptor == b.descriptor);
769 return a.idx == b.idx;
770 }
771 friend bool operator!=(const Iterator& a, const Iterator& b) {
772 return !(a == b);
773 }
774
775 Iterator& operator++() {
776 idx++;
777 return *this;
778 }
779
780 int idx;
781 const T* descriptor;
782 };
783
beginFieldRangeImpl784 Iterator begin() const { return {0, descriptor}; }
endFieldRangeImpl785 Iterator end() const { return {descriptor->field_count(), descriptor}; }
786
787 const T* descriptor;
788 };
789
790 template <typename T>
FieldRange(const T * desc)791 FieldRangeImpl<T> FieldRange(const T* desc) {
792 return {desc};
793 }
794
795 struct OneOfRangeImpl {
796 struct Iterator {
797 using iterator_category = std::forward_iterator_tag;
798 using value_type = const OneofDescriptor*;
799 using difference_type = int;
800
801 value_type operator*() { return descriptor->oneof_decl(idx); }
802
803 friend bool operator==(const Iterator& a, const Iterator& b) {
804 GOOGLE_DCHECK(a.descriptor == b.descriptor);
805 return a.idx == b.idx;
806 }
807 friend bool operator!=(const Iterator& a, const Iterator& b) {
808 return !(a == b);
809 }
810
811 Iterator& operator++() {
812 idx++;
813 return *this;
814 }
815
816 int idx;
817 const Descriptor* descriptor;
818 };
819
beginOneOfRangeImpl820 Iterator begin() const { return {0, descriptor}; }
endOneOfRangeImpl821 Iterator end() const { return {descriptor->oneof_decl_count(), descriptor}; }
822
823 const Descriptor* descriptor;
824 };
825
OneOfRange(const Descriptor * desc)826 inline OneOfRangeImpl OneOfRange(const Descriptor* desc) { return {desc}; }
827
828 void GenerateParserLoop(const Descriptor* descriptor, int num_hasbits,
829 const Options& options,
830 MessageSCCAnalyzer* scc_analyzer, io::Printer* printer);
831
832 } // namespace cpp
833 } // namespace compiler
834 } // namespace protobuf
835 } // namespace google
836
837 #include <google/protobuf/port_undef.inc>
838
839 #endif // GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
840