Skip to content

Commit b5a4fc0

Browse files
committed
JS: Make Closure concepts based on AST instead
1 parent 50e4ac8 commit b5a4fc0

File tree

2 files changed

+67
-40
lines changed

2 files changed

+67
-40
lines changed

javascript/ql/lib/semmle/javascript/Closure.qll

Lines changed: 64 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,49 @@
55
import javascript
66

77
module Closure {
8+
/** A call to `goog.require` */
9+
class RequireCallExpr extends CallExpr {
10+
RequireCallExpr() { this.getCallee().(PropAccess).getQualifiedName() = "goog.require" }
11+
12+
/** Gets the imported namespace name. */
13+
string getClosureNamespace() { result = this.getArgument(0).getStringValue() }
14+
}
15+
16+
/** A call to `goog.provide` */
17+
class ProvideCallExpr extends CallExpr {
18+
ProvideCallExpr() { this.getCallee().(PropAccess).getQualifiedName() = "goog.provide" }
19+
20+
/** Gets the imported namespace name. */
21+
string getClosureNamespace() { result = this.getArgument(0).getStringValue() }
22+
}
23+
24+
/** A call to `goog.module` or `goog.declareModuleId`. */
25+
private class ModuleDeclarationCall extends CallExpr {
26+
private string kind;
27+
28+
ModuleDeclarationCall() {
29+
this.getCallee().(PropAccess).getQualifiedName() = kind and
30+
kind = ["goog.module", "goog.declareModuleId"]
31+
}
32+
33+
/** Gets the declared namespace. */
34+
string getClosureNamespace() { result = this.getArgument(0).getStringValue() }
35+
36+
/** Gets the string `goog.module` or `goog.declareModuleId` depending on which method is being called. */
37+
string getModuleKind() { result = kind }
38+
}
39+
840
/**
941
* A reference to a Closure namespace.
1042
*/
11-
class ClosureNamespaceRef extends DataFlow::Node instanceof ClosureNamespaceRef::Range {
43+
deprecated class ClosureNamespaceRef extends DataFlow::Node instanceof ClosureNamespaceRef::Range {
1244
/**
1345
* Gets the namespace being referenced.
1446
*/
1547
string getClosureNamespace() { result = super.getClosureNamespace() }
1648
}
1749

18-
module ClosureNamespaceRef {
50+
deprecated module ClosureNamespaceRef {
1951
/**
2052
* A reference to a Closure namespace.
2153
*
@@ -32,10 +64,10 @@ module Closure {
3264
/**
3365
* A data flow node that returns the value of a closure namespace.
3466
*/
35-
class ClosureNamespaceAccess extends ClosureNamespaceRef instanceof ClosureNamespaceAccess::Range {
36-
}
67+
deprecated class ClosureNamespaceAccess extends ClosureNamespaceRef instanceof ClosureNamespaceAccess::Range
68+
{ }
3769

38-
module ClosureNamespaceAccess {
70+
deprecated module ClosureNamespaceAccess {
3971
/**
4072
* A data flow node that returns the value of a closure namespace.
4173
*
@@ -47,7 +79,7 @@ module Closure {
4779
/**
4880
* A call to a method on the `goog.` namespace, as a closure reference.
4981
*/
50-
abstract private class DefaultNamespaceRef extends DataFlow::MethodCallNode,
82+
abstract deprecated private class DefaultNamespaceRef extends DataFlow::MethodCallNode,
5183
ClosureNamespaceRef::Range
5284
{
5385
DefaultNamespaceRef() { this = DataFlow::globalVarRef("goog").getAMethodCall() }
@@ -59,14 +91,14 @@ module Closure {
5991
* Holds if `node` is the data flow node corresponding to the expression in
6092
* a top-level expression statement.
6193
*/
62-
private predicate isTopLevelExpr(DataFlow::Node node) {
94+
deprecated private predicate isTopLevelExpr(DataFlow::Node node) {
6395
any(TopLevel tl).getAChildStmt().(ExprStmt).getExpr().flow() = node
6496
}
6597

6698
/**
6799
* A top-level call to `goog.provide`.
68100
*/
69-
private class DefaultClosureProvideCall extends DefaultNamespaceRef {
101+
deprecated private class DefaultClosureProvideCall extends DefaultNamespaceRef {
70102
DefaultClosureProvideCall() {
71103
this.getMethodName() = "provide" and
72104
isTopLevelExpr(this)
@@ -76,27 +108,28 @@ module Closure {
76108
/**
77109
* A top-level call to `goog.provide`.
78110
*/
79-
class ClosureProvideCall extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureProvideCall
111+
deprecated class ClosureProvideCall extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureProvideCall
80112
{ }
81113

82114
/**
83115
* A call to `goog.require`.
84116
*/
85-
private class DefaultClosureRequireCall extends DefaultNamespaceRef, ClosureNamespaceAccess::Range
117+
deprecated private class DefaultClosureRequireCall extends DefaultNamespaceRef,
118+
ClosureNamespaceAccess::Range
86119
{
87120
DefaultClosureRequireCall() { this.getMethodName() = "require" }
88121
}
89122

90123
/**
91124
* A call to `goog.require`.
92125
*/
93-
class ClosureRequireCall extends ClosureNamespaceAccess, DataFlow::MethodCallNode instanceof DefaultClosureRequireCall
126+
deprecated class ClosureRequireCall extends ClosureNamespaceAccess, DataFlow::MethodCallNode instanceof DefaultClosureRequireCall
94127
{ }
95128

96129
/**
97130
* A top-level call to `goog.module` or `goog.declareModuleId`.
98131
*/
99-
private class DefaultClosureModuleDeclaration extends DefaultNamespaceRef {
132+
deprecated private class DefaultClosureModuleDeclaration extends DefaultNamespaceRef {
100133
DefaultClosureModuleDeclaration() {
101134
(this.getMethodName() = "module" or this.getMethodName() = "declareModuleId") and
102135
isTopLevelExpr(this)
@@ -106,41 +139,29 @@ module Closure {
106139
/**
107140
* A top-level call to `goog.module` or `goog.declareModuleId`.
108141
*/
109-
class ClosureModuleDeclaration extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureModuleDeclaration
142+
deprecated class ClosureModuleDeclaration extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureModuleDeclaration
110143
{ }
111144

112-
private GlobalVariable googVariable() { variables(result, "goog", any(GlobalScope sc)) }
113-
114-
pragma[nomagic]
115-
private MethodCallExpr googModuleDeclExpr() {
116-
result.getReceiver() = googVariable().getAnAccess() and
117-
result.getMethodName() = ["module", "declareModuleId"]
118-
}
119-
120-
pragma[nomagic]
121-
private MethodCallExpr googModuleDeclExprInContainer(StmtContainer container) {
122-
result = googModuleDeclExpr() and
123-
container = result.getContainer()
124-
}
125-
126145
pragma[noinline]
127-
private ClosureRequireCall getARequireInTopLevel(ClosureModule m) { result.getTopLevel() = m }
146+
private RequireCallExpr getARequireInTopLevel(ClosureModule m) { result.getTopLevel() = m }
128147

129148
/**
130149
* A module using the Closure module system, declared using `goog.module()` or `goog.declareModuleId()`.
131150
*/
132151
class ClosureModule extends Module {
133-
ClosureModule() { exists(googModuleDeclExprInContainer(this)) }
152+
private ModuleDeclarationCall decl;
153+
154+
ClosureModule() { decl.getTopLevel() = this }
134155

135156
/**
136157
* Gets the call to `goog.module` or `goog.declareModuleId` in this module.
137158
*/
138-
ClosureModuleDeclaration getModuleDeclaration() { result.getTopLevel() = this }
159+
deprecated ClosureModuleDeclaration getModuleDeclaration() { result.getTopLevel() = this }
139160

140161
/**
141162
* Gets the namespace of this module.
142163
*/
143-
string getClosureNamespace() { result = this.getModuleDeclaration().getClosureNamespace() }
164+
string getClosureNamespace() { result = decl.getClosureNamespace() }
144165

145166
override Module getAnImportedModule() {
146167
result.(ClosureModule).getClosureNamespace() =
@@ -156,7 +177,7 @@ module Closure {
156177
* Has no result for ES6 modules using `goog.declareModuleId`.
157178
*/
158179
Variable getExportsVariable() {
159-
this.getModuleDeclaration().getMethodName() = "module" and
180+
decl.getModuleKind() = "goog.module" and
160181
result = this.getScope().getVariable("exports")
161182
}
162183

@@ -185,23 +206,23 @@ module Closure {
185206
ClosureScript() {
186207
not this instanceof ClosureModule and
187208
(
188-
any(ClosureProvideCall provide).getTopLevel() = this
209+
any(ProvideCallExpr provide).getTopLevel() = this
189210
or
190-
any(ClosureRequireCall require).getTopLevel() = this
211+
any(RequireCallExpr require).getTopLevel() = this
191212
)
192213
}
193214

194215
/** Gets the identifier of a namespace required by this module. */
195216
string getARequiredNamespace() {
196-
exists(ClosureRequireCall require |
217+
exists(RequireCallExpr require |
197218
require.getTopLevel() = this and
198219
result = require.getClosureNamespace()
199220
)
200221
}
201222

202223
/** Gets the identifer of a namespace provided by this module. */
203224
string getAProvidedNamespace() {
204-
exists(ClosureProvideCall require |
225+
exists(ProvideCallExpr require |
205226
require.getTopLevel() = this and
206227
result = require.getClosureNamespace()
207228
)
@@ -213,7 +234,13 @@ module Closure {
213234
*/
214235
pragma[noinline]
215236
predicate isClosureNamespace(string name) {
216-
exists(string namespace | namespace = any(ClosureNamespaceRef ref).getClosureNamespace() |
237+
exists(string namespace |
238+
namespace =
239+
[
240+
any(RequireCallExpr ref).getClosureNamespace(),
241+
any(ModuleDeclarationCall c).getClosureNamespace()
242+
]
243+
|
217244
name = namespace.substring(0, namespace.indexOf("."))
218245
or
219246
name = namespace

javascript/ql/lib/semmle/javascript/GlobalAccessPaths.qll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ module AccessPath {
3434
not this.accessesGlobal(_) and
3535
not this instanceof DataFlow::PropRead and
3636
not this instanceof PropertyProjection and
37-
not this instanceof Closure::ClosureNamespaceAccess and
37+
not this.asExpr() instanceof Closure::RequireCallExpr and
3838
not this = DataFlow::parameterNode(any(ImmediatelyInvokedFunctionExpr iife).getAParameter()) and
3939
not FlowSteps::identityFunctionStep(_, this)
4040
}
@@ -139,8 +139,8 @@ module AccessPath {
139139
result = join(fromReference(prop.getBase(), root), "[number]")
140140
)
141141
or
142-
exists(Closure::ClosureNamespaceAccess acc | node = acc |
143-
result = acc.getClosureNamespace() and
142+
exists(Closure::RequireCallExpr req | node = req.flow() |
143+
result = req.getClosureNamespace() and
144144
root.isGlobal()
145145
)
146146
or

0 commit comments

Comments
 (0)