Allows UiRenderer styles before the first call to render()

Fields are initialized both upon construction and on a call to render()

Also ensured that ui:with fields never get optimized as final.

Review at http://gwt-code-reviews.appspot.com/1794803


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@11231 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/uibinder/rebind/FieldManager.java b/user/src/com/google/gwt/uibinder/rebind/FieldManager.java
index 6cbc633..706c6ec 100644
--- a/user/src/com/google/gwt/uibinder/rebind/FieldManager.java
+++ b/user/src/com/google/gwt/uibinder/rebind/FieldManager.java
@@ -134,11 +134,27 @@
       return fieldName;
     }
 
-    int count = getGetterCounter(fieldName) + 1;
-    gettersCounter.put(fieldName, count);
+    incrementFieldCounter(fieldName);
     return getFieldGetter(fieldName);
   }
 
+  /**
+   * Prevent a field from being optimized as only being referenced once (and therefore constant for
+   * all intents). This is necessary for UiRenderer fields passed as parameters to render() calls.
+   * Those fields are modified every time a template is rendered with the parameter values.
+   */
+  public void disableOptimization(String fieldName) {
+    // TODO(rchandia): This hackish method should go away when the
+    // UiRenderer generator gets separated from the one used for
+    // UiBinder. Fields corresponding to parameters of render() will
+    // not use the initialization generated by the FieldWriter.
+
+    // Incrementing the counter twice ensures no optimization happens.
+    // See AbstractFieldWriter#writeFieldDefinition()
+    incrementFieldCounter(fieldName);
+    incrementFieldCounter(fieldName);
+  }
+
   public FieldReference findFieldReference(String expressionIn) {
     String expression = expressionIn;
     if (useLazyWidgetBuilders) {
@@ -392,6 +408,14 @@
     return (count == null) ? 0 : count;
   }
 
+  /**
+   * Increments the number of times a getter for the given field is called.
+   */
+  private void incrementFieldCounter(String fieldName) {
+    int count = getGetterCounter(fieldName) + 1;
+    gettersCounter.put(fieldName, count);
+  }
+
   private FieldWriter registerField(String fieldName, FieldWriter field)
       throws UnableToCompleteException {
     ensureValidity(fieldName);
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
index 9cd10d3..76feb3e 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
@@ -394,7 +394,9 @@
 
     fieldWriter = fieldManager.registerField(
         FieldWriterType.IMPORTED, matchingResourceType.getErasedType(), resourceName);
-    fieldWriter.setInitializer(UiBinderWriter.RENDER_PARAM_HOLDER_PREFIX + resourceName);
+    // Sets initialization as a NOOP. These fields are set from
+    // parameters passed to UiRenderer#render(), instead.
+    fieldWriter.setInitializer(resourceName);
   }
 
   private void createSingleImport(XMLElement elem, JClassType enclosingType,
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
index fd6347c..9935863 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
@@ -76,8 +76,6 @@
  */
 public class UiBinderWriter implements Statements {
 
-  static final String RENDER_PARAM_HOLDER_PREFIX = "_renderer_param_holder_";
-
   private static final String SAFE_VAR_PREFIX =
     "somethingUnlikelyToCollideWithParamNamesWefio";
 
@@ -1935,8 +1933,28 @@
     w.newline();
 
     JParameter[] renderParameters = findRenderParameters(baseClass);
+    for (JParameter param : renderParameters) {
+      // Prevent fields from render() parameters from being optimized.
+      fieldManager.disableOptimization(param.getName());
+    }
 
-    writeRenderParameterDefinitions(w, renderParameters);
+    // public UiRendererImplClass() {
+    w.write("public %s() {", implClassName);
+    w.indent();
+    w.write("build_fields();");
+    w.outdent();
+    // }
+    w.write("}");
+    w.newline();
+
+    // private build_fields() {
+    w.write("private void build_fields() {");
+    w.indent();
+    fieldManager.initializeWidgetsInnerClass(w, getOwnerClass());
+    w.outdent();
+    // }
+    w.write("}");
+    w.newline();
 
     String renderParameterDeclarations = renderMethodParameters(renderParameters);
     w.write("public void render(final %s sb%s%s) {", SafeHtmlBuilder.class.getName(),
@@ -1949,7 +1967,7 @@
     w.write("uiId = com.google.gwt.dom.client.Document.get().createUniqueId();");
     w.newline();
 
-    fieldManager.initializeWidgetsInnerClass(w, getOwnerClass());
+    w.write("build_fields();");
     w.newline();
 
     String safeHtml = rootField.getSafeHtml();
@@ -2245,20 +2263,13 @@
     }
   }
 
-  private void writeRenderParameterDefinitions(IndentedWriter w, JParameter[] renderParameters) {
-    for (int i = 0; i < renderParameters.length; i++) {
-      JParameter parameter = renderParameters[i];
-      w.write("private %s %s%s;", parameter.getType().getQualifiedSourceName(),
-          RENDER_PARAM_HOLDER_PREFIX, parameter.getName());
-      w.newline();
-    }
-  }
-
   private void writeRenderParameterInitializers(IndentedWriter w, JParameter[] renderParameters) {
     for (int i = 0; i < renderParameters.length; i++) {
       JParameter parameter = renderParameters[i];
-      w.write("%s%s = %s;", RENDER_PARAM_HOLDER_PREFIX, parameter.getName(), parameter.getName());
-      w.newline();
+      if (fieldManager.lookup(parameter.getName()) != null) {
+        w.write("this.%s = %s;", parameter.getName(), parameter.getName());
+        w.newline();
+      }
     }
   }
 
diff --git a/user/test/com/google/gwt/uibinder/test/client/UiRendererTest.java b/user/test/com/google/gwt/uibinder/test/client/UiRendererTest.java
index 0474a0e..b5a5ef5 100644
--- a/user/test/com/google/gwt/uibinder/test/client/UiRendererTest.java
+++ b/user/test/com/google/gwt/uibinder/test/client/UiRendererTest.java
@@ -256,6 +256,12 @@
     assertEquals(renderer.getUiStyle().disabled(), nameSpan.getClassName());
   }
 
+  public void testGetStyleBeforeRender() {
+    HtmlRenderer renderer = GWT.create(HtmlRenderer.class);
+    assertNotNull(renderer.getUiStyle().enabled());
+    assertNotNull(renderer.getUiStyle2().ok());
+  }
+
   @Override
   protected void gwtTearDown() {
     docDiv.removeFromParent();
diff --git a/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.java b/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.java
index 12a6ebd..c745519 100644
--- a/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.java
+++ b/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.java
@@ -86,10 +86,19 @@
   }
 
   /**
+   * Another style defined within the UiBinder file.
+   */
+  public interface UiStyle2 extends CssResource {
+    String ok();
+    String bad();
+  }
+
+  /**
    * A UiRinder Cell renderer.
    */
   public interface HtmlRenderer extends UiRenderer {
     UiStyle getUiStyle();
+    UiStyle2 getUiStyle2();
     SpanElement getNameSpan(Element owner);
     TableColElement getNarrowColumn(Element owner);
     DivElement getRoot(Element owner);
diff --git a/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.ui.xml b/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.ui.xml
index e0eb3ba..8c1ca5c 100644
--- a/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.ui.xml
+++ b/user/test/com/google/gwt/uibinder/test/client/UiRendererUi.ui.xml
@@ -21,6 +21,10 @@
     .enabled { color:black; }
     .disabled { color:gray; }
   </ui:style>
+  <ui:style field="uiStyle2" type="com.google.gwt.uibinder.test.client.UiRendererUi.UiStyle2">
+    .ok { color:blue; }
+    .bad { color:red; }
+  </ui:style>
 
   <div ui:field='root' class="{res.style.bodyColor} {res.style.bodyFont}"
       title="The title of this div is localizable">