Skip to content

Commit 5725814

Browse files
authored
Merge pull request github#3403 from asger-semmle/js/getcontainer
JS: Move getContainer to single rootdef (+fixes)
2 parents 3b3ca6d + b2da4fe commit 5725814

File tree

19 files changed

+2481
-100
lines changed

19 files changed

+2481
-100
lines changed

javascript/ql/src/semmle/javascript/AST.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*/
44

55
import javascript
6+
private import internal.StmtContainers
67

78
/**
89
* A program element corresponding to JavaScript code, such as an expression
@@ -20,7 +21,7 @@ import javascript
2021
* abs(-42);
2122
* ```
2223
*/
23-
class ASTNode extends @ast_node, Locatable {
24+
class ASTNode extends @ast_node, NodeInStmtContainer {
2425
override Location getLocation() { hasLocation(this, result) }
2526

2627
override File getFile() {

javascript/ql/src/semmle/javascript/BasicBlocks.qll

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
import javascript
7+
private import internal.StmtContainers
78

89
/**
910
* Holds if `nd` starts a new basic block.
@@ -114,7 +115,7 @@ private predicate bbIPostDominates(BasicBlock dom, BasicBlock bb) =
114115
*
115116
* At the database level, a basic block is represented by its first control flow node.
116117
*/
117-
class BasicBlock extends @cfg_node, Locatable {
118+
class BasicBlock extends @cfg_node, NodeInStmtContainer {
118119
BasicBlock() { startsBB(this) }
119120

120121
/** Gets a basic block succeeding this one. */
@@ -271,11 +272,6 @@ class BasicBlock extends @cfg_node, Locatable {
271272
exists(int n | defAt(n, v, d) | not exists(int m | m < n | defAt(m, v, _)))
272273
}
273274

274-
/**
275-
* Gets the function or script to which this basic block belongs.
276-
*/
277-
StmtContainer getContainer() { result = getFirstNode().getContainer() }
278-
279275
/**
280276
* Gets the basic block that immediately dominates this basic block.
281277
*/

javascript/ql/src/semmle/javascript/CFG.qll

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -274,12 +274,13 @@
274274
*/
275275

276276
import javascript
277+
private import internal.StmtContainers
277278

278279
/**
279280
* A node in the control flow graph, which is an expression, a statement,
280281
* or a synthetic node.
281282
*/
282-
class ControlFlowNode extends @cfg_node, Locatable {
283+
class ControlFlowNode extends @cfg_node, Locatable, NodeInStmtContainer {
283284
/** Gets a node succeeding this node in the CFG. */
284285
ControlFlowNode getASuccessor() { successor(this, result) }
285286

@@ -324,17 +325,6 @@ class ControlFlowNode extends @cfg_node, Locatable {
324325
// note the override in ControlFlowEntryNode below
325326
}
326327

327-
/** Gets the function or toplevel whose CFG this node belongs to. */
328-
cached
329-
StmtContainer getContainer() {
330-
result = this.(Expr).getContainer() or
331-
result = this.(Stmt).getContainer() or
332-
result = this.(Property).getContainer() or
333-
result = this.(PropertyPattern).getContainer() or
334-
result = this.(ClassDefinition).getContainer() or
335-
result = this.(MemberDeclaration).getContainer()
336-
}
337-
338328
/** Gets the basic block this node belongs to. */
339329
BasicBlock getBasicBlock() { this = result.getANode() }
340330

@@ -364,17 +354,13 @@ class SyntheticControlFlowNode extends @synthetic_cfg_node, ControlFlowNode {
364354

365355
/** A synthetic CFG node marking the entry point of a function or toplevel script. */
366356
class ControlFlowEntryNode extends SyntheticControlFlowNode, @entry_node {
367-
override StmtContainer getContainer() { entry_cfg_node(this, result) }
368-
369357
override predicate isUnreachable() { none() }
370358

371359
override string toString() { result = "entry node of " + getContainer().toString() }
372360
}
373361

374362
/** A synthetic CFG node marking the exit of a function or toplevel script. */
375363
class ControlFlowExitNode extends SyntheticControlFlowNode, @exit_node {
376-
override StmtContainer getContainer() { exit_cfg_node(this, result) }
377-
378364
override predicate isAFinalNode() { any() }
379365

380366
override string toString() { result = "exit node of " + getContainer().toString() }
@@ -396,8 +382,6 @@ class GuardControlFlowNode extends SyntheticControlFlowNode, @guard_node {
396382
this = bb.getANode() or
397383
dominates(bb.getImmediateDominator())
398384
}
399-
400-
override StmtContainer getContainer() { result = getTest().getContainer() }
401385
}
402386

403387
/**

javascript/ql/src/semmle/javascript/Classes.qll

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,6 @@ class ClassOrInterface extends @classorinterface, TypeParameterized {
4242
result = getIdentifier().getName() // Overridden in ClassExpr
4343
}
4444

45-
/** Gets the nearest enclosing function or toplevel in which this class or interface occurs. */
46-
StmtContainer getContainer() { result = this.(ExprOrStmt).getContainer() }
47-
4845
/** Gets a member declared in this class or interface. */
4946
MemberDeclaration getAMember() { result.getDeclaringType() = this }
5047

@@ -278,9 +275,6 @@ class ClassDefinition extends @classdefinition, ClassOrInterface, AST::ValueNode
278275
* ```
279276
*/
280277
class ClassDeclStmt extends @classdeclstmt, ClassDefinition, Stmt {
281-
/** Gets the nearest enclosing function or toplevel in which this class declaration occurs. */
282-
override StmtContainer getContainer() { result = Stmt.super.getContainer() }
283-
284278
override ControlFlowNode getFirstControlFlowNode() {
285279
if hasDeclareKeyword(this) then result = this else result = getIdentifier()
286280
}
@@ -323,9 +317,6 @@ class ClassExpr extends @classexpr, ClassDefinition, Expr {
323317

324318
override predicate isImpure() { none() }
325319

326-
/** Gets the nearest enclosing function or toplevel in which this class expression occurs. */
327-
override StmtContainer getContainer() { result = Expr.super.getContainer() }
328-
329320
override ControlFlowNode getFirstControlFlowNode() {
330321
if exists(getIdentifier())
331322
then result = getIdentifier()
@@ -545,9 +536,6 @@ class MemberDeclaration extends @property, Documentable {
545536
/** Gets the index of this member within its enclosing type. */
546537
int getMemberIndex() { properties(this, _, result, _, _) }
547538

548-
/** Gets the nearest enclosing function or toplevel in which this member occurs. */
549-
StmtContainer getContainer() { result = getDeclaringType().getContainer() }
550-
551539
/** Holds if the name of this member is computed by an impure expression. */
552540
predicate hasImpureNameExpr() { isComputed() and getNameExpr().isImpure() }
553541

javascript/ql/src/semmle/javascript/Closure.qll

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,25 @@ module Closure {
115115
override DefaultClosureModuleDeclaration range;
116116
}
117117

118+
private GlobalVariable googVariable() { variables(result, "goog", any(GlobalScope sc)) }
119+
120+
pragma[nomagic]
121+
private MethodCallExpr googModuleDeclExpr() {
122+
result.getReceiver() = googVariable().getAnAccess() and
123+
result.getMethodName() = ["module", "declareModuleId"]
124+
}
125+
126+
pragma[nomagic]
127+
private MethodCallExpr googModuleDeclExprInContainer(StmtContainer container) {
128+
result = googModuleDeclExpr() and
129+
container = result.getContainer()
130+
}
131+
118132
/**
119133
* A module using the Closure module system, declared using `goog.module()` or `goog.declareModuleId()`.
120134
*/
121135
class ClosureModule extends Module {
122-
ClosureModule() {
123-
// Use AST-based predicate to cut recursive dependencies.
124-
exists(MethodCallExpr call |
125-
getAStmt().(ExprStmt).getExpr() = call and
126-
call.getReceiver().(GlobalVarAccess).getName() = "goog" and
127-
(call.getMethodName() = "module" or call.getMethodName() = "declareModuleId")
128-
)
129-
}
136+
ClosureModule() { exists(googModuleDeclExprInContainer(this)) }
130137

131138
/**
132139
* Gets the call to `goog.module` or `goog.declareModuleId` in this module.

javascript/ql/src/semmle/javascript/Expr.qll

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,6 @@ class ExprOrType extends @exprortype, Documentable {
2121
/** Gets the function in which this expression or type appears, if any. */
2222
Function getEnclosingFunction() { result = getContainer() }
2323

24-
/**
25-
* Gets the statement container (function or toplevel) in which
26-
* this expression or type appears.
27-
*/
28-
StmtContainer getContainer() { exprContainers(this, result) }
29-
3024
/**
3125
* Gets the JSDoc comment associated with this expression or type or its parent statement, if any.
3226
*/
@@ -107,12 +101,6 @@ class ExprOrType extends @exprortype, Documentable {
107101
* ```
108102
*/
109103
class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode {
110-
/**
111-
* Gets the statement container (function or toplevel) in which
112-
* this expression appears.
113-
*/
114-
override StmtContainer getContainer() { exprContainers(this, result) }
115-
116104
/** Gets this expression, with any surrounding parentheses removed. */
117105
override Expr stripParens() { result = this }
118106

@@ -246,25 +234,32 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode {
246234
)
247235
}
248236

237+
pragma[inline]
238+
private Stmt getRawEnclosingStmt(Expr e) {
239+
// For performance reasons, we need the enclosing statement without overrides
240+
enclosingStmt(e, result)
241+
}
242+
249243
/**
250244
* Gets the data-flow node where exceptions thrown by this expression will
251245
* propagate if this expression causes an exception to be thrown.
252246
*/
247+
pragma[inline]
253248
DataFlow::Node getExceptionTarget() {
254-
if exists(this.getEnclosingStmt().getEnclosingTryCatchStmt())
255-
then
256-
result =
257-
DataFlow::parameterNode(this
258-
.getEnclosingStmt()
259-
.getEnclosingTryCatchStmt()
260-
.getACatchClause()
261-
.getAParameter())
262-
else
263-
result =
264-
any(DataFlow::FunctionNode f | f.getFunction() = this.getContainer()).getExceptionalReturn()
249+
result = getCatchParameterFromStmt(getRawEnclosingStmt(this))
250+
or
251+
not exists(getCatchParameterFromStmt(getRawEnclosingStmt(this))) and
252+
result =
253+
any(DataFlow::FunctionNode f | f.getFunction() = this.getContainer()).getExceptionalReturn()
265254
}
266255
}
267256

257+
cached
258+
private DataFlow::Node getCatchParameterFromStmt(Stmt stmt) {
259+
result =
260+
DataFlow::parameterNode(stmt.getEnclosingTryCatchStmt().getACatchClause().getAParameter())
261+
}
262+
268263
/**
269264
* An identifier.
270265
*
@@ -633,9 +628,6 @@ class Property extends @property, Documentable {
633628
/** Gets the (0-based) index at which this property appears in its enclosing literal. */
634629
int getIndex() { this = getObjectExpr().getProperty(result) }
635630

636-
/** Gets the function or toplevel in which this property occurs. */
637-
StmtContainer getContainer() { result = getObjectExpr().getContainer() }
638-
639631
/**
640632
* Holds if this property is impure, that is, the evaluation of its name or
641633
* its initializer expression could have side effects.

javascript/ql/src/semmle/javascript/JSDoc.qll

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,6 @@ class JSDocTypeExpr extends @jsdoc_type_expr, JSDocTypeExprParent, TypeAnnotatio
191191
)
192192
}
193193

194-
override StmtContainer getContainer() { result = getEnclosingStmt().getContainer() }
195-
196194
override Function getEnclosingFunction() { result = getContainer() }
197195

198196
override TopLevel getTopLevel() { result = getEnclosingStmt().getTopLevel() }

javascript/ql/src/semmle/javascript/Stmt.qll

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ import javascript
1818
* ```
1919
*/
2020
class Stmt extends @stmt, ExprOrStmt, Documentable {
21-
/** Gets the statement container (toplevel, function or namespace) to which this statement belongs. */
22-
override StmtContainer getContainer() { stmtContainers(this, result) }
23-
2421
/** Holds if this statement has an implicitly inserted semicolon. */
2522
predicate hasSemicolonInserted() {
2623
isSubjectToSemicolonInsertion() and

javascript/ql/src/semmle/javascript/TypeAnnotations.qll

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
*/
44

55
import javascript
6+
private import internal.StmtContainers
67

78
/**
89
* A type annotation, either in the form of a TypeScript type or a JSDoc comment.
910
*/
10-
class TypeAnnotation extends @type_annotation, Locatable {
11+
class TypeAnnotation extends @type_annotation, NodeInStmtContainer {
1112
/** Holds if this is the `any` type. */
1213
predicate isAny() { none() }
1314

@@ -89,11 +90,6 @@ class TypeAnnotation extends @type_annotation, Locatable {
8990
/** Gets the function in which this type appears, if any. */
9091
Function getEnclosingFunction() { none() }
9192

92-
/**
93-
* Gets the statement container (function or toplevel) in which this type appears.
94-
*/
95-
StmtContainer getContainer() { none() }
96-
9793
/**
9894
* Gets the top-level containing this type annotation.
9995
*/

javascript/ql/src/semmle/javascript/TypeScript.qll

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,6 @@ class InterfaceDeclaration extends Stmt, InterfaceDefinition, @interfacedeclarat
276276
)
277277
}
278278

279-
override StmtContainer getContainer() { result = Stmt.super.getContainer() }
280-
281279
override string describe() { result = "interface " + getName() }
282280

283281
/**
@@ -299,8 +297,6 @@ class InterfaceDeclaration extends Stmt, InterfaceDefinition, @interfacedeclarat
299297
class InterfaceTypeExpr extends TypeExpr, InterfaceDefinition, @interfacetypeexpr {
300298
override Identifier getIdentifier() { none() }
301299

302-
override StmtContainer getContainer() { result = TypeExpr.super.getContainer() }
303-
304300
override string describe() { result = "anonymous interface" }
305301
}
306302

@@ -535,8 +531,6 @@ class TypeExpr extends ExprOrType, @typeexpr, TypeAnnotation {
535531

536532
override Function getEnclosingFunction() { result = ExprOrType.super.getEnclosingFunction() }
537533

538-
override StmtContainer getContainer() { result = ExprOrType.super.getContainer() }
539-
540534
override TopLevel getTopLevel() { result = ExprOrType.super.getTopLevel() }
541535

542536
override DataFlow::ClassNode getClass() { result.getAstNode() = getType().(ClassType).getClass() }

0 commit comments

Comments
 (0)