JS: Move definition of getContainer() to a single rootdef

This commit is contained in:
Asger Feldthaus
2020-05-01 13:08:40 +01:00
parent 86c5b38d62
commit 5f710bc881
12 changed files with 61 additions and 72 deletions

View File

@@ -3,6 +3,7 @@
*/
import javascript
private import internal.StmtContainers
/**
* A program element corresponding to JavaScript code, such as an expression
@@ -20,7 +21,7 @@ import javascript
* abs(-42);
* ```
*/
class ASTNode extends @ast_node, Locatable {
class ASTNode extends @ast_node, NodeInStmtContainer {
override Location getLocation() { hasLocation(this, result) }
override File getFile() {

View File

@@ -4,6 +4,7 @@
*/
import javascript
private import internal.StmtContainers
/**
* Holds if `nd` starts a new basic block.
@@ -114,7 +115,7 @@ private predicate bbIPostDominates(BasicBlock dom, BasicBlock bb) =
*
* At the database level, a basic block is represented by its first control flow node.
*/
class BasicBlock extends @cfg_node, Locatable {
class BasicBlock extends @cfg_node, NodeInStmtContainer {
BasicBlock() { startsBB(this) }
/** Gets a basic block succeeding this one. */
@@ -271,11 +272,6 @@ class BasicBlock extends @cfg_node, Locatable {
exists(int n | defAt(n, v, d) | not exists(int m | m < n | defAt(m, v, _)))
}
/**
* Gets the function or script to which this basic block belongs.
*/
StmtContainer getContainer() { result = getFirstNode().getContainer() }
/**
* Gets the basic block that immediately dominates this basic block.
*/

View File

@@ -274,12 +274,13 @@
*/
import javascript
private import internal.StmtContainers
/**
* A node in the control flow graph, which is an expression, a statement,
* or a synthetic node.
*/
class ControlFlowNode extends @cfg_node, Locatable {
class ControlFlowNode extends @cfg_node, Locatable, NodeInStmtContainer {
/** Gets a node succeeding this node in the CFG. */
ControlFlowNode getASuccessor() { successor(this, result) }
@@ -324,17 +325,6 @@ class ControlFlowNode extends @cfg_node, Locatable {
// note the override in ControlFlowEntryNode below
}
/** Gets the function or toplevel whose CFG this node belongs to. */
cached
StmtContainer getContainer() {
result = this.(Expr).getContainer() or
result = this.(Stmt).getContainer() or
result = this.(Property).getContainer() or
result = this.(PropertyPattern).getContainer() or
result = this.(ClassDefinition).getContainer() or
result = this.(MemberDeclaration).getContainer()
}
/** Gets the basic block this node belongs to. */
BasicBlock getBasicBlock() { this = result.getANode() }
@@ -364,8 +354,6 @@ class SyntheticControlFlowNode extends @synthetic_cfg_node, ControlFlowNode {
/** A synthetic CFG node marking the entry point of a function or toplevel script. */
class ControlFlowEntryNode extends SyntheticControlFlowNode, @entry_node {
override StmtContainer getContainer() { entry_cfg_node(this, result) }
override predicate isUnreachable() { none() }
override string toString() { result = "entry node of " + getContainer().toString() }
@@ -373,8 +361,6 @@ class ControlFlowEntryNode extends SyntheticControlFlowNode, @entry_node {
/** A synthetic CFG node marking the exit of a function or toplevel script. */
class ControlFlowExitNode extends SyntheticControlFlowNode, @exit_node {
override StmtContainer getContainer() { exit_cfg_node(this, result) }
override predicate isAFinalNode() { any() }
override string toString() { result = "exit node of " + getContainer().toString() }
@@ -396,8 +382,6 @@ class GuardControlFlowNode extends SyntheticControlFlowNode, @guard_node {
this = bb.getANode() or
dominates(bb.getImmediateDominator())
}
override StmtContainer getContainer() { result = getTest().getContainer() }
}
/**

View File

@@ -42,9 +42,6 @@ class ClassOrInterface extends @classorinterface, TypeParameterized {
result = getIdentifier().getName() // Overridden in ClassExpr
}
/** Gets the nearest enclosing function or toplevel in which this class or interface occurs. */
StmtContainer getContainer() { result = this.(ExprOrStmt).getContainer() }
/** Gets a member declared in this class or interface. */
MemberDeclaration getAMember() { result.getDeclaringType() = this }
@@ -278,9 +275,6 @@ class ClassDefinition extends @classdefinition, ClassOrInterface, AST::ValueNode
* ```
*/
class ClassDeclStmt extends @classdeclstmt, ClassDefinition, Stmt {
/** Gets the nearest enclosing function or toplevel in which this class declaration occurs. */
override StmtContainer getContainer() { result = Stmt.super.getContainer() }
override ControlFlowNode getFirstControlFlowNode() {
if hasDeclareKeyword(this) then result = this else result = getIdentifier()
}
@@ -323,9 +317,6 @@ class ClassExpr extends @classexpr, ClassDefinition, Expr {
override predicate isImpure() { none() }
/** Gets the nearest enclosing function or toplevel in which this class expression occurs. */
override StmtContainer getContainer() { result = Expr.super.getContainer() }
override ControlFlowNode getFirstControlFlowNode() {
if exists(getIdentifier())
then result = getIdentifier()
@@ -545,9 +536,6 @@ class MemberDeclaration extends @property, Documentable {
/** Gets the index of this member within its enclosing type. */
int getMemberIndex() { properties(this, _, result, _, _) }
/** Gets the nearest enclosing function or toplevel in which this member occurs. */
StmtContainer getContainer() { result = getDeclaringType().getContainer() }
/** Holds if the name of this member is computed by an impure expression. */
predicate hasImpureNameExpr() { isComputed() and getNameExpr().isImpure() }

View File

@@ -21,12 +21,6 @@ class ExprOrType extends @exprortype, Documentable {
/** Gets the function in which this expression or type appears, if any. */
Function getEnclosingFunction() { result = getContainer() }
/**
* Gets the statement container (function or toplevel) in which
* this expression or type appears.
*/
StmtContainer getContainer() { exprContainers(this, result) }
/**
* Gets the JSDoc comment associated with this expression or type or its parent statement, if any.
*/
@@ -107,12 +101,6 @@ class ExprOrType extends @exprortype, Documentable {
* ```
*/
class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode {
/**
* Gets the statement container (function or toplevel) in which
* this expression appears.
*/
override StmtContainer getContainer() { exprContainers(this, result) }
/** Gets this expression, with any surrounding parentheses removed. */
override Expr stripParens() { result = this }
@@ -633,9 +621,6 @@ class Property extends @property, Documentable {
/** Gets the (0-based) index at which this property appears in its enclosing literal. */
int getIndex() { this = getObjectExpr().getProperty(result) }
/** Gets the function or toplevel in which this property occurs. */
StmtContainer getContainer() { result = getObjectExpr().getContainer() }
/**
* Holds if this property is impure, that is, the evaluation of its name or
* its initializer expression could have side effects.

View File

@@ -191,8 +191,6 @@ class JSDocTypeExpr extends @jsdoc_type_expr, JSDocTypeExprParent, TypeAnnotatio
)
}
override StmtContainer getContainer() { result = getEnclosingStmt().getContainer() }
override Function getEnclosingFunction() { result = getContainer() }
override TopLevel getTopLevel() { result = getEnclosingStmt().getTopLevel() }

View File

@@ -18,9 +18,6 @@ import javascript
* ```
*/
class Stmt extends @stmt, ExprOrStmt, Documentable {
/** Gets the statement container (toplevel, function or namespace) to which this statement belongs. */
override StmtContainer getContainer() { stmtContainers(this, result) }
/** Holds if this statement has an implicitly inserted semicolon. */
predicate hasSemicolonInserted() {
isSubjectToSemicolonInsertion() and

View File

@@ -3,11 +3,12 @@
*/
import javascript
private import internal.StmtContainers
/**
* A type annotation, either in the form of a TypeScript type or a JSDoc comment.
*/
class TypeAnnotation extends @type_annotation, Locatable {
class TypeAnnotation extends @type_annotation, NodeInStmtContainer {
/** Holds if this is the `any` type. */
predicate isAny() { none() }
@@ -89,11 +90,6 @@ class TypeAnnotation extends @type_annotation, Locatable {
/** Gets the function in which this type appears, if any. */
Function getEnclosingFunction() { none() }
/**
* Gets the statement container (function or toplevel) in which this type appears.
*/
StmtContainer getContainer() { none() }
/**
* Gets the top-level containing this type annotation.
*/

View File

@@ -276,8 +276,6 @@ class InterfaceDeclaration extends Stmt, InterfaceDefinition, @interfacedeclarat
)
}
override StmtContainer getContainer() { result = Stmt.super.getContainer() }
override string describe() { result = "interface " + getName() }
/**
@@ -299,8 +297,6 @@ class InterfaceDeclaration extends Stmt, InterfaceDefinition, @interfacedeclarat
class InterfaceTypeExpr extends TypeExpr, InterfaceDefinition, @interfacetypeexpr {
override Identifier getIdentifier() { none() }
override StmtContainer getContainer() { result = TypeExpr.super.getContainer() }
override string describe() { result = "anonymous interface" }
}
@@ -535,8 +531,6 @@ class TypeExpr extends ExprOrType, @typeexpr, TypeAnnotation {
override Function getEnclosingFunction() { result = ExprOrType.super.getEnclosingFunction() }
override StmtContainer getContainer() { result = ExprOrType.super.getContainer() }
override TopLevel getTopLevel() { result = ExprOrType.super.getTopLevel() }
override DataFlow::ClassNode getClass() { result.getAstNode() = getType().(ClassType).getClass() }

View File

@@ -600,9 +600,6 @@ class PropertyPattern extends @property, ASTNode {
/** Gets the object pattern this property pattern belongs to. */
ObjectPattern getObjectPattern() { properties(this, result, _, _, _) }
/** Gets the nearest enclosing function or toplevel in which this property pattern occurs. */
StmtContainer getContainer() { result = getObjectPattern().getContainer() }
/** Holds if this pattern is impure, that is, if its evaluation could have side effects. */
predicate isImpure() {
isComputed() and getNameExpr().isImpure()

View File

@@ -0,0 +1,52 @@
/**
* INTERNAL. DO NOT IMPORT DIRECTLY.
*
* Provides predicates and classes for relating nodes to their
* enclosing `StmtContainer`.
*/
private import javascript
cached
private StmtContainer getStmtContainer(@node_in_stmt_container node) {
exprContainers(node, result)
or
stmtContainers(node, result)
or
// Properties
exists(ASTNode parent |
properties(node, parent, _, _, _)
|
exprContainers(parent, result)
or
stmtContainers(parent, result)
)
or
// Synthetic CFG nodes
entry_cfg_node(node, result)
or
exit_cfg_node(node, result)
or
exists(Expr test |
guard_node(node, _, test) and
exprContainers(test, result)
)
or
// JSDoc type annotations
stmtContainers(node.(JSDocTypeExpr).getEnclosingStmt(), result)
}
/**
* A node that occurs inside a function or top-level or is itself a top-level.
*
* Specifically, this is the union type of `ControlFlowNode`, `TypeAnnotation`,
* and `TopLevel`.
*/
class NodeInStmtContainer extends Locatable, @node_in_stmt_container {
/**
* Gets the function or toplevel to which this node belongs.
*/
pragma[inline]
final StmtContainer getContainer() {
result = getStmtContainer(this)
}
}

View File

@@ -233,6 +233,7 @@ isDelegating (int yield: @yieldexpr ref);
@exprparent = @exprorstmt | @property | @functiontypeexpr;
@arraylike = @arrayexpr | @arraypattern;
@type_annotation = @typeexpr | @jsdoc_type_expr;
@node_in_stmt_container = @cfg_node | @type_annotation | @toplevel;
case @expr.kind of
0 = @label