Skip to content

Commit ef703e7

Browse files
authored
Merge pull request #4401 from asgerf/js/angular-prerequisites
Approved by erik-krogh
2 parents 5bc7e19 + a962a8a commit ef703e7

File tree

12 files changed

+90
-17
lines changed

12 files changed

+90
-17
lines changed

javascript/ql/src/semmle/javascript/DOM.qll

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,11 @@ module DOM {
347347
}
348348

349349
/** Gets a data flow node that may refer to a value from the DOM. */
350-
DataFlow::SourceNode domValueRef() { result = domValueRef(DataFlow::TypeTracker::end()) }
350+
DataFlow::SourceNode domValueRef() {
351+
result = domValueRef(DataFlow::TypeTracker::end())
352+
or
353+
result.hasUnderlyingType("Element")
354+
}
351355

352356
module LocationSource {
353357
/**
@@ -419,5 +423,9 @@ module DOM {
419423
/**
420424
* Gets a reference to the 'document' object.
421425
*/
422-
DataFlow::SourceNode documentRef() { result = documentRef(DataFlow::TypeTracker::end()) }
426+
DataFlow::SourceNode documentRef() {
427+
result = documentRef(DataFlow::TypeTracker::end())
428+
or
429+
result.hasUnderlyingType("Document")
430+
}
423431
}

javascript/ql/src/semmle/javascript/Extend.qll

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ abstract class ExtendCall extends DataFlow::CallNode {
3434
}
3535
}
3636

37+
/** A version of `JQuery::dollarSource()` with fewer dependencies. */
38+
private DataFlow::SourceNode localDollar() {
39+
result.accessesGlobal(["$", "jQuery"])
40+
or
41+
result = DataFlow::moduleImport("jquery")
42+
}
43+
3744
/**
3845
* An extend call of form `extend(true/false, dst, src1, src2, ...)`, where the true/false
3946
* argument is possibly omitted.
@@ -47,9 +54,7 @@ private class ExtendCallWithFlag extends ExtendCall {
4754
name = "node.extend"
4855
)
4956
or
50-
// Match $.extend using the source of `$` only, as ExtendCall should not
51-
// depend on type tracking.
52-
this = JQuery::dollarSource().getAMemberCall("extend")
57+
this = localDollar().getAMemberCall("extend")
5358
}
5459

5560
/**

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

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,24 @@ private predicate barrierGuardBlocksSsaRefinement(
420420
)
421421
}
422422

423+
/**
424+
* Holds if the result of `guard` is used in the branching condition `cond`.
425+
*
426+
* `outcome` is bound to the outcome of `cond` for join-ordering purposes.
427+
*/
428+
pragma[noinline]
429+
private predicate barrierGuardUsedInCondition(
430+
BarrierGuardNode guard, ConditionGuardNode cond, boolean outcome
431+
) {
432+
barrierGuardIsRelevant(guard) and
433+
outcome = cond.getOutcome() and
434+
(
435+
cond.getTest() = guard.getEnclosingExpr()
436+
or
437+
cond.getTest().flow().getImmediatePredecessor+() = guard
438+
)
439+
}
440+
423441
/**
424442
* Holds if data flow node `nd` acts as a barrier for data flow, possibly due to aliasing
425443
* through an access path.
@@ -435,14 +453,9 @@ private predicate barrierGuardBlocksNode(BarrierGuardNode guard, DataFlow::Node
435453
)
436454
or
437455
// 2) `nd` is an instance of an access path `p`, and dominated by a barrier for `p`
438-
barrierGuardIsRelevant(guard) and
439456
exists(AccessPath p, BasicBlock bb, ConditionGuardNode cond, boolean outcome |
440457
nd = DataFlow::valueNode(p.getAnInstanceIn(bb)) and
441-
(
442-
guard.getEnclosingExpr() = cond.getTest() or
443-
guard = cond.getTest().flow().getImmediatePredecessor+()
444-
) and
445-
outcome = cond.getOutcome() and
458+
barrierGuardUsedInCondition(guard, cond, outcome) and
446459
barrierGuardBlocksAccessPath(guard, outcome, p, label) and
447460
cond.dominates(bb)
448461
)

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,14 +228,19 @@ module DataFlow {
228228
*
229229
* Doesn't take field types and function return types into account.
230230
*/
231-
private JSDocTypeExpr getFallbackTypeAnnotation() {
231+
private TypeAnnotation getFallbackTypeAnnotation() {
232232
exists(BindingPattern pattern |
233233
this = valueNode(pattern) and
234234
not ast_node_type(pattern, _) and
235235
result = pattern.getTypeAnnotation()
236236
)
237237
or
238238
result = getAPredecessor().getFallbackTypeAnnotation()
239+
or
240+
exists(DataFlow::ClassNode cls, string fieldName |
241+
this = cls.getAReceiverNode().getAPropertyRead(fieldName) and
242+
result = cls.getFieldTypeAnnotation(fieldName)
243+
)
239244
}
240245

241246
/**
@@ -704,7 +709,9 @@ module DataFlow {
704709
result = thisNode(prop.getDeclaringClass().getConstructor().getBody())
705710
}
706711

707-
override Expr getPropertyNameExpr() { result = prop.getNameExpr() }
712+
override Expr getPropertyNameExpr() {
713+
none() // The parameter value is not the name of the field
714+
}
708715

709716
override string getPropertyName() { result = prop.getName() }
710717

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,13 @@ class ClassNode extends DataFlow::SourceNode {
995995
predicate hasQualifiedName(string name) {
996996
getAClassReference().flowsTo(AccessPath::getAnAssignmentTo(name))
997997
}
998+
999+
/**
1000+
* Gets the type annotation for the field `fieldName`, if any.
1001+
*/
1002+
TypeAnnotation getFieldTypeAnnotation(string fieldName) {
1003+
result = impl.getFieldTypeAnnotation(fieldName)
1004+
}
9981005
}
9991006

