Merge pull request #839 from asger-semmle/field-propwrite

JS: add PropWrites cases for instance fields initialization
This commit is contained in:
Max Schaefer
2019-02-01 10:56:25 +00:00
committed by GitHub
12 changed files with 104 additions and 4 deletions

View File

@@ -475,14 +475,36 @@ module DataFlow {
* A static member definition, viewed as a data flow node that adds
* a property to the class.
*/
private class ClassMemberAsPropWrite extends PropWrite, PropNode {
private class StaticClassMemberAsPropWrite extends PropWrite, PropNode {
override MemberDefinition prop;
override Node getBase() {
prop.isStatic() and
result = valueNode(prop.getDeclaringClass())
StaticClassMemberAsPropWrite() { prop.isStatic() }
override Node getBase() { result = valueNode(prop.getDeclaringClass()) }
override Expr getPropertyNameExpr() { result = prop.getNameExpr() }
override string getPropertyName() { result = prop.getName() }
override Node getRhs() {
not prop instanceof AccessorMethodDefinition and
result = valueNode(prop.getInit())
}
override ControlFlowNode getWriteNode() { result = prop }
}
/**
* An instance method definition, viewed as a data flow node that adds
* a property to an unseen value.
*/
private class InstanceMethodAsPropWrite extends PropWrite, PropNode {
override MethodDefinition prop;
InstanceMethodAsPropWrite() { not prop.isStatic() }
override Node getBase() { none() } // The prototype has no DataFlow node
override Expr getPropertyNameExpr() { result = prop.getNameExpr() }
override string getPropertyName() { result = prop.getName() }
@@ -513,6 +535,49 @@ module DataFlow {
override ControlFlowNode getWriteNode() { result = prop }
}
/**
* A field induced by an initializing constructor parameter, seen as a property write (TypeScript only).
*/
private class ParameterFieldAsPropWrite extends PropWrite, PropNode {
override ParameterField prop;
override Node getBase() {
result = thisNode(prop.getDeclaringClass().getConstructor().getBody())
}
override Expr getPropertyNameExpr() { result = prop.getNameExpr() }
override string getPropertyName() { result = prop.getName() }
override Node getRhs() { result = parameterNode(prop.getParameter()) }
override ControlFlowNode getWriteNode() { result = prop.getParameter() }
}
/**
* An instance field, seen as a property write.
*/
private class InstanceFieldAsPropWrite extends PropWrite, PropNode {
override FieldDefinition prop;
InstanceFieldAsPropWrite() {
not prop.isStatic() and
not prop instanceof ParameterField
}
override Node getBase() {
result = thisNode(prop.getDeclaringClass().getConstructor().getBody())
}
override Expr getPropertyNameExpr() { result = prop.getNameExpr() }
override string getPropertyName() { result = prop.getName() }
override Node getRhs() { result = valueNode(prop.getInit()) }
override ControlFlowNode getWriteNode() { result = prop }
}
/**
* A data flow node that reads an object property.
*/

View File

@@ -1,3 +1,7 @@
| classes.ts:3:21:3:20 | constructor() {} |
| classes.ts:4:3:4:24 | instanc ... foo(); |
| classes.ts:8:3:8:39 | constru ... eld) {} |
| classes.ts:8:15:8:35 | public ... erField |
| tst.js:3:5:3:8 | x: 4 |
| tst.js:4:5:6:5 | func: f ... ;\\n } |
| tst.js:7:5:9:5 | f() {\\n ... ;\\n } |

View File

@@ -1,3 +1,5 @@
| classes.ts:4:3:4:24 | instanc ... foo(); | classes.ts:3:21:3:20 | this |
| classes.ts:8:15:8:35 | public ... erField | classes.ts:8:3:8:2 | this |
| tst.js:3:5:3:8 | x: 4 | tst.js:2:11:10:1 | {\\n x ... }\\n} |
| tst.js:4:5:6:5 | func: f ... ;\\n } | tst.js:2:11:10:1 | {\\n x ... }\\n} |
| tst.js:7:5:9:5 | f() {\\n ... ;\\n } | tst.js:2:11:10:1 | {\\n x ... }\\n} |

View File

@@ -1,3 +1,7 @@
| classes.ts:3:21:3:20 | constructor() {} | constructor |
| classes.ts:4:3:4:24 | instanc ... foo(); | instanceField |
| classes.ts:8:3:8:39 | constru ... eld) {} | constructor |
| classes.ts:8:15:8:35 | public ... erField | parameterField |
| tst.js:3:5:3:8 | x: 4 | x |
| tst.js:4:5:6:5 | func: f ... ;\\n } | func |
| tst.js:7:5:9:5 | f() {\\n ... ;\\n } | f |

