Skip to content

Commit da554ed

Browse files
committed
JS: Remove parenthesized expressions from AST
1 parent 8bbb0ec commit da554ed

File tree

13 files changed

+57
-55
lines changed

13 files changed

+57
-55
lines changed

javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,9 +1473,18 @@ public Label visit(SequenceExpression nd, Context c) {
14731473

14741474
@Override
14751475
public Label visit(ParenthesizedExpression nd, Context c) {
1476-
Label key = super.visit(nd, c);
1477-
visit(nd.getExpression(), key, 0, IdContext.VAR_BIND);
1478-
return key;
1476+
// Bypass the parenthesized expression node: visit the inner expression
1477+
// with the parent's context so it takes the place of the ParExpr in the tree.
1478+
// Count nested parentheses so that ((x)) results in depth 2.
1479+
int depth = 1;
1480+
Expression inner = nd.getExpression();
1481+
while (inner instanceof ParenthesizedExpression) {
1482+
depth++;
1483+
inner = ((ParenthesizedExpression) inner).getExpression();
1484+
}
1485+
Label innerLabel = inner.accept(this, c);
1486+
trapwriter.addTuple("has_parentheses", innerLabel, depth);
1487+
return innerLabel;
14791488
}
14801489

14811490
@Override

javascript/extractor/src/com/semmle/js/extractor/CFGExtractor.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,11 @@ public Node visit(XMLDotDotExpression nd, Void c) {
537537
return nd.getLeft().accept(this, c);
538538
}
539539

540+
@Override
541+
public Node visit(ParenthesizedExpression nd, Void c) {
542+
return nd.getExpression().accept(this, c);
543+
}
544+
540545
public static Node of(Node nd) {
541546
return nd.accept(new First(), null);
542547
}
@@ -1299,7 +1304,7 @@ public Void visit(ExpressionStatement nd, SuccessorInfo i) {
12991304

13001305
@Override
13011306
public Void visit(ParenthesizedExpression nd, SuccessorInfo i) {
1302-
writeSuccessor(nd, First.of(nd.getExpression()));
1307+
// Bypass parenthesized expression - it has no DB entry, so just delegate to the inner expression
13031308
return nd.getExpression().accept(this, i);
13041309
}
13051310

javascript/ql/lib/Expressions/ExprHasNoEffect.qll

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ predicate inVoidContext(Expr e) {
2424
)
2525
)
2626
or
27-
// propagate void context through parenthesized expressions
28-
inVoidContext(e.getParent().(ParExpr))
29-
or
3027
exists(SeqExpr seq, int i, int n |
3128
e = seq.getOperand(i) and
3229
n = seq.getNumOperands()
@@ -146,8 +143,6 @@ predicate isCompoundExpression(Expr e) {
146143
e instanceof LogicalBinaryExpr
147144
or
148145
e instanceof SeqExpr
149-
or
150-
e instanceof ParExpr
151146
}
152147

153148
/**
@@ -180,8 +175,8 @@ predicate hasNoEffect(Expr e) {
180175
not exists(fe.getName())
181176
) and
182177
// exclude block-level flow type annotations. For example: `(name: empty)`.
183-
not exists(ParExpr parent |
184-
e.getParent() = parent and
178+
not (
179+
e.isParenthesized() and
185180
e.getLastToken().getNextToken().getValue() = ":"
186181
) and
187182
// exclude expressions that are part of a conditional expression

javascript/ql/lib/semmle/javascript/Expr.qll

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ class ExprOrType extends @expr_or_type, Documentable {
4545
exists(DotExpr dot | this = dot.getProperty() | result = dot.getDocumentation())
4646
or
4747
exists(AssignExpr e | this = e.getRhs() | result = e.getDocumentation())
48-
or
49-
exists(ParExpr p | this = p.getExpression() | result = p.getDocumentation())
5048
)
5149
}
5250

@@ -109,6 +107,12 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode {
109107
/** Gets this expression, with any surrounding parentheses removed. */
110108
override Expr stripParens() { result = this }
111109

110+
/** Holds if this expression is wrapped in parentheses. */
111+
predicate isParenthesized() { has_parentheses(this, _) }
112+
113+
/** Gets the number of enclosing parentheses around this expression. */
114+
int getParenthesisDepth() { has_parentheses(this, result) }
115+
112116
/** Gets the constant integer value this expression evaluates to, if any. */
113117
int getIntValue() { none() }
114118

@@ -235,9 +239,6 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode {
235239
this = ctx.(ForOfStmt).getIterationDomain()
236240
or
237241
// recursive cases
238-
this = ctx.(ParExpr).getExpression() and
239-
ctx.(ParExpr).inNullSensitiveContext()
240-
or
241242
this = ctx.(SeqExpr).getLastOperand() and
242243
ctx.(SeqExpr).inNullSensitiveContext()
243244
or
@@ -351,6 +352,11 @@ class Literal extends @literal, Expr {
351352
/**
352353
* A parenthesized expression.
353354
*
355+
* Note: in new databases, parenthesized expressions are not represented as separate
356+
* AST nodes. Instead, the inner expression takes the place of the parenthesized
357+
* expression and `Expr.isParenthesized()` indicates whether it was wrapped in
358+
* parentheses. This class is retained for backwards compatibility with old databases.
359+
*
354360
* Example:
355361
*
356362
* ```

javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,8 +1641,6 @@ module DataFlow {
16411641
exists(Expr predExpr, Expr succExpr |
16421642
pred = TValueNode(predExpr) and succ = TValueNode(succExpr)
16431643
|
1644-
predExpr = succExpr.(ParExpr).getExpression()
1645-
or
16461644
predExpr = succExpr.(SeqExpr).getLastOperand()
16471645
or
16481646
predExpr = succExpr.(AssignExpr).getRhs()

javascript/ql/lib/semmle/javascript/dataflow/Refinements.qll

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -154,20 +154,6 @@ private class VariableRefinement extends RefinementCandidate, VarUse {
154154
}
155155
}
156156

157-
/** A parenthesized refinement expression. */
158-
private class ParRefinement extends RefinementCandidate, ParExpr {
159-
ParRefinement() { this.getExpression() instanceof RefinementCandidate }
160-
161-
override SsaSourceVariable getARefinedVar() {
162-
result = this.getExpression().(RefinementCandidate).getARefinedVar()
163-
}
164-
165-
overlay[global]
166-
override RefinementValue eval(RefinementContext ctxt) {
167-
result = this.getExpression().(RefinementCandidate).eval(ctxt)
168-
}
169-
}
170-
171157
/** A `typeof` refinement expression. */
172158
private class TypeofRefinement extends RefinementCandidate, TypeofExpr {
173159
TypeofRefinement() { this.getOperand() instanceof RefinementCandidate }

javascript/ql/lib/semmle/javascript/internal/NameResolution.qll

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,6 @@ module NameResolution {
147147
node2 = type
148148
)
149149
or
150-
exists(ParenthesisExpr expr |
151-
node1 = expr.getExpression() and
152-
node2 = expr
153-
)
154-
or
155150
exists(NonNullAssertion assertion |
156151
// For the time being we don't use this for nullness analysis, so just
157152
// propagate through these assertions.

javascript/ql/lib/semmlecode.javascript.dbscheme

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,9 @@ array_size (unique int ae: @arraylike ref,
202202

203203
is_delegating (int yield: @yield_expr ref);
204204

205+
has_parentheses (unique int expr: @expr ref,
206+
int depth: int ref);
207+
205208
@expr_or_stmt = @expr | @stmt;
206209
@expr_or_type = @expr | @typeexpr;
207210
@expr_parent = @expr_or_stmt | @property | @function_typeexpr;

javascript/ql/lib/semmlecode.javascript.dbscheme.stats

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7969,6 +7969,21 @@
79697969
<dependencies/>
79707970
</relation>
79717971
<relation>
7972+
<name>has_parentheses</name>
7973+
<cardinality>1</cardinality>
7974+
<columnsizes>
7975+
<e>
7976+
<k>expr</k>
7977+
<v>1</v>
7978+
</e>
7979+
<e>
7980+
<k>depth</k>
7981+
<v>1</v>
7982+
</e>
7983+
</columnsizes>
7984+
<dependencies/>
7985+
</relation>
7986+
<relation>
79727987
<name>expr_contains_template_tag_location</name>
79737988
<cardinality>31</cardinality>
79747989
<columnsizes>

javascript/ql/src/Expressions/CompareIdenticalValues.ql

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,13 @@
1717
import Clones
1818

1919
/**
20-
* Holds if `e` is a reference to variable `v`, possibly with parentheses or
20+
* Holds if `e` is a reference to variable `v`, possibly with
2121
* numeric conversions (that is, the unary operators `+` or `-` or a call to `Number`)
2222
* applied.
2323
*/
2424
predicate accessWithConversions(Expr e, Variable v) {
2525
e = v.getAnAccess()
2626
or
27-
accessWithConversions(e.(ParExpr).getExpression(), v)
28-
or
2927
exists(UnaryExpr ue | ue instanceof NegExpr or ue instanceof PlusExpr |
3028
ue = e and accessWithConversions(ue.getOperand(), v)
3129
)

0 commit comments

Comments
 (0)