Skip to content

Commit 4d4055a

Browse files
authored
Merge pull request #1163 from xiemaisi/js/more-type-tracking
Approved by asger-semmle
2 parents 885df87 + 3e16d16 commit 4d4055a

File tree

21 files changed

+655
-588
lines changed

21 files changed

+655
-588
lines changed

javascript/ql/src/semmle/javascript/AMD.qll

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -170,20 +170,19 @@ class AMDModuleDefinition extends CallExpr {
170170
}
171171
}
172172

173-
/** A path expression appearing in the list of dependencies of an AMD module. */
174-
private class AMDDependencyPath extends PathExprInModule, ConstantString {
175-
AMDDependencyPath() {
176-
exists(AMDModuleDefinition amd | this.getParentExpr*() = amd.getDependencies().getAnElement())
173+
/** An AMD dependency, considered as a path expression. */
174+
private class AmdDependencyPath extends PathExprCandidate {
175+
AmdDependencyPath() {
176+
exists(AMDModuleDefinition amd |
177+
this = amd.getDependencies().getAnElement() or
178+
this = amd.getARequireCall().getAnArgument()
179+
)
177180
}
178-
179-
override string getValue() { result = this.(ConstantString).getStringValue() }
180181
}
181182

182-
/** A path expression appearing in a `require` call in an AMD module. */
183-
private class AMDRequirePath extends PathExprInModule, ConstantString {
184-
AMDRequirePath() {
185-
exists(AMDModuleDefinition amd | this.getParentExpr*() = amd.getARequireCall().getAnArgument())
186-
}
183+
/** A constant path element appearing in an AMD dependency expression. */
184+
private class ConstantAmdDependencyPathElement extends PathExprInModule, ConstantString {
185+
ConstantAmdDependencyPathElement() { this = any(AmdDependencyPath amd).getAPart() }
187186

188187
override string getValue() { result = this.(ConstantString).getStringValue() }
189188
}

javascript/ql/src/semmle/javascript/Closure.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ module Closure {
6464
* a top-level expression statement.
6565
*/
6666
private predicate isTopLevelExpr(DataFlow::Node node) {
67-
node.getTopLevel().getAChildStmt().(ExprStmt).getExpr().flow() = node
67+
any(TopLevel tl).getAChildStmt().(ExprStmt).getExpr().flow() = node
6868
}
6969

7070
/**

javascript/ql/src/semmle/javascript/NodeJS.qll

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -239,22 +239,22 @@ class Require extends CallExpr, Import {
239239
}
240240
}
241241

242-
/** A literal path expression appearing in a `require` import. */
243-
private class LiteralRequiredPath extends PathExprInModule, ConstantString {
244-
LiteralRequiredPath() { exists(Require req | this.getParentExpr*() = req.getArgument(0)) }
245-
246-
override string getValue() { result = this.getStringValue() }
247-
}
248-
249-
/** A literal path expression appearing in a call to `require.resolve`. */
250-
private class LiteralRequireResolvePath extends PathExprInModule, ConstantString {
251-
LiteralRequireResolvePath() {
242+
/** An argument to `require` or `require.resolve`, considered as a path expression. */
243+
private class RequirePath extends PathExprCandidate {
244+
RequirePath() {
245+
this = any(Require req).getArgument(0)
246+
or
252247
exists(RequireVariable req, MethodCallExpr reqres |
253248
reqres.getReceiver() = req.getAnAccess() and
254249
reqres.getMethodName() = "resolve" and
255-
this.getParentExpr*() = reqres.getArgument(0)
250+
this = reqres.getArgument(0)
256251
)
257252
}
253+
}
254+
255+
/** A constant path element appearing in a call to `require` or `require.resolve`. */
256+
private class ConstantRequirePathElement extends PathExprInModule, ConstantString {
257+
ConstantRequirePathElement() { this = any(RequirePath rp).getAPart() }
258258

259259
override string getValue() { result = this.getStringValue() }
260260
}

javascript/ql/src/semmle/javascript/Paths.qll

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,3 +236,20 @@ private class ConcatPath extends PathExpr {
236236
result = this.(AddExpr).getAnOperand().(PathExpr).getSearchRoot(priority)
237237
}
238238
}
239+
240+
/**
241+
* An expression that appears in a syntactic position where it may represent a path.
242+
*
243+
* Examples include arguments to the CommonJS `require` function or AMD dependency arguments.
244+
*/
245+
abstract class PathExprCandidate extends Expr {
246+
/**
247+
* Gets an expression that is nested inside this expression.
248+
*
249+
* Equivalent to `getAChildExpr*()`, but useful to enforce a better join order (in spite of
250+
* what the optimizer thinks, there are generally far fewer `PathExprCandidate`s than
251+
* `ConstantString`s).
252+
*/
253+
pragma[nomagic]
254+
Expr getAPart() { result = this or result = getAPart().getAChildExpr() }
255+
}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,11 @@ class SourceNode extends DataFlow::Node {
162162
*
163163
* See `TypeTracker` for more details about how to use this.
164164
*/
165+
pragma[inline]
165166
DataFlow::SourceNode track(TypeTracker t2, TypeTracker t) {
166167
exists(StepSummary summary |
167168
StepSummary::step(this, result, summary) and
168-
t = StepSummary::append(t2, summary)
169+
t = t2.append(summary)
169170
)
170171
}
171172

@@ -176,10 +177,11 @@ class SourceNode extends DataFlow::Node {
176177
*
177178
* See `TypeBackTracker` for more details about how to use this.
178179
*/
180+
pragma[inline]
179181
DataFlow::SourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) {
180182
exists(StepSummary summary |
181183
StepSummary::step(result, this, summary) and
182-
t = StepSummary::prepend(summary, t2)
184+
t = t2.prepend(summary)
183185
)
184186
}
185187
}

0 commit comments

Comments
 (0)