UnifyAst works with SOYC.

When building serialized ASTs with GwtAstBuilder, we never create SourceInfoCorrelation nodes, because the same serialized ASTs are later used both with and without SOYC on.

This introduces a SOYC-only fixup pass after UnifyAst that replaces the "bare" SourceInfo nodes with correlated nodes.

http://gwt-code-reviews.appspot.com/1455801/

Review by: zundel@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10291 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/StoryRecorder.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StoryRecorder.java
index c1b935d..aeaefb3 100644
--- a/dev/core/src/com/google/gwt/core/ext/soyc/impl/StoryRecorder.java
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StoryRecorder.java
@@ -19,7 +19,6 @@
 import com.google.gwt.core.ext.soyc.ClassMember;
 import com.google.gwt.core.ext.soyc.Member;
 import com.google.gwt.core.ext.soyc.Range;
-import com.google.gwt.core.ext.soyc.Story;
 import com.google.gwt.dev.jjs.Correlation;
 import com.google.gwt.dev.jjs.Correlation.Axis;
 import com.google.gwt.dev.jjs.SourceInfo;
@@ -32,7 +31,6 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.List;
@@ -99,7 +97,6 @@
    */
   private transient Map<SourceInfo, StoryImpl> storyCache =
       new IdentityHashMap<SourceInfo, StoryImpl>();
-  private final Map<Story, Integer> storyIds = new HashMap<Story, Integer>();
 
   private StoryRecorder() {
   }
