JS: Canonicalize ThisNode

This commit is contained in:
Asger F
2018-10-03 13:30:59 +01:00
parent 3bc5e3bfdf
commit 030bae9454
10 changed files with 78 additions and 7 deletions

View File

@@ -303,6 +303,16 @@ class ThisExpr extends @thisexpr, Expr {
Function getBinder() {
result = getEnclosingFunction().getThisBinder()
}
/**
* Gets the function or top-level whose `this` binding this expression refers to,
* which is the nearest enclosing non-arrow function or top-level.
*/
StmtContainer getBindingContainer() {
result = getContainer().(Function).getThisBindingContainer()
or
result = getContainer().(TopLevel)
}
}
/** An array literal. */

View File

@@ -206,6 +206,17 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine
result = this
}
/**
* Gets the function or top-level whose `this` binding a `this` expression in this function refers to,
* which is the nearest enclosing non-arrow function or top-level.
*/
StmtContainer getThisBindingContainer() {
result = getThisBinder()
or
not exists(getThisBinder()) and
result = getTopLevel()
}
/**
* Holds if this function has a mapped `arguments` variable whose indices are aliased
* with the function's parameters.

View File

@@ -32,6 +32,7 @@ module DataFlow {
or TReflectiveCallNode(MethodCallExpr ce, string kind) {
ce.getMethodName() = kind and (kind = "call" or kind = "apply")
}
or TThisNode(StmtContainer f) { f.(Function).getThisBinder() = f or f instanceof TopLevel }
/**
* A node in the data flow graph.
@@ -867,6 +868,13 @@ module DataFlow {
nd = TDestructuringPatternNode(p)
}
/**
* INTERNAL: Use `thisNode(StmtContainer container)` instead.
*/
predicate thisNode(DataFlow::Node node, StmtContainer container) {
node = TThisNode(container)
}
/**
* A classification of flows that are not modeled, or only modeled incompletely, by
* `DataFlowNode`:
@@ -970,6 +978,11 @@ module DataFlow {
pred = valueNode(defSourceNode(def)) and
succ = TDestructuringPatternNode(def.getTarget())
)
or
// flow from 'this' parameter into 'this' expressions
exists (ThisExpr thiz |
pred = TThisNode(thiz.getBindingContainer()) and
succ = valueNode(thiz))
}
/**

View File

@@ -198,16 +198,36 @@ class NewNode extends InvokeNode {
override DataFlow::Impl::NewNodeDef impl;
}
/** A data flow node corresponding to a `this` expression. */
class ThisNode extends DataFlow::ValueNode, DataFlow::DefaultSourceNode {
override ThisExpr astNode;
/** A data flow node corresponding to the `this` parameter in a function or `this` at the top-level. */
class ThisNode extends DataFlow::Node, DataFlow::DefaultSourceNode {
ThisNode() {
DataFlow::thisNode(this, _)
}
/**
* Gets the function whose `this` binding this expression refers to,
* which is the nearest enclosing non-arrow function.
*/
FunctionNode getBinder() {
result = DataFlow::valueNode(astNode.getBinder())
exists (Function binder |
DataFlow::thisNode(this, binder) and
result = DataFlow::valueNode(binder))
}
/**
* Gets the function or top-level whose `this` binding this expression refers to,
* which is the nearest enclosing non-arrow function or top-level.
*/
StmtContainer getBindingContainer() {
DataFlow::thisNode(this, result)
}
override string toString() { result = "this" }
override predicate hasLocationInfo(string filepath, int startline, int startcolumn,
int endline, int endcolumn) {
// Use the function entry as the location
getBindingContainer().getEntry().getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}

View File

@@ -185,7 +185,6 @@ class DefaultSourceNode extends SourceNode {
astNode instanceof ObjectExpr or
astNode instanceof ArrayExpr or
astNode instanceof JSXNode or
astNode instanceof ThisExpr or
astNode instanceof GlobalVarAccess or
astNode instanceof ExternalModuleReference
)
@@ -198,5 +197,7 @@ class DefaultSourceNode extends SourceNode {
DataFlow::parameterNode(this, _)
or
this instanceof DataFlow::Impl::InvokeNodeDef
or
DataFlow::thisNode(this, _)
}
}

View File

@@ -52,10 +52,10 @@ abstract class ReactComponent extends ASTNode {
}
/**
* Gets a `this` access in an instance method of this component.
* Gets the `this` node in an instance method of this component.
*/
DataFlow::SourceNode getAThisAccess() {
result.asExpr().(ThisExpr).getBinder() = getInstanceMethod(_)
result.(DataFlow::ThisNode).getBinder().getFunction() = getInstanceMethod(_)
}
/**