| Index: third_party/protobuf/java/core/src/main/java/com/google/protobuf/TextFormat.java | 
| diff --git a/third_party/protobuf/java/core/src/main/java/com/google/protobuf/TextFormat.java b/third_party/protobuf/java/core/src/main/java/com/google/protobuf/TextFormat.java | 
| index c1c328fc7d8d6ab01fa5521c73e3814ec9c39692..49708242156ca5ded0314f0ef0845c46b46cd694 100644 | 
| --- a/third_party/protobuf/java/core/src/main/java/com/google/protobuf/TextFormat.java | 
| +++ b/third_party/protobuf/java/core/src/main/java/com/google/protobuf/TextFormat.java | 
| @@ -661,6 +661,14 @@ public final class TextFormat { | 
| nextToken(); | 
| } | 
|  | 
| +    int getPreviousLine() { | 
| +      return previousLine; | 
| +    } | 
| + | 
| +    int getPreviousColumn() { | 
| +      return previousColumn; | 
| +    } | 
| + | 
| int getLine() { | 
| return line; | 
| } | 
| @@ -1374,6 +1382,28 @@ public final class TextFormat { | 
| return text; | 
| } | 
|  | 
| +    // Check both unknown fields and unknown extensions and log warming messages | 
| +    // or throw exceptions according to the flag. | 
| +    private void checkUnknownFields(final List<String> unknownFields) | 
| +        throws ParseException { | 
| +      if (unknownFields.isEmpty()) { | 
| +        return; | 
| +      } | 
| + | 
| +      StringBuilder msg = new StringBuilder("Input contains unknown fields and/or extensions:"); | 
| +      for (String field : unknownFields) { | 
| +        msg.append('\n').append(field); | 
| +      } | 
| + | 
| +      if (allowUnknownFields) { | 
| +          logger.warning(msg.toString()); | 
| +      } else { | 
| +        String[] lineColumn = unknownFields.get(0).split(":"); | 
| +        throw new ParseException(Integer.valueOf(lineColumn[0]), | 
| +            Integer.valueOf(lineColumn[1]), msg.toString()); | 
| +      } | 
| +    } | 
| + | 
| /** | 
| * Parse a text-format message from {@code input} and merge the contents | 
| * into {@code builder}.  Extensions will be recognized if they are | 
| @@ -1387,9 +1417,13 @@ public final class TextFormat { | 
| MessageReflection.BuilderAdapter target = | 
| new MessageReflection.BuilderAdapter(builder); | 
|  | 
| +      List<String> unknownFields = new ArrayList<String>(); | 
| + | 
| while (!tokenizer.atEnd()) { | 
| -        mergeField(tokenizer, extensionRegistry, target); | 
| +        mergeField(tokenizer, extensionRegistry, target, unknownFields); | 
| } | 
| + | 
| +      checkUnknownFields(unknownFields); | 
| } | 
|  | 
|  | 
| @@ -1399,9 +1433,11 @@ public final class TextFormat { | 
| */ | 
| private void mergeField(final Tokenizer tokenizer, | 
| final ExtensionRegistry extensionRegistry, | 
| -                            final MessageReflection.MergeTarget target) | 
| +                            final MessageReflection.MergeTarget target, | 
| +                            List<String> unknownFields) | 
| throws ParseException { | 
| -      mergeField(tokenizer, extensionRegistry, target, parseInfoTreeBuilder); | 
| +      mergeField(tokenizer, extensionRegistry, target, parseInfoTreeBuilder, | 
| +                 unknownFields); | 
| } | 
|  | 
| /** | 
| @@ -1411,7 +1447,8 @@ public final class TextFormat { | 
| private void mergeField(final Tokenizer tokenizer, | 
| final ExtensionRegistry extensionRegistry, | 
| final MessageReflection.MergeTarget target, | 
| -                            TextFormatParseInfoTree.Builder parseTreeBuilder) | 
| +                            TextFormatParseInfoTree.Builder parseTreeBuilder, | 
| +                            List<String> unknownFields) | 
| throws ParseException { | 
| FieldDescriptor field = null; | 
| int startLine = tokenizer.getLine(); | 
| @@ -1432,13 +1469,9 @@ public final class TextFormat { | 
| extensionRegistry, name.toString()); | 
|  | 
| if (extension == null) { | 
| -          if (!allowUnknownFields) { | 
| -            throw tokenizer.parseExceptionPreviousToken( | 
| -              "Extension \"" + name + "\" not found in the ExtensionRegistry."); | 
| -          } else { | 
| -            logger.warning( | 
| -              "Extension \"" + name + "\" not found in the ExtensionRegistry."); | 
| -          } | 
| +          unknownFields.add((tokenizer.getPreviousLine() + 1) + ":" + | 
| +              (tokenizer.getPreviousColumn() + 1) + ":\t" + | 
| +              type.getFullName() + ".[" + name + "]"); | 
| } else { | 
| if (extension.descriptor.getContainingType() != type) { | 
| throw tokenizer.parseExceptionPreviousToken( | 
| @@ -1473,16 +1506,9 @@ public final class TextFormat { | 
| } | 
|  | 
| if (field == null) { | 
| -          if (!allowUnknownFields) { | 
| -            throw tokenizer.unknownFieldParseExceptionPreviousToken( | 
| -              name, | 
| -              "Message type \"" + type.getFullName() | 
| -              + "\" has no field named \"" + name + "\"."); | 
| -          } else { | 
| -            logger.warning( | 
| -              "Message type \"" + type.getFullName() | 
| -              + "\" has no field named \"" + name + "\"."); | 
| -          } | 
| +          unknownFields.add((tokenizer.getPreviousLine() + 1) + ":" + | 
| +              (tokenizer.getPreviousColumn() + 1) + ":\t" + | 
| +              type.getFullName() + "." + name); | 
| } | 
| } | 
|  | 
| @@ -1511,15 +1537,15 @@ public final class TextFormat { | 
| TextFormatParseInfoTree.Builder childParseTreeBuilder = | 
| parseTreeBuilder.getBuilderForSubMessageField(field); | 
| consumeFieldValues(tokenizer, extensionRegistry, target, field, extension, | 
| -              childParseTreeBuilder); | 
| +              childParseTreeBuilder, unknownFields); | 
| } else { | 
| consumeFieldValues(tokenizer, extensionRegistry, target, field, extension, | 
| -              parseTreeBuilder); | 
| +              parseTreeBuilder, unknownFields); | 
| } | 
| } else { | 
| tokenizer.consume(":");  // required | 
| -        consumeFieldValues( | 
| -            tokenizer, extensionRegistry, target, field, extension, parseTreeBuilder); | 
| +        consumeFieldValues(tokenizer, extensionRegistry, target, field, | 
| +            extension, parseTreeBuilder, unknownFields); | 
| } | 
|  | 
| if (parseTreeBuilder != null) { | 
| @@ -1544,23 +1570,32 @@ public final class TextFormat { | 
| final MessageReflection.MergeTarget target, | 
| final FieldDescriptor field, | 
| final ExtensionRegistry.ExtensionInfo extension, | 
| -        final TextFormatParseInfoTree.Builder parseTreeBuilder) | 
| +        final TextFormatParseInfoTree.Builder parseTreeBuilder, | 
| +        List<String> unknownFields) | 
| throws ParseException { | 
| // Support specifying repeated field values as a comma-separated list. | 
| // Ex."foo: [1, 2, 3]" | 
| if (field.isRepeated() && tokenizer.tryConsume("[")) { | 
| -        while (true) { | 
| -          consumeFieldValue(tokenizer, extensionRegistry, target, field, extension, | 
| -              parseTreeBuilder); | 
| -          if (tokenizer.tryConsume("]")) { | 
| -            // End of list. | 
| -            break; | 
| +        if (!tokenizer.tryConsume("]")) {  // Allow "foo: []" to be treated as empty. | 
| +          while (true) { | 
| +            consumeFieldValue( | 
| +                tokenizer, | 
| +                extensionRegistry, | 
| +                target, | 
| +                field, | 
| +                extension, | 
| +                parseTreeBuilder, | 
| +                unknownFields); | 
| +            if (tokenizer.tryConsume("]")) { | 
| +              // End of list. | 
| +              break; | 
| +            } | 
| +            tokenizer.consume(","); | 
| } | 
| -          tokenizer.consume(","); | 
| } | 
| } else { | 
| -        consumeFieldValue( | 
| -            tokenizer, extensionRegistry, target, field, extension, parseTreeBuilder); | 
| +        consumeFieldValue(tokenizer, extensionRegistry, target, field, | 
| +            extension, parseTreeBuilder, unknownFields); | 
| } | 
| } | 
|  | 
| @@ -1574,7 +1609,8 @@ public final class TextFormat { | 
| final MessageReflection.MergeTarget target, | 
| final FieldDescriptor field, | 
| final ExtensionRegistry.ExtensionInfo extension, | 
| -        final TextFormatParseInfoTree.Builder parseTreeBuilder) | 
| +        final TextFormatParseInfoTree.Builder parseTreeBuilder, | 
| +        List<String> unknownFields) | 
| throws ParseException { | 
| Object value = null; | 
|  | 
| @@ -1596,7 +1632,8 @@ public final class TextFormat { | 
| throw tokenizer.parseException( | 
| "Expected \"" + endToken + "\"."); | 
| } | 
| -          mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder); | 
| +          mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder, | 
| +              unknownFields); | 
| } | 
|  | 
| value = subField.finish(); | 
|  |