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