Simplify field access generation.

Also fixes so that js name are used when the field is a js property.

Change-Id: Ib78b8d22bdc926643ec052dd2745ffc174bcc6f7
Review-Link: https://gwt-review.googlesource.com/#/c/13591/
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
index 0da095f..845df17 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -431,22 +431,17 @@
 
     @Override
     public void endVisit(JField x, Context ctx) {
-      String name = x.getName();
-      String mangleName = mangleName(x);
+      JsName jsName;
       if (x.isStatic()) {
-        JsName jsName = topScope.declareName(mangleName, name);
-        names.put(x, jsName);
-        recordSymbol(x, jsName);
+        jsName = topScope.declareName(mangleName(x), x.getName());
       } else {
-        JsName jsName;
-        if (x.isJsProperty()) {
-          jsName = scopeStack.peek().declareUnobfuscatableName(name);
-        } else {
-          jsName = scopeStack.peek().declareName(mangleName, name);
-        }
-        names.put(x, jsName);
-        recordSymbol(x, jsName);
+        jsName =
+            x.isJsProperty()
+                ? scopeStack.peek().declareUnobfuscatableName(x.getJsName())
+                : scopeStack.peek().declareName(mangleName(x), x.getName());
       }
+      names.put(x, jsName);
+      recordSymbol(x, jsName);
     }
 
     @Override
@@ -1032,35 +1027,30 @@
 
     @Override
     public void endVisit(JFieldRef x, Context ctx) {
-      JField field = x.getField();
-      JsName jsFieldName = names.get(field);
-      JsNameRef nameRef = jsFieldName.makeRef(x.getSourceInfo());
-      JsExpression curExpr = nameRef;
+      JsExpression qualifier = (JsExpression) (x.getInstance() != null ? pop() : null);
+      boolean isStatic = x.getField().isStatic();
+      push(isStatic ? dispatchToStaticField(x, qualifier) : dispatchToInstanceField(x, qualifier));
+    }
 
+    private JsExpression dispatchToStaticField(JFieldRef x, JsExpression unnecessaryQualifier) {
       /*
        * Note: the comma expressions here would cause an illegal tree state if
        * the result expression ended up on the lhs of an assignment. A hack in
        * in endVisit(JBinaryOperation) rectifies the situation.
        */
 
-      // See if we need a clinit
-      JsInvocation jsInvocation = maybeCreateClinitCall(field, false);
-      if (jsInvocation != null) {
-        curExpr = createCommaExpression(jsInvocation, curExpr);
-      }
+      JsExpression result = names.get(x.getField()).makeRef(x.getSourceInfo());
 
-      if (x.getInstance() != null) {
-        JsExpression qualifier = pop();
-        if (field.isStatic()) {
-          // unnecessary qualifier, create a comma expression
-          curExpr = createCommaExpression(qualifier, curExpr);
-        } else {
-          // necessary qualifier, qualify the name ref
-          nameRef.setQualifier(qualifier);
-        }
-      }
+      // Add clinit (if needed).
+      result = createCommaExpression(maybeCreateClinitCall(x.getField(), false), result);
 
-      push(curExpr);
+      return createCommaExpression(unnecessaryQualifier, result);
+    }
+
+    private JsExpression dispatchToInstanceField(JFieldRef x, JsExpression instance) {
+      JsNameRef reference = names.get(x.getField()).makeRef(x.getSourceInfo());
+      reference.setQualifier(instance);
+      return reference;
     }
 
     @Override
@@ -1309,37 +1299,35 @@
         }
       }
 
+      JsExpression qualifier = (JsExpression) (x.getInstance() != null ? pop() : null);
+
       JsExpression result;
       if (method.isStatic()) {
-        result = dispatchToStatic(x, method, args);
+        result = dispatchToStatic(qualifier, method, args, x.getSourceInfo());
       } else if (x.isStaticDispatchOnly()) {
-        result = dispatchToSuper(x, method, args);
+        result = dispatchToSuper(qualifier, method, args, x.getSourceInfo());
       } else if (method.isOrOverridesJsFunctionMethod()) {
-        result = dispatchToJsFunction(args, x.getSourceInfo());
+        result = dispatchToJsFunction(qualifier, args, x.getSourceInfo());
       } else {
-        result = dispatchToInstanceMethod(method, args, x.getSourceInfo());
+        result = dispatchToInstanceMethod(qualifier, method, args, x.getSourceInfo());
       }
 
       push(result);
     }
 
