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