Further improve messages in module loading.

Change-Id: Id70efb22497e079ee6b450552c1c4235a879d92a
diff --git a/dev/core/src/com/google/gwt/dev/cfg/Messages.java b/dev/core/src/com/google/gwt/dev/cfg/Messages.java
index 449278a..28894a0 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/Messages.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/Messages.java
@@ -17,31 +17,28 @@
 
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.dev.util.msg.Message0;
-import com.google.gwt.dev.util.msg.Message1String;
-import com.google.gwt.dev.util.msg.Message2ClassClass;
+import com.google.gwt.dev.util.msg.Message2IntString;
+import com.google.gwt.dev.util.msg.Message3IntStringString;
+import com.google.gwt.dev.util.msg.Message4IntStringStringString;
 
 /**
  * User messages related to configuration.
  */
 class Messages {
+  public static final Message2IntString LINKER_NAME_INVALID = new Message2IntString(
+      TreeLogger.ERROR, "Line $0: Invalid linker name '$1'");
 
-  public static final Message2ClassClass INVALID_CLASS_DERIVATION = new Message2ClassClass(
-      TreeLogger.ERROR, "Class '$0' must derive from '$1'");
+  public static final Message2IntString NAME_INVALID = new Message2IntString(
+      TreeLogger.ERROR, "Line $0: Invalid name '$1'");
 
-  public static final Message1String LINKER_NAME_INVALID = new Message1String(
-      TreeLogger.ERROR, "Invalid linker name '$0'");
+  public static final Message2IntString PROPERTY_NAME_INVALID = new Message2IntString(
+      TreeLogger.ERROR, "Line $0: Invalid property name '$1'");
 
-  public static final Message1String NAME_INVALID = new Message1String(
-      TreeLogger.ERROR, "Invalid name '$0'");
+  public static final Message2IntString PROPERTY_NOT_FOUND = new Message2IntString(
+      TreeLogger.ERROR, "Line $0: Property '$1' not found");
 
-  public static final Message1String PROPERTY_NAME_INVALID = new Message1String(
-      TreeLogger.ERROR, "Invalid property name '$0'");
-
-  public static final Message1String PROPERTY_NOT_FOUND = new Message1String(
-      TreeLogger.ERROR, "Property '$0' not found");
-
-  public static final Message1String PROPERTY_VALUE_INVALID = new Message1String(
-      TreeLogger.ERROR, "Invalid property value '$0'");
+  public static final Message2IntString PROPERTY_VALUE_INVALID = new Message2IntString(
+      TreeLogger.ERROR, "Line $0: Invalid property value '$1'");
 
   public static final Message0 PUBLIC_PATH_LOCATIONS = new Message0(
       TreeLogger.TRACE, "Public resources found in...");
@@ -49,9 +46,23 @@
   public static final Message0 SOURCE_PATH_LOCATIONS = new Message0(
       TreeLogger.TRACE, "Translatable source found in...");
 
-  public static final Message1String UNABLE_TO_CREATE_OBJECT = new Message1String(
-      TreeLogger.ERROR, "Unable to create an instance of '$0'");
+  public static final Message2IntString UNABLE_TO_LOAD_CLASS = new Message2IntString(
+      TreeLogger.ERROR, "Line $0: Unable to load class '$1'");
 
-  public static final Message1String UNABLE_TO_LOAD_CLASS = new Message1String(
-      TreeLogger.ERROR, "Unable to load class '$0'");
+  public static final Message3IntStringString PROPERTY_VALUE_NOT_VALID =
+      new Message3IntStringString(TreeLogger.ERROR,
+          "Line $0: Value '$1' in not a valid value for property '$2'");
+
+  public static final Message3IntStringString UNDEFINED_CONFIGURATION_PROPERTY =
+      new Message3IntStringString(TreeLogger.WARN,
+          "Line $0: Setting configuration property named '$1' in module '$2' "
+              + "that has not been previously defined");
+
+  public static final Message2IntString CONFIGURATION_PROPERTY_REDEFINES_BINDING_PROPERTY =
+      new Message2IntString(TreeLogger.ERROR,
+          "Line $0: Property '$1' is already defined as a deferred-binding property");
+
+  public static final Message4IntStringStringString CANNOT_REPLACE_PROPERTY =
+      new Message4IntStringStringString(TreeLogger.ERROR,
+          "Line $0: Property '$1' cannot replace property '$2' of unknown type '$3'");
 }
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java
index cb36293..afb2cba 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java
@@ -218,7 +218,7 @@
     protected Schema __add_linker_begin(LinkerName name)
         throws UnableToCompleteException {
       if (moduleDef.getLinker(name.name) == null) {
-        Messages.LINKER_NAME_INVALID.log(logger, name.name, null);
+        Messages.LINKER_NAME_INVALID.log(logger, getLineNumber(), name.name, null);
         throw new UnableToCompleteException();
       }
       moduleDef.addLinker(name.name);
@@ -632,20 +632,17 @@
         if (!propertySettings.containsKey(name.token)) {
           propertySettings.put(name.token, moduleName);
         }
-
-        logger.log(TreeLogger.WARN, "Setting configuration property named "
-            + name.token + " in " + moduleName
-            + " that has not been previously defined."
-            + "  This may be disallowed in the future.");
+        Messages.UNDEFINED_CONFIGURATION_PROPERTY.log(
+            logger, getLineNumber(), name.token, moduleName, null);
       } else if (!(existingProperty instanceof ConfigurationProperty)) {
         if (existingProperty instanceof BindingProperty) {
-          logger.log(TreeLogger.ERROR, "The property " + name.token
-              + " is already defined as a deferred-binding property");
+          Messages.CONFIGURATION_PROPERTY_REDEFINES_BINDING_PROPERTY.log(
+              logger, getLineNumber(), name.token, null);
         } else {
           // Future proofing if other subclasses are added.
-          logger.log(TreeLogger.ERROR, "May not replace property named "
-              + name.token + " of unknown type "
-              + existingProperty.getClass().getName());
+          Messages.CANNOT_REPLACE_PROPERTY.log(
+              logger, getLineNumber(), name.token, existingProperty.getName(),
+              existingProperty.getClass().getName(), null);
         }
         throw new UnableToCompleteException();
       }
@@ -669,8 +666,8 @@
       String[] stringValues = new String[value.length];
       for (int i = 0, len = stringValues.length; i < len; i++) {
         if (!prop.isDefinedValue(stringValues[i] = value[i].token)) {
-          logger.log(TreeLogger.ERROR, "The value " + stringValues[i]
-              + " was not previously defined.");
+          Messages.PROPERTY_VALUE_NOT_VALID.log(logger, getLineNumber(),
+              stringValues[i], prop.getName(), null);
           error = true;
         }
       }
@@ -904,7 +901,7 @@
         ClassLoader cl = Thread.currentThread().getContextClassLoader();
         return cl.loadClass(value);
       } catch (ClassNotFoundException e) {
-        Messages.UNABLE_TO_LOAD_CLASS.log(logger, value, e);
+        Messages.UNABLE_TO_LOAD_CLASS.log(logger, line, value, e);
         throw new UnableToCompleteException();
       }
     }
