Merge pull request #607 from esben-semmle/js/more-react-methods

JS: model additional React component methods
This commit is contained in:
Max Schaefer
2018-12-05 08:00:16 +00:00
committed by GitHub
15 changed files with 124 additions and 7 deletions

View File

@@ -34,6 +34,11 @@ abstract class ReactComponent extends ASTNode {
*/
abstract Function getInstanceMethod(string name);
/**
* Gets a static method of this component with the given name.
*/
abstract Function getStaticMethod(string name);
/**
* Gets the abstract value that represents this component.
*/
@@ -175,6 +180,11 @@ abstract class ReactComponent extends ASTNode {
// setState with object: `this.setState({foo: 42})`
result = arg0
)
or
result.flowsToExpr(getStaticMethod("getDerivedStateFromProps").getAReturnedExpr())
or
// shouldComponentUpdate: (nextProps, nextState)
result = DataFlow::parameterNode(getInstanceMethod("shouldComponentUpdate").getParameter(1))
}
/**
@@ -190,9 +200,14 @@ abstract class ReactComponent extends ASTNode {
callback = getAMethodCall("setState").getCallback(0) and
stateParameterIndex = 0
or
// componentDidUpdate: (prevProps, prevState)
callback = getInstanceMethod("componentDidUpdate").flow() and
stateParameterIndex = 1
stateParameterIndex = 1 and (
// componentDidUpdate: (prevProps, prevState)
callback = getInstanceMethod("componentDidUpdate").flow() or
// getDerivedStateFromProps: (props, state)
callback = getStaticMethod("getDerivedStateFromProps").flow() or
// getSnapshotBeforeUpdate: (prevProps, prevState)
callback = getInstanceMethod("getSnapshotBeforeUpdate").flow()
)
)
}
@@ -205,6 +220,9 @@ abstract class ReactComponent extends ASTNode {
result.flowsTo(getComponentCreatorSource().getAnInvocation().getArgument(0))
or
result = getADefaultPropsSource()
or
// shouldComponentUpdate: (nextProps, nextState)
result = DataFlow::parameterNode(getInstanceMethod("shouldComponentUpdate").getParameter(0))
}
/**
@@ -234,9 +252,14 @@ abstract class ReactComponent extends ASTNode {
callback = getAMethodCall("setState").getCallback(0) and
propsParameterIndex = 1
or
// componentDidUpdate: (prevProps, prevState)
callback = getInstanceMethod("componentDidUpdate").flow() and
propsParameterIndex = 0
propsParameterIndex = 0 and (
// componentDidUpdate: (prevProps, prevState)
callback = getInstanceMethod("componentDidUpdate").flow() or
// getDerivedStateFromProps: (props, state)
callback = getStaticMethod("getDerivedStateFromProps").flow() or
// getSnapshotBeforeUpdate: (prevProps, prevState)
callback = getInstanceMethod("getSnapshotBeforeUpdate").flow()
)
)
}
@@ -272,6 +295,10 @@ class FunctionalComponent extends ReactComponent, Function {
name = "render" and result = this
}
override Function getStaticMethod(string name) {
none()
}
override DataFlow::SourceNode getADirectPropsAccess() {
result = DataFlow::parameterNode(getParameter(0))
}
@@ -302,6 +329,14 @@ private abstract class SharedReactPreactClassComponent extends ReactComponent, C
result = ClassDefinition.super.getInstanceMethod(name)
}
override Function getStaticMethod(string name) {
exists(MethodDeclaration decl |
decl = getMethod(name) and
decl.isStatic() and
result = decl.getBody()
)
}
override DataFlow::SourceNode getADirectPropsAccess() {
result.(DataFlow::PropRef).accesses(ref(), "props") or
result = DataFlow::parameterNode(getConstructor().getBody().getParameter(0))
@@ -428,6 +463,10 @@ class ES5Component extends ReactComponent, ObjectExpr {
result = getPropertyByName(name).getInit()
}
override Function getStaticMethod(string name) {
none()
}
override DataFlow::SourceNode getADirectPropsAccess() {
result.(DataFlow::PropRef).accesses(ref(), "props")
}