• 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