blob: bfdacd959113cccfa3c5bfa61bdc48481ab1a7fb [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
kenton@google.com24bf56f2008-09-24 20:31:01 +00002// Copyright 2008 Google Inc. All rights reserved.
Feng Xiaoe4288622014-10-01 16:26:23 -07003// https://developers.google.com/protocol-buffers/
temporal40ee5512008-07-10 02:12:20 +00004//
kenton@google.com24bf56f2008-09-24 20:31:01 +00005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
temporal40ee5512008-07-10 02:12:20 +00008//
kenton@google.com24bf56f2008-09-24 20:31:01 +00009// * 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.
temporal40ee5512008-07-10 02:12:20 +000018//
kenton@google.com24bf56f2008-09-24 20:31:01 +000019// 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.
temporal40ee5512008-07-10 02:12:20 +000030
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/stubs/hash.h>
36#include <map>
37#include <set>
jieluo@google.com4de8f552014-07-18 00:47:59 +000038#include <string>
kenton@google.com24bf56f2008-09-24 20:31:01 +000039#include <vector>
temporal40ee5512008-07-10 02:12:20 +000040#include <algorithm>
kenton@google.com684d45b2009-12-19 04:50:00 +000041#include <limits>
temporal40ee5512008-07-10 02:12:20 +000042
43#include <google/protobuf/descriptor.h>
44#include <google/protobuf/descriptor_database.h>
45#include <google/protobuf/descriptor.pb.h>
liujisi@google.com33165fe2010-11-02 13:14:58 +000046#include <google/protobuf/dynamic_message.h>
jieluo@google.com4de8f552014-07-18 00:47:59 +000047#include <google/protobuf/generated_message_util.h>
temporal40ee5512008-07-10 02:12:20 +000048#include <google/protobuf/text_format.h>
kenton@google.com24bf56f2008-09-24 20:31:01 +000049#include <google/protobuf/unknown_field_set.h>
50#include <google/protobuf/wire_format.h>
jieluo@google.com4de8f552014-07-18 00:47:59 +000051#include <google/protobuf/io/strtod.h>
kenton@google.com24bf56f2008-09-24 20:31:01 +000052#include <google/protobuf/io/coded_stream.h>
liujisi@google.com33165fe2010-11-02 13:14:58 +000053#include <google/protobuf/io/tokenizer.h>
kenton@google.com24bf56f2008-09-24 20:31:01 +000054#include <google/protobuf/io/zero_copy_stream_impl.h>
temporal40ee5512008-07-10 02:12:20 +000055#include <google/protobuf/stubs/common.h>
kenton@google.com63e646b2009-05-06 19:27:03 +000056#include <google/protobuf/stubs/once.h>
Feng Xiao6ef984a2014-11-10 17:34:54 -080057#include <google/protobuf/stubs/stringprintf.h>
temporal40ee5512008-07-10 02:12:20 +000058#include <google/protobuf/stubs/strutil.h>
59#include <google/protobuf/stubs/substitute.h>
jieluo@google.com4de8f552014-07-18 00:47:59 +000060#include <google/protobuf/stubs/map_util.h>
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +000061#include <google/protobuf/stubs/stl_util.h>
temporal40ee5512008-07-10 02:12:20 +000062
63#undef PACKAGE // autoheader #defines this. :(
64
65namespace google {
66namespace protobuf {
67
68const FieldDescriptor::CppType
69FieldDescriptor::kTypeToCppTypeMap[MAX_TYPE + 1] = {
70 static_cast<CppType>(0), // 0 is reserved for errors
71
72 CPPTYPE_DOUBLE, // TYPE_DOUBLE
73 CPPTYPE_FLOAT, // TYPE_FLOAT
74 CPPTYPE_INT64, // TYPE_INT64
75 CPPTYPE_UINT64, // TYPE_UINT64
76 CPPTYPE_INT32, // TYPE_INT32
77 CPPTYPE_UINT64, // TYPE_FIXED64
78 CPPTYPE_UINT32, // TYPE_FIXED32
79 CPPTYPE_BOOL, // TYPE_BOOL
80 CPPTYPE_STRING, // TYPE_STRING
81 CPPTYPE_MESSAGE, // TYPE_GROUP
82 CPPTYPE_MESSAGE, // TYPE_MESSAGE
83 CPPTYPE_STRING, // TYPE_BYTES
84 CPPTYPE_UINT32, // TYPE_UINT32
85 CPPTYPE_ENUM, // TYPE_ENUM
86 CPPTYPE_INT32, // TYPE_SFIXED32
87 CPPTYPE_INT64, // TYPE_SFIXED64
88 CPPTYPE_INT32, // TYPE_SINT32
89 CPPTYPE_INT64, // TYPE_SINT64
90};
91
92const char * const FieldDescriptor::kTypeToName[MAX_TYPE + 1] = {
93 "ERROR", // 0 is reserved for errors
94
95 "double", // TYPE_DOUBLE
96 "float", // TYPE_FLOAT
97 "int64", // TYPE_INT64
98 "uint64", // TYPE_UINT64
99 "int32", // TYPE_INT32
100 "fixed64", // TYPE_FIXED64
101 "fixed32", // TYPE_FIXED32
102 "bool", // TYPE_BOOL
103 "string", // TYPE_STRING
104 "group", // TYPE_GROUP
105 "message", // TYPE_MESSAGE
106 "bytes", // TYPE_BYTES
107 "uint32", // TYPE_UINT32
108 "enum", // TYPE_ENUM
109 "sfixed32", // TYPE_SFIXED32
110 "sfixed64", // TYPE_SFIXED64
111 "sint32", // TYPE_SINT32
112 "sint64", // TYPE_SINT64
113};
114
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000115const char * const FieldDescriptor::kCppTypeToName[MAX_CPPTYPE + 1] = {
116 "ERROR", // 0 is reserved for errors
117
118 "int32", // CPPTYPE_INT32
119 "int64", // CPPTYPE_INT64
120 "uint32", // CPPTYPE_UINT32
121 "uint64", // CPPTYPE_UINT64
122 "double", // CPPTYPE_DOUBLE
123 "float", // CPPTYPE_FLOAT
124 "bool", // CPPTYPE_BOOL
125 "enum", // CPPTYPE_ENUM
126 "string", // CPPTYPE_STRING
127 "message", // CPPTYPE_MESSAGE
128};
129
temporal40ee5512008-07-10 02:12:20 +0000130const char * const FieldDescriptor::kLabelToName[MAX_LABEL + 1] = {
131 "ERROR", // 0 is reserved for errors
132
133 "optional", // LABEL_OPTIONAL
134 "required", // LABEL_REQUIRED
135 "repeated", // LABEL_REPEATED
136};
137
Feng Xiao6ef984a2014-11-10 17:34:54 -0800138const char* FileDescriptor::SyntaxName(FileDescriptor::Syntax syntax) {
139 switch (syntax) {
140 case SYNTAX_PROTO2:
141 return "proto2";
142 case SYNTAX_PROTO3:
143 return "proto3";
144 case SYNTAX_UNKNOWN:
145 return "unknown";
146 }
Feng Xiao9173ba22014-12-02 15:28:11 -0800147 GOOGLE_LOG(FATAL) << "can't reach here.";
148 return NULL;
Feng Xiao6ef984a2014-11-10 17:34:54 -0800149}
150
jieluo@google.com4de8f552014-07-18 00:47:59 +0000151static const char * const kNonLinkedWeakMessageReplacementName = "google.protobuf.Empty";
152
temporal40ee5512008-07-10 02:12:20 +0000153#ifndef _MSC_VER // MSVC doesn't need these and won't even accept them.
154const int FieldDescriptor::kMaxNumber;
155const int FieldDescriptor::kFirstReservedNumber;
156const int FieldDescriptor::kLastReservedNumber;
157#endif
158
159namespace {
160
Feng Xiao6ef984a2014-11-10 17:34:54 -0800161string ToCamelCase(const string& input, bool lower_first) {
162 bool capitalize_next = !lower_first;
kenton@google.com2d6daa72009-01-22 01:27:00 +0000163 string result;
164 result.reserve(input.size());
165
166 for (int i = 0; i < input.size(); i++) {
167 if (input[i] == '_') {
168 capitalize_next = true;
169 } else if (capitalize_next) {
170 // Note: I distrust ctype.h due to locales.
171 if ('a' <= input[i] && input[i] <= 'z') {
172 result.push_back(input[i] - 'a' + 'A');
173 } else {
174 result.push_back(input[i]);
175 }
176 capitalize_next = false;
177 } else {
178 result.push_back(input[i]);
179 }
180 }
181
182 // Lower-case the first letter.
Feng Xiao6ef984a2014-11-10 17:34:54 -0800183 if (lower_first && !result.empty() && 'A' <= result[0] && result[0] <= 'Z') {
184 result[0] = result[0] - 'A' + 'a';
kenton@google.com2d6daa72009-01-22 01:27:00 +0000185 }
186
187 return result;
188}
189
temporal40ee5512008-07-10 02:12:20 +0000190// A DescriptorPool contains a bunch of hash_maps to implement the
191// various Find*By*() methods. Since hashtable lookups are O(1), it's
192// most efficient to construct a fixed set of large hash_maps used by
193// all objects in the pool rather than construct one or more small
194// hash_maps for each object.
195//
196// The keys to these hash_maps are (parent, name) or (parent, number)
197// pairs. Unfortunately STL doesn't provide hash functions for pair<>,
198// so we must invent our own.
199//
200// TODO(kenton): Use StringPiece rather than const char* in keys? It would
201// be a lot cleaner but we'd just have to convert it back to const char*
202// for the open source release.
203
204typedef pair<const void*, const char*> PointerStringPair;
205
temporal40ee5512008-07-10 02:12:20 +0000206struct PointerStringPairEqual {
207 inline bool operator()(const PointerStringPair& a,
208 const PointerStringPair& b) const {
209 return a.first == b.first && strcmp(a.second, b.second) == 0;
210 }
211};
212
213template<typename PairType>
214struct PointerIntegerPairHash {
215 size_t operator()(const PairType& p) const {
216 // FIXME(kenton): What is the best way to compute this hash? I have
217 // no idea! This seems a bit better than an XOR.
218 return reinterpret_cast<intptr_t>(p.first) * ((1 << 16) - 1) + p.second;
219 }
220
jieluo@google.com7ee0f3e2014-07-31 00:24:48 +0000221#ifdef _MSC_VER
temporal40ee5512008-07-10 02:12:20 +0000222 // Used only by MSVC and platforms where hash_map is not available.
223 static const size_t bucket_size = 4;
224 static const size_t min_buckets = 8;
jieluo@google.com7ee0f3e2014-07-31 00:24:48 +0000225#endif
temporal40ee5512008-07-10 02:12:20 +0000226 inline bool operator()(const PairType& a, const PairType& b) const {
227 return a.first < b.first ||
228 (a.first == b.first && a.second < b.second);
229 }
230};
231
232typedef pair<const Descriptor*, int> DescriptorIntPair;
233typedef pair<const EnumDescriptor*, int> EnumIntPair;
234
235struct PointerStringPairHash {
236 size_t operator()(const PointerStringPair& p) const {
237 // FIXME(kenton): What is the best way to compute this hash? I have
238 // no idea! This seems a bit better than an XOR.
239 hash<const char*> cstring_hash;
240 return reinterpret_cast<intptr_t>(p.first) * ((1 << 16) - 1) +
241 cstring_hash(p.second);
242 }
243
jieluo@google.com91e32ac2014-08-01 22:17:11 +0000244#ifdef _MSC_VER
temporal40ee5512008-07-10 02:12:20 +0000245 // Used only by MSVC and platforms where hash_map is not available.
jieluo@google.com7ee0f3e2014-07-31 00:24:48 +0000246 static const size_t bucket_size = 4;
247 static const size_t min_buckets = 8;
jieluo@google.com91e32ac2014-08-01 22:17:11 +0000248#endif
temporal40ee5512008-07-10 02:12:20 +0000249 inline bool operator()(const PointerStringPair& a,
250 const PointerStringPair& b) const {
251 if (a.first < b.first) return true;
252 if (a.first > b.first) return false;
253 return strcmp(a.second, b.second) < 0;
254 }
255};
256
257
258struct Symbol {
259 enum Type {
jieluo@google.com4de8f552014-07-18 00:47:59 +0000260 NULL_SYMBOL, MESSAGE, FIELD, ONEOF, ENUM, ENUM_VALUE, SERVICE, METHOD,
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000261 PACKAGE
temporal40ee5512008-07-10 02:12:20 +0000262 };
263 Type type;
264 union {
265 const Descriptor* descriptor;
266 const FieldDescriptor* field_descriptor;
jieluo@google.com4de8f552014-07-18 00:47:59 +0000267 const OneofDescriptor* oneof_descriptor;
temporal40ee5512008-07-10 02:12:20 +0000268 const EnumDescriptor* enum_descriptor;
269 const EnumValueDescriptor* enum_value_descriptor;
270 const ServiceDescriptor* service_descriptor;
271 const MethodDescriptor* method_descriptor;
272 const FileDescriptor* package_file_descriptor;
273 };
274
275 inline Symbol() : type(NULL_SYMBOL) { descriptor = NULL; }
276 inline bool IsNull() const { return type == NULL_SYMBOL; }
kenton@google.comd37d46d2009-04-25 02:53:47 +0000277 inline bool IsType() const {
278 return type == MESSAGE || type == ENUM;
279 }
280 inline bool IsAggregate() const {
281 return type == MESSAGE || type == PACKAGE
282 || type == ENUM || type == SERVICE;
283 }
temporal40ee5512008-07-10 02:12:20 +0000284
285#define CONSTRUCTOR(TYPE, TYPE_CONSTANT, FIELD) \
286 inline explicit Symbol(const TYPE* value) { \
287 type = TYPE_CONSTANT; \
288 this->FIELD = value; \
289 }
290
291 CONSTRUCTOR(Descriptor , MESSAGE , descriptor )
292 CONSTRUCTOR(FieldDescriptor , FIELD , field_descriptor )
jieluo@google.com4de8f552014-07-18 00:47:59 +0000293 CONSTRUCTOR(OneofDescriptor , ONEOF , oneof_descriptor )
temporal40ee5512008-07-10 02:12:20 +0000294 CONSTRUCTOR(EnumDescriptor , ENUM , enum_descriptor )
295 CONSTRUCTOR(EnumValueDescriptor, ENUM_VALUE, enum_value_descriptor )
296 CONSTRUCTOR(ServiceDescriptor , SERVICE , service_descriptor )
297 CONSTRUCTOR(MethodDescriptor , METHOD , method_descriptor )
298 CONSTRUCTOR(FileDescriptor , PACKAGE , package_file_descriptor)
299#undef CONSTRUCTOR
300
301 const FileDescriptor* GetFile() const {
302 switch (type) {
303 case NULL_SYMBOL: return NULL;
304 case MESSAGE : return descriptor ->file();
305 case FIELD : return field_descriptor ->file();
jieluo@google.com4de8f552014-07-18 00:47:59 +0000306 case ONEOF : return oneof_descriptor ->containing_type()->file();
temporal40ee5512008-07-10 02:12:20 +0000307 case ENUM : return enum_descriptor ->file();
308 case ENUM_VALUE : return enum_value_descriptor->type()->file();
309 case SERVICE : return service_descriptor ->file();
310 case METHOD : return method_descriptor ->service()->file();
311 case PACKAGE : return package_file_descriptor;
312 }
313 return NULL;
314 }
315};
316
317const Symbol kNullSymbol;
318
319typedef hash_map<const char*, Symbol,
kenton@google.comd37d46d2009-04-25 02:53:47 +0000320 hash<const char*>, streq>
temporal40ee5512008-07-10 02:12:20 +0000321 SymbolsByNameMap;
322typedef hash_map<PointerStringPair, Symbol,
323 PointerStringPairHash, PointerStringPairEqual>
324 SymbolsByParentMap;
325typedef hash_map<const char*, const FileDescriptor*,
kenton@google.comd37d46d2009-04-25 02:53:47 +0000326 hash<const char*>, streq>
temporal40ee5512008-07-10 02:12:20 +0000327 FilesByNameMap;
kenton@google.com2d6daa72009-01-22 01:27:00 +0000328typedef hash_map<PointerStringPair, const FieldDescriptor*,
329 PointerStringPairHash, PointerStringPairEqual>
330 FieldsByNameMap;
temporal40ee5512008-07-10 02:12:20 +0000331typedef hash_map<DescriptorIntPair, const FieldDescriptor*,
332 PointerIntegerPairHash<DescriptorIntPair> >
333 FieldsByNumberMap;
334typedef hash_map<EnumIntPair, const EnumValueDescriptor*,
335 PointerIntegerPairHash<EnumIntPair> >
336 EnumValuesByNumberMap;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000337// This is a map rather than a hash_map, since we use it to iterate
338// through all the extensions that extend a given Descriptor, and an
339// ordered data structure that implements lower_bound is convenient
340// for that.
341typedef map<DescriptorIntPair, const FieldDescriptor*>
342 ExtensionsGroupedByDescriptorMap;
jieluo@google.com4de8f552014-07-18 00:47:59 +0000343typedef hash_map<string, const SourceCodeInfo_Location*> LocationsByPathMap;
Feng Xiao6ef984a2014-11-10 17:34:54 -0800344
345set<string>* allowed_proto3_extendees_ = NULL;
346GOOGLE_PROTOBUF_DECLARE_ONCE(allowed_proto3_extendees_init_);
347
Feng Xiao137dd0f2014-12-03 16:31:47 -0800348void DeleteAllowedProto3Extendee() {
349 delete allowed_proto3_extendees_;
350}
351
Feng Xiao6ef984a2014-11-10 17:34:54 -0800352void InitAllowedProto3Extendee() {
353 allowed_proto3_extendees_ = new set<string>;
354 allowed_proto3_extendees_->insert("google.protobuf.FileOptions");
355 allowed_proto3_extendees_->insert("google.protobuf.MessageOptions");
356 allowed_proto3_extendees_->insert("google.protobuf.FieldOptions");
357 allowed_proto3_extendees_->insert("google.protobuf.EnumOptions");
358 allowed_proto3_extendees_->insert("google.protobuf.EnumValueOptions");
359 allowed_proto3_extendees_->insert("google.protobuf.ServiceOptions");
360 allowed_proto3_extendees_->insert("google.protobuf.MethodOptions");
Feng Xiao137dd0f2014-12-03 16:31:47 -0800361 google::protobuf::internal::OnShutdown(&DeleteAllowedProto3Extendee);
Feng Xiao6ef984a2014-11-10 17:34:54 -0800362}
363
364// Checks whether the extendee type is allowed in proto3.
365// Only extensions to descriptor options are allowed. We use name comparison
366// instead of comparing the descriptor directly because the extensions may be
367// defined in a different pool.
368bool AllowedExtendeeInProto3(const string& name) {
369 ::google::protobuf::GoogleOnceInit(&allowed_proto3_extendees_init_, &InitAllowedProto3Extendee);
370 return allowed_proto3_extendees_->find(name) !=
371 allowed_proto3_extendees_->end();
372}
373
temporal40ee5512008-07-10 02:12:20 +0000374} // anonymous namespace
375
376// ===================================================================
377// DescriptorPool::Tables
378
379class DescriptorPool::Tables {
380 public:
381 Tables();
382 ~Tables();
383
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000384 // Record the current state of the tables to the stack of checkpoints.
385 // Each call to AddCheckpoint() must be paired with exactly one call to either
386 // ClearLastCheckpoint() or RollbackToLastCheckpoint().
387 //
388 // This is used when building files, since some kinds of validation errors
389 // cannot be detected until the file's descriptors have already been added to
390 // the tables.
391 //
392 // This supports recursive checkpoints, since building a file may trigger
393 // recursive building of other files. Note that recursive checkpoints are not
394 // normally necessary; explicit dependencies are built prior to checkpointing.
395 // So although we recursively build transitive imports, there is at most one
396 // checkpoint in the stack during dependency building.
397 //
398 // Recursive checkpoints only arise during cross-linking of the descriptors.
399 // Symbol references must be resolved, via DescriptorBuilder::FindSymbol and
400 // friends. If the pending file references an unknown symbol
401 // (e.g., it is not defined in the pending file's explicit dependencies), and
402 // the pool is using a fallback database, and that database contains a file
403 // defining that symbol, and that file has not yet been built by the pool,
404 // the pool builds the file during cross-linking, leading to another
405 // checkpoint.
406 void AddCheckpoint();
temporal40ee5512008-07-10 02:12:20 +0000407
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000408 // Mark the last checkpoint as having cleared successfully, removing it from
409 // the stack. If the stack is empty, all pending symbols will be committed.
410 //
411 // Note that this does not guarantee that the symbols added since the last
412 // checkpoint won't be rolled back: if a checkpoint gets rolled back,
413 // everything past that point gets rolled back, including symbols added after
414 // checkpoints that were pushed onto the stack after it and marked as cleared.
415 void ClearLastCheckpoint();
416
417 // Roll back the Tables to the state of the checkpoint at the top of the
418 // stack, removing everything that was added after that point.
419 void RollbackToLastCheckpoint();
temporal40ee5512008-07-10 02:12:20 +0000420
421 // The stack of files which are currently being built. Used to detect
422 // cyclic dependencies when loading files from a DescriptorDatabase. Not
423 // used when fallback_database_ == NULL.
424 vector<string> pending_files_;
425
426 // A set of files which we have tried to load from the fallback database
jieluo@google.com4de8f552014-07-18 00:47:59 +0000427 // and encountered errors. We will not attempt to load them again during
428 // execution of the current public API call, but for compatibility with
429 // legacy clients, this is cleared at the beginning of each public API call.
temporal40ee5512008-07-10 02:12:20 +0000430 // Not used when fallback_database_ == NULL.
431 hash_set<string> known_bad_files_;
432
jieluo@google.com4de8f552014-07-18 00:47:59 +0000433 // A set of symbols which we have tried to load from the fallback database
434 // and encountered errors. We will not attempt to load them again during
435 // execution of the current public API call, but for compatibility with
436 // legacy clients, this is cleared at the beginning of each public API call.
437 hash_set<string> known_bad_symbols_;
438
kenton@google.comd37d46d2009-04-25 02:53:47 +0000439 // The set of descriptors for which we've already loaded the full
440 // set of extensions numbers from fallback_database_.
441 hash_set<const Descriptor*> extensions_loaded_from_db_;
442
temporal40ee5512008-07-10 02:12:20 +0000443 // -----------------------------------------------------------------
444 // Finding items.
445
kenton@google.comd37d46d2009-04-25 02:53:47 +0000446 // Find symbols. This returns a null Symbol (symbol.IsNull() is true)
kenton@google.com2d6daa72009-01-22 01:27:00 +0000447 // if not found.
temporal40ee5512008-07-10 02:12:20 +0000448 inline Symbol FindSymbol(const string& key) const;
temporal40ee5512008-07-10 02:12:20 +0000449
kenton@google.com2d6daa72009-01-22 01:27:00 +0000450 // This implements the body of DescriptorPool::Find*ByName(). It should
451 // really be a private method of DescriptorPool, but that would require
452 // declaring Symbol in descriptor.h, which would drag all kinds of other
453 // stuff into the header. Yay C++.
454 Symbol FindByNameHelper(
jieluo@google.com4de8f552014-07-18 00:47:59 +0000455 const DescriptorPool* pool, const string& name);
kenton@google.com2d6daa72009-01-22 01:27:00 +0000456
temporal40ee5512008-07-10 02:12:20 +0000457 // These return NULL if not found.
458 inline const FileDescriptor* FindFile(const string& key) const;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000459 inline const FieldDescriptor* FindExtension(const Descriptor* extendee,
460 int number);
461 inline void FindAllExtensions(const Descriptor* extendee,
462 vector<const FieldDescriptor*>* out) const;
temporal40ee5512008-07-10 02:12:20 +0000463
464 // -----------------------------------------------------------------
465 // Adding items.
466
467 // These add items to the corresponding tables. They return false if
kenton@google.comd37d46d2009-04-25 02:53:47 +0000468 // the key already exists in the table. For AddSymbol(), the string passed
469 // in must be one that was constructed using AllocateString(), as it will
470 // be used as a key in the symbols_by_name_ map without copying.
471 bool AddSymbol(const string& full_name, Symbol symbol);
temporal40ee5512008-07-10 02:12:20 +0000472 bool AddFile(const FileDescriptor* file);
kenton@google.comd37d46d2009-04-25 02:53:47 +0000473 bool AddExtension(const FieldDescriptor* field);
temporal40ee5512008-07-10 02:12:20 +0000474
475 // -----------------------------------------------------------------
476 // Allocating memory.
477
478 // Allocate an object which will be reclaimed when the pool is
479 // destroyed. Note that the object's destructor will never be called,
480 // so its fields must be plain old data (primitive data types and
481 // pointers). All of the descriptor types are such objects.
482 template<typename Type> Type* Allocate();
483
484 // Allocate an array of objects which will be reclaimed when the
485 // pool in destroyed. Again, destructors are never called.
486 template<typename Type> Type* AllocateArray(int count);
487
488 // Allocate a string which will be destroyed when the pool is destroyed.
489 // The string is initialized to the given value for convenience.
490 string* AllocateString(const string& value);
491
kenton@google.comd37d46d2009-04-25 02:53:47 +0000492 // Allocate a protocol message object. Some older versions of GCC have
493 // trouble understanding explicit template instantiations in some cases, so
494 // in those cases we have to pass a dummy pointer of the right type as the
495 // parameter instead of specifying the type explicitly.
496 template<typename Type> Type* AllocateMessage(Type* dummy = NULL);
497
498 // Allocate a FileDescriptorTables object.
499 FileDescriptorTables* AllocateFileTables();
temporal40ee5512008-07-10 02:12:20 +0000500
501 private:
502 vector<string*> strings_; // All strings in the pool.
503 vector<Message*> messages_; // All messages in the pool.
kenton@google.comd37d46d2009-04-25 02:53:47 +0000504 vector<FileDescriptorTables*> file_tables_; // All file tables in the pool.
temporal40ee5512008-07-10 02:12:20 +0000505 vector<void*> allocations_; // All other memory allocated in the pool.
506
507 SymbolsByNameMap symbols_by_name_;
temporal40ee5512008-07-10 02:12:20 +0000508 FilesByNameMap files_by_name_;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000509 ExtensionsGroupedByDescriptorMap extensions_;
temporal40ee5512008-07-10 02:12:20 +0000510
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000511 struct CheckPoint {
512 explicit CheckPoint(const Tables* tables)
513 : strings_before_checkpoint(tables->strings_.size()),
514 messages_before_checkpoint(tables->messages_.size()),
515 file_tables_before_checkpoint(tables->file_tables_.size()),
516 allocations_before_checkpoint(tables->allocations_.size()),
517 pending_symbols_before_checkpoint(
518 tables->symbols_after_checkpoint_.size()),
519 pending_files_before_checkpoint(
520 tables->files_after_checkpoint_.size()),
521 pending_extensions_before_checkpoint(
522 tables->extensions_after_checkpoint_.size()) {
523 }
524 int strings_before_checkpoint;
525 int messages_before_checkpoint;
526 int file_tables_before_checkpoint;
527 int allocations_before_checkpoint;
528 int pending_symbols_before_checkpoint;
529 int pending_files_before_checkpoint;
530 int pending_extensions_before_checkpoint;
531 };
532 vector<CheckPoint> checkpoints_;
temporal40ee5512008-07-10 02:12:20 +0000533 vector<const char* > symbols_after_checkpoint_;
temporal40ee5512008-07-10 02:12:20 +0000534 vector<const char* > files_after_checkpoint_;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000535 vector<DescriptorIntPair> extensions_after_checkpoint_;
temporal40ee5512008-07-10 02:12:20 +0000536
537 // Allocate some bytes which will be reclaimed when the pool is
538 // destroyed.
539 void* AllocateBytes(int size);
540};
541
kenton@google.comd37d46d2009-04-25 02:53:47 +0000542// Contains tables specific to a particular file. These tables are not
543// modified once the file has been constructed, so they need not be
544// protected by a mutex. This makes operations that depend only on the
545// contents of a single file -- e.g. Descriptor::FindFieldByName() --
546// lock-free.
547//
548// For historical reasons, the definitions of the methods of
549// FileDescriptorTables and DescriptorPool::Tables are interleaved below.
550// These used to be a single class.
551class FileDescriptorTables {
552 public:
553 FileDescriptorTables();
554 ~FileDescriptorTables();
555
556 // Empty table, used with placeholder files.
557 static const FileDescriptorTables kEmpty;
558
559 // -----------------------------------------------------------------
560 // Finding items.
561
562 // Find symbols. These return a null Symbol (symbol.IsNull() is true)
563 // if not found.
564 inline Symbol FindNestedSymbol(const void* parent,
565 const string& name) const;
566 inline Symbol FindNestedSymbolOfType(const void* parent,
567 const string& name,
568 const Symbol::Type type) const;
569
570 // These return NULL if not found.
571 inline const FieldDescriptor* FindFieldByNumber(
572 const Descriptor* parent, int number) const;
573 inline const FieldDescriptor* FindFieldByLowercaseName(
574 const void* parent, const string& lowercase_name) const;
575 inline const FieldDescriptor* FindFieldByCamelcaseName(
576 const void* parent, const string& camelcase_name) const;
577 inline const EnumValueDescriptor* FindEnumValueByNumber(
578 const EnumDescriptor* parent, int number) const;
Feng Xiao6ef984a2014-11-10 17:34:54 -0800579 // This creates a new EnumValueDescriptor if not found, in a thread-safe way.
580 inline const EnumValueDescriptor* FindEnumValueByNumberCreatingIfUnknown(
581 const EnumDescriptor* parent, int number) const;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000582
583 // -----------------------------------------------------------------
584 // Adding items.
585
586 // These add items to the corresponding tables. They return false if
587 // the key already exists in the table. For AddAliasUnderParent(), the
588 // string passed in must be one that was constructed using AllocateString(),
589 // as it will be used as a key in the symbols_by_parent_ map without copying.
590 bool AddAliasUnderParent(const void* parent, const string& name,
591 Symbol symbol);
592 bool AddFieldByNumber(const FieldDescriptor* field);
593 bool AddEnumValueByNumber(const EnumValueDescriptor* value);
594
595 // Adds the field to the lowercase_name and camelcase_name maps. Never
596 // fails because we allow duplicates; the first field by the name wins.
597 void AddFieldByStylizedNames(const FieldDescriptor* field);
598
jieluo@google.com4de8f552014-07-18 00:47:59 +0000599 // Populates p->first->locations_by_path_ from p->second.
600 // Unusual signature dictated by GoogleOnceDynamic.
601 static void BuildLocationsByPath(
602 pair<const FileDescriptorTables*, const SourceCodeInfo*>* p);
603
604 // Returns the location denoted by the specified path through info,
605 // or NULL if not found.
606 // The value of info must be that of the corresponding FileDescriptor.
607 // (Conceptually a pure function, but stateful as an optimisation.)
608 const SourceCodeInfo_Location* GetSourceLocation(
609 const vector<int>& path, const SourceCodeInfo* info) const;
610
kenton@google.comd37d46d2009-04-25 02:53:47 +0000611 private:
612 SymbolsByParentMap symbols_by_parent_;
613 FieldsByNameMap fields_by_lowercase_name_;
614 FieldsByNameMap fields_by_camelcase_name_;
615 FieldsByNumberMap fields_by_number_; // Not including extensions.
616 EnumValuesByNumberMap enum_values_by_number_;
Feng Xiao6ef984a2014-11-10 17:34:54 -0800617 mutable EnumValuesByNumberMap unknown_enum_values_by_number_
618 GOOGLE_GUARDED_BY(unknown_enum_values_mu_);
jieluo@google.com4de8f552014-07-18 00:47:59 +0000619
620 // Populated on first request to save space, hence constness games.
621 mutable GoogleOnceDynamic locations_by_path_once_;
622 mutable LocationsByPathMap locations_by_path_;
Feng Xiao6ef984a2014-11-10 17:34:54 -0800623
624 // Mutex to protect the unknown-enum-value map due to dynamic
625 // EnumValueDescriptor creation on unknown values.
626 mutable Mutex unknown_enum_values_mu_;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000627};
628
temporal40ee5512008-07-10 02:12:20 +0000629DescriptorPool::Tables::Tables()
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000630 // Start some hash_map and hash_set objects with a small # of buckets
631 : known_bad_files_(3),
jieluo@google.com4de8f552014-07-18 00:47:59 +0000632 known_bad_symbols_(3),
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000633 extensions_loaded_from_db_(3),
634 symbols_by_name_(3),
635 files_by_name_(3) {}
636
temporal40ee5512008-07-10 02:12:20 +0000637
638DescriptorPool::Tables::~Tables() {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000639 GOOGLE_DCHECK(checkpoints_.empty());
kenton@google.com24bf56f2008-09-24 20:31:01 +0000640 // Note that the deletion order is important, since the destructors of some
641 // messages may refer to objects in allocations_.
642 STLDeleteElements(&messages_);
temporal40ee5512008-07-10 02:12:20 +0000643 for (int i = 0; i < allocations_.size(); i++) {
644 operator delete(allocations_[i]);
645 }
646 STLDeleteElements(&strings_);
kenton@google.comd37d46d2009-04-25 02:53:47 +0000647 STLDeleteElements(&file_tables_);
temporal40ee5512008-07-10 02:12:20 +0000648}
649
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000650FileDescriptorTables::FileDescriptorTables()
651 // Initialize all the hash tables to start out with a small # of buckets
652 : symbols_by_parent_(3),
653 fields_by_lowercase_name_(3),
654 fields_by_camelcase_name_(3),
655 fields_by_number_(3),
Feng Xiao6ef984a2014-11-10 17:34:54 -0800656 enum_values_by_number_(3),
657 unknown_enum_values_by_number_(3) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000658}
659
kenton@google.comd37d46d2009-04-25 02:53:47 +0000660FileDescriptorTables::~FileDescriptorTables() {}
661
662const FileDescriptorTables FileDescriptorTables::kEmpty;
663
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000664void DescriptorPool::Tables::AddCheckpoint() {
665 checkpoints_.push_back(CheckPoint(this));
temporal40ee5512008-07-10 02:12:20 +0000666}
667
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000668void DescriptorPool::Tables::ClearLastCheckpoint() {
669 GOOGLE_DCHECK(!checkpoints_.empty());
670 checkpoints_.pop_back();
671 if (checkpoints_.empty()) {
672 // All checkpoints have been cleared: we can now commit all of the pending
673 // data.
674 symbols_after_checkpoint_.clear();
675 files_after_checkpoint_.clear();
676 extensions_after_checkpoint_.clear();
677 }
678}
679
680void DescriptorPool::Tables::RollbackToLastCheckpoint() {
681 GOOGLE_DCHECK(!checkpoints_.empty());
682 const CheckPoint& checkpoint = checkpoints_.back();
683
684 for (int i = checkpoint.pending_symbols_before_checkpoint;
685 i < symbols_after_checkpoint_.size();
686 i++) {
temporal40ee5512008-07-10 02:12:20 +0000687 symbols_by_name_.erase(symbols_after_checkpoint_[i]);
688 }
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000689 for (int i = checkpoint.pending_files_before_checkpoint;
690 i < files_after_checkpoint_.size();
691 i++) {
temporal40ee5512008-07-10 02:12:20 +0000692 files_by_name_.erase(files_after_checkpoint_[i]);
693 }
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000694 for (int i = checkpoint.pending_extensions_before_checkpoint;
695 i < extensions_after_checkpoint_.size();
696 i++) {
kenton@google.comd37d46d2009-04-25 02:53:47 +0000697 extensions_.erase(extensions_after_checkpoint_[i]);
temporal40ee5512008-07-10 02:12:20 +0000698 }
699
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000700 symbols_after_checkpoint_.resize(
701 checkpoint.pending_symbols_before_checkpoint);
702 files_after_checkpoint_.resize(checkpoint.pending_files_before_checkpoint);
703 extensions_after_checkpoint_.resize(
704 checkpoint.pending_extensions_before_checkpoint);
temporal40ee5512008-07-10 02:12:20 +0000705
706 STLDeleteContainerPointers(
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000707 strings_.begin() + checkpoint.strings_before_checkpoint, strings_.end());
temporal40ee5512008-07-10 02:12:20 +0000708 STLDeleteContainerPointers(
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000709 messages_.begin() + checkpoint.messages_before_checkpoint,
710 messages_.end());
kenton@google.comd37d46d2009-04-25 02:53:47 +0000711 STLDeleteContainerPointers(
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000712 file_tables_.begin() + checkpoint.file_tables_before_checkpoint,
713 file_tables_.end());
714 for (int i = checkpoint.allocations_before_checkpoint;
715 i < allocations_.size();
716 i++) {
temporal40ee5512008-07-10 02:12:20 +0000717 operator delete(allocations_[i]);
718 }
719
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000720 strings_.resize(checkpoint.strings_before_checkpoint);
721 messages_.resize(checkpoint.messages_before_checkpoint);
722 file_tables_.resize(checkpoint.file_tables_before_checkpoint);
723 allocations_.resize(checkpoint.allocations_before_checkpoint);
724 checkpoints_.pop_back();
temporal40ee5512008-07-10 02:12:20 +0000725}
726
727// -------------------------------------------------------------------
728
729inline Symbol DescriptorPool::Tables::FindSymbol(const string& key) const {
730 const Symbol* result = FindOrNull(symbols_by_name_, key.c_str());
731 if (result == NULL) {
732 return kNullSymbol;
733 } else {
734 return *result;
735 }
736}
737
kenton@google.comd37d46d2009-04-25 02:53:47 +0000738inline Symbol FileDescriptorTables::FindNestedSymbol(
temporal40ee5512008-07-10 02:12:20 +0000739 const void* parent, const string& name) const {
740 const Symbol* result =
741 FindOrNull(symbols_by_parent_, PointerStringPair(parent, name.c_str()));
742 if (result == NULL) {
743 return kNullSymbol;
744 } else {
745 return *result;
746 }
747}
748
kenton@google.comd37d46d2009-04-25 02:53:47 +0000749inline Symbol FileDescriptorTables::FindNestedSymbolOfType(
temporal40ee5512008-07-10 02:12:20 +0000750 const void* parent, const string& name, const Symbol::Type type) const {
751 Symbol result = FindNestedSymbol(parent, name);
752 if (result.type != type) return kNullSymbol;
753 return result;
754}
755
kenton@google.com2d6daa72009-01-22 01:27:00 +0000756Symbol DescriptorPool::Tables::FindByNameHelper(
jieluo@google.com4de8f552014-07-18 00:47:59 +0000757 const DescriptorPool* pool, const string& name) {
kenton@google.com2d6daa72009-01-22 01:27:00 +0000758 MutexLockMaybe lock(pool->mutex_);
jieluo@google.com4de8f552014-07-18 00:47:59 +0000759 known_bad_symbols_.clear();
760 known_bad_files_.clear();
kenton@google.com2d6daa72009-01-22 01:27:00 +0000761 Symbol result = FindSymbol(name);
762
763 if (result.IsNull() && pool->underlay_ != NULL) {
764 // Symbol not found; check the underlay.
765 result =
766 pool->underlay_->tables_->FindByNameHelper(pool->underlay_, name);
767 }
768
769 if (result.IsNull()) {
770 // Symbol still not found, so check fallback database.
771 if (pool->TryFindSymbolInFallbackDatabase(name)) {
772 result = FindSymbol(name);
773 }
774 }
775
776 return result;
777}
778
temporal40ee5512008-07-10 02:12:20 +0000779inline const FileDescriptor* DescriptorPool::Tables::FindFile(
780 const string& key) const {
781 return FindPtrOrNull(files_by_name_, key.c_str());
782}
783
kenton@google.comd37d46d2009-04-25 02:53:47 +0000784inline const FieldDescriptor* FileDescriptorTables::FindFieldByNumber(
temporal40ee5512008-07-10 02:12:20 +0000785 const Descriptor* parent, int number) const {
Jisi Liu885b6122015-02-28 14:51:22 -0800786 return FindPtrOrNull(fields_by_number_, std::make_pair(parent, number));
temporal40ee5512008-07-10 02:12:20 +0000787}
788
kenton@google.comd37d46d2009-04-25 02:53:47 +0000789inline const FieldDescriptor* FileDescriptorTables::FindFieldByLowercaseName(
kenton@google.com2d6daa72009-01-22 01:27:00 +0000790 const void* parent, const string& lowercase_name) const {
791 return FindPtrOrNull(fields_by_lowercase_name_,
792 PointerStringPair(parent, lowercase_name.c_str()));
793}
794
kenton@google.comd37d46d2009-04-25 02:53:47 +0000795inline const FieldDescriptor* FileDescriptorTables::FindFieldByCamelcaseName(
kenton@google.com2d6daa72009-01-22 01:27:00 +0000796 const void* parent, const string& camelcase_name) const {
797 return FindPtrOrNull(fields_by_camelcase_name_,
798 PointerStringPair(parent, camelcase_name.c_str()));
799}
800
kenton@google.comd37d46d2009-04-25 02:53:47 +0000801inline const EnumValueDescriptor* FileDescriptorTables::FindEnumValueByNumber(
temporal40ee5512008-07-10 02:12:20 +0000802 const EnumDescriptor* parent, int number) const {
Jisi Liu885b6122015-02-28 14:51:22 -0800803 return FindPtrOrNull(enum_values_by_number_, std::make_pair(parent, number));
temporal40ee5512008-07-10 02:12:20 +0000804}
805
Feng Xiao6ef984a2014-11-10 17:34:54 -0800806inline const EnumValueDescriptor*
807FileDescriptorTables::FindEnumValueByNumberCreatingIfUnknown(
808 const EnumDescriptor* parent, int number) const {
809 // First try, with map of compiled-in values.
810 {
Jisi Liu885b6122015-02-28 14:51:22 -0800811 const EnumValueDescriptor* desc =
812 FindPtrOrNull(enum_values_by_number_, std::make_pair(parent, number));
Feng Xiao6ef984a2014-11-10 17:34:54 -0800813 if (desc != NULL) {
814 return desc;
815 }
816 }
817 // Second try, with reader lock held on unknown enum values: common case.
818 {
819 ReaderMutexLock l(&unknown_enum_values_mu_);
820 const EnumValueDescriptor* desc = FindPtrOrNull(
Jisi Liu885b6122015-02-28 14:51:22 -0800821 unknown_enum_values_by_number_, std::make_pair(parent, number));
Feng Xiao6ef984a2014-11-10 17:34:54 -0800822 if (desc != NULL) {
823 return desc;
824 }
825 }
826 // If not found, try again with writer lock held, and create new descriptor if
827 // necessary.
828 {
829 WriterMutexLock l(&unknown_enum_values_mu_);
830 const EnumValueDescriptor* desc = FindPtrOrNull(
Jisi Liu885b6122015-02-28 14:51:22 -0800831 unknown_enum_values_by_number_, std::make_pair(parent, number));
Feng Xiao6ef984a2014-11-10 17:34:54 -0800832 if (desc != NULL) {
833 return desc;
834 }
835
836 // Create an EnumValueDescriptor dynamically. We don't insert it into the
837 // EnumDescriptor (it's not a part of the enum as originally defined), but
838 // we do insert it into the table so that we can return the same pointer
839 // later.
840 string enum_value_name = StringPrintf(
841 "UNKNOWN_ENUM_VALUE_%s_%d", parent->name().c_str(), number);
842 DescriptorPool::Tables* tables =
843 const_cast<DescriptorPool::Tables*>(DescriptorPool::generated_pool()->
844 tables_.get());
845 EnumValueDescriptor* result = tables->Allocate<EnumValueDescriptor>();
846 result->name_ = tables->AllocateString(enum_value_name);
847 result->full_name_ = tables->AllocateString(parent->full_name() +
848 "." + enum_value_name);
849 result->number_ = number;
850 result->type_ = parent;
851 result->options_ = &EnumValueOptions::default_instance();
852 InsertIfNotPresent(&unknown_enum_values_by_number_,
Jisi Liu885b6122015-02-28 14:51:22 -0800853 std::make_pair(parent, number), result);
Feng Xiao6ef984a2014-11-10 17:34:54 -0800854 return result;
855 }
856}
857
858
kenton@google.comd37d46d2009-04-25 02:53:47 +0000859inline const FieldDescriptor* DescriptorPool::Tables::FindExtension(
860 const Descriptor* extendee, int number) {
Jisi Liu885b6122015-02-28 14:51:22 -0800861 return FindPtrOrNull(extensions_, std::make_pair(extendee, number));
kenton@google.comd37d46d2009-04-25 02:53:47 +0000862}
863
864inline void DescriptorPool::Tables::FindAllExtensions(
865 const Descriptor* extendee, vector<const FieldDescriptor*>* out) const {
866 ExtensionsGroupedByDescriptorMap::const_iterator it =
Jisi Liu885b6122015-02-28 14:51:22 -0800867 extensions_.lower_bound(std::make_pair(extendee, 0));
kenton@google.comd37d46d2009-04-25 02:53:47 +0000868 for (; it != extensions_.end() && it->first.first == extendee; ++it) {
869 out->push_back(it->second);
870 }
871}
872
temporal40ee5512008-07-10 02:12:20 +0000873// -------------------------------------------------------------------
874
875bool DescriptorPool::Tables::AddSymbol(
kenton@google.comd37d46d2009-04-25 02:53:47 +0000876 const string& full_name, Symbol symbol) {
temporal40ee5512008-07-10 02:12:20 +0000877 if (InsertIfNotPresent(&symbols_by_name_, full_name.c_str(), symbol)) {
878 symbols_after_checkpoint_.push_back(full_name.c_str());
temporal40ee5512008-07-10 02:12:20 +0000879 return true;
880 } else {
881 return false;
882 }
883}
884
kenton@google.comd37d46d2009-04-25 02:53:47 +0000885bool FileDescriptorTables::AddAliasUnderParent(
temporal40ee5512008-07-10 02:12:20 +0000886 const void* parent, const string& name, Symbol symbol) {
887 PointerStringPair by_parent_key(parent, name.c_str());
kenton@google.comd37d46d2009-04-25 02:53:47 +0000888 return InsertIfNotPresent(&symbols_by_parent_, by_parent_key, symbol);
temporal40ee5512008-07-10 02:12:20 +0000889}
890
891bool DescriptorPool::Tables::AddFile(const FileDescriptor* file) {
892 if (InsertIfNotPresent(&files_by_name_, file->name().c_str(), file)) {
893 files_after_checkpoint_.push_back(file->name().c_str());
894 return true;
895 } else {
896 return false;
897 }
898}
899
kenton@google.comd37d46d2009-04-25 02:53:47 +0000900void FileDescriptorTables::AddFieldByStylizedNames(
kenton@google.com2d6daa72009-01-22 01:27:00 +0000901 const FieldDescriptor* field) {
902 const void* parent;
903 if (field->is_extension()) {
904 if (field->extension_scope() == NULL) {
905 parent = field->file();
906 } else {
907 parent = field->extension_scope();
908 }
909 } else {
910 parent = field->containing_type();
911 }
912
913 PointerStringPair lowercase_key(parent, field->lowercase_name().c_str());
kenton@google.comd37d46d2009-04-25 02:53:47 +0000914 InsertIfNotPresent(&fields_by_lowercase_name_, lowercase_key, field);
kenton@google.com2d6daa72009-01-22 01:27:00 +0000915
916 PointerStringPair camelcase_key(parent, field->camelcase_name().c_str());
kenton@google.comd37d46d2009-04-25 02:53:47 +0000917 InsertIfNotPresent(&fields_by_camelcase_name_, camelcase_key, field);
kenton@google.com2d6daa72009-01-22 01:27:00 +0000918}
919
kenton@google.comd37d46d2009-04-25 02:53:47 +0000920bool FileDescriptorTables::AddFieldByNumber(const FieldDescriptor* field) {
temporal40ee5512008-07-10 02:12:20 +0000921 DescriptorIntPair key(field->containing_type(), field->number());
kenton@google.comd37d46d2009-04-25 02:53:47 +0000922 return InsertIfNotPresent(&fields_by_number_, key, field);
temporal40ee5512008-07-10 02:12:20 +0000923}
924
kenton@google.comd37d46d2009-04-25 02:53:47 +0000925bool FileDescriptorTables::AddEnumValueByNumber(
temporal40ee5512008-07-10 02:12:20 +0000926 const EnumValueDescriptor* value) {
927 EnumIntPair key(value->type(), value->number());
kenton@google.comd37d46d2009-04-25 02:53:47 +0000928 return InsertIfNotPresent(&enum_values_by_number_, key, value);
929}
930
931bool DescriptorPool::Tables::AddExtension(const FieldDescriptor* field) {
932 DescriptorIntPair key(field->containing_type(), field->number());
933 if (InsertIfNotPresent(&extensions_, key, field)) {
934 extensions_after_checkpoint_.push_back(key);
temporal40ee5512008-07-10 02:12:20 +0000935 return true;
936 } else {
937 return false;
938 }
939}
940
941// -------------------------------------------------------------------
942
943template<typename Type>
944Type* DescriptorPool::Tables::Allocate() {
945 return reinterpret_cast<Type*>(AllocateBytes(sizeof(Type)));
946}
947
948template<typename Type>
949Type* DescriptorPool::Tables::AllocateArray(int count) {
950 return reinterpret_cast<Type*>(AllocateBytes(sizeof(Type) * count));
951}
952
953string* DescriptorPool::Tables::AllocateString(const string& value) {
954 string* result = new string(value);
955 strings_.push_back(result);
956 return result;
957}
958
959template<typename Type>
liujisi@google.comc5553a32014-05-28 21:48:28 +0000960Type* DescriptorPool::Tables::AllocateMessage(Type* /* dummy */) {
temporal40ee5512008-07-10 02:12:20 +0000961 Type* result = new Type;
962 messages_.push_back(result);
963 return result;
964}
965
kenton@google.comd37d46d2009-04-25 02:53:47 +0000966FileDescriptorTables* DescriptorPool::Tables::AllocateFileTables() {
967 FileDescriptorTables* result = new FileDescriptorTables;
968 file_tables_.push_back(result);
969 return result;
970}
971
temporal40ee5512008-07-10 02:12:20 +0000972void* DescriptorPool::Tables::AllocateBytes(int size) {
973 // TODO(kenton): Would it be worthwhile to implement this in some more
974 // sophisticated way? Probably not for the open source release, but for
975 // internal use we could easily plug in one of our existing memory pool
976 // allocators...
977 if (size == 0) return NULL;
978
979 void* result = operator new(size);
980 allocations_.push_back(result);
981 return result;
982}
983
jieluo@google.com4de8f552014-07-18 00:47:59 +0000984void FileDescriptorTables::BuildLocationsByPath(
985 pair<const FileDescriptorTables*, const SourceCodeInfo*>* p) {
986 for (int i = 0, len = p->second->location_size(); i < len; ++i) {
987 const SourceCodeInfo_Location* loc = &p->second->location().Get(i);
988 p->first->locations_by_path_[Join(loc->path(), ",")] = loc;
989 }
990}
991
992const SourceCodeInfo_Location* FileDescriptorTables::GetSourceLocation(
993 const vector<int>& path, const SourceCodeInfo* info) const {
994 pair<const FileDescriptorTables*, const SourceCodeInfo*> p(
Jisi Liu885b6122015-02-28 14:51:22 -0800995 std::make_pair(this, info));
jieluo@google.com4de8f552014-07-18 00:47:59 +0000996 locations_by_path_once_.Init(&FileDescriptorTables::BuildLocationsByPath, &p);
997 return FindPtrOrNull(locations_by_path_, Join(path, ","));
998}
999
temporal40ee5512008-07-10 02:12:20 +00001000// ===================================================================
1001// DescriptorPool
1002
1003DescriptorPool::ErrorCollector::~ErrorCollector() {}
1004
1005DescriptorPool::DescriptorPool()
1006 : mutex_(NULL),
1007 fallback_database_(NULL),
1008 default_error_collector_(NULL),
1009 underlay_(NULL),
1010 tables_(new Tables),
1011 enforce_dependencies_(true),
jieluo@google.com4de8f552014-07-18 00:47:59 +00001012 allow_unknown_(false),
1013 enforce_weak_(false) {}
temporal40ee5512008-07-10 02:12:20 +00001014
1015DescriptorPool::DescriptorPool(DescriptorDatabase* fallback_database,
1016 ErrorCollector* error_collector)
1017 : mutex_(new Mutex),
1018 fallback_database_(fallback_database),
1019 default_error_collector_(error_collector),
1020 underlay_(NULL),
1021 tables_(new Tables),
1022 enforce_dependencies_(true),
jieluo@google.com4de8f552014-07-18 00:47:59 +00001023 allow_unknown_(false),
1024 enforce_weak_(false) {
temporal40ee5512008-07-10 02:12:20 +00001025}
1026
1027DescriptorPool::DescriptorPool(const DescriptorPool* underlay)
1028 : mutex_(NULL),
1029 fallback_database_(NULL),
1030 default_error_collector_(NULL),
1031 underlay_(underlay),
1032 tables_(new Tables),
kenton@google.comd37d46d2009-04-25 02:53:47 +00001033 enforce_dependencies_(true),
jieluo@google.com4de8f552014-07-18 00:47:59 +00001034 allow_unknown_(false),
1035 enforce_weak_(false) {}
temporal40ee5512008-07-10 02:12:20 +00001036
1037DescriptorPool::~DescriptorPool() {
1038 if (mutex_ != NULL) delete mutex_;
1039}
1040
1041// DescriptorPool::BuildFile() defined later.
1042// DescriptorPool::BuildFileCollectingErrors() defined later.
temporal40ee5512008-07-10 02:12:20 +00001043
1044void DescriptorPool::InternalDontEnforceDependencies() {
1045 enforce_dependencies_ = false;
1046}
1047
jieluo@google.com4de8f552014-07-18 00:47:59 +00001048void DescriptorPool::AddUnusedImportTrackFile(const string& file_name) {
1049 unused_import_track_files_.insert(file_name);
1050}
1051
1052void DescriptorPool::ClearUnusedImportTrackFiles() {
1053 unused_import_track_files_.clear();
1054}
1055
kenton@google.comd37d46d2009-04-25 02:53:47 +00001056bool DescriptorPool::InternalIsFileLoaded(const string& filename) const {
1057 MutexLockMaybe lock(mutex_);
1058 return tables_->FindFile(filename) != NULL;
1059}
1060
1061// generated_pool ====================================================
1062
1063namespace {
1064
kenton@google.comfccb1462009-12-18 02:11:36 +00001065
kenton@google.comd37d46d2009-04-25 02:53:47 +00001066EncodedDescriptorDatabase* generated_database_ = NULL;
1067DescriptorPool* generated_pool_ = NULL;
temporalbdbb8632009-12-18 08:21:00 +00001068GOOGLE_PROTOBUF_DECLARE_ONCE(generated_pool_init_);
kenton@google.comd37d46d2009-04-25 02:53:47 +00001069
kenton@google.com63e646b2009-05-06 19:27:03 +00001070void DeleteGeneratedPool() {
1071 delete generated_database_;
1072 generated_database_ = NULL;
1073 delete generated_pool_;
1074 generated_pool_ = NULL;
kenton@google.comd37d46d2009-04-25 02:53:47 +00001075}
1076
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001077static void InitGeneratedPool() {
kenton@google.com63e646b2009-05-06 19:27:03 +00001078 generated_database_ = new EncodedDescriptorDatabase;
1079 generated_pool_ = new DescriptorPool(generated_database_);
kenton@google.comfccb1462009-12-18 02:11:36 +00001080
kenton@google.com63e646b2009-05-06 19:27:03 +00001081 internal::OnShutdown(&DeleteGeneratedPool);
1082}
1083
1084inline void InitGeneratedPoolOnce() {
kenton@google.com80b1d622009-07-29 01:13:20 +00001085 ::google::protobuf::GoogleOnceInit(&generated_pool_init_, &InitGeneratedPool);
kenton@google.com63e646b2009-05-06 19:27:03 +00001086}
kenton@google.comd37d46d2009-04-25 02:53:47 +00001087
1088} // anonymous namespace
1089
1090const DescriptorPool* DescriptorPool::generated_pool() {
kenton@google.com63e646b2009-05-06 19:27:03 +00001091 InitGeneratedPoolOnce();
kenton@google.comd37d46d2009-04-25 02:53:47 +00001092 return generated_pool_;
1093}
1094
1095DescriptorPool* DescriptorPool::internal_generated_pool() {
kenton@google.com63e646b2009-05-06 19:27:03 +00001096 InitGeneratedPoolOnce();
kenton@google.comd37d46d2009-04-25 02:53:47 +00001097 return generated_pool_;
1098}
1099
1100void DescriptorPool::InternalAddGeneratedFile(
1101 const void* encoded_file_descriptor, int size) {
1102 // So, this function is called in the process of initializing the
1103 // descriptors for generated proto classes. Each generated .pb.cc file
1104 // has an internal procedure called AddDescriptors() which is called at
1105 // process startup, and that function calls this one in order to register
1106 // the raw bytes of the FileDescriptorProto representing the file.
1107 //
1108 // We do not actually construct the descriptor objects right away. We just
1109 // hang on to the bytes until they are actually needed. We actually construct
1110 // the descriptor the first time one of the following things happens:
1111 // * Someone calls a method like descriptor(), GetDescriptor(), or
1112 // GetReflection() on the generated types, which requires returning the
1113 // descriptor or an object based on it.
1114 // * Someone looks up the descriptor in DescriptorPool::generated_pool().
1115 //
1116 // Once one of these happens, the DescriptorPool actually parses the
1117 // FileDescriptorProto and generates a FileDescriptor (and all its children)
1118 // based on it.
1119 //
1120 // Note that FileDescriptorProto is itself a generated protocol message.
1121 // Therefore, when we parse one, we have to be very careful to avoid using
1122 // any descriptor-based operations, since this might cause infinite recursion
1123 // or deadlock.
kenton@google.com63e646b2009-05-06 19:27:03 +00001124 InitGeneratedPoolOnce();
kenton@google.comd37d46d2009-04-25 02:53:47 +00001125 GOOGLE_CHECK(generated_database_->Add(encoded_file_descriptor, size));
1126}
1127
1128
temporal40ee5512008-07-10 02:12:20 +00001129// Find*By* methods ==================================================
1130
1131// TODO(kenton): There's a lot of repeated code here, but I'm not sure if
1132// there's any good way to factor it out. Think about this some time when
1133// there's nothing more important to do (read: never).
1134
1135const FileDescriptor* DescriptorPool::FindFileByName(const string& name) const {
1136 MutexLockMaybe lock(mutex_);
jieluo@google.com4de8f552014-07-18 00:47:59 +00001137 tables_->known_bad_symbols_.clear();
1138 tables_->known_bad_files_.clear();
temporal40ee5512008-07-10 02:12:20 +00001139 const FileDescriptor* result = tables_->FindFile(name);
1140 if (result != NULL) return result;
1141 if (underlay_ != NULL) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001142 result = underlay_->FindFileByName(name);
temporal40ee5512008-07-10 02:12:20 +00001143 if (result != NULL) return result;
1144 }
1145 if (TryFindFileInFallbackDatabase(name)) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001146 result = tables_->FindFile(name);
temporal40ee5512008-07-10 02:12:20 +00001147 if (result != NULL) return result;
1148 }
1149 return NULL;
1150}
1151
1152const FileDescriptor* DescriptorPool::FindFileContainingSymbol(
1153 const string& symbol_name) const {
1154 MutexLockMaybe lock(mutex_);
jieluo@google.com4de8f552014-07-18 00:47:59 +00001155 tables_->known_bad_symbols_.clear();
1156 tables_->known_bad_files_.clear();
temporal40ee5512008-07-10 02:12:20 +00001157 Symbol result = tables_->FindSymbol(symbol_name);
1158 if (!result.IsNull()) return result.GetFile();
1159 if (underlay_ != NULL) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001160 const FileDescriptor* file_result =
temporal40ee5512008-07-10 02:12:20 +00001161 underlay_->FindFileContainingSymbol(symbol_name);
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001162 if (file_result != NULL) return file_result;
temporal40ee5512008-07-10 02:12:20 +00001163 }
1164 if (TryFindSymbolInFallbackDatabase(symbol_name)) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001165 result = tables_->FindSymbol(symbol_name);
temporal40ee5512008-07-10 02:12:20 +00001166 if (!result.IsNull()) return result.GetFile();
1167 }
1168 return NULL;
1169}
1170
1171const Descriptor* DescriptorPool::FindMessageTypeByName(
1172 const string& name) const {
kenton@google.com2d6daa72009-01-22 01:27:00 +00001173 Symbol result = tables_->FindByNameHelper(this, name);
1174 return (result.type == Symbol::MESSAGE) ? result.descriptor : NULL;
temporal40ee5512008-07-10 02:12:20 +00001175}
1176
1177const FieldDescriptor* DescriptorPool::FindFieldByName(
1178 const string& name) const {
kenton@google.com2d6daa72009-01-22 01:27:00 +00001179 Symbol result = tables_->FindByNameHelper(this, name);
1180 if (result.type == Symbol::FIELD &&
1181 !result.field_descriptor->is_extension()) {
temporal40ee5512008-07-10 02:12:20 +00001182 return result.field_descriptor;
kenton@google.com2d6daa72009-01-22 01:27:00 +00001183 } else {
1184 return NULL;
temporal40ee5512008-07-10 02:12:20 +00001185 }
temporal40ee5512008-07-10 02:12:20 +00001186}
1187
1188const FieldDescriptor* DescriptorPool::FindExtensionByName(
1189 const string& name) const {
kenton@google.com2d6daa72009-01-22 01:27:00 +00001190 Symbol result = tables_->FindByNameHelper(this, name);
1191 if (result.type == Symbol::FIELD &&
1192 result.field_descriptor->is_extension()) {
temporal40ee5512008-07-10 02:12:20 +00001193 return result.field_descriptor;
kenton@google.com2d6daa72009-01-22 01:27:00 +00001194 } else {
1195 return NULL;
temporal40ee5512008-07-10 02:12:20 +00001196 }
temporal40ee5512008-07-10 02:12:20 +00001197}
1198
jieluo@google.com4de8f552014-07-18 00:47:59 +00001199const OneofDescriptor* DescriptorPool::FindOneofByName(
1200 const string& name) const {
1201 Symbol result = tables_->FindByNameHelper(this, name);
1202 return (result.type == Symbol::ONEOF) ? result.oneof_descriptor : NULL;
1203}
1204
temporal40ee5512008-07-10 02:12:20 +00001205const EnumDescriptor* DescriptorPool::FindEnumTypeByName(
1206 const string& name) const {
kenton@google.com2d6daa72009-01-22 01:27:00 +00001207 Symbol result = tables_->FindByNameHelper(this, name);
1208 return (result.type == Symbol::ENUM) ? result.enum_descriptor : NULL;
temporal40ee5512008-07-10 02:12:20 +00001209}
1210
1211const EnumValueDescriptor* DescriptorPool::FindEnumValueByName(
1212 const string& name) const {
kenton@google.com2d6daa72009-01-22 01:27:00 +00001213 Symbol result = tables_->FindByNameHelper(this, name);
1214 return (result.type == Symbol::ENUM_VALUE) ?
1215 result.enum_value_descriptor : NULL;
temporal40ee5512008-07-10 02:12:20 +00001216}
1217
1218const ServiceDescriptor* DescriptorPool::FindServiceByName(
1219 const string& name) const {
kenton@google.com2d6daa72009-01-22 01:27:00 +00001220 Symbol result = tables_->FindByNameHelper(this, name);
1221 return (result.type == Symbol::SERVICE) ? result.service_descriptor : NULL;
temporal40ee5512008-07-10 02:12:20 +00001222}
1223
1224const MethodDescriptor* DescriptorPool::FindMethodByName(
1225 const string& name) const {
kenton@google.com2d6daa72009-01-22 01:27:00 +00001226 Symbol result = tables_->FindByNameHelper(this, name);
1227 return (result.type == Symbol::METHOD) ? result.method_descriptor : NULL;
temporal40ee5512008-07-10 02:12:20 +00001228}
1229
1230const FieldDescriptor* DescriptorPool::FindExtensionByNumber(
1231 const Descriptor* extendee, int number) const {
1232 MutexLockMaybe lock(mutex_);
jieluo@google.com4de8f552014-07-18 00:47:59 +00001233 tables_->known_bad_symbols_.clear();
1234 tables_->known_bad_files_.clear();
kenton@google.comd37d46d2009-04-25 02:53:47 +00001235 const FieldDescriptor* result = tables_->FindExtension(extendee, number);
1236 if (result != NULL) {
temporal40ee5512008-07-10 02:12:20 +00001237 return result;
1238 }
1239 if (underlay_ != NULL) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001240 result = underlay_->FindExtensionByNumber(extendee, number);
temporal40ee5512008-07-10 02:12:20 +00001241 if (result != NULL) return result;
1242 }
1243 if (TryFindExtensionInFallbackDatabase(extendee, number)) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001244 result = tables_->FindExtension(extendee, number);
kenton@google.comd37d46d2009-04-25 02:53:47 +00001245 if (result != NULL) {
temporal40ee5512008-07-10 02:12:20 +00001246 return result;
1247 }
1248 }
1249 return NULL;
1250}
1251
kenton@google.comd37d46d2009-04-25 02:53:47 +00001252void DescriptorPool::FindAllExtensions(
1253 const Descriptor* extendee, vector<const FieldDescriptor*>* out) const {
1254 MutexLockMaybe lock(mutex_);
jieluo@google.com4de8f552014-07-18 00:47:59 +00001255 tables_->known_bad_symbols_.clear();
1256 tables_->known_bad_files_.clear();
kenton@google.comd37d46d2009-04-25 02:53:47 +00001257
1258 // Initialize tables_->extensions_ from the fallback database first
1259 // (but do this only once per descriptor).
1260 if (fallback_database_ != NULL &&
1261 tables_->extensions_loaded_from_db_.count(extendee) == 0) {
1262 vector<int> numbers;
1263 if (fallback_database_->FindAllExtensionNumbers(extendee->full_name(),
1264 &numbers)) {
1265 for (int i = 0; i < numbers.size(); ++i) {
1266 int number = numbers[i];
1267 if (tables_->FindExtension(extendee, number) == NULL) {
1268 TryFindExtensionInFallbackDatabase(extendee, number);
1269 }
1270 }
1271 tables_->extensions_loaded_from_db_.insert(extendee);
1272 }
1273 }
1274
1275 tables_->FindAllExtensions(extendee, out);
1276 if (underlay_ != NULL) {
1277 underlay_->FindAllExtensions(extendee, out);
1278 }
1279}
1280
jieluo@google.com4de8f552014-07-18 00:47:59 +00001281
temporal40ee5512008-07-10 02:12:20 +00001282// -------------------------------------------------------------------
1283
1284const FieldDescriptor*
1285Descriptor::FindFieldByNumber(int key) const {
temporal40ee5512008-07-10 02:12:20 +00001286 const FieldDescriptor* result =
kenton@google.comd37d46d2009-04-25 02:53:47 +00001287 file()->tables_->FindFieldByNumber(this, key);
temporal40ee5512008-07-10 02:12:20 +00001288 if (result == NULL || result->is_extension()) {
1289 return NULL;
1290 } else {
1291 return result;
1292 }
1293}
1294
1295const FieldDescriptor*
kenton@google.com2d6daa72009-01-22 01:27:00 +00001296Descriptor::FindFieldByLowercaseName(const string& key) const {
kenton@google.com2d6daa72009-01-22 01:27:00 +00001297 const FieldDescriptor* result =
kenton@google.comd37d46d2009-04-25 02:53:47 +00001298 file()->tables_->FindFieldByLowercaseName(this, key);
kenton@google.com2d6daa72009-01-22 01:27:00 +00001299 if (result == NULL || result->is_extension()) {
1300 return NULL;
1301 } else {
1302 return result;
1303 }
1304}
1305
1306const FieldDescriptor*
1307Descriptor::FindFieldByCamelcaseName(const string& key) const {
kenton@google.com2d6daa72009-01-22 01:27:00 +00001308 const FieldDescriptor* result =
kenton@google.comd37d46d2009-04-25 02:53:47 +00001309 file()->tables_->FindFieldByCamelcaseName(this, key);
kenton@google.com2d6daa72009-01-22 01:27:00 +00001310 if (result == NULL || result->is_extension()) {
1311 return NULL;
1312 } else {
1313 return result;
1314 }
1315}
1316
1317const FieldDescriptor*
temporal40ee5512008-07-10 02:12:20 +00001318Descriptor::FindFieldByName(const string& key) const {
temporal40ee5512008-07-10 02:12:20 +00001319 Symbol result =
kenton@google.comd37d46d2009-04-25 02:53:47 +00001320 file()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD);
temporal40ee5512008-07-10 02:12:20 +00001321 if (!result.IsNull() && !result.field_descriptor->is_extension()) {
1322 return result.field_descriptor;
1323 } else {
1324 return NULL;
1325 }
1326}
1327
jieluo@google.com4de8f552014-07-18 00:47:59 +00001328const OneofDescriptor*
1329Descriptor::FindOneofByName(const string& key) const {
1330 Symbol result =
1331 file()->tables_->FindNestedSymbolOfType(this, key, Symbol::ONEOF);
1332 if (!result.IsNull()) {
1333 return result.oneof_descriptor;
1334 } else {
1335 return NULL;
1336 }
1337}
1338
temporal40ee5512008-07-10 02:12:20 +00001339const FieldDescriptor*
1340Descriptor::FindExtensionByName(const string& key) const {
temporal40ee5512008-07-10 02:12:20 +00001341 Symbol result =
kenton@google.comd37d46d2009-04-25 02:53:47 +00001342 file()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD);
temporal40ee5512008-07-10 02:12:20 +00001343 if (!result.IsNull() && result.field_descriptor->is_extension()) {
1344 return result.field_descriptor;
1345 } else {
1346 return NULL;
1347 }
1348}
1349
kenton@google.com2d6daa72009-01-22 01:27:00 +00001350const FieldDescriptor*
1351Descriptor::FindExtensionByLowercaseName(const string& key) const {
kenton@google.com2d6daa72009-01-22 01:27:00 +00001352 const FieldDescriptor* result =
kenton@google.comd37d46d2009-04-25 02:53:47 +00001353 file()->tables_->FindFieldByLowercaseName(this, key);
kenton@google.com2d6daa72009-01-22 01:27:00 +00001354 if (result == NULL || !result->is_extension()) {
1355 return NULL;
1356 } else {
1357 return result;
1358 }
1359}
1360
1361const FieldDescriptor*
1362Descriptor::FindExtensionByCamelcaseName(const string& key) const {
kenton@google.com2d6daa72009-01-22 01:27:00 +00001363 const FieldDescriptor* result =
kenton@google.comd37d46d2009-04-25 02:53:47 +00001364 file()->tables_->FindFieldByCamelcaseName(this, key);
kenton@google.com2d6daa72009-01-22 01:27:00 +00001365 if (result == NULL || !result->is_extension()) {
1366 return NULL;
1367 } else {
1368 return result;
1369 }
1370}
1371
temporal40ee5512008-07-10 02:12:20 +00001372const Descriptor*
1373Descriptor::FindNestedTypeByName(const string& key) const {
temporal40ee5512008-07-10 02:12:20 +00001374 Symbol result =
kenton@google.comd37d46d2009-04-25 02:53:47 +00001375 file()->tables_->FindNestedSymbolOfType(this, key, Symbol::MESSAGE);
temporal40ee5512008-07-10 02:12:20 +00001376 if (!result.IsNull()) {
1377 return result.descriptor;
1378 } else {
1379 return NULL;
1380 }
1381}
1382
1383const EnumDescriptor*
1384Descriptor::FindEnumTypeByName(const string& key) const {
temporal40ee5512008-07-10 02:12:20 +00001385 Symbol result =
kenton@google.comd37d46d2009-04-25 02:53:47 +00001386 file()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM);
temporal40ee5512008-07-10 02:12:20 +00001387 if (!result.IsNull()) {
1388 return result.enum_descriptor;
1389 } else {
1390 return NULL;
1391 }
1392}
1393
1394const EnumValueDescriptor*
1395Descriptor::FindEnumValueByName(const string& key) const {
temporal40ee5512008-07-10 02:12:20 +00001396 Symbol result =
kenton@google.comd37d46d2009-04-25 02:53:47 +00001397 file()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM_VALUE);
temporal40ee5512008-07-10 02:12:20 +00001398 if (!result.IsNull()) {
1399 return result.enum_value_descriptor;
1400 } else {
1401 return NULL;
1402 }
1403}
1404
1405const EnumValueDescriptor*
1406EnumDescriptor::FindValueByName(const string& key) const {
temporal40ee5512008-07-10 02:12:20 +00001407 Symbol result =
kenton@google.comd37d46d2009-04-25 02:53:47 +00001408 file()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM_VALUE);
temporal40ee5512008-07-10 02:12:20 +00001409 if (!result.IsNull()) {
1410 return result.enum_value_descriptor;
1411 } else {
1412 return NULL;
1413 }
1414}
1415
1416const EnumValueDescriptor*
1417EnumDescriptor::FindValueByNumber(int key) const {
kenton@google.comd37d46d2009-04-25 02:53:47 +00001418 return file()->tables_->FindEnumValueByNumber(this, key);
temporal40ee5512008-07-10 02:12:20 +00001419}
1420
Feng Xiao6ef984a2014-11-10 17:34:54 -08001421const EnumValueDescriptor*
1422EnumDescriptor::FindValueByNumberCreatingIfUnknown(int key) const {
1423 return file()->tables_->FindEnumValueByNumberCreatingIfUnknown(this, key);
1424}
1425
temporal40ee5512008-07-10 02:12:20 +00001426const MethodDescriptor*
1427ServiceDescriptor::FindMethodByName(const string& key) const {
temporal40ee5512008-07-10 02:12:20 +00001428 Symbol result =
kenton@google.comd37d46d2009-04-25 02:53:47 +00001429 file()->tables_->FindNestedSymbolOfType(this, key, Symbol::METHOD);
temporal40ee5512008-07-10 02:12:20 +00001430 if (!result.IsNull()) {
1431 return result.method_descriptor;
1432 } else {
1433 return NULL;
1434 }
1435}
1436
1437const Descriptor*
1438FileDescriptor::FindMessageTypeByName(const string& key) const {
kenton@google.comd37d46d2009-04-25 02:53:47 +00001439 Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::MESSAGE);
temporal40ee5512008-07-10 02:12:20 +00001440 if (!result.IsNull()) {
1441 return result.descriptor;
1442 } else {
1443 return NULL;
1444 }
1445}
1446
1447const EnumDescriptor*
1448FileDescriptor::FindEnumTypeByName(const string& key) const {
kenton@google.comd37d46d2009-04-25 02:53:47 +00001449 Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM);
temporal40ee5512008-07-10 02:12:20 +00001450 if (!result.IsNull()) {
1451 return result.enum_descriptor;
1452 } else {
1453 return NULL;
1454 }
1455}
1456
1457const EnumValueDescriptor*
1458FileDescriptor::FindEnumValueByName(const string& key) const {
temporal40ee5512008-07-10 02:12:20 +00001459 Symbol result =
kenton@google.comd37d46d2009-04-25 02:53:47 +00001460 tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM_VALUE);
temporal40ee5512008-07-10 02:12:20 +00001461 if (!result.IsNull()) {
1462 return result.enum_value_descriptor;
1463 } else {
1464 return NULL;
1465 }
1466}
1467
1468const ServiceDescriptor*
1469FileDescriptor::FindServiceByName(const string& key) const {
kenton@google.comd37d46d2009-04-25 02:53:47 +00001470 Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::SERVICE);
temporal40ee5512008-07-10 02:12:20 +00001471 if (!result.IsNull()) {
1472 return result.service_descriptor;
1473 } else {
1474 return NULL;
1475 }
1476}
1477
1478const FieldDescriptor*
1479FileDescriptor::FindExtensionByName(const string& key) const {
kenton@google.comd37d46d2009-04-25 02:53:47 +00001480 Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD);
temporal40ee5512008-07-10 02:12:20 +00001481 if (!result.IsNull() && result.field_descriptor->is_extension()) {
1482 return result.field_descriptor;
1483 } else {
1484 return NULL;
1485 }
1486}
1487
kenton@google.com2d6daa72009-01-22 01:27:00 +00001488const FieldDescriptor*
1489FileDescriptor::FindExtensionByLowercaseName(const string& key) const {
kenton@google.comd37d46d2009-04-25 02:53:47 +00001490 const FieldDescriptor* result = tables_->FindFieldByLowercaseName(this, key);
kenton@google.com2d6daa72009-01-22 01:27:00 +00001491 if (result == NULL || !result->is_extension()) {
1492 return NULL;
1493 } else {
1494 return result;
1495 }
1496}
1497
1498const FieldDescriptor*
1499FileDescriptor::FindExtensionByCamelcaseName(const string& key) const {
kenton@google.comd37d46d2009-04-25 02:53:47 +00001500 const FieldDescriptor* result = tables_->FindFieldByCamelcaseName(this, key);
kenton@google.com2d6daa72009-01-22 01:27:00 +00001501 if (result == NULL || !result->is_extension()) {
1502 return NULL;
1503 } else {
1504 return result;
1505 }
1506}
1507
jieluo@google.com4de8f552014-07-18 00:47:59 +00001508const Descriptor::ExtensionRange*
1509Descriptor::FindExtensionRangeContainingNumber(int number) const {
temporal40ee5512008-07-10 02:12:20 +00001510 // Linear search should be fine because we don't expect a message to have
1511 // more than a couple extension ranges.
1512 for (int i = 0; i < extension_range_count(); i++) {
1513 if (number >= extension_range(i)->start &&
1514 number < extension_range(i)->end) {
jieluo@google.com4de8f552014-07-18 00:47:59 +00001515 return extension_range(i);
temporal40ee5512008-07-10 02:12:20 +00001516 }
1517 }
jieluo@google.com4de8f552014-07-18 00:47:59 +00001518 return NULL;
temporal40ee5512008-07-10 02:12:20 +00001519}
1520
1521// -------------------------------------------------------------------
1522
1523bool DescriptorPool::TryFindFileInFallbackDatabase(const string& name) const {
1524 if (fallback_database_ == NULL) return false;
1525
1526 if (tables_->known_bad_files_.count(name) > 0) return false;
1527
1528 FileDescriptorProto file_proto;
1529 if (!fallback_database_->FindFileByName(name, &file_proto) ||
1530 BuildFileFromDatabase(file_proto) == NULL) {
1531 tables_->known_bad_files_.insert(name);
1532 return false;
1533 }
temporal40ee5512008-07-10 02:12:20 +00001534 return true;
1535}
1536
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001537bool DescriptorPool::IsSubSymbolOfBuiltType(const string& name) const {
1538 string prefix = name;
1539 for (;;) {
1540 string::size_type dot_pos = prefix.find_last_of('.');
1541 if (dot_pos == string::npos) {
1542 break;
1543 }
1544 prefix = prefix.substr(0, dot_pos);
1545 Symbol symbol = tables_->FindSymbol(prefix);
1546 // If the symbol type is anything other than PACKAGE, then its complete
1547 // definition is already known.
1548 if (!symbol.IsNull() && symbol.type != Symbol::PACKAGE) {
1549 return true;
1550 }
1551 }
1552 if (underlay_ != NULL) {
1553 // Check to see if any prefix of this symbol exists in the underlay.
1554 return underlay_->IsSubSymbolOfBuiltType(name);
1555 }
1556 return false;
1557}
1558
temporal40ee5512008-07-10 02:12:20 +00001559bool DescriptorPool::TryFindSymbolInFallbackDatabase(const string& name) const {
1560 if (fallback_database_ == NULL) return false;
1561
jieluo@google.com4de8f552014-07-18 00:47:59 +00001562 if (tables_->known_bad_symbols_.count(name) > 0) return false;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001563
temporal40ee5512008-07-10 02:12:20 +00001564 FileDescriptorProto file_proto;
jieluo@google.com4de8f552014-07-18 00:47:59 +00001565 if (// We skip looking in the fallback database if the name is a sub-symbol
1566 // of any descriptor that already exists in the descriptor pool (except
1567 // for package descriptors). This is valid because all symbols except
1568 // for packages are defined in a single file, so if the symbol exists
1569 // then we should already have its definition.
1570 //
1571 // The other reason to do this is to support "overriding" type
1572 // definitions by merging two databases that define the same type. (Yes,
1573 // people do this.) The main difficulty with making this work is that
1574 // FindFileContainingSymbol() is allowed to return both false positives
1575 // (e.g., SimpleDescriptorDatabase, UpgradedDescriptorDatabase) and false
1576 // negatives (e.g. ProtoFileParser, SourceTreeDescriptorDatabase).
1577 // When two such databases are merged, looking up a non-existent
1578 // sub-symbol of a type that already exists in the descriptor pool can
1579 // result in an attempt to load multiple definitions of the same type.
1580 // The check below avoids this.
1581 IsSubSymbolOfBuiltType(name)
temporal40ee5512008-07-10 02:12:20 +00001582
jieluo@google.com4de8f552014-07-18 00:47:59 +00001583 // Look up file containing this symbol in fallback database.
1584 || !fallback_database_->FindFileContainingSymbol(name, &file_proto)
temporal40ee5512008-07-10 02:12:20 +00001585
jieluo@google.com4de8f552014-07-18 00:47:59 +00001586 // Check if we've already built this file. If so, it apparently doesn't
1587 // contain the symbol we're looking for. Some DescriptorDatabases
1588 // return false positives.
1589 || tables_->FindFile(file_proto.name()) != NULL
1590
1591 // Build the file.
1592 || BuildFileFromDatabase(file_proto) == NULL) {
1593 tables_->known_bad_symbols_.insert(name);
temporal40ee5512008-07-10 02:12:20 +00001594 return false;
1595 }
1596
1597 return true;
1598}
1599
1600bool DescriptorPool::TryFindExtensionInFallbackDatabase(
1601 const Descriptor* containing_type, int field_number) const {
1602 if (fallback_database_ == NULL) return false;
1603
1604 FileDescriptorProto file_proto;
1605 if (!fallback_database_->FindFileContainingExtension(
1606 containing_type->full_name(), field_number, &file_proto)) {
1607 return false;
1608 }
1609
1610 if (tables_->FindFile(file_proto.name()) != NULL) {
1611 // We've already loaded this file, and it apparently doesn't contain the
1612 // extension we're looking for. Some DescriptorDatabases return false
1613 // positives.
1614 return false;
1615 }
1616
1617 if (BuildFileFromDatabase(file_proto) == NULL) {
1618 return false;
1619 }
1620
1621 return true;
1622}
1623
1624// ===================================================================
1625
Feng Xiaof157a562014-11-14 11:50:31 -08001626bool FieldDescriptor::is_map() const {
1627 return type() == TYPE_MESSAGE && message_type()->options().map_entry();
1628}
1629
temporal40ee5512008-07-10 02:12:20 +00001630string FieldDescriptor::DefaultValueAsString(bool quote_string_type) const {
1631 GOOGLE_CHECK(has_default_value()) << "No default value";
1632 switch (cpp_type()) {
1633 case CPPTYPE_INT32:
1634 return SimpleItoa(default_value_int32());
1635 break;
1636 case CPPTYPE_INT64:
1637 return SimpleItoa(default_value_int64());
1638 break;
1639 case CPPTYPE_UINT32:
1640 return SimpleItoa(default_value_uint32());
1641 break;
1642 case CPPTYPE_UINT64:
1643 return SimpleItoa(default_value_uint64());
1644 break;
1645 case CPPTYPE_FLOAT:
1646 return SimpleFtoa(default_value_float());
1647 break;
1648 case CPPTYPE_DOUBLE:
1649 return SimpleDtoa(default_value_double());
1650 break;
1651 case CPPTYPE_BOOL:
1652 return default_value_bool() ? "true" : "false";
1653 break;
1654 case CPPTYPE_STRING:
1655 if (quote_string_type) {
1656 return "\"" + CEscape(default_value_string()) + "\"";
1657 } else {
1658 if (type() == TYPE_BYTES) {
1659 return CEscape(default_value_string());
1660 } else {
1661 return default_value_string();
1662 }
1663 }
1664 break;
1665 case CPPTYPE_ENUM:
1666 return default_value_enum()->name();
1667 break;
1668 case CPPTYPE_MESSAGE:
1669 GOOGLE_LOG(DFATAL) << "Messages can't have default values!";
1670 break;
1671 }
1672 GOOGLE_LOG(FATAL) << "Can't get here: failed to get default value as string";
1673 return "";
1674}
1675
1676// CopyTo methods ====================================================
1677
1678void FileDescriptor::CopyTo(FileDescriptorProto* proto) const {
1679 proto->set_name(name());
1680 if (!package().empty()) proto->set_package(package());
Feng Xiao6ef984a2014-11-10 17:34:54 -08001681 // TODO(liujisi): Also populate when syntax="proto2".
1682 if (syntax() == SYNTAX_PROTO3) proto->set_syntax(SyntaxName(syntax()));
temporal40ee5512008-07-10 02:12:20 +00001683
1684 for (int i = 0; i < dependency_count(); i++) {
1685 proto->add_dependency(dependency(i)->name());
1686 }
1687
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001688 for (int i = 0; i < public_dependency_count(); i++) {
1689 proto->add_public_dependency(public_dependencies_[i]);
1690 }
1691
1692 for (int i = 0; i < weak_dependency_count(); i++) {
1693 proto->add_weak_dependency(weak_dependencies_[i]);
1694 }
1695
temporal40ee5512008-07-10 02:12:20 +00001696 for (int i = 0; i < message_type_count(); i++) {
1697 message_type(i)->CopyTo(proto->add_message_type());
1698 }
1699 for (int i = 0; i < enum_type_count(); i++) {
1700 enum_type(i)->CopyTo(proto->add_enum_type());
1701 }
1702 for (int i = 0; i < service_count(); i++) {
1703 service(i)->CopyTo(proto->add_service());
1704 }
1705 for (int i = 0; i < extension_count(); i++) {
1706 extension(i)->CopyTo(proto->add_extension());
1707 }
1708
1709 if (&options() != &FileOptions::default_instance()) {
1710 proto->mutable_options()->CopyFrom(options());
1711 }
1712}
1713
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001714void FileDescriptor::CopySourceCodeInfoTo(FileDescriptorProto* proto) const {
Feng Xiao6ef984a2014-11-10 17:34:54 -08001715 if (source_code_info_ &&
1716 source_code_info_ != &SourceCodeInfo::default_instance()) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001717 proto->mutable_source_code_info()->CopyFrom(*source_code_info_);
1718 }
1719}
1720
temporal40ee5512008-07-10 02:12:20 +00001721void Descriptor::CopyTo(DescriptorProto* proto) const {
1722 proto->set_name(name());
1723
1724 for (int i = 0; i < field_count(); i++) {
1725 field(i)->CopyTo(proto->add_field());
1726 }
jieluo@google.com4de8f552014-07-18 00:47:59 +00001727 for (int i = 0; i < oneof_decl_count(); i++) {
1728 oneof_decl(i)->CopyTo(proto->add_oneof_decl());
1729 }
temporal40ee5512008-07-10 02:12:20 +00001730 for (int i = 0; i < nested_type_count(); i++) {
1731 nested_type(i)->CopyTo(proto->add_nested_type());
1732 }
1733 for (int i = 0; i < enum_type_count(); i++) {
1734 enum_type(i)->CopyTo(proto->add_enum_type());
1735 }
1736 for (int i = 0; i < extension_range_count(); i++) {
1737 DescriptorProto::ExtensionRange* range = proto->add_extension_range();
1738 range->set_start(extension_range(i)->start);
1739 range->set_end(extension_range(i)->end);
1740 }
1741 for (int i = 0; i < extension_count(); i++) {
1742 extension(i)->CopyTo(proto->add_extension());
1743 }
1744
1745 if (&options() != &MessageOptions::default_instance()) {
1746 proto->mutable_options()->CopyFrom(options());
1747 }
1748}
1749
1750void FieldDescriptor::CopyTo(FieldDescriptorProto* proto) const {
1751 proto->set_name(name());
1752 proto->set_number(number());
kenton@google.coma2a32c22008-11-14 17:29:32 +00001753
1754 // Some compilers do not allow static_cast directly between two enum types,
1755 // so we must cast to int first.
1756 proto->set_label(static_cast<FieldDescriptorProto::Label>(
1757 implicit_cast<int>(label())));
1758 proto->set_type(static_cast<FieldDescriptorProto::Type>(
1759 implicit_cast<int>(type())));
temporal40ee5512008-07-10 02:12:20 +00001760
1761 if (is_extension()) {
kenton@google.comd37d46d2009-04-25 02:53:47 +00001762 if (!containing_type()->is_unqualified_placeholder_) {
1763 proto->set_extendee(".");
1764 }
temporal40ee5512008-07-10 02:12:20 +00001765 proto->mutable_extendee()->append(containing_type()->full_name());
1766 }
1767
1768 if (cpp_type() == CPPTYPE_MESSAGE) {
kenton@google.comd37d46d2009-04-25 02:53:47 +00001769 if (message_type()->is_placeholder_) {
1770 // We don't actually know if the type is a message type. It could be
1771 // an enum.
1772 proto->clear_type();
1773 }
1774
1775 if (!message_type()->is_unqualified_placeholder_) {
1776 proto->set_type_name(".");
1777 }
temporal40ee5512008-07-10 02:12:20 +00001778 proto->mutable_type_name()->append(message_type()->full_name());
1779 } else if (cpp_type() == CPPTYPE_ENUM) {
kenton@google.comd37d46d2009-04-25 02:53:47 +00001780 if (!enum_type()->is_unqualified_placeholder_) {
1781 proto->set_type_name(".");
1782 }
temporal40ee5512008-07-10 02:12:20 +00001783 proto->mutable_type_name()->append(enum_type()->full_name());
1784 }
1785
1786 if (has_default_value()) {
1787 proto->set_default_value(DefaultValueAsString(false));
1788 }
1789
jieluo@google.com4de8f552014-07-18 00:47:59 +00001790 if (containing_oneof() != NULL && !is_extension()) {
1791 proto->set_oneof_index(containing_oneof()->index());
1792 }
1793
temporal40ee5512008-07-10 02:12:20 +00001794 if (&options() != &FieldOptions::default_instance()) {
1795 proto->mutable_options()->CopyFrom(options());
1796 }
1797}
1798
jieluo@google.com4de8f552014-07-18 00:47:59 +00001799void OneofDescriptor::CopyTo(OneofDescriptorProto* proto) const {
1800 proto->set_name(name());
1801}
1802
temporal40ee5512008-07-10 02:12:20 +00001803void EnumDescriptor::CopyTo(EnumDescriptorProto* proto) const {
1804 proto->set_name(name());
1805
1806 for (int i = 0; i < value_count(); i++) {
1807 value(i)->CopyTo(proto->add_value());
1808 }
1809
1810 if (&options() != &EnumOptions::default_instance()) {
1811 proto->mutable_options()->CopyFrom(options());
1812 }
1813}
1814
1815void EnumValueDescriptor::CopyTo(EnumValueDescriptorProto* proto) const {
1816 proto->set_name(name());
1817 proto->set_number(number());
1818
1819 if (&options() != &EnumValueOptions::default_instance()) {
1820 proto->mutable_options()->CopyFrom(options());
1821 }
1822}
1823
1824void ServiceDescriptor::CopyTo(ServiceDescriptorProto* proto) const {
1825 proto->set_name(name());
1826
1827 for (int i = 0; i < method_count(); i++) {
1828 method(i)->CopyTo(proto->add_method());
1829 }
1830
1831 if (&options() != &ServiceOptions::default_instance()) {
1832 proto->mutable_options()->CopyFrom(options());
1833 }
1834}
1835
1836void MethodDescriptor::CopyTo(MethodDescriptorProto* proto) const {
1837 proto->set_name(name());
1838
kenton@google.comd37d46d2009-04-25 02:53:47 +00001839 if (!input_type()->is_unqualified_placeholder_) {
1840 proto->set_input_type(".");
1841 }
temporal40ee5512008-07-10 02:12:20 +00001842 proto->mutable_input_type()->append(input_type()->full_name());
kenton@google.comd37d46d2009-04-25 02:53:47 +00001843
1844 if (!output_type()->is_unqualified_placeholder_) {
1845 proto->set_output_type(".");
1846 }
temporal40ee5512008-07-10 02:12:20 +00001847 proto->mutable_output_type()->append(output_type()->full_name());
1848
1849 if (&options() != &MethodOptions::default_instance()) {
1850 proto->mutable_options()->CopyFrom(options());
1851 }
Feng Xiao99aa0f92014-11-20 16:18:53 -08001852
1853 if (client_streaming_) {
1854 proto->set_client_streaming(true);
1855 }
1856 if (server_streaming_) {
1857 proto->set_server_streaming(true);
1858 }
temporal40ee5512008-07-10 02:12:20 +00001859}
1860
1861// DebugString methods ===============================================
1862
1863namespace {
1864
1865// Used by each of the option formatters.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001866bool RetrieveOptions(int depth,
1867 const Message &options,
1868 vector<string> *option_entries) {
temporal40ee5512008-07-10 02:12:20 +00001869 option_entries->clear();
temporal779f61c2008-08-13 03:15:00 +00001870 const Reflection* reflection = options.GetReflection();
temporal40ee5512008-07-10 02:12:20 +00001871 vector<const FieldDescriptor*> fields;
temporal779f61c2008-08-13 03:15:00 +00001872 reflection->ListFields(options, &fields);
temporal40ee5512008-07-10 02:12:20 +00001873 for (int i = 0; i < fields.size(); i++) {
temporal40ee5512008-07-10 02:12:20 +00001874 int count = 1;
1875 bool repeated = false;
1876 if (fields[i]->is_repeated()) {
temporal779f61c2008-08-13 03:15:00 +00001877 count = reflection->FieldSize(options, fields[i]);
temporal40ee5512008-07-10 02:12:20 +00001878 repeated = true;
1879 }
1880 for (int j = 0; j < count; j++) {
1881 string fieldval;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001882 if (fields[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
1883 string tmp;
1884 TextFormat::Printer printer;
1885 printer.SetInitialIndentLevel(depth + 1);
1886 printer.PrintFieldValueToString(options, fields[i],
1887 repeated ? j : -1, &tmp);
1888 fieldval.append("{\n");
1889 fieldval.append(tmp);
1890 fieldval.append(depth * 2, ' ');
1891 fieldval.append("}");
1892 } else {
1893 TextFormat::PrintFieldValueToString(options, fields[i],
1894 repeated ? j : -1, &fieldval);
1895 }
1896 string name;
1897 if (fields[i]->is_extension()) {
1898 name = "(." + fields[i]->full_name() + ")";
1899 } else {
1900 name = fields[i]->name();
1901 }
1902 option_entries->push_back(name + " = " + fieldval);
temporal40ee5512008-07-10 02:12:20 +00001903 }
1904 }
1905 return !option_entries->empty();
1906}
1907
1908// Formats options that all appear together in brackets. Does not include
1909// brackets.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001910bool FormatBracketedOptions(int depth, const Message &options, string *output) {
temporal40ee5512008-07-10 02:12:20 +00001911 vector<string> all_options;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001912 if (RetrieveOptions(depth, options, &all_options)) {
jieluo@google.com4de8f552014-07-18 00:47:59 +00001913 output->append(Join(all_options, ", "));
temporal40ee5512008-07-10 02:12:20 +00001914 }
1915 return !all_options.empty();
1916}
1917
1918// Formats options one per line
1919bool FormatLineOptions(int depth, const Message &options, string *output) {
1920 string prefix(depth * 2, ' ');
1921 vector<string> all_options;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00001922 if (RetrieveOptions(depth, options, &all_options)) {
temporal40ee5512008-07-10 02:12:20 +00001923 for (int i = 0; i < all_options.size(); i++) {
1924 strings::SubstituteAndAppend(output, "$0option $1;\n",
1925 prefix, all_options[i]);
1926 }
1927 }
1928 return !all_options.empty();
1929}
1930
Feng Xiao6ef984a2014-11-10 17:34:54 -08001931class SourceLocationCommentPrinter {
1932 public:
Jisi Liu885b6122015-02-28 14:51:22 -08001933 template<typename DescType>
Feng Xiao6ef984a2014-11-10 17:34:54 -08001934 SourceLocationCommentPrinter(const DescType* desc,
1935 const string& prefix,
1936 const DebugStringOptions& options)
1937 : options_(options), prefix_(prefix) {
1938 // Perform the SourceLocation lookup only if we're including user comments,
1939 // because the lookup is fairly expensive.
1940 have_source_loc_ = options.include_comments &&
1941 desc->GetSourceLocation(&source_loc_);
1942 }
Jisi Liu885b6122015-02-28 14:51:22 -08001943 SourceLocationCommentPrinter(const FileDescriptor* file,
1944 const vector<int>& path,
1945 const string& prefix,
1946 const DebugStringOptions& options)
1947 : options_(options), prefix_(prefix) {
1948 // Perform the SourceLocation lookup only if we're including user comments,
1949 // because the lookup is fairly expensive.
1950 have_source_loc_ = options.include_comments &&
1951 file->GetSourceLocation(path, &source_loc_);
1952 }
Feng Xiao6ef984a2014-11-10 17:34:54 -08001953 void AddPreComment(string* output) {
Jisi Liu885b6122015-02-28 14:51:22 -08001954 if (have_source_loc_) {
1955 // Detached leading comments.
1956 for (int i = 0 ; i < source_loc_.leading_detached_comments.size(); ++i) {
1957 *output += FormatComment(source_loc_.leading_detached_comments[i]);
1958 *output += "\n";
1959 }
1960 // Attached leading comments.
1961 if (!source_loc_.leading_comments.empty()) {
1962 *output += FormatComment(source_loc_.leading_comments);
1963 }
Feng Xiao6ef984a2014-11-10 17:34:54 -08001964 }
1965 }
1966 void AddPostComment(string* output) {
1967 if (have_source_loc_ && source_loc_.trailing_comments.size() > 0) {
1968 *output += FormatComment(source_loc_.trailing_comments);
1969 }
1970 }
1971
1972 // Format comment such that each line becomes a full-line C++-style comment in
1973 // the DebugString() output.
1974 string FormatComment(const string& comment_text) {
1975 string stripped_comment = comment_text;
1976 StripWhitespace(&stripped_comment);
1977 vector<string> lines = Split(stripped_comment, "\n");
1978 string output;
1979 for (int i = 0; i < lines.size(); ++i) {
1980 const string& line = lines[i];
1981 strings::SubstituteAndAppend(&output, "$0// $1\n", prefix_, line);
1982 }
1983 return output;
1984 }
1985
1986 private:
Feng Xiao6ef984a2014-11-10 17:34:54 -08001987 bool have_source_loc_;
1988 SourceLocation source_loc_;
1989 DebugStringOptions options_;
1990 string prefix_;
1991};
1992
temporal40ee5512008-07-10 02:12:20 +00001993} // anonymous namespace
1994
1995string FileDescriptor::DebugString() const {
Feng Xiao6ef984a2014-11-10 17:34:54 -08001996 DebugStringOptions options; // default options
1997 return DebugStringWithOptions(options);
1998}
1999
2000string FileDescriptor::DebugStringWithOptions(
2001 const DebugStringOptions& debug_string_options) const {
2002 string contents;
Jisi Liu885b6122015-02-28 14:51:22 -08002003 {
2004 vector<int> path;
2005 path.push_back(FileDescriptorProto::kSyntaxFieldNumber);
2006 SourceLocationCommentPrinter syntax_comment(
2007 this, path, "", debug_string_options);
2008 syntax_comment.AddPreComment(&contents);
2009 strings::SubstituteAndAppend(&contents, "syntax = \"$0\";\n\n",
2010 SyntaxName(syntax()));
2011 syntax_comment.AddPostComment(&contents);
2012 }
Feng Xiao6ef984a2014-11-10 17:34:54 -08002013
Jisi Liu885b6122015-02-28 14:51:22 -08002014 SourceLocationCommentPrinter
Feng Xiao6ef984a2014-11-10 17:34:54 -08002015 comment_printer(this, "", debug_string_options);
2016 comment_printer.AddPreComment(&contents);
temporal40ee5512008-07-10 02:12:20 +00002017
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002018 set<int> public_dependencies;
2019 set<int> weak_dependencies;
2020 public_dependencies.insert(public_dependencies_,
2021 public_dependencies_ + public_dependency_count_);
2022 weak_dependencies.insert(weak_dependencies_,
2023 weak_dependencies_ + weak_dependency_count_);
2024
temporal40ee5512008-07-10 02:12:20 +00002025 for (int i = 0; i < dependency_count(); i++) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002026 if (public_dependencies.count(i) > 0) {
2027 strings::SubstituteAndAppend(&contents, "import public \"$0\";\n",
2028 dependency(i)->name());
2029 } else if (weak_dependencies.count(i) > 0) {
2030 strings::SubstituteAndAppend(&contents, "import weak \"$0\";\n",
2031 dependency(i)->name());
2032 } else {
2033 strings::SubstituteAndAppend(&contents, "import \"$0\";\n",
2034 dependency(i)->name());
2035 }
temporal40ee5512008-07-10 02:12:20 +00002036 }
2037
2038 if (!package().empty()) {
Jisi Liu885b6122015-02-28 14:51:22 -08002039 vector<int> path;
2040 path.push_back(FileDescriptorProto::kPackageFieldNumber);
2041 SourceLocationCommentPrinter package_comment(
2042 this, path, "", debug_string_options);
2043 package_comment.AddPreComment(&contents);
temporal40ee5512008-07-10 02:12:20 +00002044 strings::SubstituteAndAppend(&contents, "package $0;\n\n", package());
Jisi Liu885b6122015-02-28 14:51:22 -08002045 package_comment.AddPostComment(&contents);
temporal40ee5512008-07-10 02:12:20 +00002046 }
2047
2048 if (FormatLineOptions(0, options(), &contents)) {
2049 contents.append("\n"); // add some space if we had options
2050 }
2051
2052 for (int i = 0; i < enum_type_count(); i++) {
Feng Xiao6ef984a2014-11-10 17:34:54 -08002053 enum_type(i)->DebugString(0, &contents, debug_string_options);
temporal40ee5512008-07-10 02:12:20 +00002054 contents.append("\n");
2055 }
2056
2057 // Find all the 'group' type extensions; we will not output their nested
2058 // definitions (those will be done with their group field descriptor).
2059 set<const Descriptor*> groups;
2060 for (int i = 0; i < extension_count(); i++) {
2061 if (extension(i)->type() == FieldDescriptor::TYPE_GROUP) {
2062 groups.insert(extension(i)->message_type());
2063 }
2064 }
2065
2066 for (int i = 0; i < message_type_count(); i++) {
2067 if (groups.count(message_type(i)) == 0) {
Feng Xiao6ef984a2014-11-10 17:34:54 -08002068 message_type(i)->DebugString(0, &contents, debug_string_options,
2069 /* include_opening_clause */ true);
temporal40ee5512008-07-10 02:12:20 +00002070 contents.append("\n");
2071 }
2072 }
2073
2074 for (int i = 0; i < service_count(); i++) {
Feng Xiao6ef984a2014-11-10 17:34:54 -08002075 service(i)->DebugString(&contents, debug_string_options);
temporal40ee5512008-07-10 02:12:20 +00002076 contents.append("\n");
2077 }
2078
2079 const Descriptor* containing_type = NULL;
2080 for (int i = 0; i < extension_count(); i++) {
2081 if (extension(i)->containing_type() != containing_type) {
2082 if (i > 0) contents.append("}\n\n");
2083 containing_type = extension(i)->containing_type();
2084 strings::SubstituteAndAppend(&contents, "extend .$0 {\n",
2085 containing_type->full_name());
2086 }
Feng Xiao6ef984a2014-11-10 17:34:54 -08002087 extension(i)->DebugString(1, FieldDescriptor::PRINT_LABEL, &contents,
2088 debug_string_options);
temporal40ee5512008-07-10 02:12:20 +00002089 }
2090 if (extension_count() > 0) contents.append("}\n\n");
2091
Feng Xiao6ef984a2014-11-10 17:34:54 -08002092 comment_printer.AddPostComment(&contents);
2093
temporal40ee5512008-07-10 02:12:20 +00002094 return contents;
2095}
2096
2097string Descriptor::DebugString() const {
Feng Xiao6ef984a2014-11-10 17:34:54 -08002098 DebugStringOptions options; // default options
2099 return DebugStringWithOptions(options);
2100}
2101
2102string Descriptor::DebugStringWithOptions(
2103 const DebugStringOptions& options) const {
temporal40ee5512008-07-10 02:12:20 +00002104 string contents;
Feng Xiao6ef984a2014-11-10 17:34:54 -08002105 DebugString(0, &contents, options, /* include_opening_clause */ true);
temporal40ee5512008-07-10 02:12:20 +00002106 return contents;
2107}
2108
Feng Xiao6ef984a2014-11-10 17:34:54 -08002109void Descriptor::DebugString(int depth, string *contents,
2110 const DebugStringOptions&
2111 debug_string_options,
2112 bool include_opening_clause) const {
2113 if (options().map_entry()) {
2114 // Do not generate debug string for auto-generated map-entry type.
2115 return;
2116 }
temporal40ee5512008-07-10 02:12:20 +00002117 string prefix(depth * 2, ' ');
2118 ++depth;
Feng Xiao6ef984a2014-11-10 17:34:54 -08002119
Jisi Liu885b6122015-02-28 14:51:22 -08002120 SourceLocationCommentPrinter
Feng Xiao6ef984a2014-11-10 17:34:54 -08002121 comment_printer(this, prefix, debug_string_options);
2122 comment_printer.AddPreComment(contents);
2123
2124 if (include_opening_clause) {
2125 strings::SubstituteAndAppend(contents, "$0message $1", prefix, name());
2126 }
temporal40ee5512008-07-10 02:12:20 +00002127 contents->append(" {\n");
2128
2129 FormatLineOptions(depth, options(), contents);
2130
2131 // Find all the 'group' types for fields and extensions; we will not output
2132 // their nested definitions (those will be done with their group field
2133 // descriptor).
2134 set<const Descriptor*> groups;
2135 for (int i = 0; i < field_count(); i++) {
2136 if (field(i)->type() == FieldDescriptor::TYPE_GROUP) {
2137 groups.insert(field(i)->message_type());
2138 }
2139 }
2140 for (int i = 0; i < extension_count(); i++) {
2141 if (extension(i)->type() == FieldDescriptor::TYPE_GROUP) {
2142 groups.insert(extension(i)->message_type());
2143 }
2144 }
2145
2146 for (int i = 0; i < nested_type_count(); i++) {
2147 if (groups.count(nested_type(i)) == 0) {
Feng Xiao6ef984a2014-11-10 17:34:54 -08002148 nested_type(i)->DebugString(depth, contents, debug_string_options,
2149 /* include_opening_clause */ true);
temporal40ee5512008-07-10 02:12:20 +00002150 }
2151 }
2152 for (int i = 0; i < enum_type_count(); i++) {
Feng Xiao6ef984a2014-11-10 17:34:54 -08002153 enum_type(i)->DebugString(depth, contents, debug_string_options);
temporal40ee5512008-07-10 02:12:20 +00002154 }
2155 for (int i = 0; i < field_count(); i++) {
jieluo@google.com4de8f552014-07-18 00:47:59 +00002156 if (field(i)->containing_oneof() == NULL) {
Feng Xiao6ef984a2014-11-10 17:34:54 -08002157 field(i)->DebugString(depth, FieldDescriptor::PRINT_LABEL, contents,
2158 debug_string_options);
jieluo@google.com4de8f552014-07-18 00:47:59 +00002159 } else if (field(i)->containing_oneof()->field(0) == field(i)) {
2160 // This is the first field in this oneof, so print the whole oneof.
Feng Xiao6ef984a2014-11-10 17:34:54 -08002161 field(i)->containing_oneof()->DebugString(depth, contents,
2162 debug_string_options);
jieluo@google.com4de8f552014-07-18 00:47:59 +00002163 }
temporal40ee5512008-07-10 02:12:20 +00002164 }
2165
2166 for (int i = 0; i < extension_range_count(); i++) {
2167 strings::SubstituteAndAppend(contents, "$0 extensions $1 to $2;\n",
2168 prefix,
2169 extension_range(i)->start,
2170 extension_range(i)->end - 1);
2171 }
2172
2173 // Group extensions by what they extend, so they can be printed out together.
2174 const Descriptor* containing_type = NULL;
2175 for (int i = 0; i < extension_count(); i++) {
2176 if (extension(i)->containing_type() != containing_type) {
2177 if (i > 0) strings::SubstituteAndAppend(contents, "$0 }\n", prefix);
2178 containing_type = extension(i)->containing_type();
2179 strings::SubstituteAndAppend(contents, "$0 extend .$1 {\n",
2180 prefix, containing_type->full_name());
2181 }
jieluo@google.com4de8f552014-07-18 00:47:59 +00002182 extension(i)->DebugString(
Feng Xiao6ef984a2014-11-10 17:34:54 -08002183 depth + 1, FieldDescriptor::PRINT_LABEL, contents,
2184 debug_string_options);
temporal40ee5512008-07-10 02:12:20 +00002185 }
2186 if (extension_count() > 0)
2187 strings::SubstituteAndAppend(contents, "$0 }\n", prefix);
2188
2189 strings::SubstituteAndAppend(contents, "$0}\n", prefix);
Feng Xiao6ef984a2014-11-10 17:34:54 -08002190 comment_printer.AddPostComment(contents);
temporal40ee5512008-07-10 02:12:20 +00002191}
2192
2193string FieldDescriptor::DebugString() const {
Feng Xiao6ef984a2014-11-10 17:34:54 -08002194 DebugStringOptions options; // default options
2195 return DebugStringWithOptions(options);
2196}
2197
2198string FieldDescriptor::DebugStringWithOptions(
2199 const DebugStringOptions& debug_string_options) const {
temporal40ee5512008-07-10 02:12:20 +00002200 string contents;
2201 int depth = 0;
2202 if (is_extension()) {
2203 strings::SubstituteAndAppend(&contents, "extend .$0 {\n",
2204 containing_type()->full_name());
2205 depth = 1;
2206 }
Feng Xiao6ef984a2014-11-10 17:34:54 -08002207 DebugString(depth, PRINT_LABEL, &contents, debug_string_options);
temporal40ee5512008-07-10 02:12:20 +00002208 if (is_extension()) {
jieluo@google.com4de8f552014-07-18 00:47:59 +00002209 contents.append("}\n");
temporal40ee5512008-07-10 02:12:20 +00002210 }
2211 return contents;
2212}
2213
Feng Xiao6ef984a2014-11-10 17:34:54 -08002214// The field type string used in FieldDescriptor::DebugString()
2215string FieldDescriptor::FieldTypeNameDebugString() const {
2216 switch(type()) {
2217 case TYPE_MESSAGE:
2218 return "." + message_type()->full_name();
2219 case TYPE_ENUM:
2220 return "." + enum_type()->full_name();
2221 default:
2222 return kTypeToName[type()];
2223 }
2224}
2225
jieluo@google.com4de8f552014-07-18 00:47:59 +00002226void FieldDescriptor::DebugString(int depth,
2227 PrintLabelFlag print_label_flag,
Feng Xiao6ef984a2014-11-10 17:34:54 -08002228 string *contents,
2229 const DebugStringOptions&
2230 debug_string_options) const {
temporal40ee5512008-07-10 02:12:20 +00002231 string prefix(depth * 2, ' ');
2232 string field_type;
Feng Xiao6ef984a2014-11-10 17:34:54 -08002233
2234 // Special case map fields.
Feng Xiaof157a562014-11-14 11:50:31 -08002235 if (is_map()) {
Feng Xiao6ef984a2014-11-10 17:34:54 -08002236 strings::SubstituteAndAppend(
2237 &field_type, "map<$0, $1>",
2238 message_type()->field(0)->FieldTypeNameDebugString(),
2239 message_type()->field(1)->FieldTypeNameDebugString());
2240 } else {
2241 field_type = FieldTypeNameDebugString();
temporal40ee5512008-07-10 02:12:20 +00002242 }
2243
jieluo@google.com4de8f552014-07-18 00:47:59 +00002244 string label;
Feng Xiaof157a562014-11-14 11:50:31 -08002245 if (print_label_flag == PRINT_LABEL && !is_map()) {
jieluo@google.com4de8f552014-07-18 00:47:59 +00002246 label = kLabelToName[this->label()];
2247 label.push_back(' ');
2248 }
2249
Jisi Liu885b6122015-02-28 14:51:22 -08002250 SourceLocationCommentPrinter
Feng Xiao6ef984a2014-11-10 17:34:54 -08002251 comment_printer(this, prefix, debug_string_options);
2252 comment_printer.AddPreComment(contents);
2253
jieluo@google.com4de8f552014-07-18 00:47:59 +00002254 strings::SubstituteAndAppend(contents, "$0$1$2 $3 = $4",
temporal40ee5512008-07-10 02:12:20 +00002255 prefix,
jieluo@google.com4de8f552014-07-18 00:47:59 +00002256 label,
temporal40ee5512008-07-10 02:12:20 +00002257 field_type,
2258 type() == TYPE_GROUP ? message_type()->name() :
2259 name(),
2260 number());
2261
2262 bool bracketed = false;
2263 if (has_default_value()) {
2264 bracketed = true;
2265 strings::SubstituteAndAppend(contents, " [default = $0",
2266 DefaultValueAsString(true));
2267 }
2268
2269 string formatted_options;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002270 if (FormatBracketedOptions(depth, options(), &formatted_options)) {
temporal40ee5512008-07-10 02:12:20 +00002271 contents->append(bracketed ? ", " : " [");
2272 bracketed = true;
2273 contents->append(formatted_options);
2274 }
2275
2276 if (bracketed) {
2277 contents->append("]");
2278 }
2279
2280 if (type() == TYPE_GROUP) {
Feng Xiao6ef984a2014-11-10 17:34:54 -08002281 message_type()->DebugString(depth, contents, debug_string_options,
2282 /* include_opening_clause */ false);
temporal40ee5512008-07-10 02:12:20 +00002283 } else {
2284 contents->append(";\n");
2285 }
Feng Xiao6ef984a2014-11-10 17:34:54 -08002286
2287 comment_printer.AddPostComment(contents);
temporal40ee5512008-07-10 02:12:20 +00002288}
2289
jieluo@google.com4de8f552014-07-18 00:47:59 +00002290string OneofDescriptor::DebugString() const {
Feng Xiao6ef984a2014-11-10 17:34:54 -08002291 DebugStringOptions options; // default values
2292 return DebugStringWithOptions(options);
2293}
2294
2295string OneofDescriptor::DebugStringWithOptions(
2296 const DebugStringOptions& options) const {
jieluo@google.com4de8f552014-07-18 00:47:59 +00002297 string contents;
Feng Xiao6ef984a2014-11-10 17:34:54 -08002298 DebugString(0, &contents, options);
jieluo@google.com4de8f552014-07-18 00:47:59 +00002299 return contents;
2300}
2301
Feng Xiao6ef984a2014-11-10 17:34:54 -08002302void OneofDescriptor::DebugString(int depth, string* contents,
2303 const DebugStringOptions&
2304 debug_string_options) const {
jieluo@google.com4de8f552014-07-18 00:47:59 +00002305 string prefix(depth * 2, ' ');
2306 ++depth;
Jisi Liu885b6122015-02-28 14:51:22 -08002307 SourceLocationCommentPrinter
Feng Xiao6ef984a2014-11-10 17:34:54 -08002308 comment_printer(this, prefix, debug_string_options);
2309 comment_printer.AddPreComment(contents);
jieluo@google.com4de8f552014-07-18 00:47:59 +00002310 strings::SubstituteAndAppend(
2311 contents, "$0 oneof $1 {\n", prefix, name());
2312 for (int i = 0; i < field_count(); i++) {
Feng Xiao6ef984a2014-11-10 17:34:54 -08002313 field(i)->DebugString(depth, FieldDescriptor::OMIT_LABEL, contents,
2314 debug_string_options);
jieluo@google.com4de8f552014-07-18 00:47:59 +00002315 }
2316 strings::SubstituteAndAppend(contents, "$0}\n", prefix);
Feng Xiao6ef984a2014-11-10 17:34:54 -08002317 comment_printer.AddPostComment(contents);
jieluo@google.com4de8f552014-07-18 00:47:59 +00002318}
2319
temporal40ee5512008-07-10 02:12:20 +00002320string EnumDescriptor::DebugString() const {
Feng Xiao6ef984a2014-11-10 17:34:54 -08002321 DebugStringOptions options; // default values
2322 return DebugStringWithOptions(options);
2323}
2324
2325string EnumDescriptor::DebugStringWithOptions(
2326 const DebugStringOptions& options) const {
temporal40ee5512008-07-10 02:12:20 +00002327 string contents;
Feng Xiao6ef984a2014-11-10 17:34:54 -08002328 DebugString(0, &contents, options);
temporal40ee5512008-07-10 02:12:20 +00002329 return contents;
2330}
2331
Feng Xiao6ef984a2014-11-10 17:34:54 -08002332void EnumDescriptor::DebugString(int depth, string *contents,
2333 const DebugStringOptions&
2334 debug_string_options) const {
temporal40ee5512008-07-10 02:12:20 +00002335 string prefix(depth * 2, ' ');
2336 ++depth;
Feng Xiao6ef984a2014-11-10 17:34:54 -08002337
Jisi Liu885b6122015-02-28 14:51:22 -08002338 SourceLocationCommentPrinter
Feng Xiao6ef984a2014-11-10 17:34:54 -08002339 comment_printer(this, prefix, debug_string_options);
2340 comment_printer.AddPreComment(contents);
2341
temporal40ee5512008-07-10 02:12:20 +00002342 strings::SubstituteAndAppend(contents, "$0enum $1 {\n",
2343 prefix, name());
2344
2345 FormatLineOptions(depth, options(), contents);
2346
2347 for (int i = 0; i < value_count(); i++) {
Feng Xiao6ef984a2014-11-10 17:34:54 -08002348 value(i)->DebugString(depth, contents, debug_string_options);
temporal40ee5512008-07-10 02:12:20 +00002349 }
2350 strings::SubstituteAndAppend(contents, "$0}\n", prefix);
Feng Xiao6ef984a2014-11-10 17:34:54 -08002351
2352 comment_printer.AddPostComment(contents);
temporal40ee5512008-07-10 02:12:20 +00002353}
2354
2355string EnumValueDescriptor::DebugString() const {
Feng Xiao6ef984a2014-11-10 17:34:54 -08002356 DebugStringOptions options; // default values
2357 return DebugStringWithOptions(options);
2358}
2359
2360string EnumValueDescriptor::DebugStringWithOptions(
2361 const DebugStringOptions& options) const {
temporal40ee5512008-07-10 02:12:20 +00002362 string contents;
Feng Xiao6ef984a2014-11-10 17:34:54 -08002363 DebugString(0, &contents, options);
temporal40ee5512008-07-10 02:12:20 +00002364 return contents;
2365}
2366
Feng Xiao6ef984a2014-11-10 17:34:54 -08002367void EnumValueDescriptor::DebugString(int depth, string *contents,
2368 const DebugStringOptions&
2369 debug_string_options) const {
temporal40ee5512008-07-10 02:12:20 +00002370 string prefix(depth * 2, ' ');
Feng Xiao6ef984a2014-11-10 17:34:54 -08002371
Jisi Liu885b6122015-02-28 14:51:22 -08002372 SourceLocationCommentPrinter
Feng Xiao6ef984a2014-11-10 17:34:54 -08002373 comment_printer(this, prefix, debug_string_options);
2374 comment_printer.AddPreComment(contents);
2375
temporal40ee5512008-07-10 02:12:20 +00002376 strings::SubstituteAndAppend(contents, "$0$1 = $2",
2377 prefix, name(), number());
2378
2379 string formatted_options;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002380 if (FormatBracketedOptions(depth, options(), &formatted_options)) {
temporal40ee5512008-07-10 02:12:20 +00002381 strings::SubstituteAndAppend(contents, " [$0]", formatted_options);
2382 }
2383 contents->append(";\n");
Feng Xiao6ef984a2014-11-10 17:34:54 -08002384
2385 comment_printer.AddPostComment(contents);
temporal40ee5512008-07-10 02:12:20 +00002386}
2387
2388string ServiceDescriptor::DebugString() const {
Feng Xiao6ef984a2014-11-10 17:34:54 -08002389 DebugStringOptions options; // default values
2390 return DebugStringWithOptions(options);
2391}
2392
2393string ServiceDescriptor::DebugStringWithOptions(
2394 const DebugStringOptions& options) const {
temporal40ee5512008-07-10 02:12:20 +00002395 string contents;
Feng Xiao6ef984a2014-11-10 17:34:54 -08002396 DebugString(&contents, options);
temporal40ee5512008-07-10 02:12:20 +00002397 return contents;
2398}
2399
Feng Xiao6ef984a2014-11-10 17:34:54 -08002400void ServiceDescriptor::DebugString(string *contents,
2401 const DebugStringOptions&
2402 debug_string_options) const {
Jisi Liu885b6122015-02-28 14:51:22 -08002403 SourceLocationCommentPrinter
Feng Xiao6ef984a2014-11-10 17:34:54 -08002404 comment_printer(this, /* prefix */ "", debug_string_options);
2405 comment_printer.AddPreComment(contents);
2406
temporal40ee5512008-07-10 02:12:20 +00002407 strings::SubstituteAndAppend(contents, "service $0 {\n", name());
2408
2409 FormatLineOptions(1, options(), contents);
2410
2411 for (int i = 0; i < method_count(); i++) {
Feng Xiao6ef984a2014-11-10 17:34:54 -08002412 method(i)->DebugString(1, contents, debug_string_options);
temporal40ee5512008-07-10 02:12:20 +00002413 }
2414
2415 contents->append("}\n");
Feng Xiao6ef984a2014-11-10 17:34:54 -08002416
2417 comment_printer.AddPostComment(contents);
temporal40ee5512008-07-10 02:12:20 +00002418}
2419
2420string MethodDescriptor::DebugString() const {
Feng Xiao6ef984a2014-11-10 17:34:54 -08002421 DebugStringOptions options; // default values
2422 return DebugStringWithOptions(options);
2423}
2424
2425string MethodDescriptor::DebugStringWithOptions(
2426 const DebugStringOptions& options) const {
temporal40ee5512008-07-10 02:12:20 +00002427 string contents;
Feng Xiao6ef984a2014-11-10 17:34:54 -08002428 DebugString(0, &contents, options);
temporal40ee5512008-07-10 02:12:20 +00002429 return contents;
2430}
2431
Feng Xiao6ef984a2014-11-10 17:34:54 -08002432void MethodDescriptor::DebugString(int depth, string *contents,
2433 const DebugStringOptions&
2434 debug_string_options) const {
temporal40ee5512008-07-10 02:12:20 +00002435 string prefix(depth * 2, ' ');
2436 ++depth;
Feng Xiao6ef984a2014-11-10 17:34:54 -08002437
Jisi Liu885b6122015-02-28 14:51:22 -08002438 SourceLocationCommentPrinter
Feng Xiao6ef984a2014-11-10 17:34:54 -08002439 comment_printer(this, prefix, debug_string_options);
2440 comment_printer.AddPreComment(contents);
2441
Feng Xiao99aa0f92014-11-20 16:18:53 -08002442 strings::SubstituteAndAppend(contents, "$0rpc $1($4.$2) returns ($5.$3)",
temporal40ee5512008-07-10 02:12:20 +00002443 prefix, name(),
2444 input_type()->full_name(),
Feng Xiao99aa0f92014-11-20 16:18:53 -08002445 output_type()->full_name(),
2446 client_streaming() ? "stream " : "",
2447 server_streaming() ? "stream " : "");
temporal40ee5512008-07-10 02:12:20 +00002448
2449 string formatted_options;
2450 if (FormatLineOptions(depth, options(), &formatted_options)) {
2451 strings::SubstituteAndAppend(contents, " {\n$0$1}\n",
2452 formatted_options, prefix);
2453 } else {
2454 contents->append(";\n");
2455 }
Feng Xiao6ef984a2014-11-10 17:34:54 -08002456
2457 comment_printer.AddPostComment(contents);
temporal40ee5512008-07-10 02:12:20 +00002458}
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002459
2460
2461// Location methods ===============================================
2462
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002463bool FileDescriptor::GetSourceLocation(const vector<int>& path,
2464 SourceLocation* out_location) const {
2465 GOOGLE_CHECK_NOTNULL(out_location);
jieluo@google.com4de8f552014-07-18 00:47:59 +00002466 if (source_code_info_) {
2467 if (const SourceCodeInfo_Location* loc =
2468 tables_->GetSourceLocation(path, source_code_info_)) {
2469 const RepeatedField<int32>& span = loc->span();
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002470 if (span.size() == 3 || span.size() == 4) {
2471 out_location->start_line = span.Get(0);
2472 out_location->start_column = span.Get(1);
2473 out_location->end_line = span.Get(span.size() == 3 ? 0 : 2);
2474 out_location->end_column = span.Get(span.size() - 1);
2475
jieluo@google.com4de8f552014-07-18 00:47:59 +00002476 out_location->leading_comments = loc->leading_comments();
2477 out_location->trailing_comments = loc->trailing_comments();
Jisi Liu885b6122015-02-28 14:51:22 -08002478 out_location->leading_detached_comments.assign(
2479 loc->leading_detached_comments().begin(),
2480 loc->leading_detached_comments().end());
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002481 return true;
2482 }
2483 }
2484 }
2485 return false;
2486}
2487
Feng Xiao6ef984a2014-11-10 17:34:54 -08002488bool FileDescriptor::GetSourceLocation(SourceLocation* out_location) const {
2489 vector<int> path; // empty path for root FileDescriptor
2490 return GetSourceLocation(path, out_location);
2491}
2492
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002493bool FieldDescriptor::is_packed() const {
2494 return is_packable() && (options_ != NULL) && options_->packed();
2495}
2496
2497bool Descriptor::GetSourceLocation(SourceLocation* out_location) const {
2498 vector<int> path;
2499 GetLocationPath(&path);
2500 return file()->GetSourceLocation(path, out_location);
2501}
2502
2503bool FieldDescriptor::GetSourceLocation(SourceLocation* out_location) const {
2504 vector<int> path;
2505 GetLocationPath(&path);
2506 return file()->GetSourceLocation(path, out_location);
2507}
2508
jieluo@google.com4de8f552014-07-18 00:47:59 +00002509bool OneofDescriptor::GetSourceLocation(SourceLocation* out_location) const {
2510 vector<int> path;
2511 GetLocationPath(&path);
2512 return containing_type()->file()->GetSourceLocation(path, out_location);
2513}
2514
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002515bool EnumDescriptor::GetSourceLocation(SourceLocation* out_location) const {
2516 vector<int> path;
2517 GetLocationPath(&path);
2518 return file()->GetSourceLocation(path, out_location);
2519}
2520
2521bool MethodDescriptor::GetSourceLocation(SourceLocation* out_location) const {
2522 vector<int> path;
2523 GetLocationPath(&path);
2524 return service()->file()->GetSourceLocation(path, out_location);
2525}
2526
2527bool ServiceDescriptor::GetSourceLocation(SourceLocation* out_location) const {
2528 vector<int> path;
2529 GetLocationPath(&path);
2530 return file()->GetSourceLocation(path, out_location);
2531}
2532
2533bool EnumValueDescriptor::GetSourceLocation(
2534 SourceLocation* out_location) const {
2535 vector<int> path;
2536 GetLocationPath(&path);
2537 return type()->file()->GetSourceLocation(path, out_location);
2538}
2539
2540void Descriptor::GetLocationPath(vector<int>* output) const {
2541 if (containing_type()) {
2542 containing_type()->GetLocationPath(output);
2543 output->push_back(DescriptorProto::kNestedTypeFieldNumber);
2544 output->push_back(index());
2545 } else {
2546 output->push_back(FileDescriptorProto::kMessageTypeFieldNumber);
2547 output->push_back(index());
2548 }
2549}
2550
2551void FieldDescriptor::GetLocationPath(vector<int>* output) const {
jieluo@google.com4de8f552014-07-18 00:47:59 +00002552 if (is_extension()) {
2553 if (extension_scope() == NULL) {
2554 output->push_back(FileDescriptorProto::kExtensionFieldNumber);
2555 output->push_back(index());
2556 } else {
2557 extension_scope()->GetLocationPath(output);
2558 output->push_back(DescriptorProto::kExtensionFieldNumber);
2559 output->push_back(index());
2560 }
2561 } else {
2562 containing_type()->GetLocationPath(output);
2563 output->push_back(DescriptorProto::kFieldFieldNumber);
2564 output->push_back(index());
2565 }
2566}
2567
2568void OneofDescriptor::GetLocationPath(vector<int>* output) const {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002569 containing_type()->GetLocationPath(output);
jieluo@google.com4de8f552014-07-18 00:47:59 +00002570 output->push_back(DescriptorProto::kOneofDeclFieldNumber);
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002571 output->push_back(index());
2572}
2573
2574void EnumDescriptor::GetLocationPath(vector<int>* output) const {
2575 if (containing_type()) {
2576 containing_type()->GetLocationPath(output);
2577 output->push_back(DescriptorProto::kEnumTypeFieldNumber);
2578 output->push_back(index());
2579 } else {
2580 output->push_back(FileDescriptorProto::kEnumTypeFieldNumber);
2581 output->push_back(index());
2582 }
2583}
2584
2585void EnumValueDescriptor::GetLocationPath(vector<int>* output) const {
2586 type()->GetLocationPath(output);
2587 output->push_back(EnumDescriptorProto::kValueFieldNumber);
2588 output->push_back(index());
2589}
2590
2591void ServiceDescriptor::GetLocationPath(vector<int>* output) const {
2592 output->push_back(FileDescriptorProto::kServiceFieldNumber);
2593 output->push_back(index());
2594}
2595
2596void MethodDescriptor::GetLocationPath(vector<int>* output) const {
2597 service()->GetLocationPath(output);
2598 output->push_back(ServiceDescriptorProto::kMethodFieldNumber);
2599 output->push_back(index());
2600}
2601
temporal40ee5512008-07-10 02:12:20 +00002602// ===================================================================
2603
kenton@google.com24bf56f2008-09-24 20:31:01 +00002604namespace {
2605
2606// Represents an options message to interpret. Extension names in the option
2607// name are respolved relative to name_scope. element_name and orig_opt are
2608// used only for error reporting (since the parser records locations against
2609// pointers in the original options, not the mutable copy). The Message must be
2610// one of the Options messages in descriptor.proto.
2611struct OptionsToInterpret {
2612 OptionsToInterpret(const string& ns,
2613 const string& el,
2614 const Message* orig_opt,
2615 Message* opt)
2616 : name_scope(ns),
2617 element_name(el),
2618 original_options(orig_opt),
2619 options(opt) {
2620 }
2621 string name_scope;
2622 string element_name;
2623 const Message* original_options;
2624 Message* options;
2625};
2626
2627} // namespace
2628
temporal40ee5512008-07-10 02:12:20 +00002629class DescriptorBuilder {
2630 public:
2631 DescriptorBuilder(const DescriptorPool* pool,
2632 DescriptorPool::Tables* tables,
2633 DescriptorPool::ErrorCollector* error_collector);
2634 ~DescriptorBuilder();
2635
kenton@google.comd37d46d2009-04-25 02:53:47 +00002636 const FileDescriptor* BuildFile(const FileDescriptorProto& proto);
temporal40ee5512008-07-10 02:12:20 +00002637
2638 private:
kenton@google.com24bf56f2008-09-24 20:31:01 +00002639 friend class OptionInterpreter;
2640
temporal40ee5512008-07-10 02:12:20 +00002641 const DescriptorPool* pool_;
2642 DescriptorPool::Tables* tables_; // for convenience
2643 DescriptorPool::ErrorCollector* error_collector_;
kenton@google.com24bf56f2008-09-24 20:31:01 +00002644
2645 // As we build descriptors we store copies of the options messages in
2646 // them. We put pointers to those copies in this vector, as we build, so we
2647 // can later (after cross-linking) interpret those options.
2648 vector<OptionsToInterpret> options_to_interpret_;
2649
temporal40ee5512008-07-10 02:12:20 +00002650 bool had_errors_;
2651 string filename_;
2652 FileDescriptor* file_;
kenton@google.comd37d46d2009-04-25 02:53:47 +00002653 FileDescriptorTables* file_tables_;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002654 set<const FileDescriptor*> dependencies_;
temporal40ee5512008-07-10 02:12:20 +00002655
jieluo@google.com4de8f552014-07-18 00:47:59 +00002656 // unused_dependency_ is used to record the unused imported files.
2657 // Note: public import is not considered.
2658 set<const FileDescriptor*> unused_dependency_;
2659
temporal40ee5512008-07-10 02:12:20 +00002660 // If LookupSymbol() finds a symbol that is in a file which is not a declared
2661 // dependency of this file, it will fail, but will set
2662 // possible_undeclared_dependency_ to point at that file. This is only used
2663 // by AddNotDefinedError() to report a more useful error message.
kenton@google.com80b1d622009-07-29 01:13:20 +00002664 // possible_undeclared_dependency_name_ is the name of the symbol that was
2665 // actually found in possible_undeclared_dependency_, which may be a parent
2666 // of the symbol actually looked for.
temporal40ee5512008-07-10 02:12:20 +00002667 const FileDescriptor* possible_undeclared_dependency_;
kenton@google.com80b1d622009-07-29 01:13:20 +00002668 string possible_undeclared_dependency_name_;
temporal40ee5512008-07-10 02:12:20 +00002669
jieluo@google.com4de8f552014-07-18 00:47:59 +00002670 // If LookupSymbol() could resolve a symbol which is not defined,
2671 // record the resolved name. This is only used by AddNotDefinedError()
2672 // to report a more useful error message.
2673 string undefine_resolved_name_;
2674
temporal40ee5512008-07-10 02:12:20 +00002675 void AddError(const string& element_name,
2676 const Message& descriptor,
2677 DescriptorPool::ErrorCollector::ErrorLocation location,
2678 const string& error);
jieluo@google.com4de8f552014-07-18 00:47:59 +00002679 void AddError(const string& element_name,
2680 const Message& descriptor,
2681 DescriptorPool::ErrorCollector::ErrorLocation location,
2682 const char* error);
2683 void AddRecursiveImportError(const FileDescriptorProto& proto, int from_here);
2684 void AddTwiceListedError(const FileDescriptorProto& proto, int index);
2685 void AddImportError(const FileDescriptorProto& proto, int index);
temporal40ee5512008-07-10 02:12:20 +00002686
2687 // Adds an error indicating that undefined_symbol was not defined. Must
2688 // only be called after LookupSymbol() fails.
2689 void AddNotDefinedError(
2690 const string& element_name,
2691 const Message& descriptor,
2692 DescriptorPool::ErrorCollector::ErrorLocation location,
2693 const string& undefined_symbol);
2694
jieluo@google.com4de8f552014-07-18 00:47:59 +00002695 void AddWarning(const string& element_name, const Message& descriptor,
2696 DescriptorPool::ErrorCollector::ErrorLocation location,
2697 const string& error);
2698
temporal40ee5512008-07-10 02:12:20 +00002699 // Silly helper which determines if the given file is in the given package.
2700 // I.e., either file->package() == package_name or file->package() is a
2701 // nested package within package_name.
2702 bool IsInPackage(const FileDescriptor* file, const string& package_name);
2703
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002704 // Helper function which finds all public dependencies of the given file, and
2705 // stores the them in the dependencies_ set in the builder.
2706 void RecordPublicDependencies(const FileDescriptor* file);
2707
temporal40ee5512008-07-10 02:12:20 +00002708 // Like tables_->FindSymbol(), but additionally:
2709 // - Search the pool's underlay if not found in tables_.
2710 // - Insure that the resulting Symbol is from one of the file's declared
2711 // dependencies.
2712 Symbol FindSymbol(const string& name);
2713
kenton@google.com26bd9ee2008-11-21 00:06:27 +00002714 // Like FindSymbol() but does not require that the symbol is in one of the
2715 // file's declared dependencies.
2716 Symbol FindSymbolNotEnforcingDeps(const string& name);
2717
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00002718 // This implements the body of FindSymbolNotEnforcingDeps().
2719 Symbol FindSymbolNotEnforcingDepsHelper(const DescriptorPool* pool,
2720 const string& name);
2721
temporal40ee5512008-07-10 02:12:20 +00002722 // Like FindSymbol(), but looks up the name relative to some other symbol
kenton@google.com24bf56f2008-09-24 20:31:01 +00002723 // name. This first searches siblings of relative_to, then siblings of its
temporal40ee5512008-07-10 02:12:20 +00002724 // parents, etc. For example, LookupSymbol("foo.bar", "baz.qux.corge") makes
2725 // the following calls, returning the first non-null result:
2726 // FindSymbol("baz.qux.foo.bar"), FindSymbol("baz.foo.bar"),
kenton@google.comd37d46d2009-04-25 02:53:47 +00002727 // FindSymbol("foo.bar"). If AllowUnknownDependencies() has been called
2728 // on the DescriptorPool, this will generate a placeholder type if
2729 // the name is not found (unless the name itself is malformed). The
2730 // placeholder_type parameter indicates what kind of placeholder should be
2731 // constructed in this case. The resolve_mode parameter determines whether
2732 // any symbol is returned, or only symbols that are types. Note, however,
2733 // that LookupSymbol may still return a non-type symbol in LOOKUP_TYPES mode,
2734 // if it believes that's all it could refer to. The caller should always
2735 // check that it receives the type of symbol it was expecting.
2736 enum PlaceholderType {
2737 PLACEHOLDER_MESSAGE,
2738 PLACEHOLDER_ENUM,
2739 PLACEHOLDER_EXTENDABLE_MESSAGE
2740 };
2741 enum ResolveMode {
2742 LOOKUP_ALL, LOOKUP_TYPES
2743 };
2744 Symbol LookupSymbol(const string& name, const string& relative_to,
2745 PlaceholderType placeholder_type = PLACEHOLDER_MESSAGE,
2746 ResolveMode resolve_mode = LOOKUP_ALL);
2747
2748 // Like LookupSymbol() but will not return a placeholder even if
2749 // AllowUnknownDependencies() has been used.
2750 Symbol LookupSymbolNoPlaceholder(const string& name,
2751 const string& relative_to,
2752 ResolveMode resolve_mode = LOOKUP_ALL);
2753
2754 // Creates a placeholder type suitable for return from LookupSymbol(). May
2755 // return kNullSymbol if the name is not a valid type name.
2756 Symbol NewPlaceholder(const string& name, PlaceholderType placeholder_type);
2757
2758 // Creates a placeholder file. Never returns NULL. This is used when an
2759 // import is not found and AllowUnknownDependencies() is enabled.
Feng Xiao6ef984a2014-11-10 17:34:54 -08002760 FileDescriptor* NewPlaceholderFile(const string& name);
temporal40ee5512008-07-10 02:12:20 +00002761
temporalf2063512008-07-23 01:19:07 +00002762 // Calls tables_->AddSymbol() and records an error if it fails. Returns
2763 // true if successful or false if failed, though most callers can ignore
2764 // the return value since an error has already been recorded.
2765 bool AddSymbol(const string& full_name,
temporal40ee5512008-07-10 02:12:20 +00002766 const void* parent, const string& name,
2767 const Message& proto, Symbol symbol);
2768
2769 // Like AddSymbol(), but succeeds if the symbol is already defined as long
2770 // as the existing definition is also a package (because it's OK to define
2771 // the same package in two different files). Also adds all parents of the
2772 // packgae to the symbol table (e.g. AddPackage("foo.bar", ...) will add
2773 // "foo.bar" and "foo" to the table).
2774 void AddPackage(const string& name, const Message& proto,
2775 const FileDescriptor* file);
2776
2777 // Checks that the symbol name contains only alphanumeric characters and
2778 // underscores. Records an error otherwise.
2779 void ValidateSymbolName(const string& name, const string& full_name,
2780 const Message& proto);
2781
kenton@google.comd37d46d2009-04-25 02:53:47 +00002782 // Like ValidateSymbolName(), but the name is allowed to contain periods and
2783 // an error is indicated by returning false (not recording the error).
2784 bool ValidateQualifiedName(const string& name);
2785
temporal40ee5512008-07-10 02:12:20 +00002786 // Used by BUILD_ARRAY macro (below) to avoid having to have the type
2787 // specified as a macro parameter.
2788 template <typename Type>
2789 inline void AllocateArray(int size, Type** output) {
2790 *output = tables_->AllocateArray<Type>(size);
2791 }
2792
kenton@google.com24bf56f2008-09-24 20:31:01 +00002793 // Allocates a copy of orig_options in tables_ and stores it in the
2794 // descriptor. Remembers its uninterpreted options, to be interpreted
2795 // later. DescriptorT must be one of the Descriptor messages from
2796 // descriptor.proto.
2797 template<class DescriptorT> void AllocateOptions(
2798 const typename DescriptorT::OptionsType& orig_options,
2799 DescriptorT* descriptor);
kenton@google.comde754372008-11-06 21:36:28 +00002800 // Specialization for FileOptions.
2801 void AllocateOptions(const FileOptions& orig_options,
2802 FileDescriptor* descriptor);
kenton@google.com24bf56f2008-09-24 20:31:01 +00002803
2804 // Implementation for AllocateOptions(). Don't call this directly.
2805 template<class DescriptorT> void AllocateOptionsImpl(
2806 const string& name_scope,
2807 const string& element_name,
2808 const typename DescriptorT::OptionsType& orig_options,
2809 DescriptorT* descriptor);
2810
temporal40ee5512008-07-10 02:12:20 +00002811 // These methods all have the same signature for the sake of the BUILD_ARRAY
2812 // macro, below.
2813 void BuildMessage(const DescriptorProto& proto,
2814 const Descriptor* parent,
2815 Descriptor* result);
2816 void BuildFieldOrExtension(const FieldDescriptorProto& proto,
2817 const Descriptor* parent,
2818 FieldDescriptor* result,
2819 bool is_extension);
2820 void BuildField(const FieldDescriptorProto& proto,
2821 const Descriptor* parent,
2822 FieldDescriptor* result) {
2823 BuildFieldOrExtension(proto, parent, result, false);
2824 }
2825 void BuildExtension(const FieldDescriptorProto& proto,
2826 const Descriptor* parent,
2827 FieldDescriptor* result) {
2828 BuildFieldOrExtension(proto, parent, result, true);
2829 }
2830 void BuildExtensionRange(const DescriptorProto::ExtensionRange& proto,
2831 const Descriptor* parent,
2832 Descriptor::ExtensionRange* result);
jieluo@google.com4de8f552014-07-18 00:47:59 +00002833 void BuildOneof(const OneofDescriptorProto& proto,
2834 Descriptor* parent,
2835 OneofDescriptor* result);
temporal40ee5512008-07-10 02:12:20 +00002836 void BuildEnum(const EnumDescriptorProto& proto,
2837 const Descriptor* parent,
2838 EnumDescriptor* result);
2839 void BuildEnumValue(const EnumValueDescriptorProto& proto,
2840 const EnumDescriptor* parent,
2841 EnumValueDescriptor* result);
2842 void BuildService(const ServiceDescriptorProto& proto,
2843 const void* dummy,
2844 ServiceDescriptor* result);
2845 void BuildMethod(const MethodDescriptorProto& proto,
2846 const ServiceDescriptor* parent,
2847 MethodDescriptor* result);
2848
jieluo@google.com4de8f552014-07-18 00:47:59 +00002849 void LogUnusedDependency(const FileDescriptor* result);
2850
kenton@google.com24bf56f2008-09-24 20:31:01 +00002851 // Must be run only after building.
2852 //
2853 // NOTE: Options will not be available during cross-linking, as they
2854 // have not yet been interpreted. Defer any handling of options to the
2855 // Validate*Options methods.
temporal40ee5512008-07-10 02:12:20 +00002856 void CrossLinkFile(FileDescriptor* file, const FileDescriptorProto& proto);
2857 void CrossLinkMessage(Descriptor* message, const DescriptorProto& proto);
2858 void CrossLinkField(FieldDescriptor* field,
2859 const FieldDescriptorProto& proto);
kenton@google.com24bf56f2008-09-24 20:31:01 +00002860 void CrossLinkEnum(EnumDescriptor* enum_type,
2861 const EnumDescriptorProto& proto);
2862 void CrossLinkEnumValue(EnumValueDescriptor* enum_value,
2863 const EnumValueDescriptorProto& proto);
temporal40ee5512008-07-10 02:12:20 +00002864 void CrossLinkService(ServiceDescriptor* service,
2865 const ServiceDescriptorProto& proto);
2866 void CrossLinkMethod(MethodDescriptor* method,
2867 const MethodDescriptorProto& proto);
kenton@google.com24bf56f2008-09-24 20:31:01 +00002868
2869 // Must be run only after cross-linking.
2870 void InterpretOptions();
2871
2872 // A helper class for interpreting options.
2873 class OptionInterpreter {
2874 public:
2875 // Creates an interpreter that operates in the context of the pool of the
2876 // specified builder, which must not be NULL. We don't take ownership of the
2877 // builder.
2878 explicit OptionInterpreter(DescriptorBuilder* builder);
2879
2880 ~OptionInterpreter();
2881
2882 // Interprets the uninterpreted options in the specified Options message.
2883 // On error, calls AddError() on the underlying builder and returns false.
2884 // Otherwise returns true.
2885 bool InterpretOptions(OptionsToInterpret* options_to_interpret);
2886
liujisi@google.com33165fe2010-11-02 13:14:58 +00002887 class AggregateOptionFinder;
2888
kenton@google.com24bf56f2008-09-24 20:31:01 +00002889 private:
2890 // Interprets uninterpreted_option_ on the specified message, which
2891 // must be the mutable copy of the original options message to which
2892 // uninterpreted_option_ belongs.
2893 bool InterpretSingleOption(Message* options);
2894
kenton@google.comd37d46d2009-04-25 02:53:47 +00002895 // Adds the uninterpreted_option to the given options message verbatim.
2896 // Used when AllowUnknownDependencies() is in effect and we can't find
2897 // the option's definition.
2898 void AddWithoutInterpreting(const UninterpretedOption& uninterpreted_option,
2899 Message* options);
2900
kenton@google.com24bf56f2008-09-24 20:31:01 +00002901 // A recursive helper function that drills into the intermediate fields
kenton@google.com80b1d622009-07-29 01:13:20 +00002902 // in unknown_fields to check if field innermost_field is set on the
kenton@google.com24bf56f2008-09-24 20:31:01 +00002903 // innermost message. Returns false and sets an error if so.
2904 bool ExamineIfOptionIsSet(
2905 vector<const FieldDescriptor*>::const_iterator intermediate_fields_iter,
2906 vector<const FieldDescriptor*>::const_iterator intermediate_fields_end,
2907 const FieldDescriptor* innermost_field, const string& debug_msg_name,
2908 const UnknownFieldSet& unknown_fields);
2909
2910 // Validates the value for the option field of the currently interpreted
2911 // option and then sets it on the unknown_field.
2912 bool SetOptionValue(const FieldDescriptor* option_field,
kenton@google.comd37d46d2009-04-25 02:53:47 +00002913 UnknownFieldSet* unknown_fields);
kenton@google.com24bf56f2008-09-24 20:31:01 +00002914
liujisi@google.com33165fe2010-11-02 13:14:58 +00002915 // Parses an aggregate value for a CPPTYPE_MESSAGE option and
2916 // saves it into *unknown_fields.
2917 bool SetAggregateOption(const FieldDescriptor* option_field,
2918 UnknownFieldSet* unknown_fields);
2919
kenton@google.com24bf56f2008-09-24 20:31:01 +00002920 // Convenience functions to set an int field the right way, depending on
2921 // its wire type (a single int CppType can represent multiple wire types).
kenton@google.comd37d46d2009-04-25 02:53:47 +00002922 void SetInt32(int number, int32 value, FieldDescriptor::Type type,
2923 UnknownFieldSet* unknown_fields);
2924 void SetInt64(int number, int64 value, FieldDescriptor::Type type,
2925 UnknownFieldSet* unknown_fields);
2926 void SetUInt32(int number, uint32 value, FieldDescriptor::Type type,
2927 UnknownFieldSet* unknown_fields);
2928 void SetUInt64(int number, uint64 value, FieldDescriptor::Type type,
2929 UnknownFieldSet* unknown_fields);
kenton@google.com24bf56f2008-09-24 20:31:01 +00002930
2931 // A helper function that adds an error at the specified location of the
2932 // option we're currently interpreting, and returns false.
2933 bool AddOptionError(DescriptorPool::ErrorCollector::ErrorLocation location,
2934 const string& msg) {
2935 builder_->AddError(options_to_interpret_->element_name,
2936 *uninterpreted_option_, location, msg);
2937 return false;
2938 }
2939
2940 // A helper function that adds an error at the location of the option name
2941 // and returns false.
2942 bool AddNameError(const string& msg) {
2943 return AddOptionError(DescriptorPool::ErrorCollector::OPTION_NAME, msg);
2944 }
2945
2946 // A helper function that adds an error at the location of the option name
2947 // and returns false.
2948 bool AddValueError(const string& msg) {
2949 return AddOptionError(DescriptorPool::ErrorCollector::OPTION_VALUE, msg);
2950 }
2951
2952 // We interpret against this builder's pool. Is never NULL. We don't own
2953 // this pointer.
2954 DescriptorBuilder* builder_;
2955
2956 // The options we're currently interpreting, or NULL if we're not in a call
2957 // to InterpretOptions.
2958 const OptionsToInterpret* options_to_interpret_;
2959
2960 // The option we're currently interpreting within options_to_interpret_, or
2961 // NULL if we're not in a call to InterpretOptions(). This points to a
2962 // submessage of the original option, not the mutable copy. Therefore we
2963 // can use it to find locations recorded by the parser.
2964 const UninterpretedOption* uninterpreted_option_;
2965
liujisi@google.com33165fe2010-11-02 13:14:58 +00002966 // Factory used to create the dynamic messages we need to parse
2967 // any aggregate option values we encounter.
2968 DynamicMessageFactory dynamic_factory_;
2969
kenton@google.com24bf56f2008-09-24 20:31:01 +00002970 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OptionInterpreter);
2971 };
2972
kenton@google.comd37d46d2009-04-25 02:53:47 +00002973 // Work-around for broken compilers: According to the C++ standard,
2974 // OptionInterpreter should have access to the private members of any class
2975 // which has declared DescriptorBuilder as a friend. Unfortunately some old
2976 // versions of GCC and other compilers do not implement this correctly. So,
2977 // we have to have these intermediate methods to provide access. We also
2978 // redundantly declare OptionInterpreter a friend just to make things extra
2979 // clear for these bad compilers.
2980 friend class OptionInterpreter;
liujisi@google.com33165fe2010-11-02 13:14:58 +00002981 friend class OptionInterpreter::AggregateOptionFinder;
2982
kenton@google.comd37d46d2009-04-25 02:53:47 +00002983 static inline bool get_allow_unknown(const DescriptorPool* pool) {
2984 return pool->allow_unknown_;
2985 }
jieluo@google.com4de8f552014-07-18 00:47:59 +00002986 static inline bool get_enforce_weak(const DescriptorPool* pool) {
2987 return pool->enforce_weak_;
2988 }
kenton@google.comd37d46d2009-04-25 02:53:47 +00002989 static inline bool get_is_placeholder(const Descriptor* descriptor) {
2990 return descriptor->is_placeholder_;
2991 }
liujisi@google.com17d57db2011-02-07 19:03:53 +00002992 static inline void assert_mutex_held(const DescriptorPool* pool) {
2993 if (pool->mutex_ != NULL) {
2994 pool->mutex_->AssertHeld();
2995 }
2996 }
kenton@google.comd37d46d2009-04-25 02:53:47 +00002997
kenton@google.com24bf56f2008-09-24 20:31:01 +00002998 // Must be run only after options have been interpreted.
2999 //
3000 // NOTE: Validation code must only reference the options in the mutable
3001 // descriptors, which are the ones that have been interpreted. The const
3002 // proto references are passed in only so they can be provided to calls to
3003 // AddError(). Do not look at their options, which have not been interpreted.
3004 void ValidateFileOptions(FileDescriptor* file,
3005 const FileDescriptorProto& proto);
3006 void ValidateMessageOptions(Descriptor* message,
3007 const DescriptorProto& proto);
3008 void ValidateFieldOptions(FieldDescriptor* field,
3009 const FieldDescriptorProto& proto);
3010 void ValidateEnumOptions(EnumDescriptor* enm,
3011 const EnumDescriptorProto& proto);
3012 void ValidateEnumValueOptions(EnumValueDescriptor* enum_value,
3013 const EnumValueDescriptorProto& proto);
3014 void ValidateServiceOptions(ServiceDescriptor* service,
3015 const ServiceDescriptorProto& proto);
3016 void ValidateMethodOptions(MethodDescriptor* method,
3017 const MethodDescriptorProto& proto);
Feng Xiao6ef984a2014-11-10 17:34:54 -08003018 void ValidateProto3(FileDescriptor* file,
3019 const FileDescriptorProto& proto);
3020 void ValidateProto3Message(Descriptor* message,
3021 const DescriptorProto& proto);
3022 void ValidateProto3Field(FieldDescriptor* field,
3023 const FieldDescriptorProto& proto);
3024 void ValidateProto3Enum(EnumDescriptor* enm,
3025 const EnumDescriptorProto& proto);
kenton@google.com24bf56f2008-09-24 20:31:01 +00003026
Feng Xiao6ef984a2014-11-10 17:34:54 -08003027 // Returns true if the map entry message is compatible with the
3028 // auto-generated entry message from map fields syntax.
3029 bool ValidateMapEntry(FieldDescriptor* field,
3030 const FieldDescriptorProto& proto);
3031
3032 // Recursively detects naming conflicts with map entry types for a
3033 // better error message.
3034 void DetectMapConflicts(const Descriptor* message,
3035 const DescriptorProto& proto);
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00003036
temporal40ee5512008-07-10 02:12:20 +00003037};
3038
3039const FileDescriptor* DescriptorPool::BuildFile(
3040 const FileDescriptorProto& proto) {
3041 GOOGLE_CHECK(fallback_database_ == NULL)
3042 << "Cannot call BuildFile on a DescriptorPool that uses a "
3043 "DescriptorDatabase. You must instead find a way to get your file "
3044 "into the underlying database.";
3045 GOOGLE_CHECK(mutex_ == NULL); // Implied by the above GOOGLE_CHECK.
jieluo@google.com4de8f552014-07-18 00:47:59 +00003046 tables_->known_bad_symbols_.clear();
3047 tables_->known_bad_files_.clear();
kenton@google.comd37d46d2009-04-25 02:53:47 +00003048 return DescriptorBuilder(this, tables_.get(), NULL).BuildFile(proto);
temporal40ee5512008-07-10 02:12:20 +00003049}
3050
3051const FileDescriptor* DescriptorPool::BuildFileCollectingErrors(
3052 const FileDescriptorProto& proto,
3053 ErrorCollector* error_collector) {
3054 GOOGLE_CHECK(fallback_database_ == NULL)
3055 << "Cannot call BuildFile on a DescriptorPool that uses a "
3056 "DescriptorDatabase. You must instead find a way to get your file "
3057 "into the underlying database.";
3058 GOOGLE_CHECK(mutex_ == NULL); // Implied by the above GOOGLE_CHECK.
jieluo@google.com4de8f552014-07-18 00:47:59 +00003059 tables_->known_bad_symbols_.clear();
3060 tables_->known_bad_files_.clear();
temporal40ee5512008-07-10 02:12:20 +00003061 return DescriptorBuilder(this, tables_.get(),
kenton@google.comd37d46d2009-04-25 02:53:47 +00003062 error_collector).BuildFile(proto);
temporal40ee5512008-07-10 02:12:20 +00003063}
3064
3065const FileDescriptor* DescriptorPool::BuildFileFromDatabase(
3066 const FileDescriptorProto& proto) const {
3067 mutex_->AssertHeld();
jieluo@google.com4de8f552014-07-18 00:47:59 +00003068 if (tables_->known_bad_files_.count(proto.name()) > 0) {
3069 return NULL;
3070 }
3071 const FileDescriptor* result =
3072 DescriptorBuilder(this, tables_.get(),
3073 default_error_collector_).BuildFile(proto);
3074 if (result == NULL) {
3075 tables_->known_bad_files_.insert(proto.name());
3076 }
3077 return result;
temporal40ee5512008-07-10 02:12:20 +00003078}
3079
3080DescriptorBuilder::DescriptorBuilder(
3081 const DescriptorPool* pool,
3082 DescriptorPool::Tables* tables,
3083 DescriptorPool::ErrorCollector* error_collector)
3084 : pool_(pool),
3085 tables_(tables),
3086 error_collector_(error_collector),
3087 had_errors_(false),
jieluo@google.com4de8f552014-07-18 00:47:59 +00003088 possible_undeclared_dependency_(NULL),
3089 undefine_resolved_name_("") {}
temporal40ee5512008-07-10 02:12:20 +00003090
3091DescriptorBuilder::~DescriptorBuilder() {}
3092
3093void DescriptorBuilder::AddError(
3094 const string& element_name,
3095 const Message& descriptor,
3096 DescriptorPool::ErrorCollector::ErrorLocation location,
3097 const string& error) {
3098 if (error_collector_ == NULL) {
3099 if (!had_errors_) {
3100 GOOGLE_LOG(ERROR) << "Invalid proto descriptor for file \"" << filename_
3101 << "\":";
3102 }
3103 GOOGLE_LOG(ERROR) << " " << element_name << ": " << error;
3104 } else {
3105 error_collector_->AddError(filename_, element_name,
3106 &descriptor, location, error);
3107 }
3108 had_errors_ = true;
3109}
3110
jieluo@google.com4de8f552014-07-18 00:47:59 +00003111void DescriptorBuilder::AddError(
3112 const string& element_name,
3113 const Message& descriptor,
3114 DescriptorPool::ErrorCollector::ErrorLocation location,
3115 const char* error) {
3116 AddError(element_name, descriptor, location, string(error));
3117}
3118
temporal40ee5512008-07-10 02:12:20 +00003119void DescriptorBuilder::AddNotDefinedError(
3120 const string& element_name,
3121 const Message& descriptor,
3122 DescriptorPool::ErrorCollector::ErrorLocation location,
3123 const string& undefined_symbol) {
jieluo@google.com4de8f552014-07-18 00:47:59 +00003124 if (possible_undeclared_dependency_ == NULL &&
3125 undefine_resolved_name_.empty()) {
temporal40ee5512008-07-10 02:12:20 +00003126 AddError(element_name, descriptor, location,
3127 "\"" + undefined_symbol + "\" is not defined.");
3128 } else {
jieluo@google.com4de8f552014-07-18 00:47:59 +00003129 if (possible_undeclared_dependency_ != NULL) {
3130 AddError(element_name, descriptor, location,
3131 "\"" + possible_undeclared_dependency_name_ +
3132 "\" seems to be defined in \"" +
3133 possible_undeclared_dependency_->name() + "\", which is not "
3134 "imported by \"" + filename_ + "\". To use it here, please "
3135 "add the necessary import.");
3136 }
3137 if (!undefine_resolved_name_.empty()) {
3138 AddError(element_name, descriptor, location,
3139 "\"" + undefined_symbol + "\" is resolved to \"" +
3140 undefine_resolved_name_ + "\", which is not defined. "
3141 "The innermost scope is searched first in name resolution. "
3142 "Consider using a leading '.'(i.e., \"."
3143 + undefined_symbol +
3144 "\") to start from the outermost scope.");
3145 }
3146 }
3147}
3148
3149void DescriptorBuilder::AddWarning(
3150 const string& element_name, const Message& descriptor,
3151 DescriptorPool::ErrorCollector::ErrorLocation location,
3152 const string& error) {
3153 if (error_collector_ == NULL) {
3154 GOOGLE_LOG(WARNING) << filename_ << " " << element_name << ": " << error;
3155 } else {
3156 error_collector_->AddWarning(filename_, element_name, &descriptor, location,
3157 error);
temporal40ee5512008-07-10 02:12:20 +00003158 }
3159}
3160
3161bool DescriptorBuilder::IsInPackage(const FileDescriptor* file,
3162 const string& package_name) {
3163 return HasPrefixString(file->package(), package_name) &&
3164 (file->package().size() == package_name.size() ||
3165 file->package()[package_name.size()] == '.');
3166}
3167
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00003168void DescriptorBuilder::RecordPublicDependencies(const FileDescriptor* file) {
3169 if (file == NULL || !dependencies_.insert(file).second) return;
3170 for (int i = 0; file != NULL && i < file->public_dependency_count(); i++) {
3171 RecordPublicDependencies(file->public_dependency(i));
3172 }
3173}
temporal40ee5512008-07-10 02:12:20 +00003174
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00003175Symbol DescriptorBuilder::FindSymbolNotEnforcingDepsHelper(
3176 const DescriptorPool* pool, const string& name) {
3177 // If we are looking at an underlay, we must lock its mutex_, since we are
3178 // accessing the underlay's tables_ directly.
3179 MutexLockMaybe lock((pool == pool_) ? NULL : pool->mutex_);
temporal40ee5512008-07-10 02:12:20 +00003180
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00003181 Symbol result = pool->tables_->FindSymbol(name);
3182 if (result.IsNull() && pool->underlay_ != NULL) {
3183 // Symbol not found; check the underlay.
3184 result = FindSymbolNotEnforcingDepsHelper(pool->underlay_, name);
3185 }
3186
3187 if (result.IsNull()) {
3188 // In theory, we shouldn't need to check fallback_database_ because the
3189 // symbol should be in one of its file's direct dependencies, and we have
3190 // already loaded those by the time we get here. But we check anyway so
3191 // that we can generate better error message when dependencies are missing
3192 // (i.e., "missing dependency" rather than "type is not defined").
3193 if (pool->TryFindSymbolInFallbackDatabase(name)) {
3194 result = pool->tables_->FindSymbol(name);
3195 }
temporal40ee5512008-07-10 02:12:20 +00003196 }
3197
kenton@google.com26bd9ee2008-11-21 00:06:27 +00003198 return result;
3199}
3200
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00003201Symbol DescriptorBuilder::FindSymbolNotEnforcingDeps(const string& name) {
3202 return FindSymbolNotEnforcingDepsHelper(pool_, name);
3203}
3204
kenton@google.com26bd9ee2008-11-21 00:06:27 +00003205Symbol DescriptorBuilder::FindSymbol(const string& name) {
3206 Symbol result = FindSymbolNotEnforcingDeps(name);
3207
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00003208 if (result.IsNull()) return result;
3209
temporal40ee5512008-07-10 02:12:20 +00003210 if (!pool_->enforce_dependencies_) {
3211 // Hack for CompilerUpgrader.
3212 return result;
3213 }
3214
3215 // Only find symbols which were defined in this file or one of its
3216 // dependencies.
3217 const FileDescriptor* file = result.GetFile();
jieluo@google.com4de8f552014-07-18 00:47:59 +00003218 if (file == file_ || dependencies_.count(file) > 0) {
3219 unused_dependency_.erase(file);
3220 return result;
3221 }
temporal40ee5512008-07-10 02:12:20 +00003222
3223 if (result.type == Symbol::PACKAGE) {
3224 // Arg, this is overcomplicated. The symbol is a package name. It could
3225 // be that the package was defined in multiple files. result.GetFile()
3226 // returns the first file we saw that used this package. We've determined
3227 // that that file is not a direct dependency of the file we are currently
3228 // building, but it could be that some other file which *is* a direct
3229 // dependency also defines the same package. We can't really rule out this
3230 // symbol unless none of the dependencies define it.
3231 if (IsInPackage(file_, name)) return result;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00003232 for (set<const FileDescriptor*>::const_iterator it = dependencies_.begin();
3233 it != dependencies_.end(); ++it) {
kenton@google.com80b1d622009-07-29 01:13:20 +00003234 // Note: A dependency may be NULL if it was not found or had errors.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00003235 if (*it != NULL && IsInPackage(*it, name)) return result;
temporal40ee5512008-07-10 02:12:20 +00003236 }
3237 }
3238
3239 possible_undeclared_dependency_ = file;
kenton@google.com80b1d622009-07-29 01:13:20 +00003240 possible_undeclared_dependency_name_ = name;
temporal40ee5512008-07-10 02:12:20 +00003241 return kNullSymbol;
3242}
3243
kenton@google.comd37d46d2009-04-25 02:53:47 +00003244Symbol DescriptorBuilder::LookupSymbolNoPlaceholder(
3245 const string& name, const string& relative_to, ResolveMode resolve_mode) {
temporal40ee5512008-07-10 02:12:20 +00003246 possible_undeclared_dependency_ = NULL;
jieluo@google.com4de8f552014-07-18 00:47:59 +00003247 undefine_resolved_name_.clear();
temporal40ee5512008-07-10 02:12:20 +00003248
3249 if (name.size() > 0 && name[0] == '.') {
3250 // Fully-qualified name.
3251 return FindSymbol(name.substr(1));
3252 }
3253
3254 // If name is something like "Foo.Bar.baz", and symbols named "Foo" are
3255 // defined in multiple parent scopes, we only want to find "Bar.baz" in the
3256 // innermost one. E.g., the following should produce an error:
3257 // message Bar { message Baz {} }
3258 // message Foo {
3259 // message Bar {
3260 // }
3261 // optional Bar.Baz baz = 1;
3262 // }
3263 // So, we look for just "Foo" first, then look for "Bar.baz" within it if
3264 // found.
xiaofeng@google.com3d46dad2012-09-27 09:04:02 +00003265 string::size_type name_dot_pos = name.find_first_of('.');
temporal40ee5512008-07-10 02:12:20 +00003266 string first_part_of_name;
3267 if (name_dot_pos == string::npos) {
3268 first_part_of_name = name;
3269 } else {
3270 first_part_of_name = name.substr(0, name_dot_pos);
3271 }
3272
3273 string scope_to_try(relative_to);
3274
3275 while (true) {
3276 // Chop off the last component of the scope.
3277 string::size_type dot_pos = scope_to_try.find_last_of('.');
3278 if (dot_pos == string::npos) {
3279 return FindSymbol(name);
3280 } else {
3281 scope_to_try.erase(dot_pos);
3282 }
3283
3284 // Append ".first_part_of_name" and try to find.
3285 string::size_type old_size = scope_to_try.size();
3286 scope_to_try.append(1, '.');
3287 scope_to_try.append(first_part_of_name);
3288 Symbol result = FindSymbol(scope_to_try);
3289 if (!result.IsNull()) {
3290 if (first_part_of_name.size() < name.size()) {
3291 // name is a compound symbol, of which we only found the first part.
3292 // Now try to look up the rest of it.
kenton@google.comd37d46d2009-04-25 02:53:47 +00003293 if (result.IsAggregate()) {
3294 scope_to_try.append(name, first_part_of_name.size(),
3295 name.size() - first_part_of_name.size());
jieluo@google.com4de8f552014-07-18 00:47:59 +00003296 result = FindSymbol(scope_to_try);
3297 if (result.IsNull()) {
3298 undefine_resolved_name_ = scope_to_try;
3299 }
3300 return result;
kenton@google.comd37d46d2009-04-25 02:53:47 +00003301 } else {
3302 // We found a symbol but it's not an aggregate. Continue the loop.
3303 }
3304 } else {
3305 if (resolve_mode == LOOKUP_TYPES && !result.IsType()) {
3306 // We found a symbol but it's not a type. Continue the loop.
3307 } else {
3308 return result;
3309 }
temporal40ee5512008-07-10 02:12:20 +00003310 }
temporal40ee5512008-07-10 02:12:20 +00003311 }
3312
3313 // Not found. Remove the name so we can try again.
3314 scope_to_try.erase(old_size);
3315 }
3316}
3317
kenton@google.comd37d46d2009-04-25 02:53:47 +00003318Symbol DescriptorBuilder::LookupSymbol(
3319 const string& name, const string& relative_to,
3320 PlaceholderType placeholder_type, ResolveMode resolve_mode) {
3321 Symbol result = LookupSymbolNoPlaceholder(
3322 name, relative_to, resolve_mode);
3323 if (result.IsNull() && pool_->allow_unknown_) {
3324 // Not found, but AllowUnknownDependencies() is enabled. Return a
3325 // placeholder instead.
3326 result = NewPlaceholder(name, placeholder_type);
3327 }
3328 return result;
3329}
3330
3331Symbol DescriptorBuilder::NewPlaceholder(const string& name,
3332 PlaceholderType placeholder_type) {
3333 // Compute names.
3334 const string* placeholder_full_name;
3335 const string* placeholder_name;
3336 const string* placeholder_package;
3337
3338 if (!ValidateQualifiedName(name)) return kNullSymbol;
3339 if (name[0] == '.') {
3340 // Fully-qualified.
3341 placeholder_full_name = tables_->AllocateString(name.substr(1));
3342 } else {
3343 placeholder_full_name = tables_->AllocateString(name);
3344 }
3345
3346 string::size_type dotpos = placeholder_full_name->find_last_of('.');
3347 if (dotpos != string::npos) {
3348 placeholder_package = tables_->AllocateString(
3349 placeholder_full_name->substr(0, dotpos));
3350 placeholder_name = tables_->AllocateString(
3351 placeholder_full_name->substr(dotpos + 1));
3352 } else {
jieluo@google.com4de8f552014-07-18 00:47:59 +00003353 placeholder_package = &internal::GetEmptyString();
kenton@google.comd37d46d2009-04-25 02:53:47 +00003354 placeholder_name = placeholder_full_name;
3355 }
3356
3357 // Create the placeholders.
Feng Xiao6ef984a2014-11-10 17:34:54 -08003358 FileDescriptor* placeholder_file = NewPlaceholderFile(
3359 *placeholder_full_name + ".placeholder.proto");
kenton@google.comd37d46d2009-04-25 02:53:47 +00003360 placeholder_file->package_ = placeholder_package;
kenton@google.comd37d46d2009-04-25 02:53:47 +00003361
3362 if (placeholder_type == PLACEHOLDER_ENUM) {
3363 placeholder_file->enum_type_count_ = 1;
3364 placeholder_file->enum_types_ =
3365 tables_->AllocateArray<EnumDescriptor>(1);
3366
3367 EnumDescriptor* placeholder_enum = &placeholder_file->enum_types_[0];
3368 memset(placeholder_enum, 0, sizeof(*placeholder_enum));
3369
3370 placeholder_enum->full_name_ = placeholder_full_name;
3371 placeholder_enum->name_ = placeholder_name;
3372 placeholder_enum->file_ = placeholder_file;
3373 placeholder_enum->options_ = &EnumOptions::default_instance();
3374 placeholder_enum->is_placeholder_ = true;
3375 placeholder_enum->is_unqualified_placeholder_ = (name[0] != '.');
3376
3377 // Enums must have at least one value.
3378 placeholder_enum->value_count_ = 1;
3379 placeholder_enum->values_ = tables_->AllocateArray<EnumValueDescriptor>(1);
3380
3381 EnumValueDescriptor* placeholder_value = &placeholder_enum->values_[0];
3382 memset(placeholder_value, 0, sizeof(*placeholder_value));
3383
3384 placeholder_value->name_ = tables_->AllocateString("PLACEHOLDER_VALUE");
3385 // Note that enum value names are siblings of their type, not children.
3386 placeholder_value->full_name_ =
3387 placeholder_package->empty() ? placeholder_value->name_ :
3388 tables_->AllocateString(*placeholder_package + ".PLACEHOLDER_VALUE");
3389
3390 placeholder_value->number_ = 0;
3391 placeholder_value->type_ = placeholder_enum;
3392 placeholder_value->options_ = &EnumValueOptions::default_instance();
3393
3394 return Symbol(placeholder_enum);
3395 } else {
3396 placeholder_file->message_type_count_ = 1;
3397 placeholder_file->message_types_ =
3398 tables_->AllocateArray<Descriptor>(1);
3399
3400 Descriptor* placeholder_message = &placeholder_file->message_types_[0];
3401 memset(placeholder_message, 0, sizeof(*placeholder_message));
3402
3403 placeholder_message->full_name_ = placeholder_full_name;
3404 placeholder_message->name_ = placeholder_name;
3405 placeholder_message->file_ = placeholder_file;
3406 placeholder_message->options_ = &MessageOptions::default_instance();
3407 placeholder_message->is_placeholder_ = true;
3408 placeholder_message->is_unqualified_placeholder_ = (name[0] != '.');
3409
3410 if (placeholder_type == PLACEHOLDER_EXTENDABLE_MESSAGE) {
3411 placeholder_message->extension_range_count_ = 1;
3412 placeholder_message->extension_ranges_ =
3413 tables_->AllocateArray<Descriptor::ExtensionRange>(1);
3414 placeholder_message->extension_ranges_->start = 1;
3415 // kMaxNumber + 1 because ExtensionRange::end is exclusive.
3416 placeholder_message->extension_ranges_->end =
3417 FieldDescriptor::kMaxNumber + 1;
3418 }
3419
3420 return Symbol(placeholder_message);
3421 }
3422}
3423
Feng Xiao6ef984a2014-11-10 17:34:54 -08003424FileDescriptor* DescriptorBuilder::NewPlaceholderFile(
kenton@google.comd37d46d2009-04-25 02:53:47 +00003425 const string& name) {
3426 FileDescriptor* placeholder = tables_->Allocate<FileDescriptor>();
3427 memset(placeholder, 0, sizeof(*placeholder));
3428
3429 placeholder->name_ = tables_->AllocateString(name);
jieluo@google.com4de8f552014-07-18 00:47:59 +00003430 placeholder->package_ = &internal::GetEmptyString();
kenton@google.comd37d46d2009-04-25 02:53:47 +00003431 placeholder->pool_ = pool_;
3432 placeholder->options_ = &FileOptions::default_instance();
3433 placeholder->tables_ = &FileDescriptorTables::kEmpty;
Feng Xiao6ef984a2014-11-10 17:34:54 -08003434 placeholder->source_code_info_ = &SourceCodeInfo::default_instance();
jieluo@google.com4de8f552014-07-18 00:47:59 +00003435 placeholder->is_placeholder_ = true;
Feng Xiao6ef984a2014-11-10 17:34:54 -08003436 placeholder->syntax_ = FileDescriptor::SYNTAX_PROTO2;
kenton@google.comd37d46d2009-04-25 02:53:47 +00003437 // All other fields are zero or NULL.
3438
3439 return placeholder;
3440}
3441
temporalf2063512008-07-23 01:19:07 +00003442bool DescriptorBuilder::AddSymbol(
temporal40ee5512008-07-10 02:12:20 +00003443 const string& full_name, const void* parent, const string& name,
3444 const Message& proto, Symbol symbol) {
3445 // If the caller passed NULL for the parent, the symbol is at file scope.
3446 // Use its file as the parent instead.
3447 if (parent == NULL) parent = file_;
3448
kenton@google.comd37d46d2009-04-25 02:53:47 +00003449 if (tables_->AddSymbol(full_name, symbol)) {
3450 if (!file_tables_->AddAliasUnderParent(parent, name, symbol)) {
3451 GOOGLE_LOG(DFATAL) << "\"" << full_name << "\" not previously defined in "
3452 "symbols_by_name_, but was defined in symbols_by_parent_; "
3453 "this shouldn't be possible.";
3454 return false;
3455 }
temporalf2063512008-07-23 01:19:07 +00003456 return true;
3457 } else {
temporal40ee5512008-07-10 02:12:20 +00003458 const FileDescriptor* other_file = tables_->FindSymbol(full_name).GetFile();
3459 if (other_file == file_) {
3460 string::size_type dot_pos = full_name.find_last_of('.');
3461 if (dot_pos == string::npos) {
3462 AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
3463 "\"" + full_name + "\" is already defined.");
3464 } else {
3465 AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
3466 "\"" + full_name.substr(dot_pos + 1) +
3467 "\" is already defined in \"" +
3468 full_name.substr(0, dot_pos) + "\".");
3469 }
3470 } else {
3471 // Symbol seems to have been defined in a different file.
3472 AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
3473 "\"" + full_name + "\" is already defined in file \"" +
3474 other_file->name() + "\".");
3475 }
temporalf2063512008-07-23 01:19:07 +00003476 return false;
temporal40ee5512008-07-10 02:12:20 +00003477 }
3478}
3479
3480void DescriptorBuilder::AddPackage(
3481 const string& name, const Message& proto, const FileDescriptor* file) {
kenton@google.comd37d46d2009-04-25 02:53:47 +00003482 if (tables_->AddSymbol(name, Symbol(file))) {
temporal40ee5512008-07-10 02:12:20 +00003483 // Success. Also add parent package, if any.
3484 string::size_type dot_pos = name.find_last_of('.');
3485 if (dot_pos == string::npos) {
3486 // No parents.
3487 ValidateSymbolName(name, name, proto);
3488 } else {
3489 // Has parent.
3490 string* parent_name = tables_->AllocateString(name.substr(0, dot_pos));
3491 AddPackage(*parent_name, proto, file);
3492 ValidateSymbolName(name.substr(dot_pos + 1), name, proto);
3493 }
3494 } else {
3495 Symbol existing_symbol = tables_->FindSymbol(name);
3496 // It's OK to redefine a package.
3497 if (existing_symbol.type != Symbol::PACKAGE) {
3498 // Symbol seems to have been defined in a different file.
3499 AddError(name, proto, DescriptorPool::ErrorCollector::NAME,
3500 "\"" + name + "\" is already defined (as something other than "
3501 "a package) in file \"" + existing_symbol.GetFile()->name() +
3502 "\".");
3503 }
3504 }
3505}
3506
3507void DescriptorBuilder::ValidateSymbolName(
3508 const string& name, const string& full_name, const Message& proto) {
3509 if (name.empty()) {
3510 AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
3511 "Missing name.");
3512 } else {
3513 for (int i = 0; i < name.size(); i++) {
3514 // I don't trust isalnum() due to locales. :(
3515 if ((name[i] < 'a' || 'z' < name[i]) &&
3516 (name[i] < 'A' || 'Z' < name[i]) &&
3517 (name[i] < '0' || '9' < name[i]) &&
3518 (name[i] != '_')) {
3519 AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
3520 "\"" + name + "\" is not a valid identifier.");
3521 }
3522 }
3523 }
3524}
3525
kenton@google.comd37d46d2009-04-25 02:53:47 +00003526bool DescriptorBuilder::ValidateQualifiedName(const string& name) {
3527 bool last_was_period = false;
3528
3529 for (int i = 0; i < name.size(); i++) {
3530 // I don't trust isalnum() due to locales. :(
3531 if (('a' <= name[i] && name[i] <= 'z') ||
3532 ('A' <= name[i] && name[i] <= 'Z') ||
3533 ('0' <= name[i] && name[i] <= '9') ||
3534 (name[i] == '_')) {
3535 last_was_period = false;
3536 } else if (name[i] == '.') {
3537 if (last_was_period) return false;
3538 last_was_period = true;
3539 } else {
3540 return false;
3541 }
3542 }
3543
3544 return !name.empty() && !last_was_period;
3545}
3546
temporal40ee5512008-07-10 02:12:20 +00003547// -------------------------------------------------------------------
3548
kenton@google.com24bf56f2008-09-24 20:31:01 +00003549// This generic implementation is good for all descriptors except
3550// FileDescriptor.
3551template<class DescriptorT> void DescriptorBuilder::AllocateOptions(
3552 const typename DescriptorT::OptionsType& orig_options,
3553 DescriptorT* descriptor) {
3554 AllocateOptionsImpl(descriptor->full_name(), descriptor->full_name(),
3555 orig_options, descriptor);
3556}
3557
3558// We specialize for FileDescriptor.
kenton@google.comde754372008-11-06 21:36:28 +00003559void DescriptorBuilder::AllocateOptions(const FileOptions& orig_options,
3560 FileDescriptor* descriptor) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00003561 // We add the dummy token so that LookupSymbol does the right thing.
3562 AllocateOptionsImpl(descriptor->package() + ".dummy", descriptor->name(),
3563 orig_options, descriptor);
3564}
3565
3566template<class DescriptorT> void DescriptorBuilder::AllocateOptionsImpl(
3567 const string& name_scope,
3568 const string& element_name,
3569 const typename DescriptorT::OptionsType& orig_options,
3570 DescriptorT* descriptor) {
kenton@google.comd37d46d2009-04-25 02:53:47 +00003571 // We need to use a dummy pointer to work around a bug in older versions of
3572 // GCC. Otherwise, the following two lines could be replaced with:
3573 // typename DescriptorT::OptionsType* options =
3574 // tables_->AllocateMessage<typename DescriptorT::OptionsType>();
3575 typename DescriptorT::OptionsType* const dummy = NULL;
3576 typename DescriptorT::OptionsType* options = tables_->AllocateMessage(dummy);
liujisi@google.comf5d5b4d2012-12-05 05:54:48 +00003577 // Avoid using MergeFrom()/CopyFrom() in this class to make it -fno-rtti
3578 // friendly. Without RTTI, MergeFrom() and CopyFrom() will fallback to the
3579 // reflection based method, which requires the Descriptor. However, we are in
3580 // the middle of building the descriptors, thus the deadlock.
3581 options->ParseFromString(orig_options.SerializeAsString());
kenton@google.com24bf56f2008-09-24 20:31:01 +00003582 descriptor->options_ = options;
kenton@google.comd37d46d2009-04-25 02:53:47 +00003583
3584 // Don't add to options_to_interpret_ unless there were uninterpreted
3585 // options. This not only avoids unnecessary work, but prevents a
3586 // bootstrapping problem when building descriptors for descriptor.proto.
3587 // descriptor.proto does not contain any uninterpreted options, but
3588 // attempting to interpret options anyway will cause
3589 // OptionsType::GetDescriptor() to be called which may then deadlock since
3590 // we're still trying to build it.
3591 if (options->uninterpreted_option_size() > 0) {
3592 options_to_interpret_.push_back(
3593 OptionsToInterpret(name_scope, element_name, &orig_options, options));
3594 }
kenton@google.com24bf56f2008-09-24 20:31:01 +00003595}
3596
3597
temporal40ee5512008-07-10 02:12:20 +00003598// A common pattern: We want to convert a repeated field in the descriptor
3599// to an array of values, calling some method to build each value.
3600#define BUILD_ARRAY(INPUT, OUTPUT, NAME, METHOD, PARENT) \
3601 OUTPUT->NAME##_count_ = INPUT.NAME##_size(); \
3602 AllocateArray(INPUT.NAME##_size(), &OUTPUT->NAME##s_); \
3603 for (int i = 0; i < INPUT.NAME##_size(); i++) { \
3604 METHOD(INPUT.NAME(i), PARENT, OUTPUT->NAME##s_ + i); \
3605 }
3606
jieluo@google.com4de8f552014-07-18 00:47:59 +00003607void DescriptorBuilder::AddRecursiveImportError(
3608 const FileDescriptorProto& proto, int from_here) {
3609 string error_message("File recursively imports itself: ");
3610 for (int i = from_here; i < tables_->pending_files_.size(); i++) {
3611 error_message.append(tables_->pending_files_[i]);
3612 error_message.append(" -> ");
3613 }
3614 error_message.append(proto.name());
3615
3616 AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER,
3617 error_message);
3618}
3619
3620void DescriptorBuilder::AddTwiceListedError(const FileDescriptorProto& proto,
3621 int index) {
3622 AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER,
3623 "Import \"" + proto.dependency(index) + "\" was listed twice.");
3624}
3625
3626void DescriptorBuilder::AddImportError(const FileDescriptorProto& proto,
3627 int index) {
3628 string message;
3629 if (pool_->fallback_database_ == NULL) {
3630 message = "Import \"" + proto.dependency(index) +
3631 "\" has not been loaded.";
3632 } else {
3633 message = "Import \"" + proto.dependency(index) +
3634 "\" was not found or had errors.";
3635 }
3636 AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER, message);
3637}
3638
3639static bool ExistingFileMatchesProto(const FileDescriptor* existing_file,
3640 const FileDescriptorProto& proto) {
3641 FileDescriptorProto existing_proto;
3642 existing_file->CopyTo(&existing_proto);
3643 return existing_proto.SerializeAsString() == proto.SerializeAsString();
3644}
3645
temporal40ee5512008-07-10 02:12:20 +00003646const FileDescriptor* DescriptorBuilder::BuildFile(
kenton@google.comd37d46d2009-04-25 02:53:47 +00003647 const FileDescriptorProto& proto) {
temporal40ee5512008-07-10 02:12:20 +00003648 filename_ = proto.name();
3649
kenton@google.comd37d46d2009-04-25 02:53:47 +00003650 // Check if the file already exists and is identical to the one being built.
3651 // Note: This only works if the input is canonical -- that is, it
3652 // fully-qualifies all type names, has no UninterpretedOptions, etc.
3653 // This is fine, because this idempotency "feature" really only exists to
Veres Lajosc7680722014-11-08 22:59:34 +00003654 // accommodate one hack in the proto1->proto2 migration layer.
kenton@google.comd37d46d2009-04-25 02:53:47 +00003655 const FileDescriptor* existing_file = tables_->FindFile(filename_);
3656 if (existing_file != NULL) {
3657 // File already in pool. Compare the existing one to the input.
jieluo@google.com4de8f552014-07-18 00:47:59 +00003658 if (ExistingFileMatchesProto(existing_file, proto)) {
kenton@google.comd37d46d2009-04-25 02:53:47 +00003659 // They're identical. Return the existing descriptor.
3660 return existing_file;
3661 }
3662
3663 // Not a match. The error will be detected and handled later.
3664 }
3665
temporal40ee5512008-07-10 02:12:20 +00003666 // Check to see if this file is already on the pending files list.
3667 // TODO(kenton): Allow recursive imports? It may not work with some
3668 // (most?) programming languages. E.g., in C++, a forward declaration
3669 // of a type is not sufficient to allow it to be used even in a
3670 // generated header file due to inlining. This could perhaps be
3671 // worked around using tricks involving inserting #include statements
3672 // mid-file, but that's pretty ugly, and I'm pretty sure there are
3673 // some languages out there that do not allow recursive dependencies
3674 // at all.
3675 for (int i = 0; i < tables_->pending_files_.size(); i++) {
3676 if (tables_->pending_files_[i] == proto.name()) {
jieluo@google.com4de8f552014-07-18 00:47:59 +00003677 AddRecursiveImportError(proto, i);
temporal40ee5512008-07-10 02:12:20 +00003678 return NULL;
3679 }
3680 }
3681
3682 // If we have a fallback_database_, attempt to load all dependencies now,
3683 // before checkpointing tables_. This avoids confusion with recursive
3684 // checkpoints.
3685 if (pool_->fallback_database_ != NULL) {
3686 tables_->pending_files_.push_back(proto.name());
3687 for (int i = 0; i < proto.dependency_size(); i++) {
3688 if (tables_->FindFile(proto.dependency(i)) == NULL &&
3689 (pool_->underlay_ == NULL ||
3690 pool_->underlay_->FindFileByName(proto.dependency(i)) == NULL)) {
3691 // We don't care what this returns since we'll find out below anyway.
3692 pool_->TryFindFileInFallbackDatabase(proto.dependency(i));
3693 }
3694 }
3695 tables_->pending_files_.pop_back();
3696 }
3697
3698 // Checkpoint the tables so that we can roll back if something goes wrong.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00003699 tables_->AddCheckpoint();
temporal40ee5512008-07-10 02:12:20 +00003700
3701 FileDescriptor* result = tables_->Allocate<FileDescriptor>();
3702 file_ = result;
3703
jieluo@google.com4de8f552014-07-18 00:47:59 +00003704 result->is_placeholder_ = false;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00003705 if (proto.has_source_code_info()) {
3706 SourceCodeInfo *info = tables_->AllocateMessage<SourceCodeInfo>();
3707 info->CopyFrom(proto.source_code_info());
3708 result->source_code_info_ = info;
3709 } else {
3710 result->source_code_info_ = &SourceCodeInfo::default_instance();
3711 }
3712
kenton@google.comd37d46d2009-04-25 02:53:47 +00003713 file_tables_ = tables_->AllocateFileTables();
3714 file_->tables_ = file_tables_;
3715
temporal40ee5512008-07-10 02:12:20 +00003716 if (!proto.has_name()) {
3717 AddError("", proto, DescriptorPool::ErrorCollector::OTHER,
3718 "Missing field: FileDescriptorProto.name.");
3719 }
3720
Feng Xiao6ef984a2014-11-10 17:34:54 -08003721 // TODO(liujisi): Report error when the syntax is empty after all the protos
3722 // have added the syntax statement.
3723 if (proto.syntax().empty() || proto.syntax() == "proto2") {
3724 file_->syntax_ = FileDescriptor::SYNTAX_PROTO2;
3725 } else if (proto.syntax() == "proto3") {
3726 file_->syntax_ = FileDescriptor::SYNTAX_PROTO3;
3727 } else {
3728 file_->syntax_ = FileDescriptor::SYNTAX_UNKNOWN;
3729 AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER,
3730 "Unrecognized syntax: " + proto.syntax());
3731 }
3732
temporal40ee5512008-07-10 02:12:20 +00003733 result->name_ = tables_->AllocateString(proto.name());
temporal6fdb0962008-07-25 04:38:05 +00003734 if (proto.has_package()) {
3735 result->package_ = tables_->AllocateString(proto.package());
3736 } else {
3737 // We cannot rely on proto.package() returning a valid string if
3738 // proto.has_package() is false, because we might be running at static
3739 // initialization time, in which case default values have not yet been
3740 // initialized.
3741 result->package_ = tables_->AllocateString("");
3742 }
temporal40ee5512008-07-10 02:12:20 +00003743 result->pool_ = pool_;
3744
3745 // Add to tables.
3746 if (!tables_->AddFile(result)) {
3747 AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER,
3748 "A file with this name is already in the pool.");
3749 // Bail out early so that if this is actually the exact same file, we
3750 // don't end up reporting that every single symbol is already defined.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00003751 tables_->RollbackToLastCheckpoint();
temporal40ee5512008-07-10 02:12:20 +00003752 return NULL;
3753 }
3754 if (!result->package().empty()) {
3755 AddPackage(result->package(), proto, result);
3756 }
3757
3758 // Make sure all dependencies are loaded.
3759 set<string> seen_dependencies;
3760 result->dependency_count_ = proto.dependency_size();
3761 result->dependencies_ =
3762 tables_->AllocateArray<const FileDescriptor*>(proto.dependency_size());
jieluo@google.com4de8f552014-07-18 00:47:59 +00003763 unused_dependency_.clear();
3764 set<int> weak_deps;
3765 for (int i = 0; i < proto.weak_dependency_size(); ++i) {
3766 weak_deps.insert(proto.weak_dependency(i));
3767 }
temporal40ee5512008-07-10 02:12:20 +00003768 for (int i = 0; i < proto.dependency_size(); i++) {
3769 if (!seen_dependencies.insert(proto.dependency(i)).second) {
jieluo@google.com4de8f552014-07-18 00:47:59 +00003770 AddTwiceListedError(proto, i);
temporal40ee5512008-07-10 02:12:20 +00003771 }
3772
3773 const FileDescriptor* dependency = tables_->FindFile(proto.dependency(i));
3774 if (dependency == NULL && pool_->underlay_ != NULL) {
3775 dependency = pool_->underlay_->FindFileByName(proto.dependency(i));
3776 }
3777
3778 if (dependency == NULL) {
jieluo@google.com4de8f552014-07-18 00:47:59 +00003779 if (pool_->allow_unknown_ ||
3780 (!pool_->enforce_weak_ && weak_deps.find(i) != weak_deps.end())) {
kenton@google.comd37d46d2009-04-25 02:53:47 +00003781 dependency = NewPlaceholderFile(proto.dependency(i));
temporal40ee5512008-07-10 02:12:20 +00003782 } else {
jieluo@google.com4de8f552014-07-18 00:47:59 +00003783 AddImportError(proto, i);
3784 }
3785 } else {
3786 // Add to unused_dependency_ to track unused imported files.
3787 // Note: do not track unused imported files for public import.
3788 if (pool_->enforce_dependencies_ &&
3789 (pool_->unused_import_track_files_.find(proto.name()) !=
3790 pool_->unused_import_track_files_.end()) &&
3791 (dependency->public_dependency_count() == 0)) {
3792 unused_dependency_.insert(dependency);
temporal40ee5512008-07-10 02:12:20 +00003793 }
temporal40ee5512008-07-10 02:12:20 +00003794 }
3795
3796 result->dependencies_[i] = dependency;
3797 }
3798
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00003799 // Check public dependencies.
3800 int public_dependency_count = 0;
3801 result->public_dependencies_ = tables_->AllocateArray<int>(
3802 proto.public_dependency_size());
3803 for (int i = 0; i < proto.public_dependency_size(); i++) {
3804 // Only put valid public dependency indexes.
3805 int index = proto.public_dependency(i);
3806 if (index >= 0 && index < proto.dependency_size()) {
3807 result->public_dependencies_[public_dependency_count++] = index;
jieluo@google.com4de8f552014-07-18 00:47:59 +00003808 // Do not track unused imported files for public import.
3809 unused_dependency_.erase(result->dependency(index));
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00003810 } else {
3811 AddError(proto.name(), proto,
3812 DescriptorPool::ErrorCollector::OTHER,
3813 "Invalid public dependency index.");
3814 }
3815 }
3816 result->public_dependency_count_ = public_dependency_count;
3817
3818 // Build dependency set
3819 dependencies_.clear();
3820 for (int i = 0; i < result->dependency_count(); i++) {
3821 RecordPublicDependencies(result->dependency(i));
3822 }
3823
3824 // Check weak dependencies.
3825 int weak_dependency_count = 0;
3826 result->weak_dependencies_ = tables_->AllocateArray<int>(
3827 proto.weak_dependency_size());
3828 for (int i = 0; i < proto.weak_dependency_size(); i++) {
3829 int index = proto.weak_dependency(i);
3830 if (index >= 0 && index < proto.dependency_size()) {
3831 result->weak_dependencies_[weak_dependency_count++] = index;
3832 } else {
3833 AddError(proto.name(), proto,
3834 DescriptorPool::ErrorCollector::OTHER,
3835 "Invalid weak dependency index.");
3836 }
3837 }
3838 result->weak_dependency_count_ = weak_dependency_count;
3839
temporal40ee5512008-07-10 02:12:20 +00003840 // Convert children.
3841 BUILD_ARRAY(proto, result, message_type, BuildMessage , NULL);
3842 BUILD_ARRAY(proto, result, enum_type , BuildEnum , NULL);
3843 BUILD_ARRAY(proto, result, service , BuildService , NULL);
3844 BUILD_ARRAY(proto, result, extension , BuildExtension, NULL);
3845
3846 // Copy options.
3847 if (!proto.has_options()) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00003848 result->options_ = NULL; // Will set to default_instance later.
temporal40ee5512008-07-10 02:12:20 +00003849 } else {
kenton@google.com24bf56f2008-09-24 20:31:01 +00003850 AllocateOptions(proto.options(), result);
3851 }
3852
3853 // Note that the following steps must occur in exactly the specified order.
3854
temporal40ee5512008-07-10 02:12:20 +00003855 // Cross-link.
3856 CrossLinkFile(result, proto);
3857
kenton@google.com24bf56f2008-09-24 20:31:01 +00003858 // Interpret any remaining uninterpreted options gathered into
3859 // options_to_interpret_ during descriptor building. Cross-linking has made
3860 // extension options known, so all interpretations should now succeed.
3861 if (!had_errors_) {
3862 OptionInterpreter option_interpreter(this);
3863 for (vector<OptionsToInterpret>::iterator iter =
3864 options_to_interpret_.begin();
3865 iter != options_to_interpret_.end(); ++iter) {
3866 option_interpreter.InterpretOptions(&(*iter));
3867 }
3868 options_to_interpret_.clear();
3869 }
3870
3871 // Validate options.
3872 if (!had_errors_) {
3873 ValidateFileOptions(result, proto);
3874 }
3875
Feng Xiao6ef984a2014-11-10 17:34:54 -08003876 // Additional naming conflict check for map entry types. Only need to check
3877 // this if there are already errors.
3878 if (had_errors_) {
3879 for (int i = 0; i < proto.message_type_size(); ++i) {
3880 DetectMapConflicts(result->message_type(i), proto.message_type(i));
3881 }
3882 }
3883
jieluo@google.com4de8f552014-07-18 00:47:59 +00003884
3885 if (!unused_dependency_.empty()) {
3886 LogUnusedDependency(result);
3887 }
3888
temporal40ee5512008-07-10 02:12:20 +00003889 if (had_errors_) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00003890 tables_->RollbackToLastCheckpoint();
temporal40ee5512008-07-10 02:12:20 +00003891 return NULL;
3892 } else {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00003893 tables_->ClearLastCheckpoint();
temporal40ee5512008-07-10 02:12:20 +00003894 return result;
3895 }
3896}
3897
3898void DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
3899 const Descriptor* parent,
3900 Descriptor* result) {
3901 const string& scope = (parent == NULL) ?
3902 file_->package() : parent->full_name();
3903 string* full_name = tables_->AllocateString(scope);
3904 if (!full_name->empty()) full_name->append(1, '.');
3905 full_name->append(proto.name());
3906
3907 ValidateSymbolName(proto.name(), *full_name, proto);
3908
3909 result->name_ = tables_->AllocateString(proto.name());
3910 result->full_name_ = full_name;
3911 result->file_ = file_;
3912 result->containing_type_ = parent;
kenton@google.comd37d46d2009-04-25 02:53:47 +00003913 result->is_placeholder_ = false;
3914 result->is_unqualified_placeholder_ = false;
temporal40ee5512008-07-10 02:12:20 +00003915
jieluo@google.com4de8f552014-07-18 00:47:59 +00003916 // Build oneofs first so that fields and extension ranges can refer to them.
3917 BUILD_ARRAY(proto, result, oneof_decl , BuildOneof , result);
temporal40ee5512008-07-10 02:12:20 +00003918 BUILD_ARRAY(proto, result, field , BuildField , result);
3919 BUILD_ARRAY(proto, result, nested_type , BuildMessage , result);
3920 BUILD_ARRAY(proto, result, enum_type , BuildEnum , result);
3921 BUILD_ARRAY(proto, result, extension_range, BuildExtensionRange, result);
3922 BUILD_ARRAY(proto, result, extension , BuildExtension , result);
3923
3924 // Copy options.
3925 if (!proto.has_options()) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00003926 result->options_ = NULL; // Will set to default_instance later.
temporal40ee5512008-07-10 02:12:20 +00003927 } else {
kenton@google.com24bf56f2008-09-24 20:31:01 +00003928 AllocateOptions(proto.options(), result);
temporal40ee5512008-07-10 02:12:20 +00003929 }
3930
3931 AddSymbol(result->full_name(), parent, result->name(),
3932 proto, Symbol(result));
3933
3934 // Check that no fields have numbers in extension ranges.
3935 for (int i = 0; i < result->field_count(); i++) {
3936 const FieldDescriptor* field = result->field(i);
3937 for (int j = 0; j < result->extension_range_count(); j++) {
3938 const Descriptor::ExtensionRange* range = result->extension_range(j);
3939 if (range->start <= field->number() && field->number() < range->end) {
3940 AddError(field->full_name(), proto.extension_range(j),
3941 DescriptorPool::ErrorCollector::NUMBER,
3942 strings::Substitute(
3943 "Extension range $0 to $1 includes field \"$2\" ($3).",
3944 range->start, range->end - 1,
3945 field->name(), field->number()));
3946 }
3947 }
3948 }
3949
3950 // Check that extension ranges don't overlap.
3951 for (int i = 0; i < result->extension_range_count(); i++) {
3952 const Descriptor::ExtensionRange* range1 = result->extension_range(i);
3953 for (int j = i + 1; j < result->extension_range_count(); j++) {
3954 const Descriptor::ExtensionRange* range2 = result->extension_range(j);
3955 if (range1->end > range2->start && range2->end > range1->start) {
3956 AddError(result->full_name(), proto.extension_range(j),
3957 DescriptorPool::ErrorCollector::NUMBER,
3958 strings::Substitute("Extension range $0 to $1 overlaps with "
3959 "already-defined range $2 to $3.",
3960 range2->start, range2->end - 1,
3961 range1->start, range1->end - 1));
3962 }
3963 }
3964 }
3965}
3966
3967void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
3968 const Descriptor* parent,
3969 FieldDescriptor* result,
3970 bool is_extension) {
3971 const string& scope = (parent == NULL) ?
3972 file_->package() : parent->full_name();
3973 string* full_name = tables_->AllocateString(scope);
3974 if (!full_name->empty()) full_name->append(1, '.');
3975 full_name->append(proto.name());
3976
3977 ValidateSymbolName(proto.name(), *full_name, proto);
3978
3979 result->name_ = tables_->AllocateString(proto.name());
3980 result->full_name_ = full_name;
3981 result->file_ = file_;
3982 result->number_ = proto.number();
temporal40ee5512008-07-10 02:12:20 +00003983 result->is_extension_ = is_extension;
3984
kenton@google.com2d6daa72009-01-22 01:27:00 +00003985 // If .proto files follow the style guide then the name should already be
3986 // lower-cased. If that's the case we can just reuse the string we already
3987 // allocated rather than allocate a new one.
3988 string lowercase_name(proto.name());
3989 LowerString(&lowercase_name);
3990 if (lowercase_name == proto.name()) {
3991 result->lowercase_name_ = result->name_;
3992 } else {
3993 result->lowercase_name_ = tables_->AllocateString(lowercase_name);
3994 }
3995
3996 // Don't bother with the above optimization for camel-case names since
3997 // .proto files that follow the guide shouldn't be using names in this
3998 // format, so the optimization wouldn't help much.
Feng Xiao6ef984a2014-11-10 17:34:54 -08003999 result->camelcase_name_ =
4000 tables_->AllocateString(ToCamelCase(proto.name(),
4001 /* lower_first = */ true));
kenton@google.com2d6daa72009-01-22 01:27:00 +00004002
kenton@google.coma2a32c22008-11-14 17:29:32 +00004003 // Some compilers do not allow static_cast directly between two enum types,
4004 // so we must cast to int first.
4005 result->type_ = static_cast<FieldDescriptor::Type>(
4006 implicit_cast<int>(proto.type()));
4007 result->label_ = static_cast<FieldDescriptor::Label>(
4008 implicit_cast<int>(proto.label()));
4009
jieluo@google.com4de8f552014-07-18 00:47:59 +00004010 // An extension cannot have a required field (b/13365836).
4011 if (result->is_extension_ &&
4012 result->label_ == FieldDescriptor::LABEL_REQUIRED) {
4013 AddError(result->full_name(), proto,
4014 // Error location `TYPE`: we would really like to indicate
4015 // `LABEL`, but the `ErrorLocation` enum has no entry for this, and
4016 // we don't necessarily know about all implementations of the
4017 // `ErrorCollector` interface to extend them to handle the new
4018 // error location type properly.
4019 DescriptorPool::ErrorCollector::TYPE,
4020 "Message extensions cannot have required fields.");
4021 }
4022
temporal40ee5512008-07-10 02:12:20 +00004023 // Some of these may be filled in when cross-linking.
4024 result->containing_type_ = NULL;
4025 result->extension_scope_ = NULL;
temporal40ee5512008-07-10 02:12:20 +00004026 result->message_type_ = NULL;
4027 result->enum_type_ = NULL;
4028
4029 result->has_default_value_ = proto.has_default_value();
kenton@google.comd37d46d2009-04-25 02:53:47 +00004030 if (proto.has_default_value() && result->is_repeated()) {
4031 AddError(result->full_name(), proto,
4032 DescriptorPool::ErrorCollector::DEFAULT_VALUE,
4033 "Repeated fields can't have default values.");
4034 }
4035
temporal40ee5512008-07-10 02:12:20 +00004036 if (proto.has_type()) {
4037 if (proto.has_default_value()) {
4038 char* end_pos = NULL;
4039 switch (result->cpp_type()) {
4040 case FieldDescriptor::CPPTYPE_INT32:
4041 result->default_value_int32_ =
4042 strtol(proto.default_value().c_str(), &end_pos, 0);
4043 break;
4044 case FieldDescriptor::CPPTYPE_INT64:
4045 result->default_value_int64_ =
4046 strto64(proto.default_value().c_str(), &end_pos, 0);
4047 break;
4048 case FieldDescriptor::CPPTYPE_UINT32:
4049 result->default_value_uint32_ =
4050 strtoul(proto.default_value().c_str(), &end_pos, 0);
4051 break;
4052 case FieldDescriptor::CPPTYPE_UINT64:
4053 result->default_value_uint64_ =
4054 strtou64(proto.default_value().c_str(), &end_pos, 0);
4055 break;
4056 case FieldDescriptor::CPPTYPE_FLOAT:
kenton@google.com684d45b2009-12-19 04:50:00 +00004057 if (proto.default_value() == "inf") {
4058 result->default_value_float_ = numeric_limits<float>::infinity();
4059 } else if (proto.default_value() == "-inf") {
4060 result->default_value_float_ = -numeric_limits<float>::infinity();
4061 } else if (proto.default_value() == "nan") {
4062 result->default_value_float_ = numeric_limits<float>::quiet_NaN();
4063 } else {
4064 result->default_value_float_ =
jieluo@google.com4de8f552014-07-18 00:47:59 +00004065 io::NoLocaleStrtod(proto.default_value().c_str(), &end_pos);
kenton@google.com684d45b2009-12-19 04:50:00 +00004066 }
temporal40ee5512008-07-10 02:12:20 +00004067 break;
4068 case FieldDescriptor::CPPTYPE_DOUBLE:
kenton@google.com684d45b2009-12-19 04:50:00 +00004069 if (proto.default_value() == "inf") {
4070 result->default_value_double_ = numeric_limits<double>::infinity();
4071 } else if (proto.default_value() == "-inf") {
4072 result->default_value_double_ = -numeric_limits<double>::infinity();
4073 } else if (proto.default_value() == "nan") {
4074 result->default_value_double_ = numeric_limits<double>::quiet_NaN();
4075 } else {
4076 result->default_value_double_ =
jieluo@google.com4de8f552014-07-18 00:47:59 +00004077 io::NoLocaleStrtod(proto.default_value().c_str(), &end_pos);
kenton@google.com684d45b2009-12-19 04:50:00 +00004078 }
temporal40ee5512008-07-10 02:12:20 +00004079 break;
4080 case FieldDescriptor::CPPTYPE_BOOL:
4081 if (proto.default_value() == "true") {
4082 result->default_value_bool_ = true;
4083 } else if (proto.default_value() == "false") {
4084 result->default_value_bool_ = false;
4085 } else {
4086 AddError(result->full_name(), proto,
4087 DescriptorPool::ErrorCollector::DEFAULT_VALUE,
4088 "Boolean default must be true or false.");
4089 }
4090 break;
4091 case FieldDescriptor::CPPTYPE_ENUM:
4092 // This will be filled in when cross-linking.
4093 result->default_value_enum_ = NULL;
4094 break;
4095 case FieldDescriptor::CPPTYPE_STRING:
4096 if (result->type() == FieldDescriptor::TYPE_BYTES) {
4097 result->default_value_string_ = tables_->AllocateString(
4098 UnescapeCEscapeString(proto.default_value()));
4099 } else {
4100 result->default_value_string_ =
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00004101 tables_->AllocateString(proto.default_value());
temporal40ee5512008-07-10 02:12:20 +00004102 }
4103 break;
4104 case FieldDescriptor::CPPTYPE_MESSAGE:
4105 AddError(result->full_name(), proto,
4106 DescriptorPool::ErrorCollector::DEFAULT_VALUE,
4107 "Messages can't have default values.");
4108 result->has_default_value_ = false;
4109 break;
4110 }
4111
4112 if (end_pos != NULL) {
4113 // end_pos is only set non-NULL by the parsers for numeric types, above.
4114 // This checks that the default was non-empty and had no extra junk
4115 // after the end of the number.
4116 if (proto.default_value().empty() || *end_pos != '\0') {
4117 AddError(result->full_name(), proto,
4118 DescriptorPool::ErrorCollector::DEFAULT_VALUE,
jieluo@google.com4de8f552014-07-18 00:47:59 +00004119 "Couldn't parse default value \"" + proto.default_value() +
4120 "\".");
temporal40ee5512008-07-10 02:12:20 +00004121 }
4122 }
4123 } else {
4124 // No explicit default value
4125 switch (result->cpp_type()) {
4126 case FieldDescriptor::CPPTYPE_INT32:
4127 result->default_value_int32_ = 0;
4128 break;
4129 case FieldDescriptor::CPPTYPE_INT64:
4130 result->default_value_int64_ = 0;
4131 break;
4132 case FieldDescriptor::CPPTYPE_UINT32:
4133 result->default_value_uint32_ = 0;
4134 break;
4135 case FieldDescriptor::CPPTYPE_UINT64:
4136 result->default_value_uint64_ = 0;
4137 break;
4138 case FieldDescriptor::CPPTYPE_FLOAT:
4139 result->default_value_float_ = 0.0f;
4140 break;
4141 case FieldDescriptor::CPPTYPE_DOUBLE:
4142 result->default_value_double_ = 0.0;
4143 break;
4144 case FieldDescriptor::CPPTYPE_BOOL:
4145 result->default_value_bool_ = false;
4146 break;
4147 case FieldDescriptor::CPPTYPE_ENUM:
4148 // This will be filled in when cross-linking.
4149 result->default_value_enum_ = NULL;
4150 break;
4151 case FieldDescriptor::CPPTYPE_STRING:
jieluo@google.com4de8f552014-07-18 00:47:59 +00004152 result->default_value_string_ = &internal::GetEmptyString();
temporal40ee5512008-07-10 02:12:20 +00004153 break;
4154 case FieldDescriptor::CPPTYPE_MESSAGE:
4155 break;
4156 }
4157 }
4158 }
4159
4160 if (result->number() <= 0) {
4161 AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
4162 "Field numbers must be positive integers.");
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00004163 } else if (!is_extension && result->number() > FieldDescriptor::kMaxNumber) {
4164 // Only validate that the number is within the valid field range if it is
4165 // not an extension. Since extension numbers are validated with the
4166 // extendee's valid set of extension numbers, and those are in turn
4167 // validated against the max allowed number, the check is unnecessary for
4168 // extension fields.
4169 // This avoids cross-linking issues that arise when attempting to check if
4170 // the extendee is a message_set_wire_format message, which has a higher max
4171 // on extension numbers.
temporal40ee5512008-07-10 02:12:20 +00004172 AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
4173 strings::Substitute("Field numbers cannot be greater than $0.",
4174 FieldDescriptor::kMaxNumber));
4175 } else if (result->number() >= FieldDescriptor::kFirstReservedNumber &&
4176 result->number() <= FieldDescriptor::kLastReservedNumber) {
4177 AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER,
4178 strings::Substitute(
4179 "Field numbers $0 through $1 are reserved for the protocol "
4180 "buffer library implementation.",
4181 FieldDescriptor::kFirstReservedNumber,
4182 FieldDescriptor::kLastReservedNumber));
4183 }
4184
4185 if (is_extension) {
4186 if (!proto.has_extendee()) {
4187 AddError(result->full_name(), proto,
4188 DescriptorPool::ErrorCollector::EXTENDEE,
4189 "FieldDescriptorProto.extendee not set for extension field.");
4190 }
4191
4192 result->extension_scope_ = parent;
jieluo@google.com4de8f552014-07-18 00:47:59 +00004193
4194 if (proto.has_oneof_index()) {
4195 AddError(result->full_name(), proto,
4196 DescriptorPool::ErrorCollector::OTHER,
4197 "FieldDescriptorProto.oneof_index should not be set for "
4198 "extensions.");
4199 }
4200
4201 // Fill in later (maybe).
4202 result->containing_oneof_ = NULL;
temporal40ee5512008-07-10 02:12:20 +00004203 } else {
4204 if (proto.has_extendee()) {
4205 AddError(result->full_name(), proto,
4206 DescriptorPool::ErrorCollector::EXTENDEE,
4207 "FieldDescriptorProto.extendee set for non-extension field.");
4208 }
4209
4210 result->containing_type_ = parent;
jieluo@google.com4de8f552014-07-18 00:47:59 +00004211
4212 if (proto.has_oneof_index()) {
4213 if (proto.oneof_index() < 0 ||
4214 proto.oneof_index() >= parent->oneof_decl_count()) {
4215 AddError(result->full_name(), proto,
4216 DescriptorPool::ErrorCollector::OTHER,
4217 strings::Substitute("FieldDescriptorProto.oneof_index $0 is "
4218 "out of range for type \"$1\".",
4219 proto.oneof_index(),
4220 parent->name()));
4221 result->containing_oneof_ = NULL;
4222 } else {
4223 result->containing_oneof_ = parent->oneof_decl(proto.oneof_index());
4224 }
4225 } else {
4226 result->containing_oneof_ = NULL;
4227 }
temporal40ee5512008-07-10 02:12:20 +00004228 }
4229
4230 // Copy options.
4231 if (!proto.has_options()) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00004232 result->options_ = NULL; // Will set to default_instance later.
temporal40ee5512008-07-10 02:12:20 +00004233 } else {
kenton@google.com24bf56f2008-09-24 20:31:01 +00004234 AllocateOptions(proto.options(), result);
temporal40ee5512008-07-10 02:12:20 +00004235 }
4236
4237 AddSymbol(result->full_name(), parent, result->name(),
4238 proto, Symbol(result));
4239}
4240
4241void DescriptorBuilder::BuildExtensionRange(
4242 const DescriptorProto::ExtensionRange& proto,
4243 const Descriptor* parent,
4244 Descriptor::ExtensionRange* result) {
4245 result->start = proto.start();
4246 result->end = proto.end();
4247 if (result->start <= 0) {
4248 AddError(parent->full_name(), proto,
4249 DescriptorPool::ErrorCollector::NUMBER,
4250 "Extension numbers must be positive integers.");
4251 }
4252
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00004253 // Checking of the upper bound of the extension range is deferred until after
4254 // options interpreting. This allows messages with message_set_wire_format to
4255 // have extensions beyond FieldDescriptor::kMaxNumber, since the extension
4256 // numbers are actually used as int32s in the message_set_wire_format.
temporal40ee5512008-07-10 02:12:20 +00004257
4258 if (result->start >= result->end) {
4259 AddError(parent->full_name(), proto,
4260 DescriptorPool::ErrorCollector::NUMBER,
4261 "Extension range end number must be greater than start number.");
4262 }
4263}
4264
jieluo@google.com4de8f552014-07-18 00:47:59 +00004265void DescriptorBuilder::BuildOneof(const OneofDescriptorProto& proto,
4266 Descriptor* parent,
4267 OneofDescriptor* result) {
4268 string* full_name = tables_->AllocateString(parent->full_name());
4269 full_name->append(1, '.');
4270 full_name->append(proto.name());
4271
4272 ValidateSymbolName(proto.name(), *full_name, proto);
4273
4274 result->name_ = tables_->AllocateString(proto.name());
4275 result->full_name_ = full_name;
4276
4277 result->containing_type_ = parent;
4278
4279 // We need to fill these in later.
4280 result->field_count_ = 0;
4281 result->fields_ = NULL;
4282
4283 AddSymbol(result->full_name(), parent, result->name(),
4284 proto, Symbol(result));
4285}
4286
temporal40ee5512008-07-10 02:12:20 +00004287void DescriptorBuilder::BuildEnum(const EnumDescriptorProto& proto,
4288 const Descriptor* parent,
4289 EnumDescriptor* result) {
4290 const string& scope = (parent == NULL) ?
4291 file_->package() : parent->full_name();
4292 string* full_name = tables_->AllocateString(scope);
4293 if (!full_name->empty()) full_name->append(1, '.');
4294 full_name->append(proto.name());
4295
4296 ValidateSymbolName(proto.name(), *full_name, proto);
4297
4298 result->name_ = tables_->AllocateString(proto.name());
4299 result->full_name_ = full_name;
4300 result->file_ = file_;
4301 result->containing_type_ = parent;
kenton@google.comd37d46d2009-04-25 02:53:47 +00004302 result->is_placeholder_ = false;
4303 result->is_unqualified_placeholder_ = false;
temporal40ee5512008-07-10 02:12:20 +00004304
4305 if (proto.value_size() == 0) {
4306 // We cannot allow enums with no values because this would mean there
4307 // would be no valid default value for fields of this type.
4308 AddError(result->full_name(), proto,
4309 DescriptorPool::ErrorCollector::NAME,
4310 "Enums must contain at least one value.");
4311 }
4312
4313 BUILD_ARRAY(proto, result, value, BuildEnumValue, result);
4314
4315 // Copy options.
4316 if (!proto.has_options()) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00004317 result->options_ = NULL; // Will set to default_instance later.
temporal40ee5512008-07-10 02:12:20 +00004318 } else {
kenton@google.com24bf56f2008-09-24 20:31:01 +00004319 AllocateOptions(proto.options(), result);
temporal40ee5512008-07-10 02:12:20 +00004320 }
4321
4322 AddSymbol(result->full_name(), parent, result->name(),
4323 proto, Symbol(result));
4324}
4325
4326void DescriptorBuilder::BuildEnumValue(const EnumValueDescriptorProto& proto,
4327 const EnumDescriptor* parent,
4328 EnumValueDescriptor* result) {
4329 result->name_ = tables_->AllocateString(proto.name());
4330 result->number_ = proto.number();
4331 result->type_ = parent;
4332
4333 // Note: full_name for enum values is a sibling to the parent's name, not a
4334 // child of it.
4335 string* full_name = tables_->AllocateString(*parent->full_name_);
4336 full_name->resize(full_name->size() - parent->name_->size());
4337 full_name->append(*result->name_);
4338 result->full_name_ = full_name;
4339
4340 ValidateSymbolName(proto.name(), *full_name, proto);
4341
4342 // Copy options.
4343 if (!proto.has_options()) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00004344 result->options_ = NULL; // Will set to default_instance later.
temporal40ee5512008-07-10 02:12:20 +00004345 } else {
kenton@google.com24bf56f2008-09-24 20:31:01 +00004346 AllocateOptions(proto.options(), result);
temporal40ee5512008-07-10 02:12:20 +00004347 }
4348
4349 // Again, enum values are weird because we makes them appear as siblings
4350 // of the enum type instead of children of it. So, we use
4351 // parent->containing_type() as the value's parent.
temporalf2063512008-07-23 01:19:07 +00004352 bool added_to_outer_scope =
4353 AddSymbol(result->full_name(), parent->containing_type(), result->name(),
4354 proto, Symbol(result));
temporal40ee5512008-07-10 02:12:20 +00004355
4356 // However, we also want to be able to search for values within a single
4357 // enum type, so we add it as a child of the enum type itself, too.
4358 // Note: This could fail, but if it does, the error has already been
4359 // reported by the above AddSymbol() call, so we ignore the return code.
temporalf2063512008-07-23 01:19:07 +00004360 bool added_to_inner_scope =
kenton@google.comd37d46d2009-04-25 02:53:47 +00004361 file_tables_->AddAliasUnderParent(parent, result->name(), Symbol(result));
temporalf2063512008-07-23 01:19:07 +00004362
4363 if (added_to_inner_scope && !added_to_outer_scope) {
4364 // This value did not conflict with any values defined in the same enum,
4365 // but it did conflict with some other symbol defined in the enum type's
4366 // scope. Let's print an additional error to explain this.
4367 string outer_scope;
4368 if (parent->containing_type() == NULL) {
4369 outer_scope = file_->package();
4370 } else {
4371 outer_scope = parent->containing_type()->full_name();
4372 }
4373
4374 if (outer_scope.empty()) {
4375 outer_scope = "the global scope";
4376 } else {
4377 outer_scope = "\"" + outer_scope + "\"";
4378 }
4379
4380 AddError(result->full_name(), proto,
4381 DescriptorPool::ErrorCollector::NAME,
4382 "Note that enum values use C++ scoping rules, meaning that "
4383 "enum values are siblings of their type, not children of it. "
4384 "Therefore, \"" + result->name() + "\" must be unique within "
4385 + outer_scope + ", not just within \"" + parent->name() + "\".");
4386 }
temporal40ee5512008-07-10 02:12:20 +00004387
4388 // An enum is allowed to define two numbers that refer to the same value.
4389 // FindValueByNumber() should return the first such value, so we simply
4390 // ignore AddEnumValueByNumber()'s return code.
kenton@google.comd37d46d2009-04-25 02:53:47 +00004391 file_tables_->AddEnumValueByNumber(result);
temporal40ee5512008-07-10 02:12:20 +00004392}
4393
4394void DescriptorBuilder::BuildService(const ServiceDescriptorProto& proto,
liujisi@google.comc5553a32014-05-28 21:48:28 +00004395 const void* /* dummy */,
temporal40ee5512008-07-10 02:12:20 +00004396 ServiceDescriptor* result) {
4397 string* full_name = tables_->AllocateString(file_->package());
4398 if (!full_name->empty()) full_name->append(1, '.');
4399 full_name->append(proto.name());
4400
4401 ValidateSymbolName(proto.name(), *full_name, proto);
4402
4403 result->name_ = tables_->AllocateString(proto.name());
4404 result->full_name_ = full_name;
4405 result->file_ = file_;
4406
4407 BUILD_ARRAY(proto, result, method, BuildMethod, result);
4408
4409 // Copy options.
4410 if (!proto.has_options()) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00004411 result->options_ = NULL; // Will set to default_instance later.
temporal40ee5512008-07-10 02:12:20 +00004412 } else {
kenton@google.com24bf56f2008-09-24 20:31:01 +00004413 AllocateOptions(proto.options(), result);
temporal40ee5512008-07-10 02:12:20 +00004414 }
4415
4416 AddSymbol(result->full_name(), NULL, result->name(),
4417 proto, Symbol(result));
4418}
4419
4420void DescriptorBuilder::BuildMethod(const MethodDescriptorProto& proto,
4421 const ServiceDescriptor* parent,
4422 MethodDescriptor* result) {
4423 result->name_ = tables_->AllocateString(proto.name());
4424 result->service_ = parent;
4425
4426 string* full_name = tables_->AllocateString(parent->full_name());
4427 full_name->append(1, '.');
4428 full_name->append(*result->name_);
4429 result->full_name_ = full_name;
4430
4431 ValidateSymbolName(proto.name(), *full_name, proto);
4432
4433 // These will be filled in when cross-linking.
4434 result->input_type_ = NULL;
4435 result->output_type_ = NULL;
4436
4437 // Copy options.
4438 if (!proto.has_options()) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00004439 result->options_ = NULL; // Will set to default_instance later.
temporal40ee5512008-07-10 02:12:20 +00004440 } else {
kenton@google.com24bf56f2008-09-24 20:31:01 +00004441 AllocateOptions(proto.options(), result);
temporal40ee5512008-07-10 02:12:20 +00004442 }
4443
Feng Xiao99aa0f92014-11-20 16:18:53 -08004444 result->client_streaming_ = proto.client_streaming();
4445 result->server_streaming_ = proto.server_streaming();
4446
temporal40ee5512008-07-10 02:12:20 +00004447 AddSymbol(result->full_name(), parent, result->name(),
4448 proto, Symbol(result));
4449}
4450
4451#undef BUILD_ARRAY
4452
4453// -------------------------------------------------------------------
4454
4455void DescriptorBuilder::CrossLinkFile(
4456 FileDescriptor* file, const FileDescriptorProto& proto) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00004457 if (file->options_ == NULL) {
4458 file->options_ = &FileOptions::default_instance();
4459 }
4460
temporal40ee5512008-07-10 02:12:20 +00004461 for (int i = 0; i < file->message_type_count(); i++) {
4462 CrossLinkMessage(&file->message_types_[i], proto.message_type(i));
4463 }
4464
4465 for (int i = 0; i < file->extension_count(); i++) {
4466 CrossLinkField(&file->extensions_[i], proto.extension(i));
4467 }
4468
kenton@google.com24bf56f2008-09-24 20:31:01 +00004469 for (int i = 0; i < file->enum_type_count(); i++) {
4470 CrossLinkEnum(&file->enum_types_[i], proto.enum_type(i));
4471 }
4472
temporal40ee5512008-07-10 02:12:20 +00004473 for (int i = 0; i < file->service_count(); i++) {
4474 CrossLinkService(&file->services_[i], proto.service(i));
4475 }
4476}
4477
4478void DescriptorBuilder::CrossLinkMessage(
4479 Descriptor* message, const DescriptorProto& proto) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00004480 if (message->options_ == NULL) {
4481 message->options_ = &MessageOptions::default_instance();
4482 }
4483
temporal40ee5512008-07-10 02:12:20 +00004484 for (int i = 0; i < message->nested_type_count(); i++) {
4485 CrossLinkMessage(&message->nested_types_[i], proto.nested_type(i));
4486 }
4487
kenton@google.com24bf56f2008-09-24 20:31:01 +00004488 for (int i = 0; i < message->enum_type_count(); i++) {
4489 CrossLinkEnum(&message->enum_types_[i], proto.enum_type(i));
4490 }
4491
temporal40ee5512008-07-10 02:12:20 +00004492 for (int i = 0; i < message->field_count(); i++) {
4493 CrossLinkField(&message->fields_[i], proto.field(i));
4494 }
4495
4496 for (int i = 0; i < message->extension_count(); i++) {
4497 CrossLinkField(&message->extensions_[i], proto.extension(i));
4498 }
jieluo@google.com4de8f552014-07-18 00:47:59 +00004499
4500 // Set up field array for each oneof.
4501
4502 // First count the number of fields per oneof.
4503 for (int i = 0; i < message->field_count(); i++) {
4504 const OneofDescriptor* oneof_decl = message->field(i)->containing_oneof();
4505 if (oneof_decl != NULL) {
4506 // Must go through oneof_decls_ array to get a non-const version of the
4507 // OneofDescriptor.
4508 ++message->oneof_decls_[oneof_decl->index()].field_count_;
4509 }
4510 }
4511
4512 // Then allocate the arrays.
4513 for (int i = 0; i < message->oneof_decl_count(); i++) {
4514 OneofDescriptor* oneof_decl = &message->oneof_decls_[i];
4515
4516 if (oneof_decl->field_count() == 0) {
4517 AddError(message->full_name() + "." + oneof_decl->name(),
4518 proto.oneof_decl(i),
4519 DescriptorPool::ErrorCollector::NAME,
4520 "Oneof must have at least one field.");
4521 }
4522
4523 oneof_decl->fields_ =
4524 tables_->AllocateArray<const FieldDescriptor*>(oneof_decl->field_count_);
4525 oneof_decl->field_count_ = 0;
4526 }
4527
4528 // Then fill them in.
4529 for (int i = 0; i < message->field_count(); i++) {
4530 const OneofDescriptor* oneof_decl = message->field(i)->containing_oneof();
4531 if (oneof_decl != NULL) {
4532 OneofDescriptor* mutable_oneof_decl =
4533 &message->oneof_decls_[oneof_decl->index()];
4534 message->fields_[i].index_in_oneof_ = mutable_oneof_decl->field_count_;
4535 mutable_oneof_decl->fields_[mutable_oneof_decl->field_count_++] =
4536 message->field(i);
4537 }
4538 }
temporal40ee5512008-07-10 02:12:20 +00004539}
4540
4541void DescriptorBuilder::CrossLinkField(
4542 FieldDescriptor* field, const FieldDescriptorProto& proto) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00004543 if (field->options_ == NULL) {
4544 field->options_ = &FieldOptions::default_instance();
4545 }
4546
temporal40ee5512008-07-10 02:12:20 +00004547 if (proto.has_extendee()) {
kenton@google.comd37d46d2009-04-25 02:53:47 +00004548 Symbol extendee = LookupSymbol(proto.extendee(), field->full_name(),
4549 PLACEHOLDER_EXTENDABLE_MESSAGE);
temporal40ee5512008-07-10 02:12:20 +00004550 if (extendee.IsNull()) {
4551 AddNotDefinedError(field->full_name(), proto,
4552 DescriptorPool::ErrorCollector::EXTENDEE,
4553 proto.extendee());
4554 return;
4555 } else if (extendee.type != Symbol::MESSAGE) {
4556 AddError(field->full_name(), proto,
4557 DescriptorPool::ErrorCollector::EXTENDEE,
4558 "\"" + proto.extendee() + "\" is not a message type.");
4559 return;
4560 }
4561 field->containing_type_ = extendee.descriptor;
4562
jieluo@google.com4de8f552014-07-18 00:47:59 +00004563 const Descriptor::ExtensionRange* extension_range = field->containing_type()
4564 ->FindExtensionRangeContainingNumber(field->number());
4565
4566 if (extension_range == NULL) {
temporal40ee5512008-07-10 02:12:20 +00004567 AddError(field->full_name(), proto,
4568 DescriptorPool::ErrorCollector::NUMBER,
4569 strings::Substitute("\"$0\" does not declare $1 as an "
4570 "extension number.",
4571 field->containing_type()->full_name(),
4572 field->number()));
4573 }
4574 }
4575
jieluo@google.com4de8f552014-07-18 00:47:59 +00004576 if (field->containing_oneof() != NULL) {
4577 if (field->label() != FieldDescriptor::LABEL_OPTIONAL) {
4578 // Note that this error will never happen when parsing .proto files.
4579 // It can only happen if you manually construct a FileDescriptorProto
4580 // that is incorrect.
4581 AddError(field->full_name(), proto,
4582 DescriptorPool::ErrorCollector::NAME,
4583 "Fields of oneofs must themselves have label LABEL_OPTIONAL.");
4584 }
4585 }
4586
temporal40ee5512008-07-10 02:12:20 +00004587 if (proto.has_type_name()) {
kenton@google.comd37d46d2009-04-25 02:53:47 +00004588 // Assume we are expecting a message type unless the proto contains some
4589 // evidence that it expects an enum type. This only makes a difference if
4590 // we end up creating a placeholder.
4591 bool expecting_enum = (proto.type() == FieldDescriptorProto::TYPE_ENUM) ||
4592 proto.has_default_value();
4593
4594 Symbol type =
4595 LookupSymbol(proto.type_name(), field->full_name(),
4596 expecting_enum ? PLACEHOLDER_ENUM : PLACEHOLDER_MESSAGE,
4597 LOOKUP_TYPES);
4598
jieluo@google.com4de8f552014-07-18 00:47:59 +00004599 // If the type is a weak type, we change the type to a google.protobuf.Empty field.
4600 if (type.IsNull() && !pool_->enforce_weak_ && proto.options().weak()) {
4601 type = FindSymbol(kNonLinkedWeakMessageReplacementName);
4602 }
4603
temporal40ee5512008-07-10 02:12:20 +00004604 if (type.IsNull()) {
4605 AddNotDefinedError(field->full_name(), proto,
4606 DescriptorPool::ErrorCollector::TYPE,
4607 proto.type_name());
4608 return;
4609 }
4610
4611 if (!proto.has_type()) {
4612 // Choose field type based on symbol.
4613 if (type.type == Symbol::MESSAGE) {
4614 field->type_ = FieldDescriptor::TYPE_MESSAGE;
4615 } else if (type.type == Symbol::ENUM) {
4616 field->type_ = FieldDescriptor::TYPE_ENUM;
4617 } else {
4618 AddError(field->full_name(), proto,
4619 DescriptorPool::ErrorCollector::TYPE,
4620 "\"" + proto.type_name() + "\" is not a type.");
4621 return;
4622 }
4623 }
4624
4625 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
4626 if (type.type != Symbol::MESSAGE) {
4627 AddError(field->full_name(), proto,
4628 DescriptorPool::ErrorCollector::TYPE,
4629 "\"" + proto.type_name() + "\" is not a message type.");
4630 return;
4631 }
4632 field->message_type_ = type.descriptor;
4633
4634 if (field->has_default_value()) {
4635 AddError(field->full_name(), proto,
4636 DescriptorPool::ErrorCollector::DEFAULT_VALUE,
4637 "Messages can't have default values.");
4638 }
4639 } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
4640 if (type.type != Symbol::ENUM) {
4641 AddError(field->full_name(), proto,
4642 DescriptorPool::ErrorCollector::TYPE,
4643 "\"" + proto.type_name() + "\" is not an enum type.");
4644 return;
4645 }
4646 field->enum_type_ = type.enum_descriptor;
4647
kenton@google.comd37d46d2009-04-25 02:53:47 +00004648 if (field->enum_type()->is_placeholder_) {
4649 // We can't look up default values for placeholder types. We'll have
4650 // to just drop them.
4651 field->has_default_value_ = false;
4652 }
4653
temporal40ee5512008-07-10 02:12:20 +00004654 if (field->has_default_value()) {
jieluo@google.com4de8f552014-07-18 00:47:59 +00004655 // Ensure that the default value is an identifier. Parser cannot always
4656 // verify this because it does not have complete type information.
4657 // N.B. that this check yields better error messages but is not
4658 // necessary for correctness (an enum symbol must be a valid identifier
4659 // anyway), only for better errors.
4660 if (!io::Tokenizer::IsIdentifier(proto.default_value())) {
temporal40ee5512008-07-10 02:12:20 +00004661 AddError(field->full_name(), proto,
4662 DescriptorPool::ErrorCollector::DEFAULT_VALUE,
jieluo@google.com4de8f552014-07-18 00:47:59 +00004663 "Default value for an enum field must be an identifier.");
4664 } else {
4665 // We can't just use field->enum_type()->FindValueByName() here
4666 // because that locks the pool's mutex, which we have already locked
4667 // at this point.
4668 Symbol default_value =
4669 LookupSymbolNoPlaceholder(proto.default_value(),
4670 field->enum_type()->full_name());
4671
4672 if (default_value.type == Symbol::ENUM_VALUE &&
4673 default_value.enum_value_descriptor->type() ==
4674 field->enum_type()) {
4675 field->default_value_enum_ = default_value.enum_value_descriptor;
4676 } else {
4677 AddError(field->full_name(), proto,
4678 DescriptorPool::ErrorCollector::DEFAULT_VALUE,
4679 "Enum type \"" + field->enum_type()->full_name() +
4680 "\" has no value named \"" + proto.default_value() +
4681 "\".");
4682 }
temporal40ee5512008-07-10 02:12:20 +00004683 }
4684 } else if (field->enum_type()->value_count() > 0) {
4685 // All enums must have at least one value, or we would have reported
4686 // an error elsewhere. We use the first defined value as the default
4687 // if a default is not explicitly defined.
4688 field->default_value_enum_ = field->enum_type()->value(0);
4689 }
4690 } else {
4691 AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
4692 "Field with primitive type has type_name.");
4693 }
4694 } else {
4695 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
4696 field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
4697 AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
4698 "Field with message or enum type missing type_name.");
4699 }
4700 }
4701
temporal40ee5512008-07-10 02:12:20 +00004702 // Add the field to the fields-by-number table.
4703 // Note: We have to do this *after* cross-linking because extensions do not
4704 // know their containing type until now.
kenton@google.comd37d46d2009-04-25 02:53:47 +00004705 if (!file_tables_->AddFieldByNumber(field)) {
temporal40ee5512008-07-10 02:12:20 +00004706 const FieldDescriptor* conflicting_field =
kenton@google.comd37d46d2009-04-25 02:53:47 +00004707 file_tables_->FindFieldByNumber(field->containing_type(),
4708 field->number());
temporal40ee5512008-07-10 02:12:20 +00004709 if (field->is_extension()) {
4710 AddError(field->full_name(), proto,
4711 DescriptorPool::ErrorCollector::NUMBER,
4712 strings::Substitute("Extension number $0 has already been used "
4713 "in \"$1\" by extension \"$2\".",
4714 field->number(),
4715 field->containing_type()->full_name(),
4716 conflicting_field->full_name()));
4717 } else {
4718 AddError(field->full_name(), proto,
4719 DescriptorPool::ErrorCollector::NUMBER,
4720 strings::Substitute("Field number $0 has already been used in "
4721 "\"$1\" by field \"$2\".",
4722 field->number(),
4723 field->containing_type()->full_name(),
4724 conflicting_field->name()));
4725 }
jieluo@google.com4de8f552014-07-18 00:47:59 +00004726 } else {
4727 if (field->is_extension()) {
4728 if (!tables_->AddExtension(field)) {
4729 const FieldDescriptor* conflicting_field =
4730 tables_->FindExtension(field->containing_type(), field->number());
4731 string error_msg = strings::Substitute(
4732 "Extension number $0 has already been used in \"$1\" by extension "
4733 "\"$2\" defined in $3.",
4734 field->number(),
4735 field->containing_type()->full_name(),
4736 conflicting_field->full_name(),
4737 conflicting_field->file()->name());
4738 // Conflicting extension numbers should be an error. However, before
4739 // turning this into an error we need to fix all existing broken
4740 // protos first.
4741 // TODO(xiaofeng): Change this to an error.
4742 AddWarning(field->full_name(), proto,
4743 DescriptorPool::ErrorCollector::NUMBER, error_msg);
4744 }
4745 }
kenton@google.comd37d46d2009-04-25 02:53:47 +00004746 }
4747
kenton@google.com2d6daa72009-01-22 01:27:00 +00004748 // Add the field to the lowercase-name and camelcase-name tables.
kenton@google.comd37d46d2009-04-25 02:53:47 +00004749 file_tables_->AddFieldByStylizedNames(field);
kenton@google.com24bf56f2008-09-24 20:31:01 +00004750}
temporal40ee5512008-07-10 02:12:20 +00004751
kenton@google.com24bf56f2008-09-24 20:31:01 +00004752void DescriptorBuilder::CrossLinkEnum(
4753 EnumDescriptor* enum_type, const EnumDescriptorProto& proto) {
4754 if (enum_type->options_ == NULL) {
4755 enum_type->options_ = &EnumOptions::default_instance();
4756 }
4757
4758 for (int i = 0; i < enum_type->value_count(); i++) {
4759 CrossLinkEnumValue(&enum_type->values_[i], proto.value(i));
4760 }
4761}
4762
4763void DescriptorBuilder::CrossLinkEnumValue(
liujisi@google.comc5553a32014-05-28 21:48:28 +00004764 EnumValueDescriptor* enum_value,
4765 const EnumValueDescriptorProto& /* proto */) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00004766 if (enum_value->options_ == NULL) {
4767 enum_value->options_ = &EnumValueOptions::default_instance();
temporal40ee5512008-07-10 02:12:20 +00004768 }
4769}
4770
4771void DescriptorBuilder::CrossLinkService(
4772 ServiceDescriptor* service, const ServiceDescriptorProto& proto) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00004773 if (service->options_ == NULL) {
4774 service->options_ = &ServiceOptions::default_instance();
4775 }
4776
temporal40ee5512008-07-10 02:12:20 +00004777 for (int i = 0; i < service->method_count(); i++) {
4778 CrossLinkMethod(&service->methods_[i], proto.method(i));
4779 }
4780}
4781
4782void DescriptorBuilder::CrossLinkMethod(
4783 MethodDescriptor* method, const MethodDescriptorProto& proto) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00004784 if (method->options_ == NULL) {
4785 method->options_ = &MethodOptions::default_instance();
4786 }
4787
temporal40ee5512008-07-10 02:12:20 +00004788 Symbol input_type = LookupSymbol(proto.input_type(), method->full_name());
4789 if (input_type.IsNull()) {
4790 AddNotDefinedError(method->full_name(), proto,
4791 DescriptorPool::ErrorCollector::INPUT_TYPE,
4792 proto.input_type());
4793 } else if (input_type.type != Symbol::MESSAGE) {
4794 AddError(method->full_name(), proto,
4795 DescriptorPool::ErrorCollector::INPUT_TYPE,
4796 "\"" + proto.input_type() + "\" is not a message type.");
4797 } else {
4798 method->input_type_ = input_type.descriptor;
4799 }
4800
4801 Symbol output_type = LookupSymbol(proto.output_type(), method->full_name());
4802 if (output_type.IsNull()) {
4803 AddNotDefinedError(method->full_name(), proto,
4804 DescriptorPool::ErrorCollector::OUTPUT_TYPE,
4805 proto.output_type());
4806 } else if (output_type.type != Symbol::MESSAGE) {
4807 AddError(method->full_name(), proto,
4808 DescriptorPool::ErrorCollector::OUTPUT_TYPE,
4809 "\"" + proto.output_type() + "\" is not a message type.");
4810 } else {
4811 method->output_type_ = output_type.descriptor;
4812 }
4813}
4814
kenton@google.com24bf56f2008-09-24 20:31:01 +00004815// -------------------------------------------------------------------
4816
4817#define VALIDATE_OPTIONS_FROM_ARRAY(descriptor, array_name, type) \
4818 for (int i = 0; i < descriptor->array_name##_count(); ++i) { \
4819 Validate##type##Options(descriptor->array_name##s_ + i, \
4820 proto.array_name(i)); \
4821 }
4822
kenton@google.com80b1d622009-07-29 01:13:20 +00004823// Determine if the file uses optimize_for = LITE_RUNTIME, being careful to
4824// avoid problems that exist at init time.
4825static bool IsLite(const FileDescriptor* file) {
4826 // TODO(kenton): I don't even remember how many of these conditions are
4827 // actually possible. I'm just being super-safe.
4828 return file != NULL &&
kenton@google.com80b1d622009-07-29 01:13:20 +00004829 &file->options() != &FileOptions::default_instance() &&
4830 file->options().optimize_for() == FileOptions::LITE_RUNTIME;
4831}
4832
kenton@google.com24bf56f2008-09-24 20:31:01 +00004833void DescriptorBuilder::ValidateFileOptions(FileDescriptor* file,
4834 const FileDescriptorProto& proto) {
4835 VALIDATE_OPTIONS_FROM_ARRAY(file, message_type, Message);
4836 VALIDATE_OPTIONS_FROM_ARRAY(file, enum_type, Enum);
4837 VALIDATE_OPTIONS_FROM_ARRAY(file, service, Service);
4838 VALIDATE_OPTIONS_FROM_ARRAY(file, extension, Field);
kenton@google.com80b1d622009-07-29 01:13:20 +00004839
4840 // Lite files can only be imported by other Lite files.
4841 if (!IsLite(file)) {
4842 for (int i = 0; i < file->dependency_count(); i++) {
4843 if (IsLite(file->dependency(i))) {
4844 AddError(
4845 file->name(), proto,
4846 DescriptorPool::ErrorCollector::OTHER,
4847 "Files that do not use optimize_for = LITE_RUNTIME cannot import "
4848 "files which do use this option. This file is not lite, but it "
4849 "imports \"" + file->dependency(i)->name() + "\" which is.");
4850 break;
4851 }
4852 }
4853 }
Feng Xiao6ef984a2014-11-10 17:34:54 -08004854 if (file->syntax() == FileDescriptor::SYNTAX_PROTO3) {
4855 ValidateProto3(file, proto);
4856 }
kenton@google.com24bf56f2008-09-24 20:31:01 +00004857}
4858
Feng Xiao6ef984a2014-11-10 17:34:54 -08004859void DescriptorBuilder::ValidateProto3(
4860 FileDescriptor* file, const FileDescriptorProto& proto) {
4861 for (int i = 0; i < file->extension_count(); ++i) {
4862 ValidateProto3Field(file->extensions_ + i, proto.extension(i));
4863 }
4864 for (int i = 0; i < file->message_type_count(); ++i) {
4865 ValidateProto3Message(file->message_types_ + i, proto.message_type(i));
4866 }
4867 for (int i = 0; i < file->enum_type_count(); ++i) {
4868 ValidateProto3Enum(file->enum_types_ + i, proto.enum_type(i));
4869 }
4870 if (IsLite(file)) {
4871 AddError(file->name(), proto,
4872 DescriptorPool::ErrorCollector::OTHER,
4873 "Lite runtime is not supported in proto3.");
4874 }
4875}
4876
4877void DescriptorBuilder::ValidateProto3Message(
4878 Descriptor* message, const DescriptorProto& proto) {
4879 for (int i = 0; i < message->nested_type_count(); ++i) {
4880 ValidateProto3Message(message->nested_types_ + i,
4881 proto.nested_type(i));
4882 }
4883 for (int i = 0; i < message->enum_type_count(); ++i) {
4884 ValidateProto3Enum(message->enum_types_ + i,
4885 proto.enum_type(i));
4886 }
4887 for (int i = 0; i < message->field_count(); ++i) {
4888 ValidateProto3Field(message->fields_ + i, proto.field(i));
4889 }
4890 for (int i = 0; i < message->extension_count(); ++i) {
4891 ValidateProto3Field(message->extensions_ +i, proto.extension(i));
4892 }
4893 if (message->extension_range_count() > 0) {
4894 AddError(message->full_name(), proto,
4895 DescriptorPool::ErrorCollector::OTHER,
4896 "Extension ranges are not allowed in proto3.");
4897 }
4898 if (message->options().message_set_wire_format()) {
4899 // Using MessageSet doesn't make sense since we disallow extensions.
4900 AddError(message->full_name(), proto,
4901 DescriptorPool::ErrorCollector::OTHER,
4902 "MessageSet is not supported in proto3.");
4903 }
4904}
4905
4906void DescriptorBuilder::ValidateProto3Field(
4907 FieldDescriptor* field, const FieldDescriptorProto& proto) {
4908 if (field->is_extension() &&
4909 !AllowedExtendeeInProto3(field->containing_type()->full_name())) {
4910 AddError(field->full_name(), proto,
4911 DescriptorPool::ErrorCollector::OTHER,
4912 "Extensions in proto3 are only allowed for defining options.");
4913 }
4914 if (field->is_required()) {
4915 AddError(field->full_name(), proto,
4916 DescriptorPool::ErrorCollector::OTHER,
4917 "Required fields are not allowed in proto3.");
4918 }
4919 if (field->has_default_value()) {
4920 AddError(
4921 field->full_name(), proto, DescriptorPool::ErrorCollector::OTHER,
4922 "Explicit default values are not allowed in proto3.");
4923 }
4924 if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
4925 field->enum_type() &&
4926 field->enum_type()->file()->syntax() != FileDescriptor::SYNTAX_PROTO3) {
4927 // Proto3 messages can only use Proto3 enum types; otherwise we can't
4928 // guarantee that the default value is zero.
4929 AddError(field->full_name(), proto,
4930 DescriptorPool::ErrorCollector::TYPE,
4931 "Enum type \"" + field->enum_type()->full_name() +
4932 "\" is not a proto3 enum, but is used in \"" +
4933 field->containing_type()->full_name() +
4934 "\" which is a proto3 message type.");
4935 }
4936}
4937
4938void DescriptorBuilder::ValidateProto3Enum(
4939 EnumDescriptor* enm, const EnumDescriptorProto& proto) {
4940 if (enm->value_count() > 0 && enm->value(0)->number() != 0) {
4941 AddError(
4942 enm->full_name(), proto, DescriptorPool::ErrorCollector::OTHER,
4943 "The first enum value must be zero in proto3.");
4944 }
4945}
jieluo@google.com4de8f552014-07-18 00:47:59 +00004946
kenton@google.com24bf56f2008-09-24 20:31:01 +00004947void DescriptorBuilder::ValidateMessageOptions(Descriptor* message,
4948 const DescriptorProto& proto) {
4949 VALIDATE_OPTIONS_FROM_ARRAY(message, field, Field);
4950 VALIDATE_OPTIONS_FROM_ARRAY(message, nested_type, Message);
4951 VALIDATE_OPTIONS_FROM_ARRAY(message, enum_type, Enum);
4952 VALIDATE_OPTIONS_FROM_ARRAY(message, extension, Field);
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00004953
4954 const int64 max_extension_range =
4955 static_cast<int64>(message->options().message_set_wire_format() ?
4956 kint32max :
4957 FieldDescriptor::kMaxNumber);
4958 for (int i = 0; i < message->extension_range_count(); ++i) {
4959 if (message->extension_range(i)->end > max_extension_range + 1) {
4960 AddError(
4961 message->full_name(), proto.extension_range(i),
4962 DescriptorPool::ErrorCollector::NUMBER,
4963 strings::Substitute("Extension numbers cannot be greater than $0.",
4964 max_extension_range));
4965 }
4966 }
kenton@google.com24bf56f2008-09-24 20:31:01 +00004967}
4968
4969void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field,
temporal40ee5512008-07-10 02:12:20 +00004970 const FieldDescriptorProto& proto) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00004971 // Only message type fields may be lazy.
4972 if (field->options().lazy()) {
4973 if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
4974 AddError(field->full_name(), proto,
4975 DescriptorPool::ErrorCollector::TYPE,
4976 "[lazy = true] can only be specified for submessage fields.");
4977 }
4978 }
4979
kenton@google.com2d6daa72009-01-22 01:27:00 +00004980 // Only repeated primitive fields may be packed.
kenton@google.comfccb1462009-12-18 02:11:36 +00004981 if (field->options().packed() && !field->is_packable()) {
4982 AddError(
4983 field->full_name(), proto,
4984 DescriptorPool::ErrorCollector::TYPE,
4985 "[packed = true] can only be specified for repeated primitive fields.");
kenton@google.com2d6daa72009-01-22 01:27:00 +00004986 }
4987
kenton@google.com24bf56f2008-09-24 20:31:01 +00004988 // Note: Default instance may not yet be initialized here, so we have to
4989 // avoid reading from it.
4990 if (field->containing_type_ != NULL &&
4991 &field->containing_type()->options() !=
4992 &MessageOptions::default_instance() &&
4993 field->containing_type()->options().message_set_wire_format()) {
4994 if (field->is_extension()) {
4995 if (!field->is_optional() ||
4996 field->type() != FieldDescriptor::TYPE_MESSAGE) {
4997 AddError(field->full_name(), proto,
4998 DescriptorPool::ErrorCollector::TYPE,
4999 "Extensions of MessageSets must be optional messages.");
5000 }
5001 } else {
5002 AddError(field->full_name(), proto,
5003 DescriptorPool::ErrorCollector::NAME,
5004 "MessageSets cannot have fields, only extensions.");
5005 }
5006 }
kenton@google.com80b1d622009-07-29 01:13:20 +00005007
5008 // Lite extensions can only be of Lite types.
5009 if (IsLite(field->file()) &&
5010 field->containing_type_ != NULL &&
5011 !IsLite(field->containing_type()->file())) {
5012 AddError(field->full_name(), proto,
5013 DescriptorPool::ErrorCollector::EXTENDEE,
5014 "Extensions to non-lite types can only be declared in non-lite "
5015 "files. Note that you cannot extend a non-lite type to contain "
5016 "a lite type, but the reverse is allowed.");
5017 }
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00005018
Feng Xiao6ef984a2014-11-10 17:34:54 -08005019 // Validate map types.
Feng Xiaof157a562014-11-14 11:50:31 -08005020 if (field->is_map()) {
Feng Xiao6ef984a2014-11-10 17:34:54 -08005021 if (!ValidateMapEntry(field, proto)) {
5022 AddError(field->full_name(), proto,
5023 DescriptorPool::ErrorCollector::OTHER,
5024 "map_entry should not be set explicitly. Use map<KeyType, "
5025 "ValueType> instead.");
5026 }
5027 }
5028
kenton@google.com24bf56f2008-09-24 20:31:01 +00005029}
5030
5031void DescriptorBuilder::ValidateEnumOptions(EnumDescriptor* enm,
5032 const EnumDescriptorProto& proto) {
5033 VALIDATE_OPTIONS_FROM_ARRAY(enm, value, EnumValue);
liujisi@google.comcb77c4c2012-12-28 23:41:54 +00005034 if (!enm->options().has_allow_alias() || !enm->options().allow_alias()) {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00005035 map<int, string> used_values;
5036 for (int i = 0; i < enm->value_count(); ++i) {
5037 const EnumValueDescriptor* enum_value = enm->value(i);
5038 if (used_values.find(enum_value->number()) != used_values.end()) {
liujisi@google.comcb77c4c2012-12-28 23:41:54 +00005039 string error =
5040 "\"" + enum_value->full_name() +
5041 "\" uses the same enum value as \"" +
5042 used_values[enum_value->number()] + "\". If this is intended, set "
5043 "'option allow_alias = true;' to the enum definition.";
5044 if (!enm->options().allow_alias()) {
5045 // Generate error if duplicated enum values are explicitly disallowed.
5046 AddError(enm->full_name(), proto,
5047 DescriptorPool::ErrorCollector::NUMBER,
5048 error);
5049 } else {
5050 // Generate warning if duplicated values are found but the option
5051 // isn't set.
5052 GOOGLE_LOG(ERROR) << error;
5053 }
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00005054 } else {
5055 used_values[enum_value->number()] = enum_value->full_name();
5056 }
5057 }
5058 }
kenton@google.com24bf56f2008-09-24 20:31:01 +00005059}
5060
5061void DescriptorBuilder::ValidateEnumValueOptions(
liujisi@google.comc5553a32014-05-28 21:48:28 +00005062 EnumValueDescriptor* /* enum_value */,
5063 const EnumValueDescriptorProto& /* proto */) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00005064 // Nothing to do so far.
5065}
5066void DescriptorBuilder::ValidateServiceOptions(ServiceDescriptor* service,
5067 const ServiceDescriptorProto& proto) {
kenton@google.comd09ab852010-04-19 19:15:12 +00005068 if (IsLite(service->file()) &&
5069 (service->file()->options().cc_generic_services() ||
5070 service->file()->options().java_generic_services())) {
kenton@google.com80b1d622009-07-29 01:13:20 +00005071 AddError(service->full_name(), proto,
5072 DescriptorPool::ErrorCollector::NAME,
kenton@google.comd09ab852010-04-19 19:15:12 +00005073 "Files with optimize_for = LITE_RUNTIME cannot define services "
5074 "unless you set both options cc_generic_services and "
5075 "java_generic_sevices to false.");
kenton@google.com80b1d622009-07-29 01:13:20 +00005076 }
5077
kenton@google.com24bf56f2008-09-24 20:31:01 +00005078 VALIDATE_OPTIONS_FROM_ARRAY(service, method, Method);
5079}
5080
liujisi@google.comc5553a32014-05-28 21:48:28 +00005081void DescriptorBuilder::ValidateMethodOptions(MethodDescriptor* /* method */,
5082 const MethodDescriptorProto& /* proto */) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00005083 // Nothing to do so far.
5084}
5085
Feng Xiao6ef984a2014-11-10 17:34:54 -08005086bool DescriptorBuilder::ValidateMapEntry(FieldDescriptor* field,
5087 const FieldDescriptorProto& proto) {
5088 const Descriptor* message = field->message_type();
5089 if (// Must not contain extensions, extension range or nested message or
5090 // enums
5091 message->extension_count() != 0 ||
5092 field->label() != FieldDescriptor::LABEL_REPEATED ||
5093 message->extension_range_count() != 0 ||
5094 message->nested_type_count() != 0 || message->enum_type_count() != 0 ||
5095 // Must contain exactly two fields
5096 message->field_count() != 2 ||
5097 // Field name and message name must match
5098 message->name() != ToCamelCase(field->name(), false) + "Entry" ||
5099 // Entry message must be in the same containing type of the field.
5100 field->containing_type() != message->containing_type()) {
5101 return false;
temporal40ee5512008-07-10 02:12:20 +00005102 }
5103
Feng Xiao6ef984a2014-11-10 17:34:54 -08005104 const FieldDescriptor* key = message->field(0);
5105 const FieldDescriptor* value = message->field(1);
5106 if (key->label() != FieldDescriptor::LABEL_OPTIONAL || key->number() != 1 ||
5107 key->name() != "key") {
5108 return false;
5109 }
5110 if (value->label() != FieldDescriptor::LABEL_OPTIONAL ||
5111 value->number() != 2 || value->name() != "value") {
5112 return false;
temporal40ee5512008-07-10 02:12:20 +00005113 }
5114
Feng Xiao6ef984a2014-11-10 17:34:54 -08005115 // Check key types are legal.
5116 switch (key->type()) {
5117 case FieldDescriptor::TYPE_ENUM:
5118 AddError(
5119 field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
5120 "Key in map fields cannot be enum types.");
5121 break;
5122 case FieldDescriptor::TYPE_FLOAT:
5123 case FieldDescriptor::TYPE_DOUBLE:
5124 case FieldDescriptor::TYPE_MESSAGE:
5125 case FieldDescriptor::TYPE_GROUP:
5126 case FieldDescriptor::TYPE_BYTES:
5127 AddError(
5128 field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
5129 "Key in map fields cannot be float/double, bytes or message types.");
5130 break;
5131 case FieldDescriptor::TYPE_BOOL:
5132 case FieldDescriptor::TYPE_INT32:
5133 case FieldDescriptor::TYPE_INT64:
5134 case FieldDescriptor::TYPE_SINT32:
5135 case FieldDescriptor::TYPE_SINT64:
5136 case FieldDescriptor::TYPE_STRING:
5137 case FieldDescriptor::TYPE_UINT32:
5138 case FieldDescriptor::TYPE_UINT64:
5139 case FieldDescriptor::TYPE_FIXED32:
5140 case FieldDescriptor::TYPE_FIXED64:
5141 case FieldDescriptor::TYPE_SFIXED32:
5142 case FieldDescriptor::TYPE_SFIXED64:
5143 // Legal cases
5144 break;
Jisi Liu885b6122015-02-28 14:51:22 -08005145 // Do not add a default, so that the compiler will complain when new types
Feng Xiao6ef984a2014-11-10 17:34:54 -08005146 // are added.
temporal40ee5512008-07-10 02:12:20 +00005147 }
5148
Feng Xiao6ef984a2014-11-10 17:34:54 -08005149 return true;
5150}
temporal40ee5512008-07-10 02:12:20 +00005151
Feng Xiao6ef984a2014-11-10 17:34:54 -08005152void DescriptorBuilder::DetectMapConflicts(const Descriptor* message,
5153 const DescriptorProto& proto) {
5154 map<string, const Descriptor*> seen_types;
5155 for (int i = 0; i < message->nested_type_count(); ++i) {
5156 const Descriptor* nested = message->nested_type(i);
5157 pair<map<string, const Descriptor*>::iterator, bool> result =
Jisi Liu885b6122015-02-28 14:51:22 -08005158 seen_types.insert(std::make_pair(nested->name(), nested));
Feng Xiao6ef984a2014-11-10 17:34:54 -08005159 if (!result.second) {
5160 if (result.first->second->options().map_entry() ||
5161 nested->options().map_entry()) {
5162 AddError(message->full_name(), proto,
5163 DescriptorPool::ErrorCollector::NAME,
5164 "Expanded map entry type " + nested->name() +
5165 " conflicts with an existing nested message type.");
5166 }
5167 }
5168 // Recursively test on the nested types.
5169 DetectMapConflicts(message->nested_type(i), proto.nested_type(i));
temporal40ee5512008-07-10 02:12:20 +00005170 }
Feng Xiao6ef984a2014-11-10 17:34:54 -08005171 // Check for conflicted field names.
5172 for (int i = 0; i < message->field_count(); ++i) {
5173 const FieldDescriptor* field = message->field(i);
5174 map<string, const Descriptor*>::iterator iter =
5175 seen_types.find(field->name());
5176 if (iter != seen_types.end() && iter->second->options().map_entry()) {
5177 AddError(message->full_name(), proto,
5178 DescriptorPool::ErrorCollector::NAME,
5179 "Expanded map entry type " + iter->second->name() +
5180 " conflicts with an existing field.");
5181 }
temporal40ee5512008-07-10 02:12:20 +00005182 }
Feng Xiao6ef984a2014-11-10 17:34:54 -08005183 // Check for conflicted enum names.
5184 for (int i = 0; i < message->enum_type_count(); ++i) {
5185 const EnumDescriptor* enum_desc = message->enum_type(i);
5186 map<string, const Descriptor*>::iterator iter =
5187 seen_types.find(enum_desc->name());
5188 if (iter != seen_types.end() && iter->second->options().map_entry()) {
5189 AddError(message->full_name(), proto,
5190 DescriptorPool::ErrorCollector::NAME,
5191 "Expanded map entry type " + iter->second->name() +
5192 " conflicts with an existing enum type.");
5193 }
temporal40ee5512008-07-10 02:12:20 +00005194 }
Feng Xiao6ef984a2014-11-10 17:34:54 -08005195 // Check for conflicted oneof names.
5196 for (int i = 0; i < message->oneof_decl_count(); ++i) {
5197 const OneofDescriptor* oneof_desc = message->oneof_decl(i);
5198 map<string, const Descriptor*>::iterator iter =
5199 seen_types.find(oneof_desc->name());
5200 if (iter != seen_types.end() && iter->second->options().map_entry()) {
5201 AddError(message->full_name(), proto,
5202 DescriptorPool::ErrorCollector::NAME,
5203 "Expanded map entry type " + iter->second->name() +
5204 " conflicts with an existing oneof type.");
5205 }
5206 }
temporal40ee5512008-07-10 02:12:20 +00005207}
5208
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00005209
kenton@google.com24bf56f2008-09-24 20:31:01 +00005210#undef VALIDATE_OPTIONS_FROM_ARRAY
5211
5212// -------------------------------------------------------------------
5213
5214DescriptorBuilder::OptionInterpreter::OptionInterpreter(
5215 DescriptorBuilder* builder) : builder_(builder) {
5216 GOOGLE_CHECK(builder_);
5217}
5218
5219DescriptorBuilder::OptionInterpreter::~OptionInterpreter() {
5220}
5221
5222bool DescriptorBuilder::OptionInterpreter::InterpretOptions(
5223 OptionsToInterpret* options_to_interpret) {
5224 // Note that these may be in different pools, so we can't use the same
5225 // descriptor and reflection objects on both.
5226 Message* options = options_to_interpret->options;
5227 const Message* original_options = options_to_interpret->original_options;
5228
5229 bool failed = false;
5230 options_to_interpret_ = options_to_interpret;
5231
kenton@google.comd37d46d2009-04-25 02:53:47 +00005232 // Find the uninterpreted_option field in the mutable copy of the options
5233 // and clear them, since we're about to interpret them.
5234 const FieldDescriptor* uninterpreted_options_field =
5235 options->GetDescriptor()->FindFieldByName("uninterpreted_option");
5236 GOOGLE_CHECK(uninterpreted_options_field != NULL)
5237 << "No field named \"uninterpreted_option\" in the Options proto.";
5238 options->GetReflection()->ClearField(options, uninterpreted_options_field);
5239
kenton@google.com24bf56f2008-09-24 20:31:01 +00005240 // Find the uninterpreted_option field in the original options.
5241 const FieldDescriptor* original_uninterpreted_options_field =
5242 original_options->GetDescriptor()->
5243 FindFieldByName("uninterpreted_option");
5244 GOOGLE_CHECK(original_uninterpreted_options_field != NULL)
5245 << "No field named \"uninterpreted_option\" in the Options proto.";
5246
5247 const int num_uninterpreted_options = original_options->GetReflection()->
5248 FieldSize(*original_options, original_uninterpreted_options_field);
5249 for (int i = 0; i < num_uninterpreted_options; ++i) {
kenton@google.com80b1d622009-07-29 01:13:20 +00005250 uninterpreted_option_ = down_cast<const UninterpretedOption*>(
kenton@google.com24bf56f2008-09-24 20:31:01 +00005251 &original_options->GetReflection()->GetRepeatedMessage(
5252 *original_options, original_uninterpreted_options_field, i));
5253 if (!InterpretSingleOption(options)) {
5254 // Error already added by InterpretSingleOption().
5255 failed = true;
5256 break;
5257 }
5258 }
5259 // Reset these, so we don't have any dangling pointers.
5260 uninterpreted_option_ = NULL;
5261 options_to_interpret_ = NULL;
5262
5263 if (!failed) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00005264 // InterpretSingleOption() added the interpreted options in the
5265 // UnknownFieldSet, in case the option isn't yet known to us. Now we
5266 // serialize the options message and deserialize it back. That way, any
5267 // option fields that we do happen to know about will get moved from the
5268 // UnknownFieldSet into the real fields, and thus be available right away.
5269 // If they are not known, that's OK too. They will get reparsed into the
5270 // UnknownFieldSet and wait there until the message is parsed by something
5271 // that does know about the options.
5272 string buf;
5273 options->AppendToString(&buf);
5274 GOOGLE_CHECK(options->ParseFromString(buf))
5275 << "Protocol message serialized itself in invalid fashion.";
5276 }
5277
5278 return !failed;
5279}
5280
5281bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption(
5282 Message* options) {
5283 // First do some basic validation.
5284 if (uninterpreted_option_->name_size() == 0) {
5285 // This should never happen unless the parser has gone seriously awry or
5286 // someone has manually created the uninterpreted option badly.
5287 return AddNameError("Option must have a name.");
5288 }
5289 if (uninterpreted_option_->name(0).name_part() == "uninterpreted_option") {
5290 return AddNameError("Option must not use reserved name "
5291 "\"uninterpreted_option\".");
5292 }
5293
5294 const Descriptor* options_descriptor = NULL;
5295 // Get the options message's descriptor from the builder's pool, so that we
5296 // get the version that knows about any extension options declared in the
5297 // file we're currently building. The descriptor should be there as long as
5298 // the file we're building imported "google/protobuf/descriptors.proto".
5299
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00005300 // Note that we use DescriptorBuilder::FindSymbolNotEnforcingDeps(), not
kenton@google.com24bf56f2008-09-24 20:31:01 +00005301 // DescriptorPool::FindMessageTypeByName() because we're already holding the
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00005302 // pool's mutex, and the latter method locks it again. We don't use
5303 // FindSymbol() because files that use custom options only need to depend on
5304 // the file that defines the option, not descriptor.proto itself.
kenton@google.com26bd9ee2008-11-21 00:06:27 +00005305 Symbol symbol = builder_->FindSymbolNotEnforcingDeps(
5306 options->GetDescriptor()->full_name());
kenton@google.com24bf56f2008-09-24 20:31:01 +00005307 if (!symbol.IsNull() && symbol.type == Symbol::MESSAGE) {
5308 options_descriptor = symbol.descriptor;
5309 } else {
5310 // The options message's descriptor was not in the builder's pool, so use
5311 // the standard version from the generated pool. We're not holding the
5312 // generated pool's mutex, so we can search it the straightforward way.
5313 options_descriptor = options->GetDescriptor();
5314 }
5315 GOOGLE_CHECK(options_descriptor);
5316
5317 // We iterate over the name parts to drill into the submessages until we find
5318 // the leaf field for the option. As we drill down we remember the current
5319 // submessage's descriptor in |descriptor| and the next field in that
5320 // submessage in |field|. We also track the fields we're drilling down
5321 // through in |intermediate_fields|. As we go, we reconstruct the full option
5322 // name in |debug_msg_name|, for use in error messages.
5323 const Descriptor* descriptor = options_descriptor;
5324 const FieldDescriptor* field = NULL;
5325 vector<const FieldDescriptor*> intermediate_fields;
5326 string debug_msg_name = "";
5327
5328 for (int i = 0; i < uninterpreted_option_->name_size(); ++i) {
5329 const string& name_part = uninterpreted_option_->name(i).name_part();
5330 if (debug_msg_name.size() > 0) {
5331 debug_msg_name += ".";
5332 }
5333 if (uninterpreted_option_->name(i).is_extension()) {
5334 debug_msg_name += "(" + name_part + ")";
5335 // Search for the extension's descriptor as an extension in the builder's
5336 // pool. Note that we use DescriptorBuilder::LookupSymbol(), not
5337 // DescriptorPool::FindExtensionByName(), for two reasons: 1) It allows
5338 // relative lookups, and 2) because we're already holding the pool's
5339 // mutex, and the latter method locks it again.
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00005340 symbol = builder_->LookupSymbol(name_part,
5341 options_to_interpret_->name_scope);
kenton@google.com24bf56f2008-09-24 20:31:01 +00005342 if (!symbol.IsNull() && symbol.type == Symbol::FIELD) {
5343 field = symbol.field_descriptor;
5344 }
5345 // If we don't find the field then the field's descriptor was not in the
5346 // builder's pool, but there's no point in looking in the generated
5347 // pool. We require that you import the file that defines any extensions
5348 // you use, so they must be present in the builder's pool.
5349 } else {
5350 debug_msg_name += name_part;
kenton@google.comd37d46d2009-04-25 02:53:47 +00005351 // Search for the field's descriptor as a regular field.
5352 field = descriptor->FindFieldByName(name_part);
kenton@google.com24bf56f2008-09-24 20:31:01 +00005353 }
5354
kenton@google.com26bd9ee2008-11-21 00:06:27 +00005355 if (field == NULL) {
kenton@google.comd37d46d2009-04-25 02:53:47 +00005356 if (get_allow_unknown(builder_->pool_)) {
5357 // We can't find the option, but AllowUnknownDependencies() is enabled,
5358 // so we will just leave it as uninterpreted.
5359 AddWithoutInterpreting(*uninterpreted_option_, options);
5360 return true;
jieluo@google.com4de8f552014-07-18 00:47:59 +00005361 } else if (!(builder_->undefine_resolved_name_).empty()) {
5362 // Option is resolved to a name which is not defined.
5363 return AddNameError(
5364 "Option \"" + debug_msg_name + "\" is resolved to \"(" +
5365 builder_->undefine_resolved_name_ +
5366 ")\", which is not defined. The innermost scope is searched first "
5367 "in name resolution. Consider using a leading '.'(i.e., \"(." +
5368 debug_msg_name.substr(1) +
5369 "\") to start from the outermost scope.");
kenton@google.comd37d46d2009-04-25 02:53:47 +00005370 } else {
5371 return AddNameError("Option \"" + debug_msg_name + "\" unknown.");
5372 }
kenton@google.com24bf56f2008-09-24 20:31:01 +00005373 } else if (field->containing_type() != descriptor) {
kenton@google.comd37d46d2009-04-25 02:53:47 +00005374 if (get_is_placeholder(field->containing_type())) {
5375 // The field is an extension of a placeholder type, so we can't
5376 // reliably verify whether it is a valid extension to use here (e.g.
5377 // we don't know if it is an extension of the correct *Options message,
5378 // or if it has a valid field number, etc.). Just leave it as
5379 // uninterpreted instead.
5380 AddWithoutInterpreting(*uninterpreted_option_, options);
5381 return true;
5382 } else {
5383 // This can only happen if, due to some insane misconfiguration of the
5384 // pools, we find the options message in one pool but the field in
5385 // another. This would probably imply a hefty bug somewhere.
5386 return AddNameError("Option field \"" + debug_msg_name +
5387 "\" is not a field or extension of message \"" +
5388 descriptor->name() + "\".");
5389 }
kenton@google.com24bf56f2008-09-24 20:31:01 +00005390 } else if (i < uninterpreted_option_->name_size() - 1) {
5391 if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
5392 return AddNameError("Option \"" + debug_msg_name +
5393 "\" is an atomic type, not a message.");
jieluo@google.com4de8f552014-07-18 00:47:59 +00005394 } else if (field->is_repeated()) {
5395 return AddNameError("Option field \"" + debug_msg_name +
5396 "\" is a repeated message. Repeated message "
5397 "options must be initialized using an "
5398 "aggregate value.");
kenton@google.com24bf56f2008-09-24 20:31:01 +00005399 } else {
5400 // Drill down into the submessage.
5401 intermediate_fields.push_back(field);
5402 descriptor = field->message_type();
5403 }
kenton@google.com24bf56f2008-09-24 20:31:01 +00005404 }
5405 }
5406
5407 // We've found the leaf field. Now we use UnknownFieldSets to set its value
5408 // on the options message. We do so because the message may not yet know
5409 // about its extension fields, so we may not be able to set the fields
5410 // directly. But the UnknownFieldSets will serialize to the same wire-format
5411 // message, so reading that message back in once the extension fields are
5412 // known will populate them correctly.
5413
5414 // First see if the option is already set.
jieluo@google.com4de8f552014-07-18 00:47:59 +00005415 if (!field->is_repeated() && !ExamineIfOptionIsSet(
kenton@google.com24bf56f2008-09-24 20:31:01 +00005416 intermediate_fields.begin(),
5417 intermediate_fields.end(),
5418 field, debug_msg_name,
5419 options->GetReflection()->GetUnknownFields(*options))) {
5420 return false; // ExamineIfOptionIsSet() already added the error.
5421 }
5422
5423
5424 // First set the value on the UnknownFieldSet corresponding to the
5425 // innermost message.
5426 scoped_ptr<UnknownFieldSet> unknown_fields(new UnknownFieldSet());
kenton@google.comd37d46d2009-04-25 02:53:47 +00005427 if (!SetOptionValue(field, unknown_fields.get())) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00005428 return false; // SetOptionValue() already added the error.
5429 }
5430
5431 // Now wrap the UnknownFieldSet with UnknownFieldSets corresponding to all
5432 // the intermediate messages.
5433 for (vector<const FieldDescriptor*>::reverse_iterator iter =
5434 intermediate_fields.rbegin();
5435 iter != intermediate_fields.rend(); ++iter) {
5436 scoped_ptr<UnknownFieldSet> parent_unknown_fields(new UnknownFieldSet());
5437 switch ((*iter)->type()) {
5438 case FieldDescriptor::TYPE_MESSAGE: {
5439 io::StringOutputStream outstr(
kenton@google.comd37d46d2009-04-25 02:53:47 +00005440 parent_unknown_fields->AddLengthDelimited((*iter)->number()));
kenton@google.com24bf56f2008-09-24 20:31:01 +00005441 io::CodedOutputStream out(&outstr);
kenton@google.comd37d46d2009-04-25 02:53:47 +00005442 internal::WireFormat::SerializeUnknownFields(*unknown_fields, &out);
5443 GOOGLE_CHECK(!out.HadError())
kenton@google.com24bf56f2008-09-24 20:31:01 +00005444 << "Unexpected failure while serializing option submessage "
5445 << debug_msg_name << "\".";
5446 break;
5447 }
5448
5449 case FieldDescriptor::TYPE_GROUP: {
kenton@google.comd37d46d2009-04-25 02:53:47 +00005450 parent_unknown_fields->AddGroup((*iter)->number())
5451 ->MergeFrom(*unknown_fields);
kenton@google.com24bf56f2008-09-24 20:31:01 +00005452 break;
5453 }
5454
5455 default:
5456 GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_MESSAGE: "
5457 << (*iter)->type();
5458 return false;
5459 }
5460 unknown_fields.reset(parent_unknown_fields.release());
5461 }
5462
5463 // Now merge the UnknownFieldSet corresponding to the top-level message into
5464 // the options message.
5465 options->GetReflection()->MutableUnknownFields(options)->MergeFrom(
5466 *unknown_fields);
5467
5468 return true;
5469}
5470
kenton@google.comd37d46d2009-04-25 02:53:47 +00005471void DescriptorBuilder::OptionInterpreter::AddWithoutInterpreting(
5472 const UninterpretedOption& uninterpreted_option, Message* options) {
5473 const FieldDescriptor* field =
5474 options->GetDescriptor()->FindFieldByName("uninterpreted_option");
5475 GOOGLE_CHECK(field != NULL);
5476
5477 options->GetReflection()->AddMessage(options, field)
5478 ->CopyFrom(uninterpreted_option);
5479}
5480
kenton@google.com24bf56f2008-09-24 20:31:01 +00005481bool DescriptorBuilder::OptionInterpreter::ExamineIfOptionIsSet(
5482 vector<const FieldDescriptor*>::const_iterator intermediate_fields_iter,
5483 vector<const FieldDescriptor*>::const_iterator intermediate_fields_end,
5484 const FieldDescriptor* innermost_field, const string& debug_msg_name,
5485 const UnknownFieldSet& unknown_fields) {
kenton@google.comd37d46d2009-04-25 02:53:47 +00005486 // We do linear searches of the UnknownFieldSet and its sub-groups. This
5487 // should be fine since it's unlikely that any one options structure will
5488 // contain more than a handful of options.
5489
kenton@google.com24bf56f2008-09-24 20:31:01 +00005490 if (intermediate_fields_iter == intermediate_fields_end) {
5491 // We're at the innermost submessage.
kenton@google.comd37d46d2009-04-25 02:53:47 +00005492 for (int i = 0; i < unknown_fields.field_count(); i++) {
5493 if (unknown_fields.field(i).number() == innermost_field->number()) {
5494 return AddNameError("Option \"" + debug_msg_name +
5495 "\" was already set.");
5496 }
kenton@google.com24bf56f2008-09-24 20:31:01 +00005497 }
kenton@google.comd37d46d2009-04-25 02:53:47 +00005498 return true;
kenton@google.com24bf56f2008-09-24 20:31:01 +00005499 }
5500
kenton@google.comd37d46d2009-04-25 02:53:47 +00005501 for (int i = 0; i < unknown_fields.field_count(); i++) {
5502 if (unknown_fields.field(i).number() ==
5503 (*intermediate_fields_iter)->number()) {
5504 const UnknownField* unknown_field = &unknown_fields.field(i);
5505 FieldDescriptor::Type type = (*intermediate_fields_iter)->type();
5506 // Recurse into the next submessage.
kenton@google.comd37d46d2009-04-25 02:53:47 +00005507 switch (type) {
5508 case FieldDescriptor::TYPE_MESSAGE:
5509 if (unknown_field->type() == UnknownField::TYPE_LENGTH_DELIMITED) {
5510 UnknownFieldSet intermediate_unknown_fields;
5511 if (intermediate_unknown_fields.ParseFromString(
5512 unknown_field->length_delimited()) &&
kenton@google.com80b1d622009-07-29 01:13:20 +00005513 !ExamineIfOptionIsSet(intermediate_fields_iter + 1,
kenton@google.comd37d46d2009-04-25 02:53:47 +00005514 intermediate_fields_end,
5515 innermost_field, debug_msg_name,
5516 intermediate_unknown_fields)) {
5517 return false; // Error already added.
5518 }
kenton@google.com24bf56f2008-09-24 20:31:01 +00005519 }
kenton@google.comd37d46d2009-04-25 02:53:47 +00005520 break;
kenton@google.com24bf56f2008-09-24 20:31:01 +00005521
kenton@google.comd37d46d2009-04-25 02:53:47 +00005522 case FieldDescriptor::TYPE_GROUP:
5523 if (unknown_field->type() == UnknownField::TYPE_GROUP) {
kenton@google.com80b1d622009-07-29 01:13:20 +00005524 if (!ExamineIfOptionIsSet(intermediate_fields_iter + 1,
kenton@google.comd37d46d2009-04-25 02:53:47 +00005525 intermediate_fields_end,
5526 innermost_field, debug_msg_name,
5527 unknown_field->group())) {
5528 return false; // Error already added.
5529 }
kenton@google.com24bf56f2008-09-24 20:31:01 +00005530 }
kenton@google.comd37d46d2009-04-25 02:53:47 +00005531 break;
kenton@google.com24bf56f2008-09-24 20:31:01 +00005532
kenton@google.comd37d46d2009-04-25 02:53:47 +00005533 default:
5534 GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_MESSAGE: " << type;
5535 return false;
5536 }
kenton@google.com24bf56f2008-09-24 20:31:01 +00005537 }
5538 }
5539 return true;
5540}
5541
5542bool DescriptorBuilder::OptionInterpreter::SetOptionValue(
5543 const FieldDescriptor* option_field,
kenton@google.comd37d46d2009-04-25 02:53:47 +00005544 UnknownFieldSet* unknown_fields) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00005545 // We switch on the CppType to validate.
5546 switch (option_field->cpp_type()) {
5547
5548 case FieldDescriptor::CPPTYPE_INT32:
5549 if (uninterpreted_option_->has_positive_int_value()) {
5550 if (uninterpreted_option_->positive_int_value() >
5551 static_cast<uint64>(kint32max)) {
5552 return AddValueError("Value out of range for int32 option \"" +
5553 option_field->full_name() + "\".");
5554 } else {
kenton@google.comd37d46d2009-04-25 02:53:47 +00005555 SetInt32(option_field->number(),
5556 uninterpreted_option_->positive_int_value(),
5557 option_field->type(), unknown_fields);
kenton@google.com24bf56f2008-09-24 20:31:01 +00005558 }
5559 } else if (uninterpreted_option_->has_negative_int_value()) {
5560 if (uninterpreted_option_->negative_int_value() <
5561 static_cast<int64>(kint32min)) {
5562 return AddValueError("Value out of range for int32 option \"" +
5563 option_field->full_name() + "\".");
5564 } else {
kenton@google.comd37d46d2009-04-25 02:53:47 +00005565 SetInt32(option_field->number(),
5566 uninterpreted_option_->negative_int_value(),
5567 option_field->type(), unknown_fields);
kenton@google.com24bf56f2008-09-24 20:31:01 +00005568 }
5569 } else {
5570 return AddValueError("Value must be integer for int32 option \"" +
5571 option_field->full_name() + "\".");
5572 }
5573 break;
5574
5575 case FieldDescriptor::CPPTYPE_INT64:
5576 if (uninterpreted_option_->has_positive_int_value()) {
5577 if (uninterpreted_option_->positive_int_value() >
5578 static_cast<uint64>(kint64max)) {
5579 return AddValueError("Value out of range for int64 option \"" +
5580 option_field->full_name() + "\".");
5581 } else {
kenton@google.comd37d46d2009-04-25 02:53:47 +00005582 SetInt64(option_field->number(),
5583 uninterpreted_option_->positive_int_value(),
5584 option_field->type(), unknown_fields);
kenton@google.com24bf56f2008-09-24 20:31:01 +00005585 }
5586 } else if (uninterpreted_option_->has_negative_int_value()) {
kenton@google.comd37d46d2009-04-25 02:53:47 +00005587 SetInt64(option_field->number(),
5588 uninterpreted_option_->negative_int_value(),
5589 option_field->type(), unknown_fields);
kenton@google.com24bf56f2008-09-24 20:31:01 +00005590 } else {
5591 return AddValueError("Value must be integer for int64 option \"" +
5592 option_field->full_name() + "\".");
5593 }
5594 break;
5595
5596 case FieldDescriptor::CPPTYPE_UINT32:
5597 if (uninterpreted_option_->has_positive_int_value()) {
5598 if (uninterpreted_option_->positive_int_value() > kuint32max) {
5599 return AddValueError("Value out of range for uint32 option \"" +
5600 option_field->name() + "\".");
5601 } else {
kenton@google.comd37d46d2009-04-25 02:53:47 +00005602 SetUInt32(option_field->number(),
5603 uninterpreted_option_->positive_int_value(),
5604 option_field->type(), unknown_fields);
kenton@google.com24bf56f2008-09-24 20:31:01 +00005605 }
5606 } else {
5607 return AddValueError("Value must be non-negative integer for uint32 "
5608 "option \"" + option_field->full_name() + "\".");
5609 }
5610 break;
5611
5612 case FieldDescriptor::CPPTYPE_UINT64:
5613 if (uninterpreted_option_->has_positive_int_value()) {
kenton@google.comd37d46d2009-04-25 02:53:47 +00005614 SetUInt64(option_field->number(),
5615 uninterpreted_option_->positive_int_value(),
5616 option_field->type(), unknown_fields);
kenton@google.com24bf56f2008-09-24 20:31:01 +00005617 } else {
5618 return AddValueError("Value must be non-negative integer for uint64 "
5619 "option \"" + option_field->full_name() + "\".");
5620 }
5621 break;
5622
5623 case FieldDescriptor::CPPTYPE_FLOAT: {
5624 float value;
5625 if (uninterpreted_option_->has_double_value()) {
5626 value = uninterpreted_option_->double_value();
5627 } else if (uninterpreted_option_->has_positive_int_value()) {
5628 value = uninterpreted_option_->positive_int_value();
5629 } else if (uninterpreted_option_->has_negative_int_value()) {
5630 value = uninterpreted_option_->negative_int_value();
5631 } else {
5632 return AddValueError("Value must be number for float option \"" +
5633 option_field->full_name() + "\".");
5634 }
kenton@google.comd37d46d2009-04-25 02:53:47 +00005635 unknown_fields->AddFixed32(option_field->number(),
kenton@google.com80b1d622009-07-29 01:13:20 +00005636 google::protobuf::internal::WireFormatLite::EncodeFloat(value));
kenton@google.com24bf56f2008-09-24 20:31:01 +00005637 break;
5638 }
5639
5640 case FieldDescriptor::CPPTYPE_DOUBLE: {
5641 double value;
5642 if (uninterpreted_option_->has_double_value()) {
5643 value = uninterpreted_option_->double_value();
5644 } else if (uninterpreted_option_->has_positive_int_value()) {
5645 value = uninterpreted_option_->positive_int_value();
5646 } else if (uninterpreted_option_->has_negative_int_value()) {
5647 value = uninterpreted_option_->negative_int_value();
5648 } else {
5649 return AddValueError("Value must be number for double option \"" +
5650 option_field->full_name() + "\".");
5651 }
kenton@google.comd37d46d2009-04-25 02:53:47 +00005652 unknown_fields->AddFixed64(option_field->number(),
kenton@google.com80b1d622009-07-29 01:13:20 +00005653 google::protobuf::internal::WireFormatLite::EncodeDouble(value));
kenton@google.com24bf56f2008-09-24 20:31:01 +00005654 break;
5655 }
5656
5657 case FieldDescriptor::CPPTYPE_BOOL:
5658 uint64 value;
5659 if (!uninterpreted_option_->has_identifier_value()) {
5660 return AddValueError("Value must be identifier for boolean option "
5661 "\"" + option_field->full_name() + "\".");
5662 }
5663 if (uninterpreted_option_->identifier_value() == "true") {
5664 value = 1;
5665 } else if (uninterpreted_option_->identifier_value() == "false") {
5666 value = 0;
5667 } else {
5668 return AddValueError("Value must be \"true\" or \"false\" for boolean "
5669 "option \"" + option_field->full_name() + "\".");
5670 }
kenton@google.comd37d46d2009-04-25 02:53:47 +00005671 unknown_fields->AddVarint(option_field->number(), value);
kenton@google.com24bf56f2008-09-24 20:31:01 +00005672 break;
5673
5674 case FieldDescriptor::CPPTYPE_ENUM: {
5675 if (!uninterpreted_option_->has_identifier_value()) {
5676 return AddValueError("Value must be identifier for enum-valued option "
5677 "\"" + option_field->full_name() + "\".");
5678 }
5679 const EnumDescriptor* enum_type = option_field->enum_type();
5680 const string& value_name = uninterpreted_option_->identifier_value();
5681 const EnumValueDescriptor* enum_value = NULL;
5682
5683 if (enum_type->file()->pool() != DescriptorPool::generated_pool()) {
5684 // Note that the enum value's fully-qualified name is a sibling of the
5685 // enum's name, not a child of it.
5686 string fully_qualified_name = enum_type->full_name();
5687 fully_qualified_name.resize(fully_qualified_name.size() -
5688 enum_type->name().size());
5689 fully_qualified_name += value_name;
5690
5691 // Search for the enum value's descriptor in the builder's pool. Note
kenton@google.com26bd9ee2008-11-21 00:06:27 +00005692 // that we use DescriptorBuilder::FindSymbolNotEnforcingDeps(), not
kenton@google.com24bf56f2008-09-24 20:31:01 +00005693 // DescriptorPool::FindEnumValueByName() because we're already holding
5694 // the pool's mutex, and the latter method locks it again.
kenton@google.com26bd9ee2008-11-21 00:06:27 +00005695 Symbol symbol =
5696 builder_->FindSymbolNotEnforcingDeps(fully_qualified_name);
kenton@google.com24bf56f2008-09-24 20:31:01 +00005697 if (!symbol.IsNull() && symbol.type == Symbol::ENUM_VALUE) {
5698 if (symbol.enum_value_descriptor->type() != enum_type) {
5699 return AddValueError("Enum type \"" + enum_type->full_name() +
5700 "\" has no value named \"" + value_name + "\" for option \"" +
5701 option_field->full_name() +
5702 "\". This appears to be a value from a sibling type.");
5703 } else {
5704 enum_value = symbol.enum_value_descriptor;
5705 }
5706 }
5707 } else {
5708 // The enum type is in the generated pool, so we can search for the
5709 // value there.
5710 enum_value = enum_type->FindValueByName(value_name);
5711 }
5712
5713 if (enum_value == NULL) {
5714 return AddValueError("Enum type \"" +
5715 option_field->enum_type()->full_name() +
5716 "\" has no value named \"" + value_name + "\" for "
5717 "option \"" + option_field->full_name() + "\".");
5718 } else {
5719 // Sign-extension is not a problem, since we cast directly from int32 to
5720 // uint64, without first going through uint32.
kenton@google.comd37d46d2009-04-25 02:53:47 +00005721 unknown_fields->AddVarint(option_field->number(),
5722 static_cast<uint64>(static_cast<int64>(enum_value->number())));
kenton@google.com24bf56f2008-09-24 20:31:01 +00005723 }
5724 break;
5725 }
5726
5727 case FieldDescriptor::CPPTYPE_STRING:
5728 if (!uninterpreted_option_->has_string_value()) {
5729 return AddValueError("Value must be quoted string for string option "
5730 "\"" + option_field->full_name() + "\".");
5731 }
5732 // The string has already been unquoted and unescaped by the parser.
kenton@google.comd37d46d2009-04-25 02:53:47 +00005733 unknown_fields->AddLengthDelimited(option_field->number(),
kenton@google.com24bf56f2008-09-24 20:31:01 +00005734 uninterpreted_option_->string_value());
5735 break;
5736
5737 case FieldDescriptor::CPPTYPE_MESSAGE:
liujisi@google.com33165fe2010-11-02 13:14:58 +00005738 if (!SetAggregateOption(option_field, unknown_fields)) {
5739 return false;
5740 }
kenton@google.com24bf56f2008-09-24 20:31:01 +00005741 break;
5742 }
5743
5744 return true;
5745}
5746
liujisi@google.com33165fe2010-11-02 13:14:58 +00005747class DescriptorBuilder::OptionInterpreter::AggregateOptionFinder
5748 : public TextFormat::Finder {
5749 public:
5750 DescriptorBuilder* builder_;
5751
5752 virtual const FieldDescriptor* FindExtension(
5753 Message* message, const string& name) const {
liujisi@google.com17d57db2011-02-07 19:03:53 +00005754 assert_mutex_held(builder_->pool_);
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00005755 const Descriptor* descriptor = message->GetDescriptor();
liujisi@google.com33165fe2010-11-02 13:14:58 +00005756 Symbol result = builder_->LookupSymbolNoPlaceholder(
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00005757 name, descriptor->full_name());
liujisi@google.com33165fe2010-11-02 13:14:58 +00005758 if (result.type == Symbol::FIELD &&
5759 result.field_descriptor->is_extension()) {
5760 return result.field_descriptor;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00005761 } else if (result.type == Symbol::MESSAGE &&
5762 descriptor->options().message_set_wire_format()) {
5763 const Descriptor* foreign_type = result.descriptor;
5764 // The text format allows MessageSet items to be specified using
5765 // the type name, rather than the extension identifier. If the symbol
5766 // lookup returned a Message, and the enclosing Message has
5767 // message_set_wire_format = true, then return the message set
5768 // extension, if one exists.
5769 for (int i = 0; i < foreign_type->extension_count(); i++) {
5770 const FieldDescriptor* extension = foreign_type->extension(i);
5771 if (extension->containing_type() == descriptor &&
5772 extension->type() == FieldDescriptor::TYPE_MESSAGE &&
5773 extension->is_optional() &&
5774 extension->message_type() == foreign_type) {
5775 // Found it.
5776 return extension;
5777 }
5778 }
liujisi@google.com33165fe2010-11-02 13:14:58 +00005779 }
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00005780 return NULL;
liujisi@google.com33165fe2010-11-02 13:14:58 +00005781 }
5782};
5783
5784// A custom error collector to record any text-format parsing errors
5785namespace {
5786class AggregateErrorCollector : public io::ErrorCollector {
5787 public:
5788 string error_;
5789
liujisi@google.comc5553a32014-05-28 21:48:28 +00005790 virtual void AddError(int /* line */, int /* column */,
5791 const string& message) {
liujisi@google.com33165fe2010-11-02 13:14:58 +00005792 if (!error_.empty()) {
5793 error_ += "; ";
5794 }
5795 error_ += message;
5796 }
5797
liujisi@google.comc5553a32014-05-28 21:48:28 +00005798 virtual void AddWarning(int /* line */, int /* column */,
5799 const string& /* message */) {
liujisi@google.com33165fe2010-11-02 13:14:58 +00005800 // Ignore warnings
5801 }
5802};
5803}
5804
5805// We construct a dynamic message of the type corresponding to
5806// option_field, parse the supplied text-format string into this
5807// message, and serialize the resulting message to produce the value.
5808bool DescriptorBuilder::OptionInterpreter::SetAggregateOption(
5809 const FieldDescriptor* option_field,
5810 UnknownFieldSet* unknown_fields) {
5811 if (!uninterpreted_option_->has_aggregate_value()) {
5812 return AddValueError("Option \"" + option_field->full_name() +
5813 "\" is a message. To set the entire message, use "
5814 "syntax like \"" + option_field->name() +
5815 " = { <proto text format> }\". "
5816 "To set fields within it, use "
5817 "syntax like \"" + option_field->name() +
5818 ".foo = value\".");
5819 }
5820
5821 const Descriptor* type = option_field->message_type();
5822 scoped_ptr<Message> dynamic(dynamic_factory_.GetPrototype(type)->New());
5823 GOOGLE_CHECK(dynamic.get() != NULL)
5824 << "Could not create an instance of " << option_field->DebugString();
5825
5826 AggregateErrorCollector collector;
5827 AggregateOptionFinder finder;
5828 finder.builder_ = builder_;
5829 TextFormat::Parser parser;
5830 parser.RecordErrorsTo(&collector);
5831 parser.SetFinder(&finder);
5832 if (!parser.ParseFromString(uninterpreted_option_->aggregate_value(),
5833 dynamic.get())) {
5834 AddValueError("Error while parsing option value for \"" +
5835 option_field->name() + "\": " + collector.error_);
5836 return false;
5837 } else {
5838 string serial;
5839 dynamic->SerializeToString(&serial); // Never fails
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +00005840 if (option_field->type() == FieldDescriptor::TYPE_MESSAGE) {
5841 unknown_fields->AddLengthDelimited(option_field->number(), serial);
5842 } else {
5843 GOOGLE_CHECK_EQ(option_field->type(), FieldDescriptor::TYPE_GROUP);
5844 UnknownFieldSet* group = unknown_fields->AddGroup(option_field->number());
5845 group->ParseFromString(serial);
5846 }
liujisi@google.com33165fe2010-11-02 13:14:58 +00005847 return true;
5848 }
5849}
5850
kenton@google.comd37d46d2009-04-25 02:53:47 +00005851void DescriptorBuilder::OptionInterpreter::SetInt32(int number, int32 value,
5852 FieldDescriptor::Type type, UnknownFieldSet* unknown_fields) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00005853 switch (type) {
5854 case FieldDescriptor::TYPE_INT32:
kenton@google.comd37d46d2009-04-25 02:53:47 +00005855 unknown_fields->AddVarint(number,
5856 static_cast<uint64>(static_cast<int64>(value)));
kenton@google.com24bf56f2008-09-24 20:31:01 +00005857 break;
5858
5859 case FieldDescriptor::TYPE_SFIXED32:
kenton@google.comd37d46d2009-04-25 02:53:47 +00005860 unknown_fields->AddFixed32(number, static_cast<uint32>(value));
kenton@google.com24bf56f2008-09-24 20:31:01 +00005861 break;
5862
5863 case FieldDescriptor::TYPE_SINT32:
kenton@google.comd37d46d2009-04-25 02:53:47 +00005864 unknown_fields->AddVarint(number,
kenton@google.com80b1d622009-07-29 01:13:20 +00005865 google::protobuf::internal::WireFormatLite::ZigZagEncode32(value));
kenton@google.com24bf56f2008-09-24 20:31:01 +00005866 break;
5867
5868 default:
5869 GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_INT32: " << type;
5870 break;
5871 }
5872}
5873
kenton@google.comd37d46d2009-04-25 02:53:47 +00005874void DescriptorBuilder::OptionInterpreter::SetInt64(int number, int64 value,
5875 FieldDescriptor::Type type, UnknownFieldSet* unknown_fields) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00005876 switch (type) {
5877 case FieldDescriptor::TYPE_INT64:
kenton@google.comd37d46d2009-04-25 02:53:47 +00005878 unknown_fields->AddVarint(number, static_cast<uint64>(value));
kenton@google.com24bf56f2008-09-24 20:31:01 +00005879 break;
5880
5881 case FieldDescriptor::TYPE_SFIXED64:
kenton@google.comd37d46d2009-04-25 02:53:47 +00005882 unknown_fields->AddFixed64(number, static_cast<uint64>(value));
kenton@google.com24bf56f2008-09-24 20:31:01 +00005883 break;
5884
5885 case FieldDescriptor::TYPE_SINT64:
kenton@google.comd37d46d2009-04-25 02:53:47 +00005886 unknown_fields->AddVarint(number,
kenton@google.com80b1d622009-07-29 01:13:20 +00005887 google::protobuf::internal::WireFormatLite::ZigZagEncode64(value));
kenton@google.com24bf56f2008-09-24 20:31:01 +00005888 break;
5889
5890 default:
5891 GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_INT64: " << type;
5892 break;
5893 }
5894}
5895
kenton@google.comd37d46d2009-04-25 02:53:47 +00005896void DescriptorBuilder::OptionInterpreter::SetUInt32(int number, uint32 value,
5897 FieldDescriptor::Type type, UnknownFieldSet* unknown_fields) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00005898 switch (type) {
5899 case FieldDescriptor::TYPE_UINT32:
kenton@google.comd37d46d2009-04-25 02:53:47 +00005900 unknown_fields->AddVarint(number, static_cast<uint64>(value));
kenton@google.com24bf56f2008-09-24 20:31:01 +00005901 break;
5902
5903 case FieldDescriptor::TYPE_FIXED32:
kenton@google.comd37d46d2009-04-25 02:53:47 +00005904 unknown_fields->AddFixed32(number, static_cast<uint32>(value));
kenton@google.com24bf56f2008-09-24 20:31:01 +00005905 break;
5906
5907 default:
5908 GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_UINT32: " << type;
5909 break;
5910 }
5911}
5912
kenton@google.comd37d46d2009-04-25 02:53:47 +00005913void DescriptorBuilder::OptionInterpreter::SetUInt64(int number, uint64 value,
5914 FieldDescriptor::Type type, UnknownFieldSet* unknown_fields) {
kenton@google.com24bf56f2008-09-24 20:31:01 +00005915 switch (type) {
5916 case FieldDescriptor::TYPE_UINT64:
kenton@google.comd37d46d2009-04-25 02:53:47 +00005917 unknown_fields->AddVarint(number, value);
kenton@google.com24bf56f2008-09-24 20:31:01 +00005918 break;
5919
5920 case FieldDescriptor::TYPE_FIXED64:
kenton@google.comd37d46d2009-04-25 02:53:47 +00005921 unknown_fields->AddFixed64(number, value);
kenton@google.com24bf56f2008-09-24 20:31:01 +00005922 break;
5923
5924 default:
5925 GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_UINT64: " << type;
5926 break;
5927 }
5928}
5929
jieluo@google.com4de8f552014-07-18 00:47:59 +00005930void DescriptorBuilder::LogUnusedDependency(const FileDescriptor* result) {
5931
5932 if (!unused_dependency_.empty()) {
5933 std::set<string> annotation_extensions;
5934 annotation_extensions.insert("google.protobuf.MessageOptions");
5935 annotation_extensions.insert("google.protobuf.FileOptions");
5936 annotation_extensions.insert("google.protobuf.FieldOptions");
5937 annotation_extensions.insert("google.protobuf.EnumOptions");
5938 annotation_extensions.insert("google.protobuf.EnumValueOptions");
5939 annotation_extensions.insert("google.protobuf.ServiceOptions");
5940 annotation_extensions.insert("google.protobuf.MethodOptions");
5941 annotation_extensions.insert("google.protobuf.StreamOptions");
5942 for (set<const FileDescriptor*>::const_iterator
5943 it = unused_dependency_.begin();
5944 it != unused_dependency_.end(); ++it) {
5945 // Do not log warnings for proto files which extend annotations.
5946 int i;
5947 for (i = 0 ; i < (*it)->extension_count(); ++i) {
5948 if (annotation_extensions.find(
5949 (*it)->extension(i)->containing_type()->full_name())
5950 != annotation_extensions.end()) {
5951 break;
5952 }
5953 }
5954 // Log warnings for unused imported files.
5955 if (i == (*it)->extension_count()) {
5956 GOOGLE_LOG(WARNING) << "Warning: Unused import: \"" << result->name()
5957 << "\" imports \"" << (*it)->name()
5958 << "\" which is not used.";
5959 }
5960 }
5961 }
5962}
5963
temporal40ee5512008-07-10 02:12:20 +00005964} // namespace protobuf
5965} // namespace google