View File

@@ -1,3 +1,7 @@
| classes.ts:3:21:3:20 | constructor() {} | classes.ts:3:21:3:20 | () {} |
| classes.ts:4:3:4:24 | instanc ... foo(); | classes.ts:4:19:4:23 | foo() |
| classes.ts:8:3:8:39 | constru ... eld) {} | classes.ts:8:3:8:39 | constru ... eld) {} |
| classes.ts:8:15:8:35 | public ... erField | classes.ts:8:22:8:35 | parameterField |
| tst.js:3:5:3:8 | x: 4 | tst.js:3:8:3:8 | 4 |
| tst.js:4:5:6:5 | func: f ... ;\\n } | tst.js:4:11:6:5 | functio ... ;\\n } |
| tst.js:7:5:9:5 | f() {\\n ... ;\\n } | tst.js:7:6:9:5 | () {\\n ... ;\\n } |

View File

@@ -0,0 +1,9 @@
import * as dummy from 'dummy';
class InstanceField {
instanceField = foo();
}
class ParameterField {
constructor(public parameterField) {}
}

View File

@@ -1,3 +1,5 @@
| classes.ts:3:21:3:20 | this | classes.ts:4:3:4:24 | instanc ... foo(); |
| classes.ts:8:3:8:2 | this | classes.ts:8:15:8:35 | public ... erField |
| tst.js:1:1:1:0 | this | tst.js:23:15:23:29 | this.someMethod |
| tst.js:1:1:1:0 | this | tst.js:24:36:24:45 | this.state |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | tst.js:3:5:3:8 | x: 4 |

View File

@@ -1,3 +1,5 @@
| classes.ts:3:21:3:20 | this | instanceField | classes.ts:4:3:4:24 | instanc ... foo(); |
| classes.ts:8:3:8:2 | this | parameterField | classes.ts:8:15:8:35 | public ... erField |
| tst.js:1:1:1:0 | this | someMethod | tst.js:23:15:23:29 | this.someMethod |
| tst.js:1:1:1:0 | this | state | tst.js:24:36:24:45 | this.state |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | f | tst.js:7:5:9:5 | f() {\\n ... ;\\n } |

View File

@@ -1,3 +1,5 @@
| classes.ts:3:21:3:20 | this | instanceField | classes.ts:4:19:4:23 | foo() |
| classes.ts:8:3:8:2 | this | parameterField | classes.ts:8:22:8:35 | parameterField |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | f | tst.js:7:6:9:5 | () {\\n ... ;\\n } |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | func | tst.js:4:11:6:5 | functio ... ;\\n } |
| tst.js:12:1:19:1 | class C ... ;\\n }\\n} | func | tst.js:13:14:15:3 | (x) {\\n ... x);\\n } |

View File

@@ -1,3 +1,5 @@
| classes.ts:3:21:3:20 | this | classes.ts:4:3:4:24 | instanc ... foo(); |
| classes.ts:8:3:8:2 | this | classes.ts:8:15:8:35 | public ... erField |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | tst.js:3:5:3:8 | x: 4 |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | tst.js:4:5:6:5 | func: f ... ;\\n } |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | tst.js:7:5:9:5 | f() {\\n ... ;\\n } |

View File

@@ -1,3 +1,5 @@
| classes.ts:3:21:3:20 | this | instanceField | classes.ts:4:3:4:24 | instanc ... foo(); |
| classes.ts:8:3:8:2 | this | parameterField | classes.ts:8:15:8:35 | public ... erField |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | f | tst.js:7:5:9:5 | f() {\\n ... ;\\n } |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | func | tst.js:4:5:6:5 | func: f ... ;\\n } |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | x | tst.js:3:5:3:8 | x: 4 |

View File

@@ -1,3 +1,5 @@
| classes.ts:3:21:3:20 | this | instanceField | classes.ts:4:19:4:23 | foo() |
| classes.ts:8:3:8:2 | this | parameterField | classes.ts:8:22:8:35 | parameterField |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | f | tst.js:7:6:9:5 | () {\\n ... ;\\n } |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | func | tst.js:4:11:6:5 | functio ... ;\\n } |
| tst.js:2:11:10:1 | {\\n x ... }\\n} | x | tst.js:3:8:3:8 | 4 |