@@ -239,16 +236,8 @@
   }
 
   private void emitStory(StoryImpl story, Range range) throws IOException {
-    int storyNum;
-    if (storyIds.containsKey(story)) {
-      storyNum = storyIds.get(story);
-    } else {
-      storyNum = storyIds.size();
-      storyIds.put(story, storyNum);
-    }
-
     builder.append("<story id=\"story");
-    builder.append(storyNum);
+    builder.append(story.getId());
     if (story.getLiteralTypeName() != null) {
       builder.append("\" literal=\"");
       builder.append(story.getLiteralTypeName());
@@ -271,7 +260,7 @@
     builder.append("<js fragment=\"");
     builder.append(curHighestFragment);
     builder.append("\"/>\n<storyref idref=\"story");
-    builder.append(storyNum);
+    builder.append(story.getId());
 
     int start = range.getStart();
     int end = range.getEnd();
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
index 0ae4157..819f123 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -104,6 +104,7 @@
 import com.google.gwt.dev.jjs.impl.ReplaceRunAsyncs;
 import com.google.gwt.dev.jjs.impl.ResolveRebinds;
 import com.google.gwt.dev.jjs.impl.SameParameterValueOptimizer;
+import com.google.gwt.dev.jjs.impl.SourceInfoCorrelator;
 import com.google.gwt.dev.jjs.impl.TypeLinker;
 import com.google.gwt.dev.jjs.impl.TypeMap;
 import com.google.gwt.dev.jjs.impl.TypeTightener;
@@ -557,6 +558,10 @@
         // Free up memory.
         rpo.clear();
 
+        if (options.isSoycEnabled()) {
+          SourceInfoCorrelator.exec(jprogram);
+        }
+
         // Compute all super type/sub type info
         jprogram.typeOracle.computeBeforeAST();
       } else {
@@ -978,7 +983,7 @@
     program.addEntryMethod(registerEntry);
 
     for (String mainClassName : mainClassNames) {
-      block.addStmt(makeStatsCalls(program, mainClassName));
+      block.addStmt(makeStatsCalls(info, program, mainClassName));
       JDeclaredType mainType = program.getFromTypeMap(mainClassName);
 
       if (mainType == null) {
@@ -1298,17 +1303,16 @@
    *   Stats.onModuleStart("mainClassName");
    * </pre>
    */
-  private static JStatement makeStatsCalls(JProgram program, String mainClassName) {
-    SourceInfo sourceInfo = program.createSourceInfoSynthetic(JavaToJavaScriptCompiler.class);
+  private static JStatement makeStatsCalls(SourceInfo info, JProgram program, String mainClassName) {
     JMethod isStatsAvailableMethod = program.getIndexedMethod("Stats.isStatsAvailable");
     JMethod onModuleStartMethod = program.getIndexedMethod("Stats.onModuleStart");
 
-    JMethodCall availableCall = new JMethodCall(sourceInfo, null, isStatsAvailableMethod);
-    JMethodCall onModuleStartCall = new JMethodCall(sourceInfo, null, onModuleStartMethod);
-    onModuleStartCall.addArg(program.getLiteralString(sourceInfo, mainClassName));
+    JMethodCall availableCall = new JMethodCall(info, null, isStatsAvailableMethod);
+    JMethodCall onModuleStartCall = new JMethodCall(info, null, onModuleStartMethod);
+    onModuleStartCall.addArg(program.getLiteralString(info, mainClassName));
 
     JBinaryOperation amp =
-        new JBinaryOperation(sourceInfo, program.getTypePrimitiveBoolean(), JBinaryOperator.AND,
+        new JBinaryOperation(info, program.getTypePrimitiveBoolean(), JBinaryOperator.AND,
             availableCall, onModuleStartCall);
 
     return amp.makeStatement();
diff --git a/dev/core/src/com/google/gwt/dev/jjs/SourceInfoCorrelation.java b/dev/core/src/com/google/gwt/dev/jjs/SourceInfoCorrelation.java
index c9d5a27..e488909 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/SourceInfoCorrelation.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/SourceInfoCorrelation.java
@@ -49,7 +49,7 @@
     this.parent = null;
   }
 
-  private SourceInfoCorrelation(SourceInfoCorrelation parent, SourceOrigin origin) {
+  public SourceInfoCorrelation(SourceInfoCorrelation parent, SourceOrigin origin) {
     this.origin = origin;
     this.parent = parent;
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JNode.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JNode.java
index bc8d2c4..74e8de1 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JNode.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JNode.java
@@ -28,7 +28,7 @@
  */
 public abstract class JNode implements JVisitable, HasSourceInfo, Serializable {
 
-  private final SourceInfo info;
+  private SourceInfo info;
 
   protected JNode(SourceInfo info) {
     assert info != null : "SourceInfo must be provided for JNodes";
@@ -39,6 +39,11 @@
     return info;
   }
 
+  public void setSourceInfo(SourceInfo info) {
+    assert this.info.getOrigin() == info.getOrigin();
+    this.info = info;
+  }
+
   // Causes source generation to delegate to the one visitor
   public final String toSource() {
     DefaultTextOutput out = new DefaultTextOutput(false);
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 359bd05..3e6765a 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
@@ -822,7 +822,7 @@
   }
 
   public JStringLiteral getLiteralString(SourceInfo sourceInfo, String s) {
-    sourceInfo.addCorrelation(correlator.by(Literal.STRING));
+    sourceInfo.addCorrelation(sourceInfo.getCorrelator().by(Literal.STRING));
     return new JStringLiteral(sourceInfo, s, typeString);
   }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
index 8d5e052..9a41672 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
@@ -112,7 +112,7 @@
         }
       }
 
-      for (JArrayType type : program.getAllArrayTypes()) {
+      for (JArrayType type : instantiatedArrayTypes) {
         computeSourceType(type);
       }
 
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 143de49..4bb1c7d 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
@@ -268,10 +268,14 @@
       names.put(nullMethod, nullFunc.getName());
 
       /*
-       * Make sure we record all of the program's array types since
-       * JProgram.traverse() doesn't iterate over them.
+       * Create names for instantiable array types since JProgram.traverse()
+       * doesn't iterate over them.
        */
-      accept(program.getAllArrayTypes());
+      for (JArrayType arrayType : program.getAllArrayTypes()) {
+        if (typeOracle.isInstantiatedType(arrayType)) {
+          accept(arrayType);
+        }
+      }
 
       // Generate symbolic names for all query type ids.
       if (!output.shouldMinimize()) {
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 dbf589c..e7b17f1 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
@@ -2002,8 +2002,8 @@
      * arguments, but with a different type signature.
      */
     private void createBridgeMethod(SyntheticMethodBinding jdtBridgeMethod) {
-      SourceInfo info = curClass.classType.getSourceInfo();
       JMethod implMethod = typeMap.get(jdtBridgeMethod.targetMethod);
+      SourceInfo info = implMethod.getSourceInfo();
       String[] paramNames = null;
       List<JParameter> implParams = implMethod.getParams();
       if (jdtBridgeMethod.parameters != null) {
@@ -2078,7 +2078,6 @@
       JLocal newLocal =
           JProgram.createLocal(info, intern(x.name), localType, b.isFinal(), curMethod.body);
       curMethod.locals.put(b, newLocal);
-      curMethod.body.addLocal(newLocal);
       return newLocal;
     }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/SourceInfoCorrelator.java b/dev/core/src/com/google/gwt/dev/jjs/impl/SourceInfoCorrelator.java
new file mode 100644
index 0000000..cffebb6
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/SourceInfoCorrelator.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2011 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.jjs.impl;
+
+import com.google.gwt.dev.jjs.Correlation.Literal;
+import com.google.gwt.dev.jjs.CorrelationFactory;
+import com.google.gwt.dev.jjs.CorrelationFactory.RealCorrelationFactory;
+import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.SourceInfoCorrelation;
+import com.google.gwt.dev.jjs.SourceOrigin;
+import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.JClassLiteral;
+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.JNode;
+import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JStringLiteral;
+import com.google.gwt.dev.jjs.ast.JVisitor;
+import com.google.gwt.dev.jjs.ast.js.JsniMethodBody;
+import com.google.gwt.dev.js.ast.JsContext;
+import com.google.gwt.dev.js.ast.JsNode;
+import com.google.gwt.dev.js.ast.JsStringLiteral;
+import com.google.gwt.dev.js.ast.JsSuperVisitor;
+
+import java.util.Stack;
+
+/**
+ * Fix up SOYC parents and add correlations.
+ */
+public class SourceInfoCorrelator {
+
+  private static class SourceInfoVisitor extends JVisitor {
+
+    /**
+     * Fix up SOYC for JSNI methods.
+     */
+    private class SourceInfoJsVisitor extends JsSuperVisitor {
+
+      @Override
+      public void endVisit(JsNode x, JsContext ctx) {
+        SourceInfo popped = parents.pop();
+        assert popped == x.getSourceInfo();
+      }
+
+      @Override
+      public void endVisit(JsStringLiteral x, JsContext ctx) {
+        x.getSourceInfo().addCorrelation(factory.by(Literal.STRING));
+        super.endVisit(x, ctx);
+      }
+
+      @Override
+      public boolean visit(JsNode x, JsContext ctx) {
+        SourceInfo info = x.getSourceInfo();
+        info = pushAndConvert(info);
+        x.setSourceInfo(info);
+        return true;
+      }
+    }
+
+    private CorrelationFactory factory = RealCorrelationFactory.INSTANCE;
+    private SourceInfoJsVisitor jsVisitor = new SourceInfoJsVisitor();
+    private Stack<SourceInfoCorrelation> parents = new Stack<SourceInfoCorrelation>();
+
+    @Override
+    public void endVisit(JClassLiteral x, Context ctx) {
+      x.getSourceInfo().addCorrelation(factory.by(Literal.CLASS));
+      super.endVisit(x, ctx);
+    }
+
+    @Override
+    public void endVisit(JDeclaredType x, Context ctx) {
+      x.getSourceInfo().addCorrelation(factory.by(x));
+      super.endVisit(x, ctx);
+    }
+
+    @Override
+    public void endVisit(JField x, Context ctx) {
+      x.getSourceInfo().addCorrelation(factory.by(x));
+      super.endVisit(x, ctx);
+    }
+
+    @Override
+    public void endVisit(JMethod x, Context ctx) {
+      x.getSourceInfo().addCorrelation(factory.by(x));
+      super.endVisit(x, ctx);
+    }
+
+    @Override
+    public void endVisit(JNode x, Context ctx) {
+      SourceInfo popped = parents.pop();
+      assert popped == x.getSourceInfo();
+    }
+
+    @Override
+    public void endVisit(JProgram x, Context ctx) {
+      SourceInfo popped = parents.pop();
+      assert popped == null;
+    }
+
+    @Override
+    public void endVisit(JsniMethodBody x, Context ctx) {
+      jsVisitor.accept(x.getFunc());
+      super.endVisit(x, ctx);
+    }
+
+    @Override
+    public void endVisit(JStringLiteral x, Context ctx) {
+      x.getSourceInfo().addCorrelation(factory.by(Literal.STRING));
+      super.endVisit(x, ctx);
+    }
+
+    @Override
+    public boolean visit(JNode x, Context ctx) {
+      SourceInfo info = x.getSourceInfo();
+      info = pushAndConvert(info);
+      x.setSourceInfo(info);
+      return true;
+    }
+
+    @Override
+    public boolean visit(JProgram x, Context ctx) {
+      // Types have no source parent.
+      parents.push(null);
+      return true;
+    }
+
+    protected SourceInfo pushAndConvert(SourceInfo info) {
+      if (info instanceof SourceOrigin) {
+        SourceOrigin origin = (SourceOrigin) info;
+        SourceInfoCorrelation parent = parents.peek();
+        if (parent != null) {
+          info = new SourceInfoCorrelation(parent, origin);
+        } else {
+          info = new SourceInfoCorrelation(origin);
+        }
+      }
+      parents.push((SourceInfoCorrelation) info);
+      return info;
+    }
+  }
+
+  public static void exec(JProgram program) {
+    new SourceInfoVisitor().accept(program);
+  }
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
index 21664da..259e8f2 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.dev.jjs.impl;
 
+import com.google.gwt.dev.jjs.SourceOrigin;
 import com.google.gwt.dev.jjs.ast.CanBeAbstract;
 import com.google.gwt.dev.jjs.ast.Context;
 import com.google.gwt.dev.jjs.ast.JArrayRef;
@@ -282,8 +283,7 @@
       // Fake an assignment-to-self on all args to prevent tightening
       JMethod method = x.getTarget();
       for (JParameter param : method.getParams()) {
-        addAssignment(param, new JParameterRef(program
-            .createSourceInfoSynthetic(RecordVisitor.class), param));
+        addAssignment(param, new JParameterRef(SourceOrigin.UNKNOWN, param));
       }
     }
 
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsNode.java b/dev/core/src/com/google/gwt/dev/js/ast/JsNode.java
index 4baa0d4..d1837cd 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsNode.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsNode.java
@@ -29,7 +29,7 @@
 public abstract class JsNode implements JsVisitable, HasSourceInfo,
     Serializable {
 
-  private final SourceInfo sourceInfo;
+  private SourceInfo sourceInfo;
 
   protected JsNode(SourceInfo sourceInfo) {
     assert sourceInfo != null : "SourceInfo must be provided for JsNodes";
@@ -40,6 +40,11 @@
     return sourceInfo;
   }
 
+  public void setSourceInfo(SourceInfo info) {
+    assert this.sourceInfo.getOrigin() == info.getOrigin();
+    this.sourceInfo = info;
+  }
+
   /**
    * Returns a source code representation of the node using short identifiers.
    */
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsSuperVisitor.java b/dev/core/src/com/google/gwt/dev/js/ast/JsSuperVisitor.java
new file mode 100644
index 0000000..231437f
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsSuperVisitor.java
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2008 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.js.ast;
+
+import com.google.gwt.dev.js.ast.JsVars.JsVar;
+
+/**
+ * A visitor that walks up the type hierarchy. By default, if a subclass has no
+ * specific override for a concrete node type, this visitor will call a
+ * visit/endVisit for its super class, and so on up the type heirarchy.
+ */
+public class JsSuperVisitor extends JsVisitor {
+
+  @Override
+  public void endVisit(JsArrayAccess x, JsContext ctx) {
+    endVisit((JsExpression) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsArrayLiteral x, JsContext ctx) {
+    endVisit((JsLiteral) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsBinaryOperation x, JsContext ctx) {
+    endVisit((JsExpression) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsBlock x, JsContext ctx) {
+    endVisit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsBooleanLiteral x, JsContext ctx) {
+    endVisit((JsValueLiteral) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsBreak x, JsContext ctx) {
+    endVisit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsCase x, JsContext ctx) {
+    endVisit((JsSwitchMember) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsCatch x, JsContext ctx) {
+    endVisit((JsNode) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsConditional x, JsContext ctx) {
+    endVisit((JsExpression) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsContinue x, JsContext ctx) {
+    endVisit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsDebugger x, JsContext ctx) {
+    endVisit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsDefault x, JsContext ctx) {
+    endVisit((JsSwitchMember) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsDoWhile x, JsContext ctx) {
+    endVisit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsEmpty x, JsContext ctx) {
+    endVisit((JsStatement) x, ctx);
+  }
+
+  public void endVisit(JsExpression x, JsContext ctx) {
+    endVisit((JsNode) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsExprStmt x, JsContext ctx) {
+    endVisit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsFor x, JsContext ctx) {
+    endVisit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsForIn x, JsContext ctx) {
+    endVisit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsFunction x, JsContext ctx) {
+    endVisit((JsLiteral) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsIf x, JsContext ctx) {
+    endVisit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsInvocation x, JsContext ctx) {
+    endVisit((JsExpression) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsLabel x, JsContext ctx) {
+    endVisit((JsStatement) x, ctx);
+  }
+
+  public void endVisit(JsLiteral x, JsContext ctx) {
+    endVisit((JsExpression) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsNameOf x, JsContext ctx) {
+    endVisit((JsExpression) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsNameRef x, JsContext ctx) {
+    endVisit((JsExpression) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsNew x, JsContext ctx) {
+    endVisit((JsExpression) x, ctx);
+  }
+
+  @SuppressWarnings("unused")
+  public void endVisit(JsNode x, JsContext ctx) {
+  }
+
+  @Override
+  public void endVisit(JsNullLiteral x, JsContext ctx) {
+    endVisit((JsValueLiteral) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsNumberLiteral x, JsContext ctx) {
+    endVisit((JsValueLiteral) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsObjectLiteral x, JsContext ctx) {
+    endVisit((JsLiteral) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsParameter x, JsContext ctx) {
+    endVisit((JsNode) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsPostfixOperation x, JsContext ctx) {
+    endVisit((JsUnaryOperation) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsPrefixOperation x, JsContext ctx) {
+    endVisit((JsUnaryOperation) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsProgram x, JsContext ctx) {
+    endVisit((JsNode) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsProgramFragment x, JsContext ctx) {
+    endVisit((JsNode) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsPropertyInitializer x, JsContext ctx) {
+    endVisit((JsNode) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsRegExp x, JsContext ctx) {
+    endVisit((JsValueLiteral) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsReturn x, JsContext ctx) {
+    endVisit((JsStatement) x, ctx);
+  }
+
+  public void endVisit(JsStatement x, JsContext ctx) {
+    endVisit((JsNode) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsStringLiteral x, JsContext ctx) {
+    endVisit((JsValueLiteral) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsSwitch x, JsContext ctx) {
+    endVisit((JsStatement) x, ctx);
+  }
+
+  public void endVisit(JsSwitchMember x, JsContext ctx) {
+    endVisit((JsNode) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsThisRef x, JsContext ctx) {
+    endVisit((JsValueLiteral) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsThrow x, JsContext ctx) {
+    endVisit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsTry x, JsContext ctx) {
+    endVisit((JsStatement) x, ctx);
+  }
+
+  public void endVisit(JsUnaryOperation x, JsContext ctx) {
+    endVisit((JsExpression) x, ctx);
+  }
+
+  public void endVisit(JsValueLiteral x, JsContext ctx) {
+    endVisit((JsLiteral) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsVar x, JsContext ctx) {
+    endVisit((JsNode) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsVars x, JsContext ctx) {
+    endVisit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public void endVisit(JsWhile x, JsContext ctx) {
+    endVisit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsArrayAccess x, JsContext ctx) {
+    return visit((JsExpression) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsArrayLiteral x, JsContext ctx) {
+    return visit((JsLiteral) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsBinaryOperation x, JsContext ctx) {
+    return visit((JsExpression) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsBlock x, JsContext ctx) {
+    return visit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsBooleanLiteral x, JsContext ctx) {
+    return visit((JsValueLiteral) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsBreak x, JsContext ctx) {
+    return visit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsCase x, JsContext ctx) {
+    return visit((JsSwitchMember) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsCatch x, JsContext ctx) {
+    return visit((JsNode) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsConditional x, JsContext ctx) {
+    return visit((JsExpression) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsContinue x, JsContext ctx) {
+    return visit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsDebugger x, JsContext ctx) {
+    return visit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsDefault x, JsContext ctx) {
+    return visit((JsSwitchMember) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsDoWhile x, JsContext ctx) {
+    return visit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsEmpty x, JsContext ctx) {
+    return visit((JsStatement) x, ctx);
+  }
+
+  public boolean visit(JsExpression x, JsContext ctx) {
+    return visit((JsNode) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsExprStmt x, JsContext ctx) {
+    return visit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsFor x, JsContext ctx) {
+    return visit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsForIn x, JsContext ctx) {
+    return visit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsFunction x, JsContext ctx) {
+    return visit((JsLiteral) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsIf x, JsContext ctx) {
+    return visit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsInvocation x, JsContext ctx) {
+    return visit((JsExpression) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsLabel x, JsContext ctx) {
+    return visit((JsStatement) x, ctx);
+  }
+
+  public boolean visit(JsLiteral x, JsContext ctx) {
+    return visit((JsExpression) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsNameOf x, JsContext ctx) {
+    return visit((JsExpression) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsNameRef x, JsContext ctx) {
+    return visit((JsExpression) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsNew x, JsContext ctx) {
+    return visit((JsExpression) x, ctx);
+  }
+
+  @SuppressWarnings("unused")
+  public boolean visit(JsNode x, JsContext ctx) {
+    return true;
+  }
+
+  @Override
+  public boolean visit(JsNullLiteral x, JsContext ctx) {
+    return visit((JsValueLiteral) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsNumberLiteral x, JsContext ctx) {
+    return visit((JsValueLiteral) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsObjectLiteral x, JsContext ctx) {
+    return visit((JsLiteral) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsParameter x, JsContext ctx) {
+    return visit((JsNode) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsPostfixOperation x, JsContext ctx) {
+    return visit((JsUnaryOperation) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsPrefixOperation x, JsContext ctx) {
+    return visit((JsUnaryOperation) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsProgram x, JsContext ctx) {
+    return visit((JsNode) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsProgramFragment x, JsContext ctx) {
+    return visit((JsNode) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsPropertyInitializer x, JsContext ctx) {
+    return visit((JsNode) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsRegExp x, JsContext ctx) {
+    return visit((JsValueLiteral) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsReturn x, JsContext ctx) {
+    return visit((JsStatement) x, ctx);
+  }
+
+  public boolean visit(JsStatement x, JsContext ctx) {
+    return visit((JsNode) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsStringLiteral x, JsContext ctx) {
+    return visit((JsValueLiteral) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsSwitch x, JsContext ctx) {
+    return visit((JsStatement) x, ctx);
+  }
+
+  public boolean visit(JsSwitchMember x, JsContext ctx) {
+    return visit((JsNode) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsThisRef x, JsContext ctx) {
+    return visit((JsValueLiteral) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsThrow x, JsContext ctx) {
+    return visit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsTry x, JsContext ctx) {
+    return visit((JsStatement) x, ctx);
+  }
+
+  public boolean visit(JsUnaryOperation x, JsContext ctx) {
+    return visit((JsExpression) x, ctx);
+  }
+
+  public boolean visit(JsValueLiteral x, JsContext ctx) {
+    return visit((JsLiteral) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsVar x, JsContext ctx) {
+    return visit((JsNode) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsVars x, JsContext ctx) {
+    return visit((JsStatement) x, ctx);
+  }
+
+  @Override
+  public boolean visit(JsWhile x, JsContext ctx) {
+    return visit((JsStatement) x, ctx);
+  }
+
+}
\ No newline at end of file
diff --git a/dev/core/test/com/google/gwt/dev/SoycTest.java b/dev/core/test/com/google/gwt/dev/SoycTest.java
index e469e3e..690af06 100644
--- a/dev/core/test/com/google/gwt/dev/SoycTest.java
+++ b/dev/core/test/com/google/gwt/dev/SoycTest.java
@@ -35,20 +35,25 @@
   private final CompilerOptionsImpl options = new CompilerOptionsImpl();
 
   public void testSoyc() throws UnableToCompleteException, IOException {
-    options.setSoycEnabled(true);
-    options.addModuleName("com.google.gwt.sample.hello.Hello");
-    options.setExtraDir(Utility.makeTemporaryDirectory(null, "helloextra"));
-    PrintWriterTreeLogger logger = new PrintWriterTreeLogger();
-    logger.setMaxDetail(TreeLogger.ERROR);
-    new Compiler(options).run(logger);
-
-    // make sure the files have been produced
-    assertTrue(new File(options.getExtraDir() + "/hello/soycReport/compile-report/index.html").exists());
-    assertTrue(new File(options.getExtraDir() + "/hello/soycReport/compile-report/SoycDashboard-1-index.html").exists());
-    assertTrue(new File(options.getExtraDir() + "/hello/soycReport/compile-report/total-1-overallBreakdown.html").exists());
-    assertTrue(new File(options.getExtraDir() + "/hello/soycReport/compile-report/soyc.css").exists());
-
-    assertFalse(new File(options.getExtraDir() + "/hello/soycReport/compile-report/index2.html").exists());
-    Util.recursiveDelete(options.getExtraDir(), false);
+    File work = Utility.makeTemporaryDirectory(null, "hellowork");
+    try {
+      options.setSoycEnabled(true);
+      options.addModuleName("com.google.gwt.sample.hello.Hello");
+      options.setWarDir(new File(work, "war"));
+      options.setExtraDir(new File(work, "extra"));
+      PrintWriterTreeLogger logger = new PrintWriterTreeLogger();
+      logger.setMaxDetail(TreeLogger.ERROR);
+      new Compiler(options).run(logger);
+  
+      // make sure the files have been produced
+      assertTrue(new File(options.getExtraDir() + "/hello/soycReport/compile-report/index.html").exists());
+      assertTrue(new File(options.getExtraDir() + "/hello/soycReport/compile-report/SoycDashboard-1-index.html").exists());
+      assertTrue(new File(options.getExtraDir() + "/hello/soycReport/compile-report/total-1-overallBreakdown.html").exists());
+      assertTrue(new File(options.getExtraDir() + "/hello/soycReport/compile-report/soyc.css").exists());
+  
+      assertFalse(new File(options.getExtraDir() + "/hello/soycReport/compile-report/index2.html").exists());
+    } finally {
+      Util.recursiveDelete(work, false);
+    }
   }
 }