@@ -1024,7 +1021,7 @@
         String attr, String value) throws UnableToCompleteException {
       // Ensure the value is a valid Java identifier
       if (!Util.isValidJavaIdent(value)) {
-        Messages.LINKER_NAME_INVALID.log(logger, value, null);
+        Messages.LINKER_NAME_INVALID.log(logger, line, value, null);
         throw new UnableToCompleteException();
       }
 
@@ -1063,7 +1060,7 @@
       for (int i = 0; i < tokens.length - 1; i++) {
         String token = tokens[i];
         if (!Util.isValidJavaIdent(token)) {
-          Messages.NAME_INVALID.log(logger, value, null);
+          Messages.NAME_INVALID.log(logger, line, value, null);
           throw new UnableToCompleteException();
         }
       }
@@ -1104,7 +1101,7 @@
       } else {
         // Property not defined. This is a problem.
         //
-        Messages.PROPERTY_NOT_FOUND.log(logger, value, null);
+        Messages.PROPERTY_NOT_FOUND.log(logger, line, value, null);
       }
       throw new UnableToCompleteException();
     }
@@ -1201,7 +1198,7 @@
       for (int i = 0; i < tokens.length - 1; i++) {
         String token = tokens[i];
         if (!Util.isValidJavaIdent(token)) {
-          Messages.PROPERTY_NAME_INVALID.log(logger, value, null);
+          Messages.PROPERTY_NAME_INVALID.log(logger, line, value, null);
           throw new UnableToCompleteException();
         }
       }
@@ -1261,7 +1258,7 @@
       if (Util.isValidJavaIdent(token)) {
         return new PropertyValue(token);
       } else {
-        Messages.PROPERTY_VALUE_INVALID.log(logger, token, null);
+        Messages.PROPERTY_VALUE_INVALID.log(logger, line, token, null);
         throw new UnableToCompleteException();
       }
     }
@@ -1290,7 +1287,7 @@
       if (Util.isValidJavaIdent(token)) {
         return new PropertyFallbackValue(token);
       } else {
-        Messages.PROPERTY_VALUE_INVALID.log(logger, token, null);
+        Messages.PROPERTY_VALUE_INVALID.log(logger, line, token, null);
         throw new UnableToCompleteException();
       }
     }
@@ -1332,7 +1329,7 @@
           || Util.isValidJavaIdent(tokenNoStar)) {
         return new PropertyValueGlob(token);
       } else {
-        Messages.PROPERTY_VALUE_INVALID.log(logger, token, null);
+        Messages.PROPERTY_VALUE_INVALID.log(logger, line, token, null);
         throw new UnableToCompleteException();
       }
     }
@@ -1413,8 +1410,10 @@
   private final PropertyNameAttrCvt propNameAttrCvt = new PropertyNameAttrCvt();
   private final PropertyValueArrayAttrCvt propValueArrayAttrCvt = new PropertyValueArrayAttrCvt();
   private final PropertyValueAttrCvt propValueAttrCvt = new PropertyValueAttrCvt();
