Skip to content

Commit 242e87a

Browse files
authored
fix(ast): invalid idx1 for new expression (#473)
Fix invalid Idx1() return for NewExpression when there are no parenthesis. Fixes #261
1 parent 7de4257 commit 242e87a

File tree

2 files changed

+73
-24
lines changed

2 files changed

+73
-24
lines changed

ast/node.go

+13-8
Original file line numberDiff line numberDiff line change
@@ -464,14 +464,19 @@ func (self *DotExpression) Idx1() file.Idx { return self.Identifier.Idx1
464464
func (self *EmptyExpression) Idx1() file.Idx { return self.End }
465465
func (self *FunctionLiteral) Idx1() file.Idx { return self.Body.Idx1() }
466466
func (self *Identifier) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Name)) }
467-
func (self *NewExpression) Idx1() file.Idx { return self.RightParenthesis + 1 }
468-
func (self *NullLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + 4) } // "null"
469-
func (self *NumberLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) }
470-
func (self *ObjectLiteral) Idx1() file.Idx { return self.RightBrace }
471-
func (self *RegExpLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) }
472-
func (self *SequenceExpression) Idx1() file.Idx { return self.Sequence[0].Idx1() }
473-
func (self *StringLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) }
474-
func (self *ThisExpression) Idx1() file.Idx { return self.Idx + 4 }
467+
func (self *NewExpression) Idx1() file.Idx {
468+
if self.RightParenthesis > 0 {
469+
return self.RightParenthesis + 1
470+
}
471+
return self.Callee.Idx1()
472+
}
473+
func (self *NullLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + 4) } // "null"
474+
func (self *NumberLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) }
475+
func (self *ObjectLiteral) Idx1() file.Idx { return self.RightBrace }
476+
func (self *RegExpLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) }
477+
func (self *SequenceExpression) Idx1() file.Idx { return self.Sequence[0].Idx1() }
478+
func (self *StringLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) }
479+
func (self *ThisExpression) Idx1() file.Idx { return self.Idx + 4 }
475480
func (self *UnaryExpression) Idx1() file.Idx {
476481
if self.Postfix {
477482
return self.Operand.Idx1() + 2 // ++ --

ast/walk_test.go

+60-16
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ import (
1010
)
1111

1212
type walker struct {
13-
stack []ast.Node
14-
source string
15-
shift file.Idx
16-
seen map[ast.Node]struct{}
17-
duplicate int
13+
stack []ast.Node
14+
source string
15+
shift file.Idx
16+
seen map[ast.Node]struct{}
17+
duplicate int
18+
newExpressionIdx1 file.Idx
1819
}
1920

2021
// push and pop below are to prove the symmetry of Enter/Exit calls
@@ -48,17 +49,23 @@ func (w *walker) Enter(n ast.Node) ast.Visitor {
4849

4950
w.seen[n] = struct{}{}
5051

51-
if id, ok := n.(*ast.Identifier); ok && id != nil {
52-
idx := n.Idx0() + w.shift - 1
53-
s := w.source[:idx] + "IDENT_" + w.source[idx:]
54-
w.source = s
55-
w.shift += 6
56-
}
57-
if v, ok := n.(*ast.VariableExpression); ok && v != nil {
58-
idx := n.Idx0() + w.shift - 1
59-
s := w.source[:idx] + "VAR_" + w.source[idx:]
60-
w.source = s
61-
w.shift += 4
52+
switch t := n.(type) {
53+
case *ast.Identifier:
54+
if t != nil {
55+
idx := n.Idx0() + w.shift - 1
56+
s := w.source[:idx] + "IDENT_" + w.source[idx:]
57+
w.source = s
58+
w.shift += 6
59+
}
60+
case *ast.VariableExpression:
61+
if t != nil {
62+
idx := n.Idx0() + w.shift - 1
63+
s := w.source[:idx] + "VAR_" + w.source[idx:]
64+
w.source = s
65+
w.shift += 4
66+
}
67+
case *ast.NewExpression:
68+
w.newExpressionIdx1 = n.Idx1()
6269
}
6370

6471
return w
@@ -93,3 +100,40 @@ func TestVisitorRewrite(t *testing.T) {
93100
require.Len(t, w.stack, 0)
94101
require.Equal(t, w.duplicate, 0)
95102
}
103+
104+
func Test_issue261(t *testing.T) {
105+
tests := map[string]struct {
106+
code string
107+
want file.Idx
108+
}{
109+
"no-parenthesis": {
110+
code: `var i = new Image;`,
111+
want: 18,
112+
},
113+
"no-args": {
114+
code: `var i = new Image();`,
115+
want: 20,
116+
},
117+
"two-args": {
118+
code: `var i = new Image(1, 2);`,
119+
want: 24,
120+
},
121+
}
122+
123+
for name, tt := range tests {
124+
t.Run(name, func(t *testing.T) {
125+
prog, err := parser.ParseFile(nil, "", tt.code, 0)
126+
require.NoError(t, err)
127+
128+
w := &walker{
129+
source: tt.code,
130+
seen: make(map[ast.Node]struct{}),
131+
}
132+
ast.Walk(w, prog)
133+
134+
require.Equal(t, tt.want, w.newExpressionIdx1)
135+
require.Len(t, w.stack, 0)
136+
require.Equal(t, w.duplicate, 0)
137+
})
138+
}
139+
}

0 commit comments

Comments
 (0)