Merge pull request #19852 from asgerf/js/react-use-server

JS: Model React 'use' and 'use server'
This commit is contained in:
Asger F
2025-06-25 09:13:56 +02:00
committed by GitHub
39 changed files with 363 additions and 317 deletions

View File

@@ -0,0 +1,6 @@
extensions:
- addsTo:
pack: codeql/javascript-all
extensible: summaryModel
data:
- ["react", "Member[use]", "Argument[0].Awaited", "ReturnValue", "value"]

View File

@@ -875,3 +875,22 @@ private class ReactPropAsViewComponentInput extends ViewComponentInput {
override string getSourceType() { result = "React props" }
}
private predicate isServerFunction(DataFlow::FunctionNode func) {
exists(Directive::UseServerDirective useServer |
useServer.getContainer() = func.getFunction()
or
useServer.getContainer().(Module).getAnExportedValue(_).getAFunctionValue() = func
)
}
private class ServerFunctionRemoteFlowSource extends RemoteFlowSource {
ServerFunctionRemoteFlowSource() {
exists(DataFlow::FunctionNode func |
isServerFunction(func) and
this = func.getAParameter()
)
}
override string getSourceType() { result = "React server function parameter" }
}

View File

@@ -0,0 +1,5 @@
---
category: majorAnalysis
---
* Taint is now tracked through the React `use` function.
* Parameters of React server functions, marked with the `"use server"` directive, are now seen as taint sources.

View File

@@ -0,0 +1,12 @@
import { use } from "react";
async function fetchData() {
return new Promise((resolve) => {
resolve(source("fetchedData"));
});
}
function Component() {
const data = use(fetchData());
sink(data); // $ hasValueFlow=fetchedData
}

View File

@@ -1,3 +0,0 @@
import semmle.javascript.frameworks.React
query predicate test_ReactComponent(ReactComponent c) { any() }

View File

@@ -1,5 +0,0 @@
import javascript
query predicate test_ReactComponent_getACandidatePropsValue(DataFlow::Node res) {
exists(ReactComponent c | res = c.getACandidatePropsValue(_))
}

View File

@@ -1,7 +0,0 @@
import semmle.javascript.frameworks.React
query predicate test_ReactComponent_getACandidateStateSource(
ReactComponent c, DataFlow::SourceNode res
) {
res = c.getACandidateStateSource()
}

View File

@@ -1,5 +0,0 @@
import semmle.javascript.frameworks.React
query predicate test_ReactComponent_getADirectPropsSource(ReactComponent c, DataFlow::SourceNode res) {
res = c.getADirectPropsAccess()
}

View File

@@ -1,7 +0,0 @@
import semmle.javascript.frameworks.React
query predicate test_ReactComponent_getAPreviousStateSource(
ReactComponent c, DataFlow::SourceNode res
) {
res = c.getAPreviousStateSource()
}

View File

@@ -1,5 +0,0 @@
import semmle.javascript.frameworks.React
query predicate test_ReactComponent_getAPropRead(ReactComponent c, string n, DataFlow::PropRead res) {
res = c.getAPropRead(n)
}

View File

@@ -1,5 +0,0 @@
import semmle.javascript.frameworks.React
query predicate test_ReactComponent_getInstanceMethod(ReactComponent c, string n, Function res) {
res = c.getInstanceMethod(n)
}

View File

@@ -1,3 +0,0 @@
import semmle.javascript.frameworks.React
query predicate test_ReactComponent_ref(ReactComponent c, DataFlow::Node res) { res = c.ref() }

View File

@@ -1,17 +0,0 @@
import semmle.javascript.frameworks.React
query predicate test_JSXname(JsxElement element, JsxName jsxname, string name, string type) {
name = jsxname.getValue() and
(
jsxname instanceof Identifier and type = "Identifier"
or
jsxname instanceof ThisExpr and type = "thisExpr"
or
jsxname.(DotExpr).getBase() instanceof JsxName and type = "dot"
or
jsxname instanceof JsxQualifiedName and type = "qualifiedName"
) and
element.getNameExpr() = jsxname
}
query ThisExpr test_JsxName_this(JsxElement element) { result.getParentExpr+() = element }

View File

@@ -1,14 +1,14 @@
var Hello = React.createClass({
displayName: 'Hello',
render: function() {
return <div>Hello {this.props.name}</div>;
return <div>Hello {this.props.name}</div>; // $ threatModelSource=view-component-input
},
getDefaultProps: function() {
return {
name: 'world'
name: 'world' // $ getACandidatePropsValue
};
}
});
}); // $ reactComponent
Hello.info = function() {
return "Nothing to see here.";
@@ -17,6 +17,6 @@ Hello.info = function() {
var createReactClass = require('create-react-class');
var Greeting = createReactClass({
render: function() {
return <h1>Hello, {this.props.name}</h1>;
return <h1>Hello, {this.props.name}</h1>; // $ threatModelSource=view-component-input
}
});
}); // $ reactComponent

View File

@@ -1,11 +1,11 @@
class Hello extends React.Component {
class Hello extends React.Component { // $ threatModelSource=view-component-input
render() {
return <div>Hello {this.props.name}</div>;
return <div>Hello {this.props.name}</div>; // $ threatModelSource=view-component-input
}
static info() {
return "Nothing to see here.";
}
}
} // $ reactComponent
Hello.displayName = 'Hello';
Hello.defaultProps = {
name: 'world'
@@ -17,4 +17,4 @@ class Hello2 extends React.Component {
this.state.bar.foo = 42;
this.state = { baz: 42};
}
}
} // $ reactComponent

View File

@@ -1,3 +1,3 @@
export function MyComponent(props) {
export function MyComponent(props) { // $ threatModelSource=view-component-input
return <div style={{color: props.color}}/>
}
} // $ reactComponent

View File

@@ -1,5 +0,0 @@
import semmle.javascript.frameworks.React
query predicate test_getADirectStateAccess(ReactComponent c, DataFlow::SourceNode res) {
res = c.getADirectStateAccess()
}

View File

@@ -1,5 +1,5 @@
import { MyComponent } from "./exportedComponent";
export function render({color, location}) {
return <MyComponent color={color}/>
}
export function render({color, location}) { // $ threatModelSource=view-component-input locationSource threatModelSource=remote
return <MyComponent color={color}/> // $ getACandidatePropsValue
} // $ reactComponent

View File

@@ -1,5 +1,5 @@
import { Component } from "react";
class C extends Component {}
class C extends Component {} // $ threatModelSource=view-component-input reactComponent
class D extends C {}
class D extends C {} // $ threatModelSource=view-component-input reactComponent

View File

