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.
diff --git a/java/src/main/java/com/google/protobuf/TextFormat.java b/java/src/main/java/com/google/protobuf/TextFormat.java
index c4fdfe6..2d949b6 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 @@
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 @@
* 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 @@
* 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 6bcc430..ba4dd5a 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 @@
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 2c485c5..8b7af10 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 @@
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 @@
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 0ad2683..8919414 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 @@
.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 e36a96f..626816f 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 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 5d690da..be4276b 100755
--- a/python/google/protobuf/internal/encoder_test.py
+++ b/python/google/protobuf/internal/encoder_test.py
@@ -21,11 +21,11 @@
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 c2074db..c8fc79d 100755
--- a/python/google/protobuf/internal/text_format_test.py
+++ b/python/google/protobuf/internal/text_format_test.py
@@ -45,14 +45,16 @@
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 @@
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 @@
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 e74eb43..8590df7 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 @@
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 @@
" $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 @@
"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 @@
"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"
+ "$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, 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"
- "}\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 622895f..3b73530 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -1034,6 +1034,9 @@
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 c75cf62..48db0cc 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -1604,8 +1604,10 @@
// 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 @@
}
}
-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 @@
"\"" + full_name + "\" is already defined in file \"" +
other_file->name() + "\".");
}
+ return false;
}
}
@@ -2480,14 +2485,41 @@
// 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 2bba4c3..4203f49 100644
--- a/src/google/protobuf/descriptor.h
+++ b/src/google/protobuf/descriptor.h
@@ -128,6 +128,7 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 27994dd..892f92d 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -174,9 +174,9 @@
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 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 18397a6..25d6040 100644
--- a/src/google/protobuf/descriptor_unittest.cc
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -1625,6 +1625,33 @@
"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 e2cede7..2171fcc 100644
--- a/src/google/protobuf/io/tokenizer_unittest.cc
+++ b/src/google/protobuf/io/tokenizer_unittest.cc
@@ -477,22 +477,22 @@
// 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));