diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc index 152f8f50132c..0576b64a4c97 100644 --- a/src/google/protobuf/compiler/parser.cc +++ b/src/google/protobuf/compiler/parser.cc @@ -902,10 +902,8 @@ bool Parser::ParseMessageField(FieldDescriptorProto* field, const LocationRecorder& field_location, const FileDescriptorProto* containing_file) { { - LocationRecorder location(field_location, - FieldDescriptorProto::kLabelFieldNumber); FieldDescriptorProto::Label label; - if (ParseLabel(&label, containing_file)) { + if (ParseLabel(&label, field_location, containing_file)) { field->set_label(label); if (label == FieldDescriptorProto::LABEL_OPTIONAL && syntax_identifier_ == "proto3") { @@ -2206,18 +2204,22 @@ bool Parser::ParseMethodOptions(const LocationRecorder& parent_location, // ------------------------------------------------------------------- bool Parser::ParseLabel(FieldDescriptorProto::Label* label, + const LocationRecorder& field_location, const FileDescriptorProto* containing_file) { + if (!LookingAt("optional") && !LookingAt("repeated") && !LookingAt("required")) { + return false; + } + LocationRecorder location(field_location, + FieldDescriptorProto::kLabelFieldNumber); if (TryConsume("optional")) { *label = FieldDescriptorProto::LABEL_OPTIONAL; - return true; } else if (TryConsume("repeated")) { *label = FieldDescriptorProto::LABEL_REPEATED; - return true; - } else if (TryConsume("required")) { + } else { + Consume("required"); *label = FieldDescriptorProto::LABEL_REQUIRED; - return true; } - return false; + return true; } bool Parser::ParseType(FieldDescriptorProto::Type* type, diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h index 9e2dc5f53204..45d433dc2b31 100644 --- a/src/google/protobuf/compiler/parser.h +++ b/src/google/protobuf/compiler/parser.h @@ -440,6 +440,7 @@ class PROTOBUF_EXPORT Parser { // Parse "required", "optional", or "repeated" and fill in "label" // with the value. Returns true if such a label is consumed. bool ParseLabel(FieldDescriptorProto::Label* label, + const LocationRecorder& field_location, const FileDescriptorProto* containing_file); // Parse a type name and fill in "type" (if it is a primitive) or diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc index ccf020b5fb5d..2070ab9052da 100644 --- a/src/google/protobuf/compiler/parser_unittest.cc +++ b/src/google/protobuf/compiler/parser_unittest.cc @@ -2808,6 +2808,35 @@ TEST_F(SourceInfoTest, Fields) { EXPECT_TRUE(HasSpan(file_.message_type(0), "name")); } +TEST_F(SourceInfoTest, Proto3Fields) { + EXPECT_TRUE( + Parse("syntax = \"proto3\";\n" + "message Foo {\n" + " $a$int32$b$ $c$bar$d$ = $e$1$f$;$g$\n" + " $h$repeated$i$ $j$X.Y$k$ $l$baz$m$ = $n$2$o$;$p$\n" + "}\n")); + + const FieldDescriptorProto& field1 = file_.message_type(0).field(0); + const FieldDescriptorProto& field2 = file_.message_type(0).field(1); + + EXPECT_TRUE(HasSpan('a', 'g', field1)); + EXPECT_TRUE(HasSpan('a', 'b', field1, "type")); + EXPECT_TRUE(HasSpan('c', 'd', field1, "name")); + EXPECT_TRUE(HasSpan('e', 'f', field1, "number")); + + EXPECT_TRUE(HasSpan('h', 'p', field2)); + EXPECT_TRUE(HasSpan('h', 'i', field2, "label")); + EXPECT_TRUE(HasSpan('j', 'k', field2, "type_name")); + EXPECT_TRUE(HasSpan('l', 'm', field2, "name")); + EXPECT_TRUE(HasSpan('n', 'o', field2, "number")); + + // Ignore these. + EXPECT_TRUE(HasSpan(file_)); + EXPECT_TRUE(HasSpan(file_, "syntax")); + EXPECT_TRUE(HasSpan(file_.message_type(0))); + EXPECT_TRUE(HasSpan(file_.message_type(0), "name")); +} + TEST_F(SourceInfoTest, Extensions) { EXPECT_TRUE( Parse("$a$extend $b$Foo$c$ {\n"