@@ -1,15 +1,15 @@
function Hello(props) {
function Hello(props) { // $ threatModelSource=view-component-input
return <div>Hello {props.name}</div>;
}
} // $ reactComponent
function Hello2(props) {
function Hello2(props) { // $ threatModelSource=view-component-input
return React.createElement("div");
}
} // $ reactComponent
function Hello3(props) {
function Hello3(props) { // $ threatModelSource=view-component-input
var x = React.createElement("div");
return x;
}
} // $ reactComponent
function NotAComponent(props) {
if (y)
@@ -17,8 +17,8 @@ function NotAComponent(props) {
return g();
}
function SpuriousComponent(props) {
function SpuriousComponent(props) { // $ threatModelSource=view-component-input
if (y)
return React.createElement("div");
return 42;
}
} // $ reactComponent

View File

@@ -1,11 +1,11 @@
class Hello extends Preact.Component {
render(props, state) {
class Hello extends Preact.Component { // $ threatModelSource=view-component-input
render(props, state) { // $ threatModelSource=view-component-input
props.name;
state.name;
return <div/>;
}
}
} // $ reactComponent
class Hello extends preact.Component {
class Hello extends preact.Component { // $ threatModelSource=view-component-input
}
} // $ reactComponent

View File

@@ -1,6 +1,6 @@
class Hello extends Component {
class Hello extends Component { // $ threatModelSource=view-component-input
render() {
this.props.name;
this.props.name; // $ threatModelSource=view-component-input
return <div/>;
}
}
} // $ reactComponent

View File

@@ -1,36 +1,36 @@
function ES2015() {
class C extends React.Component {
}
class C extends React.Component { // $ threatModelSource=view-component-input
} // $ reactComponent
C.defaultProps = { propFromDefaultProps: "propFromDefaultProps" };
C.defaultProps = { propFromDefaultProps: "propFromDefaultProps" }; // $ getACandidatePropsValue
(<C propFromJSX={"propFromJSX"}/>);
(<C propFromJSX={"propFromJSX"}/>); // $ getACandidatePropsValue
new C({propFromConstructor: "propFromConstructor"});
new C({propFromConstructor: "propFromConstructor"}); // $ getACandidatePropsValue
}
function ES5() {
var C = React.createClass({
getDefaultProps() {
return { propFromDefaultProps: "propFromDefaultProps" };
return { propFromDefaultProps: "propFromDefaultProps" }; // $ getACandidatePropsValue
}
});
}); // $ reactComponent
(<C propFromJSX={"propFromJSX"}/>);
(<C propFromJSX={"propFromJSX"}/>); // $ getACandidatePropsValue
C({propFromConstructor: "propFromConstructor"});
C({propFromConstructor: "propFromConstructor"}); // $ getACandidatePropsValue
}
function Functional() {
function C(props) {
function C(props) { // $ threatModelSource=view-component-input
return <div/>;
}
} // $ reactComponent
C.defaultProps = { propFromDefaultProps: "propFromDefaultProps" };
C.defaultProps = { propFromDefaultProps: "propFromDefaultProps" }; // $ getACandidatePropsValue
(<C propFromJSX={"propFromJSX"}/>);
(<C propFromJSX={"propFromJSX"}/>); // $ getACandidatePropsValue
new C({propFromConstructor: "propFromConstructor"});
new C({propFromConstructor: "propFromConstructor"}); // $ getACandidatePropsValue
}

View File

@@ -1,4 +1,4 @@
class C extends React.Component {
class C extends React.Component { // $ threatModelSource=view-component-input
static getDerivedStateFromProps(props, state) {
return {};
}
@@ -8,4 +8,4 @@ class C extends React.Component {
getSnapshotBeforeUpdate(prevProps, prevState) {
return {};
}
}
} // $ reactComponent

View File

@@ -1,3 +0,0 @@
import javascript
query predicate test_react(DataFlow::ValueNode nd) { react().flowsTo(nd) }

View File

@@ -10,4 +10,4 @@ class Reads extends React.Component {
componentDidUpdate(prevProps, prevState) {
prevState.p4;
}
}
} // $ reactComponent

View File

@@ -31,15 +31,15 @@ class Writes extends React.Component {
state = {
p7: 42
};
}
} // $ reactComponent
React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>;
return <div>Hello {this.props.name}</div>; // $ threatModelSource=view-component-input
},
getInitialState: function() {
return {
p8: 42
};
}
});
}); // $ reactComponent

View File

