diff options
Diffstat (limited to 'src/google/protobuf/descriptor.cc')
-rw-r--r-- | src/google/protobuf/descriptor.cc | 1195 |
1 files changed, 778 insertions, 417 deletions
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index eb5b5937..ecca3293 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -167,14 +167,6 @@ string ToCamelCase(const string& input) { typedef pair<const void*, const char*> PointerStringPair; -// Used by GCC/SGI STL only. (Why isn't this provided by the standard -// library? :( ) -struct CStringEqual { - inline bool operator()(const char* a, const char* b) const { - return strcmp(a, b) == 0; - } -}; - struct PointerStringPairEqual { inline bool operator()(const PointerStringPair& a, const PointerStringPair& b) const { @@ -240,6 +232,13 @@ struct Symbol { inline Symbol() : type(NULL_SYMBOL) { descriptor = NULL; } inline bool IsNull() const { return type == NULL_SYMBOL; } + inline bool IsType() const { + return type == MESSAGE || type == ENUM; + } + inline bool IsAggregate() const { + return type == MESSAGE || type == PACKAGE + || type == ENUM || type == SERVICE; + } #define CONSTRUCTOR(TYPE, TYPE_CONSTANT, FIELD) \ inline explicit Symbol(const TYPE* value) { \ @@ -274,13 +273,13 @@ struct Symbol { const Symbol kNullSymbol; typedef hash_map<const char*, Symbol, - hash<const char*>, CStringEqual> + hash<const char*>, streq> SymbolsByNameMap; typedef hash_map<PointerStringPair, Symbol, PointerStringPairHash, PointerStringPairEqual> SymbolsByParentMap; typedef hash_map<const char*, const FileDescriptor*, - hash<const char*>, CStringEqual> + hash<const char*>, streq> FilesByNameMap; typedef hash_map<PointerStringPair, const FieldDescriptor*, PointerStringPairHash, PointerStringPairEqual> @@ -291,6 +290,12 @@ typedef hash_map<DescriptorIntPair, const FieldDescriptor*, typedef hash_map<EnumIntPair, const EnumValueDescriptor*, PointerIntegerPairHash<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 map<DescriptorIntPair, const FieldDescriptor*> + ExtensionsGroupedByDescriptorMap; } // anonymous namespace @@ -324,17 +329,16 @@ class DescriptorPool::Tables { // Not used when fallback_database_ == NULL. hash_set<string> known_bad_files_; + // 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_; + // ----------------------------------------------------------------- // Finding items. - // Find symbols. These return a null Symbol (symbol.IsNull() is true) + // Find symbols. This returns a null Symbol (symbol.IsNull() is true) // if not found. inline Symbol FindSymbol(const string& key) const; - inline Symbol FindNestedSymbol(const void* parent, - const string& name) const; - inline Symbol FindNestedSymbolOfType(const void* parent, - const string& name, - const Symbol::Type type) const; // This implements the body of DescriptorPool::Find*ByName(). It should // really be a private method of DescriptorPool, but that would require @@ -345,40 +349,21 @@ class DescriptorPool::Tables { // These return NULL if not found. inline const FileDescriptor* FindFile(const string& key) const; - inline const FieldDescriptor* FindFieldByNumber( - const Descriptor* parent, int number) const; - inline const FieldDescriptor* FindFieldByLowercaseName( - const void* parent, const string& lowercase_name) const; - inline const FieldDescriptor* FindFieldByCamelcaseName( - const void* parent, const string& camelcase_name) const; - inline const EnumValueDescriptor* FindEnumValueByNumber( - const EnumDescriptor* parent, int number) const; + inline const FieldDescriptor* FindExtension(const Descriptor* extendee, + int number); + inline void FindAllExtensions(const Descriptor* extendee, + vector<const FieldDescriptor*>* out) const; // ----------------------------------------------------------------- // Adding items. // These add items to the corresponding tables. They return false if - // the key already exists in the table. For AddSymbol(), the strings passed - // in must be ones that were constructed using AllocateString(), as they will - // be used as keys in the symbols_by_name_ and symbols_by_parent_ maps - // without copying. (If parent is NULL, nothing is added to - // symbols_by_parent_.) - bool AddSymbol(const string& full_name, - const void* parent, const string& name, - Symbol symbol); + // the key already exists in the table. For AddSymbol(), the string passed + // in must be one that was constructed using AllocateString(), as it will + // be used as a key in the symbols_by_name_ map without copying. + bool AddSymbol(const string& full_name, Symbol symbol); bool AddFile(const FileDescriptor* file); - bool AddFieldByNumber(const FieldDescriptor* field); - bool AddEnumValueByNumber(const EnumValueDescriptor* value); - - // Adds the field to the lowercase_name and camelcase_name maps. Never - // fails because we allow duplicates; the first field by the name wins. - void AddFieldByStylizedNames(const FieldDescriptor* field); - - // Like AddSymbol(), but only adds to symbols_by_parent_, not - // symbols_by_name_. Used for enum values, which need to be registered - // under multiple parents (their type and its parent). - bool AddAliasUnderParent(const void* parent, const string& name, - Symbol symbol); + bool AddExtension(const FieldDescriptor* field); // ----------------------------------------------------------------- // Allocating memory. @@ -397,38 +382,100 @@ class DescriptorPool::Tables { // The string is initialized to the given value for convenience. string* AllocateString(const string& value); - // Allocate a protocol message object. - template<typename Type> Type* AllocateMessage(); + // Allocate a protocol message object. Some older versions of GCC have + // trouble understanding explicit template instantiations in some cases, so + // in those cases we have to pass a dummy pointer of the right type as the + // parameter instead of specifying the type explicitly. + template<typename Type> Type* AllocateMessage(Type* dummy = NULL); + + // Allocate a FileDescriptorTables object. + FileDescriptorTables* AllocateFileTables(); private: vector<string*> strings_; // All strings in the pool. vector<Message*> messages_; // All messages in the pool. + vector<FileDescriptorTables*> file_tables_; // All file tables in the pool. vector<void*> allocations_; // All other memory allocated in the pool. SymbolsByNameMap symbols_by_name_; - SymbolsByParentMap symbols_by_parent_; FilesByNameMap files_by_name_; - FieldsByNameMap fields_by_lowercase_name_; - FieldsByNameMap fields_by_camelcase_name_; - FieldsByNumberMap fields_by_number_; // Includes extensions. - EnumValuesByNumberMap enum_values_by_number_; + ExtensionsGroupedByDescriptorMap extensions_; int strings_before_checkpoint_; int messages_before_checkpoint_; + int file_tables_before_checkpoint_; int allocations_before_checkpoint_; vector<const char* > symbols_after_checkpoint_; - vector<PointerStringPair> symbols_by_parent_after_checkpoint_; vector<const char* > files_after_checkpoint_; - vector<PointerStringPair> field_lowercase_names_after_checkpoint_; - vector<PointerStringPair> field_camelcase_names_after_checkpoint_; - vector<DescriptorIntPair> field_numbers_after_checkpoint_; - vector<EnumIntPair > enum_numbers_after_checkpoint_; + vector<DescriptorIntPair> extensions_after_checkpoint_; // Allocate some bytes which will be reclaimed when the pool is // destroyed. void* AllocateBytes(int size); }; +// Contains tables specific to a particular file. These tables are not +// modified once the file has been constructed, so they need not be +// protected by a mutex. This makes operations that depend only on the +// contents of a single file -- e.g. Descriptor::FindFieldByName() -- +// lock-free. +// +// For historical reasons, the definitions of the methods of +// FileDescriptorTables and DescriptorPool::Tables are interleaved below. +// These used to be a single class. +class FileDescriptorTables { + public: + FileDescriptorTables(); + ~FileDescriptorTables(); + + // Empty table, used with placeholder files. + static const FileDescriptorTables kEmpty; + + // ----------------------------------------------------------------- + // Finding items. + + // Find symbols. These return a null Symbol (symbol.IsNull() is true) + // if not found. + inline Symbol FindNestedSymbol(const void* parent, + const string& name) const; + inline Symbol FindNestedSymbolOfType(const void* parent, + const string& name, + const Symbol::Type type) const; + + // These return NULL if not found. + inline const FieldDescriptor* FindFieldByNumber( + const Descriptor* parent, int number) const; + inline const FieldDescriptor* FindFieldByLowercaseName( + const void* parent, const string& lowercase_name) const; + inline const FieldDescriptor* FindFieldByCamelcaseName( + const void* parent, const string& camelcase_name) const; + inline const EnumValueDescriptor* FindEnumValueByNumber( + const EnumDescriptor* parent, int number) const; + + // ----------------------------------------------------------------- + // Adding items. + + // These add items to the corresponding tables. They return false if + // the key already exists in the table. For AddAliasUnderParent(), the + // string passed in must be one that was constructed using AllocateString(), + // as it will be used as a key in the symbols_by_parent_ map without copying. + bool AddAliasUnderParent(const void* parent, const string& name, + Symbol symbol); + bool AddFieldByNumber(const FieldDescriptor* field); + bool AddEnumValueByNumber(const EnumValueDescriptor* value); + + // Adds the field to the lowercase_name and camelcase_name maps. Never + // fails because we allow duplicates; the first field by the name wins. + void AddFieldByStylizedNames(const FieldDescriptor* field); + + private: + SymbolsByParentMap symbols_by_parent_; + FieldsByNameMap fields_by_lowercase_name_; + FieldsByNameMap fields_by_camelcase_name_; + FieldsByNumberMap fields_by_number_; // Not including extensions. + EnumValuesByNumberMap enum_values_by_number_; +}; + DescriptorPool::Tables::Tables() : strings_before_checkpoint_(0), messages_before_checkpoint_(0), @@ -442,63 +489,53 @@ DescriptorPool::Tables::~Tables() { operator delete(allocations_[i]); } STLDeleteElements(&strings_); + STLDeleteElements(&file_tables_); } +FileDescriptorTables::FileDescriptorTables() {} +FileDescriptorTables::~FileDescriptorTables() {} + +const FileDescriptorTables FileDescriptorTables::kEmpty; + void DescriptorPool::Tables::Checkpoint() { strings_before_checkpoint_ = strings_.size(); messages_before_checkpoint_ = messages_.size(); + file_tables_before_checkpoint_ = file_tables_.size(); allocations_before_checkpoint_ = allocations_.size(); symbols_after_checkpoint_.clear(); - symbols_by_parent_after_checkpoint_.clear(); files_after_checkpoint_.clear(); - field_lowercase_names_after_checkpoint_.clear(); - field_camelcase_names_after_checkpoint_.clear(); - field_numbers_after_checkpoint_.clear(); - enum_numbers_after_checkpoint_.clear(); + extensions_after_checkpoint_.clear(); } void DescriptorPool::Tables::Rollback() { for (int i = 0; i < symbols_after_checkpoint_.size(); i++) { symbols_by_name_.erase(symbols_after_checkpoint_[i]); } - for (int i = 0; i < symbols_by_parent_after_checkpoint_.size(); i++) { - symbols_by_parent_.erase(symbols_by_parent_after_checkpoint_[i]); - } for (int i = 0; i < files_after_checkpoint_.size(); i++) { files_by_name_.erase(files_after_checkpoint_[i]); } - for (int i = 0; i < field_lowercase_names_after_checkpoint_.size(); i++) { - fields_by_lowercase_name_.erase(field_lowercase_names_after_checkpoint_[i]); - } - for (int i = 0; i < field_camelcase_names_after_checkpoint_.size(); i++) { - fields_by_camelcase_name_.erase(field_camelcase_names_after_checkpoint_[i]); - } - for (int i = 0; i < field_numbers_after_checkpoint_.size(); i++) { - fields_by_number_.erase(field_numbers_after_checkpoint_[i]); - } - for (int i = 0; i < enum_numbers_after_checkpoint_.size(); i++) { - enum_values_by_number_.erase(enum_numbers_after_checkpoint_[i]); + for (int i = 0; i < extensions_after_checkpoint_.size(); i++) { + extensions_.erase(extensions_after_checkpoint_[i]); } symbols_after_checkpoint_.clear(); - symbols_by_parent_after_checkpoint_.clear(); files_after_checkpoint_.clear(); - field_lowercase_names_after_checkpoint_.clear(); - field_camelcase_names_after_checkpoint_.clear(); - field_numbers_after_checkpoint_.clear(); - enum_numbers_after_checkpoint_.clear(); + extensions_after_checkpoint_.clear(); STLDeleteContainerPointers( strings_.begin() + strings_before_checkpoint_, strings_.end()); STLDeleteContainerPointers( messages_.begin() + messages_before_checkpoint_, messages_.end()); + STLDeleteContainerPointers( + file_tables_.begin() + file_tables_before_checkpoint_, file_tables_.end()); for (int i = allocations_before_checkpoint_; i < allocations_.size(); i++) { operator delete(allocations_[i]); } strings_.resize(strings_before_checkpoint_); messages_.resize(messages_before_checkpoint_); + file_tables_.resize(file_tables_before_checkpoint_); allocations_.resize(allocations_before_checkpoint_); } @@ -513,7 +550,7 @@ inline Symbol DescriptorPool::Tables::FindSymbol(const string& key) const { } } -inline Symbol DescriptorPool::Tables::FindNestedSymbol( +inline Symbol FileDescriptorTables::FindNestedSymbol( const void* parent, const string& name) const { const Symbol* result = FindOrNull(symbols_by_parent_, PointerStringPair(parent, name.c_str())); @@ -524,7 +561,7 @@ inline Symbol DescriptorPool::Tables::FindNestedSymbol( } } -inline Symbol DescriptorPool::Tables::FindNestedSymbolOfType( +inline Symbol FileDescriptorTables::FindNestedSymbolOfType( const void* parent, const string& name, const Symbol::Type type) const { Symbol result = FindNestedSymbol(parent, name); if (result.type != type) return kNullSymbol; @@ -557,59 +594,58 @@ inline const FileDescriptor* DescriptorPool::Tables::FindFile( return FindPtrOrNull(files_by_name_, key.c_str()); } -inline const FieldDescriptor* DescriptorPool::Tables::FindFieldByNumber( +inline const FieldDescriptor* FileDescriptorTables::FindFieldByNumber( const Descriptor* parent, int number) const { return FindPtrOrNull(fields_by_number_, make_pair(parent, number)); } -inline const FieldDescriptor* DescriptorPool::Tables::FindFieldByLowercaseName( +inline const FieldDescriptor* FileDescriptorTables::FindFieldByLowercaseName( const void* parent, const string& lowercase_name) const { return FindPtrOrNull(fields_by_lowercase_name_, PointerStringPair(parent, lowercase_name.c_str())); } -inline const FieldDescriptor* DescriptorPool::Tables::FindFieldByCamelcaseName( +inline const FieldDescriptor* FileDescriptorTables::FindFieldByCamelcaseName( const void* parent, const string& camelcase_name) const { return FindPtrOrNull(fields_by_camelcase_name_, PointerStringPair(parent, camelcase_name.c_str())); } -inline const EnumValueDescriptor* DescriptorPool::Tables::FindEnumValueByNumber( +inline const EnumValueDescriptor* FileDescriptorTables::FindEnumValueByNumber( const EnumDescriptor* parent, int number) const { return FindPtrOrNull(enum_values_by_number_, make_pair(parent, number)); } +inline const FieldDescriptor* DescriptorPool::Tables::FindExtension( + const Descriptor* extendee, int number) { + return FindPtrOrNull(extensions_, make_pair(extendee, number)); +} + +inline void DescriptorPool::Tables::FindAllExtensions( + const Descriptor* extendee, vector<const FieldDescriptor*>* out) const { + ExtensionsGroupedByDescriptorMap::const_iterator it = + extensions_.lower_bound(make_pair(extendee, 0)); + for (; it != extensions_.end() && it->first.first == extendee; ++it) { + out->push_back(it->second); + } +} + // ------------------------------------------------------------------- bool DescriptorPool::Tables::AddSymbol( - const string& full_name, - const void* parent, const string& name, - Symbol symbol) { + const string& full_name, Symbol symbol) { if (InsertIfNotPresent(&symbols_by_name_, full_name.c_str(), symbol)) { symbols_after_checkpoint_.push_back(full_name.c_str()); - - if (parent != NULL && !AddAliasUnderParent(parent, name, symbol)) { - GOOGLE_LOG(DFATAL) << "\"" << full_name << "\" not previously defined in " - "symbols_by_name_, but was defined in symbols_by_parent_; " - "this shouldn't be possible."; - return false; - } - return true; } else { return false; } } -bool DescriptorPool::Tables::AddAliasUnderParent( +bool FileDescriptorTables::AddAliasUnderParent( const void* parent, const string& name, Symbol symbol) { PointerStringPair by_parent_key(parent, name.c_str()); - if (InsertIfNotPresent(&symbols_by_parent_, by_parent_key, symbol)) { - symbols_by_parent_after_checkpoint_.push_back(by_parent_key); - return true; - } else { - return false; - } + return InsertIfNotPresent(&symbols_by_parent_, by_parent_key, symbol); } bool DescriptorPool::Tables::AddFile(const FileDescriptor* file) { @@ -621,7 +657,7 @@ bool DescriptorPool::Tables::AddFile(const FileDescriptor* file) { } } -void DescriptorPool::Tables::AddFieldByStylizedNames( +void FileDescriptorTables::AddFieldByStylizedNames( const FieldDescriptor* field) { const void* parent; if (field->is_extension()) { @@ -635,31 +671,27 @@ void DescriptorPool::Tables::AddFieldByStylizedNames( } PointerStringPair lowercase_key(parent, field->lowercase_name().c_str()); - if (InsertIfNotPresent(&fields_by_lowercase_name_, lowercase_key, field)) { - field_lowercase_names_after_checkpoint_.push_back(lowercase_key); - } + InsertIfNotPresent(&fields_by_lowercase_name_, lowercase_key, field); PointerStringPair camelcase_key(parent, field->camelcase_name().c_str()); - if (InsertIfNotPresent(&fields_by_camelcase_name_, camelcase_key, field)) { - field_camelcase_names_after_checkpoint_.push_back(camelcase_key); - } + InsertIfNotPresent(&fields_by_camelcase_name_, camelcase_key, field); } -bool DescriptorPool::Tables::AddFieldByNumber(const FieldDescriptor* field) { +bool FileDescriptorTables::AddFieldByNumber(const FieldDescriptor* field) { DescriptorIntPair key(field->containing_type(), field->number()); - if (InsertIfNotPresent(&fields_by_number_, key, field)) { - field_numbers_after_checkpoint_.push_back(key); - return true; - } else { - return false; - } + return InsertIfNotPresent(&fields_by_number_, key, field); } -bool DescriptorPool::Tables::AddEnumValueByNumber( +bool FileDescriptorTables::AddEnumValueByNumber( const EnumValueDescriptor* value) { EnumIntPair key(value->type(), value->number()); - if (InsertIfNotPresent(&enum_values_by_number_, key, value)) { - enum_numbers_after_checkpoint_.push_back(key); + return InsertIfNotPresent(&enum_values_by_number_, key, value); +} + +bool DescriptorPool::Tables::AddExtension(const FieldDescriptor* field) { + DescriptorIntPair key(field->containing_type(), field->number()); + if (InsertIfNotPresent(&extensions_, key, field)) { + extensions_after_checkpoint_.push_back(key); return true; } else { return false; @@ -685,12 +717,18 @@ string* DescriptorPool::Tables::AllocateString(const string& value) { } template<typename Type> -Type* DescriptorPool::Tables::AllocateMessage() { +Type* DescriptorPool::Tables::AllocateMessage(Type* dummy) { Type* result = new Type; messages_.push_back(result); return result; } +FileDescriptorTables* DescriptorPool::Tables::AllocateFileTables() { + FileDescriptorTables* result = new FileDescriptorTables; + file_tables_.push_back(result); + return result; +} + void* DescriptorPool::Tables::AllocateBytes(int size) { // TODO(kenton): Would it be worthwhile to implement this in some more // sophisticated way? Probably not for the open source release, but for @@ -715,7 +753,7 @@ DescriptorPool::DescriptorPool() underlay_(NULL), tables_(new Tables), enforce_dependencies_(true), - last_internal_build_generated_file_call_(NULL) {} + allow_unknown_(false) {} DescriptorPool::DescriptorPool(DescriptorDatabase* fallback_database, ErrorCollector* error_collector) @@ -725,7 +763,7 @@ DescriptorPool::DescriptorPool(DescriptorDatabase* fallback_database, underlay_(NULL), tables_(new Tables), enforce_dependencies_(true), - last_internal_build_generated_file_call_(NULL) { + allow_unknown_(false) { } DescriptorPool::DescriptorPool(const DescriptorPool* underlay) @@ -734,7 +772,8 @@ DescriptorPool::DescriptorPool(const DescriptorPool* underlay) default_error_collector_(NULL), underlay_(underlay), tables_(new Tables), - last_internal_build_generated_file_call_(NULL) {} + enforce_dependencies_(true), + allow_unknown_(false) {} DescriptorPool::~DescriptorPool() { if (mutex_ != NULL) delete mutex_; @@ -742,21 +781,78 @@ DescriptorPool::~DescriptorPool() { // DescriptorPool::BuildFile() defined later. // DescriptorPool::BuildFileCollectingErrors() defined later. -// DescriptorPool::InternalBuildGeneratedFile() defined later. + +void DescriptorPool::InternalDontEnforceDependencies() { + enforce_dependencies_ = false; +} + +bool DescriptorPool::InternalIsFileLoaded(const string& filename) const { + MutexLockMaybe lock(mutex_); + return tables_->FindFile(filename) != NULL; +} + +// generated_pool ==================================================== + +namespace { + +EncodedDescriptorDatabase* generated_database_ = NULL; +DescriptorPool* generated_pool_ = NULL; + +void InitGeneratedPool() { + GOOGLE_CHECK(generated_pool_ == NULL); + generated_database_ = new EncodedDescriptorDatabase; + generated_pool_ = new DescriptorPool(generated_database_); +} + +// Force InitGeneratedPool to be called at static init time, before any threads +// can be created. +struct Initializer { + Initializer() { + if (generated_pool_ == NULL) InitGeneratedPool(); + } +} initializer; + +} // anonymous namespace const DescriptorPool* DescriptorPool::generated_pool() { - return internal_generated_pool(); + if (generated_pool_ == NULL) InitGeneratedPool(); + return generated_pool_; } DescriptorPool* DescriptorPool::internal_generated_pool() { - static DescriptorPool singleton; - return &singleton; + if (generated_pool_ == NULL) InitGeneratedPool(); + return generated_pool_; } -void DescriptorPool::InternalDontEnforceDependencies() { - enforce_dependencies_ = false; +void DescriptorPool::InternalAddGeneratedFile( + const void* encoded_file_descriptor, int size) { + // So, this function is called in the process of initializing the + // descriptors for generated proto classes. Each generated .pb.cc file + // has an internal procedure called AddDescriptors() which is called at + // process startup, and that function calls this one in order to register + // the raw bytes of the FileDescriptorProto representing the file. + // + // We do not actually construct the descriptor objects right away. We just + // hang on to the bytes until they are actually needed. We actually construct + // the descriptor the first time one of the following things happens: + // * Someone calls a method like descriptor(), GetDescriptor(), or + // GetReflection() on the generated types, which requires returning the + // descriptor or an object based on it. + // * Someone looks up the descriptor in DescriptorPool::generated_pool(). + // + // Once one of these happens, the DescriptorPool actually parses the + // FileDescriptorProto and generates a FileDescriptor (and all its children) + // based on it. + // + // Note that FileDescriptorProto is itself a generated protocol message. + // Therefore, when we parse one, we have to be very careful to avoid using + // any descriptor-based operations, since this might cause infinite recursion + // or deadlock. + if (generated_pool_ == NULL) InitGeneratedPool(); + GOOGLE_CHECK(generated_database_->Add(encoded_file_descriptor, size)); } + // Find*By* methods ================================================== // TODO(kenton): There's a lot of repeated code here, but I'm not sure if @@ -851,8 +947,8 @@ const MethodDescriptor* DescriptorPool::FindMethodByName( const FieldDescriptor* DescriptorPool::FindExtensionByNumber( const Descriptor* extendee, int number) const { MutexLockMaybe lock(mutex_); - const FieldDescriptor* result = tables_->FindFieldByNumber(extendee, number); - if (result != NULL && result->is_extension()) { + const FieldDescriptor* result = tables_->FindExtension(extendee, number); + if (result != NULL) { return result; } if (underlay_ != NULL) { @@ -861,22 +957,47 @@ const FieldDescriptor* DescriptorPool::FindExtensionByNumber( if (result != NULL) return result; } if (TryFindExtensionInFallbackDatabase(extendee, number)) { - const FieldDescriptor* result = - tables_->FindFieldByNumber(extendee, number); - if (result != NULL && result->is_extension()) { + const FieldDescriptor* result = tables_->FindExtension(extendee, number); + if (result != NULL) { return result; } } return NULL; } +void DescriptorPool::FindAllExtensions( + const Descriptor* extendee, vector<const FieldDescriptor*>* out) const { + MutexLockMaybe lock(mutex_); + + // Initialize tables_->extensions_ from the fallback database first + // (but do this only once per descriptor). + if (fallback_database_ != NULL && + tables_->extensions_loaded_from_db_.count(extendee) == 0) { + vector<int> numbers; + if (fallback_database_->FindAllExtensionNumbers(extendee->full_name(), + &numbers)) { + for (int i = 0; i < numbers.size(); ++i) { + int number = numbers[i]; + if (tables_->FindExtension(extendee, number) == NULL) { + TryFindExtensionInFallbackDatabase(extendee, number); + } + } + tables_->extensions_loaded_from_db_.insert(extendee); + } + } + + tables_->FindAllExtensions(extendee, out); + if (underlay_ != NULL) { + underlay_->FindAllExtensions(extendee, out); + } +} + // ------------------------------------------------------------------- const FieldDescriptor* Descriptor::FindFieldByNumber(int key) const { - MutexLockMaybe lock(file()->pool()->mutex_); const FieldDescriptor* result = - file()->pool()->tables_->FindFieldByNumber(this, key); + file()->tables_->FindFieldByNumber(this, key); if (result == NULL || result->is_extension()) { return NULL; } else { @@ -886,9 +1007,8 @@ Descriptor::FindFieldByNumber(int key) const { const FieldDescriptor* Descriptor::FindFieldByLowercaseName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); const FieldDescriptor* result = - file()->pool()->tables_->FindFieldByLowercaseName(this, key); + file()->tables_->FindFieldByLowercaseName(this, key); if (result == NULL || result->is_extension()) { return NULL; } else { @@ -898,9 +1018,8 @@ Descriptor::FindFieldByLowercaseName(const string& key) const { const FieldDescriptor* Descriptor::FindFieldByCamelcaseName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); const FieldDescriptor* result = - file()->pool()->tables_->FindFieldByCamelcaseName(this, key); + file()->tables_->FindFieldByCamelcaseName(this, key); if (result == NULL || result->is_extension()) { return NULL; } else { @@ -910,9 +1029,8 @@ Descriptor::FindFieldByCamelcaseName(const string& key) const { const FieldDescriptor* Descriptor::FindFieldByName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); Symbol result = - file()->pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD); + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD); if (!result.IsNull() && !result.field_descriptor->is_extension()) { return result.field_descriptor; } else { @@ -922,9 +1040,8 @@ Descriptor::FindFieldByName(const string& key) const { const FieldDescriptor* Descriptor::FindExtensionByName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); Symbol result = - file()->pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD); + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD); if (!result.IsNull() && result.field_descriptor->is_extension()) { return result.field_descriptor; } else { @@ -934,9 +1051,8 @@ Descriptor::FindExtensionByName(const string& key) const { const FieldDescriptor* Descriptor::FindExtensionByLowercaseName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); const FieldDescriptor* result = - file()->pool()->tables_->FindFieldByLowercaseName(this, key); + file()->tables_->FindFieldByLowercaseName(this, key); if (result == NULL || !result->is_extension()) { return NULL; } else { @@ -946,9 +1062,8 @@ Descriptor::FindExtensionByLowercaseName(const string& key) const { const FieldDescriptor* Descriptor::FindExtensionByCamelcaseName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); const FieldDescriptor* result = - file()->pool()->tables_->FindFieldByCamelcaseName(this, key); + file()->tables_->FindFieldByCamelcaseName(this, key); if (result == NULL || !result->is_extension()) { return NULL; } else { @@ -958,9 +1073,8 @@ Descriptor::FindExtensionByCamelcaseName(const string& key) const { const Descriptor* Descriptor::FindNestedTypeByName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); Symbol result = - file()->pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::MESSAGE); + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::MESSAGE); if (!result.IsNull()) { return result.descriptor; } else { @@ -970,9 +1084,8 @@ Descriptor::FindNestedTypeByName(const string& key) const { const EnumDescriptor* Descriptor::FindEnumTypeByName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); Symbol result = - file()->pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM); + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM); if (!result.IsNull()) { return result.enum_descriptor; } else { @@ -982,10 +1095,8 @@ Descriptor::FindEnumTypeByName(const string& key) const { const EnumValueDescriptor* Descriptor::FindEnumValueByName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); Symbol result = - file()->pool()->tables_->FindNestedSymbolOfType( - this, key, Symbol::ENUM_VALUE); + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM_VALUE); if (!result.IsNull()) { return result.enum_value_descriptor; } else { @@ -995,10 +1106,8 @@ Descriptor::FindEnumValueByName(const string& key) const { const EnumValueDescriptor* EnumDescriptor::FindValueByName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); Symbol result = - file()->pool()->tables_->FindNestedSymbolOfType( - this, key, Symbol::ENUM_VALUE); + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM_VALUE); if (!result.IsNull()) { return result.enum_value_descriptor; } else { @@ -1008,15 +1117,13 @@ EnumDescriptor::FindValueByName(const string& key) const { const EnumValueDescriptor* EnumDescriptor::FindValueByNumber(int key) const { - MutexLockMaybe lock(file()->pool()->mutex_); - return file()->pool()->tables_->FindEnumValueByNumber(this, key); + return file()->tables_->FindEnumValueByNumber(this, key); } const MethodDescriptor* ServiceDescriptor::FindMethodByName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); Symbol result = - file()->pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::METHOD); + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::METHOD); if (!result.IsNull()) { return result.method_descriptor; } else { @@ -1026,9 +1133,7 @@ ServiceDescriptor::FindMethodByName(const string& key) const { const Descriptor* FileDescriptor::FindMessageTypeByName(const string& key) const { - MutexLockMaybe lock(pool()->mutex_); - Symbol result = - pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::MESSAGE); + Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::MESSAGE); if (!result.IsNull()) { return result.descriptor; } else { @@ -1038,9 +1143,7 @@ FileDescriptor::FindMessageTypeByName(const string& key) const { const EnumDescriptor* FileDescriptor::FindEnumTypeByName(const string& key) const { - MutexLockMaybe lock(pool()->mutex_); - Symbol result = - pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM); + Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM); if (!result.IsNull()) { return result.enum_descriptor; } else { @@ -1050,9 +1153,8 @@ FileDescriptor::FindEnumTypeByName(const string& key) const { const EnumValueDescriptor* FileDescriptor::FindEnumValueByName(const string& key) const { - MutexLockMaybe lock(pool()->mutex_); Symbol result = - pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM_VALUE); + tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM_VALUE); if (!result.IsNull()) { return result.enum_value_descriptor; } else { @@ -1062,9 +1164,7 @@ FileDescriptor::FindEnumValueByName(const string& key) const { const ServiceDescriptor* FileDescriptor::FindServiceByName(const string& key) const { - MutexLockMaybe lock(pool()->mutex_); - Symbol result = - pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::SERVICE); + Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::SERVICE); if (!result.IsNull()) { return result.service_descriptor; } else { @@ -1074,9 +1174,7 @@ FileDescriptor::FindServiceByName(const string& key) const { const FieldDescriptor* FileDescriptor::FindExtensionByName(const string& key) const { - MutexLockMaybe lock(pool()->mutex_); - Symbol result = - pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD); + Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD); if (!result.IsNull() && result.field_descriptor->is_extension()) { return result.field_descriptor; } else { @@ -1086,9 +1184,7 @@ FileDescriptor::FindExtensionByName(const string& key) const { const FieldDescriptor* FileDescriptor::FindExtensionByLowercaseName(const string& key) const { - MutexLockMaybe lock(pool()->mutex_); - const FieldDescriptor* result = - pool()->tables_->FindFieldByLowercaseName(this, key); + const FieldDescriptor* result = tables_->FindFieldByLowercaseName(this, key); if (result == NULL || !result->is_extension()) { return NULL; } else { @@ -1098,9 +1194,7 @@ FileDescriptor::FindExtensionByLowercaseName(const string& key) const { const FieldDescriptor* FileDescriptor::FindExtensionByCamelcaseName(const string& key) const { - MutexLockMaybe lock(pool()->mutex_); - const FieldDescriptor* result = - pool()->tables_->FindFieldByCamelcaseName(this, key); + const FieldDescriptor* result = tables_->FindFieldByCamelcaseName(this, key); if (result == NULL || !result->is_extension()) { return NULL; } else { @@ -1297,15 +1391,27 @@ void FieldDescriptor::CopyTo(FieldDescriptorProto* proto) const { implicit_cast<int>(type()))); if (is_extension()) { - proto->set_extendee("."); + if (!containing_type()->is_unqualified_placeholder_) { + proto->set_extendee("."); + } proto->mutable_extendee()->append(containing_type()->full_name()); } if (cpp_type() == CPPTYPE_MESSAGE) { - proto->set_type_name("."); + if (message_type()->is_placeholder_) { + // We don't actually know if the type is a message type. It could be + // an enum. + proto->clear_type(); + } + + if (!message_type()->is_unqualified_placeholder_) { + proto->set_type_name("."); + } proto->mutable_type_name()->append(message_type()->full_name()); } else if (cpp_type() == CPPTYPE_ENUM) { - proto->set_type_name("."); + if (!enum_type()->is_unqualified_placeholder_) { + proto->set_type_name("."); + } proto->mutable_type_name()->append(enum_type()->full_name()); } @@ -1354,9 +1460,14 @@ void ServiceDescriptor::CopyTo(ServiceDescriptorProto* proto) const { void MethodDescriptor::CopyTo(MethodDescriptorProto* proto) const { proto->set_name(name()); - proto->set_input_type("."); + if (!input_type()->is_unqualified_placeholder_) { + proto->set_input_type("."); + } proto->mutable_input_type()->append(input_type()->full_name()); - proto->set_output_type("."); + + if (!output_type()->is_unqualified_placeholder_) { + proto->set_output_type("."); + } proto->mutable_output_type()->append(output_type()->full_name()); if (&options() != &MethodOptions::default_instance()) { @@ -1720,8 +1831,7 @@ class DescriptorBuilder { DescriptorPool::ErrorCollector* error_collector); ~DescriptorBuilder(); - const FileDescriptor* BuildFile(const FileDescriptorProto& proto, - DescriptorPool::InternalDescriptorAssigner descriptor_assigner); + const FileDescriptor* BuildFile(const FileDescriptorProto& proto); private: friend class OptionInterpreter; @@ -1738,6 +1848,7 @@ class DescriptorBuilder { bool had_errors_; string filename_; FileDescriptor* file_; + FileDescriptorTables* file_tables_; // If LookupSymbol() finds a symbol that is in a file which is not a declared // dependency of this file, it will fail, but will set @@ -1778,8 +1889,40 @@ class DescriptorBuilder { // parents, etc. For example, LookupSymbol("foo.bar", "baz.qux.corge") makes // the following calls, returning the first non-null result: // FindSymbol("baz.qux.foo.bar"), FindSymbol("baz.foo.bar"), - // FindSymbol("foo.bar"). - Symbol LookupSymbol(const string& name, const string& relative_to); + // FindSymbol("foo.bar"). If AllowUnknownDependencies() has been called + // on the DescriptorPool, this will generate a placeholder type if + // the name is not found (unless the name itself is malformed). The + // placeholder_type parameter indicates what kind of placeholder should be + // constructed in this case. The resolve_mode parameter determines whether + // any symbol is returned, or only symbols that are types. Note, however, + // that LookupSymbol may still return a non-type symbol in LOOKUP_TYPES mode, + // if it believes that's all it could refer to. The caller should always + // check that it receives the type of symbol it was expecting. + enum PlaceholderType { + PLACEHOLDER_MESSAGE, + PLACEHOLDER_ENUM, + PLACEHOLDER_EXTENDABLE_MESSAGE + }; + enum ResolveMode { + LOOKUP_ALL, LOOKUP_TYPES + }; + Symbol LookupSymbol(const string& name, const string& relative_to, + PlaceholderType placeholder_type = PLACEHOLDER_MESSAGE, + ResolveMode resolve_mode = LOOKUP_ALL); + + // Like LookupSymbol() but will not return a placeholder even if + // AllowUnknownDependencies() has been used. + Symbol LookupSymbolNoPlaceholder(const string& name, + const string& relative_to, + ResolveMode resolve_mode = LOOKUP_ALL); + + // Creates a placeholder type suitable for return from LookupSymbol(). May + // return kNullSymbol if the name is not a valid type name. + Symbol NewPlaceholder(const string& name, PlaceholderType placeholder_type); + + // Creates a placeholder file. Never returns NULL. This is used when an + // import is not found and AllowUnknownDependencies() is enabled. + const FileDescriptor* NewPlaceholderFile(const string& name); // Calls tables_->AddSymbol() and records an error if it fails. Returns // true if successful or false if failed, though most callers can ignore @@ -1801,6 +1944,10 @@ class DescriptorBuilder { void ValidateSymbolName(const string& name, const string& full_name, const Message& proto); + // Like ValidateSymbolName(), but the name is allowed to contain periods and + // an error is indicated by returning false (not recording the error). + bool ValidateQualifiedName(const string& name); + // Used by BUILD_ARRAY macro (below) to avoid having to have the type // specified as a macro parameter. template <typename Type> @@ -1903,6 +2050,12 @@ class DescriptorBuilder { // uninterpreted_option_ belongs. bool InterpretSingleOption(Message* options); + // Adds the uninterpreted_option to the given options message verbatim. + // Used when AllowUnknownDependencies() is in effect and we can't find + // the option's definition. + void AddWithoutInterpreting(const UninterpretedOption& uninterpreted_option, + Message* options); + // A recursive helper function that drills into the intermediate fields // in unknown_fields to check if field #field_number is set on the // innermost message. Returns false and sets an error if so. @@ -1915,18 +2068,18 @@ class DescriptorBuilder { // Validates the value for the option field of the currently interpreted // option and then sets it on the unknown_field. bool SetOptionValue(const FieldDescriptor* option_field, - UnknownField* unknown_field); + UnknownFieldSet* unknown_fields); // Convenience functions to set an int field the right way, depending on // its wire type (a single int CppType can represent multiple wire types). - void SetInt32(int32 value, FieldDescriptor::Type type, - UnknownField* unknown_field); - void SetInt64(int64 value, FieldDescriptor::Type type, - UnknownField* unknown_field); - void SetUInt32(uint32 value, FieldDescriptor::Type type, - UnknownField* unknown_field); - void SetUInt64(uint64 value, FieldDescriptor::Type type, - UnknownField* unknown_field); + void SetInt32(int number, int32 value, FieldDescriptor::Type type, + UnknownFieldSet* unknown_fields); + void SetInt64(int number, int64 value, FieldDescriptor::Type type, + UnknownFieldSet* unknown_fields); + void SetUInt32(int number, uint32 value, FieldDescriptor::Type type, + UnknownFieldSet* unknown_fields); + void SetUInt64(int number, uint64 value, FieldDescriptor::Type type, + UnknownFieldSet* unknown_fields); // A helper function that adds an error at the specified location of the // option we're currently interpreting, and returns false. @@ -1966,6 +2119,21 @@ class DescriptorBuilder { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OptionInterpreter); }; + // Work-around for broken compilers: According to the C++ standard, + // OptionInterpreter should have access to the private members of any class + // which has declared DescriptorBuilder as a friend. Unfortunately some old + // versions of GCC and other compilers do not implement this correctly. So, + // we have to have these intermediate methods to provide access. We also + // redundantly declare OptionInterpreter a friend just to make things extra + // clear for these bad compilers. + friend class OptionInterpreter; + static inline bool get_allow_unknown(const DescriptorPool* pool) { + return pool->allow_unknown_; + } + static inline bool get_is_placeholder(const Descriptor* descriptor) { + return descriptor->is_placeholder_; + } + // Must be run only after options have been interpreted. // // NOTE: Validation code must only reference the options in the mutable @@ -1998,7 +2166,7 @@ const FileDescriptor* DescriptorPool::BuildFile( "DescriptorDatabase. You must instead find a way to get your file " "into the underlying database."; GOOGLE_CHECK(mutex_ == NULL); // Implied by the above GOOGLE_CHECK. - return DescriptorBuilder(this, tables_.get(), NULL).BuildFile(proto, NULL); + return DescriptorBuilder(this, tables_.get(), NULL).BuildFile(proto); } const FileDescriptor* DescriptorPool::BuildFileCollectingErrors( @@ -2010,73 +2178,14 @@ const FileDescriptor* DescriptorPool::BuildFileCollectingErrors( "into the underlying database."; GOOGLE_CHECK(mutex_ == NULL); // Implied by the above GOOGLE_CHECK. return DescriptorBuilder(this, tables_.get(), - error_collector).BuildFile(proto, NULL); + error_collector).BuildFile(proto); } const FileDescriptor* DescriptorPool::BuildFileFromDatabase( const FileDescriptorProto& proto) const { mutex_->AssertHeld(); return DescriptorBuilder(this, tables_.get(), - default_error_collector_).BuildFile(proto, NULL); -} - -const FileDescriptor* DescriptorPool::InternalBuildGeneratedFile( - const void* data, int size, - InternalDescriptorAssigner descriptor_assigner) { - // So, this function is called in the process of initializing the - // descriptors for generated proto classes. Each generated .pb.cc file - // has an internal procedure called BuildDescriptors() which is called the - // first time one of its descriptors is accessed, and that function calls - // this one in order to parse the raw bytes of the FileDescriptorProto - // representing the file. - // - // Note, though, that FileDescriptorProto is itself a generated protocol - // message. So, when we attempt to construct one below, it will attempt - // to initialize its own descriptors via its own BuildDescriptors() method. - // This will in turn cause InternalBuildGeneratedFile() to build - // descriptor.proto's descriptors. - // - // We are saved from an infinite loop by the fact that BuildDescriptors() - // only does anything the first time it is called. That is, the first few - // lines of any BuildDescriptors() procedure look like this: - // void BuildDescriptors() { - // static bool already_here = false; - // if (already_here) return; - // already_here = true; - // ... - // So, when descriptor.pb.cc's BuildDescriptors() is called recursively, it - // will end up just returning without doing anything. The result is that - // all of the descriptors for FileDescriptorProto and friends will just be - // NULL. - // - // Luckily, it turns out that our limited use of FileDescriptorProto within - // InternalBuildGeneratedFile() does not require that its descriptors be - // initialized. So, this ends up working. As soon as - // InternalBuildGeneratedFile() returns, the descriptors will be initialized - // by the original call to BuildDescriptors(), and everything will be happy - // again. - // - // If this turns out to be too fragile a hack, there are other ways we - // can accomplish bootstrapping here (like building the descriptor for - // descriptor.proto manually), but if this works then it's a lot easier. - // - // Note that because this is only triggered at static initialization time, - // there are no thread-safety concerns here. - GOOGLE_CHECK(fallback_database_ == NULL) - << "Cannot call BuildFile on a DescriptorPool that uses a " - "DescriptorDatabase. You must instead find a way to get your file " - "into the underlying database."; - GOOGLE_CHECK(mutex_ == NULL); // Implied by the above GOOGLE_CHECK. - - FileDescriptorProto proto; - GOOGLE_CHECK(proto.ParseFromArray(data, size)); - const FileDescriptor* result = - DescriptorBuilder(this, tables_.get(), NULL).BuildFile( - proto, descriptor_assigner); - - GOOGLE_CHECK(result != NULL); - - return result; + default_error_collector_).BuildFile(proto); } DescriptorBuilder::DescriptorBuilder( @@ -2189,8 +2298,8 @@ Symbol DescriptorBuilder::FindSymbol(const string& name) { return kNullSymbol; } -Symbol DescriptorBuilder::LookupSymbol( - const string& name, const string& relative_to) { +Symbol DescriptorBuilder::LookupSymbolNoPlaceholder( + const string& name, const string& relative_to, ResolveMode resolve_mode) { possible_undeclared_dependency_ = NULL; if (name.size() > 0 && name[0] == '.') { @@ -2237,11 +2346,20 @@ Symbol DescriptorBuilder::LookupSymbol( if (first_part_of_name.size() < name.size()) { // name is a compound symbol, of which we only found the first part. // Now try to look up the rest of it. - scope_to_try.append(name, first_part_of_name.size(), - name.size() - first_part_of_name.size()); - result = FindSymbol(scope_to_try); + if (result.IsAggregate()) { + scope_to_try.append(name, first_part_of_name.size(), + name.size() - first_part_of_name.size()); + return FindSymbol(scope_to_try); + } else { + // We found a symbol but it's not an aggregate. Continue the loop. + } + } else { + if (resolve_mode == LOOKUP_TYPES && !result.IsType()) { + // We found a symbol but it's not a type. Continue the loop. + } else { + return result; + } } - return result; } // Not found. Remove the name so we can try again. @@ -2249,6 +2367,134 @@ Symbol DescriptorBuilder::LookupSymbol( } } +Symbol DescriptorBuilder::LookupSymbol( + const string& name, const string& relative_to, + PlaceholderType placeholder_type, ResolveMode resolve_mode) { + Symbol result = LookupSymbolNoPlaceholder( + name, relative_to, resolve_mode); + if (result.IsNull() && pool_->allow_unknown_) { + // Not found, but AllowUnknownDependencies() is enabled. Return a + // placeholder instead. + result = NewPlaceholder(name, placeholder_type); + } + return result; +} + +Symbol DescriptorBuilder::NewPlaceholder(const string& name, + PlaceholderType placeholder_type) { + // Compute names. + const string* placeholder_full_name; + const string* placeholder_name; + const string* placeholder_package; + + if (!ValidateQualifiedName(name)) return kNullSymbol; + if (name[0] == '.') { + // Fully-qualified. + placeholder_full_name = tables_->AllocateString(name.substr(1)); + } else { + placeholder_full_name = tables_->AllocateString(name); + } + + string::size_type dotpos = placeholder_full_name->find_last_of('.'); + if (dotpos != string::npos) { + placeholder_package = tables_->AllocateString( + placeholder_full_name->substr(0, dotpos)); + placeholder_name = tables_->AllocateString( + placeholder_full_name->substr(dotpos + 1)); + } else { + placeholder_package = &kEmptyString; + placeholder_name = placeholder_full_name; + } + + // Create the placeholders. + FileDescriptor* placeholder_file = tables_->Allocate<FileDescriptor>(); + memset(placeholder_file, 0, sizeof(*placeholder_file)); + + placeholder_file->name_ = + tables_->AllocateString(*placeholder_full_name + ".placeholder.proto"); + placeholder_file->package_ = placeholder_package; + placeholder_file->pool_ = pool_; + placeholder_file->options_ = &FileOptions::default_instance(); + placeholder_file->tables_ = &FileDescriptorTables::kEmpty; + // All other fields are zero or NULL. + + if (placeholder_type == PLACEHOLDER_ENUM) { + placeholder_file->enum_type_count_ = 1; + placeholder_file->enum_types_ = + tables_->AllocateArray<EnumDescriptor>(1); + + EnumDescriptor* placeholder_enum = &placeholder_file->enum_types_[0]; + memset(placeholder_enum, 0, sizeof(*placeholder_enum)); + + placeholder_enum->full_name_ = placeholder_full_name; + placeholder_enum->name_ = placeholder_name; + placeholder_enum->file_ = placeholder_file; + placeholder_enum->options_ = &EnumOptions::default_instance(); + placeholder_enum->is_placeholder_ = true; + placeholder_enum->is_unqualified_placeholder_ = (name[0] != '.'); + + // Enums must have at least one value. + placeholder_enum->value_count_ = 1; + placeholder_enum->values_ = tables_->AllocateArray<EnumValueDescriptor>(1); + + EnumValueDescriptor* placeholder_value = &placeholder_enum->values_[0]; + memset(placeholder_value, 0, sizeof(*placeholder_value)); + + placeholder_value->name_ = tables_->AllocateString("PLACEHOLDER_VALUE"); + // Note that enum value names are siblings of their type, not children. + placeholder_value->full_name_ = + placeholder_package->empty() ? placeholder_value->name_ : + tables_->AllocateString(*placeholder_package + ".PLACEHOLDER_VALUE"); + + placeholder_value->number_ = 0; + placeholder_value->type_ = placeholder_enum; + placeholder_value->options_ = &EnumValueOptions::default_instance(); + + return Symbol(placeholder_enum); + } else { + placeholder_file->message_type_count_ = 1; + placeholder_file->message_types_ = + tables_->AllocateArray<Descriptor>(1); + + Descriptor* placeholder_message = &placeholder_file->message_types_[0]; + memset(placeholder_message, 0, sizeof(*placeholder_message)); + + placeholder_message->full_name_ = placeholder_full_name; + placeholder_message->name_ = placeholder_name; + placeholder_message->file_ = placeholder_file; + placeholder_message->options_ = &MessageOptions::default_instance(); + placeholder_message->is_placeholder_ = true; + placeholder_message->is_unqualified_placeholder_ = (name[0] != '.'); + + if (placeholder_type == PLACEHOLDER_EXTENDABLE_MESSAGE) { + placeholder_message->extension_range_count_ = 1; + placeholder_message->extension_ranges_ = + tables_->AllocateArray<Descriptor::ExtensionRange>(1); + placeholder_message->extension_ranges_->start = 1; + // kMaxNumber + 1 because ExtensionRange::end is exclusive. + placeholder_message->extension_ranges_->end = + FieldDescriptor::kMaxNumber + 1; + } + + return Symbol(placeholder_message); + } +} + +const FileDescriptor* DescriptorBuilder::NewPlaceholderFile( + const string& name) { + FileDescriptor* placeholder = tables_->Allocate<FileDescriptor>(); + memset(placeholder, 0, sizeof(*placeholder)); + + placeholder->name_ = tables_->AllocateString(name); + placeholder->package_ = &kEmptyString; + placeholder->pool_ = pool_; + placeholder->options_ = &FileOptions::default_instance(); + placeholder->tables_ = &FileDescriptorTables::kEmpty; + // All other fields are zero or NULL. + + return placeholder; +} + bool DescriptorBuilder::AddSymbol( const string& full_name, const void* parent, const string& name, const Message& proto, Symbol symbol) { @@ -2256,7 +2502,13 @@ bool DescriptorBuilder::AddSymbol( // Use its file as the parent instead. if (parent == NULL) parent = file_; - if (tables_->AddSymbol(full_name, parent, name, symbol)) { + if (tables_->AddSymbol(full_name, symbol)) { + if (!file_tables_->AddAliasUnderParent(parent, name, symbol)) { + GOOGLE_LOG(DFATAL) << "\"" << full_name << "\" not previously defined in " + "symbols_by_name_, but was defined in symbols_by_parent_; " + "this shouldn't be possible."; + return false; + } return true; } else { const FileDescriptor* other_file = tables_->FindSymbol(full_name).GetFile(); @@ -2283,7 +2535,7 @@ bool DescriptorBuilder::AddSymbol( void DescriptorBuilder::AddPackage( const string& name, const Message& proto, const FileDescriptor* file) { - if (tables_->AddSymbol(name, NULL, name, Symbol(file))) { + if (tables_->AddSymbol(name, Symbol(file))) { // Success. Also add parent package, if any. string::size_type dot_pos = name.find_last_of('.'); if (dot_pos == string::npos) { @@ -2327,6 +2579,27 @@ void DescriptorBuilder::ValidateSymbolName( } } +bool DescriptorBuilder::ValidateQualifiedName(const string& name) { + bool last_was_period = false; + + for (int i = 0; i < name.size(); i++) { + // I don't trust isalnum() due to locales. :( + if (('a' <= name[i] && name[i] <= 'z') || + ('A' <= name[i] && name[i] <= 'Z') || + ('0' <= name[i] && name[i] <= '9') || + (name[i] == '_')) { + last_was_period = false; + } else if (name[i] == '.') { + if (last_was_period) return false; + last_was_period = true; + } else { + return false; + } + } + + return !name.empty() && !last_was_period; +} + // ------------------------------------------------------------------- // This generic implementation is good for all descriptors except @@ -2351,12 +2624,26 @@ template<class DescriptorT> void DescriptorBuilder::AllocateOptionsImpl( const string& element_name, const typename DescriptorT::OptionsType& orig_options, DescriptorT* descriptor) { - typename DescriptorT::OptionsType* options = - tables_->AllocateMessage<typename DescriptorT::OptionsType>(); + // 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 = + // tables_->AllocateMessage<typename DescriptorT::OptionsType>(); + typename DescriptorT::OptionsType* const dummy = NULL; + typename DescriptorT::OptionsType* options = tables_->AllocateMessage(dummy); options->CopyFrom(orig_options); - options_to_interpret_.push_back( - OptionsToInterpret(name_scope, element_name, &orig_options, options)); descriptor->options_ = options; + + // Don't add to options_to_interpret_ unless there were uninterpreted + // options. This not only avoids unnecessary work, but prevents a + // bootstrapping problem when building descriptors for descriptor.proto. + // descriptor.proto does not contain any uninterpreted options, but + // attempting to interpret options anyway will cause + // OptionsType::GetDescriptor() to be called which may then deadlock since + // 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)); + } } @@ -2370,10 +2657,27 @@ template<class DescriptorT> void DescriptorBuilder::AllocateOptionsImpl( } const FileDescriptor* DescriptorBuilder::BuildFile( - const FileDescriptorProto& proto, - DescriptorPool::InternalDescriptorAssigner descriptor_assigner) { + const FileDescriptorProto& proto) { filename_ = proto.name(); + // Check if the file already exists and is identical to the one being built. + // Note: This only works if the input is canonical -- that is, it + // fully-qualifies all type names, has no UninterpretedOptions, etc. + // This is fine, because this idempotency "feature" really only exists to + // accomodate one hack in the proto1->proto2 migration layer. + const FileDescriptor* existing_file = tables_->FindFile(filename_); + if (existing_file != NULL) { + // File already in pool. Compare the existing one to the input. + FileDescriptorProto existing_proto; + existing_file->CopyTo(&existing_proto); + if (existing_proto.SerializeAsString() == proto.SerializeAsString()) { + // They're identical. Return the existing descriptor. + return existing_file; + } + + // Not a match. The error will be detected and handled later. + } + // Check to see if this file is already on the pending files list. // TODO(kenton): Allow recursive imports? It may not work with some // (most?) programming languages. E.g., in C++, a forward declaration @@ -2420,6 +2724,9 @@ const FileDescriptor* DescriptorBuilder::BuildFile( FileDescriptor* result = tables_->Allocate<FileDescriptor>(); file_ = result; + file_tables_ = tables_->AllocateFileTables(); + file_->tables_ = file_tables_; + if (!proto.has_name()) { AddError("", proto, DescriptorPool::ErrorCollector::OTHER, "Missing field: FileDescriptorProto.name."); @@ -2468,17 +2775,21 @@ const FileDescriptor* DescriptorBuilder::BuildFile( } if (dependency == NULL) { - string message; - if (pool_->fallback_database_ == NULL) { - message = "Import \"" + proto.dependency(i) + - "\" has not been loaded."; + if (pool_->allow_unknown_) { + dependency = NewPlaceholderFile(proto.dependency(i)); } else { - message = "Import \"" + proto.dependency(i) + - "\" was not found or had errors."; + string message; + if (pool_->fallback_database_ == NULL) { + message = "Import \"" + proto.dependency(i) + + "\" has not been loaded."; + } else { + message = "Import \"" + proto.dependency(i) + + "\" was not found or had errors."; + } + AddError(proto.name(), proto, + DescriptorPool::ErrorCollector::OTHER, + message); } - AddError(proto.name(), proto, - DescriptorPool::ErrorCollector::OTHER, - message); } result->dependencies_[i] = dependency; @@ -2499,11 +2810,6 @@ const FileDescriptor* DescriptorBuilder::BuildFile( // Note that the following steps must occur in exactly the specified order. - // Assign descriptors, if needed. - if (descriptor_assigner != NULL) { - (*descriptor_assigner)(result); - } - // Cross-link. CrossLinkFile(result, proto); @@ -2549,6 +2855,8 @@ void DescriptorBuilder::BuildMessage(const DescriptorProto& proto, result->full_name_ = full_name; result->file_ = file_; result->containing_type_ = parent; + result->is_placeholder_ = false; + result->is_unqualified_placeholder_ = false; BUILD_ARRAY(proto, result, field , BuildField , result); BUILD_ARRAY(proto, result, nested_type , BuildMessage , result); @@ -2648,6 +2956,12 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto, result->enum_type_ = NULL; result->has_default_value_ = proto.has_default_value(); + if (proto.has_default_value() && result->is_repeated()) { + AddError(result->full_name(), proto, + DescriptorPool::ErrorCollector::DEFAULT_VALUE, + "Repeated fields can't have default values."); + } + if (proto.has_type()) { if (proto.has_default_value()) { char* end_pos = NULL; @@ -2842,6 +3156,8 @@ void DescriptorBuilder::BuildEnum(const EnumDescriptorProto& proto, result->full_name_ = full_name; result->file_ = file_; result->containing_type_ = parent; + result->is_placeholder_ = false; + result->is_unqualified_placeholder_ = false; if (proto.value_size() == 0) { // We cannot allow enums with no values because this would mean there @@ -2899,7 +3215,7 @@ void DescriptorBuilder::BuildEnumValue(const EnumValueDescriptorProto& proto, // Note: This could fail, but if it does, the error has already been // reported by the above AddSymbol() call, so we ignore the return code. bool added_to_inner_scope = - tables_->AddAliasUnderParent(parent, result->name(), Symbol(result)); + file_tables_->AddAliasUnderParent(parent, result->name(), Symbol(result)); if (added_to_inner_scope && !added_to_outer_scope) { // This value did not conflict with any values defined in the same enum, @@ -2929,7 +3245,7 @@ void DescriptorBuilder::BuildEnumValue(const EnumValueDescriptorProto& proto, // An enum is allowed to define two numbers that refer to the same value. // FindValueByNumber() should return the first such value, so we simply // ignore AddEnumValueByNumber()'s return code. - tables_->AddEnumValueByNumber(result); + file_tables_->AddEnumValueByNumber(result); } void DescriptorBuilder::BuildService(const ServiceDescriptorProto& proto, @@ -3043,7 +3359,8 @@ void DescriptorBuilder::CrossLinkField( } if (proto.has_extendee()) { - Symbol extendee = LookupSymbol(proto.extendee(), field->full_name()); + Symbol extendee = LookupSymbol(proto.extendee(), field->full_name(), + PLACEHOLDER_EXTENDABLE_MESSAGE); if (extendee.IsNull()) { AddNotDefinedError(field->full_name(), proto, DescriptorPool::ErrorCollector::EXTENDEE, @@ -3068,7 +3385,17 @@ void DescriptorBuilder::CrossLinkField( } if (proto.has_type_name()) { - Symbol type = LookupSymbol(proto.type_name(), field->full_name()); + // Assume we are expecting a message type unless the proto contains some + // evidence that it expects an enum type. This only makes a difference if + // we end up creating a placeholder. + bool expecting_enum = (proto.type() == FieldDescriptorProto::TYPE_ENUM) || + proto.has_default_value(); + + Symbol type = + LookupSymbol(proto.type_name(), field->full_name(), + expecting_enum ? PLACEHOLDER_ENUM : PLACEHOLDER_MESSAGE, + LOOKUP_TYPES); + if (type.IsNull()) { AddNotDefinedError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, @@ -3113,12 +3440,19 @@ void DescriptorBuilder::CrossLinkField( } field->enum_type_ = type.enum_descriptor; + if (field->enum_type()->is_placeholder_) { + // We can't look up default values for placeholder types. We'll have + // to just drop them. + field->has_default_value_ = false; + } + if (field->has_default_value()) { // We can't just use field->enum_type()->FindValueByName() here // because that locks the pool's mutex, which we have already locked // at this point. Symbol default_value = - LookupSymbol(proto.default_value(), field->enum_type()->full_name()); + LookupSymbolNoPlaceholder(proto.default_value(), + field->enum_type()->full_name()); if (default_value.type == Symbol::ENUM_VALUE && default_value.enum_value_descriptor->type() == field->enum_type()) { @@ -3150,9 +3484,10 @@ void DescriptorBuilder::CrossLinkField( // Add the field to the fields-by-number table. // Note: We have to do this *after* cross-linking because extensions do not // know their containing type until now. - if (!tables_->AddFieldByNumber(field)) { + if (!file_tables_->AddFieldByNumber(field)) { const FieldDescriptor* conflicting_field = - tables_->FindFieldByNumber(field->containing_type(), field->number()); + file_tables_->FindFieldByNumber(field->containing_type(), + field->number()); if (field->is_extension()) { AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER, @@ -3172,8 +3507,14 @@ void DescriptorBuilder::CrossLinkField( } } + if (field->is_extension()) { + // No need for error checking: if the extension number collided, + // we've already been informed of it by the if() above. + tables_->AddExtension(field); + } + // Add the field to the lowercase-name and camelcase-name tables. - tables_->AddFieldByStylizedNames(field); + file_tables_->AddFieldByStylizedNames(field); } void DescriptorBuilder::CrossLinkEnum( @@ -3397,6 +3738,14 @@ bool DescriptorBuilder::OptionInterpreter::InterpretOptions( bool failed = false; options_to_interpret_ = options_to_interpret; + // Find the uninterpreted_option field in the mutable copy of the options + // and clear them, since we're about to interpret them. + const FieldDescriptor* uninterpreted_options_field = + options->GetDescriptor()->FindFieldByName("uninterpreted_option"); + GOOGLE_CHECK(uninterpreted_options_field != NULL) + << "No field named \"uninterpreted_option\" in the Options proto."; + options->GetReflection()->ClearField(options, uninterpreted_options_field); + // Find the uninterpreted_option field in the original options. const FieldDescriptor* original_uninterpreted_options_field = original_options->GetDescriptor()-> @@ -3421,17 +3770,6 @@ bool DescriptorBuilder::OptionInterpreter::InterpretOptions( options_to_interpret_ = NULL; if (!failed) { - // Find the uninterpreted_option field in the mutable copy of the options. - const FieldDescriptor* uninterpreted_options_field = - options->GetDescriptor()->FindFieldByName("uninterpreted_option"); - GOOGLE_CHECK(uninterpreted_options_field != NULL) - << "No field named \"uninterpreted_option\" in the Options proto."; - - // We don't want to carry around the uninterpreted options, now that we've - // interpreted them. - options->GetReflection()->ClearField(options, uninterpreted_options_field); - - // InterpretSingleOption() added the interpreted options in the // UnknownFieldSet, in case the option isn't yet known to us. Now we // serialize the options message and deserialize it back. That way, any @@ -3517,36 +3855,36 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption( // you use, so they must be present in the builder's pool. } else { debug_msg_name += name_part; - // Search for the field's descriptor as a regular field in the builder's - // pool. First we must qualify it by its message name. Note that we use - // DescriptorBuilder::FindSymbolNotEnforcingDeps(), not - // DescriptorPool::FindFieldByName() because we're already holding the - // pool's mutex, and the latter method locks it again. We must not - // enforce dependencies here because we did not enforce dependencies - // when looking up |descriptor|, and we need the two to match. - string fully_qualified_name = descriptor->full_name() + "." + name_part; - Symbol symbol = - builder_->FindSymbolNotEnforcingDeps(fully_qualified_name); - if (!symbol.IsNull() && symbol.type == Symbol::FIELD) { - field = symbol.field_descriptor; - } else { - // The field's descriptor was not in the builder's pool, so search for - // the standard version from the generated pool. We're not holding the - // generated pool's mutex, so we can search it the straightforward way. - field = DescriptorPool::generated_pool()->FindFieldByName( - fully_qualified_name); - } + // Search for the field's descriptor as a regular field. + field = descriptor->FindFieldByName(name_part); } if (field == NULL) { - return AddNameError("Option \"" + debug_msg_name + "\" unknown."); + if (get_allow_unknown(builder_->pool_)) { + // We can't find the option, but AllowUnknownDependencies() is enabled, + // so we will just leave it as uninterpreted. + AddWithoutInterpreting(*uninterpreted_option_, options); + return true; + } else { + return AddNameError("Option \"" + debug_msg_name + "\" unknown."); + } } else if (field->containing_type() != descriptor) { - // This can only happen if, due to some insane misconfiguration of the - // pools, we find the options message in one pool but the field in - // another. This would probably imply a hefty bug somewhere. - return AddNameError("Option field \"" + debug_msg_name + - "\" is not a field or extension of message \"" + - descriptor->name() + "\"."); + if (get_is_placeholder(field->containing_type())) { + // The field is an extension of a placeholder type, so we can't + // reliably verify whether it is a valid extension to use here (e.g. + // we don't know if it is an extension of the correct *Options message, + // or if it has a valid field number, etc.). Just leave it as + // uninterpreted instead. + AddWithoutInterpreting(*uninterpreted_option_, options); + return true; + } else { + // This can only happen if, due to some insane misconfiguration of the + // pools, we find the options message in one pool but the field in + // another. This would probably imply a hefty bug somewhere. + return AddNameError("Option field \"" + debug_msg_name + + "\" is not a field or extension of message \"" + + descriptor->name() + "\"."); + } } else if (field->is_repeated()) { return AddNameError("Option field \"" + debug_msg_name + "\" is repeated. Repeated options are not " @@ -3586,7 +3924,7 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption( // First set the value on the UnknownFieldSet corresponding to the // innermost message. scoped_ptr<UnknownFieldSet> unknown_fields(new UnknownFieldSet()); - if (!SetOptionValue(field, unknown_fields.get()->AddField(field->number()))) { + if (!SetOptionValue(field, unknown_fields.get())) { return false; // SetOptionValue() already added the error. } @@ -3599,19 +3937,18 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption( switch ((*iter)->type()) { case FieldDescriptor::TYPE_MESSAGE: { io::StringOutputStream outstr( - parent_unknown_fields->AddField((*iter)->number())-> - add_length_delimited()); + parent_unknown_fields->AddLengthDelimited((*iter)->number())); io::CodedOutputStream out(&outstr); - GOOGLE_CHECK(internal::WireFormat::SerializeUnknownFields(*unknown_fields, - &out)) + internal::WireFormat::SerializeUnknownFields(*unknown_fields, &out); + GOOGLE_CHECK(!out.HadError()) << "Unexpected failure while serializing option submessage " << debug_msg_name << "\"."; break; } case FieldDescriptor::TYPE_GROUP: { - parent_unknown_fields->AddField((*iter)->number())-> - add_group()->MergeFrom(*unknown_fields); + parent_unknown_fields->AddGroup((*iter)->number()) + ->MergeFrom(*unknown_fields); break; } @@ -3631,56 +3968,73 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption( return true; } +void DescriptorBuilder::OptionInterpreter::AddWithoutInterpreting( + const UninterpretedOption& uninterpreted_option, Message* options) { + const FieldDescriptor* field = + options->GetDescriptor()->FindFieldByName("uninterpreted_option"); + GOOGLE_CHECK(field != NULL); + + options->GetReflection()->AddMessage(options, field) + ->CopyFrom(uninterpreted_option); +} + bool DescriptorBuilder::OptionInterpreter::ExamineIfOptionIsSet( vector<const FieldDescriptor*>::const_iterator intermediate_fields_iter, vector<const FieldDescriptor*>::const_iterator intermediate_fields_end, const FieldDescriptor* innermost_field, const string& debug_msg_name, const UnknownFieldSet& unknown_fields) { + // We do linear searches of the UnknownFieldSet and its sub-groups. This + // should be fine since it's unlikely that any one options structure will + // contain more than a handful of options. + if (intermediate_fields_iter == intermediate_fields_end) { // We're at the innermost submessage. - if (unknown_fields.FindFieldByNumber(innermost_field->number()) != NULL) { - return AddNameError("Option \"" + debug_msg_name + - "\" was already set."); - } else { - return true; + for (int i = 0; i < unknown_fields.field_count(); i++) { + if (unknown_fields.field(i).number() == innermost_field->number()) { + return AddNameError("Option \"" + debug_msg_name + + "\" was already set."); + } } + return true; } - const UnknownField* unknown_field = unknown_fields.FindFieldByNumber( - (*intermediate_fields_iter)->number()); - if (unknown_field != NULL) { - FieldDescriptor::Type type = (*intermediate_fields_iter)->type(); - // Recurse into the next submessage. - ++intermediate_fields_iter; - switch (type) { - case FieldDescriptor::TYPE_MESSAGE: - for (int i = 0; i < unknown_field->length_delimited_size(); ++i) { - UnknownFieldSet intermediate_unknown_fields; - if (intermediate_unknown_fields.ParseFromString( - unknown_field->length_delimited(i)) && - !ExamineIfOptionIsSet(intermediate_fields_iter, - intermediate_fields_end, - innermost_field, debug_msg_name, - intermediate_unknown_fields)) { - return false; // Error already added. + for (int i = 0; i < unknown_fields.field_count(); i++) { + if (unknown_fields.field(i).number() == + (*intermediate_fields_iter)->number()) { + const UnknownField* unknown_field = &unknown_fields.field(i); + FieldDescriptor::Type type = (*intermediate_fields_iter)->type(); + // Recurse into the next submessage. + ++intermediate_fields_iter; + switch (type) { + case FieldDescriptor::TYPE_MESSAGE: + if (unknown_field->type() == UnknownField::TYPE_LENGTH_DELIMITED) { + UnknownFieldSet intermediate_unknown_fields; + if (intermediate_unknown_fields.ParseFromString( + unknown_field->length_delimited()) && + !ExamineIfOptionIsSet(intermediate_fields_iter, + intermediate_fields_end, + innermost_field, debug_msg_name, + intermediate_unknown_fields)) { + return false; // Error already added. + } } - } - break; + break; - case FieldDescriptor::TYPE_GROUP: - for (int i = 0; i < unknown_field->group_size(); ++i) { - if (!ExamineIfOptionIsSet(intermediate_fields_iter, - intermediate_fields_end, - innermost_field, debug_msg_name, - unknown_field->group(i))) { - return false; // Error already added. + case FieldDescriptor::TYPE_GROUP: + if (unknown_field->type() == UnknownField::TYPE_GROUP) { + if (!ExamineIfOptionIsSet(intermediate_fields_iter, + intermediate_fields_end, + innermost_field, debug_msg_name, + unknown_field->group())) { + return false; // Error already added. + } } - } - break; + break; - default: - GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_MESSAGE: " << type; - return false; + default: + GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_MESSAGE: " << type; + return false; + } } } return true; @@ -3688,7 +4042,7 @@ bool DescriptorBuilder::OptionInterpreter::ExamineIfOptionIsSet( bool DescriptorBuilder::OptionInterpreter::SetOptionValue( const FieldDescriptor* option_field, - UnknownField* unknown_field) { + UnknownFieldSet* unknown_fields) { // We switch on the CppType to validate. switch (option_field->cpp_type()) { @@ -3699,8 +4053,9 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( return AddValueError("Value out of range for int32 option \"" + option_field->full_name() + "\"."); } else { - SetInt32(uninterpreted_option_->positive_int_value(), - option_field->type(), unknown_field); + SetInt32(option_field->number(), + uninterpreted_option_->positive_int_value(), + option_field->type(), unknown_fields); } } else if (uninterpreted_option_->has_negative_int_value()) { if (uninterpreted_option_->negative_int_value() < @@ -3708,8 +4063,9 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( return AddValueError("Value out of range for int32 option \"" + option_field->full_name() + "\"."); } else { - SetInt32(uninterpreted_option_->negative_int_value(), - option_field->type(), unknown_field); + SetInt32(option_field->number(), + uninterpreted_option_->negative_int_value(), + option_field->type(), unknown_fields); } } else { return AddValueError("Value must be integer for int32 option \"" + @@ -3724,12 +4080,14 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( return AddValueError("Value out of range for int64 option \"" + option_field->full_name() + "\"."); } else { - SetInt64(uninterpreted_option_->positive_int_value(), - option_field->type(), unknown_field); + SetInt64(option_field->number(), + uninterpreted_option_->positive_int_value(), + option_field->type(), unknown_fields); } } else if (uninterpreted_option_->has_negative_int_value()) { - SetInt64(uninterpreted_option_->negative_int_value(), - option_field->type(), unknown_field); + SetInt64(option_field->number(), + uninterpreted_option_->negative_int_value(), + option_field->type(), unknown_fields); } else { return AddValueError("Value must be integer for int64 option \"" + option_field->full_name() + "\"."); @@ -3742,8 +4100,9 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( return AddValueError("Value out of range for uint32 option \"" + option_field->name() + "\"."); } else { - SetUInt32(uninterpreted_option_->positive_int_value(), - option_field->type(), unknown_field); + SetUInt32(option_field->number(), + uninterpreted_option_->positive_int_value(), + option_field->type(), unknown_fields); } } else { return AddValueError("Value must be non-negative integer for uint32 " @@ -3753,8 +4112,9 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( case FieldDescriptor::CPPTYPE_UINT64: if (uninterpreted_option_->has_positive_int_value()) { - SetUInt64(uninterpreted_option_->positive_int_value(), - option_field->type(), unknown_field); + SetUInt64(option_field->number(), + uninterpreted_option_->positive_int_value(), + option_field->type(), unknown_fields); } else { return AddValueError("Value must be non-negative integer for uint64 " "option \"" + option_field->full_name() + "\"."); @@ -3773,7 +4133,7 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( return AddValueError("Value must be number for float option \"" + option_field->full_name() + "\"."); } - unknown_field->add_fixed32( + unknown_fields->AddFixed32(option_field->number(), google::protobuf::internal::WireFormat::EncodeFloat(value)); break; } @@ -3790,7 +4150,7 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( return AddValueError("Value must be number for double option \"" + option_field->full_name() + "\"."); } - unknown_field->add_fixed64( + unknown_fields->AddFixed64(option_field->number(), google::protobuf::internal::WireFormat::EncodeDouble(value)); break; } @@ -3809,7 +4169,7 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( return AddValueError("Value must be \"true\" or \"false\" for boolean " "option \"" + option_field->full_name() + "\"."); } - unknown_field->add_varint(value); + unknown_fields->AddVarint(option_field->number(), value); break; case FieldDescriptor::CPPTYPE_ENUM: { @@ -3859,8 +4219,8 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( } else { // Sign-extension is not a problem, since we cast directly from int32 to // uint64, without first going through uint32. - unknown_field->add_varint(static_cast<uint64>( - static_cast<int64>(enum_value->number()))); + unknown_fields->AddVarint(option_field->number(), + static_cast<uint64>(static_cast<int64>(enum_value->number()))); } break; } @@ -3871,7 +4231,7 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( "\"" + option_field->full_name() + "\"."); } // The string has already been unquoted and unescaped by the parser. - unknown_field->add_length_delimited( + unknown_fields->AddLengthDelimited(option_field->number(), uninterpreted_option_->string_value()); break; @@ -3888,19 +4248,20 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( return true; } -void DescriptorBuilder::OptionInterpreter::SetInt32(int32 value, - FieldDescriptor::Type type, UnknownField* unknown_field) { +void DescriptorBuilder::OptionInterpreter::SetInt32(int number, int32 value, + FieldDescriptor::Type type, UnknownFieldSet* unknown_fields) { switch (type) { case FieldDescriptor::TYPE_INT32: - unknown_field->add_varint(static_cast<uint64>(static_cast<int64>(value))); + unknown_fields->AddVarint(number, + static_cast<uint64>(static_cast<int64>(value))); break; case FieldDescriptor::TYPE_SFIXED32: - unknown_field->add_fixed32(static_cast<uint32>(value)); + unknown_fields->AddFixed32(number, static_cast<uint32>(value)); break; case FieldDescriptor::TYPE_SINT32: - unknown_field->add_varint( + unknown_fields->AddVarint(number, google::protobuf::internal::WireFormat::ZigZagEncode32(value)); break; @@ -3910,19 +4271,19 @@ void DescriptorBuilder::OptionInterpreter::SetInt32(int32 value, } } -void DescriptorBuilder::OptionInterpreter::SetInt64(int64 value, - FieldDescriptor::Type type, UnknownField* unknown_field) { +void DescriptorBuilder::OptionInterpreter::SetInt64(int number, int64 value, + FieldDescriptor::Type type, UnknownFieldSet* unknown_fields) { switch (type) { case FieldDescriptor::TYPE_INT64: - unknown_field->add_varint(static_cast<uint64>(value)); + unknown_fields->AddVarint(number, static_cast<uint64>(value)); break; case FieldDescriptor::TYPE_SFIXED64: - unknown_field->add_fixed64(static_cast<uint64>(value)); + unknown_fields->AddFixed64(number, static_cast<uint64>(value)); break; case FieldDescriptor::TYPE_SINT64: - unknown_field->add_varint( + unknown_fields->AddVarint(number, google::protobuf::internal::WireFormat::ZigZagEncode64(value)); break; @@ -3932,15 +4293,15 @@ void DescriptorBuilder::OptionInterpreter::SetInt64(int64 value, } } -void DescriptorBuilder::OptionInterpreter::SetUInt32(uint32 value, - FieldDescriptor::Type type, UnknownField* unknown_field) { +void DescriptorBuilder::OptionInterpreter::SetUInt32(int number, uint32 value, + FieldDescriptor::Type type, UnknownFieldSet* unknown_fields) { switch (type) { case FieldDescriptor::TYPE_UINT32: - unknown_field->add_varint(static_cast<uint64>(value)); + unknown_fields->AddVarint(number, static_cast<uint64>(value)); break; case FieldDescriptor::TYPE_FIXED32: - unknown_field->add_fixed32(static_cast<uint32>(value)); + unknown_fields->AddFixed32(number, static_cast<uint32>(value)); break; default: @@ -3949,15 +4310,15 @@ void DescriptorBuilder::OptionInterpreter::SetUInt32(uint32 value, } } -void DescriptorBuilder::OptionInterpreter::SetUInt64(uint64 value, - FieldDescriptor::Type type, UnknownField* unknown_field) { +void DescriptorBuilder::OptionInterpreter::SetUInt64(int number, uint64 value, + FieldDescriptor::Type type, UnknownFieldSet* unknown_fields) { switch (type) { case FieldDescriptor::TYPE_UINT64: - unknown_field->add_varint(value); + unknown_fields->AddVarint(number, value); break; case FieldDescriptor::TYPE_FIXED64: - unknown_field->add_fixed64(value); + unknown_fields->AddFixed64(number, value); break; default: |