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 bool IsStringInlined(const FieldDescriptor* descriptor, const Options& options);
322
323 // For a string field, returns the effective ctype. If the actual ctype is
324 // not supported, returns the default of STRING.
325 FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field,
326 const Options& options);
327
IsCord(const FieldDescriptor * field,const Options & options)328 inline bool IsCord(const FieldDescriptor* field, const Options& options) {
329 return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
330 EffectiveStringCType(field, options) == FieldOptions::CORD;
331 }
332
IsStringPiece(const FieldDescriptor * field,const Options & options)333 inline bool IsStringPiece(const FieldDescriptor* field,
334 const Options& options) {
335 return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
336 EffectiveStringCType(field, options) == FieldOptions::STRING_PIECE;
337 }
338
339 // Does the given FileDescriptor use lazy fields?
340 bool HasLazyFields(const FileDescriptor* file, const Options& options);
341
342 // Is the given field a supported lazy field?
IsLazy(const FieldDescriptor * field,const Options & options)343 inline bool IsLazy(const FieldDescriptor* field, const Options& options) {
344 return field->options().lazy() && !field->is_repeated() &&
345 field->type() == FieldDescriptor::TYPE_MESSAGE &&
346 GetOptimizeFor(field->file(), options) != FileOptions::LITE_RUNTIME &&
347 !options.opensource_runtime;
348 }
349
350 // Returns true if "field" is used.
IsFieldUsed(const FieldDescriptor *,const Options &)351 inline bool IsFieldUsed(const FieldDescriptor* /*field*/,
352 const Options& /*options*/) {
353 return true;
354 }
355
356 // Does the file contain any definitions that need extension_set.h?
357 bool HasExtensionsOrExtendableMessage(const FileDescriptor* file);
358
359 // Does the file have any repeated fields, necessitating the file to include
360 // repeated_field.h? This does not include repeated extensions, since those are
361 // all stored internally in an ExtensionSet, not a separate RepeatedField*.
362 bool HasRepeatedFields(const FileDescriptor* file);
363
364 // Does the file have any string/bytes fields with ctype=STRING_PIECE? This
365 // does not include extensions, since ctype is ignored for extensions.
366 bool HasStringPieceFields(const FileDescriptor* file, const Options& options);
367
368 // Does the file have any string/bytes fields with ctype=CORD? This does not
369 // include extensions, since ctype is ignored for extensions.
370 bool HasCordFields(const FileDescriptor* file, const Options& options);
371
372 // Does the file have any map fields, necessitating the file to include
373 // map_field_inl.h and map.h.
374 bool HasMapFields(const FileDescriptor* file);
375
376 // Does this file have any enum type definitions?
377 bool HasEnumDefinitions(const FileDescriptor* file);
378
379 // Does this file have generated parsing, serialization, and other
380 // standard methods for which reflection-based fallback implementations exist?
HasGeneratedMethods(const FileDescriptor * file,const Options & options)381 inline bool HasGeneratedMethods(const FileDescriptor* file,
382 const Options& options) {
383 return GetOptimizeFor(file, options) != FileOptions::CODE_SIZE;
384 }
385
386 // Do message classes in this file have descriptor and reflection methods?
HasDescriptorMethods(const FileDescriptor * file,const Options & options)387 inline bool HasDescriptorMethods(const FileDescriptor* file,
388 const Options& options) {
389 return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME;
390 }
391
392 // Should we generate generic services for this file?
HasGenericServices(const FileDescriptor * file,const Options & options)393 inline bool HasGenericServices(const FileDescriptor* file,
394 const Options& options) {
395 return file->service_count() > 0 &&
396 GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME &&
397 file->options().cc_generic_services();
398 }
399
IsProto2MessageSet(const Descriptor * descriptor,const Options & options)400 inline bool IsProto2MessageSet(const Descriptor* descriptor,
401 const Options& options) {
402 return !options.opensource_runtime &&
403 options.enforce_mode != EnforceOptimizeMode::kLiteRuntime &&
404 !options.lite_implicit_weak_fields &&
405 descriptor->options().message_set_wire_format() &&
406 descriptor->full_name() == "google.protobuf.bridge.MessageSet";
407 }
408
IsProto2MessageSetFile(const FileDescriptor * file,const Options & options)409 inline bool IsProto2MessageSetFile(const FileDescriptor* file,
410 const Options& options) {
411 return !options.opensource_runtime &&
412 options.enforce_mode != EnforceOptimizeMode::kLiteRuntime &&
413 !options.lite_implicit_weak_fields &&
414 file->name() == "net/proto2/bridge/proto/message_set.proto";
415 }
416
IsMapEntryMessage(const Descriptor * descriptor)417 inline bool IsMapEntryMessage(const Descriptor* descriptor) {
418 return descriptor->options().map_entry();
419 }
420
421 // Returns true if the field's CPPTYPE is string or message.
422 bool IsStringOrMessage(const FieldDescriptor* field);
423
424 std::string UnderscoresToCamelCase(const std::string& input,
425 bool cap_next_letter);
426
HasFieldPresence(const FileDescriptor * file)427 inline bool HasFieldPresence(const FileDescriptor* file) {
428 return file->syntax() != FileDescriptor::SYNTAX_PROTO3;
429 }
430
HasHasbit(const FieldDescriptor * field)431 inline bool HasHasbit(const FieldDescriptor* field) {
432 // This predicate includes proto3 message fields only if they have "optional".
433 // Foo submsg1 = 1; // HasHasbit() == false
434 // optional Foo submsg2 = 2; // HasHasbit() == true
435 // This is slightly odd, as adding "optional" to a singular proto3 field does
436 // not change the semantics or API. However whenever any field in a message
437 // has a hasbit, it forces reflection to include hasbit offsets for *all*
438 // fields, even if almost all of them are set to -1 (no hasbit). So to avoid
439 // causing a sudden size regression for ~all proto3 messages, we give proto3
440 // message fields a hasbit only if "optional" is present. If the user is
441 // explicitly writing "optional", it is likely they are writing it on
442 // primitive fields also.
443 return (field->has_optional_keyword() || field->is_required()) &&
444 !field->options().weak();
445 }
446
447 // Returns true if 'enum' semantics are such that unknown values are preserved
448 // in the enum field itself, rather than going to the UnknownFieldSet.
HasPreservingUnknownEnumSemantics(const FieldDescriptor * field)449 inline bool HasPreservingUnknownEnumSemantics(const FieldDescriptor* field) {
450 return field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3;
451 }
452
SupportsArenas(const FileDescriptor * file)453 inline bool SupportsArenas(const FileDescriptor* file) {
454 return file->options().cc_enable_arenas();
455 }
456
SupportsArenas(const Descriptor * desc)457 inline bool SupportsArenas(const Descriptor* desc) {
458 return SupportsArenas(desc->file());
459 }
460
SupportsArenas(const FieldDescriptor * field)461 inline bool SupportsArenas(const FieldDescriptor* field) {
462 return SupportsArenas(field->file());
463 }
464
IsCrossFileMessage(const FieldDescriptor * field)465 inline bool IsCrossFileMessage(const FieldDescriptor* field) {
466 return field->type() == FieldDescriptor::TYPE_MESSAGE &&
467 field->message_type()->file() != field->file();
468 }
469
MessageCreateFunction(const Descriptor * d)470 inline std::string MessageCreateFunction(const Descriptor* d) {
471 return SupportsArenas(d) ? "CreateMessage" : "Create";
472 }
473
MakeDefaultName(const FieldDescriptor * field)474 inline std::string MakeDefaultName(const FieldDescriptor* field) {
475 return "_i_give_permission_to_break_this_code_default_" + FieldName(field) +
476 "_";
477 }
478
479 bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options);
480 bool IsAnyMessage(const Descriptor* descriptor, const Options& options);
481
482 bool IsWellKnownMessage(const FileDescriptor* descriptor);
483
IncludeGuard(const FileDescriptor * file,bool pb_h,const Options & options)484 inline std::string IncludeGuard(const FileDescriptor* file, bool pb_h,
485 const Options& options) {
486 // If we are generating a .pb.h file and the proto_h option is enabled, then
487 // the .pb.h gets an extra suffix.
488 std::string filename_identifier = FilenameIdentifier(
489 file->name() + (pb_h && options.proto_h ? ".pb.h" : ""));
490
491 if (IsWellKnownMessage(file)) {
492 // For well-known messages we need third_party/protobuf and net/proto2 to
493 // have distinct include guards, because some source files include both and
494 // both need to be defined (the third_party copies will be in the
495 // google::protobuf_opensource namespace).
496 return MacroPrefix(options) + "_INCLUDED_" + filename_identifier;
497 } else {
498 // Ideally this case would use distinct include guards for opensource and
499 // google3 protos also. (The behavior of "first #included wins" is not
500 // ideal). But unfortunately some legacy code includes both and depends on
501 // the identical include guards to avoid compile errors.
502 //
503 // We should clean this up so that this case can be removed.
504 return "GOOGLE_PROTOBUF_INCLUDED_" + filename_identifier;
505 }
506 }
507
508 // Returns the OptimizeMode for this file, furthermore it updates a status
509 // bool if has_opt_codesize_extension is non-null. If this status bool is true
510 // it means this file contains an extension that itself is defined as
511 // optimized_for = CODE_SIZE.
512 FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file,
513 const Options& options,
514 bool* has_opt_codesize_extension);
GetOptimizeFor(const FileDescriptor * file,const Options & options)515 inline FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file,
516 const Options& options) {
517 return GetOptimizeFor(file, options, nullptr);
518 }
NeedsEagerDescriptorAssignment(const FileDescriptor * file,const Options & options)519 inline bool NeedsEagerDescriptorAssignment(const FileDescriptor* file,
520 const Options& options) {
521 bool has_opt_codesize_extension;
522 if (GetOptimizeFor(file, options, &has_opt_codesize_extension) ==
523 FileOptions::CODE_SIZE &&
524 has_opt_codesize_extension) {
525 // If this filedescriptor contains an extension from another file which
526 // is optimized_for = CODE_SIZE. We need to be careful in the ordering so
527 // we eagerly build the descriptors in the dependencies before building
528 // the descriptors of this file.
529 return true;
530 } else {
531 // If we have a generated code based parser we never need eager
532 // initialization of descriptors of our deps.
533 return false;
534 }
535 }
536
537 // This orders the messages in a .pb.cc as it's outputted by file.cc
538 void FlattenMessagesInFile(const FileDescriptor* file,
539 std::vector<const Descriptor*>* result);
FlattenMessagesInFile(const FileDescriptor * file)540 inline std::vector<const Descriptor*> FlattenMessagesInFile(
541 const FileDescriptor* file) {
542 std::vector<const Descriptor*> result;
543 FlattenMessagesInFile(file, &result);
544 return result;
545 }
546
547 bool HasWeakFields(const Descriptor* desc, const Options& options);
548 bool HasWeakFields(const FileDescriptor* desc, const Options& options);
549
550 // Returns true if the "required" restriction check should be ignored for the
551 // given field.
ShouldIgnoreRequiredFieldCheck(const FieldDescriptor * field,const Options & options)552 inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field,
553 const Options& options) {
554 // Do not check "required" for lazy fields.
555 return IsLazy(field, options);
556 }
557
558 struct MessageAnalysis {
559 bool is_recursive;
560 bool contains_cord;
561 bool contains_extension;
562 bool contains_required;
563 bool constructor_requires_initialization;
564 };
565
566 // This class is used in FileGenerator, to ensure linear instead of
567 // quadratic performance, if we do this per message we would get O(V*(V+E)).
568 // Logically this is just only used in message.cc, but in the header for
569 // FileGenerator to help share it.
570 class PROTOC_EXPORT MessageSCCAnalyzer {
571 public:
MessageSCCAnalyzer(const Options & options)572 explicit MessageSCCAnalyzer(const Options& options) : options_(options) {}
573
574 MessageAnalysis GetSCCAnalysis(const SCC* scc);
575
HasRequiredFields(const Descriptor * descriptor)576 bool HasRequiredFields(const Descriptor* descriptor) {
577 MessageAnalysis result = GetSCCAnalysis(GetSCC(descriptor));
578 return result.contains_required || result.contains_extension;
579 }
GetSCC(const Descriptor * descriptor)580 const SCC* GetSCC(const Descriptor* descriptor) {
581 return analyzer_.GetSCC(descriptor);
582 }
583
584 private:
585 struct DepsGenerator {
operatorDepsGenerator586 std::vector<const Descriptor*> operator()(const Descriptor* desc) const {
587 std::vector<const Descriptor*> deps;
588 for (int i = 0; i < desc->field_count(); i++) {
589 if (desc->field(i)->message_type()) {
590 deps.push_back(desc->field(i)->message_type());
591 }
592 }
593 return deps;
594 }
595 };
596 SCCAnalyzer<DepsGenerator> analyzer_;
597 Options options_;
598 std::map<const SCC*, MessageAnalysis> analysis_cache_;
599 };
600
SccInfoSymbol(const SCC * scc,const Options & options)601 inline std::string SccInfoSymbol(const SCC* scc, const Options& options) {
602 return UniqueName("scc_info_" + ClassName(scc->GetRepresentative()),
603 scc->GetRepresentative(), options);
604 }
605
SccInfoPtrSymbol(const SCC * scc,const Options & options)606 inline std::string SccInfoPtrSymbol(const SCC* scc, const Options& options) {
607 return UniqueName("scc_info_ptr_" + ClassName(scc->GetRepresentative()),
608 scc->GetRepresentative(), options);
609 }
610
611 void ListAllFields(const Descriptor* d,
612 std::vector<const FieldDescriptor*>* fields);
613 void ListAllFields(const FileDescriptor* d,
614 std::vector<const FieldDescriptor*>* fields);
615
616 template <class T>
ForEachField(const Descriptor * d,T && func)617 void ForEachField(const Descriptor* d, T&& func) {
618 for (int i = 0; i < d->nested_type_count(); i++) {
619 ForEachField(d->nested_type(i), std::forward<T&&>(func));
620 }
621 for (int i = 0; i < d->extension_count(); i++) {
622 func(d->extension(i));
623 }
624 for (int i = 0; i < d->field_count(); i++) {
625 func(d->field(i));
626 }
627 }
628
629 template <class T>
ForEachField(const FileDescriptor * d,T && func)630 void ForEachField(const FileDescriptor* d, T&& func) {
631 for (int i = 0; i < d->message_type_count(); i++) {
632 ForEachField(d->message_type(i), std::forward<T&&>(func));
633 }
634 for (int i = 0; i < d->extension_count(); i++) {
635 func(d->extension(i));
636 }
637 }
638
639 void ListAllTypesForServices(const FileDescriptor* fd,
640 std::vector<const Descriptor*>* types);
641
642 // Indicates whether we should use implicit weak fields for this file.
643 bool UsingImplicitWeakFields(const FileDescriptor* file,
644 const Options& options);
645
646 // Indicates whether to treat this field as implicitly weak.
647 bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options,
648 MessageSCCAnalyzer* scc_analyzer);
649
650 // Formatter is a functor class which acts as a closure around printer and
651 // the variable map. It's much like printer->Print except it supports both named
652 // variables that are substituted using a key value map and direct arguments. In
653 // the format string $1$, $2$, etc... are substituted for the first, second, ...
654 // direct argument respectively in the format call, it accepts both strings and
655 // integers. The implementation verifies all arguments are used and are "first"
656 // used in order of appearance in the argument list. For example,
657 //
658 // Format("return array[$1$];", 3) -> "return array[3];"
659 // Format("array[$2$] = $1$;", "Bla", 3) -> FATAL error (wrong order)
660 // Format("array[$1$] = $2$;", 3, "Bla") -> "array[3] = Bla;"
661 //
662 // The arguments can be used more than once like
663 //
664 // Format("array[$1$] = $2$; // Index = $1$", 3, "Bla") ->
665 // "array[3] = Bla; // Index = 3"
666 //
667 // If you use more arguments use the following style to help the reader,
668 //
669 // Format("int $1$() {\n"
670 // " array[$2$] = $3$;\n"
671 // " return $4$;"
672 // "}\n",
673 // funname, // 1
674 // idx, // 2
675 // varname, // 3
676 // retval); // 4
677 //
678 // but consider using named variables. Named variables like $foo$, with some
679 // identifier foo, are looked up in the map. One additional feature is that
680 // spaces are accepted between the '$' delimiters, $ foo$ will
681 // substiture to " bar" if foo stands for "bar", but in case it's empty
682 // will substitute to "". Hence, for example,
683 //
684 // Format(vars, "$dllexport $void fun();") -> "void fun();"
685 // "__declspec(export) void fun();"
686 //
687 // which is convenient to prevent double, leading or trailing spaces.
688 class PROTOC_EXPORT Formatter {
689 public:
Formatter(io::Printer * printer)690 explicit Formatter(io::Printer* printer) : printer_(printer) {}
Formatter(io::Printer * printer,const std::map<std::string,std::string> & vars)691 Formatter(io::Printer* printer,
692 const std::map<std::string, std::string>& vars)
693 : printer_(printer), vars_(vars) {}
694
695 template <typename T>
Set(const std::string & key,const T & value)696 void Set(const std::string& key, const T& value) {
697 vars_[key] = ToString(value);
698 }
699
AddMap(const std::map<std::string,std::string> & vars)700 void AddMap(const std::map<std::string, std::string>& vars) {
701 for (const auto& keyval : vars) vars_[keyval.first] = keyval.second;
702 }
703
704 template <typename... Args>
operator()705 void operator()(const char* format, const Args&... args) const {
706 printer_->FormatInternal({ToString(args)...}, vars_, format);
707 }
708
Indent()709 void Indent() const { printer_->Indent(); }
Outdent()710 void Outdent() const { printer_->Outdent(); }
printer()711 io::Printer* printer() const { return printer_; }
712
713 class PROTOC_EXPORT SaveState {
714 public:
SaveState(Formatter * format)715 explicit SaveState(Formatter* format)
716 : format_(format), vars_(format->vars_) {}
~SaveState()717 ~SaveState() { format_->vars_.swap(vars_); }
718
719 private:
720 Formatter* format_;
721 std::map<std::string, std::string> vars_;
722 };
723
724 private:
725 io::Printer* printer_;
726 std::map<std::string, std::string> vars_;
727
728 // Convenience overloads to accept different types as arguments.
ToString(const std::string & s)729 static std::string ToString(const std::string& s) { return s; }
730 template <typename I, typename = typename std::enable_if<
731 std::is_integral<I>::value>::type>
ToString(I x)732 static std::string ToString(I x) {
733 return StrCat(x);
734 }
ToString(strings::Hex x)735 static std::string ToString(strings::Hex x) { return StrCat(x); }
ToString(const FieldDescriptor * d)736 static std::string ToString(const FieldDescriptor* d) { return Payload(d); }
ToString(const Descriptor * d)737 static std::string ToString(const Descriptor* d) { return Payload(d); }
ToString(const EnumDescriptor * d)738 static std::string ToString(const EnumDescriptor* d) { return Payload(d); }
ToString(const EnumValueDescriptor * d)739 static std::string ToString(const EnumValueDescriptor* d) {
740 return Payload(d);
741 }
ToString(const OneofDescriptor * d)742 static std::string ToString(const OneofDescriptor* d) { return Payload(d); }
743
744 template <typename Descriptor>
Payload(const Descriptor * descriptor)745 static std::string Payload(const Descriptor* descriptor) {
746 std::vector<int> path;
747 descriptor->GetLocationPath(&path);
748 GeneratedCodeInfo::Annotation annotation;
749 for (int i = 0; i < path.size(); ++i) {
750 annotation.add_path(path[i]);
751 }
752 annotation.set_source_file(descriptor->file()->name());
753 return annotation.SerializeAsString();
754 }
755 };
756
757 template <class T>
PrintFieldComment(const Formatter & format,const T * field)758 void PrintFieldComment(const Formatter& format, const T* field) {
759 // Print the field's (or oneof's) proto-syntax definition as a comment.
760 // We don't want to print group bodies so we cut off after the first
761 // line.
762 DebugStringOptions options;
763 options.elide_group_body = true;
764 options.elide_oneof_body = true;
765 std::string def = field->DebugStringWithOptions(options);
766 format("// $1$\n", def.substr(0, def.find_first_of('\n')));
767 }
768
769 class PROTOC_EXPORT NamespaceOpener {
770 public:
NamespaceOpener(const Formatter & format)771 explicit NamespaceOpener(const Formatter& format)
772 : printer_(format.printer()) {}
NamespaceOpener(const std::string & name,const Formatter & format)773 NamespaceOpener(const std::string& name, const Formatter& format)
774 : NamespaceOpener(format) {
775 ChangeTo(name);
776 }
~NamespaceOpener()777 ~NamespaceOpener() { ChangeTo(""); }
778
ChangeTo(const std::string & name)779 void ChangeTo(const std::string& name) {
780 std::vector<std::string> new_stack_ =
781 Split(name, "::", true);
782 int len = std::min(name_stack_.size(), new_stack_.size());
783 int common_idx = 0;
784 while (common_idx < len) {
785 if (name_stack_[common_idx] != new_stack_[common_idx]) break;
786 common_idx++;
787 }
788 for (int i = name_stack_.size() - 1; i >= common_idx; i--) {
789 if (name_stack_[i] == "PROTOBUF_NAMESPACE_ID") {
790 printer_->Print("PROTOBUF_NAMESPACE_CLOSE\n");
791 } else {
792 printer_->Print("} // namespace $ns$\n", "ns", name_stack_[i]);
793 }
794 }
795 name_stack_.swap(new_stack_);
796 for (int i = common_idx; i < name_stack_.size(); i++) {
797 if (name_stack_[i] == "PROTOBUF_NAMESPACE_ID") {
798 printer_->Print("PROTOBUF_NAMESPACE_OPEN\n");
799 } else {
800 printer_->Print("namespace $ns$ {\n", "ns", name_stack_[i]);
801 }
802 }
803 }
804
805 private:
806 io::Printer* printer_;
807 std::vector<std::string> name_stack_;
808 };
809
810 enum Utf8CheckMode {
811 STRICT = 0, // Parsing will fail if non UTF-8 data is in string fields.
812 VERIFY = 1, // Only log an error but parsing will succeed.
813 NONE = 2, // No UTF-8 check.
814 };
815
816 Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field,
817 const Options& options);
818
819 void GenerateUtf8CheckCodeForString(const FieldDescriptor* field,
820 const Options& options, bool for_parse,
821 const char* parameters,
822 const Formatter& format);
823
824 void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field,
825 const Options& options, bool for_parse,
826 const char* parameters,
827 const Formatter& format);
828
829 template <typename T>
830 struct FieldRangeImpl {
831 struct Iterator {
832 using iterator_category = std::forward_iterator_tag;
833 using value_type = const FieldDescriptor*;
834 using difference_type = int;
835
836 value_type operator*() { return descriptor->field(idx); }
837
838 friend bool operator==(const Iterator& a, const Iterator& b) {
839 GOOGLE_DCHECK(a.descriptor == b.descriptor);
840 return a.idx == b.idx;
841 }
842 friend bool operator!=(const Iterator& a, const Iterator& b) {
843 return !(a == b);
844 }
845
846 Iterator& operator++() {
847 idx++;
848 return *this;
849 }
850
851 int idx;
852 const T* descriptor;
853 };
854
beginFieldRangeImpl855 Iterator begin() const { return {0, descriptor}; }
endFieldRangeImpl856 Iterator end() const { return {descriptor->field_count(), descriptor}; }
857
858 const T* descriptor;
859 };
860
861 template <typename T>
FieldRange(const T * desc)862 FieldRangeImpl<T> FieldRange(const T* desc) {
863 return {desc};
864 }
865
866 struct OneOfRangeImpl {
867 struct Iterator {
868 using iterator_category = std::forward_iterator_tag;
869 using value_type = const OneofDescriptor*;
870 using difference_type = int;
871
872 value_type operator*() { return descriptor->oneof_decl(idx); }
873
874 friend bool operator==(const Iterator& a, const Iterator& b) {
875 GOOGLE_DCHECK(a.descriptor == b.descriptor);
876 return a.idx == b.idx;
877 }
878 friend bool operator!=(const Iterator& a, const Iterator& b) {
879 return !(a == b);
880 }
881
882 Iterator& operator++() {
883 idx++;
884 return *this;
885 }
886
887 int idx;
888 const Descriptor* descriptor;
889 };
890
beginOneOfRangeImpl891 Iterator begin() const { return {0, descriptor}; }
endOneOfRangeImpl892 Iterator end() const {
893 return {descriptor->real_oneof_decl_count(), descriptor};
894 }
895
896 const Descriptor* descriptor;
897 };
898
OneOfRange(const Descriptor * desc)899 inline OneOfRangeImpl OneOfRange(const Descriptor* desc) { return {desc}; }
900
901 void GenerateParserLoop(const Descriptor* descriptor, int num_hasbits,
902 const Options& options,
903 MessageSCCAnalyzer* scc_analyzer, io::Printer* printer);
904
905 } // namespace cpp
906 } // namespace compiler
907 } // namespace protobuf
908 } // namespace google
909
910 #include <google/protobuf/port_undef.inc>
911
912 #endif // GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
913