In progress: [Issue 164] Validate that the default value of a field
matches the type of such field.

Added "quick fix" for errors found in default values of numeric fields.
diff --git a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/core/XtextRule.java b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/core/XtextRule.java
index 0b445be..6cccc7e 100644
--- a/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/core/XtextRule.java
+++ b/com.google.eclipse.protobuf.test/src/com/google/eclipse/protobuf/junit/core/XtextRule.java
@@ -73,10 +73,8 @@
     boolean ignoreSyntaxErrors = shouldIgnoreSyntaxErrorsIn(text);
     resource = resourceFrom(new StringInputStream(text));
     IParseResult parseResult = resource.getParseResult();
-    if (ignoreSyntaxErrors) {
-      root = (Protobuf) parseResult.getRootASTElement();
-      return;
-    }
+    root = (Protobuf) parseResult.getRootASTElement();
+    if (ignoreSyntaxErrors) return;
     if (!parseResult.hasSyntaxErrors()) {
       if (root.getSyntax() == null) {
         throw new IllegalStateException("Please specify 'proto2' syntax");
diff --git a/com.google.eclipse.protobuf.ui/icons/change.gif b/com.google.eclipse.protobuf.ui/icons/change.gif
new file mode 100644
index 0000000..068e18d
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/icons/change.gif
Binary files differ
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/grammar/CompoundElement.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/grammar/CompoundElement.java
index 258065a..d21b959 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/grammar/CompoundElement.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/grammar/CompoundElement.java
@@ -9,6 +9,7 @@
 package com.google.eclipse.protobuf.ui.grammar;
 
 import static com.google.eclipse.protobuf.grammar.CommonKeyword.*;
+import static com.google.eclipse.protobuf.grammar.ValidSyntax.proto2;
 import static com.google.eclipse.protobuf.util.CommonWords.space;
 
 import com.google.eclipse.protobuf.grammar.CommonKeyword;
@@ -26,7 +27,7 @@
   EMPTY_STRING(join(QUOTE, QUOTE)),
   DEFAULT_EQUAL_STRING(joinWithWhitespace(DEFAULT_EQUAL, EMPTY_STRING)),
   DEFAULT_EQUAL_STRING_IN_BRACKETS(inBrackets(DEFAULT_EQUAL_STRING)),
-  PROTO2_IN_QUOTES(join(QUOTE, "proto2", QUOTE, SEMICOLON)),
+  PROTO2_IN_QUOTES(join(QUOTE, proto2(), QUOTE, SEMICOLON)),
   EQUAL_PROTO2_IN_QUOTES(joinWithWhitespace(EQUAL, PROTO2_IN_QUOTES));
 
   private final String value;
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/quickfix/Messages.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/quickfix/Messages.java
index b1048ba..6a1d456 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/quickfix/Messages.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/quickfix/Messages.java
@@ -16,11 +16,10 @@
  */
 public class Messages extends NLS {
 
-  public static String changeToProto2;
-  public static String changeToProto2Label;
-  public static String regenerateTagNumber;
+  public static String changeValueDescription;
+  public static String changeValueLabel;
   public static String regenerateTagNumberLabel;
-  public static String removeDuplicatePackage;
+  public static String regenerateTagNumberDescription;
   public static String removeDuplicatePackageLabel;
 
   static {
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/quickfix/Messages.properties b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/quickfix/Messages.properties
index 21e5a91..efbe0b8 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/quickfix/Messages.properties
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/quickfix/Messages.properties
@@ -1,6 +1,5 @@
-changeToProto2=Change syntax to "proto2."
-changeToProto2Label=Change syntax to "proto2"
-regenerateTagNumber=Regenerate tag number.
+changeValueDescription=%s = %s
+changeValueLabel=Change value to '%s'
 regenerateTagNumberLabel=Regenerate tag number
-removeDuplicatePackage=Remove duplicate package declaration.
+regenerateTagNumberDescription=Regenerate tag number.
 removeDuplicatePackageLabel=Remove duplicate package declaration
\ No newline at end of file
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/quickfix/ProtobufQuickfixProvider.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/quickfix/ProtobufQuickfixProvider.java
index e2e2626..bd694c6 100644
--- a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/quickfix/ProtobufQuickfixProvider.java
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/quickfix/ProtobufQuickfixProvider.java
@@ -1,27 +1,36 @@
 /*
  * Copyright (c) 2011 Google Inc.
  *
- * All rights reserved. This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License v1.0 which
- * accompanies this distribution, and is available at
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
  *
  * http://www.eclipse.org/legal/epl-v10.html
  */
 package com.google.eclipse.protobuf.ui.quickfix;
 
+import static com.google.eclipse.protobuf.grammar.ValidSyntax.proto2;
+import static com.google.eclipse.protobuf.protobuf.BOOL.*;
 import static com.google.eclipse.protobuf.ui.quickfix.Messages.*;
+import static com.google.eclipse.protobuf.util.Strings.quote;
+import static com.google.eclipse.protobuf.validation.DataTypeValidator.*;
 import static com.google.eclipse.protobuf.validation.ProtobufJavaValidator.*;
 import static org.eclipse.emf.ecore.util.EcoreUtil.remove;
+import static org.eclipse.xtext.nodemodel.util.NodeModelUtils.findActualNodeFor;
 
 import org.eclipse.emf.ecore.EObject;
+import org.eclipse.xtext.nodemodel.INode;
+import org.eclipse.xtext.resource.XtextResource;
+import org.eclipse.xtext.ui.editor.model.IXtextDocument;
 import org.eclipse.xtext.ui.editor.model.edit.*;
 import org.eclipse.xtext.ui.editor.quickfix.*;
+import org.eclipse.xtext.util.concurrent.IUnitOfWork;
 import org.eclipse.xtext.validation.Issue;
 
-import com.google.eclipse.protobuf.model.util.IndexedElements;
+import com.google.eclipse.protobuf.grammar.CommonKeyword;
+import com.google.eclipse.protobuf.model.util.*;
+import com.google.eclipse.protobuf.naming.NameResolver;
 import com.google.eclipse.protobuf.protobuf.*;
 import com.google.eclipse.protobuf.protobuf.Package;
-import com.google.eclipse.protobuf.ui.labeling.Images;
 import com.google.inject.Inject;
 
 /**
@@ -29,42 +38,118 @@
  */
 public class ProtobufQuickfixProvider extends DefaultQuickfixProvider {
 
+  private static final String ICON_FOR_CHANGE = "change.gif";
+
   @Inject private IndexedElements indexedElements;
-  @Inject private Images images;
+  @Inject private NameResolver nameResolver;
+  @Inject private INodes nodes;
 
   @Fix(SYNTAX_IS_NOT_PROTO2_ERROR)
-  public void makeSyntaxProto2(Issue issue, IssueResolutionAcceptor acceptor) {
-    String image = images.imageFor(Syntax.class);
-    acceptor.accept(issue, changeToProto2Label, changeToProto2, image, new ISemanticModification() {
+  public void changeSyntaxToProto2(Issue issue, IssueResolutionAcceptor acceptor) {
+    ISemanticModification modification = new ISemanticModification() {
       @Override public void apply(EObject element, IModificationContext context) throws Exception {
-        if (!(element instanceof Syntax)) return;
         Syntax syntax = (Syntax) element;
-        syntax.setName("proto2");
+        syntax.setName(proto2());
       }
-    });
+    };
+    String description = String.format(changeValueDescription, "syntax", quote(proto2()));
+    String label = String.format(changeValueLabel, proto2());
+    acceptor.accept(issue, label, description, ICON_FOR_CHANGE, modification);
   }
 
   @Fix(INVALID_FIELD_TAG_NUMBER_ERROR)
   public void regenerateTagNumber(Issue issue, IssueResolutionAcceptor acceptor) {
-    acceptor.accept(issue, regenerateTagNumberLabel, regenerateTagNumber, "field.gif", new ISemanticModification() {
+    ISemanticModification modification = new ISemanticModification() {
       @Override public void apply(EObject element, IModificationContext context) throws Exception {
-        if (!(element instanceof IndexedElement)) return;
         IndexedElement e = (IndexedElement) element;
         long tagNumber = indexedElements.calculateTagNumberOf(e);
         indexedElements.setIndexTo(e, tagNumber);
       }
-    });
+    };
+    acceptor.accept(issue, regenerateTagNumberLabel, regenerateTagNumberDescription, "field.gif", modification);
   }
 
   @Fix(MORE_THAN_ONE_PACKAGE_ERROR)
   public void removeDuplicatePackage(Issue issue, IssueResolutionAcceptor acceptor) {
-    acceptor.accept(issue, removeDuplicatePackageLabel, removeDuplicatePackage, "remove.gif",
-        new ISemanticModification() {
-          @Override public void apply(EObject element, IModificationContext context) throws Exception {
-            if (!(element instanceof Package)) return;
-            Package aPackage = (Package) element;
-            remove(aPackage);
-          }
-        });
+    final Package aPackage = element(issue, Package.class);
+    if (aPackage == null) return;
+    ISemanticModification modification = new ISemanticModification() {
+      @Override public void apply(EObject element, IModificationContext context) throws Exception {
+        if (!(element instanceof Package)) return;
+        remove(aPackage);
+      }
+    };
+    INode node = findActualNodeFor(aPackage);
+    String description = nodes.textOf(node);
+    acceptor.accept(issue, removeDuplicatePackageLabel, description, "remove.gif", modification);
+  }
+
+  @Fix(EXPECTED_BOOL_ERROR)
+  public void changeValueToTrue(Issue issue, IssueResolutionAcceptor acceptor) {
+    EObject element = elementIn(issue);
+    if (element instanceof FieldOption) {
+      FieldOption option = (FieldOption) element;
+      changeValue(option, linkTo(TRUE), CommonKeyword.TRUE, issue, acceptor);
+    }
+  }
+
+  @Fix(EXPECTED_BOOL_ERROR)
+  public void changeValueToFalse(Issue issue, IssueResolutionAcceptor acceptor) {
+    EObject element = elementIn(issue);
+    if (element instanceof FieldOption) {
+      FieldOption option = (FieldOption) element;
+      changeValue(option, linkTo(FALSE), CommonKeyword.FALSE, issue, acceptor);
+    }
+  }
+
+  // TODO rename BooleanLink to BoolLink
+  private BooleanLink linkTo(BOOL value) {
+    BooleanLink link = ProtobufFactory.eINSTANCE.createBooleanLink();
+    link.setTarget(value);
+    return link;
+  }
+
+  @Fix(EXPECTED_STRING_ERROR)
+  public void changeValueToEmptyString(Issue issue, IssueResolutionAcceptor acceptor) {
+    EObject element = elementIn(issue);
+    if (element instanceof FieldOption) {
+      FieldOption option = (FieldOption) element;
+      String valueToPropose = "";
+      changeValue(option, linkTo(valueToPropose), valueToPropose, issue, acceptor);
+    }
+  }
+
+  private StringLink linkTo(String value) {
+    StringLink link = ProtobufFactory.eINSTANCE.createStringLink();
+    link.setTarget(value);
+    return link;
+  }
+
+  private void changeValue(final FieldOption option, final Value newValue, Object proposedValue, Issue issue,
+      IssueResolutionAcceptor acceptor) {
+    ISemanticModification modification = new ISemanticModification() {
+      @Override public void apply(EObject element, IModificationContext context) throws Exception {
+        option.setValue(newValue);
+      }
+    };
+    String name = nameResolver.nameOf(option);
+    String description = String.format(changeValueDescription, name, proposedValue);
+    String label = String.format(changeValueLabel, proposedValue);
+    acceptor.accept(issue, label, description, ICON_FOR_CHANGE, modification);
+  }
+
+  private EObject elementIn(Issue issue) {
+    return element(issue, EObject.class);
+  }
+
+  private <T extends EObject> T element(final Issue issue, final Class<T> type) {
+    IModificationContext modificationContext = getModificationContextFactory().createModificationContext(issue);
+    IXtextDocument xtextDocument = modificationContext.getXtextDocument();
+    return xtextDocument.readOnly(new IUnitOfWork<T, XtextResource>() {
+      @Override public T exec(XtextResource state) throws Exception {
+        EObject e = state.getEObject(issue.getUriToProblem().fragment());
+        return (type.isInstance(e)) ? type.cast(e) : null;
+      }
+    });
   }
 }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/Protobuf.xtext b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/Protobuf.xtext
index d455e5d..d104050 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/Protobuf.xtext
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/Protobuf.xtext
@@ -88,7 +88,7 @@
   target=[ComplexType|QualifiedName];
 
 Enum:
-  'enum' name=Name '{'
+  =>'enum' name=Name '{'
   elements+=EnumElement*
   '}' ';'?;
 
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/grammar/ValidSyntax.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/grammar/ValidSyntax.java
new file mode 100644
index 0000000..c57cf8c
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/grammar/ValidSyntax.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.grammar;
+
+/**
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public final class ValidSyntax {
+
+  public static String proto2() {
+    return "proto2";
+  }
+
+  public static boolean isProto2Syntax(String s) {
+    return proto2().equals(s);
+  }
+
+  private ValidSyntax() {}
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/INodes.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/INodes.java
index 20debce..95bcc68 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/INodes.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/INodes.java
@@ -110,10 +110,11 @@
 
   /**
    * Returns the text of the given node, with leading and trailing whitespace omitted.
-   * @param node the given node.
-   * @return  the text of the given node, with leading and trailing whitespace omitted.
+   * @param node the given node, may be {@code null}.
+   * @return the text of the given node, with leading and trailing whitespace omitted.
    */
   public String textOf(INode node) {
+    if (node == null) return null;
     String text = node.getText();
     return (text == null) ? null : text.trim();
   }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/MessageFields.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/MessageFields.java
index ffcd151..16df608 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/MessageFields.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/model/util/MessageFields.java
@@ -56,6 +56,15 @@
   }
 
   /**
+   * Indicates whether the given field is of type {@code bytes}.
+   * @param field the given field.
+   * @return {@code true} if the given field is of type {@code bytes}, {@code false} otherwise.
+   */
+  public boolean isBytes(MessageField field) {
+    return isScalarType(field, BYTES);
+  }
+
+  /**
    * Indicates whether the given field is of type {@code float} or {@code double}.
    * @param field the given field.
    * @return {@code true} if the given field is a floating point number, {@code false} otherwise.
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/NameResolver.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/NameResolver.java
index 45258ed..ba95742 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/NameResolver.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/naming/NameResolver.java
@@ -10,22 +10,28 @@
 
 import static org.eclipse.xtext.util.SimpleAttributeResolver.NAME_RESOLVER;
 
-import com.google.inject.Singleton;
-
 import org.eclipse.emf.ecore.*;
 
+import com.google.eclipse.protobuf.grammar.CommonKeyword;
+import com.google.eclipse.protobuf.protobuf.DefaultValueFieldOption;
+import com.google.inject.Singleton;
+
 /**
+ * TODO test
  * @author alruiz@google.com (Alex Ruiz)
  */
 @Singleton
 public class NameResolver {
 
   public String nameOf(EObject o) {
+    if (o instanceof DefaultValueFieldOption) {
+      return CommonKeyword.DEFAULT.toString();
+    }
     Object value = nameFeatureOf(o);
     if (value instanceof String) return (String) value;
     return null;
   }
-  
+
   private Object nameFeatureOf(EObject e) {
     EStructuralFeature f = NAME_RESOLVER.getAttribute(e);
     return (f != null) ? e.eGet(f) : null;
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/Strings.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/Strings.java
new file mode 100644
index 0000000..b909361
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/Strings.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2011 Google Inc.
+ *
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
+ * Public License v1.0 which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ */
+package com.google.eclipse.protobuf.util;
+
+/**
+ * Utility methods related to {@code String}.s
+ *
+ * @author alruiz@google.com (Alex Ruiz)
+ */
+public final class Strings {
+
+  /**
+   * Returns the given {@code String} in double quotes.
+   * @param s the given {@code String}, may be {@code null}.
+   * @return  the given {@code String} in double quotes, or {@code null} if the given {@code String} is {@code null}.
+   */
+  public static String quote(String s) {
+    if (s == null) return s;
+    return "\"" + s + "\"";
+  }
+
+  private Strings() {}
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/DataTypeValidator.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/DataTypeValidator.java
index 4e4a82a..4d1b8bf 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/DataTypeValidator.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/DataTypeValidator.java
@@ -25,6 +25,9 @@
  */
 public class DataTypeValidator extends AbstractDeclarativeValidator {
 
+  public static final String EXPECTED_BOOL_ERROR = "expectedBool";
+  public static final String EXPECTED_STRING_ERROR = "expectedString";
+
   @Override public void register(EValidatorRegistrar registrar) {}
 
   @Inject private FieldOptions fieldOptions;
@@ -52,7 +55,7 @@
     if (!messageFields.isBool(field)) return false;
     Value value = option.getValue();
     if (!(value instanceof BooleanLink)) {
-      error(expectedTrueOrFalse, FIELD_OPTION__VALUE);
+      error(expectedTrueOrFalse, option, FIELD_OPTION__VALUE, EXPECTED_BOOL_ERROR);
     }
     return true;
   }
@@ -83,10 +86,10 @@
   }
 
   private boolean validateString(FieldOption option, MessageField field) {
-    if (!messageFields.isString(field)) return false;
+    if (!messageFields.isBytes(field) && !messageFields.isString(field)) return false;
     Value value = option.getValue();
     if (!(value instanceof StringLink)) {
-      error(expectedString, FIELD_OPTION__VALUE);
+      error(expectedString, option, FIELD_OPTION__VALUE, EXPECTED_STRING_ERROR);
     }
     return true;
   }
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufJavaValidator.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufJavaValidator.java
index 911bbb4..7722c39 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufJavaValidator.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufJavaValidator.java
@@ -8,6 +8,7 @@
  */
 package com.google.eclipse.protobuf.validation;
 
+import static com.google.eclipse.protobuf.grammar.ValidSyntax.isProto2Syntax;
 import static com.google.eclipse.protobuf.protobuf.ProtobufPackage.Literals.*;
 import static com.google.eclipse.protobuf.validation.Messages.*;
 import static java.lang.String.format;
@@ -67,7 +68,7 @@
 
   @Check public void checkSyntaxIsProto2(Syntax syntax) {
     String name = syntax.getName();
-    if ("proto2".equals(name)) return;
+    if (isProto2Syntax(name)) return;
     String msg = (name == null) ? expectedSyntaxIdentifier : format(unrecognizedSyntaxIdentifier, name);
     error(msg, syntax, SYNTAX__NAME, SYNTAX_IS_NOT_PROTO2_ERROR);
   }