1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file or at 6 // https://developers.google.com/open-source/licenses/bsd 7 8 // Author: kenton@google.com (Kenton Varda) 9 // Based on original Protocol Buffers design by 10 // Sanjay Ghemawat, Jeff Dean, and others. 11 // 12 // Implements parsing of .proto files to FileDescriptorProtos. 13 14 #ifndef GOOGLE_PROTOBUF_COMPILER_PARSER_H__ 15 #define GOOGLE_PROTOBUF_COMPILER_PARSER_H__ 16 17 #include <cstdint> 18 #include <string> 19 #include <type_traits> 20 #include <utility> 21 22 #include "absl/container/flat_hash_map.h" 23 #include "absl/strings/string_view.h" 24 #include "google/protobuf/descriptor.h" 25 #include "google/protobuf/descriptor.pb.h" 26 #include "google/protobuf/io/tokenizer.h" 27 #include "google/protobuf/repeated_field.h" 28 29 // Must be included last. 30 #include "google/protobuf/port_def.inc" 31 32 namespace google { 33 namespace protobuf { 34 35 class Message; 36 37 namespace compiler { 38 39 // Defined in this file. 40 class Parser; 41 class SourceLocationTable; 42 43 // Implements parsing of protocol definitions (such as .proto files). 44 // 45 // Note that most users will be more interested in the Importer class. 46 // Parser is a lower-level class which simply converts a single .proto file 47 // to a FileDescriptorProto. It does not resolve import directives or perform 48 // many other kinds of validation needed to construct a complete 49 // FileDescriptor. 50 class PROTOBUF_EXPORT Parser final { 51 public: 52 Parser(); 53 Parser(const Parser&) = delete; 54 Parser& operator=(const Parser&) = delete; 55 ~Parser(); 56 57 // Parse the entire input and construct a FileDescriptorProto representing 58 // it. Returns true if no errors occurred, false otherwise. 59 bool Parse(io::Tokenizer* input, FileDescriptorProto* file); 60 61 // Optional features: 62 63 // DEPRECATED: New code should use the SourceCodeInfo embedded in the 64 // FileDescriptorProto. 65 // 66 // Requests that locations of certain definitions be recorded to the given 67 // SourceLocationTable while parsing. This can be used to look up exact line 68 // and column numbers for errors reported by DescriptorPool during validation. 69 // Set to NULL (the default) to discard source location information. RecordSourceLocationsTo(SourceLocationTable * location_table)70 void RecordSourceLocationsTo(SourceLocationTable* location_table) { 71 source_location_table_ = location_table; 72 } 73 74 // Requests that errors be recorded to the given ErrorCollector while 75 // parsing. Set to NULL (the default) to discard error messages. RecordErrorsTo(io::ErrorCollector * error_collector)76 void RecordErrorsTo(io::ErrorCollector* error_collector) { 77 error_collector_ = error_collector; 78 } 79 80 // Returns the identifier used in the "syntax = " declaration, if one was 81 // seen during the last call to Parse(), or the empty string otherwise. GetSyntaxIdentifier()82 absl::string_view GetSyntaxIdentifier() { return syntax_identifier_; } 83 84 // If set true, input files will be required to begin with a syntax 85 // identifier. Otherwise, files may omit this. If a syntax identifier 86 // is provided, it must be 'syntax = "proto2";' and must appear at the 87 // top of this file regardless of whether or not it was required. SetRequireSyntaxIdentifier(bool value)88 void SetRequireSyntaxIdentifier(bool value) { 89 require_syntax_identifier_ = value; 90 } 91 92 // Call SetStopAfterSyntaxIdentifier(true) to tell the parser to stop 93 // parsing as soon as it has seen the syntax identifier, or lack thereof. 94 // This is useful for quickly identifying the syntax of the file without 95 // parsing the whole thing. If this is enabled, no error will be recorded 96 // if the syntax identifier is something other than "proto2" (since 97 // presumably the caller intends to deal with that), but other kinds of 98 // errors (e.g. parse errors) will still be reported. When this is enabled, 99 // you may pass a NULL FileDescriptorProto to Parse(). SetStopAfterSyntaxIdentifier(bool value)100 void SetStopAfterSyntaxIdentifier(bool value) { 101 stop_after_syntax_identifier_ = value; 102 } 103 104 private: 105 class LocationRecorder; 106 struct MapField; 107 108 // ================================================================= 109 // Error recovery helpers 110 111 // Consume the rest of the current statement. This consumes tokens 112 // until it sees one of: 113 // ';' Consumes the token and returns. 114 // '{' Consumes the brace then calls SkipRestOfBlock(). 115 // '}' Returns without consuming. 116 // EOF Returns (can't consume). 117 // The Parser often calls SkipStatement() after encountering a syntax 118 // error. This allows it to go on parsing the following lines, allowing 119 // it to report more than just one error in the file. 120 void SkipStatement(); 121 122 // Consume the rest of the current block, including nested blocks, 123 // ending after the closing '}' is encountered and consumed, or at EOF. 124 void SkipRestOfBlock(); 125 126 // ----------------------------------------------------------------- 127 // Single-token consuming helpers 128 // 129 // These make parsing code more readable. 130 131 // True if the current token is TYPE_END. 132 inline bool AtEnd(); 133 134 // True if the next token matches the given text. 135 inline bool LookingAt(absl::string_view text); 136 // True if the next token is of the given type. 137 inline bool LookingAtType(io::Tokenizer::TokenType token_type); 138 139 // If the next token exactly matches the text given, consume it and return 140 // true. Otherwise, return false without logging an error. 141 bool TryConsume(absl::string_view text); 142 143 // In the following functions the error is passed as a lazily evaluated 144 // callable to reduce stack usage and delay the actual execution of the error 145 // statement. 146 // Super simple type erasure interface. Similar to absl::FunctionRef but takes 147 // the callable by value. Optimized for lambdas with at most a single pointer 148 // as payload. 149 class ErrorMaker { 150 using StorageT = void*; 151 152 public: 153 template <typename F, 154 typename = std::enable_if_t<std::is_same< 155 std::string, decltype(std::declval<F>()())>::value>> ErrorMaker(F f)156 ErrorMaker(F f) { 157 static_assert(sizeof(F) <= sizeof(StorageT), ""); 158 static_assert(alignof(F) <= alignof(StorageT), ""); 159 static_assert(std::is_trivially_destructible<F>::value, ""); 160 ::new (static_cast<void*>(storage_)) F(f); 161 func_ = [](const void* p) { return (*reinterpret_cast<const F*>(p))(); }; 162 } 163 // This overload helps callers that just want to pass a literal string. ErrorMaker(const char * error)164 ErrorMaker(const char* error) : error_(error), func_(nullptr) {} 165 get()166 std::string get() const { return func_ ? func_(storage_) : error_; } 167 168 private: 169 union { 170 alignas(StorageT) char storage_[sizeof(StorageT)]; 171 const char* error_; 172 }; 173 std::string (*func_)(const void*); 174 }; 175 176 // These attempt to read some kind of token from the input. If successful, 177 // they return true. Otherwise they return false and add the given error 178 // to the error list. 179 180 // Consume a token with the exact text given. 181 bool Consume(absl::string_view text, ErrorMaker error); 182 // Same as above, but automatically generates the error "Expected \"text\".", 183 // where "text" is the expected token text. 184 bool Consume(absl::string_view text); 185 // Consume a token of type IDENTIFIER and store its text in "output". 186 bool ConsumeIdentifier(std::string* output, ErrorMaker error); 187 // Consume an integer and store its value in "output". 188 bool ConsumeInteger(int* output, ErrorMaker error); 189 // Consume a signed integer and store its value in "output". 190 bool ConsumeSignedInteger(int* output, ErrorMaker error); 191 // Consume a 64-bit integer and store its value in "output". If the value 192 // is greater than max_value, an error will be reported. 193 bool ConsumeInteger64(uint64_t max_value, uint64_t* output, ErrorMaker error); 194 // Try to consume a 64-bit integer and store its value in "output". No 195 // error is reported on failure, allowing caller to consume token another way. 196 bool TryConsumeInteger64(uint64_t max_value, uint64_t* output); 197 // Consume a number and store its value in "output". This will accept 198 // tokens of either INTEGER or FLOAT type. 199 bool ConsumeNumber(double* output, ErrorMaker error); 200 // Consume a string literal and store its (unescaped) value in "output". 201 bool ConsumeString(std::string* output, ErrorMaker error); 202 203 // Consume a token representing the end of the statement. Comments between 204 // this token and the next will be harvested for documentation. The given 205 // LocationRecorder should refer to the declaration that was just parsed; 206 // it will be populated with these comments. 207 // 208 // TODO: The LocationRecorder is const because historically locations 209 // have been passed around by const reference, for no particularly good 210 // reason. We should probably go through and change them all to mutable 211 // pointer to make this more intuitive. 212 bool TryConsumeEndOfDeclaration(absl::string_view text, 213 const LocationRecorder* location); 214 bool TryConsumeEndOfDeclarationFinishScope(absl::string_view text, 215 const LocationRecorder* location); 216 217 bool ConsumeEndOfDeclaration(absl::string_view text, 218 const LocationRecorder* location); 219 220 // ----------------------------------------------------------------- 221 // Error logging helpers 222 223 // Invokes error_collector_->RecordError(), if error_collector_ is not NULL. 224 PROTOBUF_NOINLINE void RecordError(int line, int column, ErrorMaker error); 225 226 // Invokes error_collector_->RecordError() with the line and column number 227 // of the current token. 228 PROTOBUF_NOINLINE void RecordError(ErrorMaker error); 229 230 // Invokes error_collector_->RecordWarning(), if error_collector_ is not NULL. 231 PROTOBUF_NOINLINE void RecordWarning(int line, int column, ErrorMaker error); 232 233 // Invokes error_collector_->RecordWarning() with the line and column number 234 // of the current token. 235 PROTOBUF_NOINLINE void RecordWarning(ErrorMaker error); 236 237 // Records a location in the SourceCodeInfo.location table (see 238 // descriptor.proto). We use RAII to ensure that the start and end locations 239 // are recorded -- the constructor records the start location and the 240 // destructor records the end location. Since the parser is 241 // recursive-descent, this works out beautifully. 242 class PROTOBUF_EXPORT LocationRecorder { 243 public: 244 // Construct the file's "root" location. 245 LocationRecorder(Parser* parser); 246 247 // Construct a location that represents a declaration nested within the 248 // given parent. E.g. a field's location is nested within the location 249 // for a message type. The parent's path will be copied, so you should 250 // call AddPath() only to add the path components leading from the parent 251 // to the child (as opposed to leading from the root to the child). 252 LocationRecorder(const LocationRecorder& parent); 253 254 // Convenience constructors that call AddPath() one or two times. 255 LocationRecorder(const LocationRecorder& parent, int path1); 256 LocationRecorder(const LocationRecorder& parent, int path1, int path2); 257 258 // Creates a recorder that generates locations into given source code info. 259 LocationRecorder(const LocationRecorder& parent, int path1, 260 SourceCodeInfo* source_code_info); 261 262 ~LocationRecorder(); 263 264 // Add a path component. See SourceCodeInfo.Location.path in 265 // descriptor.proto. 266 void AddPath(int path_component); 267 268 // By default the location is considered to start at the current token at 269 // the time the LocationRecorder is created. StartAt() sets the start 270 // location to the given token instead. 271 void StartAt(const io::Tokenizer::Token& token); 272 273 // Start at the same location as some other LocationRecorder. 274 void StartAt(const LocationRecorder& other); 275 276 // By default the location is considered to end at the previous token at 277 // the time the LocationRecorder is destroyed. EndAt() sets the end 278 // location to the given token instead. 279 void EndAt(const io::Tokenizer::Token& token); 280 281 // Records the start point of this location to the SourceLocationTable that 282 // was passed to RecordSourceLocationsTo(), if any. SourceLocationTable 283 // is an older way of keeping track of source locations which is still 284 // used in some places. 285 void RecordLegacyLocation( 286 const Message* descriptor, 287 DescriptorPool::ErrorCollector::ErrorLocation location); 288 void RecordLegacyImportLocation(const Message* descriptor, 289 const std::string& name); 290 291 // Returns the number of path components in the recorder's current location. 292 int CurrentPathSize() const; 293 294 // Attaches leading and trailing comments to the location. The two strings 295 // will be swapped into place, so after this is called *leading and 296 // *trailing will be empty. 297 // 298 // TODO: See comment on TryConsumeEndOfDeclaration(), above, for 299 // why this is const. 300 void AttachComments(std::string* leading, std::string* trailing, 301 std::vector<std::string>* detached_comments) const; 302 303 private: 304 Parser* parser_; 305 SourceCodeInfo* source_code_info_; 306 SourceCodeInfo::Location* location_; 307 308 void Init(const LocationRecorder& parent, SourceCodeInfo* source_code_info); 309 }; 310 311 // ================================================================= 312 // Parsers for various language constructs 313 314 // Parses the "syntax = \"proto2\";" line at the top of the file. Returns 315 // false if it failed to parse or if the syntax identifier was not 316 // recognized. 317 bool ParseSyntaxIdentifier(const FileDescriptorProto* file, 318 const LocationRecorder& parent); 319 320 // These methods parse various individual bits of code. They return 321 // false if they completely fail to parse the construct. In this case, 322 // it is probably necessary to skip the rest of the statement to recover. 323 // However, if these methods return true, it does NOT mean that there 324 // were no errors; only that there were no *syntax* errors. For instance, 325 // if a service method is defined using proper syntax but uses a primitive 326 // type as its input or output, ParseMethodField() still returns true 327 // and only reports the error by calling RecordError(). In practice, this 328 // makes logic much simpler for the caller. 329 330 // Parse a top-level message, enum, service, etc. 331 bool ParseTopLevelStatement(FileDescriptorProto* file, 332 const LocationRecorder& root_location); 333 334 // Parse various language high-level language construrcts. 335 bool ParseMessageDefinition(DescriptorProto* message, 336 const LocationRecorder& message_location, 337 const FileDescriptorProto* containing_file); 338 bool ParseEnumDefinition(EnumDescriptorProto* enum_type, 339 const LocationRecorder& enum_location, 340 const FileDescriptorProto* containing_file); 341 bool ParseServiceDefinition(ServiceDescriptorProto* service, 342 const LocationRecorder& service_location, 343 const FileDescriptorProto* containing_file); 344 bool ParsePackage(FileDescriptorProto* file, 345 const LocationRecorder& root_location, 346 const FileDescriptorProto* containing_file); 347 bool ParseImport(RepeatedPtrField<std::string>* dependency, 348 RepeatedField<int32_t>* public_dependency, 349 RepeatedField<int32_t>* weak_dependency, 350 const LocationRecorder& root_location, 351 const FileDescriptorProto* containing_file); 352 353 // These methods parse the contents of a message, enum, or service type and 354 // add them to the given object. They consume the entire block including 355 // the beginning and ending brace. 356 bool ParseMessageBlock(DescriptorProto* message, 357 const LocationRecorder& message_location, 358 const FileDescriptorProto* containing_file); 359 bool ParseEnumBlock(EnumDescriptorProto* enum_type, 360 const LocationRecorder& enum_location, 361 const FileDescriptorProto* containing_file); 362 bool ParseServiceBlock(ServiceDescriptorProto* service, 363 const LocationRecorder& service_location, 364 const FileDescriptorProto* containing_file); 365 366 // Parse one statement within a message, enum, or service block, including 367 // final semicolon. 368 bool ParseMessageStatement(DescriptorProto* message, 369 const LocationRecorder& message_location, 370 const FileDescriptorProto* containing_file); 371 bool ParseEnumStatement(EnumDescriptorProto* message, 372 const LocationRecorder& enum_location, 373 const FileDescriptorProto* containing_file); 374 bool ParseServiceStatement(ServiceDescriptorProto* message, 375 const LocationRecorder& service_location, 376 const FileDescriptorProto* containing_file); 377 378 // Parse a field of a message. If the field is a group, its type will be 379 // added to "messages". 380 // 381 // parent_location and location_field_number_for_nested_type are needed when 382 // parsing groups -- we need to generate a nested message type within the 383 // parent and record its location accordingly. Since the parent could be 384 // either a FileDescriptorProto or a DescriptorProto, we must pass in the 385 // correct field number to use. 386 bool ParseMessageField(FieldDescriptorProto* field, 387 RepeatedPtrField<DescriptorProto>* messages, 388 const LocationRecorder& parent_location, 389 int location_field_number_for_nested_type, 390 const LocationRecorder& field_location, 391 const FileDescriptorProto* containing_file); 392 393 // Like ParseMessageField() but expects the label has already been filled in 394 // by the caller. 395 bool ParseMessageFieldNoLabel(FieldDescriptorProto* field, 396 RepeatedPtrField<DescriptorProto>* messages, 397 const LocationRecorder& parent_location, 398 int location_field_number_for_nested_type, 399 const LocationRecorder& field_location, 400 const FileDescriptorProto* containing_file); 401 402 bool ParseMapType(MapField* map_field, FieldDescriptorProto* field, 403 LocationRecorder& type_name_location); 404 405 // Parse an "extensions" declaration. 406 bool ParseExtensions(DescriptorProto* message, 407 const LocationRecorder& extensions_location, 408 const FileDescriptorProto* containing_file); 409 410 // Parse a "reserved" declaration. 411 bool ParseReserved(DescriptorProto* message, 412 const LocationRecorder& message_location); 413 bool ParseReservedNames(DescriptorProto* message, 414 const LocationRecorder& parent_location); 415 bool ParseReservedName(std::string* name, ErrorMaker error_message); 416 bool ParseReservedIdentifiers(DescriptorProto* message, 417 const LocationRecorder& parent_location); 418 bool ParseReservedIdentifier(std::string* name, ErrorMaker error_message); 419 bool ParseReservedNumbers(DescriptorProto* message, 420 const LocationRecorder& parent_location); 421 bool ParseReserved(EnumDescriptorProto* message, 422 const LocationRecorder& message_location); 423 bool ParseReservedNames(EnumDescriptorProto* message, 424 const LocationRecorder& parent_location); 425 bool ParseReservedIdentifiers(EnumDescriptorProto* message, 426 const LocationRecorder& parent_location); 427 bool ParseReservedNumbers(EnumDescriptorProto* message, 428 const LocationRecorder& parent_location); 429 430 // Parse an "extend" declaration. (See also comments for 431 // ParseMessageField().) 432 bool ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions, 433 RepeatedPtrField<DescriptorProto>* messages, 434 const LocationRecorder& parent_location, 435 int location_field_number_for_nested_type, 436 const LocationRecorder& extend_location, 437 const FileDescriptorProto* containing_file); 438 439 // Parse a "oneof" declaration. The caller is responsible for setting 440 // oneof_decl->label() since it will have had to parse the label before it 441 // knew it was parsing a oneof. 442 bool ParseOneof(OneofDescriptorProto* oneof_decl, 443 DescriptorProto* containing_type, int oneof_index, 444 const LocationRecorder& oneof_location, 445 const LocationRecorder& containing_type_location, 446 const FileDescriptorProto* containing_file); 447 448 // Parse a single enum value within an enum block. 449 bool ParseEnumConstant(EnumValueDescriptorProto* enum_value, 450 const LocationRecorder& enum_value_location, 451 const FileDescriptorProto* containing_file); 452 453 // Parse enum constant options, i.e. the list in square brackets at the end 454 // of the enum constant value definition. 455 bool ParseEnumConstantOptions(EnumValueDescriptorProto* value, 456 const LocationRecorder& enum_value_location, 457 const FileDescriptorProto* containing_file); 458 459 // Parse a single method within a service definition. 460 bool ParseServiceMethod(MethodDescriptorProto* method, 461 const LocationRecorder& method_location, 462 const FileDescriptorProto* containing_file); 463 464 // Parse options of a single method or stream. 465 bool ParseMethodOptions(const LocationRecorder& parent_location, 466 const FileDescriptorProto* containing_file, 467 const int optionsFieldNumber, 468 Message* mutable_options); 469 470 // Parse "required", "optional", or "repeated" and fill in "label" 471 // with the value. Returns true if such a label is consumed. 472 bool ParseLabel(FieldDescriptorProto::Label* label, 473 const LocationRecorder& field_location); 474 475 // Parse a type name and fill in "type" (if it is a primitive) or 476 // "type_name" (if it is not) with the type parsed. 477 bool ParseType(FieldDescriptorProto::Type* type, std::string* type_name); 478 // Parse a user-defined type and fill in "type_name" with the name. 479 // If a primitive type is named, it is treated as an error. 480 bool ParseUserDefinedType(std::string* type_name); 481 482 // Parses field options, i.e. the stuff in square brackets at the end 483 // of a field definition. Also parses default value. 484 bool ParseFieldOptions(FieldDescriptorProto* field, 485 const LocationRecorder& field_location, 486 const FileDescriptorProto* containing_file); 487 488 // Parse the "default" option. This needs special handling because its 489 // type is the field's type. 490 bool ParseDefaultAssignment(FieldDescriptorProto* field, 491 const LocationRecorder& field_location, 492 const FileDescriptorProto* containing_file); 493 494 bool ParseJsonName(FieldDescriptorProto* field, 495 const LocationRecorder& field_location, 496 const FileDescriptorProto* containing_file); 497 498 enum OptionStyle { 499 OPTION_ASSIGNMENT, // just "name = value" 500 OPTION_STATEMENT // "option name = value;" 501 }; 502 503 // Parse a single option name/value pair, e.g. "ctype = CORD". The name 504 // identifies a field of the given Message, and the value of that field 505 // is set to the parsed value. 506 bool ParseOption(Message* options, const LocationRecorder& options_location, 507 const FileDescriptorProto* containing_file, 508 OptionStyle style); 509 510 // Parses a single part of a multipart option name. A multipart name consists 511 // of names separated by dots. Each name is either an identifier or a series 512 // of identifiers separated by dots and enclosed in parentheses. E.g., 513 // "foo.(bar.baz).moo". 514 bool ParseOptionNamePart(UninterpretedOption* uninterpreted_option, 515 const LocationRecorder& part_location, 516 const FileDescriptorProto* containing_file); 517 518 // Parses a string surrounded by balanced braces. Strips off the outer 519 // braces and stores the enclosed string in *value. 520 // E.g., 521 // { foo } *value gets 'foo' 522 // { foo { bar: box } } *value gets 'foo { bar: box }' 523 // {} *value gets '' 524 // 525 // REQUIRES: LookingAt("{") 526 // When finished successfully, we are looking at the first token past 527 // the ending brace. 528 bool ParseUninterpretedBlock(std::string* value); 529 530 struct MapField { 531 // Whether the field is a map field. 532 bool is_map_field; 533 // The types of the key and value if they are primitive types. 534 FieldDescriptorProto::Type key_type; 535 FieldDescriptorProto::Type value_type; 536 // Or the type names string if the types are customized types. 537 std::string key_type_name; 538 std::string value_type_name; 539 MapFieldMapField540 MapField() : is_map_field(false) {} 541 }; 542 // Desugar the map syntax to generate a nested map entry message. 543 void GenerateMapEntry(const MapField& map_field, FieldDescriptorProto* field, 544 RepeatedPtrField<DescriptorProto>* messages); 545 546 // Whether fields without label default to optional fields. DefaultToOptionalFields()547 bool DefaultToOptionalFields() const { 548 if (syntax_identifier_ == "editions") return true; 549 return syntax_identifier_ == "proto3"; 550 } 551 552 bool ValidateMessage(const DescriptorProto* proto); 553 bool ValidateEnum(const EnumDescriptorProto* proto); 554 555 // ================================================================= 556 557 io::Tokenizer* input_; 558 io::ErrorCollector* error_collector_; 559 SourceCodeInfo* source_code_info_; 560 SourceLocationTable* source_location_table_; // legacy 561 bool had_errors_; 562 bool require_syntax_identifier_; 563 bool stop_after_syntax_identifier_; 564 std::string syntax_identifier_; 565 Edition edition_ = Edition::EDITION_UNKNOWN; 566 int recursion_depth_; 567 568 // Leading doc comments for the next declaration. These are not complete 569 // yet; use ConsumeEndOfDeclaration() to get the complete comments. 570 std::string upcoming_doc_comments_; 571 572 // Detached comments are not connected to any syntax entities. Elements in 573 // this vector are paragraphs of comments separated by empty lines. The 574 // detached comments will be put into the leading_detached_comments field for 575 // the next element (See SourceCodeInfo.Location in descriptor.proto), when 576 // ConsumeEndOfDeclaration() is called. 577 std::vector<std::string> upcoming_detached_comments_; 578 }; 579 580 // A table mapping (descriptor, ErrorLocation) pairs -- as reported by 581 // DescriptorPool when validating descriptors -- to line and column numbers 582 // within the original source code. 583 // 584 // This is semi-obsolete: FileDescriptorProto.source_code_info now contains 585 // far more complete information about source locations. However, as of this 586 // writing you still need to use SourceLocationTable when integrating with 587 // DescriptorPool. 588 class PROTOBUF_EXPORT SourceLocationTable { 589 public: 590 SourceLocationTable(); 591 ~SourceLocationTable(); 592 593 // Finds the precise location of the given error and fills in *line and 594 // *column with the line and column numbers. If not found, sets *line to 595 // -1 and *column to 0 (since line = -1 is used to mean "error has no exact 596 // location" in the ErrorCollector interface). Returns true if found, false 597 // otherwise. 598 bool Find(const Message* descriptor, 599 DescriptorPool::ErrorCollector::ErrorLocation location, int* line, 600 int* column) const; 601 bool FindImport(const Message* descriptor, absl::string_view name, int* line, 602 int* column) const; 603 604 // Adds a location to the table. 605 void Add(const Message* descriptor, 606 DescriptorPool::ErrorCollector::ErrorLocation location, int line, 607 int column); 608 void AddImport(const Message* descriptor, const std::string& name, int line, 609 int column); 610 611 // Clears the contents of the table. 612 void Clear(); 613 614 private: 615 using LocationMap = absl::flat_hash_map< 616 std::pair<const Message*, DescriptorPool::ErrorCollector::ErrorLocation>, 617 std::pair<int, int>>; 618 LocationMap location_map_; 619 absl::flat_hash_map<std::pair<const Message*, std::string>, 620 std::pair<int, int>> 621 import_location_map_; 622 }; 623 624 } // namespace compiler 625 } // namespace protobuf 626 } // namespace google 627 628 #include "google/protobuf/port_undef.inc" 629 630 #endif // GOOGLE_PROTOBUF_COMPILER_PARSER_H__ 631