Skip to content

Commit d61f576

Browse files
committed
JS: Add UnderlyingTypes.qll
1 parent 1533e13 commit d61f576

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/**
2+
* Provides name resolution and propagates type information.
3+
*/
4+
5+
private import javascript
6+
private import semmle.javascript.internal.NameResolution::NameResolution
7+
8+
/**
9+
* Provides name resolution and propagates type information.
10+
*/
11+
module UnderlyingTypes {
12+
private predicate subtypeStep(Node node1, Node node2) {
13+
exists(ClassOrInterface cls |
14+
(
15+
node1 = cls.getSuperClass() or
16+
node1 = cls.getASuperInterface()
17+
) and
18+
node2 = cls
19+
)
20+
}
21+
22+
predicate underlyingTypeStep(Node node1, Node node2) {
23+
exists(UnionOrIntersectionTypeExpr type |
24+
node1 = type.getAnElementType() and
25+
node2 = type
26+
)
27+
or
28+
exists(ReadonlyTypeExpr type |
29+
node1 = type.getElementType() and
30+
node2 = type
31+
)
32+
or
33+
exists(OptionalTypeExpr type |
34+
node1 = type.getElementType() and
35+
node2 = type
36+
)
37+
or
38+
exists(GenericTypeExpr type |
39+
node1 = type.getTypeAccess() and
40+
node2 = type
41+
)
42+
or
43+
exists(ExpressionWithTypeArguments e |
44+
node1 = e.getExpression() and
45+
node2 = e
46+
)
47+
or
48+
exists(JSDocUnionTypeExpr type |
49+
node1 = type.getAnAlternative() and
50+
node2 = type
51+
)
52+
or
53+
exists(JSDocNonNullableTypeExpr type |
54+
node1 = type.getTypeExpr() and
55+
node2 = type
56+
)
57+
or
58+
exists(JSDocNullableTypeExpr type |
59+
node1 = type.getTypeExpr() and
60+
node2 = type
61+
)
62+
or
63+
exists(JSDocAppliedTypeExpr type |
64+
node1 = type.getHead() and
65+
node2 = type
66+
)
67+
or
68+
exists(JSDocOptionalParameterTypeExpr type |
69+
node1 = type.getUnderlyingType() and
70+
node2 = type
71+
)
72+
}
73+
74+
predicate nodeHasUnderlyingType(Node node, string mod, string name) {
75+
nodeRefersToModule(node, mod, name)
76+
or
77+
exists(JSDocLocalTypeAccess type |
78+
node = type and
79+
not exists(type.getALexicalName()) and
80+
not type = any(JSDocQualifiedTypeAccess t).getBase() and
81+
name = type.getName() and
82+
mod = "global"
83+
)
84+
or
85+
exists(LocalTypeAccess type |
86+
node = type and
87+
not exists(type.getLocalTypeName()) and
88+
name = type.getName() and
89+
mod = "global"
90+
)
91+
or
92+
exists(Node mid | nodeHasUnderlyingType(mid, mod, name) |
93+
TypeFlow::step(mid, node)
94+
or
95+
underlyingTypeStep(mid, node)
96+
or
97+
subtypeStep(mid, node)
98+
)
99+
}
100+
101+
pragma[nomagic]
102+
predicate nodeHasUnderlyingType(Node node, string name) {
103+
nodeHasUnderlyingType(node, "global", name)
104+
}
105+
106+
predicate nodeHasUnderlyingClassType(Node node, DataFlow::ClassNode cls) {
107+
node = cls.getAstNode()
108+
or
109+
exists(string name |
110+
classHasGlobalName(cls, name) and
111+
nodeHasUnderlyingType(node, name)
112+
)
113+
or
114+
exists(Node mid | nodeHasUnderlyingClassType(mid, cls) |
115+
TypeFlow::step(mid, node)
116+
or
117+
underlyingTypeStep(mid, node)
118+
// Note: unlike for external types, we do not use subtype steps here.
119+
// The caller is responsible for handling the class hierarchy.
120+
)
121+
}
122+
123+
pragma[nomagic]
124+
private predicate classHasGlobalName(DataFlow::ClassNode cls, string name) {
125+
cls.flowsTo(AccessPath::getAnAssignmentTo(name)) and
126+
not cls.getTopLevel().isExterns() // don't propagate externs classes
127+
}
128+
}

0 commit comments

Comments
 (0)