Skip to content

Commit 23e42c8

Browse files
committed
JS: Overlay annotations for AST layer
1 parent 467bd54 commit 23e42c8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+615
-21
lines changed

javascript/ql/lib/Expressions/ExprHasNoEffect.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/**
22
* Provides classes and predicates for the 'js/useless-expression' query.
33
*/
4+
overlay[local]
5+
module;
46

57
import javascript
68
import DOMProperties
@@ -60,6 +62,7 @@ predicate isDeclaration(Expr e) {
6062
/**
6163
* Holds if there exists a getter for a property called `name` anywhere in the program.
6264
*/
65+
overlay[global]
6366
predicate isGetterProperty(string name) {
6467
// there is a call of the form `Object.defineProperty(..., name, descriptor)` ...
6568
exists(CallToObjectDefineProperty defProp | name = defProp.getPropertyName() |
@@ -85,6 +88,7 @@ predicate isGetterProperty(string name) {
8588
/**
8689
* A property access that may invoke a getter.
8790
*/
91+
overlay[global]
8892
class GetterPropertyAccess extends PropAccess {
8993
override predicate isImpure() { isGetterProperty(this.getPropertyName()) }
9094
}
@@ -123,6 +127,7 @@ predicate isReceiverSuppressingCall(CallExpr c, Expr dummy, PropAccess callee) {
123127
* even if they do, the call itself is useless and should be flagged by this
124128
* query.
125129
*/
130+
overlay[global]
126131
predicate noSideEffects(Expr e) {
127132
e.isPure()
128133
or
@@ -148,6 +153,7 @@ predicate isCompoundExpression(Expr e) {
148153
/**
149154
* Holds if the expression `e` should be reported as having no effect.
150155
*/
156+
overlay[global]
151157
predicate hasNoEffect(Expr e) {
152158
noSideEffects(e) and
153159
inVoidContext(e) and

javascript/ql/lib/semmle/javascript/AMD.qll

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
* Provides classes for working with
33
* [Asynchronous Module Definitions](https://github.com/amdjs/amdjs-api/wiki/AMD).
44
*/
5+
overlay[local]
6+
module;
57

68
import javascript
79
private import semmle.javascript.internal.CachedStages
@@ -62,9 +64,11 @@ class AmdModuleDefinition extends CallExpr instanceof AmdModuleDefinition::Range
6264
}
6365

6466
/** DEPRECATED. Use `getDependencyExpr` instead. */
67+
overlay[global]
6568
deprecated PathExpr getDependency(int i) { result = this.getDependencyExpr(i) }
6669

6770
/** DEPRECATED. Use `getADependencyExpr` instead. */
71+
overlay[global]
6872
deprecated PathExpr getADependency() { result = this.getADependencyExpr() }
6973

7074
/** Gets the `i`th dependency of this module definition. */
@@ -194,16 +198,19 @@ class AmdModuleDefinition extends CallExpr instanceof AmdModuleDefinition::Range
194198
* Gets an abstract value representing one or more values that may flow
195199
* into this module's `module.exports` property.
196200
*/
201+
overlay[global]
197202
DefiniteAbstractValue getAModuleExportsValue() {
198203
result = [this.getAnImplicitExportsValue(), this.getAnExplicitExportsValue()]
199204
}
200205

206+
overlay[global]
201207
pragma[noinline, nomagic]
202208
private AbstractValue getAnImplicitExportsValue() {
203209
// implicit exports: anything that is returned from the factory function
204210
result = this.getModuleExpr().analyze().getAValue()
205211
}
206212

213+
overlay[global]
207214
pragma[noinline]
208215
private AbstractValue getAnExplicitExportsValue() {
209216
// explicit exports: anything assigned to `module.exports`
@@ -227,6 +234,7 @@ class AmdModuleDefinition extends CallExpr instanceof AmdModuleDefinition::Range
227234
private predicate isPseudoDependency(string s) { s = ["exports", "require", "module"] }
228235

229236
/** An AMD dependency, considered as a path expression. */
237+
overlay[global]
230238
private class AmdDependencyPath extends PathExprCandidate {
231239
AmdDependencyPath() {
232240
exists(AmdModuleDefinition amd |
@@ -239,6 +247,7 @@ private class AmdDependencyPath extends PathExprCandidate {
239247
}
240248

241249
/** A constant path element appearing in an AMD dependency expression. */
250+
overlay[global]
242251
deprecated private class ConstantAmdDependencyPathElement extends PathExpr, ConstantString {
243252
ConstantAmdDependencyPathElement() { this = any(AmdDependencyPath amd).getAPart() }
244253

@@ -281,6 +290,7 @@ private class AmdDependencyImport extends Import {
281290
* Specifically, we look for files whose absolute path ends with the imported path, possibly
282291
* adding well-known JavaScript file extensions like `.js`.
283292
*/
293+
overlay[global]
284294
private File guessTarget() {
285295
exists(FilePath imported, string abspath, string dirname, string basename |
286296
this.targetCandidate(result, abspath, imported, dirname, basename)
@@ -303,6 +313,7 @@ private class AmdDependencyImport extends Import {
303313
* Additionally, `abspath` is bound to the absolute path of `f`, `imported` to the imported path, and
304314
* `dirname` and `basename` to the dirname and basename (respectively) of `imported`.
305315
*/
316+
overlay[global]
306317
private predicate targetCandidate(
307318
File f, string abspath, FilePath imported, string dirname, string basename
308319
) {
@@ -316,10 +327,12 @@ private class AmdDependencyImport extends Import {
316327
/**
317328
* Gets the module whose absolute path matches this import, if there is only a single such module.
318329
*/
330+
overlay[global]
319331
private Module resolveByAbsolutePath() {
320332
result.getFile() = unique(File file | file = this.guessTarget())
321333
}
322334

335+
overlay[global]
323336
override Module getImportedModule() {
324337
result = super.getImportedModule()
325338
or
@@ -348,21 +361,20 @@ private class AmdDependencyImport extends Import {
348361
*/
349362
class AmdModule extends Module {
350363
cached
351-
AmdModule() {
352-
Stages::DataFlowStage::ref() and
353-
exists(unique(AmdModuleDefinition def | amdModuleTopLevel(def, this)))
354-
}
364+
AmdModule() { exists(unique(AmdModuleDefinition def | amdModuleTopLevel(def, this))) }
355365

356366
/** Gets the definition of this module. */
357367
AmdModuleDefinition getDefine() { amdModuleTopLevel(result, this) }
358368

369+
overlay[global]
359370
override DataFlow::Node getAnExportedValue(string name) {
360371
exists(DataFlow::PropWrite pwn | result = pwn.getRhs() |
361372
pwn.getBase().analyze().getAValue() = this.getDefine().getAModuleExportsValue() and
362373
name = pwn.getPropertyName()
363374
)
364375
}
365376

377+
overlay[global]
366378
override DataFlow::Node getABulkExportedNode() {
367379
// Assigned to `module.exports` via the factory's `module` parameter
368380
exists(AbstractModuleObject m, DataFlow::PropWrite write |

javascript/ql/lib/semmle/javascript/AST.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/**
22
* Provides classes for working with the AST-based representation of JavaScript programs.
33
*/
4+
overlay[local]
5+
module;
46

57
import javascript
68
private import internal.StmtContainers
@@ -470,6 +472,7 @@ module AST {
470472
*/
471473
class ValueNode extends AstNode, @dataflownode {
472474
/** Gets type inference results for this element. */
475+
overlay[global]
473476
DataFlow::AnalyzedNode analyze() { result = DataFlow::valueNode(this).analyze() }
474477

475478
/** Gets the data flow node associated with this program element. */
@@ -481,6 +484,7 @@ module AST {
481484
* This can be used to map an expression to the class it refers to, or
482485
* associate it with a named value coming from an dependency.
483486
*/
487+
overlay[global]
484488
ExprNameBindingNode getNameBinding() { result = this }
485489

486490
/**
@@ -490,6 +494,7 @@ module AST {
490494
* (according to the type system), or to associate it with a named type coming
491495
* from a dependency.
492496
*/
497+
overlay[global]
493498
TypeNameBindingNode getTypeBinding() { TypeResolution::valueHasType(this, result) }
494499
}
495500
}

javascript/ql/lib/semmle/javascript/CFG.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@
272272
* Note that the `import` statement as a whole is part of the CFG of the body, while its single
273273
* import specifier `x as y` forms part of the preamble.
274274
*/
275+
overlay[local]
276+
module;
275277

276278
import javascript
277279
private import internal.StmtContainers

javascript/ql/lib/semmle/javascript/Classes.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
* Class declarations and class expressions are modeled by (QL) classes `ClassDeclaration`
55
* and `ClassExpression`, respectively, which are both subclasses of `ClassDefinition`.
66
*/
7+
overlay[local]
8+
module;
79

810
import javascript
911

@@ -119,6 +121,7 @@ class ClassOrInterface extends @class_or_interface, TypeParameterized {
119121
*
120122
* Anonymous classes and interfaces do not have a canonical name.
121123
*/
124+
overlay[global]
122125
deprecated TypeName getTypeName() { result.getADefinition() = this }
123126

124127
/**
@@ -253,6 +256,7 @@ class ClassDefinition extends @class_definition, ClassOrInterface, AST::ValueNod
253256
/**
254257
* Gets the definition of the super class of this class, if it can be determined.
255258
*/
259+
overlay[global]
256260
ClassDefinition getSuperClassDefinition() {
257261
result = this.getSuperClass().analyze().getAValue().(AbstractClass).getClass()
258262
}
@@ -580,6 +584,7 @@ class MemberDeclaration extends @property, Documentable {
580584
int getMemberIndex() { properties(this, _, result, _, _) }
581585

582586
/** Holds if the name of this member is computed by an impure expression. */
587+
overlay[global]
583588
predicate hasImpureNameExpr() { this.isComputed() and this.getNameExpr().isImpure() }
584589

585590
/**

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/**
22
* Provides classes for working with the Closure-Library module system.
33
*/
4+
overlay[local]
5+
module;
46

57
import javascript
68

@@ -40,13 +42,15 @@ module Closure {
4042
/**
4143
* A reference to a Closure namespace.
4244
*/
45+
overlay[global]
4346
deprecated class ClosureNamespaceRef extends DataFlow::Node instanceof ClosureNamespaceRef::Range {
4447
/**
4548
* Gets the namespace being referenced.
4649
*/
4750
string getClosureNamespace() { result = super.getClosureNamespace() }
4851
}
4952

53+
overlay[global]
5054
deprecated module ClosureNamespaceRef {
5155
/**
5256
* A reference to a Closure namespace.
@@ -64,9 +68,11 @@ module Closure {
6468
/**
6569
* A data flow node that returns the value of a closure namespace.
6670
*/
71+
overlay[global]
6772
deprecated class ClosureNamespaceAccess extends ClosureNamespaceRef instanceof ClosureNamespaceAccess::Range
6873
{ }
6974

75+
overlay[global]
7076
deprecated module ClosureNamespaceAccess {
7177
/**
7278
* A data flow node that returns the value of a closure namespace.
@@ -79,6 +85,7 @@ module Closure {
7985
/**
8086
* A call to a method on the `goog.` namespace, as a closure reference.
8187
*/
88+
overlay[global]
8289
abstract deprecated private class DefaultNamespaceRef extends DataFlow::MethodCallNode,
8390
ClosureNamespaceRef::Range
8491
{
@@ -91,13 +98,15 @@ module Closure {
9198
* Holds if `node` is the data flow node corresponding to the expression in
9299
* a top-level expression statement.
93100
*/
101+
overlay[global]
94102
deprecated private predicate isTopLevelExpr(DataFlow::Node node) {
95103
any(TopLevel tl).getAChildStmt().(ExprStmt).getExpr().flow() = node
96104
}
97105

98106
/**
99107
* A top-level call to `goog.provide`.
100108
*/
109+
overlay[global]
101110
deprecated private class DefaultClosureProvideCall extends DefaultNamespaceRef {
102111
DefaultClosureProvideCall() {
103112
this.getMethodName() = "provide" and
@@ -108,12 +117,14 @@ module Closure {
108117
/**
109118
* A top-level call to `goog.provide`.
110119
*/
120+
overlay[global]
111121
deprecated class ClosureProvideCall extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureProvideCall
112122
{ }
113123

114124
/**
115125
* A call to `goog.require`.
116126
*/
127+
overlay[global]
117128
deprecated private class DefaultClosureRequireCall extends DefaultNamespaceRef,
118129
ClosureNamespaceAccess::Range
119130
{
@@ -123,12 +134,14 @@ module Closure {
123134
/**
124135
* A call to `goog.require`.
125136
*/
137+
overlay[global]
126138
deprecated class ClosureRequireCall extends ClosureNamespaceAccess, DataFlow::MethodCallNode instanceof DefaultClosureRequireCall
127139
{ }
128140

129141
/**
130142
* A top-level call to `goog.module` or `goog.declareModuleId`.
131143
*/
144+
overlay[global]
132145
deprecated private class DefaultClosureModuleDeclaration extends DefaultNamespaceRef {
133146
DefaultClosureModuleDeclaration() {
134147
(this.getMethodName() = "module" or this.getMethodName() = "declareModuleId") and
@@ -139,6 +152,7 @@ module Closure {
139152
/**
140153
* A top-level call to `goog.module` or `goog.declareModuleId`.
141154
*/
155+
overlay[global]
142156
deprecated class ClosureModuleDeclaration extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureModuleDeclaration
143157
{ }
144158

@@ -156,6 +170,7 @@ module Closure {
156170
/**
157171
* Gets the call to `goog.module` or `goog.declareModuleId` in this module.
158172
*/
173+
overlay[global]
159174
deprecated ClosureModuleDeclaration getModuleDeclaration() { result.getTopLevel() = this }
160175

161176
/**
@@ -181,6 +196,7 @@ module Closure {
181196
result = this.getScope().getVariable("exports")
182197
}
183198

199+
overlay[global]
184200
override DataFlow::Node getAnExportedValue(string name) {
185201
exists(DataFlow::PropWrite write, Expr base |
186202
result = write.getRhs() and
@@ -193,6 +209,7 @@ module Closure {
193209
)
194210
}
195211

212+
overlay[global]
196213
override DataFlow::Node getABulkExportedNode() {
197214
result = this.getExportsVariable().getAnAssignedExpr().flow()
198215
}
@@ -232,6 +249,7 @@ module Closure {
232249
/**
233250
* Holds if `name` is a closure namespace, including proper namespace prefixes.
234251
*/
252+
overlay[global]
235253
pragma[noinline]
236254
predicate isClosureNamespace(string name) {
237255
exists(string namespace |
@@ -253,6 +271,7 @@ module Closure {
253271
* Holds if a prefix of `name` is a closure namespace.
254272
*/
255273
bindingset[name]
274+
overlay[global]
256275
private predicate hasClosureNamespacePrefix(string name) {
257276
isClosureNamespace(name.substring(0, name.indexOf(".")))
258277
or
@@ -262,6 +281,7 @@ module Closure {
262281
/**
263282
* Gets the closure namespace path addressed by the given data flow node, if any.
264283
*/
284+
overlay[global]
265285
string getClosureNamespaceFromSourceNode(DataFlow::SourceNode node) {
266286
node = AccessPath::getAReferenceOrAssignmentTo(result) and
267287
hasClosureNamespacePrefix(result)
@@ -270,6 +290,7 @@ module Closure {
270290
/**
271291
* Gets the closure namespace path written to by the given property write, if any.
272292
*/
293+
overlay[global]
273294
string getWrittenClosureNamespace(DataFlow::PropWrite node) {
274295
node.getRhs() = AccessPath::getAnAssignmentTo(result) and
275296
hasClosureNamespacePrefix(result)
@@ -278,13 +299,15 @@ module Closure {
278299
/**
279300
* Gets a data flow node that refers to the given value exported from a Closure module.
280301
*/
302+
overlay[global]
281303
DataFlow::SourceNode moduleImport(string moduleName) {
282304
getClosureNamespaceFromSourceNode(result) = moduleName
283305
}
284306

285307
/**
286308
* A call to `goog.bind`, as a partial function invocation.
287309
*/
310+
overlay[global]
288311
private class BindCall extends DataFlow::PartialInvokeNode::Range, DataFlow::CallNode {
289312
BindCall() { this = moduleImport("goog.bind").getACall() }
290313

0 commit comments

Comments
 (0)