@@ -1,42 +1,112 @@
test_react
| es5.js:1:13:1:17 | React |
| es6.js:1:21:1:25 | React |
| es6.js:14:22:14:26 | React |
| globalReactRefs.js:1:1:1:5 | React |
| globalReactRefs.js:4:5:4:9 | React |
| globalReactRefs.js:7:1:7:5 | React |
| importedReactRefs.js:1:8:1:12 | React |
| importedReactRefs.js:3:1:3:5 | React |
| importedReactRefs.js:6:5:6:9 | React |
| importedReactRefs.js:9:1:9:5 | React |
| plainfn.js:6:12:6:16 | React |
| plainfn.js:10:13:10:17 | React |
| plainfn.js:16:16:16:20 | React |
| plainfn.js:22:16:22:20 | React |
| props.js:2:21:2:25 | React |
| props.js:13:13:13:17 | React |
| rare-lifecycle-methods.js:1:17:1:21 | React |
| requiredReactRefs.js:1:13:1:28 | require("react") |
| requiredReactRefs.js:3:1:3:5 | React |
| requiredReactRefs.js:6:5:6:9 | React |
| requiredReactRefs.js:9:1:9:5 | React |
| requiredReactRefs.js:12:17:12:32 | require("react") |
| requiredReactRefs.js:14:5:14:9 | React |
| requiredReactRefs.js:17:9:17:13 | React |
| requiredReactRefs.js:20:5:20:9 | React |
| statePropertyReads.js:1:21:1:25 | React |
| statePropertyWrites.js:1:22:1:26 | React |
| statePropertyWrites.js:36:1:36:5 | React |
| thisAccesses.js:1:17:1:21 | React |
| thisAccesses.js:18:1:18:5 | React |
| thisAccesses.js:38:1:38:5 | React |
| thisAccesses.js:40:9:40:13 | React |
| thisAccesses.js:47:18:47:22 | React |
| thisAccesses.js:54:18:54:22 | React |
| thisAccesses_importedMappers.js:1:8:1:12 | React |
| thisAccesses_importedMappers.js:4:1:4:5 | React |
| thisAccesses_importedMappers.js:6:9:6:13 | React |
test_JSXname
getACandidatePropsValue
| es5.js:8:13:8:19 | 'world' |
| importedComponent.jsx:4:32:4:36 | color |
| props.js:5:46:5:67 | "propFr ... tProps" |
| props.js:7:22:7:34 | "propFromJSX" |
| props.js:9:33:9:53 | "propFr ... ructor" |
| props.js:15:44:15:65 | "propFr ... tProps" |
| props.js:19:22:19:34 | "propFromJSX" |
| props.js:21:29:21:49 | "propFr ... ructor" |
| props.js:30:46:30:67 | "propFr ... tProps" |
| props.js:32:22:32:34 | "propFromJSX" |
| props.js:34:33:34:53 | "propFr ... ructor" |
| useHigherOrderComponent.jsx:5:33:5:37 | "red" |
| useHigherOrderComponent.jsx:11:39:11:44 | "lazy" |
| useHigherOrderComponent.jsx:17:40:17:46 | "lazy2" |
getACandidateStateSource
| es6.js:14:1:20:1 | class H ... }\\n} | es6.js:18:22:18:31 | { baz: 42} |
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:3:16:3:17 | {} |
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:5:38:5:46 | nextState |
| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:7:45:7:56 | prevState.p3 |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:8:18:8:19 | {} |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:12:18:12:19 | {} |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:16:18:16:19 | {} |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:20:18:20:19 | {} |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:31:13:33:5 | {\\n ... 2\\n } |
| statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | statePropertyWrites.js:41:12:43:5 | {\\n p8: 42\\n } |
| thisAccesses.js:47:1:52:1 | class C ... }\\n} | thisAccesses.js:48:18:48:18 | y |
| thisAccesses.js:47:1:52:1 | class C ... }\\n} | thisAccesses.js:49:22:49:22 | x |
getADirectPropsSource
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | es5.js:4:24:4:33 | this.props |
| es5.js:18:33:22:1 | {\\n ren ... t\\n }\\n} | es5.js:20:24:20:33 | this.props |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:1:37:1:36 | args |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:3:24:3:33 | this.props |
| exportedComponent.jsx:1:8:3:1 | functio ... r}}/>\\n} | exportedComponent.jsx:1:29:1:33 | props |
| importedComponent.jsx:3:8:5:1 | functio ... Value\\n} | importedComponent.jsx:3:24:3:40 | {color, location} |
| namedImport.js:3:1:3:28 | class C ... nent {} | namedImport.js:3:27:3:26 | args |
| namedImport.js:5:1:5:20 | class D extends C {} | namedImport.js:5:19:5:18 | args |
| plainfn.js:1:1:3:1 | functio ... div>;\\n} | plainfn.js:1:16:1:20 | props |
| plainfn.js:5:1:7:1 | functio ... iv");\\n} | plainfn.js:5:17:5:21 | props |
| plainfn.js:9:1:12:1 | functio ... rn x;\\n} | plainfn.js:9:17:9:21 | props |
| plainfn.js:20:1:24:1 | functio ... n 42;\\n} | plainfn.js:20:28:20:32 | props |
| preact.js:1:1:7:1 | class H ... }\\n} | preact.js:1:38:1:37 | args |
| preact.js:1:1:7:1 | class H ... }\\n} | preact.js:2:12:2:16 | props |
| preact.js:9:1:11:1 | class H ... nput\\n\\n} | preact.js:9:38:9:37 | args |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:1:31:1:30 | args |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:3:9:3:18 | this.props |
| props.js:2:5:3:5 | class C ... t\\n } | props.js:2:37:2:36 | args |
| props.js:26:5:28:5 | functio ... ;\\n } | props.js:26:16:26:20 | props |
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:1:33:1:32 | args |
| statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | statePropertyWrites.js:38:24:38:33 | this.props |
| thisAccesses.js:31:2:36:1 | functio ... iv/>;\\n} | thisAccesses.js:31:12:31:16 | props |
| thisAccesses.js:47:1:52:1 | class C ... }\\n} | thisAccesses.js:48:18:48:18 | y |
getADirectStateAccess
| es6.js:14:1:20:1 | class H ... }\\n} | es6.js:16:9:16:18 | this.state |
| es6.js:14:1:20:1 | class H ... }\\n} | es6.js:17:9:17:18 | this.state |
| es6.js:14:1:20:1 | class H ... }\\n} | es6.js:18:9:18:18 | this.state |
| preact.js:1:1:7:1 | class H ... }\\n} | preact.js:2:19:2:23 | state |
| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:3:9:3:18 | this.state |
| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:5:9:5:18 | this.state |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:4:9:4:17 | cmp.state |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:6:9:6:17 | cmp.state |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:10:9:10:17 | cmp.state |
| thisAccesses.js:47:1:52:1 | class C ... }\\n} | thisAccesses.js:49:9:49:18 | this.state |
| thisAccesses.js:47:1:52:1 | class C ... }\\n} | thisAccesses.js:50:9:50:18 | this.state |
getAPreviousStateSource
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:2:44:2:48 | state |
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:8:40:8:48 | prevState |
| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:7:24:7:32 | prevState |
| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:10:35:10:43 | prevState |
getAPropRead
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | name | es5.js:4:24:4:38 | this.props.name |
| es5.js:18:33:22:1 | {\\n ren ... t\\n }\\n} | name | es5.js:20:24:20:38 | this.props.name |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | name | es6.js:3:24:3:38 | this.props.name |
| exportedComponent.jsx:1:8:3:1 | functio ... r}}/>\\n} | color | exportedComponent.jsx:2:32:2:42 | props.color |
| importedComponent.jsx:3:8:5:1 | functio ... Value\\n} | color | importedComponent.jsx:3:25:3:29 | color |
| importedComponent.jsx:3:8:5:1 | functio ... Value\\n} | location | importedComponent.jsx:3:32:3:39 | location |
| plainfn.js:1:1:3:1 | functio ... div>;\\n} | name | plainfn.js:2:22:2:31 | props.name |
| preact.js:1:1:7:1 | class H ... }\\n} | name | preact.js:3:9:3:18 | props.name |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | name | probably-a-component.js:3:9:3:23 | this.props.name |
| statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | name | statePropertyWrites.js:38:24:38:38 | this.props.name |
getInstanceMethod
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | getDefaultProps | es5.js:6:20:10:3 | functio ... };\\n } |
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | render | es5.js:3:11:5:3 | functio ... put\\n } |
| es5.js:18:33:22:1 | {\\n ren ... t\\n }\\n} | render | es5.js:19:11:21:3 | functio ... put\\n } |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | render | es6.js:2:9:4:3 | () {\\n ... put\\n } |
| exportedComponent.jsx:1:8:3:1 | functio ... r}}/>\\n} | render | exportedComponent.jsx:1:8:3:1 | functio ... r}}/>\\n} |
| importedComponent.jsx:3:8:5:1 | functio ... Value\\n} | render | importedComponent.jsx:3:8:5:1 | functio ... Value\\n} |
| plainfn.js:1:1:3:1 | functio ... div>;\\n} | render | plainfn.js:1:1:3:1 | functio ... div>;\\n} |
| plainfn.js:5:1:7:1 | functio ... iv");\\n} | render | plainfn.js:5:1:7:1 | functio ... iv");\\n} |
| plainfn.js:9:1:12:1 | functio ... rn x;\\n} | render | plainfn.js:9:1:12:1 | functio ... rn x;\\n} |
| plainfn.js:20:1:24:1 | functio ... n 42;\\n} | render | plainfn.js:20:1:24:1 | functio ... n 42;\\n} |
| preact.js:1:1:7:1 | class H ... }\\n} | render | preact.js:2:11:6:5 | (props, ... ;\\n } |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | render | probably-a-component.js:2:11:5:5 | () {\\n ... ;\\n } |
| props.js:13:31:17:5 | {\\n ... }\\n } | getDefaultProps | props.js:14:24:16:9 | () {\\n ... } |
| props.js:26:5:28:5 | functio ... ;\\n } | render | props.js:26:5:28:5 | functio ... ;\\n } |
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | getSnapshotBeforeUpdate | rare-lifecycle-methods.js:8:28:10:5 | (prevPr ... ;\\n } |
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | shouldComponentUpdate | rare-lifecycle-methods.js:5:26:7:5 | (nextPr ... ;\\n } |
| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | componentDidUpdate | statePropertyReads.js:10:23:12:5 | (prevPr ... ;\\n } |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | getInitialState | statePropertyWrites.js:25:20:29:5 | () { // ... ;\\n } |
| statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | getInitialState | statePropertyWrites.js:40:20:44:3 | functio ... };\\n } |
| statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | render | statePropertyWrites.js:37:11:39:3 | functio ... put\\n } |
| thisAccesses.js:1:1:16:1 | class C ... }\\n} | someInstanceMethod | thisAccesses.js:13:23:15:5 | () {\\n ... ;\\n } |
| thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | render | thisAccesses.js:19:13:24:5 | functio ... ;\\n } |
| thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | someInstanceMethod | thisAccesses.js:26:25:28:5 | functio ... ;\\n } |
| thisAccesses.js:31:2:36:1 | functio ... iv/>;\\n} | render | thisAccesses.js:31:2:36:1 | functio ... iv/>;\\n} |
| thisAccesses.js:38:19:45:1 | {\\n r ... },\\n} | render | thisAccesses.js:39:13:44:5 | functio ... ;\\n } |
| thisAccesses.js:54:1:63:1 | class C ... }\\n} | render | thisAccesses.js:59:11:62:5 | () {\\n ... ;\\n } |
| thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | render | thisAccesses_importedMappers.js:5:13:14:5 | functio ... ;\\n } |
jsxName
| es5.js:4:12:4:45 | <div>He ... }</div> | es5.js:4:13:4:15 | div | div | Identifier |
| es5.js:20:12:20:44 | <h1>Hel ... e}</h1> | es5.js:20:13:20:14 | h1 | h1 | Identifier |
| es6.js:3:12:3:45 | <div>He ... }</div> | es6.js:3:13:3:15 | div | div | Identifier |
@@ -62,13 +132,22 @@ test_JSXname
| useHigherOrderComponent.jsx:5:12:5:39 | <SomeCo ... "red"/> | useHigherOrderComponent.jsx:5:13:5:25 | SomeComponent | SomeComponent | Identifier |
| useHigherOrderComponent.jsx:11:12:11:46 | <LazyLo ... lazy"/> | useHigherOrderComponent.jsx:11:13:11:31 | LazyLoadedComponent | LazyLoadedComponent | Identifier |
| useHigherOrderComponent.jsx:17:12:17:48 | <LazyLo ... azy2"/> | useHigherOrderComponent.jsx:17:13:17:32 | LazyLoadedComponent2 | LazyLoadedComponent2 | Identifier |
test_ReactComponent
jsxNameThis
| es5.js:4:12:4:45 | <div>He ... }</div> | es5.js:4:24:4:27 | this |
| es5.js:20:12:20:44 | <h1>Hel ... e}</h1> | es5.js:20:24:20:27 | this |
| es6.js:3:12:3:45 | <div>He ... }</div> | es6.js:3:24:3:27 | this |
| statePropertyWrites.js:38:12:38:45 | <div>He ... }</div> | statePropertyWrites.js:38:24:38:27 | this |
| thisAccesses.js:60:19:60:41 | <this.n ... s.name> | thisAccesses.js:60:20:60:23 | this |
| thisAccesses.js:61:19:61:41 | <this.t ... s.this> | thisAccesses.js:61:20:61:23 | this |
locationSource
| importedComponent.jsx:3:32:3:39 | location |
reactComponent
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} |
| es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} |
| es5.js:18:33:22:1 | {\\n ren ... t\\n }\\n} |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} |
| es6.js:14:1:20:1 | class H ... }\\n} |
| exportedComponent.jsx:1:8:3:1 | functio ... r}}/>\\n} |
| importedComponent.jsx:3:8:5:1 | functio ... or}/>\\n} |
| importedComponent.jsx:3:8:5:1 | functio ... Value\\n} |
| namedImport.js:3:1:3:28 | class C ... nent {} |
| namedImport.js:5:1:5:20 | class D extends C {} |
| plainfn.js:1:1:3:1 | functio ... div>;\\n} |
@@ -76,9 +155,9 @@ test_ReactComponent
| plainfn.js:9:1:12:1 | functio ... rn x;\\n} |
| plainfn.js:20:1:24:1 | functio ... n 42;\\n} |
| preact.js:1:1:7:1 | class H ... }\\n} |
| preact.js:9:1:11:1 | class H ... nt {\\n\\n} |
| preact.js:9:1:11:1 | class H ... nput\\n\\n} |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} |
| props.js:2:5:3:5 | class C ... {\\n } |
| props.js:2:5:3:5 | class C ... t\\n } |
| props.js:13:31:17:5 | {\\n ... }\\n } |
| props.js:26:5:28:5 | functio ... ;\\n } |
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} |
@@ -92,14 +171,14 @@ test_ReactComponent
| thisAccesses.js:47:1:52:1 | class C ... }\\n} |
| thisAccesses.js:54:1:63:1 | class C ... }\\n} |
| thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} |
test_ReactComponent_ref
reactComponentRef
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} |
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | es5.js:3:11:3:10 | this |
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | es5.js:4:24:4:27 | this |
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | es5.js:6:20:6:19 | this |
| es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} | es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} |
| es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} | es5.js:19:11:19:10 | this |
| es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} | es5.js:20:24:20:27 | this |
| es5.js:18:33:22:1 | {\\n ren ... t\\n }\\n} | es5.js:18:33:22:1 | {\\n ren ... t\\n }\\n} |
| es5.js:18:33:22:1 | {\\n ren ... t\\n }\\n} | es5.js:19:11:19:10 | this |
| es5.js:18:33:22:1 | {\\n ren ... t\\n }\\n} | es5.js:20:24:20:27 | this |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:1:37:1:36 | implicit 'this' |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:1:37:1:36 | this |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:2:9:2:8 | this |
@@ -110,7 +189,7 @@ test_ReactComponent_ref
| es6.js:14:1:20:1 | class H ... }\\n} | es6.js:17:9:17:12 | this |
| es6.js:14:1:20:1 | class H ... }\\n} | es6.js:18:9:18:12 | this |
| exportedComponent.jsx:1:8:3:1 | functio ... r}}/>\\n} | exportedComponent.jsx:1:8:1:7 | this |
| importedComponent.jsx:3:8:5:1 | functio ... or}/>\\n} | importedComponent.jsx:3:8:3:7 | this |
| importedComponent.jsx:3:8:5:1 | functio ... Value\\n} | importedComponent.jsx:3:8:3:7 | this |
| namedImport.js:3:1:3:28 | class C ... nent {} | namedImport.js:3:27:3:26 | implicit 'this' |
| namedImport.js:3:1:3:28 | class C ... nent {} | namedImport.js:3:27:3:26 | this |
| namedImport.js:5:1:5:20 | class D extends C {} | namedImport.js:5:19:5:18 | implicit 'this' |
@@ -122,15 +201,15 @@ test_ReactComponent_ref
| preact.js:1:1:7:1 | class H ... }\\n} | preact.js:1:38:1:37 | implicit 'this' |
| preact.js:1:1:7:1 | class H ... }\\n} | preact.js:1:38:1:37 | this |
| preact.js:1:1:7:1 | class H ... }\\n} | preact.js:2:11:2:10 | this |
| preact.js:9:1:11:1 | class H ... nt {\\n\\n} | preact.js:9:38:9:37 | implicit 'this' |
| preact.js:9:1:11:1 | class H ... nt {\\n\\n} | preact.js:9:38:9:37 | this |
| preact.js:9:1:11:1 | class H ... nput\\n\\n} | preact.js:9:38:9:37 | implicit 'this' |
| preact.js:9:1:11:1 | class H ... nput\\n\\n} | preact.js:9:38:9:37 | this |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:1:31:1:30 | implicit 'this' |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:1:31:1:30 | this |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:2:11:2:10 | this |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:3:9:3:12 | this |
| props.js:2:5:3:5 | class C ... {\\n } | props.js:2:37:2:36 | implicit 'this' |
| props.js:2:5:3:5 | class C ... {\\n } | props.js:2:37:2:36 | this |
| props.js:2:5:3:5 | class C ... {\\n } | props.js:9:5:9:55 | new C({ ... ctor"}) |
| props.js:2:5:3:5 | class C ... t\\n } | props.js:2:37:2:36 | implicit 'this' |
| props.js:2:5:3:5 | class C ... t\\n } | props.js:2:37:2:36 | this |
| props.js:2:5:3:5 | class C ... t\\n } | props.js:9:5:9:55 | new C({ ... ctor"}) |
| props.js:13:31:17:5 | {\\n ... }\\n } | props.js:13:31:17:5 | {\\n ... }\\n } |
| props.js:13:31:17:5 | {\\n ... }\\n } | props.js:14:24:14:23 | this |
| props.js:26:5:28:5 | functio ... ;\\n } | props.js:26:5:26:4 | this |
@@ -201,123 +280,6 @@ test_ReactComponent_ref
| thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:9:25:9:24 | this |
| thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:10:13:10:16 | this |
| thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | thisAccesses_importedMappers.js:11:12:11:15 | this |
test_getADirectStateAccess
| es6.js:14:1:20:1 | class H ... }\\n} | es6.js:16:9:16:18 | this.state |
| es6.js:14:1:20:1 | class H ... }\\n} | es6.js:17:9:17:18 | this.state |
| es6.js:14:1:20:1 | class H ... }\\n} | es6.js:18:9:18:18 | this.state |
| preact.js:1:1:7:1 | class H ... }\\n} | preact.js:2:19:2:23 | state |
| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:3:9:3:18 | this.state |
| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:5:9:5:18 | this.state |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:4:9:4:17 | cmp.state |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:6:9:6:17 | cmp.state |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:10:9:10:17 | cmp.state |
| thisAccesses.js:47:1:52:1 | class C ... }\\n} | thisAccesses.js:49:9:49:18 | this.state |
| thisAccesses.js:47:1:52:1 | class C ... }\\n} | thisAccesses.js:50:9:50:18 | this.state |
test_ReactComponent_getAPropRead
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | name | es5.js:4:24:4:38 | this.props.name |
| es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} | name | es5.js:20:24:20:38 | this.props.name |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | name | es6.js:3:24:3:38 | this.props.name |
| exportedComponent.jsx:1:8:3:1 | functio ... r}}/>\\n} | color | exportedComponent.jsx:2:32:2:42 | props.color |
| importedComponent.jsx:3:8:5:1 | functio ... or}/>\\n} | color | importedComponent.jsx:3:25:3:29 | color |
| importedComponent.jsx:3:8:5:1 | functio ... or}/>\\n} | location | importedComponent.jsx:3:32:3:39 | location |
| plainfn.js:1:1:3:1 | functio ... div>;\\n} | name | plainfn.js:2:22:2:31 | props.name |
| preact.js:1:1:7:1 | class H ... }\\n} | name | preact.js:3:9:3:18 | props.name |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | name | probably-a-component.js:3:9:3:23 | this.props.name |
| statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | name | statePropertyWrites.js:38:24:38:38 | this.props.name |
test_ReactComponent_getInstanceMethod
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | getDefaultProps | es5.js:6:20:10:3 | functio ... };\\n } |
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | render | es5.js:3:11:5:3 | functio ... v>;\\n } |
| es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} | render | es5.js:19:11:21:3 | functio ... 1>;\\n } |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | render | es6.js:2:9:4:3 | () {\\n ... v>;\\n } |
| exportedComponent.jsx:1:8:3:1 | functio ... r}}/>\\n} | render | exportedComponent.jsx:1:8:3:1 | functio ... r}}/>\\n} |
| importedComponent.jsx:3:8:5:1 | functio ... or}/>\\n} | render | importedComponent.jsx:3:8:5:1 | functio ... or}/>\\n} |
| plainfn.js:1:1:3:1 | functio ... div>;\\n} | render | plainfn.js:1:1:3:1 | functio ... div>;\\n} |
| plainfn.js:5:1:7:1 | functio ... iv");\\n} | render | plainfn.js:5:1:7:1 | functio ... iv");\\n} |
| plainfn.js:9:1:12:1 | functio ... rn x;\\n} | render | plainfn.js:9:1:12:1 | functio ... rn x;\\n} |
| plainfn.js:20:1:24:1 | functio ... n 42;\\n} | render | plainfn.js:20:1:24:1 | functio ... n 42;\\n} |
| preact.js:1:1:7:1 | class H ... }\\n} | render | preact.js:2:11:6:5 | (props, ... ;\\n } |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | render | probably-a-component.js:2:11:5:5 | () {\\n ... ;\\n } |
| props.js:13:31:17:5 | {\\n ... }\\n } | getDefaultProps | props.js:14:24:16:9 | () {\\n ... } |
| props.js:26:5:28:5 | functio ... ;\\n } | render | props.js:26:5:28:5 | functio ... ;\\n } |
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | getSnapshotBeforeUpdate | rare-lifecycle-methods.js:8:28:10:5 | (prevPr ... ;\\n } |
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | shouldComponentUpdate | rare-lifecycle-methods.js:5:26:7:5 | (nextPr ... ;\\n } |
| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | componentDidUpdate | statePropertyReads.js:10:23:12:5 | (prevPr ... ;\\n } |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | getInitialState | statePropertyWrites.js:25:20:29:5 | () { // ... ;\\n } |
| statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | getInitialState | statePropertyWrites.js:40:20:44:3 | functio ... };\\n } |
| statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | render | statePropertyWrites.js:37:11:39:3 | functio ... v>;\\n } |
| thisAccesses.js:1:1:16:1 | class C ... }\\n} | someInstanceMethod | thisAccesses.js:13:23:15:5 | () {\\n ... ;\\n } |
| thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | render | thisAccesses.js:19:13:24:5 | functio ... ;\\n } |
| thisAccesses.js:18:19:29:1 | {\\n r ... }\\n} | someInstanceMethod | thisAccesses.js:26:25:28:5 | functio ... ;\\n } |
| thisAccesses.js:31:2:36:1 | functio ... iv/>;\\n} | render | thisAccesses.js:31:2:36:1 | functio ... iv/>;\\n} |
| thisAccesses.js:38:19:45:1 | {\\n r ... },\\n} | render | thisAccesses.js:39:13:44:5 | functio ... ;\\n } |
| thisAccesses.js:54:1:63:1 | class C ... }\\n} | render | thisAccesses.js:59:11:62:5 | () {\\n ... ;\\n } |
| thisAccesses_importedMappers.js:4:19:15:1 | {\\n r ... },\\n} | render | thisAccesses_importedMappers.js:5:13:14:5 | functio ... ;\\n } |
test_ReactComponent_getADirectPropsSource
| es5.js:1:31:11:1 | {\\n dis ... ;\\n }\\n} | es5.js:4:24:4:33 | this.props |
| es5.js:18:33:22:1 | {\\n ren ... ;\\n }\\n} | es5.js:20:24:20:33 | this.props |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:1:37:1:36 | args |
| es6.js:1:1:8:1 | class H ... ;\\n }\\n} | es6.js:3:24:3:33 | this.props |
| exportedComponent.jsx:1:8:3:1 | functio ... r}}/>\\n} | exportedComponent.jsx:1:29:1:33 | props |
| importedComponent.jsx:3:8:5:1 | functio ... or}/>\\n} | importedComponent.jsx:3:24:3:40 | {color, location} |
| namedImport.js:3:1:3:28 | class C ... nent {} | namedImport.js:3:27:3:26 | args |
| namedImport.js:5:1:5:20 | class D extends C {} | namedImport.js:5:19:5:18 | args |
| plainfn.js:1:1:3:1 | functio ... div>;\\n} | plainfn.js:1:16:1:20 | props |
| plainfn.js:5:1:7:1 | functio ... iv");\\n} | plainfn.js:5:17:5:21 | props |
| plainfn.js:9:1:12:1 | functio ... rn x;\\n} | plainfn.js:9:17:9:21 | props |
| plainfn.js:20:1:24:1 | functio ... n 42;\\n} | plainfn.js:20:28:20:32 | props |
| preact.js:1:1:7:1 | class H ... }\\n} | preact.js:1:38:1:37 | args |
| preact.js:1:1:7:1 | class H ... }\\n} | preact.js:2:12:2:16 | props |
| preact.js:9:1:11:1 | class H ... nt {\\n\\n} | preact.js:9:38:9:37 | args |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:1:31:1:30 | args |
| probably-a-component.js:1:1:6:1 | class H ... }\\n} | probably-a-component.js:3:9:3:18 | this.props |
| props.js:2:5:3:5 | class C ... {\\n } | props.js:2:37:2:36 | args |
| props.js:26:5:28:5 | functio ... ;\\n } | props.js:26:16:26:20 | props |
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:1:33:1:32 | args |
| statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | statePropertyWrites.js:38:24:38:33 | this.props |
| thisAccesses.js:31:2:36:1 | functio ... iv/>;\\n} | thisAccesses.js:31:12:31:16 | props |
| thisAccesses.js:47:1:52:1 | class C ... }\\n} | thisAccesses.js:48:18:48:18 | y |
test_ReactComponent_getACandidatePropsValue
| es5.js:8:13:8:19 | 'world' |
| importedComponent.jsx:4:32:4:36 | color |
| props.js:5:46:5:67 | "propFr ... tProps" |
| props.js:7:22:7:34 | "propFromJSX" |
| props.js:9:33:9:53 | "propFr ... ructor" |
| props.js:15:44:15:65 | "propFr ... tProps" |
| props.js:19:22:19:34 | "propFromJSX" |
| props.js:21:29:21:49 | "propFr ... ructor" |
| props.js:30:46:30:67 | "propFr ... tProps" |
| props.js:32:22:32:34 | "propFromJSX" |
| props.js:34:33:34:53 | "propFr ... ructor" |
| useHigherOrderComponent.jsx:5:33:5:37 | "red" |
| useHigherOrderComponent.jsx:11:39:11:44 | "lazy" |
| useHigherOrderComponent.jsx:17:40:17:46 | "lazy2" |
test_ReactComponent_getAPreviousStateSource
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:2:44:2:48 | state |
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:8:40:8:48 | prevState |
| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:7:24:7:32 | prevState |
| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:10:35:10:43 | prevState |
test_ReactComponent_getACandidateStateSource
| es6.js:14:1:20:1 | class H ... }\\n} | es6.js:18:22:18:31 | { baz: 42} |
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:3:16:3:17 | {} |
| rare-lifecycle-methods.js:1:1:11:1 | class C ... }\\n} | rare-lifecycle-methods.js:5:38:5:46 | nextState |
| statePropertyReads.js:1:1:13:1 | class R ... }\\n} | statePropertyReads.js:7:45:7:56 | prevState.p3 |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:8:18:8:19 | {} |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:12:18:12:19 | {} |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:16:18:16:19 | {} |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:20:18:20:19 | {} |
| statePropertyWrites.js:1:1:34:1 | class W ... };\\n} | statePropertyWrites.js:31:13:33:5 | {\\n ... 2\\n } |
| statePropertyWrites.js:36:19:45:1 | {\\n ren ... ;\\n }\\n} | statePropertyWrites.js:41:12:43:5 | {\\n p8: 42\\n } |
| thisAccesses.js:47:1:52:1 | class C ... }\\n} | thisAccesses.js:48:18:48:18 | y |
| thisAccesses.js:47:1:52:1 | class C ... }\\n} | thisAccesses.js:49:22:49:22 | x |
test_JsxName_this
| es5.js:4:12:4:45 | <div>He ... }</div> | es5.js:4:24:4:27 | this |
| es5.js:20:12:20:44 | <h1>Hel ... e}</h1> | es5.js:20:24:20:27 | this |
| es6.js:3:12:3:45 | <div>He ... }</div> | es6.js:3:24:3:27 | this |
| statePropertyWrites.js:38:12:38:45 | <div>He ... }</div> | statePropertyWrites.js:38:24:38:27 | this |
| thisAccesses.js:60:19:60:41 | <this.n ... s.name> | thisAccesses.js:60:20:60:23 | this |
| thisAccesses.js:61:19:61:41 | <this.t ... s.this> | thisAccesses.js:61:20:61:23 | this |
locationSource
| importedComponent.jsx:3:32:3:39 | location |
threatModelSource
| es5.js:4:24:4:33 | this.props | view-component-input |
| es5.js:20:24:20:33 | this.props | view-component-input |
@@ -343,3 +305,7 @@ threatModelSource
| statePropertyWrites.js:38:24:38:33 | this.props | view-component-input |
| thisAccesses.js:31:12:31:16 | props | view-component-input |
| thisAccesses.js:48:18:48:18 | y | view-component-input |
| use-server1.js:2:5:2:5 | x | remote |
| use-server1.js:3:5:3:5 | y | remote |
| use-server2.js:4:5:4:5 | x | remote |
| use-server2.js:5:5:5:5 | y | remote |

