Skip to content

Commit 9bfde95

Browse files
author
Max Schaefer
authored
Merge pull request #839 from asger-semmle/field-propwrite
JS: add PropWrites cases for instance fields initialization
2 parents 2227380 + 720f442 commit 9bfde95

File tree

12 files changed

+104
-4
lines changed

12 files changed

+104
-4
lines changed

javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -475,14 +475,36 @@ module DataFlow {
475475
* A static member definition, viewed as a data flow node that adds
476476
* a property to the class.
477477
*/
478-
private class ClassMemberAsPropWrite extends PropWrite, PropNode {
478+
private class StaticClassMemberAsPropWrite extends PropWrite, PropNode {
479479
override MemberDefinition prop;
480480

481-
override Node getBase() {
482-
prop.isStatic() and
483-
result = valueNode(prop.getDeclaringClass())
481+
StaticClassMemberAsPropWrite() { prop.isStatic() }
482+
483+
override Node getBase() { result = valueNode(prop.getDeclaringClass()) }
484+
485+
override Expr getPropertyNameExpr() { result = prop.getNameExpr() }
486+
487+
override string getPropertyName() { result = prop.getName() }
488+
489+
override Node getRhs() {
490+
not prop instanceof AccessorMethodDefinition and
491+
result = valueNode(prop.getInit())
484492
}
485493

494+
override ControlFlowNode getWriteNode() { result = prop }
495+
}
496+
497+
/**
498+
* An instance method definition, viewed as a data flow node that adds
499+
* a property to an unseen value.
500+
*/
501+
private class InstanceMethodAsPropWrite extends PropWrite, PropNode {
502+
override MethodDefinition prop;
503+
504+
InstanceMethodAsPropWrite() { not prop.isStatic() }
505+
506+
override Node getBase() { none() } // The prototype has no DataFlow node
507+
486508
override Expr getPropertyNameExpr() { result = prop.getNameExpr() }
487509

488510
override string getPropertyName() { result = prop.getName() }
@@ -513,6 +535,49 @@ module DataFlow {
513535
override ControlFlowNode getWriteNode() { result = prop }
514536
}
515537

538+
/**
539+
* A field induced by an initializing constructor parameter, seen as a property write (TypeScript only).
540+
*/
541+
private class ParameterFieldAsPropWrite extends PropWrite, PropNode {
542+
override ParameterField prop;
543+
544+
override Node getBase() {
545+
result = thisNode(prop.getDeclaringClass().getConstructor().getBody())
546+
}
547+
548+
override Expr getPropertyNameExpr() { result = prop.getNameExpr() }
549+
550+
override string getPropertyName() { result = prop.getName() }
551+
552+
override Node getRhs() { result = parameterNode(prop.getParameter()) }
553+
554+
override ControlFlowNode getWriteNode() { result = prop.getParameter() }
555+
}
556+
557+
/**
558+
* An instance field, seen as a property write.
559+
*/
560+
private class InstanceFieldAsPropWrite extends PropWrite, PropNode {
561+
override FieldDefinition prop;
562+
563+
InstanceFieldAsPropWrite() {
564+
not prop.isStatic() and
565+
not prop instanceof ParameterField
566+
}
567+
568+
override Node getBase() {
569+
result = thisNode(prop.getDeclaringClass().getConstructor().getBody())
570+
}
571+
572+
override Expr getPropertyNameExpr() { result = prop.getNameExpr() }
573+
574+
override string getPropertyName() { result = prop.getName() }
575+
576+
override Node getRhs() { result = valueNode(prop.getInit()) }
577+
578+
override ControlFlowNode getWriteNode() { result = prop }
579+
}
580+
516581
/**
517582
* A data flow node that reads an object property.
518583
*/

javascript/ql/test/library-tests/PropWrite/PropWrite.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
| classes.ts:3:21:3:20 | constructor() {} |
2+
| classes.ts:4:3:4:24 | instanc ... foo(); |
3+
| classes.ts:8:3:8:39 | constru ... eld) {} |
4+
| classes.ts:8:15:8:35 | public ... erField |
15
| tst.js:3:5:3:8 | x: 4 |
26
| tst.js:4:5:6:5 | func: f ... ;\\n } |
37
| tst.js:7:5:9:5 | f() {\\n ... ;\\n } |

javascript/ql/test/library-tests/PropWrite/PropWriteBase.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
| classes.ts:4:3:4:24 | instanc ... foo(); | classes.ts:3:21:3:20 | this |
2+
| classes.ts:8:15:8:35 | public ... erField | classes.ts:8:3:8:2 | this |
13
| tst.js:3:5:3:8 | x: 4 | tst.js:2:11:10:1 | {\\n x ... }\\n} |
24
| tst.js:4:5:6:5 | func: f ... ;\\n } | tst.js:2:11:10:1 | {\\n x ... }\\n} |
35
| tst.js:7:5:9:5 | f() {\\n ... ;\\n } | tst.js:2:11:10:1 | {\\n x ... }\\n} |

