diff options
Diffstat (limited to 'src/google/protobuf/descriptor.cc')
-rw-r--r-- | src/google/protobuf/descriptor.cc | 432 |
1 files changed, 307 insertions, 125 deletions
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index 3f54b848..58dd0ac4 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -32,29 +32,28 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include <algorithm> +#include <functional> #include <google/protobuf/stubs/hash.h> +#include <limits> #include <map> #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <set> #include <string> #include <vector> -#include <algorithm> -#include <limits> +#include <google/protobuf/stubs/casts.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/mutex.h> #include <google/protobuf/stubs/once.h> #include <google/protobuf/stubs/stringprintf.h> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/io/strtod.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/tokenizer.h> #include <google/protobuf/io/zero_copy_stream_impl.h> -#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor_database.h> #include <google/protobuf/dynamic_message.h> @@ -64,6 +63,7 @@ #include <google/protobuf/wire_format.h> #include <google/protobuf/stubs/substitute.h> + #include <google/protobuf/stubs/map_util.h> #include <google/protobuf/stubs/stl_util.h> @@ -346,14 +346,14 @@ class PrefixRemover { } if (ascii_tolower(str[i]) != prefix_[j++]) { - return str.as_string(); + return string(str); } } // If we didn't make it through the prefix, we've failed to strip the // prefix. if (j < prefix_.size()) { - return str.as_string(); + return string(str); } // Skip underscores between prefix and further characters. @@ -363,27 +363,25 @@ class PrefixRemover { // Enum label can't be the empty string. if (i == str.size()) { - return str.as_string(); + return string(str); } // We successfully stripped the prefix. str.remove_prefix(i); - return str.as_string(); + return string(str); } private: string prefix_; }; -// A DescriptorPool contains a bunch of hash_maps to implement the +// A DescriptorPool contains a bunch of hash-maps to implement the // various Find*By*() methods. Since hashtable lookups are O(1), it's -// most efficient to construct a fixed set of large hash_maps used by +// most efficient to construct a fixed set of large hash-maps used by // all objects in the pool rather than construct one or more small -// hash_maps for each object. +// hash-maps for each object. // -// The keys to these hash_maps are (parent, name) or (parent, number) -// pairs. Unfortunately STL doesn't provide hash functions for pair<>, -// so we must invent our own. +// The keys to these hash-maps are (parent, name) or (parent, number) pairs. // // TODO(kenton): Use StringPiece rather than const char* in keys? It would // be a lot cleaner but we'd just have to convert it back to const char* @@ -398,12 +396,20 @@ struct PointerStringPairEqual { } }; +typedef std::pair<const Descriptor*, int> DescriptorIntPair; +typedef std::pair<const EnumDescriptor*, int> EnumIntPair; + +#define HASH_MAP hash_map +#define HASH_SET hash_set +#define HASH_FXN hash + template<typename PairType> struct PointerIntegerPairHash { size_t operator()(const PairType& p) const { - // FIXME(kenton): What is the best way to compute this hash? I have - // no idea! This seems a bit better than an XOR. - return reinterpret_cast<intptr_t>(p.first) * ((1 << 16) - 1) + p.second; + static const size_t prime1 = 16777499; + static const size_t prime2 = 16777619; + return reinterpret_cast<size_t>(p.first) * prime1 ^ + static_cast<size_t>(p.second) * prime2; } #ifdef _MSC_VER @@ -417,16 +423,12 @@ struct PointerIntegerPairHash { } }; -typedef std::pair<const Descriptor*, int> DescriptorIntPair; -typedef std::pair<const EnumDescriptor*, int> EnumIntPair; - struct PointerStringPairHash { size_t operator()(const PointerStringPair& p) const { - // FIXME(kenton): What is the best way to compute this hash? I have - // no idea! This seems a bit better than an XOR. + static const size_t prime = 16777619; hash<const char*> cstring_hash; - return reinterpret_cast<intptr_t>(p.first) * ((1 << 16) - 1) + - cstring_hash(p.second); + return reinterpret_cast<size_t>(p.first) * prime ^ + static_cast<size_t>(cstring_hash(p.second)); } #ifdef _MSC_VER @@ -445,31 +447,37 @@ struct PointerStringPairHash { const Symbol kNullSymbol; -typedef hash_map<const char*, Symbol, - hash<const char*>, streq> - SymbolsByNameMap; -typedef hash_map<PointerStringPair, Symbol, - PointerStringPairHash, PointerStringPairEqual> - SymbolsByParentMap; -typedef hash_map<const char*, const FileDescriptor*, - hash<const char*>, streq> - FilesByNameMap; -typedef hash_map<PointerStringPair, const FieldDescriptor*, +typedef HASH_MAP<const char*, Symbol, HASH_FXN<const char*>, streq> + SymbolsByNameMap; + +typedef HASH_MAP<PointerStringPair, Symbol, PointerStringPairHash, + PointerStringPairEqual> + SymbolsByParentMap; + +typedef HASH_MAP<const char*, const FileDescriptor*, HASH_FXN<const char*>, + streq> + FilesByNameMap; + +typedef HASH_MAP<PointerStringPair, const FieldDescriptor*, PointerStringPairHash, PointerStringPairEqual> - FieldsByNameMap; -typedef hash_map<DescriptorIntPair, const FieldDescriptor*, - PointerIntegerPairHash<DescriptorIntPair> > - FieldsByNumberMap; -typedef hash_map<EnumIntPair, const EnumValueDescriptor*, - PointerIntegerPairHash<EnumIntPair> > - EnumValuesByNumberMap; -// This is a map rather than a hash_map, since we use it to iterate + FieldsByNameMap; + +typedef HASH_MAP<DescriptorIntPair, const FieldDescriptor*, + PointerIntegerPairHash<DescriptorIntPair>, + std::equal_to<DescriptorIntPair> > + FieldsByNumberMap; + +typedef HASH_MAP<EnumIntPair, const EnumValueDescriptor*, + PointerIntegerPairHash<EnumIntPair>, + std::equal_to<EnumIntPair> > + EnumValuesByNumberMap; +// This is a map rather than a hash-map, since we use it to iterate // through all the extensions that extend a given Descriptor, and an // ordered data structure that implements lower_bound is convenient // for that. typedef std::map<DescriptorIntPair, const FieldDescriptor*> ExtensionsGroupedByDescriptorMap; -typedef hash_map<string, const SourceCodeInfo_Location*> LocationsByPathMap; +typedef HASH_MAP<string, const SourceCodeInfo_Location*> LocationsByPathMap; std::set<string>* allowed_proto3_extendees_ = NULL; GOOGLE_PROTOBUF_DECLARE_ONCE(allowed_proto3_extendees_init_); @@ -564,17 +572,17 @@ class DescriptorPool::Tables { // execution of the current public API call, but for compatibility with // legacy clients, this is cleared at the beginning of each public API call. // Not used when fallback_database_ == NULL. - hash_set<string> known_bad_files_; + HASH_SET<string> known_bad_files_; // A set of symbols which we have tried to load from the fallback database // and encountered errors. We will not attempt to load them again during // execution of the current public API call, but for compatibility with // legacy clients, this is cleared at the beginning of each public API call. - hash_set<string> known_bad_symbols_; + HASH_SET<string> known_bad_symbols_; // The set of descriptors for which we've already loaded the full // set of extensions numbers from fallback_database_. - hash_set<const Descriptor*> extensions_loaded_from_db_; + HASH_SET<const Descriptor*> extensions_loaded_from_db_; // ----------------------------------------------------------------- // Finding items. @@ -767,10 +775,10 @@ class FileDescriptorTables { SymbolsByParentMap symbols_by_parent_; mutable FieldsByNameMap fields_by_lowercase_name_; - mutable FieldsByNameMap* fields_by_lowercase_name_tmp_; + std::unique_ptr<FieldsByNameMap> fields_by_lowercase_name_tmp_; mutable GoogleOnceDynamic fields_by_lowercase_name_once_; mutable FieldsByNameMap fields_by_camelcase_name_; - mutable FieldsByNameMap* fields_by_camelcase_name_tmp_; + std::unique_ptr<FieldsByNameMap> fields_by_camelcase_name_tmp_; mutable GoogleOnceDynamic fields_by_camelcase_name_once_; FieldsByNumberMap fields_by_number_; // Not including extensions. EnumValuesByNumberMap enum_values_by_number_; @@ -787,14 +795,13 @@ class FileDescriptorTables { }; DescriptorPool::Tables::Tables() - // Start some hash_map and hash_set objects with a small # of buckets + // Start some hash-map and hash-set objects with a small # of buckets : known_bad_files_(3), known_bad_symbols_(3), extensions_loaded_from_db_(3), symbols_by_name_(3), files_by_name_(3) {} - DescriptorPool::Tables::~Tables() { GOOGLE_DCHECK(checkpoints_.empty()); // Note that the deletion order is important, since the destructors of some @@ -948,8 +955,10 @@ inline Symbol FileDescriptorTables::FindNestedSymbolOfType( Symbol DescriptorPool::Tables::FindByNameHelper( const DescriptorPool* pool, const string& name) { MutexLockMaybe lock(pool->mutex_); - known_bad_symbols_.clear(); - known_bad_files_.clear(); + if (pool->fallback_database_ != NULL) { + known_bad_symbols_.clear(); + known_bad_files_.clear(); + } Symbol result = FindSymbol(name); if (result.IsNull() && pool->underlay_ != NULL) { @@ -1137,10 +1146,8 @@ bool DescriptorPool::Tables::AddFile(const FileDescriptor* file) { void FileDescriptorTables::FinalizeTables() { // Clean up the temporary maps used by AddFieldByStylizedNames(). - delete fields_by_lowercase_name_tmp_; - fields_by_lowercase_name_tmp_ = NULL; - delete fields_by_camelcase_name_tmp_; - fields_by_camelcase_name_tmp_ = NULL; + fields_by_lowercase_name_tmp_ = nullptr; + fields_by_camelcase_name_tmp_ = nullptr; } void FileDescriptorTables::AddFieldByStylizedNames( @@ -1155,7 +1162,7 @@ void FileDescriptorTables::AddFieldByStylizedNames( // entries from fields_by_number_. PointerStringPair lowercase_key(parent, field->lowercase_name().c_str()); - if (!InsertIfNotPresent(fields_by_lowercase_name_tmp_, lowercase_key, + if (!InsertIfNotPresent(fields_by_lowercase_name_tmp_.get(), lowercase_key, field)) { InsertIfNotPresent( &fields_by_lowercase_name_, lowercase_key, @@ -1163,7 +1170,7 @@ void FileDescriptorTables::AddFieldByStylizedNames( } PointerStringPair camelcase_key(parent, field->camelcase_name().c_str()); - if (!InsertIfNotPresent(fields_by_camelcase_name_tmp_, camelcase_key, + if (!InsertIfNotPresent(fields_by_camelcase_name_tmp_.get(), camelcase_key, field)) { InsertIfNotPresent( &fields_by_camelcase_name_, camelcase_key, @@ -1403,8 +1410,10 @@ void DescriptorPool::InternalAddGeneratedFile( const FileDescriptor* DescriptorPool::FindFileByName(const string& name) const { MutexLockMaybe lock(mutex_); - tables_->known_bad_symbols_.clear(); - tables_->known_bad_files_.clear(); + if (fallback_database_ != NULL) { + tables_->known_bad_symbols_.clear(); + tables_->known_bad_files_.clear(); + } const FileDescriptor* result = tables_->FindFile(name); if (result != NULL) return result; if (underlay_ != NULL) { @@ -1421,8 +1430,10 @@ const FileDescriptor* DescriptorPool::FindFileByName(const string& name) const { const FileDescriptor* DescriptorPool::FindFileContainingSymbol( const string& symbol_name) const { MutexLockMaybe lock(mutex_); - tables_->known_bad_symbols_.clear(); - tables_->known_bad_files_.clear(); + if (fallback_database_ != NULL) { + tables_->known_bad_symbols_.clear(); + tables_->known_bad_files_.clear(); + } Symbol result = tables_->FindSymbol(symbol_name); if (!result.IsNull()) return result.GetFile(); if (underlay_ != NULL) { @@ -1508,8 +1519,10 @@ const FieldDescriptor* DescriptorPool::FindExtensionByNumber( } } MutexLockMaybe lock(mutex_); - tables_->known_bad_symbols_.clear(); - tables_->known_bad_files_.clear(); + if (fallback_database_ != NULL) { + tables_->known_bad_symbols_.clear(); + tables_->known_bad_files_.clear(); + } const FieldDescriptor* result = tables_->FindExtension(extendee, number); if (result != NULL) { return result; @@ -1531,8 +1544,10 @@ void DescriptorPool::FindAllExtensions( const Descriptor* extendee, std::vector<const FieldDescriptor*>* out) const { MutexLockMaybe lock(mutex_); - tables_->known_bad_symbols_.clear(); - tables_->known_bad_files_.clear(); + if (fallback_database_ != NULL) { + tables_->known_bad_symbols_.clear(); + tables_->known_bad_files_.clear(); + } // Initialize tables_->extensions_ from the fallback database first // (but do this only once per descriptor). @@ -1784,6 +1799,15 @@ FileDescriptor::FindExtensionByCamelcaseName(const string& key) const { } } +void Descriptor::ExtensionRange::CopyTo( + DescriptorProto_ExtensionRange* proto) const { + proto->set_start(this->start); + proto->set_end(this->end); + if (options_ != &google::protobuf::ExtensionRangeOptions::default_instance()) { + *proto->mutable_options() = *options_; + } +} + const Descriptor::ExtensionRange* Descriptor::FindExtensionRangeContainingNumber(int number) const { // Linear search should be fine because we don't expect a message to have @@ -2051,13 +2075,7 @@ void Descriptor::CopyTo(DescriptorProto* proto) const { enum_type(i)->CopyTo(proto->add_enum_type()); } for (int i = 0; i < extension_range_count(); i++) { - DescriptorProto::ExtensionRange* range = proto->add_extension_range(); - range->set_start(extension_range(i)->start); - range->set_end(extension_range(i)->end); - const ExtensionRangeOptions* options = extension_range(i)->options_; - if (options != &ExtensionRangeOptions::default_instance()) { - range->mutable_options()->CopyFrom(*options); - } + extension_range(i)->CopyTo(proto->add_extension_range()); } for (int i = 0; i < extension_count(); i++) { extension(i)->CopyTo(proto->add_extension()); @@ -2288,7 +2306,7 @@ bool RetrieveOptions(int depth, const Message& options, return RetrieveOptionsAssumingRightPool(depth, options, option_entries); } DynamicMessageFactory factory; - google::protobuf::scoped_ptr<Message> dynamic_options( + std::unique_ptr<Message> dynamic_options( factory.GetPrototype(option_descriptor)->New()); if (dynamic_options->ParseFromString(options.SerializeAsString())) { return RetrieveOptionsAssumingRightPool(depth, *dynamic_options, @@ -3098,15 +3116,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; }; @@ -3273,7 +3294,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); @@ -3283,7 +3304,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. @@ -3372,13 +3394,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 @@ -3453,6 +3483,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_; @@ -4070,24 +4110,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 = @@ -4110,7 +4156,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)); } } @@ -4248,8 +4295,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 { @@ -4447,6 +4495,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 @@ -4518,7 +4570,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(), @@ -4539,7 +4592,7 @@ void DescriptorBuilder::BuildMessage(const DescriptorProto& proto, } } - hash_set<string> reserved_name_set; + HASH_SET<string> reserved_name_set; for (int i = 0; i < proto.reserved_name_size(); i++) { const string& name = proto.reserved_name(i); if (reserved_name_set.find(name) == reserved_name_set.end()) { @@ -4898,7 +4951,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); } @@ -4932,8 +4986,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); } } @@ -4985,7 +5047,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(), @@ -5102,7 +5165,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(), @@ -5114,18 +5178,18 @@ void DescriptorBuilder::BuildEnum(const EnumDescriptorProto& proto, for (int j = i + 1; j < proto.reserved_range_size(); j++) { const EnumDescriptorProto_EnumReservedRange& range2 = proto.reserved_range(j); - if (range1.end() > range2.start() && range2.end() > range1.start()) { + if (range1.end() >= range2.start() && range2.end() >= range1.start()) { AddError(result->full_name(), proto.reserved_range(i), DescriptorPool::ErrorCollector::NUMBER, strings::Substitute("Reserved range $0 to $1 overlaps with " "already-defined range $2 to $3.", - range2.start(), range2.end() - 1, - range1.start(), range1.end() - 1)); + range2.start(), range2.end(), + range1.start(), range1.end())); } } } - hash_set<string> reserved_name_set; + HASH_SET<string> reserved_name_set; for (int i = 0; i < proto.reserved_name_size(); i++) { const string& name = proto.reserved_name(i); if (reserved_name_set.find(name) == reserved_name_set.end()) { @@ -5179,7 +5243,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 @@ -5246,7 +5311,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(), @@ -5274,7 +5340,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(); @@ -5643,13 +5710,15 @@ void DescriptorBuilder::CrossLinkField( if (!tables_->AddExtension(field)) { const FieldDescriptor* conflicting_field = tables_->FindExtension(field->containing_type(), field->number()); + string containing_type_name = + field->containing_type() == NULL + ? "unknown" + : field->containing_type()->full_name(); string error_msg = strings::Substitute( "Extension number $0 has already been used in \"$1\" by extension " "\"$2\" defined in $3.", - field->number(), - field->containing_type()->full_name(), - conflicting_field->full_name(), - conflicting_field->file()->name()); + field->number(), containing_type_name, + conflicting_field->full_name(), conflicting_field->file()->name()); // Conflicting extension numbers should be an error. However, before // turning this into an error we need to fix all existing broken // protos first. @@ -6244,6 +6313,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()-> @@ -6254,14 +6326,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; @@ -6294,7 +6369,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 @@ -6340,6 +6415,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) { @@ -6402,19 +6479,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(); + } } } } @@ -6435,10 +6517,9 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption( return false; // ExamineIfOptionIsSet() already added the error. } - // First set the value on the UnknownFieldSet corresponding to the // innermost message. - google::protobuf::scoped_ptr<UnknownFieldSet> unknown_fields(new UnknownFieldSet()); + std::unique_ptr<UnknownFieldSet> unknown_fields(new UnknownFieldSet()); if (!SetOptionValue(field, unknown_fields.get())) { return false; // SetOptionValue() already added the error. } @@ -6448,7 +6529,7 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption( for (std::vector<const FieldDescriptor*>::reverse_iterator iter = intermediate_fields.rbegin(); iter != intermediate_fields.rend(); ++iter) { - google::protobuf::scoped_ptr<UnknownFieldSet> parent_unknown_fields( + std::unique_ptr<UnknownFieldSet> parent_unknown_fields( new UnknownFieldSet()); switch ((*iter)->type()) { case FieldDescriptor::TYPE_MESSAGE: { @@ -6481,9 +6562,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 = @@ -6767,7 +6949,7 @@ class DescriptorBuilder::OptionInterpreter::AggregateOptionFinder DescriptorBuilder* builder_; virtual const FieldDescriptor* FindExtension( - Message* message, const string& name) const { + Message* message, const string& name) const override { assert_mutex_held(builder_->pool_); const Descriptor* descriptor = message->GetDescriptor(); Symbol result = builder_->LookupSymbolNoPlaceholder( @@ -6805,7 +6987,7 @@ class AggregateErrorCollector : public io::ErrorCollector { string error_; virtual void AddError(int /* line */, int /* column */, - const string& message) { + const string& message) override { if (!error_.empty()) { error_ += "; "; } @@ -6813,7 +6995,7 @@ class AggregateErrorCollector : public io::ErrorCollector { } virtual void AddWarning(int /* line */, int /* column */, - const string& /* message */) { + const string& /* message */) override { // Ignore warnings } }; @@ -6836,7 +7018,7 @@ bool DescriptorBuilder::OptionInterpreter::SetAggregateOption( } const Descriptor* type = option_field->message_type(); - google::protobuf::scoped_ptr<Message> dynamic(dynamic_factory_.GetPrototype(type)->New()); + std::unique_ptr<Message> dynamic(dynamic_factory_.GetPrototype(type)->New()); GOOGLE_CHECK(dynamic.get() != NULL) << "Could not create an instance of " << option_field->DebugString(); |