Skip to content

Commit 107b091

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

File tree

19 files changed

+4915
-46
lines changed

19 files changed

+4915
-46
lines changed

javascript/downgrades/462ace12909fd8fe7abf468003dba4457c91ad76/old.dbscheme

Lines changed: 1219 additions & 0 deletions
Large diffs are not rendered by default.

javascript/downgrades/462ace12909fd8fe7abf468003dba4457c91ad76/semmlecode.javascript.dbscheme

Lines changed: 1217 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
description: Remove parenthesized expression from AST, add has_parentheses relation
2+
compatibility: full

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,9 +1473,11 @@ 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+
Label innerLabel = nd.getExpression().accept(this, c);
1479+
trapwriter.addTuple("has_parentheses", innerLabel);
1480+
return innerLabel;
14791481
}
14801482

14811483
@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: 8 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,9 @@ 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+
112113
/** Gets the constant integer value this expression evaluates to, if any. */
113114
int getIntValue() { none() }
114115

@@ -235,9 +236,6 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode {
235236
this = ctx.(ForOfStmt).getIterationDomain()
236237
or
237238
// recursive cases
238-
this = ctx.(ParExpr).getExpression() and
239-
ctx.(ParExpr).inNullSensitiveContext()
240-
or
241239
this = ctx.(SeqExpr).getLastOperand() and
242240
ctx.(SeqExpr).inNullSensitiveContext()
243241
or
@@ -351,6 +349,11 @@ class Literal extends @literal, Expr {
351349
/**
352350
* A parenthesized expression.
353351
*
352+
* Note: in new databases, parenthesized expressions are not represented as separate
353+
* AST nodes. Instead, the inner expression takes the place of the parenthesized
354+
* expression and `Expr.isParenthesized()` indicates whether it was wrapped in
355+
* parentheses. This class is retained for backwards compatibility with old databases.
356+
*
354357
* Example:
355358
*
356359
* ```

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.

0 commit comments

Comments
 (0)