View File

@@ -1,14 +1,53 @@
import getADirectStateAccess
import ReactComponent_getInstanceMethod
import react
import ReactComponent_getAPreviousStateSource
import ReactComponent_ref
import ReactComponent_getACandidateStateSource
import ReactComponent_getADirectPropsSource
import ReactComponent_getACandidatePropsValue
import ReactComponent
import ReactComponent_getAPropRead
import ReactName
import javascript
import semmle.javascript.frameworks.React
query predicate getADirectStateAccess(ReactComponent c, DataFlow::SourceNode res) {
res = c.getADirectStateAccess()
}
query predicate getInstanceMethod(ReactComponent c, string n, Function res) {
res = c.getInstanceMethod(n)
}
query predicate getAPreviousStateSource(ReactComponent c, DataFlow::SourceNode res) {
res = c.getAPreviousStateSource()
}
query predicate reactComponentRef(ReactComponent c, DataFlow::Node res) { res = c.ref() }
query predicate getACandidateStateSource(ReactComponent c, DataFlow::SourceNode res) {
res = c.getACandidateStateSource()
}
query predicate getADirectPropsSource(ReactComponent c, DataFlow::SourceNode res) {
res = c.getADirectPropsAccess()
}
query predicate getACandidatePropsValue(DataFlow::Node res) {
exists(ReactComponent c | res = c.getACandidatePropsValue(_))
}
query predicate reactComponent(ReactComponent c) { any() }
query predicate getAPropRead(ReactComponent c, string n, DataFlow::PropRead res) {
res = c.getAPropRead(n)
}
query predicate jsxName(JsxElement element, JsxName jsxname, string name, string type) {
name = jsxname.getValue() and
(
jsxname instanceof Identifier and type = "Identifier"
or
jsxname instanceof ThisExpr and type = "thisExpr"
or
jsxname.(DotExpr).getBase() instanceof JsxName and type = "dot"
or
jsxname instanceof JsxQualifiedName and type = "qualifiedName"
) and
element.getNameExpr() = jsxname
}
query ThisExpr jsxNameThis(JsxElement element) { result.getParentExpr+() = element }
query DataFlow::SourceNode locationSource() { result = DOM::locationSource() }

