Re-apply r5790 to improve accuracy of JsParser's SourceInfo objects.


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5802 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/js/JsParser.java b/dev/core/src/com/google/gwt/dev/js/JsParser.java
index 4f6e463..d8b9d1b 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsParser.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsParser.java
@@ -29,6 +29,7 @@
 import com.google.gwt.dev.js.ast.JsContinue;
 import com.google.gwt.dev.js.ast.JsDefault;
 import com.google.gwt.dev.js.ast.JsDoWhile;
+import com.google.gwt.dev.js.ast.JsExprStmt;
 import com.google.gwt.dev.js.ast.JsExpression;
 import com.google.gwt.dev.js.ast.JsFor;
 import com.google.gwt.dev.js.ast.JsForIn;
@@ -150,8 +151,12 @@
 
   private SourceInfo makeSourceInfo(Node node) {
     SourceInfo parent = sourceInfoStack.peek();
-    SourceInfo toReturn = program.createSourceInfo(node.getLineno(),
-        parent.getFileName());
+    int lineno = node.getLineno();
+    if (lineno == -1) {
+      // Rhino only reports line numbers for statement nodes, not expressions
+      return parent;
+    }
+    SourceInfo toReturn = program.createSourceInfo(lineno, parent.getFileName());
     toReturn.copyMissingCorrelationsFrom(parent);
     return toReturn;
   }
@@ -173,7 +178,7 @@
         return null;
 
       case TokenStream.EXPRSTMT:
-        return mapExpression(node.getFirstChild()).makeStmt();
+        return mapExprStmt(node);
 
       case TokenStream.REGEXP:
         return mapRegExp(node);
@@ -418,8 +423,11 @@
   }
 
   private JsBlock mapBlock(Node nodeStmts) throws JsParserException {
-    JsBlock block = new JsBlock(makeSourceInfo(nodeStmts));
+    SourceInfo info = makeSourceInfo(nodeStmts);
+    JsBlock block = new JsBlock(info);
+    pushSourceInfo(info);
     mapStatements(block.getStatements(), nodeStmts);
+    popSourceInfo();
     return block;
   }
 
@@ -515,6 +523,9 @@
       fromTestExpr = ifNode.getFirstChild().getNext();
     }
 
+    SourceInfo info = makeSourceInfo(ifNode);
+    pushSourceInfo(info);
+
     // Map the test expression.
     //
     JsExpression toTestExpr = mapExpression(fromTestExpr);
@@ -523,12 +534,14 @@
     //
     JsStatement toBody = mapStatement(fromBody);
 
+    popSourceInfo();
+
     // Create and attach the "while" or "do" statement we're mapping to.
     //
     if (isWhile) {
-      return new JsWhile(makeSourceInfo(ifNode), toTestExpr, toBody);
+      return new JsWhile(info, toTestExpr, toBody);
     } else {
-      return new JsDoWhile(makeSourceInfo(ifNode), toTestExpr, toBody);
+      return new JsDoWhile(info, toTestExpr, toBody);
     }
   }
 
@@ -575,6 +588,13 @@
     }
   }
 
+  private JsExprStmt mapExprStmt(Node node) throws JsParserException {
+    pushSourceInfo(makeSourceInfo(node));
+    JsExpression expr = mapExpression(node.getFirstChild());
+    popSourceInfo();
+    return expr.makeStmt();
+  }
+
   private JsStatement mapForStatement(Node forNode) throws JsParserException {
     Node fromInit = forNode.getFirstChild();
     Node fromTest = fromInit.getNext();
@@ -935,13 +955,16 @@
   }
 
   private JsReturn mapReturn(Node returnNode) throws JsParserException {
-    JsReturn toReturn = new JsReturn(makeSourceInfo(returnNode));
+    SourceInfo info = makeSourceInfo(returnNode);
+    JsReturn toReturn = new JsReturn(info);
+    pushSourceInfo(info);
     Node from = returnNode.getFirstChild();
     if (from != null) {
       JsExpression to = mapExpression(from);
       toReturn.setExpr(to);
     }
 
+    popSourceInfo();
     return toReturn;
   }
 
@@ -1032,7 +1055,9 @@
   }
 
   private JsSwitch mapSwitchStatement(Node switchNode) throws JsParserException {
-    JsSwitch toSwitch = new JsSwitch(makeSourceInfo(switchNode));
+    SourceInfo info = makeSourceInfo(switchNode);
+    JsSwitch toSwitch = new JsSwitch(info);
+    pushSourceInfo(info);
 
     // The switch expression.
     //
@@ -1078,15 +1103,20 @@
       fromMember = fromMember.getNext();
     }
 
+    popSourceInfo();
     return toSwitch;
   }
 
   private JsThrow mapThrowStatement(Node throwNode) throws JsParserException {
+    SourceInfo info = makeSourceInfo(throwNode);
+    pushSourceInfo(info);
+
     // Create, map, and attach.
     //
     Node fromExpr = throwNode.getFirstChild();
-    JsThrow toThrow = new JsThrow(makeSourceInfo(throwNode),
-        mapExpression(fromExpr));
+    JsThrow toThrow = new JsThrow(info, mapExpression(fromExpr));
+
+    popSourceInfo();
     return toThrow;
   }
 
@@ -1180,7 +1210,9 @@
   }
 
   private JsVars mapVar(Node varNode) throws JsParserException {
-    JsVars toVars = new JsVars(makeSourceInfo(varNode));
+    SourceInfo info = makeSourceInfo(varNode);
+    pushSourceInfo(info);
+    JsVars toVars = new JsVars(info);
     Node fromVar = varNode.getFirstChild();
     while (fromVar != null) {
       // Use a conservative name allocation strategy that allocates all names
@@ -1201,6 +1233,7 @@
       fromVar = fromVar.getNext();
     }
 
+    popSourceInfo();
     return toVars;
   }
 
@@ -1220,8 +1253,24 @@
     sourceInfoStack.pop();
   }
 
+  private void popSourceInfo() {
+    sourceInfoStack.pop();
+  }
+
   private void pushScope(JsScope scope, SourceInfo sourceInfo) {
     scopeStack.push(scope);
     sourceInfoStack.push(sourceInfo);
   }
+
+  /**
+   * This should be called when processing any Rhino statement Node that has
+   * line number data so that enclosed expressions will have a useful source
+   * location.
+   * 
+   * @see Node#hasLineno
+   */
+  private void pushSourceInfo(SourceInfo sourceInfo) {
+    assert sourceInfo.getStartLine() >= 0 : "Bad SourceInfo line number";
+    sourceInfoStack.push(sourceInfo);
+  }
 }