javascript/ql/test/library-tests/PropWrite/PropWritePropName.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
| classes.ts:3:21:3:20 | constructor() {} | constructor |
2+
| classes.ts:4:3:4:24 | instanc ... foo(); | instanceField |
3+
| classes.ts:8:3:8:39 | constru ... eld) {} | constructor |
4+
| classes.ts:8:15:8:35 | public ... erField | parameterField |
15
| tst.js:3:5:3:8 | x: 4 | x |
26
| tst.js:4:5:6:5 | func: f ... ;\\n } | func |
37
| tst.js:7:5:9:5 | f() {\\n ... ;\\n } | f |

javascript/ql/test/library-tests/PropWrite/PropWriteRhs.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
| classes.ts:3:21:3:20 | constructor() {} | classes.ts:3:21:3:20 | () {} |
2+
| classes.ts:4:3:4:24 | instanc ... foo(); | classes.ts:4:19:4:23 | foo() |
3+
| classes.ts:8:3:8:39 | constru ... eld) {} | classes.ts:8:3:8:39 | constru ... eld) {} |
4+
| classes.ts:8:15:8:35 | public ... erField | classes.ts:8:22:8:35 | parameterField |
15
| tst.js:3:5:3:8 | x: 4 | tst.js:3:8:3:8 | 4 |
26
| tst.js:4:5:6:5 | func: f ... ;\\n } | tst.js:4:11:6:5 | functio ... ;\\n } |
37
| tst.js:7:5:9:5 | f() {\\n ... ;\\n } | tst.js:7:6:9:5 | () {\\n ... ;\\n } |
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import * as dummy from 'dummy';
2+
3+
class InstanceField {
4+
instanceField = foo();
5+
}
6+
7+
class ParameterField {
8+
constructor(public parameterField) {}
9+
}

javascript/ql/test/library-tests/PropWrite/getAPropertyReference.expected

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

javascript/ql/test/library-tests/PropWrite/getAPropertyReference2.expected

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

javascript/ql/test/library-tests/PropWrite/getAPropertySource.expected

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

javascript/ql/test/library-tests/PropWrite/getAPropertyWrite.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
| classes.ts:3:21:3:20 | this | classes.ts:4:3:4:24 | instanc ... foo(); |
2+
| classes.ts:8:3:8:2 | this | classes.ts:8:15:8:35 | public ... erField |
13
| tst.js:2:11:10:1 | {\\n x ... }\\n} | tst.js:3:5:3:8 | x: 4 |
24
| tst.js:2:11:10:1 | {\\n x ... }\\n} | tst.js:4:5:6:5 | func: f ... ;\\n } |
35
| tst.js:2:11:10:1 | {\\n x ... }\\n} | tst.js:7:5:9:5 | f() {\\n ... ;\\n } |

0 commit comments

Comments
 (0)