View File

@@ -0,0 +1,2 @@
query: tests.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -13,7 +13,7 @@ class C extends React.Component {
someInstanceMethod() {
this;
}
}
} // $ reactComponent
React.createClass({
render: function() {
@@ -26,14 +26,14 @@ React.createClass({
someInstanceMethod: function() {
this;
}
});
}); // $ reactComponent
(function (props) {
(function (props) { // $ threatModelSource=view-component-input
(function () {
this; props;
}).bind(this);
return <div/>;
})
}) // $ reactComponent
React.createClass({
render: function() {
@@ -42,14 +42,14 @@ React.createClass({
}, this)
return <div/>;
},
});
}); // $ reactComponent
class C2 extends React.Component {
constructor (y) {
constructor (y) { // $ threatModelSource=view-component-input
this.state = x;
this.state = y;
}
}
} // $ reactComponent
class C3 extends React.Component {
constructor() {
@@ -60,4 +60,4 @@ class C3 extends React.Component {
var foo = <this.name></this.name>;
var bar = <this.this></this.this>;
}
}
} // $ reactComponent

View File

@@ -12,4 +12,4 @@ React.createClass({
return <div/>;
},
});
}); // $ reactComponent

View File

@@ -0,0 +1,10 @@
async function getData(
x, // $ threatModelSource=remote
y) { // $ threatModelSource=remote
"use server";
}
async function getData2(
x, // should not be remote flow sources (because the function does not have "use server")
y) {
}

