LCOV - code coverage report
Current view: top level - third_party/protobuf/src/google/protobuf - descriptor_database.cc (source / functions) Hit Total Coverage
Test: tmp.zDYK9MVh93 Lines: 54 202 26.7 %
Date: 2015-10-10 Functions: 12 59 20.3 %

          Line data    Source code
       1             : // Protocol Buffers - Google's data interchange format
       2             : // Copyright 2008 Google Inc.  All rights reserved.
       3             : // https://developers.google.com/protocol-buffers/
       4             : //
       5             : // Redistribution and use in source and binary forms, with or without
       6             : // modification, are permitted provided that the following conditions are
       7             : // met:
       8             : //
       9             : //     * Redistributions of source code must retain the above copyright
      10             : // notice, this list of conditions and the following disclaimer.
      11             : //     * Redistributions in binary form must reproduce the above
      12             : // copyright notice, this list of conditions and the following disclaimer
      13             : // in the documentation and/or other materials provided with the
      14             : // distribution.
      15             : //     * Neither the name of Google Inc. nor the names of its
      16             : // contributors may be used to endorse or promote products derived from
      17             : // this software without specific prior written permission.
      18             : //
      19             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      20             : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      21             : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      22             : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      23             : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      24             : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      25             : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      26             : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      27             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      28             : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      29             : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      30             : 
      31             : // Author: kenton@google.com (Kenton Varda)
      32             : //  Based on original Protocol Buffers design by
      33             : //  Sanjay Ghemawat, Jeff Dean, and others.
      34             : 
      35             : #include <google/protobuf/descriptor_database.h>
      36             : 
      37             : #include <set>
      38             : 
      39             : #include <google/protobuf/descriptor.pb.h>
      40             : #include <google/protobuf/wire_format_lite_inl.h>
      41             : #include <google/protobuf/stubs/strutil.h>
      42             : #include <google/protobuf/stubs/stl_util.h>
      43             : #include <google/protobuf/stubs/map_util.h>
      44             : 
      45             : namespace google {
      46             : namespace protobuf {
      47             : 
      48          17 : DescriptorDatabase::~DescriptorDatabase() {}
      49             : 
      50             : // ===================================================================
      51             : 
      52             : template <typename Value>
      53         103 : bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddFile(
      54             :     const FileDescriptorProto& file,
      55             :     Value value) {
      56         103 :   if (!InsertIfNotPresent(&by_name_, file.name(), value)) {
      57           0 :     GOOGLE_LOG(ERROR) << "File already exists in database: " << file.name();
      58           0 :     return false;
      59             :   }
      60             : 
      61             :   // We must be careful here -- calling file.package() if file.has_package() is
      62             :   // false could access an uninitialized static-storage variable if we are being
      63             :   // run at startup time.
      64         309 :   string path = file.has_package() ? file.package() : string();
      65         103 :   if (!path.empty()) path += '.';
      66             : 
      67        2313 :   for (int i = 0; i < file.message_type_size(); i++) {
      68        3315 :     if (!AddSymbol(path + file.message_type(i).name(), value)) return false;
      69        1105 :     if (!AddNestedExtensions(file.message_type(i), value)) return false;
      70             :   }
      71         183 :   for (int i = 0; i < file.enum_type_size(); i++) {
      72         120 :     if (!AddSymbol(path + file.enum_type(i).name(), value)) return false;
      73             :   }
      74         103 :   for (int i = 0; i < file.extension_size(); i++) {
      75           0 :     if (!AddSymbol(path + file.extension(i).name(), value)) return false;
      76           0 :     if (!AddExtension(file.extension(i), value)) return false;
      77             :   }
      78         139 :   for (int i = 0; i < file.service_size(); i++) {
      79          54 :     if (!AddSymbol(path + file.service(i).name(), value)) return false;
      80             :   }
      81             : 
      82             :   return true;
      83             : }
      84             : 
      85             : template <typename Value>
      86        1163 : bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddSymbol(
      87             :     const string& name, Value value) {
      88             :   // We need to make sure not to violate our map invariant.
      89             : 
      90             :   // If the symbol name is invalid it could break our lookup algorithm (which
      91             :   // relies on the fact that '.' sorts before all other characters that are
      92             :   // valid in symbol names).
      93        1163 :   if (!ValidateSymbolName(name)) {
      94           0 :     GOOGLE_LOG(ERROR) << "Invalid symbol name: " << name;
      95           0 :     return false;
      96             :   }
      97             : 
      98             :   // Try to look up the symbol to make sure a super-symbol doesn't already
      99             :   // exist.
     100        1163 :   typename map<string, Value>::iterator iter = FindLastLessOrEqual(name);
     101             : 
     102        2326 :   if (iter == by_symbol_.end()) {
     103             :     // Apparently the map is currently empty.  Just insert and be done with it.
     104          92 :     by_symbol_.insert(typename map<string, Value>::value_type(name, value));
     105          46 :     return true;
     106             :   }
     107             : 
     108        1117 :   if (IsSubSymbol(iter->first, name)) {
     109           0 :     GOOGLE_LOG(ERROR) << "Symbol name \"" << name << "\" conflicts with the existing "
     110           0 :                   "symbol \"" << iter->first << "\".";
     111           0 :     return false;
     112             :   }
     113             : 
     114             :   // OK, that worked.  Now we have to make sure that no symbol in the map is
     115             :   // a sub-symbol of the one we are inserting.  The only symbol which could
     116             :   // be so is the first symbol that is greater than the new symbol.  Since
     117             :   // |iter| points at the last symbol that is less than or equal, we just have
     118             :   // to increment it.
     119             :   ++iter;
     120             : 
     121        3103 :   if (iter != by_symbol_.end() && IsSubSymbol(name, iter->first)) {
     122           0 :     GOOGLE_LOG(ERROR) << "Symbol name \"" << name << "\" conflicts with the existing "
     123           0 :                   "symbol \"" << iter->first << "\".";
     124           0 :     return false;
     125             :   }
     126             : 
     127             :   // OK, no conflicts.
     128             : 
     129             :   // Insert the new symbol using the iterator as a hint, the new entry will
     130             :   // appear immediately before the one the iterator is pointing at.
     131        2234 :   by_symbol_.insert(iter, typename map<string, Value>::value_type(name, value));
     132             : 
     133        1117 :   return true;
     134             : }
     135             : 
     136             : template <typename Value>
     137        1314 : bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddNestedExtensions(
     138             :     const DescriptorProto& message_type,
     139             :     Value value) {
     140        3046 :   for (int i = 0; i < message_type.nested_type_size(); i++) {
     141         209 :     if (!AddNestedExtensions(message_type.nested_type(i), value)) return false;
     142             :   }
     143        1314 :   for (int i = 0; i < message_type.extension_size(); i++) {
     144           0 :     if (!AddExtension(message_type.extension(i), value)) return false;
     145             :   }
     146             :   return true;
     147             : }
     148             : 
     149             : template <typename Value>
     150           0 : bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddExtension(
     151             :     const FieldDescriptorProto& field,
     152             :     Value value) {
     153           0 :   if (!field.extendee().empty() && field.extendee()[0] == '.') {
     154             :     // The extension is fully-qualified.  We can use it as a lookup key in
     155             :     // the by_symbol_ table.
     156           0 :     if (!InsertIfNotPresent(
     157             :             &by_extension_,
     158             :             std::make_pair(field.extendee().substr(1), field.number()),
     159           0 :             value)) {
     160           0 :       GOOGLE_LOG(ERROR) << "Extension conflicts with extension already in database: "
     161           0 :                     "extend " << field.extendee() << " { "
     162           0 :                  << field.name() << " = " << field.number() << " }";
     163           0 :       return false;
     164             :     }
     165             :   } else {
     166             :     // Not fully-qualified.  We can't really do anything here, unfortunately.
     167             :     // We don't consider this an error, though, because the descriptor is
     168             :     // valid.
     169             :   }
     170             :   return true;
     171             : }
     172             : 
     173             : template <typename Value>
     174           5 : Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindFile(
     175             :     const string& filename) {
     176          10 :   return FindWithDefault(by_name_, filename, Value());
     177             : }
     178             : 
     179             : template <typename Value>
     180           0 : Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindSymbol(
     181             :     const string& name) {
     182           0 :   typename map<string, Value>::iterator iter = FindLastLessOrEqual(name);
     183             : 
     184           0 :   return (iter != by_symbol_.end() && IsSubSymbol(iter->first, name)) ?
     185           0 :          iter->second : Value();
     186             : }
     187             : 
     188             : template <typename Value>
     189           0 : Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindExtension(
     190             :     const string& containing_type,
     191             :     int field_number) {
     192             :   return FindWithDefault(
     193           0 :       by_extension_, std::make_pair(containing_type, field_number), Value());
     194             : }
     195             : 
     196             : template <typename Value>
     197           0 : bool SimpleDescriptorDatabase::DescriptorIndex<Value>::FindAllExtensionNumbers(
     198             :     const string& containing_type,
     199             :     vector<int>* output) {
     200             :   typename map<pair<string, int>, Value>::const_iterator it =
     201           0 :       by_extension_.lower_bound(std::make_pair(containing_type, 0));
     202           0 :   bool success = false;
     203             : 
     204           0 :   for (; it != by_extension_.end() && it->first.first == containing_type;
     205             :        ++it) {
     206           0 :     output->push_back(it->first.second);
     207           0 :     success = true;
     208             :   }
     209             : 
     210           0 :   return success;
     211             : }
     212             : 
     213             : template <typename Value>
     214             : typename map<string, Value>::iterator
     215        1163 : SimpleDescriptorDatabase::DescriptorIndex<Value>::FindLastLessOrEqual(
     216             :     const string& name) {
     217             :   // Find the last key in the map which sorts less than or equal to the
     218             :   // symbol name.  Since upper_bound() returns the *first* key that sorts
     219             :   // *greater* than the input, we want the element immediately before that.
     220        2326 :   typename map<string, Value>::iterator iter = by_symbol_.upper_bound(name);
     221        2326 :   if (iter != by_symbol_.begin()) --iter;
     222        1163 :   return iter;
     223             : }
     224             : 
     225             : template <typename Value>
     226        1986 : bool SimpleDescriptorDatabase::DescriptorIndex<Value>::IsSubSymbol(
     227             :     const string& sub_symbol, const string& super_symbol) {
     228        1986 :   return sub_symbol == super_symbol ||
     229        1986 :          (HasPrefixString(super_symbol, sub_symbol) &&
     230        3994 :              super_symbol[sub_symbol.size()] == '.');
     231             : }
     232             : 
     233             : template <typename Value>
     234        1163 : bool SimpleDescriptorDatabase::DescriptorIndex<Value>::ValidateSymbolName(
     235             :     const string& name) {
     236       76230 :   for (int i = 0; i < name.size(); i++) {
     237             :     // I don't trust ctype.h due to locales.  :(
     238      275044 :     if (name[i] != '.' && name[i] != '_' &&
     239       68992 :         (name[i] < '0' || name[i] > '9') &&
     240       68992 :         (name[i] < 'A' || name[i] > 'Z') &&
     241       63156 :         (name[i] < 'a' || name[i] > 'z')) {
     242             :       return false;
     243             :     }
     244             :   }
     245             :   return true;
     246             : }
     247             : 
     248             : // -------------------------------------------------------------------
     249             : 
     250           0 : SimpleDescriptorDatabase::SimpleDescriptorDatabase() {}
     251           0 : SimpleDescriptorDatabase::~SimpleDescriptorDatabase() {
     252           0 :   STLDeleteElements(&files_to_delete_);
     253           0 : }
     254             : 
     255           0 : bool SimpleDescriptorDatabase::Add(const FileDescriptorProto& file) {
     256           0 :   FileDescriptorProto* new_file = new FileDescriptorProto;
     257           0 :   new_file->CopyFrom(file);
     258           0 :   return AddAndOwn(new_file);
     259             : }
     260             : 
     261           0 : bool SimpleDescriptorDatabase::AddAndOwn(const FileDescriptorProto* file) {
     262           0 :   files_to_delete_.push_back(file);
     263           0 :   return index_.AddFile(*file, file);
     264             : }
     265             : 
     266           0 : bool SimpleDescriptorDatabase::FindFileByName(
     267             :     const string& filename,
     268             :     FileDescriptorProto* output) {
     269           0 :   return MaybeCopy(index_.FindFile(filename), output);
     270             : }
     271             : 
     272           0 : bool SimpleDescriptorDatabase::FindFileContainingSymbol(
     273             :     const string& symbol_name,
     274             :     FileDescriptorProto* output) {
     275           0 :   return MaybeCopy(index_.FindSymbol(symbol_name), output);
     276             : }
     277             : 
     278           0 : bool SimpleDescriptorDatabase::FindFileContainingExtension(
     279             :     const string& containing_type,
     280             :     int field_number,
     281             :     FileDescriptorProto* output) {
     282           0 :   return MaybeCopy(index_.FindExtension(containing_type, field_number), output);
     283             : }
     284             : 
     285           0 : bool SimpleDescriptorDatabase::FindAllExtensionNumbers(
     286             :     const string& extendee_type,
     287             :     vector<int>* output) {
     288           0 :   return index_.FindAllExtensionNumbers(extendee_type, output);
     289             : }
     290             : 
     291             : 
     292           0 : bool SimpleDescriptorDatabase::MaybeCopy(const FileDescriptorProto* file,
     293             :                                          FileDescriptorProto* output) {
     294           0 :   if (file == NULL) return false;
     295           0 :   output->CopyFrom(*file);
     296           0 :   return true;
     297             : }
     298             : 
     299             : // -------------------------------------------------------------------
     300             : 
     301         184 : EncodedDescriptorDatabase::EncodedDescriptorDatabase() {}
     302           0 : EncodedDescriptorDatabase::~EncodedDescriptorDatabase() {
     303           0 :   for (int i = 0; i < files_to_delete_.size(); i++) {
     304           0 :     operator delete(files_to_delete_[i]);
     305             :   }
     306           0 : }
     307             : 
     308         103 : bool EncodedDescriptorDatabase::Add(
     309             :     const void* encoded_file_descriptor, int size) {
     310         103 :   FileDescriptorProto file;
     311         103 :   if (file.ParseFromArray(encoded_file_descriptor, size)) {
     312         103 :     return index_.AddFile(file, std::make_pair(encoded_file_descriptor, size));
     313             :   } else {
     314           0 :     GOOGLE_LOG(ERROR) << "Invalid file descriptor data passed to "
     315           0 :                   "EncodedDescriptorDatabase::Add().";
     316           0 :     return false;
     317         103 :   }
     318             : }
     319             : 
     320           0 : bool EncodedDescriptorDatabase::AddCopy(
     321             :     const void* encoded_file_descriptor, int size) {
     322           0 :   void* copy = operator new(size);
     323           0 :   memcpy(copy, encoded_file_descriptor, size);
     324           0 :   files_to_delete_.push_back(copy);
     325           0 :   return Add(copy, size);
     326             : }
     327             : 
     328           5 : bool EncodedDescriptorDatabase::FindFileByName(
     329             :     const string& filename,
     330             :     FileDescriptorProto* output) {
     331           5 :   return MaybeParse(index_.FindFile(filename), output);
     332             : }
     333             : 
     334           0 : bool EncodedDescriptorDatabase::FindFileContainingSymbol(
     335             :     const string& symbol_name,
     336             :     FileDescriptorProto* output) {
     337           0 :   return MaybeParse(index_.FindSymbol(symbol_name), output);
     338             : }
     339             : 
     340           0 : bool EncodedDescriptorDatabase::FindNameOfFileContainingSymbol(
     341             :     const string& symbol_name,
     342             :     string* output) {
     343           0 :   pair<const void*, int> encoded_file = index_.FindSymbol(symbol_name);
     344           0 :   if (encoded_file.first == NULL) return false;
     345             : 
     346             :   // Optimization:  The name should be the first field in the encoded message.
     347             :   //   Try to just read it directly.
     348             :   io::CodedInputStream input(reinterpret_cast<const uint8*>(encoded_file.first),
     349           0 :                              encoded_file.second);
     350             : 
     351             :   const uint32 kNameTag = internal::WireFormatLite::MakeTag(
     352             :       FileDescriptorProto::kNameFieldNumber,
     353           0 :       internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
     354             : 
     355           0 :   if (input.ReadTag() == kNameTag) {
     356             :     // Success!
     357             :     return internal::WireFormatLite::ReadString(&input, output);
     358             :   } else {
     359             :     // Slow path.  Parse whole message.
     360           0 :     FileDescriptorProto file_proto;
     361           0 :     if (!file_proto.ParseFromArray(encoded_file.first, encoded_file.second)) {
     362             :       return false;
     363             :     }
     364           0 :     *output = file_proto.name();
     365           0 :     return true;
     366           0 :   }
     367             : }
     368             : 
     369           0 : bool EncodedDescriptorDatabase::FindFileContainingExtension(
     370             :     const string& containing_type,
     371             :     int field_number,
     372             :     FileDescriptorProto* output) {
     373             :   return MaybeParse(index_.FindExtension(containing_type, field_number),
     374           0 :                     output);
     375             : }
     376             : 
     377           0 : bool EncodedDescriptorDatabase::FindAllExtensionNumbers(
     378             :     const string& extendee_type,
     379             :     vector<int>* output) {
     380           0 :   return index_.FindAllExtensionNumbers(extendee_type, output);
     381             : }
     382             : 
     383           5 : bool EncodedDescriptorDatabase::MaybeParse(
     384             :     pair<const void*, int> encoded_file,
     385             :     FileDescriptorProto* output) {
     386           5 :   if (encoded_file.first == NULL) return false;
     387           5 :   return output->ParseFromArray(encoded_file.first, encoded_file.second);
     388             : }
     389             : 
     390             : // ===================================================================
     391             : 
     392           0 : DescriptorPoolDatabase::DescriptorPoolDatabase(const DescriptorPool& pool)
     393           0 :   : pool_(pool) {}
     394           0 : DescriptorPoolDatabase::~DescriptorPoolDatabase() {}
     395             : 
     396           0 : bool DescriptorPoolDatabase::FindFileByName(
     397             :     const string& filename,
     398             :     FileDescriptorProto* output) {
     399           0 :   const FileDescriptor* file = pool_.FindFileByName(filename);
     400           0 :   if (file == NULL) return false;
     401           0 :   output->Clear();
     402           0 :   file->CopyTo(output);
     403           0 :   return true;
     404             : }
     405             : 
     406           0 : bool DescriptorPoolDatabase::FindFileContainingSymbol(
     407             :     const string& symbol_name,
     408             :     FileDescriptorProto* output) {
     409           0 :   const FileDescriptor* file = pool_.FindFileContainingSymbol(symbol_name);
     410           0 :   if (file == NULL) return false;
     411           0 :   output->Clear();
     412           0 :   file->CopyTo(output);
     413           0 :   return true;
     414             : }
     415             : 
     416           0 : bool DescriptorPoolDatabase::FindFileContainingExtension(
     417             :     const string& containing_type,
     418             :     int field_number,
     419             :     FileDescriptorProto* output) {
     420           0 :   const Descriptor* extendee = pool_.FindMessageTypeByName(containing_type);
     421           0 :   if (extendee == NULL) return false;
     422             : 
     423           0 :   const FieldDescriptor* extension =
     424           0 :     pool_.FindExtensionByNumber(extendee, field_number);
     425           0 :   if (extension == NULL) return false;
     426             : 
     427           0 :   output->Clear();
     428           0 :   extension->file()->CopyTo(output);
     429           0 :   return true;
     430             : }
     431             : 
     432           0 : bool DescriptorPoolDatabase::FindAllExtensionNumbers(
     433             :     const string& extendee_type,
     434             :     vector<int>* output) {
     435           0 :   const Descriptor* extendee = pool_.FindMessageTypeByName(extendee_type);
     436           0 :   if (extendee == NULL) return false;
     437             : 
     438             :   vector<const FieldDescriptor*> extensions;
     439           0 :   pool_.FindAllExtensions(extendee, &extensions);
     440             : 
     441           0 :   for (int i = 0; i < extensions.size(); ++i) {
     442           0 :     output->push_back(extensions[i]->number());
     443             :   }
     444             : 
     445           0 :   return true;
     446             : }
     447             : 
     448             : // ===================================================================
     449             : 
     450           0 : MergedDescriptorDatabase::MergedDescriptorDatabase(
     451             :     DescriptorDatabase* source1,
     452           0 :     DescriptorDatabase* source2) {
     453           0 :   sources_.push_back(source1);
     454           0 :   sources_.push_back(source2);
     455           0 : }
     456           0 : MergedDescriptorDatabase::MergedDescriptorDatabase(
     457             :     const vector<DescriptorDatabase*>& sources)
     458           0 :   : sources_(sources) {}
     459           0 : MergedDescriptorDatabase::~MergedDescriptorDatabase() {}
     460             : 
     461           0 : bool MergedDescriptorDatabase::FindFileByName(
     462             :     const string& filename,
     463             :     FileDescriptorProto* output) {
     464           0 :   for (int i = 0; i < sources_.size(); i++) {
     465           0 :     if (sources_[i]->FindFileByName(filename, output)) {
     466             :       return true;
     467             :     }
     468             :   }
     469             :   return false;
     470             : }
     471             : 
     472           0 : bool MergedDescriptorDatabase::FindFileContainingSymbol(
     473             :     const string& symbol_name,
     474             :     FileDescriptorProto* output) {
     475           0 :   for (int i = 0; i < sources_.size(); i++) {
     476           0 :     if (sources_[i]->FindFileContainingSymbol(symbol_name, output)) {
     477             :       // The symbol was found in source i.  However, if one of the previous
     478             :       // sources defines a file with the same name (which presumably doesn't
     479             :       // contain the symbol, since it wasn't found in that source), then we
     480             :       // must hide it from the caller.
     481           0 :       FileDescriptorProto temp;
     482           0 :       for (int j = 0; j < i; j++) {
     483           0 :         if (sources_[j]->FindFileByName(output->name(), &temp)) {
     484             :           // Found conflicting file in a previous source.
     485             :           return false;
     486             :         }
     487             :       }
     488           0 :       return true;
     489             :     }
     490             :   }
     491             :   return false;
     492             : }
     493             : 
     494           0 : bool MergedDescriptorDatabase::FindFileContainingExtension(
     495             :     const string& containing_type,
     496             :     int field_number,
     497             :     FileDescriptorProto* output) {
     498           0 :   for (int i = 0; i < sources_.size(); i++) {
     499           0 :     if (sources_[i]->FindFileContainingExtension(
     500           0 :           containing_type, field_number, output)) {
     501             :       // The symbol was found in source i.  However, if one of the previous
     502             :       // sources defines a file with the same name (which presumably doesn't
     503             :       // contain the symbol, since it wasn't found in that source), then we
     504             :       // must hide it from the caller.
     505           0 :       FileDescriptorProto temp;
     506           0 :       for (int j = 0; j < i; j++) {
     507           0 :         if (sources_[j]->FindFileByName(output->name(), &temp)) {
     508             :           // Found conflicting file in a previous source.
     509             :           return false;
     510             :         }
     511             :       }
     512           0 :       return true;
     513             :     }
     514             :   }
     515             :   return false;
     516             : }
     517             : 
     518           0 : bool MergedDescriptorDatabase::FindAllExtensionNumbers(
     519             :     const string& extendee_type,
     520             :     vector<int>* output) {
     521             :   set<int> merged_results;
     522             :   vector<int> results;
     523           0 :   bool success = false;
     524             : 
     525           0 :   for (int i = 0; i < sources_.size(); i++) {
     526           0 :     if (sources_[i]->FindAllExtensionNumbers(extendee_type, &results)) {
     527             :       std::copy(
     528             :           results.begin(), results.end(),
     529             :           insert_iterator<set<int> >(merged_results, merged_results.begin()));
     530             :       success = true;
     531             :     }
     532             :     results.clear();
     533             :   }
     534             : 
     535             :   std::copy(merged_results.begin(), merged_results.end(),
     536             :             insert_iterator<vector<int> >(*output, output->end()));
     537             : 
     538           0 :   return success;
     539             : }
     540             : 
     541             : 
     542             : }  // namespace protobuf
     543             : }  // namespace google

Generated by: LCOV version 1.10