Index: third_party/protobuf/src/google/protobuf/compiler/parser.cc |
diff --git a/third_party/protobuf/src/google/protobuf/compiler/parser.cc b/third_party/protobuf/src/google/protobuf/compiler/parser.cc |
index 9fcb13149fcf135ccd06630622709af036cb3901..34317b1fd94fb0c162f1ae85766185f5f3d9a57c 100644 |
--- a/third_party/protobuf/src/google/protobuf/compiler/parser.cc |
+++ b/third_party/protobuf/src/google/protobuf/compiler/parser.cc |
@@ -250,20 +250,69 @@ void Parser::AddError(const string& error) { |
AddError(input_->current().line, input_->current().column, error); |
} |
-void Parser::RecordLocation( |
- const Message* descriptor, |
- DescriptorPool::ErrorCollector::ErrorLocation location, |
- int line, int column) { |
- if (source_location_table_ != NULL) { |
- source_location_table_->Add(descriptor, location, line, column); |
+// ------------------------------------------------------------------- |
+ |
+Parser::LocationRecorder::LocationRecorder(Parser* parser) |
+ : parser_(parser), |
+ location_(parser_->source_code_info_->add_location()) { |
+ location_->add_span(parser_->input_->current().line); |
+ location_->add_span(parser_->input_->current().column); |
+} |
+ |
+Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent) { |
+ Init(parent); |
+} |
+ |
+Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent, |
+ int path1) { |
+ Init(parent); |
+ AddPath(path1); |
+} |
+ |
+Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent, |
+ int path1, int path2) { |
+ Init(parent); |
+ AddPath(path1); |
+ AddPath(path2); |
+} |
+ |
+void Parser::LocationRecorder::Init(const LocationRecorder& parent) { |
+ parser_ = parent.parser_; |
+ location_ = parser_->source_code_info_->add_location(); |
+ location_->mutable_path()->CopyFrom(parent.location_->path()); |
+ |
+ location_->add_span(parser_->input_->current().line); |
+ location_->add_span(parser_->input_->current().column); |
+} |
+ |
+Parser::LocationRecorder::~LocationRecorder() { |
+ if (location_->span_size() <= 2) { |
+ EndAt(parser_->input_->previous()); |
} |
} |
-void Parser::RecordLocation( |
- const Message* descriptor, |
+void Parser::LocationRecorder::AddPath(int path_component) { |
+ location_->add_path(path_component); |
+} |
+ |
+void Parser::LocationRecorder::StartAt(const io::Tokenizer::Token& token) { |
+ location_->set_span(0, token.line); |
+ location_->set_span(1, token.column); |
+} |
+ |
+void Parser::LocationRecorder::EndAt(const io::Tokenizer::Token& token) { |
+ if (token.line != location_->span(0)) { |
+ location_->add_span(token.line); |
+ } |
+ location_->add_span(token.end_column); |
+} |
+ |
+void Parser::LocationRecorder::RecordLegacyLocation(const Message* descriptor, |
DescriptorPool::ErrorCollector::ErrorLocation location) { |
- RecordLocation(descriptor, location, |
- input_->current().line, input_->current().column); |
+ if (parser_->source_location_table_ != NULL) { |
+ parser_->source_location_table_->Add( |
+ descriptor, location, location_->span(0), location_->span(1)); |
+ } |
} |
// ------------------------------------------------------------------- |
@@ -308,38 +357,51 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) { |
had_errors_ = false; |
syntax_identifier_.clear(); |
+ // Note that |file| could be NULL at this point if |
+ // stop_after_syntax_identifier_ is true. So, we conservatively allocate |
+ // SourceCodeInfo on the stack, then swap it into the FileDescriptorProto |
+ // later on. |
+ SourceCodeInfo source_code_info; |
+ source_code_info_ = &source_code_info; |
+ |
if (LookingAtType(io::Tokenizer::TYPE_START)) { |
// Advance to first token. |
input_->Next(); |
} |
- if (require_syntax_identifier_ || LookingAt("syntax")) { |
- if (!ParseSyntaxIdentifier()) { |
- // Don't attempt to parse the file if we didn't recognize the syntax |
- // identifier. |
- return false; |
+ { |
+ LocationRecorder root_location(this); |
+ |
+ if (require_syntax_identifier_ || LookingAt("syntax")) { |
+ if (!ParseSyntaxIdentifier()) { |
+ // Don't attempt to parse the file if we didn't recognize the syntax |
+ // identifier. |
+ return false; |
+ } |
+ } else if (!stop_after_syntax_identifier_) { |
+ syntax_identifier_ = "proto2"; |
} |
- } else if (!stop_after_syntax_identifier_) { |
- syntax_identifier_ = "proto2"; |
- } |
- if (stop_after_syntax_identifier_) return !had_errors_; |
+ if (stop_after_syntax_identifier_) return !had_errors_; |
- // Repeatedly parse statements until we reach the end of the file. |
- while (!AtEnd()) { |
- if (!ParseTopLevelStatement(file)) { |
- // This statement failed to parse. Skip it, but keep looping to parse |
- // other statements. |
- SkipStatement(); |
+ // Repeatedly parse statements until we reach the end of the file. |
+ while (!AtEnd()) { |
+ if (!ParseTopLevelStatement(file, root_location)) { |
+ // This statement failed to parse. Skip it, but keep looping to parse |
+ // other statements. |
+ SkipStatement(); |
- if (LookingAt("}")) { |
- AddError("Unmatched \"}\"."); |
- input_->Next(); |
+ if (LookingAt("}")) { |
+ AddError("Unmatched \"}\"."); |
+ input_->Next(); |
+ } |
} |
} |
} |
input_ = NULL; |
+ source_code_info_ = NULL; |
+ source_code_info.Swap(file->mutable_source_code_info()); |
return !had_errors_; |
} |
@@ -363,25 +425,40 @@ bool Parser::ParseSyntaxIdentifier() { |
return true; |
} |
-bool Parser::ParseTopLevelStatement(FileDescriptorProto* file) { |
+bool Parser::ParseTopLevelStatement(FileDescriptorProto* file, |
+ const LocationRecorder& root_location) { |
if (TryConsume(";")) { |
// empty statement; ignore |
return true; |
} else if (LookingAt("message")) { |
- return ParseMessageDefinition(file->add_message_type()); |
+ LocationRecorder location(root_location, |
+ FileDescriptorProto::kMessageTypeFieldNumber, file->message_type_size()); |
+ return ParseMessageDefinition(file->add_message_type(), location); |
} else if (LookingAt("enum")) { |
- return ParseEnumDefinition(file->add_enum_type()); |
+ LocationRecorder location(root_location, |
+ FileDescriptorProto::kEnumTypeFieldNumber, file->enum_type_size()); |
+ return ParseEnumDefinition(file->add_enum_type(), location); |
} else if (LookingAt("service")) { |
- return ParseServiceDefinition(file->add_service()); |
+ LocationRecorder location(root_location, |
+ FileDescriptorProto::kServiceFieldNumber, file->service_size()); |
+ return ParseServiceDefinition(file->add_service(), location); |
} else if (LookingAt("extend")) { |
+ LocationRecorder location(root_location, |
+ FileDescriptorProto::kExtensionFieldNumber); |
return ParseExtend(file->mutable_extension(), |
- file->mutable_message_type()); |
+ file->mutable_message_type(), |
+ root_location, |
+ FileDescriptorProto::kMessageTypeFieldNumber, |
+ location); |
} else if (LookingAt("import")) { |
- return ParseImport(file->add_dependency()); |
+ int index = file->dependency_size(); |
+ return ParseImport(file->add_dependency(), root_location, index); |
} else if (LookingAt("package")) { |
- return ParsePackage(file); |
+ return ParsePackage(file, root_location); |
} else if (LookingAt("option")) { |
- return ParseOption(file->mutable_options()); |
+ LocationRecorder location(root_location, |
+ FileDescriptorProto::kOptionsFieldNumber); |
+ return ParseOption(file->mutable_options(), location); |
} else { |
AddError("Expected top-level statement (e.g. \"message\")."); |
return false; |
@@ -391,15 +468,22 @@ bool Parser::ParseTopLevelStatement(FileDescriptorProto* file) { |
// ------------------------------------------------------------------- |
// Messages |
-bool Parser::ParseMessageDefinition(DescriptorProto* message) { |
+bool Parser::ParseMessageDefinition(DescriptorProto* message, |
+ const LocationRecorder& message_location) { |
DO(Consume("message")); |
- RecordLocation(message, DescriptorPool::ErrorCollector::NAME); |
- DO(ConsumeIdentifier(message->mutable_name(), "Expected message name.")); |
- DO(ParseMessageBlock(message)); |
+ { |
+ LocationRecorder location(message_location, |
+ DescriptorProto::kNameFieldNumber); |
+ location.RecordLegacyLocation( |
+ message, DescriptorPool::ErrorCollector::NAME); |
+ DO(ConsumeIdentifier(message->mutable_name(), "Expected message name.")); |
+ } |
+ DO(ParseMessageBlock(message, message_location)); |
return true; |
} |
-bool Parser::ParseMessageBlock(DescriptorProto* message) { |
+bool Parser::ParseMessageBlock(DescriptorProto* message, |
+ const LocationRecorder& message_location) { |
DO(Consume("{")); |
while (!TryConsume("}")) { |
@@ -408,7 +492,7 @@ bool Parser::ParseMessageBlock(DescriptorProto* message) { |
return false; |
} |
- if (!ParseMessageStatement(message)) { |
+ if (!ParseMessageStatement(message, message_location)) { |
// This statement failed to parse. Skip it, but keep looping to parse |
// other statements. |
SkipStatement(); |
@@ -418,66 +502,133 @@ bool Parser::ParseMessageBlock(DescriptorProto* message) { |
return true; |
} |
-bool Parser::ParseMessageStatement(DescriptorProto* message) { |
+bool Parser::ParseMessageStatement(DescriptorProto* message, |
+ const LocationRecorder& message_location) { |
if (TryConsume(";")) { |
// empty statement; ignore |
return true; |
} else if (LookingAt("message")) { |
- return ParseMessageDefinition(message->add_nested_type()); |
+ LocationRecorder location(message_location, |
+ DescriptorProto::kNestedTypeFieldNumber, |
+ message->nested_type_size()); |
+ return ParseMessageDefinition(message->add_nested_type(), location); |
} else if (LookingAt("enum")) { |
- return ParseEnumDefinition(message->add_enum_type()); |
+ LocationRecorder location(message_location, |
+ DescriptorProto::kEnumTypeFieldNumber, |
+ message->enum_type_size()); |
+ return ParseEnumDefinition(message->add_enum_type(), location); |
} else if (LookingAt("extensions")) { |
- return ParseExtensions(message); |
+ LocationRecorder location(message_location, |
+ DescriptorProto::kExtensionRangeFieldNumber); |
+ return ParseExtensions(message, location); |
} else if (LookingAt("extend")) { |
+ LocationRecorder location(message_location, |
+ DescriptorProto::kExtensionFieldNumber); |
return ParseExtend(message->mutable_extension(), |
- message->mutable_nested_type()); |
+ message->mutable_nested_type(), |
+ message_location, |
+ DescriptorProto::kNestedTypeFieldNumber, |
+ location); |
} else if (LookingAt("option")) { |
- return ParseOption(message->mutable_options()); |
+ LocationRecorder location(message_location, |
+ DescriptorProto::kOptionsFieldNumber); |
+ return ParseOption(message->mutable_options(), location); |
} else { |
+ LocationRecorder location(message_location, |
+ DescriptorProto::kFieldFieldNumber, |
+ message->field_size()); |
return ParseMessageField(message->add_field(), |
- message->mutable_nested_type()); |
+ message->mutable_nested_type(), |
+ message_location, |
+ DescriptorProto::kNestedTypeFieldNumber, |
+ location); |
} |
} |
bool Parser::ParseMessageField(FieldDescriptorProto* field, |
- RepeatedPtrField<DescriptorProto>* messages) { |
+ RepeatedPtrField<DescriptorProto>* messages, |
+ const LocationRecorder& parent_location, |
+ int location_field_number_for_nested_type, |
+ const LocationRecorder& field_location) { |
// Parse label and type. |
- FieldDescriptorProto::Label label; |
- DO(ParseLabel(&label)); |
- field->set_label(label); |
- |
- RecordLocation(field, DescriptorPool::ErrorCollector::TYPE); |
- FieldDescriptorProto::Type type = FieldDescriptorProto::TYPE_INT32; |
- string type_name; |
- DO(ParseType(&type, &type_name)); |
- if (type_name.empty()) { |
- field->set_type(type); |
- } else { |
- field->set_type_name(type_name); |
+ io::Tokenizer::Token label_token = input_->current(); |
+ { |
+ LocationRecorder location(field_location, |
+ FieldDescriptorProto::kLabelFieldNumber); |
+ FieldDescriptorProto::Label label; |
+ DO(ParseLabel(&label)); |
+ field->set_label(label); |
+ } |
+ |
+ { |
+ LocationRecorder location(field_location); // add path later |
+ location.RecordLegacyLocation(field, DescriptorPool::ErrorCollector::TYPE); |
+ |
+ FieldDescriptorProto::Type type = FieldDescriptorProto::TYPE_INT32; |
+ string type_name; |
+ DO(ParseType(&type, &type_name)); |
+ if (type_name.empty()) { |
+ location.AddPath(FieldDescriptorProto::kTypeFieldNumber); |
+ field->set_type(type); |
+ } else { |
+ location.AddPath(FieldDescriptorProto::kTypeNameFieldNumber); |
+ field->set_type_name(type_name); |
+ } |
} |
// Parse name and '='. |
- RecordLocation(field, DescriptorPool::ErrorCollector::NAME); |
io::Tokenizer::Token name_token = input_->current(); |
- DO(ConsumeIdentifier(field->mutable_name(), "Expected field name.")); |
+ { |
+ LocationRecorder location(field_location, |
+ FieldDescriptorProto::kNameFieldNumber); |
+ location.RecordLegacyLocation(field, DescriptorPool::ErrorCollector::NAME); |
+ DO(ConsumeIdentifier(field->mutable_name(), "Expected field name.")); |
+ } |
DO(Consume("=", "Missing field number.")); |
// Parse field number. |
- RecordLocation(field, DescriptorPool::ErrorCollector::NUMBER); |
- int number; |
- DO(ConsumeInteger(&number, "Expected field number.")); |
- field->set_number(number); |
+ { |
+ LocationRecorder location(field_location, |
+ FieldDescriptorProto::kNumberFieldNumber); |
+ location.RecordLegacyLocation( |
+ field, DescriptorPool::ErrorCollector::NUMBER); |
+ int number; |
+ DO(ConsumeInteger(&number, "Expected field number.")); |
+ field->set_number(number); |
+ } |
// Parse options. |
- DO(ParseFieldOptions(field)); |
+ DO(ParseFieldOptions(field, field_location)); |
// Deal with groups. |
- if (type_name.empty() && type == FieldDescriptorProto::TYPE_GROUP) { |
+ if (field->has_type() && field->type() == FieldDescriptorProto::TYPE_GROUP) { |
+ // Awkward: Since a group declares both a message type and a field, we |
+ // have to create overlapping locations. |
+ LocationRecorder group_location(parent_location); |
+ group_location.StartAt(label_token); |
+ group_location.AddPath(location_field_number_for_nested_type); |
+ group_location.AddPath(messages->size()); |
+ |
DescriptorProto* group = messages->Add(); |
group->set_name(field->name()); |
+ |
// Record name location to match the field name's location. |
- RecordLocation(group, DescriptorPool::ErrorCollector::NAME, |
- name_token.line, name_token.column); |
+ { |
+ LocationRecorder location(group_location, |
+ DescriptorProto::kNameFieldNumber); |
+ location.StartAt(name_token); |
+ location.EndAt(name_token); |
+ location.RecordLegacyLocation( |
+ group, DescriptorPool::ErrorCollector::NAME); |
+ } |
+ |
+ // The field's type_name also comes from the name. Confusing! |
+ { |
+ LocationRecorder location(field_location, |
+ FieldDescriptorProto::kTypeNameFieldNumber); |
+ location.StartAt(name_token); |
+ location.EndAt(name_token); |
+ } |
// As a hack for backwards-compatibility, we force the group name to start |
// with a capital letter and lower-case the field name. New code should |
@@ -490,7 +641,7 @@ bool Parser::ParseMessageField(FieldDescriptorProto* field, |
field->set_type_name(group->name()); |
if (LookingAt("{")) { |
- DO(ParseMessageBlock(group)); |
+ DO(ParseMessageBlock(group, group_location)); |
} else { |
AddError("Missing group body."); |
return false; |
@@ -502,15 +653,23 @@ bool Parser::ParseMessageField(FieldDescriptorProto* field, |
return true; |
} |
-bool Parser::ParseFieldOptions(FieldDescriptorProto* field) { |
- if (!TryConsume("[")) return true; |
+bool Parser::ParseFieldOptions(FieldDescriptorProto* field, |
+ const LocationRecorder& field_location) { |
+ if (!LookingAt("[")) return true; |
+ |
+ LocationRecorder location(field_location, |
+ FieldDescriptorProto::kOptionsFieldNumber); |
+ |
+ DO(Consume("[")); |
// Parse field options. |
do { |
if (LookingAt("default")) { |
- DO(ParseDefaultAssignment(field)); |
+ // We intentionally pass field_location rather than location here, since |
+ // the default value is not actually an option. |
+ DO(ParseDefaultAssignment(field, field_location)); |
} else { |
- DO(ParseOptionAssignment(field->mutable_options())); |
+ DO(ParseOptionAssignment(field->mutable_options(), location)); |
} |
} while (TryConsume(",")); |
@@ -518,7 +677,8 @@ bool Parser::ParseFieldOptions(FieldDescriptorProto* field) { |
return true; |
} |
-bool Parser::ParseDefaultAssignment(FieldDescriptorProto* field) { |
+bool Parser::ParseDefaultAssignment(FieldDescriptorProto* field, |
+ const LocationRecorder& field_location) { |
if (field->has_default_value()) { |
AddError("Already set option \"default\"."); |
field->clear_default_value(); |
@@ -527,7 +687,10 @@ bool Parser::ParseDefaultAssignment(FieldDescriptorProto* field) { |
DO(Consume("default")); |
DO(Consume("=")); |
- RecordLocation(field, DescriptorPool::ErrorCollector::DEFAULT_VALUE); |
+ LocationRecorder location(field_location, |
+ FieldDescriptorProto::kDefaultValueFieldNumber); |
+ location.RecordLegacyLocation( |
+ field, DescriptorPool::ErrorCollector::DEFAULT_VALUE); |
string* default_value = field->mutable_default_value(); |
if (!field->has_type()) { |
@@ -634,26 +797,35 @@ bool Parser::ParseDefaultAssignment(FieldDescriptorProto* field) { |
return true; |
} |
-bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option) { |
+bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option, |
+ const LocationRecorder& part_location) { |
UninterpretedOption::NamePart* name = uninterpreted_option->add_name(); |
string identifier; // We parse identifiers into this string. |
if (LookingAt("(")) { // This is an extension. |
DO(Consume("(")); |
- // An extension name consists of dot-separated identifiers, and may begin |
- // with a dot. |
- if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) { |
- DO(ConsumeIdentifier(&identifier, "Expected identifier.")); |
- name->mutable_name_part()->append(identifier); |
- } |
- while (LookingAt(".")) { |
- DO(Consume(".")); |
- name->mutable_name_part()->append("."); |
- DO(ConsumeIdentifier(&identifier, "Expected identifier.")); |
- name->mutable_name_part()->append(identifier); |
+ |
+ { |
+ LocationRecorder location( |
+ part_location, UninterpretedOption::NamePart::kNamePartFieldNumber); |
+ // An extension name consists of dot-separated identifiers, and may begin |
+ // with a dot. |
+ if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) { |
+ DO(ConsumeIdentifier(&identifier, "Expected identifier.")); |
+ name->mutable_name_part()->append(identifier); |
+ } |
+ while (LookingAt(".")) { |
+ DO(Consume(".")); |
+ name->mutable_name_part()->append("."); |
+ DO(ConsumeIdentifier(&identifier, "Expected identifier.")); |
+ name->mutable_name_part()->append(identifier); |
+ } |
} |
+ |
DO(Consume(")")); |
name->set_is_extension(true); |
} else { // This is a regular field. |
+ LocationRecorder location( |
+ part_location, UninterpretedOption::NamePart::kNamePartFieldNumber); |
DO(ConsumeIdentifier(&identifier, "Expected identifier.")); |
name->mutable_name_part()->append(identifier); |
name->set_is_extension(false); |
@@ -661,34 +833,75 @@ bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option) { |
return true; |
} |
+bool Parser::ParseUninterpretedBlock(string* value) { |
+ // Note that enclosing braces are not added to *value. |
+ DO(Consume("{")); |
+ int brace_depth = 1; |
+ while (!AtEnd()) { |
+ if (LookingAt("{")) { |
+ brace_depth++; |
+ } else if (LookingAt("}")) { |
+ brace_depth--; |
+ if (brace_depth == 0) { |
+ input_->Next(); |
+ return true; |
+ } |
+ } |
+ // TODO(sanjay): Interpret line/column numbers to preserve formatting |
+ if (!value->empty()) value->push_back(' '); |
+ value->append(input_->current().text); |
+ input_->Next(); |
+ } |
+ AddError("Unexpected end of stream while parsing aggregate value."); |
+ return false; |
+} |
+ |
// We don't interpret the option here. Instead we store it in an |
// UninterpretedOption, to be interpreted later. |
-bool Parser::ParseOptionAssignment(Message* options) { |
+bool Parser::ParseOptionAssignment(Message* options, |
+ const LocationRecorder& options_location) { |
// Create an entry in the uninterpreted_option field. |
const FieldDescriptor* uninterpreted_option_field = options->GetDescriptor()-> |
FindFieldByName("uninterpreted_option"); |
GOOGLE_CHECK(uninterpreted_option_field != NULL) |
<< "No field named \"uninterpreted_option\" in the Options proto."; |
+ const Reflection* reflection = options->GetReflection(); |
+ |
+ LocationRecorder location( |
+ options_location, uninterpreted_option_field->number(), |
+ reflection->FieldSize(*options, uninterpreted_option_field)); |
+ |
UninterpretedOption* uninterpreted_option = down_cast<UninterpretedOption*>( |
options->GetReflection()->AddMessage(options, |
uninterpreted_option_field)); |
// Parse dot-separated name. |
- RecordLocation(uninterpreted_option, |
- DescriptorPool::ErrorCollector::OPTION_NAME); |
- |
- DO(ParseOptionNamePart(uninterpreted_option)); |
+ { |
+ LocationRecorder name_location(location, |
+ UninterpretedOption::kNameFieldNumber); |
+ name_location.RecordLegacyLocation( |
+ uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_NAME); |
+ |
+ { |
+ LocationRecorder part_location(name_location, |
+ uninterpreted_option->name_size()); |
+ DO(ParseOptionNamePart(uninterpreted_option, part_location)); |
+ } |
- while (LookingAt(".")) { |
- DO(Consume(".")); |
- DO(ParseOptionNamePart(uninterpreted_option)); |
+ while (LookingAt(".")) { |
+ DO(Consume(".")); |
+ LocationRecorder part_location(name_location, |
+ uninterpreted_option->name_size()); |
+ DO(ParseOptionNamePart(uninterpreted_option, part_location)); |
+ } |
} |
DO(Consume("=")); |
- RecordLocation(uninterpreted_option, |
- DescriptorPool::ErrorCollector::OPTION_VALUE); |
+ LocationRecorder value_location(location); |
+ value_location.RecordLegacyLocation( |
+ uninterpreted_option, DescriptorPool::ErrorCollector::OPTION_VALUE); |
// All values are a single token, except for negative numbers, which consist |
// of a single '-' symbol, followed by a positive number. |
@@ -704,6 +917,7 @@ bool Parser::ParseOptionAssignment(Message* options) { |
return false; |
case io::Tokenizer::TYPE_IDENTIFIER: { |
+ value_location.AddPath(UninterpretedOption::kIdentifierValueFieldNumber); |
if (is_negative) { |
AddError("Invalid '-' symbol before identifier."); |
return false; |
@@ -720,15 +934,19 @@ bool Parser::ParseOptionAssignment(Message* options) { |
is_negative ? static_cast<uint64>(kint64max) + 1 : kuint64max; |
DO(ConsumeInteger64(max_value, &value, "Expected integer.")); |
if (is_negative) { |
- uninterpreted_option->set_negative_int_value( |
- -static_cast<int64>(value)); |
+ value_location.AddPath( |
+ UninterpretedOption::kNegativeIntValueFieldNumber); |
+ uninterpreted_option->set_negative_int_value(-static_cast<int64>(value)); |
} else { |
+ value_location.AddPath( |
+ UninterpretedOption::kPositiveIntValueFieldNumber); |
uninterpreted_option->set_positive_int_value(value); |
} |
break; |
} |
case io::Tokenizer::TYPE_FLOAT: { |
+ value_location.AddPath(UninterpretedOption::kDoubleValueFieldNumber); |
double value; |
DO(ConsumeNumber(&value, "Expected number.")); |
uninterpreted_option->set_double_value(is_negative ? -value : value); |
@@ -736,6 +954,7 @@ bool Parser::ParseOptionAssignment(Message* options) { |
} |
case io::Tokenizer::TYPE_STRING: { |
+ value_location.AddPath(UninterpretedOption::kStringValueFieldNumber); |
if (is_negative) { |
AddError("Invalid '-' symbol before string."); |
return false; |
@@ -747,31 +966,57 @@ bool Parser::ParseOptionAssignment(Message* options) { |
} |
case io::Tokenizer::TYPE_SYMBOL: |
- AddError("Expected option value."); |
- return false; |
+ if (LookingAt("{")) { |
+ value_location.AddPath(UninterpretedOption::kAggregateValueFieldNumber); |
+ DO(ParseUninterpretedBlock( |
+ uninterpreted_option->mutable_aggregate_value())); |
+ } else { |
+ AddError("Expected option value."); |
+ return false; |
+ } |
+ break; |
} |
return true; |
} |
-bool Parser::ParseExtensions(DescriptorProto* message) { |
+bool Parser::ParseExtensions(DescriptorProto* message, |
+ const LocationRecorder& extensions_location) { |
// Parse the declaration. |
DO(Consume("extensions")); |
do { |
+ // Note that kExtensionRangeFieldNumber was already pushed by the parent. |
+ LocationRecorder location(extensions_location, |
+ message->extension_range_size()); |
+ |
DescriptorProto::ExtensionRange* range = message->add_extension_range(); |
- RecordLocation(range, DescriptorPool::ErrorCollector::NUMBER); |
+ location.RecordLegacyLocation( |
+ range, DescriptorPool::ErrorCollector::NUMBER); |
int start, end; |
- DO(ConsumeInteger(&start, "Expected field number range.")); |
+ io::Tokenizer::Token start_token; |
+ |
+ { |
+ LocationRecorder start_location( |
+ location, DescriptorProto::ExtensionRange::kStartFieldNumber); |
+ start_token = input_->current(); |
+ DO(ConsumeInteger(&start, "Expected field number range.")); |
+ } |
if (TryConsume("to")) { |
+ LocationRecorder end_location( |
+ location, DescriptorProto::ExtensionRange::kEndFieldNumber); |
if (TryConsume("max")) { |
end = FieldDescriptor::kMaxNumber; |
} else { |
DO(ConsumeInteger(&end, "Expected integer.")); |
} |
} else { |
+ LocationRecorder end_location( |
+ location, DescriptorProto::ExtensionRange::kEndFieldNumber); |
+ end_location.StartAt(start_token); |
+ end_location.EndAt(start_token); |
end = start; |
} |
@@ -788,16 +1033,17 @@ bool Parser::ParseExtensions(DescriptorProto* message) { |
} |
bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions, |
- RepeatedPtrField<DescriptorProto>* messages) { |
+ RepeatedPtrField<DescriptorProto>* messages, |
+ const LocationRecorder& parent_location, |
+ int location_field_number_for_nested_type, |
+ const LocationRecorder& extend_location) { |
DO(Consume("extend")); |
- // We expect to see at least one extension field defined in the extend block. |
- // We need to create it now so we can record the extendee's location. |
- FieldDescriptorProto* first_field = extensions->Add(); |
- |
// Parse the extendee type. |
- RecordLocation(first_field, DescriptorPool::ErrorCollector::EXTENDEE); |
- DO(ParseUserDefinedType(first_field->mutable_extendee())); |
+ io::Tokenizer::Token extendee_start = input_->current(); |
+ string extendee; |
+ DO(ParseUserDefinedType(&extendee)); |
+ io::Tokenizer::Token extendee_end = input_->previous(); |
// Parse the block. |
DO(Consume("{")); |
@@ -810,16 +1056,29 @@ bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions, |
return false; |
} |
- FieldDescriptorProto* field; |
- if (is_first) { |
- field = first_field; |
- is_first = false; |
- } else { |
- field = extensions->Add(); |
- field->set_extendee(first_field->extendee()); |
+ // Note that kExtensionFieldNumber was already pushed by the parent. |
+ LocationRecorder location(extend_location, extensions->size()); |
+ |
+ FieldDescriptorProto* field = extensions->Add(); |
+ |
+ { |
+ LocationRecorder extendee_location( |
+ location, FieldDescriptorProto::kExtendeeFieldNumber); |
+ extendee_location.StartAt(extendee_start); |
+ extendee_location.EndAt(extendee_end); |
+ |
+ if (is_first) { |
+ extendee_location.RecordLegacyLocation( |
+ field, DescriptorPool::ErrorCollector::EXTENDEE); |
+ is_first = false; |
+ } |
} |
- if (!ParseMessageField(field, messages)) { |
+ field->set_extendee(extendee); |
+ |
+ if (!ParseMessageField(field, messages, parent_location, |
+ location_field_number_for_nested_type, |
+ location)) { |
// This statement failed to parse. Skip it, but keep looping to parse |
// other statements. |
SkipStatement(); |
@@ -832,15 +1091,24 @@ bool Parser::ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions, |
// ------------------------------------------------------------------- |
// Enums |
-bool Parser::ParseEnumDefinition(EnumDescriptorProto* enum_type) { |
+bool Parser::ParseEnumDefinition(EnumDescriptorProto* enum_type, |
+ const LocationRecorder& enum_location) { |
DO(Consume("enum")); |
- RecordLocation(enum_type, DescriptorPool::ErrorCollector::NAME); |
- DO(ConsumeIdentifier(enum_type->mutable_name(), "Expected enum name.")); |
- DO(ParseEnumBlock(enum_type)); |
+ |
+ { |
+ LocationRecorder location(enum_location, |
+ EnumDescriptorProto::kNameFieldNumber); |
+ location.RecordLegacyLocation( |
+ enum_type, DescriptorPool::ErrorCollector::NAME); |
+ DO(ConsumeIdentifier(enum_type->mutable_name(), "Expected enum name.")); |
+ } |
+ |
+ DO(ParseEnumBlock(enum_type, enum_location)); |
return true; |
} |
-bool Parser::ParseEnumBlock(EnumDescriptorProto* enum_type) { |
+bool Parser::ParseEnumBlock(EnumDescriptorProto* enum_type, |
+ const LocationRecorder& enum_location) { |
DO(Consume("{")); |
while (!TryConsume("}")) { |
@@ -849,7 +1117,7 @@ bool Parser::ParseEnumBlock(EnumDescriptorProto* enum_type) { |
return false; |
} |
- if (!ParseEnumStatement(enum_type)) { |
+ if (!ParseEnumStatement(enum_type, enum_location)) { |
// This statement failed to parse. Skip it, but keep looping to parse |
// other statements. |
SkipStatement(); |
@@ -859,41 +1127,69 @@ bool Parser::ParseEnumBlock(EnumDescriptorProto* enum_type) { |
return true; |
} |
-bool Parser::ParseEnumStatement(EnumDescriptorProto* enum_type) { |
+bool Parser::ParseEnumStatement(EnumDescriptorProto* enum_type, |
+ const LocationRecorder& enum_location) { |
if (TryConsume(";")) { |
// empty statement; ignore |
return true; |
} else if (LookingAt("option")) { |
- return ParseOption(enum_type->mutable_options()); |
+ LocationRecorder location(enum_location, |
+ EnumDescriptorProto::kOptionsFieldNumber); |
+ return ParseOption(enum_type->mutable_options(), location); |
} else { |
- return ParseEnumConstant(enum_type->add_value()); |
+ LocationRecorder location(enum_location, |
+ EnumDescriptorProto::kValueFieldNumber, enum_type->value_size()); |
+ return ParseEnumConstant(enum_type->add_value(), location); |
} |
} |
-bool Parser::ParseEnumConstant(EnumValueDescriptorProto* enum_value) { |
- RecordLocation(enum_value, DescriptorPool::ErrorCollector::NAME); |
- DO(ConsumeIdentifier(enum_value->mutable_name(), |
- "Expected enum constant name.")); |
+bool Parser::ParseEnumConstant(EnumValueDescriptorProto* enum_value, |
+ const LocationRecorder& enum_value_location) { |
+ // Parse name. |
+ { |
+ LocationRecorder location(enum_value_location, |
+ EnumValueDescriptorProto::kNameFieldNumber); |
+ location.RecordLegacyLocation( |
+ enum_value, DescriptorPool::ErrorCollector::NAME); |
+ DO(ConsumeIdentifier(enum_value->mutable_name(), |
+ "Expected enum constant name.")); |
+ } |
+ |
DO(Consume("=", "Missing numeric value for enum constant.")); |
- bool is_negative = TryConsume("-"); |
- int number; |
- DO(ConsumeInteger(&number, "Expected integer.")); |
- if (is_negative) number *= -1; |
- enum_value->set_number(number); |
+ // Parse value. |
+ { |
+ LocationRecorder location( |
+ enum_value_location, EnumValueDescriptorProto::kNumberFieldNumber); |
+ location.RecordLegacyLocation( |
+ enum_value, DescriptorPool::ErrorCollector::NUMBER); |
+ |
+ bool is_negative = TryConsume("-"); |
+ int number; |
+ DO(ConsumeInteger(&number, "Expected integer.")); |
+ if (is_negative) number *= -1; |
+ enum_value->set_number(number); |
+ } |
- DO(ParseEnumConstantOptions(enum_value)); |
+ DO(ParseEnumConstantOptions(enum_value, enum_value_location)); |
DO(Consume(";")); |
return true; |
} |
-bool Parser::ParseEnumConstantOptions(EnumValueDescriptorProto* value) { |
- if (!TryConsume("[")) return true; |
+bool Parser::ParseEnumConstantOptions( |
+ EnumValueDescriptorProto* value, |
+ const LocationRecorder& enum_value_location) { |
+ if (!LookingAt("[")) return true; |
+ |
+ LocationRecorder location( |
+ enum_value_location, EnumValueDescriptorProto::kOptionsFieldNumber); |
+ |
+ DO(Consume("[")); |
do { |
- DO(ParseOptionAssignment(value->mutable_options())); |
+ DO(ParseOptionAssignment(value->mutable_options(), location)); |
} while (TryConsume(",")); |
DO(Consume("]")); |
@@ -903,15 +1199,24 @@ bool Parser::ParseEnumConstantOptions(EnumValueDescriptorProto* value) { |
// ------------------------------------------------------------------- |
// Services |
-bool Parser::ParseServiceDefinition(ServiceDescriptorProto* service) { |
+bool Parser::ParseServiceDefinition(ServiceDescriptorProto* service, |
+ const LocationRecorder& service_location) { |
DO(Consume("service")); |
- RecordLocation(service, DescriptorPool::ErrorCollector::NAME); |
- DO(ConsumeIdentifier(service->mutable_name(), "Expected service name.")); |
- DO(ParseServiceBlock(service)); |
+ |
+ { |
+ LocationRecorder location(service_location, |
+ ServiceDescriptorProto::kNameFieldNumber); |
+ location.RecordLegacyLocation( |
+ service, DescriptorPool::ErrorCollector::NAME); |
+ DO(ConsumeIdentifier(service->mutable_name(), "Expected service name.")); |
+ } |
+ |
+ DO(ParseServiceBlock(service, service_location)); |
return true; |
} |
-bool Parser::ParseServiceBlock(ServiceDescriptorProto* service) { |
+bool Parser::ParseServiceBlock(ServiceDescriptorProto* service, |
+ const LocationRecorder& service_location) { |
DO(Consume("{")); |
while (!TryConsume("}")) { |
@@ -920,7 +1225,7 @@ bool Parser::ParseServiceBlock(ServiceDescriptorProto* service) { |
return false; |
} |
- if (!ParseServiceStatement(service)) { |
+ if (!ParseServiceStatement(service, service_location)) { |
// This statement failed to parse. Skip it, but keep looping to parse |
// other statements. |
SkipStatement(); |
@@ -930,33 +1235,55 @@ bool Parser::ParseServiceBlock(ServiceDescriptorProto* service) { |
return true; |
} |
-bool Parser::ParseServiceStatement(ServiceDescriptorProto* service) { |
+bool Parser::ParseServiceStatement(ServiceDescriptorProto* service, |
+ const LocationRecorder& service_location) { |
if (TryConsume(";")) { |
// empty statement; ignore |
return true; |
} else if (LookingAt("option")) { |
- return ParseOption(service->mutable_options()); |
+ LocationRecorder location( |
+ service_location, ServiceDescriptorProto::kOptionsFieldNumber); |
+ return ParseOption(service->mutable_options(), location); |
} else { |
- return ParseServiceMethod(service->add_method()); |
+ LocationRecorder location(service_location, |
+ ServiceDescriptorProto::kMethodFieldNumber, service->method_size()); |
+ return ParseServiceMethod(service->add_method(), location); |
} |
} |
-bool Parser::ParseServiceMethod(MethodDescriptorProto* method) { |
+bool Parser::ParseServiceMethod(MethodDescriptorProto* method, |
+ const LocationRecorder& method_location) { |
DO(Consume("rpc")); |
- RecordLocation(method, DescriptorPool::ErrorCollector::NAME); |
- DO(ConsumeIdentifier(method->mutable_name(), "Expected method name.")); |
+ |
+ { |
+ LocationRecorder location(method_location, |
+ MethodDescriptorProto::kNameFieldNumber); |
+ location.RecordLegacyLocation( |
+ method, DescriptorPool::ErrorCollector::NAME); |
+ DO(ConsumeIdentifier(method->mutable_name(), "Expected method name.")); |
+ } |
// Parse input type. |
DO(Consume("(")); |
- RecordLocation(method, DescriptorPool::ErrorCollector::INPUT_TYPE); |
- DO(ParseUserDefinedType(method->mutable_input_type())); |
+ { |
+ LocationRecorder location(method_location, |
+ MethodDescriptorProto::kInputTypeFieldNumber); |
+ location.RecordLegacyLocation( |
+ method, DescriptorPool::ErrorCollector::INPUT_TYPE); |
+ DO(ParseUserDefinedType(method->mutable_input_type())); |
+ } |
DO(Consume(")")); |
// Parse output type. |
DO(Consume("returns")); |
DO(Consume("(")); |
- RecordLocation(method, DescriptorPool::ErrorCollector::OUTPUT_TYPE); |
- DO(ParseUserDefinedType(method->mutable_output_type())); |
+ { |
+ LocationRecorder location(method_location, |
+ MethodDescriptorProto::kOutputTypeFieldNumber); |
+ location.RecordLegacyLocation( |
+ method, DescriptorPool::ErrorCollector::OUTPUT_TYPE); |
+ DO(ParseUserDefinedType(method->mutable_output_type())); |
+ } |
DO(Consume(")")); |
if (TryConsume("{")) { |
@@ -970,7 +1297,9 @@ bool Parser::ParseServiceMethod(MethodDescriptorProto* method) { |
if (TryConsume(";")) { |
// empty statement; ignore |
} else { |
- if (!ParseOption(method->mutable_options())) { |
+ LocationRecorder location(method_location, |
+ MethodDescriptorProto::kOptionsFieldNumber); |
+ if (!ParseOption(method->mutable_options(), location)) { |
// This statement failed to parse. Skip it, but keep looping to |
// parse other statements. |
SkipStatement(); |
@@ -1054,7 +1383,8 @@ bool Parser::ParseUserDefinedType(string* type_name) { |
// =================================================================== |
-bool Parser::ParsePackage(FileDescriptorProto* file) { |
+bool Parser::ParsePackage(FileDescriptorProto* file, |
+ const LocationRecorder& root_location) { |
if (file->has_package()) { |
AddError("Multiple package definitions."); |
// Don't append the new package to the old one. Just replace it. Not |
@@ -1064,31 +1394,43 @@ bool Parser::ParsePackage(FileDescriptorProto* file) { |
DO(Consume("package")); |
- RecordLocation(file, DescriptorPool::ErrorCollector::NAME); |
+ { |
+ LocationRecorder location(root_location, |
+ FileDescriptorProto::kPackageFieldNumber); |
+ location.RecordLegacyLocation(file, DescriptorPool::ErrorCollector::NAME); |
- while (true) { |
- string identifier; |
- DO(ConsumeIdentifier(&identifier, "Expected identifier.")); |
- file->mutable_package()->append(identifier); |
- if (!TryConsume(".")) break; |
- file->mutable_package()->append("."); |
+ while (true) { |
+ string identifier; |
+ DO(ConsumeIdentifier(&identifier, "Expected identifier.")); |
+ file->mutable_package()->append(identifier); |
+ if (!TryConsume(".")) break; |
+ file->mutable_package()->append("."); |
+ } |
} |
DO(Consume(";")); |
return true; |
} |
-bool Parser::ParseImport(string* import_filename) { |
+bool Parser::ParseImport(string* import_filename, |
+ const LocationRecorder& root_location, |
+ int index) { |
DO(Consume("import")); |
- DO(ConsumeString(import_filename, |
- "Expected a string naming the file to import.")); |
+ { |
+ LocationRecorder location(root_location, |
+ FileDescriptorProto::kDependencyFieldNumber, |
+ index); |
+ DO(ConsumeString(import_filename, |
+ "Expected a string naming the file to import.")); |
+ } |
DO(Consume(";")); |
return true; |
} |
-bool Parser::ParseOption(Message* options) { |
+bool Parser::ParseOption(Message* options, |
+ const LocationRecorder& options_location) { |
DO(Consume("option")); |
- DO(ParseOptionAssignment(options)); |
+ DO(ParseOptionAssignment(options, options_location)); |
DO(Consume(";")); |
return true; |
} |