Skip to content

Commit 3dabff6

Browse files
committed
JS: Recognize field types in untyped code
1 parent d38121f commit 3dabff6

File tree

3 files changed

+34
-4
lines changed

3 files changed

+34
-4
lines changed

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/DataFlow.qll

Lines changed: 6 additions & 1 deletion
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
/**

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) {

0 commit comments

Comments
 (0)