View File

@@ -0,0 +1,11 @@
"use server";
export async function getData(
x, // $ threatModelSource=remote
y) { // $ threatModelSource=remote
}
async function getData2(
x, // should not be remote flow sources (because the function is not exported)
y) {
}

View File

@@ -2,17 +2,17 @@ import SomeComponent from './higherOrderComponent';
import { lazy } from 'react';
function foo() {
return <SomeComponent color="red"/>
return <SomeComponent color="red"/> // $ getACandidatePropsValue
}
const LazyLoadedComponent = lazy(() => import('./higherOrderComponent'));
function bar() {
return <LazyLoadedComponent color="lazy"/>
return <LazyLoadedComponent color="lazy"/> // $ getACandidatePropsValue
}
const LazyLoadedComponent2 = lazy(() => import('./exportedComponent').then(m => m.MyComponent));
function barz() {
return <LazyLoadedComponent2 color="lazy2"/>
return <LazyLoadedComponent2 color="lazy2"/> // $ getACandidatePropsValue
}

View File

@@ -65,7 +65,8 @@
| module.js:11:17:11:30 | req.query.code | module.js:11:17:11:30 | req.query.code | module.js:11:17:11:30 | req.query.code | This code execution depends on a $@. | module.js:11:17:11:30 | req.query.code | user-provided value |
| react-native.js:8:32:8:38 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:8:32:8:38 | tainted | This code execution depends on a $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value |
| react-native.js:10:23:10:29 | tainted | react-native.js:7:17:7:33 | req.param("code") | react-native.js:10:23:10:29 | tainted | This code execution depends on a $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value |
| react.js:10:56:10:77 | documen ... on.hash | react.js:10:56:10:77 | documen ... on.hash | react.js:10:56:10:77 | documen ... on.hash | This code execution depends on a $@. | react.js:10:56:10:77 | documen ... on.hash | user-provided value |
| react.js:11:56:11:77 | documen ... on.hash | react.js:11:56:11:77 | documen ... on.hash | react.js:11:56:11:77 | documen ... on.hash | This code execution depends on a $@. | react.js:11:56:11:77 | documen ... on.hash | user-provided value |
| react.js:25:8:25:11 | data | react-server-function.js:3:35:3:35 | x | react.js:25:8:25:11 | data | This code execution depends on a $@. | react-server-function.js:3:35:3:35 | x | user-provided value |
| template-sinks.js:20:17:20:23 | tainted | template-sinks.js:18:19:18:31 | req.query.foo | template-sinks.js:20:17:20:23 | tainted | Template, which may contain code, depends on a $@. | template-sinks.js:18:19:18:31 | req.query.foo | user-provided value |
| template-sinks.js:21:16:21:22 | tainted | template-sinks.js:18:19:18:31 | req.query.foo | template-sinks.js:21:16:21:22 | tainted | Template, which may contain code, depends on a $@. | template-sinks.js:18:19:18:31 | req.query.foo | user-provided value |
| template-sinks.js:22:18:22:24 | tainted | template-sinks.js:18:19:18:31 | req.query.foo | template-sinks.js:22:18:22:24 | tainted | Template, which may contain code, depends on a $@. | template-sinks.js:18:19:18:31 | req.query.foo | user-provided value |
@@ -156,6 +157,12 @@ edges
| react-native.js:7:7:7:33 | tainted | react-native.js:8:32:8:38 | tainted | provenance | |
| react-native.js:7:7:7:33 | tainted | react-native.js:10:23:10:29 | tainted | provenance | |
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted | provenance | |
| react-server-function.js:3:35:3:35 | x | react-server-function.js:4:12:4:12 | x | provenance | |
| react-server-function.js:4:12:4:12 | x | react-server-function.js:4:12:4:29 | x + " from server" | provenance | |
| react-server-function.js:4:12:4:29 | x + " from server" | react.js:24:20:24:44 | echoSer ... value") [PromiseValue] | provenance | |
| react.js:24:9:24:45 | data | react.js:25:8:25:11 | data | provenance | |
| react.js:24:16:24:45 | use(ech ... alue")) | react.js:24:9:24:45 | data | provenance | |
| react.js:24:20:24:44 | echoSer ... value") [PromiseValue] | react.js:24:16:24:45 | use(ech ... alue")) | provenance | |
| template-sinks.js:18:9:18:31 | tainted | template-sinks.js:20:17:20:23 | tainted | provenance | |
| template-sinks.js:18:9:18:31 | tainted | template-sinks.js:21:16:21:22 | tainted | provenance | |
| template-sinks.js:18:9:18:31 | tainted | template-sinks.js:22:18:22:24 | tainted | provenance | |
@@ -287,7 +294,14 @@ nodes
| react-native.js:7:17:7:33 | req.param("code") | semmle.label | req.param("code") |
| react-native.js:8:32:8:38 | tainted | semmle.label | tainted |
| react-native.js:10:23:10:29 | tainted | semmle.label | tainted |
| react.js:10:56:10:77 | documen ... on.hash | semmle.label | documen ... on.hash |
| react-server-function.js:3:35:3:35 | x | semmle.label | x |
| react-server-function.js:4:12:4:12 | x | semmle.label | x |
| react-server-function.js:4:12:4:29 | x + " from server" | semmle.label | x + " from server" |
| react.js:11:56:11:77 | documen ... on.hash | semmle.label | documen ... on.hash |
| react.js:24:9:24:45 | data | semmle.label | data |
| react.js:24:16:24:45 | use(ech ... alue")) | semmle.label | use(ech ... alue")) |
| react.js:24:20:24:44 | echoSer ... value") [PromiseValue] | semmle.label | echoSer ... value") [PromiseValue] |
| react.js:25:8:25:11 | data | semmle.label | data |
| template-sinks.js:18:9:18:31 | tainted | semmle.label | tainted |
| template-sinks.js:18:19:18:31 | req.query.foo | semmle.label | req.query.foo |
| template-sinks.js:20:17:20:23 | tainted | semmle.label | tainted |

