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