10001007
module ClassNode {
@@ -1047,6 +1054,11 @@ module ClassNode {
10471054
* of this node.
10481055
*/
10491056
abstract DataFlow::Node getASuperClassNode();
1057+
1058+
/**
1059+
* Gets the type annotation for the field `fieldName`, if any.
1060+
*/
1061+
TypeAnnotation getFieldTypeAnnotation(string fieldName) { none() }
10501062
}
10511063

10521064
/**
@@ -1106,6 +1118,14 @@ module ClassNode {
11061118
}
11071119

11081120
override DataFlow::Node getASuperClassNode() { result = astNode.getSuperClass().flow() }
1121+
1122+
override TypeAnnotation getFieldTypeAnnotation(string fieldName) {
1123+
exists(FieldDeclaration field |
1124+
field.getDeclaringClass() = astNode and
1125+
fieldName = field.getName() and
1126+
result = field.getTypeAnnotation()
1127+
)
1128+
}
11091129
}
11101130

11111131
private DataFlow::PropRef getAPrototypeReferenceInFile(string name, File f) {

javascript/ql/test/library-tests/ClassNode/InstanceMember.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
| fields.ts:2:16:2:32 | (x: string) => {} | Foo.m | method |
1+
| fields.ts:12:16:12:32 | (x: string) => {} | Foo.m | method |
22
| namespace.js:5:32:5:44 | function() {} | Baz.method | method |
33
| tst2.js:6:9:9:3 | () {\\n ... .x;\\n } | C.method | method |
44
| tst2.js:11:13:13:3 | () {\\n ... .x;\\n } | C.getter | getter |

javascript/ql/test/library-tests/ClassNode/InstanceMethod.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
| fields.ts:2:16:2:32 | (x: string) => {} | Foo.m |
1+
| fields.ts:12:16:12:32 | (x: string) => {} | Foo.m |
22
| namespace.js:5:32:5:44 | function() {} | Baz.method |
33
| tst2.js:6:9:9:3 | () {\\n ... .x;\\n } | C.method |
44
| tst2.js:18:14:18:22 | (x) => {} | D.f |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
| fields.ts:5:1:13:1 | class F ... > {};\\n} | Foo | fields.ts:1:1:3:1 | class B ... mber;\\n} | Base |
12
| tst.js:13:1:13:21 | class A ... ds A {} | A2 | tst.js:3:1:10:1 | class A ... () {}\\n} | A |
23
| tst.js:15:1:15:15 | function B() {} | B | tst.js:3:1:10:1 | class A ... () {}\\n} | A |
34
| tst.js:19:1:19:15 | function C() {} | C | tst.js:15:1:15:15 | function B() {} | B |
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1-
class Foo {
1+
class Base {
2+
baseField: number;
3+
}
4+
5+
class Foo extends Base {
6+
constructor(public x: number, private y: string) {
7+
super();
8+
}
9+
10+
z: string[];
11+
212
public m = (x: string) => {};
313
}

javascript/ql/test/library-tests/ClassNode/getAReceiverNode.expected

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
| fields.ts:1:1:3:1 | class F ... > {};\\n} | fields.ts:1:11:1:10 | this |
1+
| fields.ts:1:1:3:1 | class B ... mber;\\n} | fields.ts:1:12:1:11 | this |
2+
| fields.ts:5:1:13:1 | class F ... > {};\\n} | fields.ts:6:5:6:4 | this |
23
| namespace.js:3:15:3:31 | function Baz() {} | namespace.js:3:15:3:14 | this |
34
| namespace.js:3:15:3:31 | function Baz() {} | namespace.js:5:32:5:31 | this |
45
| tst2.js:1:1:14:1 | class C ... ;\\n }\\n} | tst2.js:2:14:2:13 | this |

0 commit comments

Comments
 (0)