View File

@@ -58,6 +58,12 @@ edges
| react-native.js:7:7:7:33 | tainted | react-native.js:8:32:8:38 | tainted | provenance | |
| react-native.js:7:7:7:33 | tainted | react-native.js:10:23:10:29 | tainted | provenance | |
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted | provenance | |
| react-server-function.js:3:35:3:35 | x | react-server-function.js:4:12:4:12 | x | provenance | |
| react-server-function.js:4:12:4:12 | x | react-server-function.js:4:12:4:29 | x + " from server" | provenance | |
| react-server-function.js:4:12:4:29 | x + " from server" | react.js:24:20:24:44 | echoSer ... value") [PromiseValue] | provenance | |
| react.js:24:9:24:45 | data | react.js:25:8:25:11 | data | provenance | |
| react.js:24:16:24:45 | use(ech ... alue")) | react.js:24:9:24:45 | data | provenance | |
| react.js:24:20:24:44 | echoSer ... value") [PromiseValue] | react.js:24:16:24:45 | use(ech ... alue")) | provenance | |
| template-sinks.js:18:9:18:31 | tainted | template-sinks.js:20:17:20:23 | tainted | provenance | |
| template-sinks.js:18:9:18:31 | tainted | template-sinks.js:21:16:21:22 | tainted | provenance | |
| template-sinks.js:18:9:18:31 | tainted | template-sinks.js:22:18:22:24 | tainted | provenance | |
@@ -191,7 +197,14 @@ nodes
| react-native.js:7:17:7:33 | req.param("code") | semmle.label | req.param("code") |
| react-native.js:8:32:8:38 | tainted | semmle.label | tainted |
| react-native.js:10:23:10:29 | tainted | semmle.label | tainted |
| react.js:10:56:10:77 | documen ... on.hash | semmle.label | documen ... on.hash |
| react-server-function.js:3:35:3:35 | x | semmle.label | x |
| react-server-function.js:4:12:4:12 | x | semmle.label | x |
| react-server-function.js:4:12:4:29 | x + " from server" | semmle.label | x + " from server" |
| react.js:11:56:11:77 | documen ... on.hash | semmle.label | documen ... on.hash |
| react.js:24:9:24:45 | data | semmle.label | data |
| react.js:24:16:24:45 | use(ech ... alue")) | semmle.label | use(ech ... alue")) |
| react.js:24:20:24:44 | echoSer ... value") [PromiseValue] | semmle.label | echoSer ... value") [PromiseValue] |
| react.js:25:8:25:11 | data | semmle.label | data |
| template-sinks.js:18:9:18:31 | tainted | semmle.label | tainted |
| template-sinks.js:18:19:18:31 | req.query.foo | semmle.label | req.query.foo |
| template-sinks.js:20:17:20:23 | tainted | semmle.label | tainted |

View File

@@ -0,0 +1,5 @@
"use server";
export async function echoService(x) { // $ Source[js/code-injection]
return x + " from server";
}

View File

@@ -1,6 +1,7 @@
import React from "react";
import React, { use } from "react";
import {Helmet} from "react-helmet";
import { echoService } from "./react-server-function";
class Application extends React.Component {
render () {
return (
@@ -14,4 +15,12 @@ class Application extends React.Component {
}
};
export default Application
export default Application
export function Component() {
// We currently get false-positive flow through server functions in cases where a safe value
// is passed as the argument, which flows to the return value. In this case, the tainted parameter
// flows out of the return value regardless.
const data = use(echoService("safe value"));
eval(data); // $ SPURIOUS: Alert[js/code-injection]
}