source code info for interpreted options; fix source code info for extension range options (#4342)
* when interpreting options, rewrite file descriptor's source code info - so that interpreted option paths have correct location information - so that corresponding uninterpreted option paths are removed also includes a fix to source code locations for extension range options
This commit is contained in:
parent
d34e3190df
commit
1156ee7ea7
@ -337,31 +337,42 @@ void Parser::AddError(const string& error) {
|
||||
|
||||
Parser::LocationRecorder::LocationRecorder(Parser* parser)
|
||||
: parser_(parser),
|
||||
source_code_info_(parser->source_code_info_),
|
||||
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);
|
||||
Init(parent, parent.source_code_info_);
|
||||
}
|
||||
|
||||
Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent,
|
||||
int path1,
|
||||
SourceCodeInfo* source_code_info) {
|
||||
Init(parent, source_code_info);
|
||||
AddPath(path1);
|
||||
}
|
||||
|
||||
Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent,
|
||||
int path1) {
|
||||
Init(parent);
|
||||
Init(parent, parent.source_code_info_);
|
||||
AddPath(path1);
|
||||
}
|
||||
|
||||
Parser::LocationRecorder::LocationRecorder(const LocationRecorder& parent,
|
||||
int path1, int path2) {
|
||||
Init(parent);
|
||||
Init(parent, parent.source_code_info_);
|
||||
AddPath(path1);
|
||||
AddPath(path2);
|
||||
}
|
||||
|
||||
void Parser::LocationRecorder::Init(const LocationRecorder& parent) {
|
||||
void Parser::LocationRecorder::Init(const LocationRecorder& parent,
|
||||
SourceCodeInfo* source_code_info) {
|
||||
parser_ = parent.parser_;
|
||||
location_ = parser_->source_code_info_->add_location();
|
||||
source_code_info_ = source_code_info;
|
||||
|
||||
location_ = source_code_info_->add_location();
|
||||
location_->mutable_path()->CopyFrom(parent.location_->path());
|
||||
|
||||
location_->add_span(parser_->input_->current().line);
|
||||
@ -403,6 +414,10 @@ void Parser::LocationRecorder::RecordLegacyLocation(const Message* descriptor,
|
||||
}
|
||||
}
|
||||
|
||||
int Parser::LocationRecorder::CurrentPathSize() const {
|
||||
return location_->path_size();
|
||||
}
|
||||
|
||||
void Parser::LocationRecorder::AttachComments(
|
||||
string* leading, string* trailing,
|
||||
std::vector<string>* detached_comments) const {
|
||||
@ -1496,21 +1511,30 @@ bool Parser::ParseExtensions(DescriptorProto* message,
|
||||
range->set_end(end);
|
||||
} while (TryConsume(","));
|
||||
|
||||
if (LookingAt("[")) {
|
||||
LocationRecorder location(
|
||||
extensions_location,
|
||||
DescriptorProto::ExtensionRange::kOptionsFieldNumber);
|
||||
|
||||
DO(Consume("["));
|
||||
if (LookingAt("[")) {
|
||||
int range_number_index = extensions_location.CurrentPathSize();
|
||||
SourceCodeInfo info;
|
||||
|
||||
// Parse extension range options in the first range.
|
||||
ExtensionRangeOptions* options =
|
||||
message->mutable_extension_range(old_range_size)->mutable_options();
|
||||
do {
|
||||
DO(ParseOption(options, location, containing_file, OPTION_ASSIGNMENT));
|
||||
} while (TryConsume(","));
|
||||
|
||||
DO(Consume("]"));
|
||||
{
|
||||
LocationRecorder index_location(
|
||||
extensions_location, 0 /* we fill this in w/ actual index below */,
|
||||
&info);
|
||||
LocationRecorder location(
|
||||
index_location,
|
||||
DescriptorProto::ExtensionRange::kOptionsFieldNumber);
|
||||
DO(Consume("["));
|
||||
|
||||
do {
|
||||
DO(ParseOption(options, location, containing_file, OPTION_ASSIGNMENT));
|
||||
} while (TryConsume(","));
|
||||
|
||||
DO(Consume("]"));
|
||||
}
|
||||
|
||||
// Then copy the extension range options to all of the other ranges we've
|
||||
// parsed.
|
||||
@ -1518,6 +1542,19 @@ bool Parser::ParseExtensions(DescriptorProto* message,
|
||||
message->mutable_extension_range(i)->mutable_options()
|
||||
->CopyFrom(*options);
|
||||
}
|
||||
// and copy source locations to the other ranges, too
|
||||
for (int i = old_range_size; i < message->extension_range_size(); i++) {
|
||||
for (int j = 0; j < info.location_size(); j++) {
|
||||
if (info.location(j).path_size() == range_number_index + 1) {
|
||||
// this location's path is up to the extension range index, but doesn't
|
||||
// include options; so it's redundant with location above
|
||||
continue;
|
||||
}
|
||||
SourceCodeInfo_Location* dest = source_code_info_->add_location();
|
||||
dest->CopyFrom(info.location(j));
|
||||
dest->set_path(range_number_index, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DO(ConsumeEndOfDeclaration(";", &extensions_location));
|
||||
|
@ -224,6 +224,10 @@ class LIBPROTOBUF_EXPORT Parser {
|
||||
LocationRecorder(const LocationRecorder& parent, int path1);
|
||||
LocationRecorder(const LocationRecorder& parent, int path1, int path2);
|
||||
|
||||
// Creates a recorder that generates locations into given source code info.
|
||||
LocationRecorder(const LocationRecorder& parent, int path1,
|
||||
SourceCodeInfo* source_code_info);
|
||||
|
||||
~LocationRecorder();
|
||||
|
||||
// Add a path component. See SourceCodeInfo.Location.path in
|
||||
@ -250,6 +254,9 @@ class LIBPROTOBUF_EXPORT Parser {
|
||||
void RecordLegacyLocation(const Message* descriptor,
|
||||
DescriptorPool::ErrorCollector::ErrorLocation location);
|
||||
|
||||
// Returns the number of path components in the recorder's current location.
|
||||
int CurrentPathSize() const;
|
||||
|
||||
// Attaches leading and trailing comments to the location. The two strings
|
||||
// will be swapped into place, so after this is called *leading and
|
||||
// *trailing will be empty.
|
||||
@ -264,9 +271,10 @@ class LIBPROTOBUF_EXPORT Parser {
|
||||
// SourceCodeInfo.location repeated field. For top-level elements,
|
||||
// parent_index_ is -1.
|
||||
Parser* parser_;
|
||||
SourceCodeInfo* source_code_info_;
|
||||
SourceCodeInfo::Location* location_;
|
||||
|
||||
void Init(const LocationRecorder& parent);
|
||||
void Init(const LocationRecorder& parent, SourceCodeInfo* source_code_info);
|
||||
};
|
||||
|
||||
// =================================================================
|
||||
|
@ -3118,15 +3118,18 @@ namespace {
|
||||
struct OptionsToInterpret {
|
||||
OptionsToInterpret(const string& ns,
|
||||
const string& el,
|
||||
std::vector<int>& path,
|
||||
const Message* orig_opt,
|
||||
Message* opt)
|
||||
: name_scope(ns),
|
||||
element_name(el),
|
||||
element_path(path),
|
||||
original_options(orig_opt),
|
||||
options(opt) {
|
||||
}
|
||||
string name_scope;
|
||||
string element_name;
|
||||
std::vector<int> element_path;
|
||||
const Message* original_options;
|
||||
Message* options;
|
||||
};
|
||||
@ -3293,7 +3296,7 @@ class DescriptorBuilder {
|
||||
// descriptor.proto.
|
||||
template<class DescriptorT> void AllocateOptions(
|
||||
const typename DescriptorT::OptionsType& orig_options,
|
||||
DescriptorT* descriptor);
|
||||
DescriptorT* descriptor, int options_field_tag);
|
||||
// Specialization for FileOptions.
|
||||
void AllocateOptions(const FileOptions& orig_options,
|
||||
FileDescriptor* descriptor);
|
||||
@ -3303,7 +3306,8 @@ class DescriptorBuilder {
|
||||
const string& name_scope,
|
||||
const string& element_name,
|
||||
const typename DescriptorT::OptionsType& orig_options,
|
||||
DescriptorT* descriptor);
|
||||
DescriptorT* descriptor,
|
||||
std::vector<int>& options_path);
|
||||
|
||||
// These methods all have the same signature for the sake of the BUILD_ARRAY
|
||||
// macro, below.
|
||||
@ -3392,13 +3396,21 @@ class DescriptorBuilder {
|
||||
// Otherwise returns true.
|
||||
bool InterpretOptions(OptionsToInterpret* options_to_interpret);
|
||||
|
||||
// Updates the given source code info by re-writing uninterpreted option
|
||||
// locations to refer to the corresponding interpreted option.
|
||||
void UpdateSourceCodeInfo(SourceCodeInfo* info);
|
||||
|
||||
class AggregateOptionFinder;
|
||||
|
||||
private:
|
||||
// Interprets uninterpreted_option_ on the specified message, which
|
||||
// must be the mutable copy of the original options message to which
|
||||
// uninterpreted_option_ belongs.
|
||||
bool InterpretSingleOption(Message* options);
|
||||
// uninterpreted_option_ belongs. The given src_path is the source
|
||||
// location path to the uninterpreted option, and options_path is the
|
||||
// source location path to the options message. The location paths are
|
||||
// recorded and then used in UpdateSourceCodeInfo.
|
||||
bool InterpretSingleOption(Message* options, std::vector<int>& src_path,
|
||||
std::vector<int>& options_path);
|
||||
|
||||
// Adds the uninterpreted_option to the given options message verbatim.
|
||||
// Used when AllowUnknownDependencies() is in effect and we can't find
|
||||
@ -3473,6 +3485,16 @@ class DescriptorBuilder {
|
||||
// can use it to find locations recorded by the parser.
|
||||
const UninterpretedOption* uninterpreted_option_;
|
||||
|
||||
// This maps the element path of uninterpreted options to the element path
|
||||
// of the resulting interpreted option. This is used to modify a file's
|
||||
// source code info to account for option interpretation.
|
||||
std::map<std::vector<int>, std::vector<int>> interpreted_paths_;
|
||||
|
||||
// This maps the path to a repeated option field to the known number of
|
||||
// elements the field contains. This is used to track the compute the
|
||||
// index portion of the element path when interpreting a single option.
|
||||
std::map<std::vector<int>, int> repeated_option_counts_;
|
||||
|
||||
// Factory used to create the dynamic messages we need to parse
|
||||
// any aggregate option values we encounter.
|
||||
DynamicMessageFactory dynamic_factory_;
|
||||
@ -4090,24 +4112,30 @@ void DescriptorBuilder::ValidateSymbolName(
|
||||
// FileDescriptor.
|
||||
template<class DescriptorT> void DescriptorBuilder::AllocateOptions(
|
||||
const typename DescriptorT::OptionsType& orig_options,
|
||||
DescriptorT* descriptor) {
|
||||
DescriptorT* descriptor, int options_field_tag) {
|
||||
std::vector<int> options_path;
|
||||
descriptor->GetLocationPath(&options_path);
|
||||
options_path.push_back(options_field_tag);
|
||||
AllocateOptionsImpl(descriptor->full_name(), descriptor->full_name(),
|
||||
orig_options, descriptor);
|
||||
orig_options, descriptor, options_path);
|
||||
}
|
||||
|
||||
// We specialize for FileDescriptor.
|
||||
void DescriptorBuilder::AllocateOptions(const FileOptions& orig_options,
|
||||
FileDescriptor* descriptor) {
|
||||
std::vector<int> options_path;
|
||||
options_path.push_back(FileDescriptorProto::kOptionsFieldNumber);
|
||||
// We add the dummy token so that LookupSymbol does the right thing.
|
||||
AllocateOptionsImpl(descriptor->package() + ".dummy", descriptor->name(),
|
||||
orig_options, descriptor);
|
||||
orig_options, descriptor, options_path);
|
||||
}
|
||||
|
||||
template<class DescriptorT> void DescriptorBuilder::AllocateOptionsImpl(
|
||||
const string& name_scope,
|
||||
const string& element_name,
|
||||
const typename DescriptorT::OptionsType& orig_options,
|
||||
DescriptorT* descriptor) {
|
||||
DescriptorT* descriptor,
|
||||
std::vector<int>& options_path) {
|
||||
// We need to use a dummy pointer to work around a bug in older versions of
|
||||
// GCC. Otherwise, the following two lines could be replaced with:
|
||||
// typename DescriptorT::OptionsType* options =
|
||||
@ -4130,7 +4158,8 @@ template<class DescriptorT> void DescriptorBuilder::AllocateOptionsImpl(
|
||||
// we're still trying to build it.
|
||||
if (options->uninterpreted_option_size() > 0) {
|
||||
options_to_interpret_.push_back(
|
||||
OptionsToInterpret(name_scope, element_name, &orig_options, options));
|
||||
OptionsToInterpret(name_scope, element_name, options_path,
|
||||
&orig_options, options));
|
||||
}
|
||||
}
|
||||
|
||||
@ -4268,8 +4297,9 @@ FileDescriptor* DescriptorBuilder::BuildFileImpl(
|
||||
|
||||
result->is_placeholder_ = false;
|
||||
result->finished_building_ = false;
|
||||
SourceCodeInfo *info = NULL;
|
||||
if (proto.has_source_code_info()) {
|
||||
SourceCodeInfo *info = tables_->AllocateMessage<SourceCodeInfo>();
|
||||
info = tables_->AllocateMessage<SourceCodeInfo>();
|
||||
info->CopyFrom(proto.source_code_info());
|
||||
result->source_code_info_ = info;
|
||||
} else {
|
||||
@ -4467,6 +4497,10 @@ FileDescriptor* DescriptorBuilder::BuildFileImpl(
|
||||
option_interpreter.InterpretOptions(&(*iter));
|
||||
}
|
||||
options_to_interpret_.clear();
|
||||
|
||||
if (info != NULL) {
|
||||
option_interpreter.UpdateSourceCodeInfo(info);
|
||||
}
|
||||
}
|
||||
|
||||
// Validate options. See comments at InternalSetLazilyBuildDependencies about
|
||||
@ -4538,7 +4572,8 @@ void DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
|
||||
if (!proto.has_options()) {
|
||||
result->options_ = NULL; // Will set to default_instance later.
|
||||
} else {
|
||||
AllocateOptions(proto.options(), result);
|
||||
AllocateOptions(proto.options(), result,
|
||||
DescriptorProto::kOptionsFieldNumber);
|
||||
}
|
||||
|
||||
AddSymbol(result->full_name(), parent, result->name(),
|
||||
@ -4918,7 +4953,8 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
|
||||
if (!proto.has_options()) {
|
||||
result->options_ = NULL; // Will set to default_instance later.
|
||||
} else {
|
||||
AllocateOptions(proto.options(), result);
|
||||
AllocateOptions(proto.options(), result,
|
||||
FieldDescriptorProto::kOptionsFieldNumber);
|
||||
}
|
||||
|
||||
|
||||
@ -4952,8 +4988,16 @@ void DescriptorBuilder::BuildExtensionRange(
|
||||
if (!proto.has_options()) {
|
||||
result->options_ = NULL; // Will set to default_instance later.
|
||||
} else {
|
||||
std::vector<int> options_path;
|
||||
parent->GetLocationPath(&options_path);
|
||||
options_path.push_back(DescriptorProto::kExtensionRangeFieldNumber);
|
||||
// find index of this extension range in order to compute path
|
||||
int index;
|
||||
for (index = 0; parent->extension_ranges_ + index != result; index++);
|
||||
options_path.push_back(index);
|
||||
options_path.push_back(DescriptorProto_ExtensionRange::kOptionsFieldNumber);
|
||||
AllocateOptionsImpl(parent->full_name(), parent->full_name(),
|
||||
proto.options(), result);
|
||||
proto.options(), result, options_path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5005,7 +5049,8 @@ void DescriptorBuilder::BuildOneof(const OneofDescriptorProto& proto,
|
||||
if (!proto.has_options()) {
|
||||
result->options_ = NULL; // Will set to default_instance later.
|
||||
} else {
|
||||
AllocateOptions(proto.options(), result);
|
||||
AllocateOptions(proto.options(), result,
|
||||
OneofDescriptorProto::kOptionsFieldNumber);
|
||||
}
|
||||
|
||||
AddSymbol(result->full_name(), parent, result->name(),
|
||||
@ -5122,7 +5167,8 @@ void DescriptorBuilder::BuildEnum(const EnumDescriptorProto& proto,
|
||||
if (!proto.has_options()) {
|
||||
result->options_ = NULL; // Will set to default_instance later.
|
||||
} else {
|
||||
AllocateOptions(proto.options(), result);
|
||||
AllocateOptions(proto.options(), result,
|
||||
EnumDescriptorProto::kOptionsFieldNumber);
|
||||
}
|
||||
|
||||
AddSymbol(result->full_name(), parent, result->name(),
|
||||
@ -5199,7 +5245,8 @@ void DescriptorBuilder::BuildEnumValue(const EnumValueDescriptorProto& proto,
|
||||
if (!proto.has_options()) {
|
||||
result->options_ = NULL; // Will set to default_instance later.
|
||||
} else {
|
||||
AllocateOptions(proto.options(), result);
|
||||
AllocateOptions(proto.options(), result,
|
||||
EnumValueDescriptorProto::kOptionsFieldNumber);
|
||||
}
|
||||
|
||||
// Again, enum values are weird because we makes them appear as siblings
|
||||
@ -5266,7 +5313,8 @@ void DescriptorBuilder::BuildService(const ServiceDescriptorProto& proto,
|
||||
if (!proto.has_options()) {
|
||||
result->options_ = NULL; // Will set to default_instance later.
|
||||
} else {
|
||||
AllocateOptions(proto.options(), result);
|
||||
AllocateOptions(proto.options(), result,
|
||||
ServiceDescriptorProto::kOptionsFieldNumber);
|
||||
}
|
||||
|
||||
AddSymbol(result->full_name(), NULL, result->name(),
|
||||
@ -5294,7 +5342,8 @@ void DescriptorBuilder::BuildMethod(const MethodDescriptorProto& proto,
|
||||
if (!proto.has_options()) {
|
||||
result->options_ = NULL; // Will set to default_instance later.
|
||||
} else {
|
||||
AllocateOptions(proto.options(), result);
|
||||
AllocateOptions(proto.options(), result,
|
||||
MethodDescriptorProto::kOptionsFieldNumber);
|
||||
}
|
||||
|
||||
result->client_streaming_ = proto.client_streaming();
|
||||
@ -6266,6 +6315,9 @@ bool DescriptorBuilder::OptionInterpreter::InterpretOptions(
|
||||
<< "No field named \"uninterpreted_option\" in the Options proto.";
|
||||
options->GetReflection()->ClearField(options, uninterpreted_options_field);
|
||||
|
||||
std::vector<int> src_path = options_to_interpret->element_path;
|
||||
src_path.push_back(uninterpreted_options_field->number());
|
||||
|
||||
// Find the uninterpreted_option field in the original options.
|
||||
const FieldDescriptor* original_uninterpreted_options_field =
|
||||
original_options->GetDescriptor()->
|
||||
@ -6276,14 +6328,17 @@ bool DescriptorBuilder::OptionInterpreter::InterpretOptions(
|
||||
const int num_uninterpreted_options = original_options->GetReflection()->
|
||||
FieldSize(*original_options, original_uninterpreted_options_field);
|
||||
for (int i = 0; i < num_uninterpreted_options; ++i) {
|
||||
src_path.push_back(i);
|
||||
uninterpreted_option_ = down_cast<const UninterpretedOption*>(
|
||||
&original_options->GetReflection()->GetRepeatedMessage(
|
||||
*original_options, original_uninterpreted_options_field, i));
|
||||
if (!InterpretSingleOption(options)) {
|
||||
if (!InterpretSingleOption(options, src_path,
|
||||
options_to_interpret->element_path)) {
|
||||
// Error already added by InterpretSingleOption().
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
src_path.pop_back();
|
||||
}
|
||||
// Reset these, so we don't have any dangling pointers.
|
||||
uninterpreted_option_ = NULL;
|
||||
@ -6316,7 +6371,7 @@ bool DescriptorBuilder::OptionInterpreter::InterpretOptions(
|
||||
}
|
||||
|
||||
bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
|
||||
Message* options) {
|
||||
Message* options, std::vector<int>& src_path, std::vector<int>& opts_path) {
|
||||
// First do some basic validation.
|
||||
if (uninterpreted_option_->name_size() == 0) {
|
||||
// This should never happen unless the parser has gone seriously awry or
|
||||
@ -6362,6 +6417,8 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
|
||||
std::vector<const FieldDescriptor*> intermediate_fields;
|
||||
string debug_msg_name = "";
|
||||
|
||||
std::vector<int> dest_path = opts_path;
|
||||
|
||||
for (int i = 0; i < uninterpreted_option_->name_size(); ++i) {
|
||||
const string& name_part = uninterpreted_option_->name(i).name_part();
|
||||
if (debug_msg_name.size() > 0) {
|
||||
@ -6424,19 +6481,24 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
|
||||
"\" is not a field or extension of message \"" +
|
||||
descriptor->name() + "\".");
|
||||
}
|
||||
} else if (i < uninterpreted_option_->name_size() - 1) {
|
||||
if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
return AddNameError("Option \"" + debug_msg_name +
|
||||
"\" is an atomic type, not a message.");
|
||||
} else if (field->is_repeated()) {
|
||||
return AddNameError("Option field \"" + debug_msg_name +
|
||||
"\" is a repeated message. Repeated message "
|
||||
"options must be initialized using an "
|
||||
"aggregate value.");
|
||||
} else {
|
||||
// Drill down into the submessage.
|
||||
intermediate_fields.push_back(field);
|
||||
descriptor = field->message_type();
|
||||
} else {
|
||||
// accumulate field numbers to form path to interpreted option
|
||||
dest_path.push_back(field->number());
|
||||
|
||||
if (i < uninterpreted_option_->name_size() - 1) {
|
||||
if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
return AddNameError("Option \"" + debug_msg_name +
|
||||
"\" is an atomic type, not a message.");
|
||||
} else if (field->is_repeated()) {
|
||||
return AddNameError("Option field \"" + debug_msg_name +
|
||||
"\" is a repeated message. Repeated message "
|
||||
"options must be initialized using an "
|
||||
"aggregate value.");
|
||||
} else {
|
||||
// Drill down into the submessage.
|
||||
intermediate_fields.push_back(field);
|
||||
descriptor = field->message_type();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6457,7 +6519,6 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
|
||||
return false; // ExamineIfOptionIsSet() already added the error.
|
||||
}
|
||||
|
||||
|
||||
// First set the value on the UnknownFieldSet corresponding to the
|
||||
// innermost message.
|
||||
std::unique_ptr<UnknownFieldSet> unknown_fields(new UnknownFieldSet());
|
||||
@ -6503,9 +6564,110 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
|
||||
options->GetReflection()->MutableUnknownFields(options)->MergeFrom(
|
||||
*unknown_fields);
|
||||
|
||||
// record the element path of the interpreted option
|
||||
if (field->is_repeated()) {
|
||||
int index = repeated_option_counts_[dest_path]++;
|
||||
dest_path.push_back(index);
|
||||
}
|
||||
interpreted_paths_[src_path] = dest_path;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DescriptorBuilder::OptionInterpreter::UpdateSourceCodeInfo(
|
||||
SourceCodeInfo* info) {
|
||||
|
||||
if (interpreted_paths_.empty()) {
|
||||
// nothing to do!
|
||||
return;
|
||||
}
|
||||
|
||||
// We find locations that match keys in interpreted_paths_ and
|
||||
// 1) replace the path with the corresponding value in interpreted_paths_
|
||||
// 2) remove any subsequent sub-locations (sub-location is one whose path
|
||||
// has the parent path as a prefix)
|
||||
//
|
||||
// To avoid quadratic behavior of removing interior rows as we go,
|
||||
// we keep a copy. But we don't actually copy anything until we've
|
||||
// found the first match (so if the source code info has no locations
|
||||
// that need to be changed, there is zero copy overhead).
|
||||
|
||||
RepeatedPtrField<SourceCodeInfo_Location>* locs = info->mutable_location();
|
||||
RepeatedPtrField<SourceCodeInfo_Location> new_locs;
|
||||
bool copying = false;
|
||||
|
||||
std::vector<int> pathv;
|
||||
bool matched = false;
|
||||
|
||||
for (RepeatedPtrField<SourceCodeInfo_Location>::iterator loc = locs->begin();
|
||||
loc != locs->end(); loc++) {
|
||||
|
||||
if (matched) {
|
||||
// see if this location is in the range to remove
|
||||
bool loc_matches = true;
|
||||
if (loc->path_size() < pathv.size()) {
|
||||
loc_matches = false;
|
||||
} else {
|
||||
for (int j = 0; j < pathv.size(); j++) {
|
||||
if (loc->path(j) != pathv[j]) {
|
||||
loc_matches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (loc_matches) {
|
||||
// don't copy this row since it is a sub-location that we're removing
|
||||
continue;
|
||||
}
|
||||
|
||||
matched = false;
|
||||
}
|
||||
|
||||
pathv.clear();
|
||||
for (int j = 0; j < loc->path_size(); j++) {
|
||||
pathv.push_back(loc->path(j));
|
||||
}
|
||||
|
||||
std::map<std::vector<int>, std::vector<int>>::iterator entry =
|
||||
interpreted_paths_.find(pathv);
|
||||
|
||||
if (entry == interpreted_paths_.end()) {
|
||||
// not a match
|
||||
if (copying) {
|
||||
new_locs.Add()->CopyFrom(*loc);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
matched = true;
|
||||
|
||||
if (!copying) {
|
||||
// initialize the copy we are building
|
||||
copying = true;
|
||||
new_locs.Reserve(locs->size());
|
||||
for (RepeatedPtrField<SourceCodeInfo_Location>::iterator it =
|
||||
locs->begin(); it != loc; it++) {
|
||||
new_locs.Add()->CopyFrom(*it);
|
||||
}
|
||||
}
|
||||
|
||||
// add replacement and update its path
|
||||
SourceCodeInfo_Location* replacement = new_locs.Add();
|
||||
replacement->CopyFrom(*loc);
|
||||
replacement->clear_path();
|
||||
for (std::vector<int>::iterator rit = entry->second.begin();
|
||||
rit != entry->second.end(); rit++) {
|
||||
replacement->add_path(*rit);
|
||||
}
|
||||
}
|
||||
|
||||
// if we made a changed copy, put it in place
|
||||
if (copying) {
|
||||
*locs = new_locs;
|
||||
}
|
||||
}
|
||||
|
||||
void DescriptorBuilder::OptionInterpreter::AddWithoutInterpreting(
|
||||
const UninterpretedOption& uninterpreted_option, Message* options) {
|
||||
const FieldDescriptor* field =
|
||||
|
@ -6918,40 +6918,95 @@ class SingletonSourceTree : public compiler::SourceTree {
|
||||
|
||||
const char *const kSourceLocationTestInput =
|
||||
"syntax = \"proto2\";\n"
|
||||
"option java_package = \"com.foo.bar\";\n"
|
||||
"option (test_file_opt) = \"foobar\";\n"
|
||||
"message A {\n"
|
||||
" optional int32 a = 1;\n"
|
||||
" option (test_msg_opt) = \"foobar\";\n"
|
||||
" optional int32 a = 1 [deprecated = true];\n"
|
||||
" message B {\n"
|
||||
" required double b = 1;\n"
|
||||
" required double b = 1 [(test_field_opt) = \"foobar\"];\n"
|
||||
" }\n"
|
||||
" oneof c {\n"
|
||||
" option (test_oneof_opt) = \"foobar\";\n"
|
||||
" string d = 2;\n"
|
||||
" string e = 3;\n"
|
||||
" string f = 4;\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"enum Indecision {\n"
|
||||
" YES = 1;\n"
|
||||
" NO = 2;\n"
|
||||
" option (test_enum_opt) = 21;\n"
|
||||
" option (test_enum_opt) = 42;\n"
|
||||
" option (test_enum_opt) = 63;\n"
|
||||
" YES = 1 [(test_enumval_opt).a = 100];\n"
|
||||
" NO = 2 [(test_enumval_opt) = {a:200}];\n"
|
||||
" MAYBE = 3;\n"
|
||||
"}\n"
|
||||
"service S {\n"
|
||||
" option (test_svc_opt) = {a:100};\n"
|
||||
" option (test_svc_opt) = {a:200};\n"
|
||||
" option (test_svc_opt) = {a:300};\n"
|
||||
" rpc Method(A) returns (A.B);\n"
|
||||
// Put an empty line here to make the source location range match.
|
||||
"\n"
|
||||
" rpc OtherMethod(A) returns (A) {\n"
|
||||
" option deprecated = true;\n"
|
||||
" option (test_method_opt) = \"foobar\";\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"message MessageWithExtensions {\n"
|
||||
" extensions 1000 to max;\n"
|
||||
" extensions 1000 to 2000, 2001 to max [(test_ext_opt) = \"foobar\"];\n"
|
||||
"}\n"
|
||||
"extend MessageWithExtensions {\n"
|
||||
" optional int32 int32_extension = 1001;\n"
|
||||
" repeated int32 int32_extension = 1001 [packed=true];\n"
|
||||
"}\n"
|
||||
"message C {\n"
|
||||
" extend MessageWithExtensions {\n"
|
||||
" optional C message_extension = 1002;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
"}\n"
|
||||
"import \"google/protobuf/descriptor.proto\";\n"
|
||||
"extend google.protobuf.FileOptions {\n"
|
||||
" optional string test_file_opt = 10101;\n"
|
||||
"}\n"
|
||||
"extend google.protobuf.MessageOptions {\n"
|
||||
" optional string test_msg_opt = 10101;\n"
|
||||
"}\n"
|
||||
"extend google.protobuf.FieldOptions {\n"
|
||||
" optional string test_field_opt = 10101;\n"
|
||||
"}\n"
|
||||
"extend google.protobuf.EnumOptions {\n"
|
||||
" repeated int32 test_enum_opt = 10101;\n"
|
||||
"}\n"
|
||||
"extend google.protobuf.EnumValueOptions {\n"
|
||||
" optional A test_enumval_opt = 10101;\n"
|
||||
"}\n"
|
||||
"extend google.protobuf.ServiceOptions {\n"
|
||||
" repeated A test_svc_opt = 10101;\n"
|
||||
"}\n"
|
||||
"extend google.protobuf.MethodOptions {\n"
|
||||
" optional string test_method_opt = 10101;\n"
|
||||
"}\n"
|
||||
"extend google.protobuf.OneofOptions {\n"
|
||||
" optional string test_oneof_opt = 10101;\n"
|
||||
"}\n"
|
||||
"extend google.protobuf.ExtensionRangeOptions {\n"
|
||||
" optional string test_ext_opt = 10101;\n"
|
||||
"}\n"
|
||||
;
|
||||
|
||||
class SourceLocationTest : public testing::Test {
|
||||
public:
|
||||
SourceLocationTest()
|
||||
: source_tree_("/test/test.proto", kSourceLocationTestInput),
|
||||
db_(&source_tree_),
|
||||
pool_(&db_, &collector_) {}
|
||||
simple_db_(),
|
||||
source_tree_db_(&source_tree_),
|
||||
merged_db_(&simple_db_, &source_tree_db_),
|
||||
pool_(&merged_db_, &collector_) {
|
||||
// we need descriptor.proto to be accessible by the pool
|
||||
// since our test file imports it
|
||||
FileDescriptorProto::descriptor()->file()->CopyTo(&file_proto_);
|
||||
simple_db_.Add(file_proto_);
|
||||
}
|
||||
|
||||
static string PrintSourceLocation(const SourceLocation &loc) {
|
||||
return strings::Substitute("$0:$1-$2:$3",
|
||||
@ -6962,12 +7017,20 @@ class SourceLocationTest : public testing::Test {
|
||||
}
|
||||
|
||||
private:
|
||||
FileDescriptorProto file_proto_;
|
||||
AbortingErrorCollector collector_;
|
||||
SingletonSourceTree source_tree_;
|
||||
compiler::SourceTreeDescriptorDatabase db_;
|
||||
SimpleDescriptorDatabase simple_db_; // contains descriptor.proto
|
||||
compiler::SourceTreeDescriptorDatabase source_tree_db_; // loads test.proto
|
||||
MergedDescriptorDatabase merged_db_; // combines above two dbs
|
||||
|
||||
protected:
|
||||
DescriptorPool pool_;
|
||||
|
||||
// tag number of all custom options in above test file
|
||||
static const int kCustomOptionFieldNumber = 10101;
|
||||
// tag number of field "a" in message type "A" in above test file
|
||||
static const int kA_aFieldNumber = 1;
|
||||
};
|
||||
|
||||
// TODO(adonovan): implement support for option fields and for
|
||||
@ -6981,27 +7044,27 @@ TEST_F(SourceLocationTest, GetSourceLocation) {
|
||||
|
||||
const Descriptor *a_desc = file_desc->FindMessageTypeByName("A");
|
||||
EXPECT_TRUE(a_desc->GetSourceLocation(&loc));
|
||||
EXPECT_EQ("2:1-7:2", PrintSourceLocation(loc));
|
||||
EXPECT_EQ("4:1-16:2", PrintSourceLocation(loc));
|
||||
|
||||
const Descriptor *a_b_desc = a_desc->FindNestedTypeByName("B");
|
||||
EXPECT_TRUE(a_b_desc->GetSourceLocation(&loc));
|
||||
EXPECT_EQ("4:3-6:4", PrintSourceLocation(loc));
|
||||
EXPECT_EQ("7:3-9:4", PrintSourceLocation(loc));
|
||||
|
||||
const EnumDescriptor *e_desc = file_desc->FindEnumTypeByName("Indecision");
|
||||
EXPECT_TRUE(e_desc->GetSourceLocation(&loc));
|
||||
EXPECT_EQ("8:1-12:2", PrintSourceLocation(loc));
|
||||
EXPECT_EQ("17:1-24:2", PrintSourceLocation(loc));
|
||||
|
||||
const EnumValueDescriptor *yes_desc = e_desc->FindValueByName("YES");
|
||||
EXPECT_TRUE(yes_desc->GetSourceLocation(&loc));
|
||||
EXPECT_EQ("9:3-9:13", PrintSourceLocation(loc));
|
||||
EXPECT_EQ("21:3-21:42", PrintSourceLocation(loc));
|
||||
|
||||
const ServiceDescriptor *s_desc = file_desc->FindServiceByName("S");
|
||||
EXPECT_TRUE(s_desc->GetSourceLocation(&loc));
|
||||
EXPECT_EQ("13:1-16:2", PrintSourceLocation(loc));
|
||||
EXPECT_EQ("25:1-35:2", PrintSourceLocation(loc));
|
||||
|
||||
const MethodDescriptor *m_desc = s_desc->FindMethodByName("Method");
|
||||
EXPECT_TRUE(m_desc->GetSourceLocation(&loc));
|
||||
EXPECT_EQ("14:3-14:31", PrintSourceLocation(loc));
|
||||
EXPECT_EQ("29:3-29:31", PrintSourceLocation(loc));
|
||||
|
||||
}
|
||||
|
||||
@ -7014,16 +7077,426 @@ TEST_F(SourceLocationTest, ExtensionSourceLocation) {
|
||||
const FieldDescriptor *int32_extension_desc =
|
||||
file_desc->FindExtensionByName("int32_extension");
|
||||
EXPECT_TRUE(int32_extension_desc->GetSourceLocation(&loc));
|
||||
EXPECT_EQ("21:3-21:41", PrintSourceLocation(loc));
|
||||
EXPECT_EQ("40:3-40:55", PrintSourceLocation(loc));
|
||||
|
||||
const Descriptor *c_desc = file_desc->FindMessageTypeByName("C");
|
||||
EXPECT_TRUE(c_desc->GetSourceLocation(&loc));
|
||||
EXPECT_EQ("23:1-27:2", PrintSourceLocation(loc));
|
||||
EXPECT_EQ("42:1-46:2", PrintSourceLocation(loc));
|
||||
|
||||
const FieldDescriptor *message_extension_desc =
|
||||
c_desc->FindExtensionByName("message_extension");
|
||||
EXPECT_TRUE(message_extension_desc->GetSourceLocation(&loc));
|
||||
EXPECT_EQ("25:5-25:41", PrintSourceLocation(loc));
|
||||
EXPECT_EQ("44:5-44:41", PrintSourceLocation(loc));
|
||||
}
|
||||
|
||||
TEST_F(SourceLocationTest, InterpretedOptionSourceLocation) {
|
||||
// This one's a doozy. It checks every kind of option, including
|
||||
// extension range options.
|
||||
|
||||
// We are verifying that the file's source info contains correct
|
||||
// info for interpreted options and that it does *not* contain
|
||||
// any info for corresponding uninterpreted option path.
|
||||
|
||||
SourceLocation loc;
|
||||
|
||||
const FileDescriptor *file_desc =
|
||||
GOOGLE_CHECK_NOTNULL(pool_.FindFileByName("/test/test.proto"));
|
||||
|
||||
// File options
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kOptionsFieldNumber,
|
||||
FileOptions::kJavaPackageFieldNumber};
|
||||
int unint[] = {FileDescriptorProto::kOptionsFieldNumber,
|
||||
FileOptions::kUninterpretedOptionFieldNumber,
|
||||
0};
|
||||
|
||||
std::vector<int> vpath(path, path + 2);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("2:1-2:37", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 3);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber};
|
||||
int unint[] = {FileDescriptorProto::kOptionsFieldNumber,
|
||||
FileOptions::kUninterpretedOptionFieldNumber,
|
||||
1};
|
||||
std::vector<int> vpath(path, path + 2);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("3:1-3:35", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 3);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
|
||||
// Message option
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kMessageTypeFieldNumber,
|
||||
0,
|
||||
DescriptorProto::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber};
|
||||
int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
|
||||
0,
|
||||
DescriptorProto::kOptionsFieldNumber,
|
||||
MessageOptions::kUninterpretedOptionFieldNumber,
|
||||
0};
|
||||
std::vector<int> vpath(path, path + 4);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("5:3-5:36", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 5);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
|
||||
// Field option
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kMessageTypeFieldNumber,
|
||||
0,
|
||||
DescriptorProto::kFieldFieldNumber,
|
||||
0,
|
||||
FieldDescriptorProto::kOptionsFieldNumber,
|
||||
FieldOptions::kDeprecatedFieldNumber};
|
||||
int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
|
||||
0,
|
||||
DescriptorProto::kFieldFieldNumber,
|
||||
0,
|
||||
FieldDescriptorProto::kOptionsFieldNumber,
|
||||
FieldOptions::kUninterpretedOptionFieldNumber,
|
||||
0};
|
||||
std::vector<int> vpath(path, path + 6);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("6:25-6:42", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 7);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
|
||||
// Nested message option
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kMessageTypeFieldNumber,
|
||||
0,
|
||||
DescriptorProto::kNestedTypeFieldNumber,
|
||||
0,
|
||||
DescriptorProto::kFieldFieldNumber,
|
||||
0,
|
||||
FieldDescriptorProto::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber};
|
||||
int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
|
||||
0,
|
||||
DescriptorProto::kNestedTypeFieldNumber,
|
||||
0,
|
||||
DescriptorProto::kFieldFieldNumber,
|
||||
0,
|
||||
FieldDescriptorProto::kOptionsFieldNumber,
|
||||
FieldOptions::kUninterpretedOptionFieldNumber,
|
||||
0};
|
||||
std::vector<int> vpath(path, path + 8);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("8:28-8:55", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 9);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
|
||||
// One-of option
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kMessageTypeFieldNumber,
|
||||
0,
|
||||
DescriptorProto::kOneofDeclFieldNumber,
|
||||
0,
|
||||
OneofDescriptorProto::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber};
|
||||
int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
|
||||
0,
|
||||
DescriptorProto::kOneofDeclFieldNumber,
|
||||
0,
|
||||
OneofDescriptorProto::kOptionsFieldNumber,
|
||||
OneofOptions::kUninterpretedOptionFieldNumber,
|
||||
0};
|
||||
std::vector<int> vpath(path, path + 6);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("11:5-11:40", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 7);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
|
||||
// Enum option, repeated options
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kEnumTypeFieldNumber,
|
||||
0,
|
||||
EnumDescriptorProto::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber,
|
||||
0};
|
||||
int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber,
|
||||
0,
|
||||
EnumDescriptorProto::kOptionsFieldNumber,
|
||||
EnumOptions::kUninterpretedOptionFieldNumber,
|
||||
0};
|
||||
std::vector<int> vpath(path, path + 5);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("18:3-18:31", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 5);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kEnumTypeFieldNumber,
|
||||
0,
|
||||
EnumDescriptorProto::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber,
|
||||
1};
|
||||
int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber,
|
||||
0,
|
||||
EnumDescriptorProto::kOptionsFieldNumber,
|
||||
EnumOptions::kUninterpretedOptionFieldNumber,
|
||||
1};
|
||||
std::vector<int> vpath(path, path + 5);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("19:3-19:31", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 5);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kEnumTypeFieldNumber,
|
||||
0,
|
||||
EnumDescriptorProto::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber,
|
||||
2};
|
||||
int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber,
|
||||
0,
|
||||
EnumDescriptorProto::kOptionsFieldNumber,
|
||||
OneofOptions::kUninterpretedOptionFieldNumber,
|
||||
2};
|
||||
std::vector<int> vpath(path, path + 5);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("20:3-20:31", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 5);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
|
||||
// Enum value options
|
||||
{
|
||||
// option w/ message type that directly sets field
|
||||
int path[] = {FileDescriptorProto::kEnumTypeFieldNumber,
|
||||
0,
|
||||
EnumDescriptorProto::kValueFieldNumber,
|
||||
0,
|
||||
EnumValueDescriptorProto::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber,
|
||||
kA_aFieldNumber};
|
||||
int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber,
|
||||
0,
|
||||
EnumDescriptorProto::kValueFieldNumber,
|
||||
0,
|
||||
EnumValueDescriptorProto::kOptionsFieldNumber,
|
||||
EnumValueOptions::kUninterpretedOptionFieldNumber,
|
||||
0};
|
||||
std::vector<int> vpath(path, path + 7);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("21:14-21:40", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 7);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kEnumTypeFieldNumber,
|
||||
0,
|
||||
EnumDescriptorProto::kValueFieldNumber,
|
||||
1,
|
||||
EnumValueDescriptorProto::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber};
|
||||
int unint[] = {FileDescriptorProto::kEnumTypeFieldNumber,
|
||||
0,
|
||||
EnumDescriptorProto::kValueFieldNumber,
|
||||
1,
|
||||
EnumValueDescriptorProto::kOptionsFieldNumber,
|
||||
EnumValueOptions::kUninterpretedOptionFieldNumber,
|
||||
0};
|
||||
std::vector<int> vpath(path, path + 6);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("22:14-22:42", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 7);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
|
||||
// Service option, repeated options
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kServiceFieldNumber,
|
||||
0,
|
||||
ServiceDescriptorProto::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber,
|
||||
0};
|
||||
int unint[] = {FileDescriptorProto::kServiceFieldNumber,
|
||||
0,
|
||||
ServiceDescriptorProto::kOptionsFieldNumber,
|
||||
ServiceOptions::kUninterpretedOptionFieldNumber,
|
||||
0};
|
||||
std::vector<int> vpath(path, path + 5);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("26:3-26:35", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 5);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kServiceFieldNumber,
|
||||
0,
|
||||
ServiceDescriptorProto::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber,
|
||||
1};
|
||||
int unint[] = {FileDescriptorProto::kServiceFieldNumber,
|
||||
0,
|
||||
ServiceDescriptorProto::kOptionsFieldNumber,
|
||||
ServiceOptions::kUninterpretedOptionFieldNumber,
|
||||
1};
|
||||
std::vector<int> vpath(path, path + 5);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("27:3-27:35", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 5);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kServiceFieldNumber,
|
||||
0,
|
||||
ServiceDescriptorProto::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber,
|
||||
2};
|
||||
int unint[] = {FileDescriptorProto::kServiceFieldNumber,
|
||||
0,
|
||||
ServiceDescriptorProto::kOptionsFieldNumber,
|
||||
ServiceOptions::kUninterpretedOptionFieldNumber,
|
||||
2};
|
||||
std::vector<int> vpath(path, path + 5);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("28:3-28:35", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 5);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
|
||||
// Method options
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kServiceFieldNumber,
|
||||
0,
|
||||
ServiceDescriptorProto::kMethodFieldNumber,
|
||||
1,
|
||||
MethodDescriptorProto::kOptionsFieldNumber,
|
||||
MethodOptions::kDeprecatedFieldNumber};
|
||||
int unint[] = {FileDescriptorProto::kServiceFieldNumber,
|
||||
0,
|
||||
ServiceDescriptorProto::kMethodFieldNumber,
|
||||
1,
|
||||
MethodDescriptorProto::kOptionsFieldNumber,
|
||||
MethodOptions::kUninterpretedOptionFieldNumber,
|
||||
0};
|
||||
std::vector<int> vpath(path, path + 6);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("32:5-32:30", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 7);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kServiceFieldNumber,
|
||||
0,
|
||||
ServiceDescriptorProto::kMethodFieldNumber,
|
||||
1,
|
||||
MethodDescriptorProto::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber};
|
||||
int unint[] = {FileDescriptorProto::kServiceFieldNumber,
|
||||
0,
|
||||
ServiceDescriptorProto::kMethodFieldNumber,
|
||||
1,
|
||||
MethodDescriptorProto::kOptionsFieldNumber,
|
||||
MethodOptions::kUninterpretedOptionFieldNumber,
|
||||
1};
|
||||
std::vector<int> vpath(path, path + 6);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("33:5-33:41", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 7);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
|
||||
// Extension range options
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kMessageTypeFieldNumber,
|
||||
1,
|
||||
DescriptorProto::kExtensionRangeFieldNumber,
|
||||
0,
|
||||
DescriptorProto_ExtensionRange::kOptionsFieldNumber};
|
||||
std::vector<int> vpath(path, path + 5);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("37:40-37:67", PrintSourceLocation(loc));
|
||||
}
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kMessageTypeFieldNumber,
|
||||
1,
|
||||
DescriptorProto::kExtensionRangeFieldNumber,
|
||||
0,
|
||||
DescriptorProto_ExtensionRange::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber};
|
||||
int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
|
||||
1,
|
||||
DescriptorProto::kExtensionRangeFieldNumber,
|
||||
0,
|
||||
DescriptorProto_ExtensionRange::kOptionsFieldNumber,
|
||||
ExtensionRangeOptions::kUninterpretedOptionFieldNumber,
|
||||
0};
|
||||
std::vector<int> vpath(path, path + 6);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("37:41-37:66", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 7);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kMessageTypeFieldNumber,
|
||||
1,
|
||||
DescriptorProto::kExtensionRangeFieldNumber,
|
||||
1,
|
||||
DescriptorProto_ExtensionRange::kOptionsFieldNumber,
|
||||
kCustomOptionFieldNumber};
|
||||
int unint[] = {FileDescriptorProto::kMessageTypeFieldNumber,
|
||||
1,
|
||||
DescriptorProto::kExtensionRangeFieldNumber,
|
||||
1,
|
||||
DescriptorProto_ExtensionRange::kOptionsFieldNumber,
|
||||
ExtensionRangeOptions::kUninterpretedOptionFieldNumber,
|
||||
0};
|
||||
std::vector<int> vpath(path, path + 6);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("37:41-37:66", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 7);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
|
||||
// Field option on extension
|
||||
{
|
||||
int path[] = {FileDescriptorProto::kExtensionFieldNumber,
|
||||
0,
|
||||
FieldDescriptorProto::kOptionsFieldNumber,
|
||||
FieldOptions::kPackedFieldNumber};
|
||||
int unint[] = {FileDescriptorProto::kExtensionFieldNumber,
|
||||
0,
|
||||
FieldDescriptorProto::kOptionsFieldNumber,
|
||||
FieldOptions::kUninterpretedOptionFieldNumber,
|
||||
0};
|
||||
std::vector<int> vpath(path, path + 4);
|
||||
EXPECT_TRUE(file_desc->GetSourceLocation(vpath, &loc));
|
||||
EXPECT_EQ("40:42-40:53", PrintSourceLocation(loc));
|
||||
|
||||
std::vector<int> vunint(unint, unint + 5);
|
||||
EXPECT_FALSE(file_desc->GetSourceLocation(vunint, &loc));
|
||||
}
|
||||
}
|
||||
|
||||
// Missing SourceCodeInfo doesn't cause crash:
|
||||
|
Loading…
Reference in New Issue
Block a user