-  private final PropertyFallbackValueAttrCvt propFallbackValueAttrCvt = new PropertyFallbackValueAttrCvt();
-  private final PropertyValueGlobArrayAttrCvt propValueGlobArrayAttrCvt = new PropertyValueGlobArrayAttrCvt();
+  private final PropertyFallbackValueAttrCvt propFallbackValueAttrCvt =
+      new PropertyFallbackValueAttrCvt();
+  private final PropertyValueGlobArrayAttrCvt propValueGlobArrayAttrCvt =
+      new PropertyValueGlobArrayAttrCvt();
   private final PropertyValueGlobAttrCvt propValueGlobAttrCvt = new PropertyValueGlobAttrCvt();
 
   public ModuleDefSchema(TreeLogger logger, ModuleDefLoader loader,
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message.java b/dev/core/src/com/google/gwt/dev/util/msg/Message.java
index 899f0c0..5e983a3 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message.java
@@ -22,10 +22,14 @@
 import java.net.URL;
 
 /**
- * Fast way to produce messages for the logger. Use $N to specify the
- * replacement argument. Caveats: - N must be a single digit (you shouldn't need
- * more than 10 args, right?) - '$' cannot be escaped - each arg can only appear
- * once
+ * Fast way to produce messages for the logger. Use $N to specify the replacement argument.
+ * <p>
+ * Caveats:
+ * <ul>
+ * <li>N must be a single digit (you shouldn't need more than 10 args, right?)
+ * <li>'$' cannot be escaped
+ * <li>each arg can only appear once
+ * </ul>
  */
 public abstract class Message {
 
@@ -61,16 +65,14 @@
     int from = 0;
     for (int i = 0; i < args; ++i) {
       int to = fmt.indexOf('$', from);
-      if (to != -1) {
-        if (to < fmt.length() - 1) {
-          char charDigit = fmt.charAt(to + 1);
-          if (Character.isDigit(charDigit)) {
-            int digit = Character.digit(charDigit, 10);
-            fmtParts[i] = fmt.substring(from, to).toCharArray();
-            argIndices[i] = digit;
-            from = to + 2;
-            continue;
-          }
+      if (to != -1 && to < fmt.length() - 1) {
+        char charDigit = fmt.charAt(to + 1);
+        if (Character.isDigit(charDigit)) {
+          int digit = Character.digit(charDigit, 10);
+          fmtParts[i] = fmt.substring(from, to).toCharArray();
+          argIndices[i] = digit;
+          from = to + 2;
+          continue;
         }
       }
       throw new IllegalArgumentException("Expected arg $" + i);
@@ -151,4 +153,88 @@
   protected final Formatter getToStringFormatter() {
     return FMT_TOSTRING;
   }
+
+  protected TreeLogger branch(TreeLogger logger, Throwable caught) {
+    return branch(logger, toArray(), new Formatter[0], caught);
+  }
+
+  protected TreeLogger branch(TreeLogger logger, Object arg, Formatter fmt, Throwable caught) {
+    return branch(logger, toArray(arg), toArray(fmt), caught);
+  }
+
+  protected TreeLogger branch(TreeLogger logger, Object arg1, Object arg2, Formatter fmt1,
+      Formatter fmt2, Throwable caught) {
+    return branch(logger, toArray(arg1, arg2), toArray(fmt1, fmt2), caught);
+  }
+
+  protected TreeLogger branch(TreeLogger logger, Object arg1, Object arg2, Object arg3,
+      Formatter fmt1, Formatter fmt2, Formatter fmt3, Throwable caught) {
+    return branch(logger, toArray(arg1, arg2, arg3), toArray(fmt1, fmt2, fmt3), caught);
+  }
+
+  protected TreeLogger branch(TreeLogger logger, Object arg1, Object arg2, Object arg3, Object arg4,
+      Formatter fmt1, Formatter fmt2, Formatter fmt3, Formatter fmt4, Throwable caught) {
+    return branch(logger, toArray(arg1, arg2, arg3, arg4), toArray(fmt1, fmt2, fmt3, fmt4), caught);
+  }
+
+  protected TreeLogger branch(TreeLogger logger, Object[] args, Object[] fmts,
+      Throwable caught) {
+    return logger.branch(type, compose(args, fmts), caught);
+  }
+
+  protected String compose(Object[] args, Object[] fmts) {
+    // Format the objects.
+
+    assert args.length == fmts.length;
+    String[] formattedArgs = new String[args.length];
+    for (int i = 0; i < argIndices.length; i++) {
+      int referredIndex = argIndices[i];
+      Object referredArg = args[referredIndex];
+      Formatter formatter = (Formatter) fmts[referredIndex];
+      formattedArgs[i] = (referredArg != null ? formatter.format(referredArg) : "null");
+    }
+
+    StringBuilder stringBuilder = new StringBuilder();
+    for (int i = 0; i < formattedArgs.length; i++) {
+      stringBuilder.append(fmtParts[i]);
+      stringBuilder.append(formattedArgs[i]);
+    }
+    // final literal
+    stringBuilder.append(fmtParts[fmtParts.length - 1]);
+
+    return stringBuilder.toString();
+  }
+
+  protected void log(TreeLogger logger, Throwable caught) {
+    log(logger, toArray(), toArray(), caught);
+  }
+
+  protected void log(TreeLogger logger, Object arg, Formatter fmt, Throwable caught) {
+    log(logger, toArray(arg), toArray(fmt), caught);
+  }
+
+  protected void log(TreeLogger logger, Object arg1, Object arg2, Formatter fmt1, Formatter fmt2,
+      Throwable caught) {
+    log(logger, toArray(arg1, arg2), toArray(fmt1, fmt2), caught);
+  }
+
+  protected void log(TreeLogger logger, Object arg1, Object arg2, Object arg3, Formatter fmt1,
+      Formatter fmt2, Formatter fmt3, Throwable caught) {
+    log(logger, toArray(arg1, arg2, arg3), toArray(fmt1, fmt2, fmt3), caught);
+  }
+
+  protected void log(TreeLogger logger, Object arg1, Object arg2, Object arg3, Object arg4,
+      Formatter fmt1, Formatter fmt2, Formatter fmt3, Formatter fmt4, Throwable caught) {
+    log(logger, toArray(arg1, arg2, arg3, arg4), toArray(fmt1, fmt2, fmt3, fmt4), caught);
+  }
+
+  protected void log(TreeLogger logger, Object[] args, Object[] fmts, Throwable caught) {
+    if (logger.isLoggable(type)) {
+      logger.log(type, compose(args, fmts), caught);
+    }
+  }
+
+  private Object[] toArray(Object... pars) {
+    return pars;
+  }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message0.java b/dev/core/src/com/google/gwt/dev/util/msg/Message0.java
index a703153..5a9c6f3 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message0.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message0.java
@@ -28,15 +28,10 @@
   }
 
   public TreeLogger branch(TreeLogger logger, Throwable caught) {
-    // Always branch, even if the branch root is not loggable.
-    // See TreeLogger.branch() for details as to why.
-    //
-    return logger.branch(type, new String(fmtParts[0]), caught);
+    return super.branch(logger, caught);
   }
 
   public void log(TreeLogger logger, Throwable caught) {
-    if (logger.isLoggable(type)) {
-      logger.log(type, new String(fmtParts[0]), caught);
-    }
+    super.log(logger, caught);
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message1.java b/dev/core/src/com/google/gwt/dev/util/msg/Message1.java
deleted file mode 100644
index a6c5993..0000000
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message1.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2006 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.dev.util.msg;
-
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.TreeLogger.Type;
-
-/**
- * 1-arg message.
- */
-public abstract class Message1 extends Message {
-
-  public Message1(Type type, String fmt) {
-    super(type, fmt, 1);
-  }
-
-  protected TreeLogger branch1(TreeLogger logger, Object arg1, Formatter fmt1,
-      Throwable caught) {
-    return logger.branch(type, compose1(arg1, fmt1), caught);
-  }
-
-  protected String compose1(Object arg1, Formatter fmt1) {
-    // Format the objects.
-    //
-    String stringArg1 = (arg1 != null ? fmt1.format(arg1) : "null");
-
-    // To maintain consistency with the other impls, we use an insert var.
-    //
-    String insert1 = stringArg1;
-
-    // Cache the length of the inserts.
-    //
-    int lenInsert1 = insert1.length();
-
-    // Cache the length of each part.
-    //
-    int lenPart0 = fmtParts[0].length;
-    int lenPart1 = fmtParts[1].length;
-
-    // Prep for copying.
-    //
-    int dest = 0;
-    char[] chars = new char[minChars + lenInsert1];
-
-    // literal + insert, part 0
-    System.arraycopy(fmtParts[0], 0, chars, dest, lenPart0);
-    dest += lenPart0;
-
-    insert1.getChars(0, lenInsert1, chars, dest);
-    dest += lenInsert1;
-
-    // final literal
-    System.arraycopy(fmtParts[1], 0, chars, dest, lenPart1);
-
-    return new String(chars);
-  }
-
-  protected void log1(TreeLogger logger, Object arg1, Formatter fmt1,
-      Throwable caught) {
-    if (logger.isLoggable(type)) {
-      logger.log(type, compose1(arg1, fmt1), caught);
-    }
-  }
-}
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message1File.java b/dev/core/src/com/google/gwt/dev/util/msg/Message1File.java
index bd07195..9f3c66f 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message1File.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message1File.java
@@ -23,17 +23,17 @@
 /**
  * File message.
  */
-public final class Message1File extends Message1 {
+public final class Message1File extends Message {
 
   public Message1File(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 1);
   }
 
   public TreeLogger branch(TreeLogger logger, File f, Throwable caught) {
-    return branch1(logger, f, getFormatter(f), caught);
+    return branch(logger, f, getFormatter(f), caught);
   }
 
   public void log(TreeLogger logger, File f, Throwable caught) {
-    log1(logger, f, getFormatter(f), caught);
+    log(logger, f, getFormatter(f), caught);
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message1Long.java b/dev/core/src/com/google/gwt/dev/util/msg/Message1Long.java
index efbf1d9..ce29597 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message1Long.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message1Long.java
@@ -21,20 +21,20 @@
 /**
  * Long message.
  */
-public final class Message1Long extends Message1 {
+public final class Message1Long extends Message {
 
   public Message1Long(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 1);
   }
 
   public TreeLogger branch(TreeLogger logger, long x, Throwable caught) {
     Long xl = Long.valueOf(x);
-    return branch1(logger, xl, getFormatter(xl), caught);
+    return branch(logger, xl, getFormatter(xl), caught);
   }
 
   public void log(TreeLogger logger, long x, Throwable caught) {
     Long xl = Long.valueOf(x);
-    log1(logger, xl, getFormatter(xl), caught);
+    log(logger, xl, getFormatter(xl), caught);
   }
 
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message1String.java b/dev/core/src/com/google/gwt/dev/util/msg/Message1String.java
index b2b9a01..afc793f 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message1String.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message1String.java
@@ -21,17 +21,17 @@
 /**
  * String message.
  */
-public final class Message1String extends Message1 {
+public final class Message1String extends Message {
 
   public Message1String(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 1);
   }
 
   public TreeLogger branch(TreeLogger logger, String s, Throwable caught) {
-    return branch1(logger, s, getFormatter(s), caught);
+    return branch(logger, s, getFormatter(s), caught);
   }
 
   public void log(TreeLogger logger, String s, Throwable caught) {
-    log1(logger, s, getFormatter(s), caught);
+    log(logger, s, getFormatter(s), caught);
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message1StringArray.java b/dev/core/src/com/google/gwt/dev/util/msg/Message1StringArray.java
index a0398cf..2d6dbaa 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message1StringArray.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message1StringArray.java
@@ -21,17 +21,17 @@
 /**
  * String array message.
  */
-public final class Message1StringArray extends Message1 {
+public final class Message1StringArray extends Message {
 
   public Message1StringArray(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 1);
   }
 
   public TreeLogger branch(TreeLogger logger, String[] sa, Throwable caught) {
-    return branch1(logger, sa, getFormatter(sa), caught);
+    return branch(logger, sa, getFormatter(sa), caught);
   }
 
   public void log(TreeLogger logger, String[] sa, Throwable caught) {
-    log1(logger, sa, getFormatter(sa), caught);
+    log(logger, sa, getFormatter(sa), caught);
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message1ToString.java b/dev/core/src/com/google/gwt/dev/util/msg/Message1ToString.java
index 8fe5204..ff0bf71 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message1ToString.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message1ToString.java
@@ -21,17 +21,17 @@
 /**
  * String message.
  */
-public final class Message1ToString extends Message1 {
+public final class Message1ToString extends Message {
 
   public Message1ToString(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 1);
   }
 
   public TreeLogger branch(TreeLogger logger, Object o, Throwable caught) {
-    return branch1(logger, o, getToStringFormatter(), caught);
+    return branch(logger, o, getToStringFormatter(), caught);
   }
 
   public void log(TreeLogger logger, Object o, Throwable caught) {
-    log1(logger, o, getToStringFormatter(), caught);
+    log(logger, o, getToStringFormatter(), caught);
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message1URL.java b/dev/core/src/com/google/gwt/dev/util/msg/Message1URL.java
index e573d01..d705371 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message1URL.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message1URL.java
@@ -23,17 +23,17 @@
 /**
  * URL message.
  */
-public final class Message1URL extends Message1 {
+public final class Message1URL extends Message {
 
   public Message1URL(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 1);
   }
 
   public TreeLogger branch(TreeLogger logger, URL u, Throwable caught) {
-    return branch1(logger, u, getFormatter(u), caught);
+    return branch(logger, u, getFormatter(u), caught);
   }
 
   public void log(TreeLogger logger, URL u, Throwable caught) {
-    log1(logger, u, getFormatter(u), caught);
+    log(logger, u, getFormatter(u), caught);
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message2.java b/dev/core/src/com/google/gwt/dev/util/msg/Message2.java
deleted file mode 100644
index cefd97b..0000000
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message2.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2006 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.dev.util.msg;
-
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.TreeLogger.Type;
-
-/**
- * 2-arg message.
- */
-public abstract class Message2 extends Message {
-
-  public Message2(Type type, String fmt) {
-    super(type, fmt, 2);
-  }
-
-  protected TreeLogger branch2(TreeLogger logger, Object arg1, Object arg2,
-      Formatter fmt1, Formatter fmt2, Throwable caught) {
-    return logger.branch(type, compose2(arg1, arg2, fmt1, fmt2), caught);
-  }
-
-  protected String compose2(Object arg1, Object arg2, Formatter fmt1,
-      Formatter fmt2) {
-
-    // Format the objects.
-    //
-    String stringArg1 = (arg1 != null ? fmt1.format(arg1) : "null");
-    String stringArg2 = (arg2 != null ? fmt2.format(arg2) : "null");
-
-    // Decide how to order the inserts.
-    // Tests are biased toward $1..$2 order.
-    //
-    String insert1 = (argIndices[0] == 0) ? stringArg1 : stringArg2;
-    String insert2 = (argIndices[1] == 1) ? stringArg2 : stringArg1;
-
-    // Cache the length of the inserts.
-    //
-    int lenInsert1 = insert1.length();
-    int lenInsert2 = insert2.length();
-
-    // Cache the length of each part.
-    //
-    int lenPart0 = fmtParts[0].length;
-    int lenPart1 = fmtParts[1].length;
-    int lenPart2 = fmtParts[2].length;
-
-    // Prep for copying.
-    //
-    int dest = 0;
-    char[] chars = new char[minChars + lenInsert1 + lenInsert2];
-
-    // literal + insert, part 0
-    System.arraycopy(fmtParts[0], 0, chars, dest, lenPart0);
-    dest += lenPart0;
-
-    insert1.getChars(0, lenInsert1, chars, dest);
-    dest += lenInsert1;
-
-    // literal + insert, part 1
-    System.arraycopy(fmtParts[1], 0, chars, dest, lenPart1);
-    dest += lenPart1;
-
-    insert2.getChars(0, lenInsert2, chars, dest);
-    dest += lenInsert2;
-
-    // final literal
-    System.arraycopy(fmtParts[2], 0, chars, dest, lenPart2);
-
-    return new String(chars);
-  }
-
-  protected void log2(TreeLogger logger, Object arg1, Object arg2,
-      Formatter fmt1, Formatter fmt2, Throwable caught) {
-    if (logger.isLoggable(type)) {
-      logger.log(type, compose2(arg1, arg2, fmt1, fmt2), caught);
-    }
-  }
-}
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message2ClassClass.java b/dev/core/src/com/google/gwt/dev/util/msg/Message2ClassClass.java
index 8bef641..0dfb987 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message2ClassClass.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message2ClassClass.java
@@ -21,18 +21,18 @@
 /**
  * Class & Class message.
  */
-public final class Message2ClassClass extends Message2 {
+public final class Message2ClassClass extends Message {
 
   public Message2ClassClass(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 2);
   }
 
   public TreeLogger branch(TreeLogger logger, Class<?> c1, Class<?> c2,
       Throwable caught) {
-    return branch2(logger, c1, c2, getFormatter(c1), getFormatter(c2), caught);
+    return branch(logger, c1, c2, getFormatter(c1), getFormatter(c2), caught);
   }
 
   public void log(TreeLogger logger, Class<?> c1, Class<?> c2, Throwable caught) {
-    log2(logger, c1, c2, getFormatter(c1), getFormatter(c2), caught);
+    log(logger, c1, c2, getFormatter(c1), getFormatter(c2), caught);
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message2FileString.java b/dev/core/src/com/google/gwt/dev/util/msg/Message2FileString.java
index 48d4a2f..c6f3805 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message2FileString.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message2FileString.java
@@ -23,17 +23,17 @@
 /**
  * File & String message.
  */
-public final class Message2FileString extends Message2 {
+public final class Message2FileString extends Message {
 
   public Message2FileString(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 2);
   }
 
   public TreeLogger branch(TreeLogger logger, File f, String s, Throwable caught) {
-    return branch2(logger, f, s, getFormatter(f), getFormatter(s), caught);
+    return branch(logger, f, s, getFormatter(f), getFormatter(s), caught);
   }
 
   public void log(TreeLogger logger, File f, String s, Throwable caught) {
-    log2(logger, f, s, getFormatter(f), getFormatter(s), caught);
+    log(logger, f, s, getFormatter(f), getFormatter(s), caught);
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message2IntString.java b/dev/core/src/com/google/gwt/dev/util/msg/Message2IntString.java
index 3f11c48..75e404c 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message2IntString.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message2IntString.java
@@ -21,20 +21,20 @@
 /**
  * Integer & String message.
  */
-public final class Message2IntString extends Message2 {
+public final class Message2IntString extends Message {
 
   public Message2IntString(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 2);
   }
 
   public TreeLogger branch(TreeLogger logger, int x, String s, Throwable caught) {
     Integer xi = Integer.valueOf(x);
-    return branch2(logger, xi, s, getFormatter(xi), getFormatter(s), caught);
+    return branch(logger, xi, s, getFormatter(xi), getFormatter(s), caught);
   }
 
   public void log(TreeLogger logger, int x, String s, Throwable caught) {
     Integer xi = Integer.valueOf(x);
-    log2(logger, xi, s, getFormatter(xi), getFormatter(s), caught);
+    log(logger, xi, s, getFormatter(xi), getFormatter(s), caught);
   }
 
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message2LongString.java b/dev/core/src/com/google/gwt/dev/util/msg/Message2LongString.java
index 737ebe2..4a745c6 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message2LongString.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message2LongString.java
@@ -21,19 +21,19 @@
 /**
  * Long & String message.
  */
-public final class Message2LongString extends Message2 {
+public final class Message2LongString extends Message {
 
   public Message2LongString(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 2);
   }
 
   public TreeLogger branch(TreeLogger logger, long x, String s, Throwable caught) {
     Long xi = Long.valueOf(x);
-    return branch2(logger, xi, s, getFormatter(xi), getFormatter(s), caught);
+    return branch(logger, xi, s, getFormatter(xi), getFormatter(s), caught);
   }
 
   public void log(TreeLogger logger, long x, String s, Throwable caught) {
     Long xi = Long.valueOf(x);
-    log2(logger, xi, s, getFormatter(xi), getFormatter(s), caught);
+    log(logger, xi, s, getFormatter(xi), getFormatter(s), caught);
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message2StringFile.java b/dev/core/src/com/google/gwt/dev/util/msg/Message2StringFile.java
index a8ed555..409100d 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message2StringFile.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message2StringFile.java
@@ -23,18 +23,18 @@
 /**
  * String & File message.
  */
-public final class Message2StringFile extends Message2 {
+public final class Message2StringFile extends Message {
 
   public Message2StringFile(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 2);
   }
 
   public TreeLogger branch(TreeLogger logger, String s, File f, Throwable caught) {
-    return branch2(logger, s, f, getFormatter(s), getFormatter(f), caught);
+    return branch(logger, s, f, getFormatter(s), getFormatter(f), caught);
   }
 
   public void log(TreeLogger logger, String s, File f, Throwable caught) {
-    log2(logger, s, f, getFormatter(s), getFormatter(f), caught);
+    log(logger, s, f, getFormatter(s), getFormatter(f), caught);
   }
 
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message2StringInt.java b/dev/core/src/com/google/gwt/dev/util/msg/Message2StringInt.java
index 4c26be5..812d3de 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message2StringInt.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message2StringInt.java
@@ -21,20 +21,20 @@
 /**
  * String & Integer message.
  */
-public final class Message2StringInt extends Message2 {
+public final class Message2StringInt extends Message {
 
   public Message2StringInt(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 2);
   }
 
   public TreeLogger branch(TreeLogger logger, String s, int x, Throwable caught) {
     Integer xi = Integer.valueOf(x);
-    return branch2(logger, s, xi, getFormatter(s), getFormatter(xi), caught);
+    return branch(logger, s, xi, getFormatter(s), getFormatter(xi), caught);
   }
 
   public void log(TreeLogger logger, String s, int x, Throwable caught) {
     Integer xi = Integer.valueOf(x);
-    log2(logger, s, xi, getFormatter(s), getFormatter(xi), caught);
+    log(logger, s, xi, getFormatter(s), getFormatter(xi), caught);
   }
 
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message2StringString.java b/dev/core/src/com/google/gwt/dev/util/msg/Message2StringString.java
index 416b918..4e7b0df 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message2StringString.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message2StringString.java
@@ -21,18 +21,18 @@
 /**
  * String & String message.
  */
-public final class Message2StringString extends Message2 {
+public final class Message2StringString extends Message {
 
   public Message2StringString(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 2);
   }
 
   public TreeLogger branch(TreeLogger logger, String s1, String s2,
       Throwable caught) {
-    return branch2(logger, s1, s2, getFormatter(s1), getFormatter(s2), caught);
+    return branch(logger, s1, s2, getFormatter(s1), getFormatter(s2), caught);
   }
 
   public void log(TreeLogger logger, String s1, String s2, Throwable caught) {
-    log2(logger, s1, s2, getFormatter(s1), getFormatter(s2), caught);
+    log(logger, s1, s2, getFormatter(s1), getFormatter(s2), caught);
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message2StringStringArray.java b/dev/core/src/com/google/gwt/dev/util/msg/Message2StringStringArray.java
index 36c7d72..5b21128 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message2StringStringArray.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message2StringStringArray.java
@@ -21,17 +21,18 @@
 /**
  * String & String array message.
  */
-public final class Message2StringStringArray extends Message2 {
+public final class Message2StringStringArray extends Message {
+
   public Message2StringStringArray(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 2);
   }
 
   public TreeLogger branch(TreeLogger logger, String s, String[] sa,
       Throwable caught) {
-    return branch2(logger, s, sa, getFormatter(s), getFormatter(sa), caught);
+    return branch(logger, s, sa, getFormatter(s), getFormatter(sa), caught);
   }
 
   public void log(TreeLogger logger, String s, String[] sa, Throwable caught) {
-    log2(logger, s, sa, getFormatter(s), getFormatter(sa), caught);
+    log(logger, s, sa, getFormatter(s), getFormatter(sa), caught);
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message2StringURL.java b/dev/core/src/com/google/gwt/dev/util/msg/Message2StringURL.java
index 89ad0ed..ef20b0f 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message2StringURL.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message2StringURL.java
@@ -23,18 +23,18 @@
 /**
  * String & URL message.
  */
-public final class Message2StringURL extends Message2 {
+public final class Message2StringURL extends Message {
 
   public Message2StringURL(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 2);
   }
 
   public TreeLogger branch(TreeLogger logger, String s, URL u, Throwable caught) {
-    return branch2(logger, s, u, getFormatter(s), getFormatter(u), caught);
+    return branch(logger, s, u, getFormatter(s), getFormatter(u), caught);
   }
 
   public void log(TreeLogger logger, String s, URL u, Throwable caught) {
-    log2(logger, s, u, getFormatter(s), getFormatter(u), caught);
+    log(logger, s, u, getFormatter(s), getFormatter(u), caught);
   }
 
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message2URLInt.java b/dev/core/src/com/google/gwt/dev/util/msg/Message2URLInt.java
index 5038479..3ec7b1f 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message2URLInt.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message2URLInt.java
@@ -23,19 +23,19 @@
 /**
  * URL & Integer message.
  */
-public final class Message2URLInt extends Message2 {
+public final class Message2URLInt extends Message {
 
   public Message2URLInt(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 2);
   }
 
   public TreeLogger branch(TreeLogger logger, URL u, int x, Throwable caught) {
     Integer xi = Integer.valueOf(x);
-    return branch2(logger, u, xi, getFormatter(u), getFormatter(xi), caught);
+    return branch(logger, u, xi, getFormatter(u), getFormatter(xi), caught);
   }
 
   public void log(TreeLogger logger, URL u, int x, Throwable caught) {
     Integer xi = Integer.valueOf(x);
-    log2(logger, u, xi, getFormatter(u), getFormatter(xi), caught);
+    log(logger, u, xi, getFormatter(u), getFormatter(xi), caught);
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message2URLString.java b/dev/core/src/com/google/gwt/dev/util/msg/Message2URLString.java
index f03624b..13f27eb 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message2URLString.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message2URLString.java
@@ -23,17 +23,17 @@
 /**
  * URL & String message.
  */
-public final class Message2URLString extends Message2 {
+public final class Message2URLString extends Message {
 
   public Message2URLString(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 2);
   }
 
   public TreeLogger branch(TreeLogger logger, URL u, String s, Throwable caught) {
-    return branch2(logger, u, s, getFormatter(u), getFormatter(s), caught);
+    return branch(logger, u, s, getFormatter(u), getFormatter(s), caught);
   }
 
   public void log(TreeLogger logger, URL u, String s, Throwable caught) {
-    log2(logger, u, s, getFormatter(u), getFormatter(s), caught);
+    log(logger, u, s, getFormatter(u), getFormatter(s), caught);
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message2URLURL.java b/dev/core/src/com/google/gwt/dev/util/msg/Message2URLURL.java
index 238eaaf..e6caf0b 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message2URLURL.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message2URLURL.java
@@ -23,17 +23,17 @@
 /**
  * URL & URL message.
  */
-public final class Message2URLURL extends Message2 {
+public final class Message2URLURL extends Message {
 
   public Message2URLURL(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 2);
   }
 
   public TreeLogger branch(TreeLogger logger, URL u1, URL u2, Throwable caught) {
-    return branch2(logger, u1, u2, getFormatter(u1), getFormatter(u2), caught);
+    return branch(logger, u1, u2, getFormatter(u1), getFormatter(u2), caught);
   }
 
   public void log(TreeLogger logger, URL u1, URL u2, Throwable caught) {
-    log2(logger, u1, u2, getFormatter(u1), getFormatter(u2), caught);
+    log(logger, u1, u2, getFormatter(u1), getFormatter(u2), caught);
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message3.java b/dev/core/src/com/google/gwt/dev/util/msg/Message3.java
deleted file mode 100644
index 13db67e..0000000
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message3.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2006 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.dev.util.msg;
-
-import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.TreeLogger.Type;
-
-/**
- * 3-arg message.
- */
-public abstract class Message3 extends Message {
-
-  protected Message3(Type type, String fmt) {
-    super(type, fmt, 3);
-  }
-
-  protected TreeLogger branch3(TreeLogger logger, Object arg1, Object arg2,
-      Object arg3, Formatter fmt1, Formatter fmt2, Formatter fmt3,
-      Throwable caught) {
-    return logger.branch(type, compose3(arg1, arg2, arg3, fmt1, fmt2, fmt3),
-        caught);
-  }
-
-  protected String compose3(Object arg1, Object arg2, Object arg3,
-      Formatter fmt1, Formatter fmt2, Formatter fmt3) {
-
-    // Format the objects.
-    //
-    String stringArg1 = (arg1 != null ? fmt1.format(arg1) : "null");
-    String stringArg2 = (arg2 != null ? fmt2.format(arg2) : "null");
-    String stringArg3 = (arg3 != null ? fmt3.format(arg3) : "null");
-
-    // Decide how to order the inserts.
-    // Tests are biased toward $1..$2 order.
-    //
-    String insert1 = (argIndices[0] == 0) ? stringArg1 : ((argIndices[0] == 1)
-        ? stringArg2 : stringArg3);
-    String insert2 = (argIndices[1] == 1) ? stringArg2 : ((argIndices[1] == 0)
-        ? stringArg1 : stringArg3);
-    String insert3 = (argIndices[2] == 2) ? stringArg3 : ((argIndices[2] == 0)
-        ? stringArg1 : stringArg2);
-
-    // Cache the length of the inserts.
-    //
-    int lenInsert1 = insert1.length();
-    int lenInsert2 = insert2.length();
-    int lenInsert3 = insert3.length();
-
-    // Cache the length of each part.
-    //
-    int lenPart0 = fmtParts[0].length;
-    int lenPart1 = fmtParts[1].length;
-    int lenPart2 = fmtParts[2].length;
-    int lenPart3 = fmtParts[3].length;
-
-    // Prep for copying.
-    //
-    int dest = 0;
-    char[] chars = new char[minChars + lenInsert1 + lenInsert2 + lenInsert3];
-
-    // literal + insert, part 0
-    System.arraycopy(fmtParts[0], 0, chars, dest, lenPart0);
-    dest += lenPart0;
-
-    insert1.getChars(0, lenInsert1, chars, dest);
-    dest += lenInsert1;
-
-    // literal + insert, part 1
-    System.arraycopy(fmtParts[1], 0, chars, dest, lenPart1);
-    dest += lenPart1;
-
-    insert2.getChars(0, lenInsert2, chars, dest);
-    dest += lenInsert2;
-
-    // literal + insert, part 2
-    System.arraycopy(fmtParts[2], 0, chars, dest, lenPart2);
-    dest += lenPart2;
-
-    insert3.getChars(0, lenInsert3, chars, dest);
-    dest += lenInsert3;
-
-    // final literal
-    System.arraycopy(fmtParts[3], 0, chars, dest, lenPart3);
-
-    return new String(chars);
-  }
-
-  protected void log3(TreeLogger logger, Object arg1, Object arg2, Object arg3,
-      Formatter fmt1, Formatter fmt2, Formatter fmt3, Throwable caught) {
-    if (logger.isLoggable(type)) {
-      logger.log(type, compose3(arg1, arg2, arg3, fmt1, fmt2, fmt3), caught);
-    }
-  }
-}
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message3IntMethodString.java b/dev/core/src/com/google/gwt/dev/util/msg/Message3IntMethodString.java
index 83e0a9e..543803f 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message3IntMethodString.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message3IntMethodString.java
@@ -23,22 +23,22 @@
 /**
  * Integer, Method, & String message.
  */
-public final class Message3IntMethodString extends Message3 {
+public final class Message3IntMethodString extends Message {
 
   public Message3IntMethodString(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 3);
   }
 
   public TreeLogger branch(TreeLogger logger, int x, Method m, String s,
       Throwable caught) {
     Integer xi = Integer.valueOf(x);
-    return branch3(logger, xi, m, s, getFormatter(xi), getFormatter(m),
+    return branch(logger, xi, m, s, getFormatter(xi), getFormatter(m),
         getFormatter(s), caught);
   }
 
   public void log(TreeLogger logger, int x, Method m, String s, Throwable caught) {
     Integer xi = Integer.valueOf(x);
-    log3(logger, xi, m, s, getFormatter(xi), getFormatter(m), getFormatter(s),
+    log(logger, xi, m, s, getFormatter(xi), getFormatter(m), getFormatter(s),
         caught);
   }
 
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message3IntStringClass.java b/dev/core/src/com/google/gwt/dev/util/msg/Message3IntStringClass.java
index d3e097c..a3560a9 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message3IntStringClass.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message3IntStringClass.java
@@ -21,22 +21,22 @@
 /**
  * Integer, String & Class message.
  */
-public final class Message3IntStringClass extends Message3 {
+public final class Message3IntStringClass extends Message {
 
   public Message3IntStringClass(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 3);
   }
 
   public TreeLogger branch(TreeLogger logger, int x, String s, Class<?> c,
       Throwable caught) {
     Integer xi = Integer.valueOf(x);
-    return branch3(logger, xi, s, c, getFormatter(xi), getFormatter(s),
+    return branch(logger, xi, s, c, getFormatter(xi), getFormatter(s),
         getFormatter(c), caught);
   }
 
   public void log(TreeLogger logger, int x, String s, Class<?> c, Throwable caught) {
     Integer xi = Integer.valueOf(x);
-    log3(logger, xi, s, c, getFormatter(xi), getFormatter(s), getFormatter(c),
+    log(logger, xi, s, c, getFormatter(xi), getFormatter(s), getFormatter(c),
         caught);
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message3IntStringString.java b/dev/core/src/com/google/gwt/dev/util/msg/Message3IntStringString.java
index c98aae8..b097c56 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message3IntStringString.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message3IntStringString.java
@@ -21,23 +21,23 @@
 /**
  * Integer, String, & String message.
  */
-public final class Message3IntStringString extends Message3 {
+public final class Message3IntStringString extends Message {
 
   public Message3IntStringString(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 3);
   }
 
   public TreeLogger branch(TreeLogger logger, int x, String s1, String s2,
       Throwable caught) {
     Integer xi = Integer.valueOf(x);
-    return branch3(logger, xi, s1, s2, getFormatter(xi), getFormatter(s1),
+    return branch(logger, xi, s1, s2, getFormatter(xi), getFormatter(s1),
         getFormatter(s2), caught);
   }
 
   public void log(TreeLogger logger, int x, String s1, String s2,
       Throwable caught) {
     Integer xi = Integer.valueOf(x);
-    log3(logger, xi, s1, s2, getFormatter(xi), getFormatter(s1),
+    log(logger, xi, s1, s2, getFormatter(xi), getFormatter(s1),
         getFormatter(s2), caught);
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message3StringIntString.java b/dev/core/src/com/google/gwt/dev/util/msg/Message3StringIntString.java
index a441b6c..b7fcbf0 100644
--- a/dev/core/src/com/google/gwt/dev/util/msg/Message3StringIntString.java
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message3StringIntString.java
@@ -21,23 +21,23 @@
 /**
  * String, Integer, & String message.
  */
-public final class Message3StringIntString extends Message3 {
+public final class Message3StringIntString extends Message {
 
   public Message3StringIntString(Type type, String fmt) {
-    super(type, fmt);
+    super(type, fmt, 3);
   }
 
   public TreeLogger branch(TreeLogger logger, String s1, int x, String s2,
       Throwable caught) {
     Integer xi = Integer.valueOf(x);
-    return branch3(logger, s1, xi, s2, getFormatter(s1), getFormatter(xi),
+    return branch(logger, s1, xi, s2, getFormatter(s1), getFormatter(xi),
         getFormatter(s2), caught);
   }
 
   public void log(TreeLogger logger, String s1, int x, String s2,
       Throwable caught) {
     Integer xi = Integer.valueOf(x);
-    log3(logger, s1, xi, s2, getFormatter(s1), getFormatter(xi),
+    log(logger, s1, xi, s2, getFormatter(s1), getFormatter(xi),
         getFormatter(s2), caught);
   }
 
diff --git a/dev/core/src/com/google/gwt/dev/util/msg/Message4IntStringStringString.java b/dev/core/src/com/google/gwt/dev/util/msg/Message4IntStringStringString.java
new file mode 100644
index 0000000..8cccf81
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/msg/Message4IntStringStringString.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.util.msg;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.TreeLogger.Type;
+
+/**
+ * Integer, String, String & String message.
+ */
+public final class Message4IntStringStringString extends Message {
+
+  public Message4IntStringStringString(Type type, String fmt) {
+    super(type, fmt, 4);
+  }
+
+  public TreeLogger branch(TreeLogger logger, int x, String s1, String s2, String s3,
+      Throwable caught) {
+    Integer xi = Integer.valueOf(x);
+    return branch(logger, xi, s1, s2, s3, getFormatter(xi), getFormatter(s1), getFormatter(s2),
+        getFormatter(s3), caught);
+  }
+
+  public void log(TreeLogger logger, int x, String s1, String s2, String s3, Throwable caught) {
+    Integer xi = Integer.valueOf(x);
+    log(logger, xi, s1, s2, s3, getFormatter(xi), getFormatter(s1), getFormatter(s2),
+        getFormatter(s3), caught);
+  }
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/xml/Messages.java b/dev/core/src/com/google/gwt/dev/util/xml/Messages.java
index 5805f94..03c0585 100644
--- a/dev/core/src/com/google/gwt/dev/util/xml/Messages.java
+++ b/dev/core/src/com/google/gwt/dev/util/xml/Messages.java
@@ -26,16 +26,16 @@
  * Static XML messages.
  */
 class Messages {
-  public static final Message3IntStringClass XML_ATTRIBUTE_CONVERSION_ERROR = new Message3IntStringClass(
-      TreeLogger.ERROR,
+  public static final Message3IntStringClass XML_ATTRIBUTE_CONVERSION_ERROR =
+      new Message3IntStringClass(TreeLogger.ERROR,
       "Line $0: Unable to convert attribute '$1' to type '$2'");
 
-  public static final Message3StringIntString XML_ATTRIBUTE_UNEXPECTED = new Message3StringIntString(
-      TreeLogger.ERROR,
-      "Element '$0' beginning on line $1 contains unexpected attribute '$2'");
+  public static final Message3StringIntString XML_ATTRIBUTE_UNEXPECTED =
+      new Message3StringIntString(TreeLogger.ERROR,
+      "Line $1: Unexpected attribute '$2' in element '$0'");
 
-  public static final Message2StringInt XML_CHILDREN_NOT_ALLOWED = new Message2StringInt(
-      TreeLogger.ERROR, "Child element $0 on line $1 is not allowed");
+  public static final Message2StringInt XML_CHILDREN_NOT_ALLOWED =
+      new Message2StringInt(TreeLogger.ERROR, "Line $1: Child element '$0' is not allowed");
 
   public static final Message2IntString XML_ELEMENT_HANDLER_EXCEPTION = new Message2IntString(
       TreeLogger.ERROR,
@@ -49,7 +49,7 @@
 
   public static final Message3StringIntString XML_REQUIRED_ATTRIBUTE_MISSING = new Message3StringIntString(
       TreeLogger.ERROR,
-      "Element '$0' beginning on line $1 is missing required attribute '$2'");
+      "Line $1: Missing required attribute '$2' in element '$0'");
 
   private Messages() {
   }
diff --git a/dev/core/test/com/google/gwt/dev/cfg/ModuleDefLoaderTest.java b/dev/core/test/com/google/gwt/dev/cfg/ModuleDefLoaderTest.java
index 60637df..7936c3c 100644
--- a/dev/core/test/com/google/gwt/dev/cfg/ModuleDefLoaderTest.java
+++ b/dev/core/test/com/google/gwt/dev/cfg/ModuleDefLoaderTest.java
@@ -74,6 +74,24 @@
             + "attribute specifications, \">\" or \"/>\".");
   }
 
+  public void testErrorReporting_badLinker() throws UnableToCompleteException, IOException,
+      IncompatibleLibraryVersionException {
+    assertErrorsWhenLoading("com.google.gwt.dev.cfg.testdata.errors.BadLinker",
+        "Line 2: Invalid linker name 'X'");
+  }
+
+  public void testErrorReporting_badProperty() throws UnableToCompleteException, IOException,
+      IncompatibleLibraryVersionException {
+    assertErrorsWhenLoading("com.google.gwt.dev.cfg.testdata.errors.BadProperty",
+        "Line 2: Property 'X' not found");
+  }
+
+  public void testErrorReporting_badPropertyValue() throws UnableToCompleteException, IOException,
+      IncompatibleLibraryVersionException {
+    assertErrorsWhenLoading("com.google.gwt.dev.cfg.testdata.errors.BadPropertyValue",
+        "Line 3: Value 'z' in not a valid value for property 'X'");
+  }
+
   public void testErrorReporting_deepError() throws UnableToCompleteException, IOException,
       IncompatibleLibraryVersionException {
     UnitTestTreeLogger.Builder builder = new UnitTestTreeLogger.Builder();
@@ -109,16 +127,22 @@
             + "for source?");
   }
 
+  public void testErrorReporting_invalidName() throws UnableToCompleteException, IOException,
+      IncompatibleLibraryVersionException {
+    assertErrorsWhenLoading("com.google.gwt.dev.cfg.testdata.errors.InvalidName",
+        "Line 2: Invalid property name '123:33'");
+  }
+
   public void testErrorReporting_multipleErrors() throws UnableToCompleteException, IOException,
       IncompatibleLibraryVersionException {
     assertErrorsWhenLoading("com.google.gwt.dev.cfg.testdata.errors.MultipleErrors",
-        "Element 'module' beginning on line 1 contains unexpected attribute 'blah'");
+        "Line 1: Unexpected attribute 'blah' in element 'module'");
   }
 
   public void testErrorReporting_unexpectedAttribute() throws UnableToCompleteException,
       IOException, IncompatibleLibraryVersionException {
     assertErrorsWhenLoading("com.google.gwt.dev.cfg.testdata.errors.UnexpectedAttribute",
-        "Element 'inherits' beginning on line 2 contains unexpected attribute 'blah'");
+        "Line 2: Unexpected attribute 'blah' in element 'inherits'");
   }
 
   public void testErrorReporting_unexpectedTag() throws UnableToCompleteException, IOException,
diff --git a/dev/core/test/com/google/gwt/dev/cfg/testdata/errors/BadLinker.gwt.xml b/dev/core/test/com/google/gwt/dev/cfg/testdata/errors/BadLinker.gwt.xml
new file mode 100644
index 0000000..360189f
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/cfg/testdata/errors/BadLinker.gwt.xml
@@ -0,0 +1,3 @@
+<module rename-to="F">
+  <add-linker name="X"/>
+</module>
diff --git a/dev/core/test/com/google/gwt/dev/cfg/testdata/errors/BadProperty.gwt.xml b/dev/core/test/com/google/gwt/dev/cfg/testdata/errors/BadProperty.gwt.xml
new file mode 100644
index 0000000..d9fcdde
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/cfg/testdata/errors/BadProperty.gwt.xml
@@ -0,0 +1,3 @@
+<module rename-to="F">
+  <set-property name="X" value="x"/>
+</module>
diff --git a/dev/core/test/com/google/gwt/dev/cfg/testdata/errors/BadPropertyValue.gwt.xml b/dev/core/test/com/google/gwt/dev/cfg/testdata/errors/BadPropertyValue.gwt.xml
new file mode 100644
index 0000000..10d644e
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/cfg/testdata/errors/BadPropertyValue.gwt.xml
@@ -0,0 +1,4 @@
+<module rename-to="F">
+  <define-property name="X" values="x,y"/>
+  <set-property name="X" value="z"/>
+</module>
diff --git a/dev/core/test/com/google/gwt/dev/cfg/testdata/errors/InvalidLinkerName.gwt.xml b/dev/core/test/com/google/gwt/dev/cfg/testdata/errors/InvalidLinkerName.gwt.xml
new file mode 100644
index 0000000..8cd3349
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/cfg/testdata/errors/InvalidLinkerName.gwt.xml
@@ -0,0 +1,3 @@
+<module rename-to="F">
+  <add-linker name="123:33"/>
+</module>
diff --git a/dev/core/test/com/google/gwt/dev/cfg/testdata/errors/InvalidName.gwt.xml b/dev/core/test/com/google/gwt/dev/cfg/testdata/errors/InvalidName.gwt.xml
new file mode 100644
index 0000000..4ce1faa
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/cfg/testdata/errors/InvalidName.gwt.xml
@@ -0,0 +1,3 @@
+<module rename-to="F">
+  <define-property name="123:33" values="*"/>
+</module>