-    private JsExpression dispatchToStatic(JMethodCall x, JMethod method, List<JsExpression> args) {
+    private JsExpression dispatchToStatic(JsExpression unnecessaryQualifier, JMethod method,
+        List<JsExpression> args, SourceInfo sourceInfo) {
       JsNameRef methodName =
           method.isJsNative()
-              ? createJsQualifier(method.getQualifiedJsName(), x.getSourceInfo())
-              : names.get(method).makeRef(x.getSourceInfo());
-      JsExpression result = new JsInvocation(x.getSourceInfo(), methodName, args);
-      if (x.getInstance() != null) {
-        JsExpression unnecessaryQualifier = pop();
-        result = createCommaExpression(unnecessaryQualifier, result);
-      }
-      return result;
+              ? createJsQualifier(method.getQualifiedJsName(), sourceInfo)
+              : names.get(method).makeRef(sourceInfo);
+      JsExpression result = new JsInvocation(sourceInfo, methodName, args);
+
+      return createCommaExpression(unnecessaryQualifier, result);
     }
 
-    private JsExpression dispatchToSuper(JMethodCall x, JMethod method, List<JsExpression> args) {
-      SourceInfo sourceInfo = x.getSourceInfo();
-      JsExpression instance = (JsExpression) pop();
-
+    private JsExpression dispatchToSuper(
+        JsExpression instance, JMethod method, List<JsExpression> args, SourceInfo sourceInfo) {
       JsNameRef methodNameRef;
       if (method.isConstructor()) {
         // We don't generate calls to super native constructors (yet).
@@ -1363,7 +1351,7 @@
         JDeclaredType superClass = method.getEnclosingType();
         if (method.isJsNative()) {
           // Construct jsPrototype.prototype.jsname
-          methodNameRef = createJsQualifier(method.getQualifiedJsName(), x.getSourceInfo());
+          methodNameRef = createJsQualifier(method.getQualifiedJsName(), sourceInfo);
         } else {
           // Construct JCHSU.getPrototypeFor(type).polyname
 
@@ -1387,17 +1375,18 @@
       return jsInvocation;
     }
 
-    private JsExpression dispatchToJsFunction(List<JsExpression> args, SourceInfo sourceInfo) {
-      return new JsInvocation(sourceInfo, (JsExpression) pop(), args);
+    private JsExpression dispatchToJsFunction(
+        JsExpression instance, List<JsExpression> args, SourceInfo sourceInfo) {
+      return new JsInvocation(sourceInfo, instance, args);
     }
 
     private JsExpression dispatchToInstanceMethod(
-        JMethod method, List<JsExpression> args, SourceInfo sourceInfo) {
+        JsExpression instance, JMethod method, List<JsExpression> args, SourceInfo sourceInfo) {
       JsNameRef reference =
           method.isOrOverridesJsMethod()
               ? new JsNameRef(sourceInfo, method.getJsName())
               : polymorphicNames.get(method).makeRef(sourceInfo);
-      reference.setQualifier((JsExpression) pop()); // instance
+      reference.setQualifier(instance);
 
       switch (method.getJsPropertyAccessorType()) {
         case SETTER:
@@ -2641,9 +2630,8 @@
         }
 
         if (method.exposesJsMethod()) {
-          String jsName = method.getJsName();
-          JsName exportedName = interfaceScope.declareUnobfuscatableName(jsName);
-          generateVTableAlias(globalStmts, method, exportedName);
+          JsName jsName = interfaceScope.declareUnobfuscatableName(method.getJsName());
+          generateVTableAlias(globalStmts, method, jsName);
         }
 
         if (method.exposesPackagePrivateMethod()) {
diff --git a/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java b/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
index 427345b..c5f3894 100644
--- a/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
@@ -539,6 +539,25 @@
     assertEquals(null, checkRescued);
   }
 
+  private static boolean testClassInitialized = false;
+
+  private static class TestClass {
+    static {
+      testClassInitialized = true;
+    }
+    public static int staticField = 32;
+  }
+
+  public void testClinitOverInstance() {
+    assertEquals(32, getTest().staticField);
+    assertTrue(testClassInitialized);
+  }
+
+  private TestClass getTest() {
+    assertFalse(testClassInitialized);
+    return null;
+  }
+
   public void testConditionals() {
     assertTrue(TRUE ? TRUE : FALSE);
     assertFalse(FALSE ? TRUE : FALSE);