• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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