JParameter cleanup.

Centralizes the create of JParameter object as a responsibility of
JMethod. This patch is in preparation for the JsInterop varargs patch.

Change-Id: I6a4872d278c8cb8b2473024386bcf8943e0c18b3
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
index 8e2af23..78fa2a2 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
@@ -90,6 +90,40 @@
     return isJsNative() || isJsFunctionMethod() || isJsInterfaceMethod();
   }
 
+  public JParameter createFinalParameter(SourceInfo info, String name, JType type) {
+    return createParameter(info, name, type, true, false);
+  }
+
+  public JParameter createParameter(SourceInfo info, String name, JType type) {
+    return createParameter(info, name, type, false, false);
+  }
+
+  public JParameter createParameter(SourceInfo info, String name, JType type, boolean isFinal) {
+    return createParameter(info, name, type, isFinal, false);
+  }
+
+  public JParameter cloneParameter(JParameter from) {
+    return createParameter(
+        from.getSourceInfo(), from.getName(), from.getType(), from.isFinal(), from.isThis());
+  }
+
+  /**
+   * Creates a parameter to hold the value of this in devirtualized methods.
+   */
+  public JParameter createThisParameter(SourceInfo info, JType type) {
+    return createParameter(info,  "this$static", type, true, true);
+  }
+
+  private JParameter createParameter(SourceInfo info, String name, JType type,
+      boolean isFinal, boolean isThis) {
+    assert (name != null);
+    assert (type != null);
+
+    JParameter x = new JParameter(info, name, type, isFinal, isThis);
+    addParam(x);
+    return x;
+  }
+
   private boolean isJsInterfaceMethod() {
     return isInterfaceMethod() && enclosingType.isJsType();
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JParameter.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JParameter.java
index 3b461f8..d051fc5 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JParameter.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JParameter.java
@@ -23,11 +23,10 @@
 public class JParameter extends JVariable {
   private final boolean isThis;
 
-  public JParameter(SourceInfo info, String name, JType type, boolean isFinal, boolean isThis) {
+  JParameter(SourceInfo info, String name, JType type, boolean isFinal, boolean isThis) {
     super(info, name, type, isFinal);
     this.isThis = isThis;
   }
-
   /**
    * Returns <code>true</code> if this parameter is the this parameter of a
    * static impl method.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
index 573b563..13b6402 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
@@ -229,17 +229,6 @@
     return x;
   }
 
-  public static JParameter createParameter(SourceInfo info, String name, JType type,
-      boolean isFinal, boolean isThis, JMethod enclosingMethod) {
-    assert (name != null);
-    assert (type != null);
-    assert (enclosingMethod != null);
-
-    JParameter x = new JParameter(info, name, type, isFinal, isThis);
-    enclosingMethod.addParam(x);
-    return x;
-  }
-
   public static List<JDeclaredType> deserializeTypes(ObjectInputStream stream) throws IOException,
       ClassNotFoundException {
     @SuppressWarnings("unchecked")
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Devirtualizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Devirtualizer.java
index bd1e20f..c3f3bb9 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/Devirtualizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Devirtualizer.java
@@ -260,11 +260,9 @@
     devirtualMethod.setSynthetic();
     inClass.addMethod(devirtualMethod);
     // Setup parameters.
-    JProgram.createParameter(sourceInfo, "this$static", method.getEnclosingType(), true,
-        true, devirtualMethod);
+    devirtualMethod.createThisParameter(sourceInfo, method.getEnclosingType());
     for (JParameter oldParam : method.getParams()) {
-      JProgram.createParameter(sourceInfo, oldParam.getName(), oldParam.getType(), true, false,
-          devirtualMethod);
+      devirtualMethod.createFinalParameter(sourceInfo, oldParam.getName(), oldParam.getType());
     }
 
     devirtualMethod.freezeParamTypes();
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
index 929e09e..b1e46c2 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
@@ -858,17 +858,7 @@
         FieldBinding fieldBinding = x.binding;
         SourceInfo info = makeSourceInfo(x);
         JExpression instance = pop(x.receiver);
-        JExpression expr;
-        if (fieldBinding.declaringClass == null) {
-          if (!LENGTH_FIELD_NAME.equals(String.valueOf(fieldBinding.name))) {
-            throw new InternalCompilerException("Expected [array].length.");
-          }
-          expr = new JArrayLength(info, instance);
-        } else {
-          JField field = typeMap.get(fieldBinding);
-          expr = new JFieldRef(info, instance, field, curClass.type);
-        }
-
+        JExpression expr = createFieldRef(instance, info, fieldBinding);
         if (x.genericCast != null) {
           JType castType = typeMap.get(x.genericCast);
           /*
@@ -1275,9 +1265,7 @@
       // The parameters to this method will be the same as the Java interface that must be
       // implemented
       for (JParameter origParam : interfaceMethod.getParams()) {
-        JType origType = origParam.getType();
-        samMethod.addParam(new JParameter(origParam.getSourceInfo(), origParam.getName(), origType,
-            origParam.isFinal(), origParam.isThis()));
+        samMethod.cloneParameter(origParam);
       }
       // Create a body like void onClick(ClickEvent e) { OuterClass.lambdaMethod(locals, e); }
       JMethodBody samMethodBody = new JMethodBody(info);
@@ -1457,9 +1445,7 @@
 
     private JParameter createLambdaParameter(SourceInfo info, String paramName, JType paramType,
         JConstructor ctor) {
-      JParameter outerParam = new JParameter(info, paramName, paramType, true, false);
-      ctor.addParam(outerParam);
-      return outerParam;
+      return ctor.createFinalParameter(info, paramName, paramType);
     }
 
     private JClassType createInnerClass(String name, FunctionalExpression x, SourceInfo info,
@@ -1667,16 +1653,7 @@
         if (x.otherBindings != null) {
           for (int i = 0; i < x.otherBindings.length; ++i) {
             FieldBinding fieldBinding = x.otherBindings[i];
-            if (fieldBinding.declaringClass == null) {
-              // probably array.length
-              if (!LENGTH_FIELD_NAME.equals(String.valueOf(fieldBinding.name))) {
-                throw new InternalCompilerException("Expected [array].length.");
-              }
-              curRef = new JArrayLength(info, curRef);
-            } else {
-              JField field = typeMap.get(fieldBinding);
-              curRef = new JFieldRef(info, curRef, field, curClass.type);
-            }
+            curRef = createFieldRef(curRef, info, fieldBinding);
             if (x.otherGenericCasts != null && x.otherGenericCasts[i] != null) {
               JType castType = typeMap.get(x.otherGenericCasts[i]);
               curRef = maybeCast(castType, curRef);
@@ -1689,6 +1666,21 @@
       }
     }
 
+    private JExpression createFieldRef(JExpression instance, SourceInfo info,
+        FieldBinding fieldBinding) {
+      if (fieldBinding.declaringClass == null) {
+        // probably array.length
+        if (!LENGTH_FIELD_NAME.equals(String.valueOf(fieldBinding.name))) {
+          throw new InternalCompilerException("Expected [array].length.");
+        }
+        instance = new JArrayLength(info, instance);
+      } else {
+        JField field = typeMap.get(fieldBinding);
+        instance = new JFieldRef(info, instance, field, curClass.type);
+      }
+      return instance;
+    }
+
     @Override
     public void endVisit(QualifiedSuperReference x, BlockScope scope) {
       try {
@@ -1830,9 +1822,7 @@
             innerLambdaClass, interfaceMethod.getType(),
             false, false, true, interfaceMethod.getAccess());
         for (JParameter origParam : interfaceMethod.getParams()) {
-          JType origType = origParam.getType();
-          samMethod.addParam(new JParameter(origParam.getSourceInfo(), origParam.getName(),
-              origType, origParam.isFinal(), origParam.isThis()));
+          samMethod.cloneParameter(origParam);
         }
         JMethodBody samMethodBody = new JMethodBody(info);
 
@@ -2787,9 +2777,7 @@
       for (TypeBinding jdtParamType : jdtBridgeMethod.parameters) {
         JParameter param = implParams.get(paramIdx++);
         JType paramType = typeMap.get(jdtParamType.erasure());
-        JParameter newParam =
-            new JParameter(param.getSourceInfo(), param.getName(), paramType, true, false);
-        bridgeMethod.addParam(newParam);
+        bridgeMethod.createFinalParameter(param.getSourceInfo(), param.getName(), paramType);
       }
       for (ReferenceBinding exceptionReference : jdtBridgeMethod.thrownExceptions) {
         bridgeMethod.addThrownException((JClassType) typeMap.get(exceptionReference.erasure()));
@@ -3999,11 +3987,7 @@
         }
       }
     } catch (Throwable e) {
-      InternalCompilerException ice = translateException(null, e);
-      StringBuffer sb = new StringBuffer();
-      x.printHeader(0, sb);
-      ice.addNode(x.getClass().getName(), sb.toString(), type.getSourceInfo());
-      throw ice;
+      throw getInternalCompilerException(x, e);
     }
   }
 
@@ -4033,9 +4017,8 @@
       }
       if (x.binding.declaringClass.isEnum()) {
         // Enums have hidden arguments for name and value
-        method.addParam(new JParameter(info, "enum$name", typeMap.get(x.scope.getJavaLangString()),
-            true, false));
-        method.addParam(new JParameter(info, "enum$ordinal", JPrimitiveType.INT, true, false));
+        method.createFinalParameter(info, "enum$name", typeMap.get(x.scope.getJavaLangString()));
+        method.createFinalParameter(info, "enum$ordinal", JPrimitiveType.INT);
       }
       // add synthetic args for outer this
       if (isNested) {
@@ -4165,9 +4148,8 @@
   private void createParameter(SourceInfo info, LocalVariableBinding binding, String name,
       JMethod method, Annotation... annotations) {
     JParameter param =
-        new JParameter(info, name, typeMap.get(binding.type), binding.isFinal(), false);
+        method.createParameter(info, name, typeMap.get(binding.type), binding.isFinal());
     processSuppressedWarnings(param, annotations);
-    method.addParam(param);
   }
 
   private void createParameters(JMethod method, AbstractMethodDeclaration x) {
@@ -4297,14 +4279,19 @@
         }
       }
     } catch (Throwable e) {
-      InternalCompilerException ice = translateException(null, e);
-      StringBuffer sb = new StringBuffer();
-      x.printHeader(0, sb);
-      ice.addNode(x.getClass().getName(), sb.toString(), type.getSourceInfo());
-      throw ice;
+      throw getInternalCompilerException(x, e);
     }
   }
 
+  private InternalCompilerException getInternalCompilerException(TypeDeclaration x, Throwable e) {
+    JDeclaredType type = (JDeclaredType) typeMap.get(x.binding);
+    InternalCompilerException ice = translateException(null, e);
+    StringBuffer sb = new StringBuffer();
+    x.printHeader(0, sb);
+    ice.addNode(x.getClass().getName(), sb.toString(), type.getSourceInfo());
+    return ice;
+  }
+
   /**
    * Returns the list of expressions as a single expression; returns {@code null} if the list
    * is empty.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JjsUtils.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JjsUtils.java
index b94ebaf..78c2c8e 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JjsUtils.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JjsUtils.java
@@ -550,8 +550,7 @@
     emptyMethod.setSynthetic();
     // Copy parameters.
     for (JParameter param : exampleMethod.getParams()) {
-      emptyMethod.addParam(new JParameter(param.getSourceInfo(), param.getName(), param.getType(),
-          param.isFinal(), param.isThis()));
+      emptyMethod.cloneParameter(param);
     }
     JMethodBody body = new JMethodBody(exampleMethod.getSourceInfo());
     emptyMethod.setBody(body);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java b/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
index 12b9b1c..1c4cb4f 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
@@ -47,10 +47,9 @@
 import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event;
 import com.google.gwt.thirdparty.guava.common.annotations.VisibleForTesting;
 import com.google.gwt.thirdparty.guava.common.collect.Lists;
+import com.google.gwt.thirdparty.guava.common.collect.Maps;
 import com.google.gwt.thirdparty.guava.common.collect.Sets;
 
-import java.util.ArrayList;
-import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -179,15 +178,10 @@
 
       JType thisParameterType = enclosingType.strengthenToNonNull();
       // Setup parameters; map from the old params to the new params
-      JParameter thisParam =
-          JProgram.createParameter(sourceInfo, "this$static", thisParameterType, true, true,
-              newMethod);
-      Map<JParameter, JParameter> varMap = new IdentityHashMap<JParameter, JParameter>();
-      for (int i = 0; i < x.getParams().size(); ++i) {
-        JParameter oldVar = x.getParams().get(i);
-        JParameter newVar =
-            JProgram.createParameter(oldVar.getSourceInfo(), oldVar.getName(), oldVar.getType(),
-                oldVar.isFinal(), false, newMethod);
+      JParameter thisParam = newMethod.createThisParameter(sourceInfo, thisParameterType);
+      Map<JParameter, JParameter> varMap = Maps.newIdentityHashMap();
+      for (JParameter oldVar : x.getParams()) {
+        JParameter newVar = newMethod.cloneParameter(oldVar);
         varMap.put(oldVar, newVar);
       }
 
@@ -492,7 +486,7 @@
       Specialization specialization = method.getSpecialization();
       if (specialization != null) {
         JMethod staticMethod = program.getStaticImpl(method);
-        List<JType> params = new ArrayList<JType>(specialization.getParams());
+        List<JType> params = Lists.newArrayList(specialization.getParams());
         params.add(0, staticMethod.getParams().get(0).getType());
         staticMethod.setSpecialization(params, specialization.getReturns(),
             staticMethod.getName());
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java
index f98453a..ff57f5b 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java
@@ -267,19 +267,8 @@
 
   private JParameter createParameter(SourceInfo info, TypeBinding paramType,
       JMethod enclosingMethod, int argPosition) {
-    JType type = get(paramType);
     ensureArgNames(argPosition);
-    JParameter param =
-        new JParameter(info, argNames.get(argPosition), type, true, false);
-    enclosingMethod.addParam(param);
-    return param;
-  }
-
-  private JParameter createParameter(SourceInfo info, TypeBinding paramType,
-      JMethod enclosingMethod, String name) {
-    JParameter param = new JParameter(info, name, get(paramType), true, false);
-    enclosingMethod.addParam(param);
-    return param;
+    return enclosingMethod.createFinalParameter(info, argNames.get(argPosition), get(paramType));
   }
 
   private JDeclaredType createType(ReferenceBinding binding) {
@@ -326,7 +315,7 @@
     if (binding.parameters != null) {
       ensureArgNames(argPosition + binding.parameters.length);
       for (TypeBinding argType : binding.parameters) {
-        createParameter(info, argType, method, argNames.get(argPosition++));
+        method.createFinalParameter(info, argNames.get(argPosition++), get(argType));
       }
     }
     method.freezeParamTypes();
@@ -338,7 +327,7 @@
     if (binding.parameters != null) {
       int i = 0;
       for (TypeBinding argType : binding.parameters) {
-        createParameter(info, argType, method, paramNames[i++]);
+        method.createFinalParameter(info, paramNames[i++], get(argType));
       }
     }
     method.freezeParamTypes();
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/JChangeTrackingVisitorTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/JChangeTrackingVisitorTest.java
index 49173d7..1374bd9 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/JChangeTrackingVisitorTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/JChangeTrackingVisitorTest.java
@@ -22,7 +22,6 @@
 import com.google.gwt.dev.jjs.ast.JDeclaredType;
 import com.google.gwt.dev.jjs.ast.JField;
 import com.google.gwt.dev.jjs.ast.JMethod;
-import com.google.gwt.dev.jjs.ast.JParameter;
 import com.google.gwt.dev.jjs.ast.JPrimitiveType;
 import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.ast.JVariable;
@@ -47,8 +46,7 @@
 
     @Override
     public boolean enter(JMethod x, Context ctx) {
-      x.addParam(new JParameter(SourceOrigin.UNKNOWN, "_newParam_enter",
-          JPrimitiveType.INT, false, false));
+      x.createParameter(SourceOrigin.UNKNOWN, "_newParam_enter", JPrimitiveType.INT);
       return true;
     }
   }
@@ -60,8 +58,7 @@
 
     @Override
     public void exit(JMethod x, Context ctx) {
-      x.addParam(new JParameter(SourceOrigin.UNKNOWN, "_newParam_exit",
-          JPrimitiveType.INT, false, false));
+      x.createParameter(SourceOrigin.UNKNOWN, "_newParam_exit", JPrimitiveType.INT);
     }
   }
 
@@ -72,15 +69,13 @@
 
     @Override
     public boolean enter(JMethod x, Context ctx) {
-      x.addParam(new JParameter(SourceOrigin.UNKNOWN, "_newParam_enter",
-          JPrimitiveType.INT, false, false));
+      x.createParameter(SourceOrigin.UNKNOWN, "_newParam_enter", JPrimitiveType.INT);
       return true;
     }
 
     @Override
     public void exit(JMethod x, Context ctx) {
-      x.addParam(new JParameter(SourceOrigin.UNKNOWN, "_newParam_exit",
-          JPrimitiveType.INT, false, false));
+      x.createParameter(SourceOrigin.UNKNOWN, "_newParam_exit", JPrimitiveType.INT);
     }
   }
 
@@ -92,8 +87,7 @@
 
     @Override
     public boolean enter(JMethod x, Context ctx) {
-      x.addParam(new JParameter(SourceOrigin.UNKNOWN, "_newParam_enter",
-          JPrimitiveType.INT, false, false));
+      x.createParameter(SourceOrigin.UNKNOWN, "_newParam_enter", JPrimitiveType.INT);
       return true;
     }
 
@@ -111,8 +105,7 @@
 
     @Override
     public void exit(JMethod x, Context ctx) {
-      x.addParam(new JParameter(SourceOrigin.UNKNOWN, "_newParam_exit",
-          JPrimitiveType.INT, false, false));
+      x.createParameter(SourceOrigin.UNKNOWN, "_newParam_exit", JPrimitiveType.INT);
     }
 
     @Override