mooz / js2-mode

Improved JavaScript editing mode for GNU Emacs
GNU General Public License v3.0
1.32k stars 186 forks source link

Possible bug with js2-node-abs-pos and `new` expressions #591

Closed DamienCassou closed 2 years ago

DamienCassou commented 2 years ago

I'm trying to get the node defining a variable's value from a variable reference. For example, given this code:

function f() {
    let foo = new Foo();

    return foo;
}

and the point on the "foo" of the return statement, I would like to get the node "new Foo()".

Here is the code (copied from js2r-inline-var of js2r-vars.el but without any code from this project):

(with-temp-buffer
  (insert "function f() {\n  let foo = new Foo();\n  return foo;\n}")
  (js2-mode)
  (js2-parse)
  (setf (point) (point-min))
  (search-forward "return fo")
  (let* ((var-ref-node (js2-node-at-point (point))) ;; "foo" reference
         (var-def-node (js2-symbol-ast-node   ;; "foo" definition
                        (js2-scope-get-symbol
                         (js2-get-defining-scope
                          (js2-node-get-enclosing-scope var-ref-node)
                          (js2-name-node-name var-ref-node))
                         (js2-name-node-name var-ref-node))))
         (var-creation-node (js2-node-parent var-def-node)) ;; let foo = new Foo()"
         (var-creation-value-node (js2-var-init-node-initializer var-creation-node))) ;; "new Foo()"
    (setf (point) (js2-node-abs-pos var-creation-value-node)))
  (message "Looking at new? %s" (looking-at "new")) ;; ⇒ nil (??)
  (message "Looking at Foo? %s" (looking-at "Foo")) ;; ⇒ t (??)
  nil)

At the end, point is on Foo instead of being on new.

In practice, this means that js2r-inline-var doesn't move the new keyword when inlining resulting in broken code:

function f() {
    return Foo();   // the `new` keyword is missing here!
}

Is there a problem with my code?

dgutov commented 2 years ago

Hi Damien,

That looks like a bug.

Does the following make things better?

diff --git a/js2-mode.el b/js2-mode.el
index 65241ad..458a8ec 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -10373,11 +10373,11 @@ Returns the list in reverse order.  Consumes the right-paren token."
         pn pos target args beg end init)
     (if (/= tt js2-NEW)
         (setq pn (js2-parse-primary-expr))
+      (setq pos (js2-current-token-beg)
+            beg pos)
       ;; parse a 'new' expression
       (js2-get-token)
-      (setq pos (js2-current-token-beg)
-            beg pos
-            target (js2-parse-member-expr)
+      (setq target (js2-parse-member-expr)
             end (js2-node-end target)
             pn (make-js2-new-node :pos pos
                                   :target target
DamienCassou commented 2 years ago

That fixes my problem, thank you very much!

dgutov commented 2 years ago

Thanks for testing. ;-)