aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar temporal <temporal@630680e5-0e50-0410-840e-4b1c322b438d>2008-07-23 01:19:07 +0000
committerGravatar temporal <temporal@630680e5-0e50-0410-840e-4b1c322b438d>2008-07-23 01:19:07 +0000
commitf206351d1469970230caa5f61eaa54797194bee1 (patch)
tree3b1b9ea37171fdb231bca2fe6c74492eeea2abd7
parentcc930432c2823c3d82e0b8dd2ae4f446c82f4fce (diff)
Sync code with Google-internal branch. Changes:
Protoc (parser) - Improved error message when an enum value's name conflicts with another symbol defined in the enum type's scope, e.g. if two enum types declared in the same scope have values with the same name. This is disallowed for compatibility with C++, but this wasn't clear from the error. C++ - Restored the set_foo(const char*) accessor for "bytes" type because some code inside Google depends on it. However, set_foo(const char*, int) is still there (and actually is changed to take const void*). - Fixed TokenizerTest when compiling with -DNDEBUG on Linux. - Other irrelevant tweaks. Java - Fixed UnknownFieldSet's parsing of varints larger than 32 bits. - Fixed TextFormat's parsing of "inf" and "nan". - Fixed TextFormat's parsing of comments. Python - Fixed text_format_test on Windows where floating-point exponents sometimes contain extra zeros.
-rw-r--r--java/src/main/java/com/google/protobuf/TextFormat.java40
-rw-r--r--java/src/main/java/com/google/protobuf/UnknownFieldSet.java2
-rw-r--r--java/src/test/java/com/google/protobuf/TextFormatTest.java41
-rw-r--r--java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java15
-rwxr-xr-xpython/google/protobuf/internal/decoder_test.py2
-rwxr-xr-xpython/google/protobuf/internal/encoder_test.py2
-rwxr-xr-xpython/google/protobuf/internal/text_format_test.py19
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.cc63
-rw-r--r--src/google/protobuf/compiler/parser.cc3
-rw-r--r--src/google/protobuf/descriptor.cc46
-rw-r--r--src/google/protobuf/descriptor.h14
-rw-r--r--src/google/protobuf/descriptor.pb.h8
-rw-r--r--src/google/protobuf/descriptor_unittest.cc27
-rw-r--r--src/google/protobuf/io/tokenizer_unittest.cc12
14 files changed, 230 insertions, 64 deletions
diff --git a/java/src/main/java/com/google/protobuf/TextFormat.java b/java/src/main/java/com/google/protobuf/TextFormat.java
index c4fdfe64..2d949b65 100644
--- a/java/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/src/main/java/com/google/protobuf/TextFormat.java
@@ -384,12 +384,24 @@ public final class TextFormat {
private int previousLine = 0;
private int previousColumn = 0;
- private static Pattern WHITESPACE = Pattern.compile("(\\s|(#[^\n]*$))*");
+ private static Pattern WHITESPACE =
+ Pattern.compile("(\\s|(#.*$))+", Pattern.MULTILINE);
private static Pattern TOKEN = Pattern.compile(
"[a-zA-Z_][0-9a-zA-Z_+-]*|" + // an identifier
"[0-9+-][0-9a-zA-Z_.+-]*|" + // a number
- "\"([^\"\n\\\\]|\\\\[^\n])*(\"|\\\\?$)|" + // a double-quoted string
- "\'([^\"\n\\\\]|\\\\[^\n])*(\'|\\\\?$)"); // a single-quoted string
+ "\"([^\"\n\\\\]|\\\\.)*(\"|\\\\?$)|" + // a double-quoted string
+ "\'([^\"\n\\\\]|\\\\.)*(\'|\\\\?$)", // a single-quoted string
+ Pattern.MULTILINE);
+
+ private static Pattern DOUBLE_INFINITY = Pattern.compile(
+ "-?inf(inity)?",
+ Pattern.CASE_INSENSITIVE);
+ private static Pattern FLOAT_INFINITY = Pattern.compile(
+ "-?inf(inity)?f?",
+ Pattern.CASE_INSENSITIVE);
+ private static Pattern FLOAT_NAN = Pattern.compile(
+ "nanf?",
+ Pattern.CASE_INSENSITIVE);
/** Construct a tokenizer that parses tokens from the given text. */
public Tokenizer(CharSequence text) {
@@ -570,6 +582,17 @@ public final class TextFormat {
* Otherwise, throw a {@link ParseException}.
*/
public double consumeDouble() throws ParseException {
+ // We need to parse infinity and nan separately because
+ // Double.parseDouble() does not accept "inf", "infinity", or "nan".
+ if (DOUBLE_INFINITY.matcher(currentToken).matches()) {
+ boolean negative = currentToken.startsWith("-");
+ nextToken();
+ return negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
+ }
+ if (currentToken.equalsIgnoreCase("nan")) {
+ nextToken();
+ return Double.NaN;
+ }
try {
double result = Double.parseDouble(currentToken);
nextToken();
@@ -584,6 +607,17 @@ public final class TextFormat {
* Otherwise, throw a {@link ParseException}.
*/
public float consumeFloat() throws ParseException {
+ // We need to parse infinity and nan separately because
+ // Float.parseFloat() does not accept "inf", "infinity", or "nan".
+ if (FLOAT_INFINITY.matcher(currentToken).matches()) {
+ boolean negative = currentToken.startsWith("-");
+ nextToken();
+ return negative ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
+ }
+ if (FLOAT_NAN.matcher(currentToken).matches()) {
+ nextToken();
+ return Float.NaN;
+ }
try {
float result = Float.parseFloat(currentToken);
nextToken();
diff --git a/java/src/main/java/com/google/protobuf/UnknownFieldSet.java b/java/src/main/java/com/google/protobuf/UnknownFieldSet.java
index 6bcc4309..ba4dd5ad 100644
--- a/java/src/main/java/com/google/protobuf/UnknownFieldSet.java
+++ b/java/src/main/java/com/google/protobuf/UnknownFieldSet.java
@@ -387,7 +387,7 @@ public final class UnknownFieldSet {
int number = WireFormat.getTagFieldNumber(tag);
switch (WireFormat.getTagWireType(tag)) {
case WireFormat.WIRETYPE_VARINT:
- getFieldBuilder(number).addVarint(input.readInt32());
+ getFieldBuilder(number).addVarint(input.readInt64());
return true;
case WireFormat.WIRETYPE_FIXED64:
getFieldBuilder(number).addFixed64(input.readFixed64());
diff --git a/java/src/test/java/com/google/protobuf/TextFormatTest.java b/java/src/test/java/com/google/protobuf/TextFormatTest.java
index 2c485c55..8b7af107 100644
--- a/java/src/test/java/com/google/protobuf/TextFormatTest.java
+++ b/java/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -250,6 +250,36 @@ public class TextFormatTest extends TestCase {
TestUtil.assertAllExtensionsSet(builder.build());
}
+ public void testParseCompatibility() throws Exception {
+ String original = "repeated_float: inf\n" +
+ "repeated_float: -inf\n" +
+ "repeated_float: nan\n" +
+ "repeated_float: inff\n" +
+ "repeated_float: -inff\n" +
+ "repeated_float: nanf\n" +
+ "repeated_float: 1.0f\n" +
+ "repeated_float: infinityf\n" +
+ "repeated_float: -Infinityf\n" +
+ "repeated_double: infinity\n" +
+ "repeated_double: -infinity\n" +
+ "repeated_double: nan\n";
+ String canonical = "repeated_float: Infinity\n" +
+ "repeated_float: -Infinity\n" +
+ "repeated_float: NaN\n" +
+ "repeated_float: Infinity\n" +
+ "repeated_float: -Infinity\n" +
+ "repeated_float: NaN\n" +
+ "repeated_float: 1.0\n" +
+ "repeated_float: Infinity\n" +
+ "repeated_float: -Infinity\n" +
+ "repeated_double: Infinity\n" +
+ "repeated_double: -Infinity\n" +
+ "repeated_double: NaN\n";
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TextFormat.merge(original, builder);
+ assertEquals(canonical, builder.build().toString());
+ }
+
public void testParseExotic() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge(exoticText, builder);
@@ -291,6 +321,17 @@ public class TextFormatTest extends TestCase {
assertEquals(1, builder.getOptionalGroup().getA());
}
+ public void testParseComment() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TextFormat.merge(
+ "# this is a comment\n" +
+ "optional_int32: 1 # another comment\n" +
+ "optional_int64: 2\n" +
+ "# EOF comment", builder);
+ assertEquals(1, builder.getOptionalInt32());
+ assertEquals(2, builder.getOptionalInt64());
+ }
+
private void assertParseError(String error, String text) {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
try {
diff --git a/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java b/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
index 0ad2683d..8919414e 100644
--- a/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
+++ b/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
@@ -312,4 +312,19 @@ public class UnknownFieldSetTest extends TestCase {
.getVarintList());
}
}
+
+ public void testLargeVarint() throws Exception {
+ ByteString data =
+ UnknownFieldSet.newBuilder()
+ .addField(1,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(0x7FFFFFFFFFFFFFFFL)
+ .build())
+ .build()
+ .toByteString();
+ UnknownFieldSet parsed = UnknownFieldSet.parseFrom(data);
+ UnknownFieldSet.Field field = parsed.getField(1);
+ assertEquals(1, field.getVarintList().size());
+ assertEquals(0x7FFFFFFFFFFFFFFFL, (long)field.getVarintList().get(0));
+ }
}
diff --git a/python/google/protobuf/internal/decoder_test.py b/python/google/protobuf/internal/decoder_test.py
index e36a96fc..626816f6 100755
--- a/python/google/protobuf/internal/decoder_test.py
+++ b/python/google/protobuf/internal/decoder_test.py
@@ -24,9 +24,9 @@ from google.protobuf.internal import wire_format
from google.protobuf.internal import encoder
from google.protobuf.internal import decoder
import logging
-import mox
from google.protobuf.internal import input_stream
from google.protobuf import message
+import mox
class DecoderTest(unittest.TestCase):
diff --git a/python/google/protobuf/internal/encoder_test.py b/python/google/protobuf/internal/encoder_test.py
index 5d690da7..be4276b6 100755
--- a/python/google/protobuf/internal/encoder_test.py
+++ b/python/google/protobuf/internal/encoder_test.py
@@ -21,11 +21,11 @@ __author__ = 'robinson@google.com (Will Robinson)'
import struct
import logging
import unittest
-import mox
from google.protobuf.internal import wire_format
from google.protobuf.internal import encoder
from google.protobuf.internal import output_stream
from google.protobuf import message
+import mox
class EncoderTest(unittest.TestCase):
diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py
index c2074db5..c8fc79dc 100755
--- a/python/google/protobuf/internal/text_format_test.py
+++ b/python/google/protobuf/internal/text_format_test.py
@@ -45,14 +45,16 @@ class TextFormatTest(unittest.TestCase):
def testPrintAllFields(self):
message = unittest_pb2.TestAllTypes()
test_util.SetAllFields(message)
- self.CompareToGoldenFile(text_format.MessageToString(message),
- 'text_format_unittest_data.txt')
+ self.CompareToGoldenFile(
+ self.RemoveRedundantZeros(text_format.MessageToString(message)),
+ 'text_format_unittest_data.txt')
def testPrintAllExtensions(self):
message = unittest_pb2.TestAllExtensions()
test_util.SetAllExtensions(message)
- self.CompareToGoldenFile(text_format.MessageToString(message),
- 'text_format_unittest_extensions_data.txt')
+ self.CompareToGoldenFile(
+ self.RemoveRedundantZeros(text_format.MessageToString(message)),
+ 'text_format_unittest_extensions_data.txt')
def testPrintMessageSet(self):
message = unittest_mset_pb2.TestMessageSetContainer()
@@ -78,7 +80,8 @@ class TextFormatTest(unittest.TestCase):
message.repeated_double.append(1.23e22);
message.repeated_double.append(1.23e-18);
message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'\"');
- self.CompareToGoldenText(text_format.MessageToString(message),
+ self.CompareToGoldenText(
+ self.RemoveRedundantZeros(text_format.MessageToString(message)),
'repeated_int64: -9223372036854775808\n'
'repeated_uint64: 18446744073709551615\n'
'repeated_double: 123.456\n'
@@ -92,6 +95,12 @@ class TextFormatTest(unittest.TestCase):
message.c = 123
self.assertEqual('c: 123\n', str(message))
+ def RemoveRedundantZeros(self, text):
+ # Some platforms print 1e+5 as 1e+005. This is fine, but we need to remove
+ # these zeros in order to match the golden file.
+ return text.replace('e+0','e+').replace('e+0','e+') \
+ .replace('e-0','e-').replace('e-0','e-')
+
if __name__ == '__main__':
unittest.main()
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index e74eb432..8590df7e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -96,13 +96,11 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
printer->Print(variables_,
"inline const ::std::string& $name$() const;\n"
- "inline void set_$name$(const ::std::string& value);\n");
+ "inline void set_$name$(const ::std::string& value);\n"
+ "inline void set_$name$(const char* value);\n");
if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) {
printer->Print(variables_,
- "inline void set_$name$(const char* value, size_t size);\n");
- } else {
- printer->Print(variables_,
- "inline void set_$name$(const char* value);\n");
+ "inline void set_$name$(const void* value, size_t size);\n");
}
printer->Print(variables_,
@@ -127,25 +125,23 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" $name$_ = new ::std::string;\n"
" }\n"
" $name$_->assign(value);\n"
+ "}\n"
+ "inline void $classname$::set_$name$(const char* value) {\n"
+ " _set_bit($index$);\n"
+ " if ($name$_ == &_default_$name$_) {\n"
+ " $name$_ = new ::std::string;\n"
+ " }\n"
+ " $name$_->assign(value);\n"
"}\n");
if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) {
printer->Print(variables_,
- "inline void $classname$::set_$name$(const char* value, size_t size) {\n"
+ "inline void $classname$::set_$name$(const void* value, size_t size) {\n"
" _set_bit($index$);\n"
" if ($name$_ == &_default_$name$_) {\n"
" $name$_ = new ::std::string;\n"
" }\n"
- " $name$_->assign(value, size);\n"
- "}\n");
- } else {
- printer->Print(variables_,
- "inline void $classname$::set_$name$(const char* value) {\n"
- " _set_bit($index$);\n"
- " if ($name$_ == &_default_$name$_) {\n"
- " $name$_ = new ::std::string;\n"
- " }\n"
- " $name$_->assign(value);\n"
+ " $name$_->assign(reinterpret_cast<const char*>(value), size);\n"
"}\n");
}
@@ -265,17 +261,15 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
"inline const ::std::string& $name$(int index) const;\n"
"inline ::std::string* mutable_$name$(int index);\n"
"inline void set_$name$(int index, const ::std::string& value);\n"
+ "inline void set_$name$(int index, const char* value);\n"
"inline ::std::string* add_$name$();\n"
- "inline void add_$name$(const ::std::string& value);\n");
+ "inline void add_$name$(const ::std::string& value);\n"
+ "inline void add_$name$(const char* value);\n");
if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) {
printer->Print(variables_,
- "inline void set_$name$(int index, const char* value, size_t size);\n"
- "inline void add_$name$(const char* value, size_t size);\n");
- } else {
- printer->Print(variables_,
- "inline void set_$name$(int index, const char* value);\n"
- "inline void add_$name$(const char* value);\n");
+ "inline void set_$name$(int index, const void* value, size_t size);\n"
+ "inline void add_$name$(const void* value, size_t size);\n");
}
if (descriptor_->options().has_ctype()) {
@@ -305,29 +299,28 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
"inline void $classname$::set_$name$(int index, const ::std::string& value) {\n"
" $name$_.Mutable(index)->assign(value);\n"
"}\n"
+ "inline void $classname$::set_$name$(int index, const char* value) {\n"
+ " $name$_.Mutable(index)->assign(value);\n"
+ "}\n"
"inline ::std::string* $classname$::add_$name$() {\n"
" return $name$_.Add();\n"
"}\n"
"inline void $classname$::add_$name$(const ::std::string& value) {\n"
" $name$_.Add()->assign(value);\n"
+ "}\n"
+ "inline void $classname$::add_$name$(const char* value) {\n"
+ " $name$_.Add()->assign(value);\n"
"}\n");
if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) {
printer->Print(variables_,
"inline void "
- "$classname$::set_$name$(int index, const char* value, size_t size) {\n"
- " $name$_.Mutable(index)->assign(value, size);\n"
- "}\n"
- "inline void $classname$::add_$name$(const char* value, size_t size) {\n"
- " $name$_.Add()->assign(value, size);\n"
- "}\n");
- } else {
- printer->Print(variables_,
- "inline void $classname$::set_$name$(int index, const char* value) {\n"
- " $name$_.Mutable(index)->assign(value);\n"
+ "$classname$::set_$name$(int index, const void* value, size_t size) {\n"
+ " $name$_.Mutable(index)->assign(\n"
+ " reinterpret_cast<const char*>(value), size);\n"
"}\n"
- "inline void $classname$::add_$name$(const char* value) {\n"
- " $name$_.Add()->assign(value);\n"
+ "inline void $classname$::add_$name$(const void* value, size_t size) {\n"
+ " $name$_.Add()->assign(reinterpret_cast<const char*>(value), size);\n"
"}\n");
}
}
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index 622895ff..3b73530b 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -1034,6 +1034,9 @@ bool Parser::ParseUserDefinedType(string* type_name) {
bool Parser::ParsePackage(FileDescriptorProto* file) {
if (file->has_package()) {
AddError("Multiple package definitions.");
+ // Don't append the new package to the old one. Just replace it. Not
+ // that it really matters since this is an error anyway.
+ file->clear_package();
}
DO(Consume("package"));
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index c75cf623..48db0cc2 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -1604,8 +1604,10 @@ class DescriptorBuilder {
// FindSymbol("foo.bar").
Symbol LookupSymbol(const string& name, const string& relative_to);
- // Calls tables_->AddSymbol() and records an error if it fails.
- void AddSymbol(const string& full_name,
+ // Calls tables_->AddSymbol() and records an error if it fails. Returns
+ // true if successful or false if failed, though most callers can ignore
+ // the return value since an error has already been recorded.
+ bool AddSymbol(const string& full_name,
const void* parent, const string& name,
const Message& proto, Symbol symbol);
@@ -1918,14 +1920,16 @@ Symbol DescriptorBuilder::LookupSymbol(
}
}
-void DescriptorBuilder::AddSymbol(
+bool DescriptorBuilder::AddSymbol(
const string& full_name, const void* parent, const string& name,
const Message& proto, Symbol symbol) {
// If the caller passed NULL for the parent, the symbol is at file scope.
// Use its file as the parent instead.
if (parent == NULL) parent = file_;
- if (!tables_->AddSymbol(full_name, parent, name, symbol)) {
+ if (tables_->AddSymbol(full_name, parent, name, symbol)) {
+ return true;
+ } else {
const FileDescriptor* other_file = tables_->FindSymbol(full_name).GetFile();
if (other_file == file_) {
string::size_type dot_pos = full_name.find_last_of('.');
@@ -1944,6 +1948,7 @@ void DescriptorBuilder::AddSymbol(
"\"" + full_name + "\" is already defined in file \"" +
other_file->name() + "\".");
}
+ return false;
}
}
@@ -2480,14 +2485,41 @@ void DescriptorBuilder::BuildEnumValue(const EnumValueDescriptorProto& proto,
// Again, enum values are weird because we makes them appear as siblings
// of the enum type instead of children of it. So, we use
// parent->containing_type() as the value's parent.
- AddSymbol(result->full_name(), parent->containing_type(), result->name(),
- proto, Symbol(result));
+ bool added_to_outer_scope =
+ AddSymbol(result->full_name(), parent->containing_type(), result->name(),
+ proto, Symbol(result));
// However, we also want to be able to search for values within a single
// enum type, so we add it as a child of the enum type itself, too.
// Note: This could fail, but if it does, the error has already been
// reported by the above AddSymbol() call, so we ignore the return code.
- tables_->AddAliasUnderParent(parent, result->name(), Symbol(result));
+ bool added_to_inner_scope =
+ tables_->AddAliasUnderParent(parent, result->name(), Symbol(result));
+
+ if (added_to_inner_scope && !added_to_outer_scope) {
+ // This value did not conflict with any values defined in the same enum,
+ // but it did conflict with some other symbol defined in the enum type's
+ // scope. Let's print an additional error to explain this.
+ string outer_scope;
+ if (parent->containing_type() == NULL) {
+ outer_scope = file_->package();
+ } else {
+ outer_scope = parent->containing_type()->full_name();
+ }
+
+ if (outer_scope.empty()) {
+ outer_scope = "the global scope";
+ } else {
+ outer_scope = "\"" + outer_scope + "\"";
+ }
+
+ AddError(result->full_name(), proto,
+ DescriptorPool::ErrorCollector::NAME,
+ "Note that enum values use C++ scoping rules, meaning that "
+ "enum values are siblings of their type, not children of it. "
+ "Therefore, \"" + result->name() + "\" must be unique within "
+ + outer_scope + ", not just within \"" + parent->name() + "\".");
+ }
// An enum is allowed to define two numbers that refer to the same value.
// FindValueByNumber() should return the first such value, so we simply
diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h
index 2bba4c38..4203f496 100644
--- a/src/google/protobuf/descriptor.h
+++ b/src/google/protobuf/descriptor.h
@@ -128,6 +128,7 @@ class LIBPROTOBUF_EXPORT Descriptor {
// The number of fields in this message type.
int field_count() const;
// Gets a field by index, where 0 <= index < field_count().
+ // These are returned in the order they were defined in the .proto file.
const FieldDescriptor* field(int index) const;
// Looks up a field by declared tag number. Returns NULL if no such field
@@ -141,6 +142,7 @@ class LIBPROTOBUF_EXPORT Descriptor {
// The number of nested types in this message type.
int nested_type_count() const;
// Gets a nested type by index, where 0 <= index < nested_type_count().
+ // These are returned in the order they were defined in the .proto file.
const Descriptor* nested_type(int index) const;
// Looks up a nested type by name. Returns NULL if no such nested type
@@ -152,6 +154,7 @@ class LIBPROTOBUF_EXPORT Descriptor {
// The number of enum types in this message type.
int enum_type_count() const;
// Gets an enum type by index, where 0 <= index < enum_type_count().
+ // These are returned in the order they were defined in the .proto file.
const EnumDescriptor* enum_type(int index) const;
// Looks up an enum type by name. Returns NULL if no such enum type exists.
@@ -173,7 +176,8 @@ class LIBPROTOBUF_EXPORT Descriptor {
// The number of extension ranges in this message type.
int extension_range_count() const;
// Gets an extension range by index, where 0 <= index <
- // extension_range_count().
+ // extension_range_count(). These are returned in the order they were defined
+ // in the .proto file.
const ExtensionRange* extension_range(int index) const;
// Returns true if the number is in one of the extension ranges.
@@ -183,6 +187,7 @@ class LIBPROTOBUF_EXPORT Descriptor {
// defined nested within this message type's scope.
int extension_count() const;
// Get an extension by index, where 0 <= index < extension_count().
+ // These are returned in the order they were defined in the .proto file.
const FieldDescriptor* extension(int index) const;
// Looks up a named extension (which extends some *other* message type)
@@ -463,6 +468,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptor {
// than zero.
int value_count() const;
// Gets a value by index, where 0 <= index < value_count().
+ // These are returned in the order they were defined in the .proto file.
const EnumValueDescriptor* value(int index) const;
// Looks up a value by name. Returns NULL if no such value exists.
@@ -583,6 +589,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptor {
// The number of methods this service defines.
int method_count() const;
// Gets a MethodDescriptor by index, where 0 <= index < method_count().
+ // These are returned in the order they were defined in the .proto file.
const MethodDescriptor* method(int index) const;
// Look up a MethodDescriptor by name.
@@ -683,29 +690,34 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
// The number of files imported by this one.
int dependency_count() const;
// Gets an imported file by index, where 0 <= index < dependency_count().
+ // These are returned in the order they were defined in the .proto file.
const FileDescriptor* dependency(int index) const;
// Number of top-level message types defined in this file. (This does not
// include nested types.)
int message_type_count() const;
// Gets a top-level message type, where 0 <= index < message_type_count().
+ // These are returned in the order they were defined in the .proto file.
const Descriptor* message_type(int index) const;
// Number of top-level enum types defined in this file. (This does not
// include nested types.)
int enum_type_count() const;
// Gets a top-level enum type, where 0 <= index < enum_type_count().
+ // These are returned in the order they were defined in the .proto file.
const EnumDescriptor* enum_type(int index) const;
// Number of services defined in this file.
int service_count() const;
// Gets a service, where 0 <= index < service_count().
+ // These are returned in the order they were defined in the .proto file.
const ServiceDescriptor* service(int index) const;
// Number of extensions defined at file scope. (This does not include
// extensions nested within message types.)
int extension_count() const;
// Gets an extension's descriptor, where 0 <= index < extension_count().
+ // These are returned in the order they were defined in the .proto file.
const FieldDescriptor* extension(int index) const;
// Get options for this file. These are specified in the .proto
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index 27994dda..892f92d0 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -174,9 +174,9 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag
inline const ::std::string& dependency(int index) const;
inline ::std::string* mutable_dependency(int index);
inline void set_dependency(int index, const ::std::string& value);
+ inline void set_dependency(int index, const char* value);
inline ::std::string* add_dependency();
inline void add_dependency(const ::std::string& value);
- inline void set_dependency(int index, const char* value);
inline void add_dependency(const char* value);
// repeated .google.protobuf.DescriptorProto message_type = 4;
@@ -1835,15 +1835,15 @@ inline ::std::string* FileDescriptorProto::mutable_dependency(int index) {
inline void FileDescriptorProto::set_dependency(int index, const ::std::string& value) {
dependency_.Mutable(index)->assign(value);
}
+inline void FileDescriptorProto::set_dependency(int index, const char* value) {
+ dependency_.Mutable(index)->assign(value);
+}
inline ::std::string* FileDescriptorProto::add_dependency() {
return dependency_.Add();
}
inline void FileDescriptorProto::add_dependency(const ::std::string& value) {
dependency_.Add()->assign(value);
}
-inline void FileDescriptorProto::set_dependency(int index, const char* value) {
- dependency_.Mutable(index)->assign(value);
-}
inline void FileDescriptorProto::add_dependency(const char* value) {
dependency_.Add()->assign(value);
}
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
index 18397a66..25d6040d 100644
--- a/src/google/protobuf/descriptor_unittest.cc
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -1625,6 +1625,33 @@ TEST_F(ValidationErrorTest, PackageAlreadyDefined) {
"than a package) in file \"foo.proto\".\n");
}
+TEST_F(ValidationErrorTest, EnumValueAlreadyDefinedInParent) {
+ BuildFileWithErrors(
+ "name: \"foo.proto\" "
+ "enum_type { name: \"Foo\" value { name: \"FOO\" number: 1 } } "
+ "enum_type { name: \"Bar\" value { name: \"FOO\" number: 1 } } ",
+
+ "foo.proto: FOO: NAME: \"FOO\" is already defined.\n"
+ "foo.proto: FOO: NAME: Note that enum values use C++ scoping rules, "
+ "meaning that enum values are siblings of their type, not children of "
+ "it. Therefore, \"FOO\" must be unique within the global scope, not "
+ "just within \"Bar\".\n");
+}
+
+TEST_F(ValidationErrorTest, EnumValueAlreadyDefinedInParentNonGlobal) {
+ BuildFileWithErrors(
+ "name: \"foo.proto\" "
+ "package: \"pkg\" "
+ "enum_type { name: \"Foo\" value { name: \"FOO\" number: 1 } } "
+ "enum_type { name: \"Bar\" value { name: \"FOO\" number: 1 } } ",
+
+ "foo.proto: pkg.FOO: NAME: \"FOO\" is already defined in \"pkg\".\n"
+ "foo.proto: pkg.FOO: NAME: Note that enum values use C++ scoping rules, "
+ "meaning that enum values are siblings of their type, not children of "
+ "it. Therefore, \"FOO\" must be unique within \"pkg\", not just within "
+ "\"Bar\".\n");
+}
+
TEST_F(ValidationErrorTest, MissingName) {
BuildFileWithErrors(
"name: \"foo.proto\" "
diff --git a/src/google/protobuf/io/tokenizer_unittest.cc b/src/google/protobuf/io/tokenizer_unittest.cc
index e2cede7e..2171fcc3 100644
--- a/src/google/protobuf/io/tokenizer_unittest.cc
+++ b/src/google/protobuf/io/tokenizer_unittest.cc
@@ -477,22 +477,22 @@ TEST_F(TokenizerTest, ParseInteger) {
// Test invalid integers that may still be tokenized as integers.
EXPECT_EQ(0, ParseInteger("0x"));
+ uint64 i;
#ifdef GTEST_HAS_DEATH_TEST // death tests do not work on Windows yet
// Test invalid integers that will never be tokenized as integers.
- EXPECT_DEBUG_DEATH(ParseInteger("zxy"),
+ EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("zxy", kuint64max, &i),
"passed text that could not have been tokenized as an integer");
- EXPECT_DEBUG_DEATH(ParseInteger("1.2"),
+ EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("1.2", kuint64max, &i),
"passed text that could not have been tokenized as an integer");
- EXPECT_DEBUG_DEATH(ParseInteger("08"),
+ EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("08", kuint64max, &i),
"passed text that could not have been tokenized as an integer");
- EXPECT_DEBUG_DEATH(ParseInteger("0xg"),
+ EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("0xg", kuint64max, &i),
"passed text that could not have been tokenized as an integer");
- EXPECT_DEBUG_DEATH(ParseInteger("-1"),
+ EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("-1", kuint64max, &i),
"passed text that could not have been tokenized as an integer");
#endif // GTEST_HAS_DEATH_TEST
// Test overflows.
- uint64 i;
EXPECT_TRUE (Tokenizer::ParseInteger("0", 0, &i));
EXPECT_FALSE(Tokenizer::ParseInteger("1", 0, &i));
EXPECT_TRUE (Tokenizer::ParseInteger("1", 1, &i));