mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
JS: Overlay annotations for AST layer
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Provides classes and predicates for the 'js/useless-expression' query.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
import DOMProperties
|
||||
@@ -60,6 +62,7 @@ predicate isDeclaration(Expr e) {
|
||||
/**
|
||||
* Holds if there exists a getter for a property called `name` anywhere in the program.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate isGetterProperty(string name) {
|
||||
// there is a call of the form `Object.defineProperty(..., name, descriptor)` ...
|
||||
exists(CallToObjectDefineProperty defProp | name = defProp.getPropertyName() |
|
||||
@@ -85,6 +88,7 @@ predicate isGetterProperty(string name) {
|
||||
/**
|
||||
* A property access that may invoke a getter.
|
||||
*/
|
||||
overlay[global]
|
||||
class GetterPropertyAccess extends PropAccess {
|
||||
override predicate isImpure() { isGetterProperty(this.getPropertyName()) }
|
||||
}
|
||||
@@ -123,6 +127,7 @@ predicate isReceiverSuppressingCall(CallExpr c, Expr dummy, PropAccess callee) {
|
||||
* even if they do, the call itself is useless and should be flagged by this
|
||||
* query.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate noSideEffects(Expr e) {
|
||||
e.isPure()
|
||||
or
|
||||
@@ -148,6 +153,7 @@ predicate isCompoundExpression(Expr e) {
|
||||
/**
|
||||
* Holds if the expression `e` should be reported as having no effect.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate hasNoEffect(Expr e) {
|
||||
noSideEffects(e) and
|
||||
inVoidContext(e) and
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
* Provides classes for working with
|
||||
* [Asynchronous Module Definitions](https://github.com/amdjs/amdjs-api/wiki/AMD).
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
private import semmle.javascript.internal.CachedStages
|
||||
@@ -62,9 +64,11 @@ class AmdModuleDefinition extends CallExpr instanceof AmdModuleDefinition::Range
|
||||
}
|
||||
|
||||
/** DEPRECATED. Use `getDependencyExpr` instead. */
|
||||
overlay[global]
|
||||
deprecated PathExpr getDependency(int i) { result = this.getDependencyExpr(i) }
|
||||
|
||||
/** DEPRECATED. Use `getADependencyExpr` instead. */
|
||||
overlay[global]
|
||||
deprecated PathExpr getADependency() { result = this.getADependencyExpr() }
|
||||
|
||||
/** Gets the `i`th dependency of this module definition. */
|
||||
@@ -194,16 +198,19 @@ class AmdModuleDefinition extends CallExpr instanceof AmdModuleDefinition::Range
|
||||
* Gets an abstract value representing one or more values that may flow
|
||||
* into this module's `module.exports` property.
|
||||
*/
|
||||
overlay[global]
|
||||
DefiniteAbstractValue getAModuleExportsValue() {
|
||||
result = [this.getAnImplicitExportsValue(), this.getAnExplicitExportsValue()]
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
pragma[noinline, nomagic]
|
||||
private AbstractValue getAnImplicitExportsValue() {
|
||||
// implicit exports: anything that is returned from the factory function
|
||||
result = this.getModuleExpr().analyze().getAValue()
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
pragma[noinline]
|
||||
private AbstractValue getAnExplicitExportsValue() {
|
||||
// explicit exports: anything assigned to `module.exports`
|
||||
@@ -227,6 +234,7 @@ class AmdModuleDefinition extends CallExpr instanceof AmdModuleDefinition::Range
|
||||
private predicate isPseudoDependency(string s) { s = ["exports", "require", "module"] }
|
||||
|
||||
/** An AMD dependency, considered as a path expression. */
|
||||
overlay[global]
|
||||
private class AmdDependencyPath extends PathExprCandidate {
|
||||
AmdDependencyPath() {
|
||||
exists(AmdModuleDefinition amd |
|
||||
@@ -239,6 +247,7 @@ private class AmdDependencyPath extends PathExprCandidate {
|
||||
}
|
||||
|
||||
/** A constant path element appearing in an AMD dependency expression. */
|
||||
overlay[global]
|
||||
deprecated private class ConstantAmdDependencyPathElement extends PathExpr, ConstantString {
|
||||
ConstantAmdDependencyPathElement() { this = any(AmdDependencyPath amd).getAPart() }
|
||||
|
||||
@@ -281,6 +290,7 @@ private class AmdDependencyImport extends Import {
|
||||
* Specifically, we look for files whose absolute path ends with the imported path, possibly
|
||||
* adding well-known JavaScript file extensions like `.js`.
|
||||
*/
|
||||
overlay[global]
|
||||
private File guessTarget() {
|
||||
exists(FilePath imported, string abspath, string dirname, string basename |
|
||||
this.targetCandidate(result, abspath, imported, dirname, basename)
|
||||
@@ -303,6 +313,7 @@ private class AmdDependencyImport extends Import {
|
||||
* Additionally, `abspath` is bound to the absolute path of `f`, `imported` to the imported path, and
|
||||
* `dirname` and `basename` to the dirname and basename (respectively) of `imported`.
|
||||
*/
|
||||
overlay[global]
|
||||
private predicate targetCandidate(
|
||||
File f, string abspath, FilePath imported, string dirname, string basename
|
||||
) {
|
||||
@@ -316,10 +327,12 @@ private class AmdDependencyImport extends Import {
|
||||
/**
|
||||
* Gets the module whose absolute path matches this import, if there is only a single such module.
|
||||
*/
|
||||
overlay[global]
|
||||
private Module resolveByAbsolutePath() {
|
||||
result.getFile() = unique(File file | file = this.guessTarget())
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
override Module getImportedModule() {
|
||||
result = super.getImportedModule()
|
||||
or
|
||||
@@ -348,14 +361,12 @@ private class AmdDependencyImport extends Import {
|
||||
*/
|
||||
class AmdModule extends Module {
|
||||
cached
|
||||
AmdModule() {
|
||||
Stages::DataFlowStage::ref() and
|
||||
exists(unique(AmdModuleDefinition def | amdModuleTopLevel(def, this)))
|
||||
}
|
||||
AmdModule() { exists(unique(AmdModuleDefinition def | amdModuleTopLevel(def, this))) }
|
||||
|
||||
/** Gets the definition of this module. */
|
||||
AmdModuleDefinition getDefine() { amdModuleTopLevel(result, this) }
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::Node getAnExportedValue(string name) {
|
||||
exists(DataFlow::PropWrite pwn | result = pwn.getRhs() |
|
||||
pwn.getBase().analyze().getAValue() = this.getDefine().getAModuleExportsValue() and
|
||||
@@ -363,6 +374,7 @@ class AmdModule extends Module {
|
||||
)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::Node getABulkExportedNode() {
|
||||
// Assigned to `module.exports` via the factory's `module` parameter
|
||||
exists(AbstractModuleObject m, DataFlow::PropWrite write |
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Provides classes for working with the AST-based representation of JavaScript programs.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
private import internal.StmtContainers
|
||||
@@ -470,6 +472,7 @@ module AST {
|
||||
*/
|
||||
class ValueNode extends AstNode, @dataflownode {
|
||||
/** Gets type inference results for this element. */
|
||||
overlay[global]
|
||||
DataFlow::AnalyzedNode analyze() { result = DataFlow::valueNode(this).analyze() }
|
||||
|
||||
/** Gets the data flow node associated with this program element. */
|
||||
@@ -481,6 +484,7 @@ module AST {
|
||||
* This can be used to map an expression to the class it refers to, or
|
||||
* associate it with a named value coming from an dependency.
|
||||
*/
|
||||
overlay[global]
|
||||
ExprNameBindingNode getNameBinding() { result = this }
|
||||
|
||||
/**
|
||||
@@ -490,6 +494,7 @@ module AST {
|
||||
* (according to the type system), or to associate it with a named type coming
|
||||
* from a dependency.
|
||||
*/
|
||||
overlay[global]
|
||||
TypeNameBindingNode getTypeBinding() { TypeResolution::valueHasType(this, result) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,6 +272,8 @@
|
||||
* Note that the `import` statement as a whole is part of the CFG of the body, while its single
|
||||
* import specifier `x as y` forms part of the preamble.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
private import internal.StmtContainers
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* Class declarations and class expressions are modeled by (QL) classes `ClassDeclaration`
|
||||
* and `ClassExpression`, respectively, which are both subclasses of `ClassDefinition`.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
@@ -119,6 +121,7 @@ class ClassOrInterface extends @class_or_interface, TypeParameterized {
|
||||
*
|
||||
* Anonymous classes and interfaces do not have a canonical name.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated TypeName getTypeName() { result.getADefinition() = this }
|
||||
|
||||
/**
|
||||
@@ -253,6 +256,7 @@ class ClassDefinition extends @class_definition, ClassOrInterface, AST::ValueNod
|
||||
/**
|
||||
* Gets the definition of the super class of this class, if it can be determined.
|
||||
*/
|
||||
overlay[global]
|
||||
ClassDefinition getSuperClassDefinition() {
|
||||
result = this.getSuperClass().analyze().getAValue().(AbstractClass).getClass()
|
||||
}
|
||||
@@ -580,6 +584,7 @@ class MemberDeclaration extends @property, Documentable {
|
||||
int getMemberIndex() { properties(this, _, result, _, _) }
|
||||
|
||||
/** Holds if the name of this member is computed by an impure expression. */
|
||||
overlay[global]
|
||||
predicate hasImpureNameExpr() { this.isComputed() and this.getNameExpr().isImpure() }
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Provides classes for working with the Closure-Library module system.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
@@ -40,6 +42,7 @@ module Closure {
|
||||
/**
|
||||
* A reference to a Closure namespace.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class ClosureNamespaceRef extends DataFlow::Node instanceof ClosureNamespaceRef::Range {
|
||||
/**
|
||||
* Gets the namespace being referenced.
|
||||
@@ -47,6 +50,7 @@ module Closure {
|
||||
string getClosureNamespace() { result = super.getClosureNamespace() }
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
deprecated module ClosureNamespaceRef {
|
||||
/**
|
||||
* A reference to a Closure namespace.
|
||||
@@ -64,9 +68,11 @@ module Closure {
|
||||
/**
|
||||
* A data flow node that returns the value of a closure namespace.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class ClosureNamespaceAccess extends ClosureNamespaceRef instanceof ClosureNamespaceAccess::Range
|
||||
{ }
|
||||
|
||||
overlay[global]
|
||||
deprecated module ClosureNamespaceAccess {
|
||||
/**
|
||||
* A data flow node that returns the value of a closure namespace.
|
||||
@@ -79,6 +85,7 @@ module Closure {
|
||||
/**
|
||||
* A call to a method on the `goog.` namespace, as a closure reference.
|
||||
*/
|
||||
overlay[global]
|
||||
abstract deprecated private class DefaultNamespaceRef extends DataFlow::MethodCallNode,
|
||||
ClosureNamespaceRef::Range
|
||||
{
|
||||
@@ -91,6 +98,7 @@ module Closure {
|
||||
* Holds if `node` is the data flow node corresponding to the expression in
|
||||
* a top-level expression statement.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated private predicate isTopLevelExpr(DataFlow::Node node) {
|
||||
any(TopLevel tl).getAChildStmt().(ExprStmt).getExpr().flow() = node
|
||||
}
|
||||
@@ -98,6 +106,7 @@ module Closure {
|
||||
/**
|
||||
* A top-level call to `goog.provide`.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated private class DefaultClosureProvideCall extends DefaultNamespaceRef {
|
||||
DefaultClosureProvideCall() {
|
||||
this.getMethodName() = "provide" and
|
||||
@@ -108,12 +117,14 @@ module Closure {
|
||||
/**
|
||||
* A top-level call to `goog.provide`.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class ClosureProvideCall extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureProvideCall
|
||||
{ }
|
||||
|
||||
/**
|
||||
* A call to `goog.require`.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated private class DefaultClosureRequireCall extends DefaultNamespaceRef,
|
||||
ClosureNamespaceAccess::Range
|
||||
{
|
||||
@@ -123,12 +134,14 @@ module Closure {
|
||||
/**
|
||||
* A call to `goog.require`.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class ClosureRequireCall extends ClosureNamespaceAccess, DataFlow::MethodCallNode instanceof DefaultClosureRequireCall
|
||||
{ }
|
||||
|
||||
/**
|
||||
* A top-level call to `goog.module` or `goog.declareModuleId`.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated private class DefaultClosureModuleDeclaration extends DefaultNamespaceRef {
|
||||
DefaultClosureModuleDeclaration() {
|
||||
(this.getMethodName() = "module" or this.getMethodName() = "declareModuleId") and
|
||||
@@ -139,6 +152,7 @@ module Closure {
|
||||
/**
|
||||
* A top-level call to `goog.module` or `goog.declareModuleId`.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class ClosureModuleDeclaration extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureModuleDeclaration
|
||||
{ }
|
||||
|
||||
@@ -156,6 +170,7 @@ module Closure {
|
||||
/**
|
||||
* Gets the call to `goog.module` or `goog.declareModuleId` in this module.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated ClosureModuleDeclaration getModuleDeclaration() { result.getTopLevel() = this }
|
||||
|
||||
/**
|
||||
@@ -181,6 +196,7 @@ module Closure {
|
||||
result = this.getScope().getVariable("exports")
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::Node getAnExportedValue(string name) {
|
||||
exists(DataFlow::PropWrite write, Expr base |
|
||||
result = write.getRhs() and
|
||||
@@ -193,6 +209,7 @@ module Closure {
|
||||
)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::Node getABulkExportedNode() {
|
||||
result = this.getExportsVariable().getAnAssignedExpr().flow()
|
||||
}
|
||||
@@ -232,6 +249,7 @@ module Closure {
|
||||
/**
|
||||
* Holds if `name` is a closure namespace, including proper namespace prefixes.
|
||||
*/
|
||||
overlay[global]
|
||||
pragma[noinline]
|
||||
predicate isClosureNamespace(string name) {
|
||||
exists(string namespace |
|
||||
@@ -253,6 +271,7 @@ module Closure {
|
||||
* Holds if a prefix of `name` is a closure namespace.
|
||||
*/
|
||||
bindingset[name]
|
||||
overlay[global]
|
||||
private predicate hasClosureNamespacePrefix(string name) {
|
||||
isClosureNamespace(name.substring(0, name.indexOf(".")))
|
||||
or
|
||||
@@ -262,6 +281,7 @@ module Closure {
|
||||
/**
|
||||
* Gets the closure namespace path addressed by the given data flow node, if any.
|
||||
*/
|
||||
overlay[global]
|
||||
string getClosureNamespaceFromSourceNode(DataFlow::SourceNode node) {
|
||||
node = AccessPath::getAReferenceOrAssignmentTo(result) and
|
||||
hasClosureNamespacePrefix(result)
|
||||
@@ -270,6 +290,7 @@ module Closure {
|
||||
/**
|
||||
* Gets the closure namespace path written to by the given property write, if any.
|
||||
*/
|
||||
overlay[global]
|
||||
string getWrittenClosureNamespace(DataFlow::PropWrite node) {
|
||||
node.getRhs() = AccessPath::getAnAssignmentTo(result) and
|
||||
hasClosureNamespacePrefix(result)
|
||||
@@ -278,6 +299,7 @@ module Closure {
|
||||
/**
|
||||
* Gets a data flow node that refers to the given value exported from a Closure module.
|
||||
*/
|
||||
overlay[global]
|
||||
DataFlow::SourceNode moduleImport(string moduleName) {
|
||||
getClosureNamespaceFromSourceNode(result) = moduleName
|
||||
}
|
||||
@@ -285,6 +307,7 @@ module Closure {
|
||||
/**
|
||||
* A call to `goog.bind`, as a partial function invocation.
|
||||
*/
|
||||
overlay[global]
|
||||
private class BindCall extends DataFlow::PartialInvokeNode::Range, DataFlow::CallNode {
|
||||
BindCall() { this = moduleImport("goog.bind").getACall() }
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/** Provides classes for working with JavaScript comments. */
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Provides classes for working with expressions that evaluate to constant values.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
private import semmle.javascript.internal.CachedStages
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/** Provides classes and predicates for working with variable definitions and uses. */
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
@@ -231,6 +233,7 @@ class VarUse extends ControlFlowNode, @varref instanceof RValue {
|
||||
*
|
||||
* For global variables, each definition is considered to reach each use.
|
||||
*/
|
||||
overlay[global]
|
||||
VarDef getADef() {
|
||||
result = this.getSsaVariable().getDefinition().getAContributingVarDef() or
|
||||
result.getAVariable() = this.getVariable().(GlobalVariable)
|
||||
@@ -241,5 +244,6 @@ class VarUse extends ControlFlowNode, @varref instanceof RValue {
|
||||
*
|
||||
* This predicate is only defined for variables that can be SSA-converted.
|
||||
*/
|
||||
overlay[global]
|
||||
SsaVariable getSsaVariable() { result.getAUse() = this }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Provides classes for working with E4X.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/** Provides classes for working with ECMAScript 2015 modules. */
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
private import semmle.javascript.internal.CachedStages
|
||||
@@ -29,11 +31,13 @@ class ES2015Module extends Module {
|
||||
/** Gets an export declaration in this module. */
|
||||
ExportDeclaration getAnExport() { result.getTopLevel() = this }
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::Node getAnExportedValue(string name) {
|
||||
exists(ExportDeclaration ed | ed = this.getAnExport() and result = ed.getSourceNode(name))
|
||||
}
|
||||
|
||||
/** Holds if this module exports variable `v` under the name `name`. */
|
||||
overlay[global]
|
||||
predicate exportsAs(LexicalName v, string name) { this.getAnExport().exportsAs(v, name) }
|
||||
|
||||
override predicate isStrict() {
|
||||
@@ -50,6 +54,7 @@ class ES2015Module extends Module {
|
||||
* When a module has both named and `default` exports, the non-standard interpretation can lead to
|
||||
* ambiguities, so we only allow the standard interpretation in that case.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate hasBothNamedAndDefaultExports() {
|
||||
hasNamedExports(this) and
|
||||
hasDefaultExport(this)
|
||||
@@ -59,6 +64,7 @@ class ES2015Module extends Module {
|
||||
/**
|
||||
* Holds if `mod` contains one or more named export declarations other than `default`.
|
||||
*/
|
||||
overlay[global]
|
||||
private predicate hasNamedExports(ES2015Module mod) {
|
||||
mod.getAnExport().(ExportNamedDeclaration).getASpecifier().getExportedName() != "default"
|
||||
or
|
||||
@@ -71,6 +77,7 @@ private predicate hasNamedExports(ES2015Module mod) {
|
||||
/**
|
||||
* Holds if this module contains a default export.
|
||||
*/
|
||||
overlay[global]
|
||||
private predicate hasDefaultExport(ES2015Module mod) {
|
||||
// export default foo;
|
||||
mod.getAnExport() instanceof ExportDefaultDeclaration
|
||||
@@ -172,6 +179,7 @@ class ImportDeclaration extends Stmt, Import, @import_declaration {
|
||||
}
|
||||
|
||||
/** A literal path expression appearing in an `import` declaration. */
|
||||
overlay[global]
|
||||
deprecated private class LiteralImportPath extends PathExpr, ConstantString {
|
||||
LiteralImportPath() { exists(ImportDeclaration req | this = req.getChildExpr(-1)) }
|
||||
|
||||
@@ -198,6 +206,7 @@ deprecated private class LiteralImportPath extends PathExpr, ConstantString {
|
||||
*/
|
||||
class ImportSpecifier extends Expr, @import_specifier {
|
||||
/** Gets the import declaration in which this specifier appears. */
|
||||
overlay[global]
|
||||
ImportDeclaration getImportDeclaration() { result.getASpecifier() = this }
|
||||
|
||||
/** Gets the imported symbol; undefined for default and namespace import specifiers. */
|
||||
@@ -297,6 +306,7 @@ class BulkImportDeclaration extends ImportDeclaration {
|
||||
* import console, { log } from 'console';
|
||||
* ```
|
||||
*/
|
||||
overlay[global]
|
||||
class SelectiveImportDeclaration extends ImportDeclaration {
|
||||
SelectiveImportDeclaration() { not this instanceof BulkImportDeclaration }
|
||||
|
||||
@@ -330,9 +340,11 @@ class SelectiveImportDeclaration extends ImportDeclaration {
|
||||
*/
|
||||
abstract class ExportDeclaration extends Stmt, @export_declaration {
|
||||
/** Gets the module to which this export declaration belongs. */
|
||||
overlay[global]
|
||||
ES2015Module getEnclosingModule() { this = result.getAnExport() }
|
||||
|
||||
/** Holds if this export declaration exports variable `v` under the name `name`. */
|
||||
overlay[global]
|
||||
abstract predicate exportsAs(LexicalName v, string name);
|
||||
|
||||
/**
|
||||
@@ -356,6 +368,7 @@ abstract class ExportDeclaration extends Stmt, @export_declaration {
|
||||
* exports under the same name. In particular, its source node belongs
|
||||
* to module `a` or possibly to some other module from which `a` re-exports.
|
||||
*/
|
||||
overlay[global]
|
||||
abstract DataFlow::Node getSourceNode(string name);
|
||||
|
||||
/** Holds if is declared with the `type` keyword, so only types are exported. */
|
||||
@@ -407,11 +420,13 @@ class BulkReExportDeclaration extends ReExportDeclaration, @export_all_declarati
|
||||
/** Gets the name of the module from which this declaration re-exports. */
|
||||
override ConstantString getImportedPath() { result = this.getChildExpr(0) }
|
||||
|
||||
overlay[global]
|
||||
override predicate exportsAs(LexicalName v, string name) {
|
||||
this.getReExportedES2015Module().exportsAs(v, name) and
|
||||
not isShadowedFromBulkExport(this, name)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::Node getSourceNode(string name) {
|
||||
result = this.getReExportedES2015Module().getAnExport().getSourceNode(name)
|
||||
}
|
||||
@@ -430,6 +445,7 @@ class BulkReExportDeclaration extends ReExportDeclaration, @export_all_declarati
|
||||
* At runtime, the interface `X` will have been removed, so `X` is actually re-exported anyway,
|
||||
* but we ignore this subtlety.
|
||||
*/
|
||||
overlay[global]
|
||||
private predicate isShadowedFromBulkExport(BulkReExportDeclaration reExport, string name) {
|
||||
exists(ExportNamedDeclaration other | other.getTopLevel() = reExport.getEnclosingModule() |
|
||||
other.getAnExportedDecl().getName() = name
|
||||
@@ -452,6 +468,7 @@ class ExportDefaultDeclaration extends ExportDeclaration, @export_default_declar
|
||||
/** Gets the operand statement or expression that is exported by this declaration. */
|
||||
ExprOrStmt getOperand() { result = this.getChild(0) }
|
||||
|
||||
overlay[global]
|
||||
override predicate exportsAs(LexicalName v, string name) {
|
||||
name = "default" and v = this.getADecl().getVariable()
|
||||
}
|
||||
@@ -464,6 +481,7 @@ class ExportDefaultDeclaration extends ExportDeclaration, @export_default_declar
|
||||
)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::Node getSourceNode(string name) {
|
||||
name = "default" and result = DataFlow::valueNode(this.getOperand())
|
||||
}
|
||||
@@ -506,6 +524,7 @@ class ExportNamedDeclaration extends ExportDeclaration, @export_named_declaratio
|
||||
/** Gets the variable declaration, if any, exported by this named export. */
|
||||
VarDecl getADecl() { result = this.getAnExportedDecl() }
|
||||
|
||||
overlay[global]
|
||||
override predicate exportsAs(LexicalName v, string name) {
|
||||
exists(LexicalDecl vd | vd = this.getAnExportedDecl() |
|
||||
name = vd.getName() and v = vd.getALexicalName()
|
||||
@@ -518,6 +537,7 @@ class ExportNamedDeclaration extends ExportDeclaration, @export_named_declaratio
|
||||
)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::Node getSourceNode(string name) {
|
||||
exists(VarDef d | d.getTarget() = this.getADecl() |
|
||||
name = d.getTarget().(VarDecl).getName() and
|
||||
@@ -555,6 +575,7 @@ class ExportNamedDeclaration extends ExportDeclaration, @export_named_declaratio
|
||||
|
||||
private import semmle.javascript.dataflow.internal.PreCallGraphStep
|
||||
|
||||
overlay[global]
|
||||
private class ExportNamespaceStep extends PreCallGraphStep {
|
||||
override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||
exists(ExportNamedDeclaration exprt, ExportNamespaceSpecifier spec |
|
||||
@@ -572,6 +593,7 @@ private class ExportNamespaceStep extends PreCallGraphStep {
|
||||
private class TypeOnlyExportDeclaration extends ExportNamedDeclaration {
|
||||
TypeOnlyExportDeclaration() { this.isTypeOnly() }
|
||||
|
||||
overlay[global]
|
||||
override predicate exportsAs(LexicalName v, string name) {
|
||||
super.exportsAs(v, name) and
|
||||
not v instanceof Variable
|
||||
@@ -745,9 +767,11 @@ abstract class ReExportDeclaration extends ExportDeclaration {
|
||||
abstract ConstantString getImportedPath();
|
||||
|
||||
/** Gets the module from which this declaration re-exports, if it is an ES2015 module. */
|
||||
overlay[global]
|
||||
ES2015Module getReExportedES2015Module() { result = this.getReExportedModule() }
|
||||
|
||||
/** Gets the module from which this declaration re-exports. */
|
||||
overlay[global]
|
||||
cached
|
||||
Module getReExportedModule() {
|
||||
Stages::Imports::ref() and
|
||||
@@ -756,6 +780,7 @@ abstract class ReExportDeclaration extends ExportDeclaration {
|
||||
}
|
||||
|
||||
/** A literal path expression appearing in a re-export declaration. */
|
||||
overlay[global]
|
||||
deprecated private class LiteralReExportPath extends PathExpr, ConstantString {
|
||||
LiteralReExportPath() { exists(ReExportDeclaration bred | this = bred.getImportedPath()) }
|
||||
|
||||
@@ -795,11 +820,13 @@ class SelectiveReExportDeclaration extends ReExportDeclaration, ExportNamedDecla
|
||||
class OriginalExportDeclaration extends ExportDeclaration {
|
||||
OriginalExportDeclaration() { not this instanceof ReExportDeclaration }
|
||||
|
||||
overlay[global]
|
||||
override predicate exportsAs(LexicalName v, string name) {
|
||||
this.(ExportDefaultDeclaration).exportsAs(v, name) or
|
||||
this.(ExportNamedDeclaration).exportsAs(v, name)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::Node getSourceNode(string name) {
|
||||
result = this.(ExportDefaultDeclaration).getSourceNode(name) or
|
||||
result = this.(ExportNamedDeclaration).getSourceNode(name)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/** Provides classes for working with syntax errors. */
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Provides classes for working with expressions.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
private import semmle.javascript.internal.CachedStages
|
||||
@@ -115,12 +117,14 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode {
|
||||
string getStringValue() { Stages::Ast::ref() and result = getStringValue(this) }
|
||||
|
||||
/** Holds if this expression is impure, that is, its evaluation could have side effects. */
|
||||
overlay[global]
|
||||
predicate isImpure() { any() }
|
||||
|
||||
/**
|
||||
* Holds if this expression is pure, that is, its evaluation is guaranteed
|
||||
* to be side-effect free.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate isPure() { not this.isImpure() }
|
||||
|
||||
/**
|
||||
@@ -153,21 +157,25 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode {
|
||||
* Holds if this expression accesses the global variable `g`, either directly
|
||||
* or through the `window` object.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate accessesGlobal(string g) { this.flow().accessesGlobal(g) }
|
||||
|
||||
/**
|
||||
* Holds if this expression may evaluate to `s`.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate mayHaveStringValue(string s) { this.flow().mayHaveStringValue(s) }
|
||||
|
||||
/**
|
||||
* Holds if this expression may evaluate to `b`.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate mayHaveBooleanValue(boolean b) { this.flow().mayHaveBooleanValue(b) }
|
||||
|
||||
/**
|
||||
* Holds if this expression may refer to the initial value of parameter `p`.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate mayReferToParameter(Parameter p) { DataFlow::parameterNode(p).flowsToExpr(this) }
|
||||
|
||||
/**
|
||||
@@ -178,6 +186,7 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode {
|
||||
* Has no result if the expression is in a JavaScript file or in a TypeScript
|
||||
* file that was extracted without type information.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated Type getType() { ast_node_type(this, result) }
|
||||
|
||||
/**
|
||||
@@ -250,6 +259,7 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode {
|
||||
* Gets the data-flow node where exceptions thrown by this expression will
|
||||
* propagate if this expression causes an exception to be thrown.
|
||||
*/
|
||||
overlay[caller]
|
||||
pragma[inline]
|
||||
DataFlow::Node getExceptionTarget() {
|
||||
result = getCatchParameterFromStmt(this.getRawEnclosingStmt(this))
|
||||
@@ -301,6 +311,7 @@ class Identifier extends @identifier, ExprOrType {
|
||||
* ```
|
||||
*/
|
||||
class Label extends @label, Identifier, Expr {
|
||||
overlay[global]
|
||||
override predicate isImpure() { none() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Label" }
|
||||
@@ -330,6 +341,7 @@ class Literal extends @literal, Expr {
|
||||
*/
|
||||
string getRawValue() { literals(_, result, this) }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() { none() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Literal" }
|
||||
@@ -352,6 +364,7 @@ class ParExpr extends @par_expr, Expr {
|
||||
|
||||
override int getIntValue() { result = this.getExpression().getIntValue() }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() { this.getExpression().isImpure() }
|
||||
|
||||
override Expr getUnderlyingValue() { result = this.getExpression().getUnderlyingValue() }
|
||||
@@ -500,6 +513,7 @@ class RegExpLiteral extends @regexp_literal, Literal, RegExpParent {
|
||||
* ```
|
||||
*/
|
||||
class ThisExpr extends @this_expr, Expr {
|
||||
overlay[global]
|
||||
override predicate isImpure() { none() }
|
||||
|
||||
/**
|
||||
@@ -555,6 +569,7 @@ class ArrayExpr extends @array_expr, Expr {
|
||||
/** Holds if this array literal has an omitted element. */
|
||||
predicate hasOmittedElement() { this.elementIsOmitted(_) }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() { this.getAnElement().isImpure() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ArrayExpr" }
|
||||
@@ -597,6 +612,7 @@ class ObjectExpr extends @obj_expr, Expr {
|
||||
*/
|
||||
predicate hasTrailingComma() { this.getLastToken().getPreviousToken().getValue() = "," }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() { this.getAProperty().isImpure() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ObjectExpr" }
|
||||
@@ -664,6 +680,7 @@ class Property extends @property, Documentable {
|
||||
* Holds if this property is impure, that is, the evaluation of its name or
|
||||
* its initializer expression could have side effects.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate isImpure() {
|
||||
this.isComputed() and this.getNameExpr().isImpure()
|
||||
or
|
||||
@@ -826,6 +843,7 @@ class FunctionExpr extends @function_expr, Expr, Function {
|
||||
Stages::Ast::ref() and result = Expr.super.getContainer()
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() { none() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FunctionExpr" }
|
||||
@@ -846,6 +864,7 @@ class ArrowFunctionExpr extends @arrow_function_expr, Expr, Function {
|
||||
|
||||
override StmtContainer getEnclosingContainer() { result = Expr.super.getContainer() }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() { none() }
|
||||
|
||||
override Function getThisBinder() {
|
||||
@@ -877,6 +896,7 @@ class SeqExpr extends @seq_expr, Expr {
|
||||
/** Gets the last expression in this sequence. */
|
||||
Expr getLastOperand() { result = this.getOperand(this.getNumOperands() - 1) }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() { this.getAnOperand().isImpure() }
|
||||
|
||||
override Expr getUnderlyingValue() { result = this.getLastOperand().getUnderlyingValue() }
|
||||
@@ -906,6 +926,7 @@ class ConditionalExpr extends @conditional_expr, Expr {
|
||||
/** Gets either the 'then' or the 'else' expression of this conditional. */
|
||||
Expr getABranch() { result = this.getConsequent() or result = this.getAlternate() }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() {
|
||||
this.getCondition().isImpure() or
|
||||
this.getABranch().isImpure()
|
||||
@@ -985,6 +1006,7 @@ class InvokeExpr extends @invokeexpr, Expr {
|
||||
*
|
||||
* This predicate is an approximation, computed using only local data flow.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate hasOptionArgument(int i, string name, Expr value) {
|
||||
value = this.flow().(DataFlow::InvokeNode).getOptionArgument(i, name).asExpr()
|
||||
}
|
||||
@@ -997,6 +1019,7 @@ class InvokeExpr extends @invokeexpr, Expr {
|
||||
*
|
||||
* This predicate is only populated for files extracted with full TypeScript extraction.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated CallSignatureType getResolvedSignature() { invoke_expr_signature(this, result) }
|
||||
|
||||
/**
|
||||
@@ -1014,6 +1037,7 @@ class InvokeExpr extends @invokeexpr, Expr {
|
||||
*
|
||||
* This predicate is only populated for files extracted with full TypeScript extraction.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated CanonicalFunctionName getResolvedCalleeName() { ast_node_symbol(this, result) }
|
||||
|
||||
/**
|
||||
@@ -1022,6 +1046,7 @@ class InvokeExpr extends @invokeexpr, Expr {
|
||||
* Note that the resolved function may be overridden in a subclass and thus is not
|
||||
* necessarily the actual target of this invocation at runtime.
|
||||
*/
|
||||
overlay[global]
|
||||
Function getResolvedCallee() { TypeResolution::callTarget(this, result) }
|
||||
}
|
||||
|
||||
@@ -1156,6 +1181,7 @@ class DotExpr extends @dot_expr, PropAccess {
|
||||
/** Gets the identifier specifying the name of the accessed property. */
|
||||
Identifier getProperty() { result = this.getChildExpr(1) }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() { this.getBase().isImpure() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "DotExpr" }
|
||||
@@ -1176,6 +1202,7 @@ class IndexExpr extends @index_expr, PropAccess {
|
||||
|
||||
override string getPropertyName() { result = this.getIndex().(Literal).getValue() }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() {
|
||||
this.getBase().isImpure() or
|
||||
this.getIndex().isImpure()
|
||||
@@ -1201,6 +1228,7 @@ class UnaryExpr extends @unaryexpr, Expr {
|
||||
/** Gets the operator of this expression. */
|
||||
string getOperator() { none() }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() { this.getOperand().isImpure() }
|
||||
|
||||
override ControlFlowNode getFirstControlFlowNode() {
|
||||
@@ -1302,6 +1330,7 @@ class VoidExpr extends @void_expr, UnaryExpr {
|
||||
class DeleteExpr extends @delete_expr, UnaryExpr {
|
||||
override string getOperator() { result = "delete" }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() { any() }
|
||||
}
|
||||
|
||||
@@ -1352,6 +1381,7 @@ class BinaryExpr extends @binaryexpr, Expr {
|
||||
/** Gets the operator of this expression. */
|
||||
string getOperator() { none() }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() { this.getAnOperand().isImpure() }
|
||||
|
||||
override ControlFlowNode getFirstControlFlowNode() {
|
||||
@@ -2233,6 +2263,7 @@ class YieldExpr extends @yield_expr, Expr {
|
||||
/** Holds if this is a `yield*` expression. */
|
||||
predicate isDelegating() { is_delegating(this) }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() { any() }
|
||||
|
||||
override ControlFlowNode getFirstControlFlowNode() {
|
||||
@@ -2289,6 +2320,7 @@ class ComprehensionExpr extends @comprehension_expr, Expr {
|
||||
/** Gets the body expression of this comprehension. */
|
||||
Expr getBody() { result = this.getChildExpr(0) }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() {
|
||||
this.getABlock().isImpure() or
|
||||
this.getAFilter().isImpure() or
|
||||
@@ -2349,6 +2381,7 @@ class ComprehensionBlock extends @comprehension_block, Expr {
|
||||
/** Gets the domain over which this comprehension block iterates. */
|
||||
Expr getDomain() { result = this.getChildExpr(1) }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() {
|
||||
this.getIterator().isImpure() or
|
||||
this.getDomain().isImpure()
|
||||
@@ -2675,6 +2708,7 @@ class AwaitExpr extends @await_expr, Expr {
|
||||
/** Gets the operand of this `await` expression. */
|
||||
Expr getOperand() { result = this.getChildExpr(0) }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() { any() }
|
||||
|
||||
override ControlFlowNode getFirstControlFlowNode() {
|
||||
@@ -2698,6 +2732,7 @@ class AwaitExpr extends @await_expr, Expr {
|
||||
* ```
|
||||
*/
|
||||
class FunctionSentExpr extends @function_sent_expr, Expr {
|
||||
overlay[global]
|
||||
override predicate isImpure() { none() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "FunctionSentExpr" }
|
||||
@@ -2857,6 +2892,7 @@ class DynamicImportExpr extends @dynamic_import, Expr, Import {
|
||||
}
|
||||
|
||||
/** A literal path expression appearing in a dynamic import. */
|
||||
overlay[global]
|
||||
deprecated private class LiteralDynamicImportPath extends PathExpr, ConstantString {
|
||||
LiteralDynamicImportPath() {
|
||||
exists(DynamicImportExpr di | this.getParentExpr*() = di.getSource())
|
||||
@@ -2919,6 +2955,7 @@ class OptionalChainRoot extends ChainElem {
|
||||
* ```
|
||||
*/
|
||||
class ImportMetaExpr extends @import_meta_expr, Expr {
|
||||
overlay[global]
|
||||
override predicate isImpure() { none() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ImportMetaExpr" }
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
* Array.prototype.length;
|
||||
* </pre>
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/** Provides classes for working with files and folders. */
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
private import NodeModuleResolutionImpl
|
||||
@@ -33,12 +35,14 @@ module Folder = Impl::Folder;
|
||||
/** A folder. */
|
||||
class Folder extends Container, Impl::Folder {
|
||||
/** Gets the file or subfolder in this folder that has the given `name`, if any. */
|
||||
overlay[global]
|
||||
Container getChildContainer(string name) {
|
||||
result = this.getAChildContainer() and
|
||||
result.getBaseName() = name
|
||||
}
|
||||
|
||||
/** Gets the file in this folder that has the given `stem` and `extension`, if any. */
|
||||
overlay[global]
|
||||
File getFile(string stem, string extension) {
|
||||
result = this.getAChildContainer() and
|
||||
result.getStem() = stem and
|
||||
@@ -46,6 +50,7 @@ class Folder extends Container, Impl::Folder {
|
||||
}
|
||||
|
||||
/** Like `getFile` except `d.ts` is treated as a single extension. */
|
||||
overlay[global]
|
||||
private File getFileLongExtension(string stem, string extension) {
|
||||
not (stem.matches("%.d") and extension = "ts") and
|
||||
result = this.getFile(stem, extension)
|
||||
@@ -65,6 +70,7 @@ class Folder extends Container, Impl::Folder {
|
||||
*
|
||||
* HTML files will not be found by this method.
|
||||
*/
|
||||
overlay[global]
|
||||
File getJavaScriptFile(string stem) {
|
||||
result =
|
||||
min(int p, string ext |
|
||||
@@ -78,6 +84,7 @@ class Folder extends Container, Impl::Folder {
|
||||
* Gets an implementation file and/or a typings file from this folder that has the given `stem`.
|
||||
* This could be a single `.ts` file or a pair of `.js` and `.d.ts` files.
|
||||
*/
|
||||
overlay[global]
|
||||
File getJavaScriptFileOrTypings(string stem) {
|
||||
exists(File jsFile | jsFile = this.getJavaScriptFile(stem) |
|
||||
result = jsFile
|
||||
@@ -88,6 +95,7 @@ class Folder extends Container, Impl::Folder {
|
||||
}
|
||||
|
||||
/** Gets a subfolder contained in this folder. */
|
||||
overlay[global]
|
||||
Folder getASubFolder() { result = this.getAChildContainer() }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/** Provides classes for working with functions. */
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
@@ -434,11 +436,13 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine
|
||||
*
|
||||
* This predicate is only populated for files extracted with full TypeScript extraction.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated CanonicalFunctionName getCanonicalName() { ast_node_symbol(this, result) }
|
||||
|
||||
/**
|
||||
* Gets the call signature of this function, as determined by the TypeScript compiler, if any.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated CallSignatureType getCallSignature() { declared_function_signature(this, result) }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/** Provides classes for working with HTML documents. */
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
@@ -283,6 +285,7 @@ module HTML {
|
||||
/**
|
||||
* A path string arising from the `src` attribute of a `script` tag.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated private class ScriptSrcPath extends PathString {
|
||||
ScriptSrcPath() { scriptSrc(this, _) }
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/** Provides classes for working with JSDoc comments. */
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
private import semmle.javascript.internal.CachedStages
|
||||
@@ -627,6 +629,7 @@ module JSDoc {
|
||||
/**
|
||||
* A statement container which may declare JSDoc name aliases.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class Environment extends StmtContainer {
|
||||
/**
|
||||
* Gets the fully qualified name aliased by the given unqualified name
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Provides classes for working with JSON data.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Provides classes for working with JSX code.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* This information is only available for snapshots that have been extracted with
|
||||
* the `--extract-program-text` flag.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/** Provides classes for working with locations and program elements that have locations. */
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* ECMAScript 2015-style modules, and the older CommonJS and AMD-style
|
||||
* modules.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
private import semmle.javascript.internal.CachedStages
|
||||
@@ -23,9 +25,11 @@ abstract class Module extends TopLevel {
|
||||
Import getAnImport() { result.getTopLevel() = this }
|
||||
|
||||
/** Gets a module from which this module imports. */
|
||||
overlay[global]
|
||||
Module getAnImportedModule() { result = this.getAnImport().getImportedModule() }
|
||||
|
||||
/** Gets a symbol exported by this module. */
|
||||
overlay[global]
|
||||
string getAnExportedSymbol() { exists(this.getAnExportedValue(result)) }
|
||||
|
||||
/**
|
||||
@@ -39,12 +43,14 @@ abstract class Module extends TopLevel {
|
||||
* Symbols defined in another module that are re-exported by
|
||||
* this module are only sometimes considered.
|
||||
*/
|
||||
overlay[global]
|
||||
cached
|
||||
abstract DataFlow::Node getAnExportedValue(string name);
|
||||
|
||||
/**
|
||||
* Gets a value that is exported as the whole exports object of this module.
|
||||
*/
|
||||
overlay[global]
|
||||
cached
|
||||
DataFlow::Node getABulkExportedNode() { none() } // overridden in subclasses
|
||||
|
||||
@@ -55,6 +61,7 @@ abstract class Module extends TopLevel {
|
||||
* This can be used to determine which value a default-import will likely refer to,
|
||||
* as the interaction between different module types is not standardized.
|
||||
*/
|
||||
overlay[global]
|
||||
DataFlow::Node getDefaultOrBulkExport() {
|
||||
result = [this.getAnExportedValue("default"), this.getABulkExportedNode()]
|
||||
}
|
||||
@@ -69,6 +76,7 @@ abstract class Module extends TopLevel {
|
||||
* This predicate is not part of the public API, it is only exposed to allow
|
||||
* overriding by subclasses.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated predicate searchRoot(PathExpr path, Folder searchRoot, int priority) {
|
||||
path.getEnclosingModule() = this and
|
||||
priority = 0 and
|
||||
@@ -90,6 +98,7 @@ abstract class Module extends TopLevel {
|
||||
* resolves to a folder containing a main module (such as `index.js`), then
|
||||
* that file is the result.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated File resolve(PathExpr path) {
|
||||
path.getEnclosingModule() = this and
|
||||
(
|
||||
@@ -124,6 +133,7 @@ abstract class Import extends AstNode {
|
||||
abstract Module getEnclosingModule();
|
||||
|
||||
/** DEPRECATED. Use `getImportedPathExpr` instead. */
|
||||
overlay[global]
|
||||
deprecated PathExpr getImportedPath() { result = this.getImportedPathExpr() }
|
||||
|
||||
/** Gets the (unresolved) path that this import refers to. */
|
||||
@@ -138,6 +148,7 @@ abstract class Import extends AstNode {
|
||||
* Any externs module whose name exactly matches the imported
|
||||
* path is assumed to be a possible target of the import.
|
||||
*/
|
||||
overlay[global]
|
||||
Module resolveExternsImport() {
|
||||
result.isExterns() and result.getName() = this.getImportedPathString()
|
||||
}
|
||||
@@ -145,16 +156,19 @@ abstract class Import extends AstNode {
|
||||
/**
|
||||
* Gets the module the path of this import resolves to.
|
||||
*/
|
||||
overlay[global]
|
||||
Module resolveImportedPath() { result.getFile() = this.getImportedFile() }
|
||||
|
||||
/**
|
||||
* Gets the module the path of this import resolves to.
|
||||
*/
|
||||
overlay[global]
|
||||
File getImportedFile() { result = ImportPathResolver::resolveExpr(this.getImportedPathExpr()) }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Use `getImportedModule()` instead.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated Module resolveFromTypeScriptSymbol() {
|
||||
exists(CanonicalName symbol |
|
||||
ast_node_symbol(this, symbol) and
|
||||
@@ -170,6 +184,7 @@ abstract class Import extends AstNode {
|
||||
* behavior of Node.js imports, which prefer core modules such as `fs` over any
|
||||
* source module of the same name.
|
||||
*/
|
||||
overlay[global]
|
||||
cached
|
||||
Module getImportedModule() {
|
||||
Stages::Imports::ref() and
|
||||
@@ -210,6 +225,7 @@ abstract class Import extends AstNode {
|
||||
* in cases where it would cause ambiguity between named exports and properties
|
||||
* of a default export.
|
||||
*/
|
||||
overlay[global]
|
||||
final DataFlow::Node getImportedModuleNodeStrict() {
|
||||
result = this.getImportedModuleNode() and
|
||||
not (
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Provides classes for working with NPM module definitions and dependencies.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
private import NodeModuleResolutionImpl
|
||||
|
||||
@@ -17,6 +17,7 @@ private import semmle.javascript.dataflow.internal.DataFlowNode
|
||||
* process.stdout.write(fs.readFileSync(process.argv[i], 'utf8'));
|
||||
* ```
|
||||
*/
|
||||
overlay[local]
|
||||
class NodeModule extends Module {
|
||||
NodeModule() {
|
||||
is_module(this) and
|
||||
@@ -36,11 +37,13 @@ class NodeModule extends Module {
|
||||
* Gets an abstract value representing one or more values that may flow
|
||||
* into this module's `module.exports` property.
|
||||
*/
|
||||
overlay[global]
|
||||
pragma[noinline]
|
||||
DefiniteAbstractValue getAModuleExportsValue() {
|
||||
result = this.getAModuleExportsProperty().getAValue()
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
pragma[noinline]
|
||||
private AbstractProperty getAModuleExportsProperty() {
|
||||
result.getBase().(AbstractModuleObject).getModule() = this and
|
||||
@@ -52,12 +55,14 @@ class NodeModule extends Module {
|
||||
* For performance this predicate only computes relevant expressions (in `getAModuleExportsCandidate`).
|
||||
* So if using this predicate - consider expanding the list of relevant expressions.
|
||||
*/
|
||||
overlay[global]
|
||||
DataFlow::AnalyzedNode getAModuleExportsNode() {
|
||||
result = getAModuleExportsCandidate() and
|
||||
result.getAValue() = this.getAModuleExportsValue()
|
||||
}
|
||||
|
||||
/** Gets a symbol exported by this module. */
|
||||
overlay[global]
|
||||
override string getAnExportedSymbol() {
|
||||
result = super.getAnExportedSymbol()
|
||||
or
|
||||
@@ -70,6 +75,7 @@ class NodeModule extends Module {
|
||||
)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::Node getAnExportedValue(string name) {
|
||||
// a property write whose base is `exports` or `module.exports`
|
||||
exists(DataFlow::PropWrite pwn | result = pwn.getRhs() |
|
||||
@@ -114,6 +120,7 @@ class NodeModule extends Module {
|
||||
)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::Node getABulkExportedNode() {
|
||||
Stages::Imports::ref() and
|
||||
exists(DataFlow::PropWrite write |
|
||||
@@ -124,6 +131,7 @@ class NodeModule extends Module {
|
||||
}
|
||||
|
||||
/** Gets a symbol that the module object inherits from its prototypes. */
|
||||
overlay[global]
|
||||
private string getAnImplicitlyExportedSymbol() {
|
||||
exists(ExternalConstructor ec | ec = this.getPrototypeOfExportedExpr() |
|
||||
result = ec.getAMember().getName()
|
||||
@@ -136,6 +144,7 @@ class NodeModule extends Module {
|
||||
}
|
||||
|
||||
/** Gets an externs declaration of the prototype object of a value exported by this module. */
|
||||
overlay[global]
|
||||
private ExternalConstructor getPrototypeOfExportedExpr() {
|
||||
exists(AbstractValue exported | exported = this.getAModuleExportsValue() |
|
||||
result instanceof ObjectExternal
|
||||
@@ -146,6 +155,7 @@ class NodeModule extends Module {
|
||||
)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
deprecated override predicate searchRoot(PathExpr path, Folder searchRoot, int priority) {
|
||||
path.getEnclosingModule() = this and
|
||||
exists(string pathval | pathval = path.getValue() |
|
||||
@@ -224,6 +234,7 @@ predicate findNodeModulesFolder(Folder f, Folder nodeModules, int distance) {
|
||||
/**
|
||||
* A Node.js `require` variable.
|
||||
*/
|
||||
overlay[local]
|
||||
private class RequireVariable extends Variable {
|
||||
RequireVariable() {
|
||||
this = any(ModuleScope m).getVariable("require")
|
||||
@@ -236,6 +247,7 @@ private class RequireVariable extends Variable {
|
||||
}
|
||||
}
|
||||
|
||||
overlay[local]
|
||||
private predicate isModuleModule(EarlyStageNode nd) {
|
||||
exists(ImportDeclaration imp | imp.getRawImportPath() = "module" |
|
||||
nd = TDestructuredModuleImportNode(imp)
|
||||
@@ -249,6 +261,7 @@ private predicate isModuleModule(EarlyStageNode nd) {
|
||||
)
|
||||
}
|
||||
|
||||
overlay[local]
|
||||
private predicate isCreateRequire(EarlyStageNode nd) {
|
||||
exists(PropAccess prop |
|
||||
isModuleModule(TValueNode(prop.getBase())) and
|
||||
@@ -278,6 +291,7 @@ private predicate isCreateRequire(EarlyStageNode nd) {
|
||||
/**
|
||||
* Holds if `nd` may refer to `require`, either directly or modulo local data flow.
|
||||
*/
|
||||
overlay[local]
|
||||
cached
|
||||
private predicate isRequire(EarlyStageNode nd) {
|
||||
exists(VarAccess access |
|
||||
@@ -320,6 +334,7 @@ private predicate isRequire(EarlyStageNode nd) {
|
||||
* require('fs')
|
||||
* ```
|
||||
*/
|
||||
overlay[local]
|
||||
class Require extends CallExpr, Import {
|
||||
Require() { isRequire(TValueNode(this.getCallee())) }
|
||||
|
||||
|
||||
@@ -186,11 +186,13 @@ module Promises {
|
||||
/**
|
||||
* Gets the pseudo-field used to describe resolved values in a promise.
|
||||
*/
|
||||
overlay[local]
|
||||
string valueProp() { result = "$PromiseResolveField$" }
|
||||
|
||||
/**
|
||||
* Gets the pseudo-field used to describe rejected values in a promise.
|
||||
*/
|
||||
overlay[local]
|
||||
string errorProp() { result = "$PromiseRejectField$" }
|
||||
|
||||
/** A property set containing the pseudo-properites of a promise object. */
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* Regular expression literals are represented as an abstract syntax tree of regular expression
|
||||
* terms.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
private import semmle.javascript.dataflow.InferredTypes
|
||||
@@ -150,6 +152,7 @@ class RegExpTerm extends Locatable, @regexpterm {
|
||||
* /[a-z]+/g; // YES - Regexp literals are always used as regexp
|
||||
* ```
|
||||
*/
|
||||
overlay[global]
|
||||
predicate isUsedAsRegExp() {
|
||||
exists(RegExpParent parent | parent = this.getRootTerm().getParent() |
|
||||
parent instanceof RegExpLiteral
|
||||
@@ -964,6 +967,7 @@ class RegExpParseError extends Error, @regexp_parse_error {
|
||||
/**
|
||||
* Holds if `func` is a method defined on `String.prototype` with name `name`.
|
||||
*/
|
||||
overlay[global]
|
||||
private predicate isNativeStringMethod(Function func, string name) {
|
||||
exists(ExternalInstanceMemberDecl decl |
|
||||
decl.hasQualifiedName("String", name) and
|
||||
@@ -975,6 +979,7 @@ private predicate isNativeStringMethod(Function func, string name) {
|
||||
* Holds if `name` is the name of a property on a Match object returned by `String.prototype.match`,
|
||||
* not including array indices.
|
||||
*/
|
||||
overlay[global]
|
||||
private predicate isMatchObjectProperty(string name) {
|
||||
any(ExternalInstanceMemberDecl decl).hasQualifiedName("Array", name)
|
||||
or
|
||||
@@ -982,6 +987,7 @@ private predicate isMatchObjectProperty(string name) {
|
||||
}
|
||||
|
||||
/** Holds if `call` is a call to `match` whose result is used in a way that is incompatible with Match objects. */
|
||||
overlay[global]
|
||||
private predicate isUsedAsNonMatchObject(DataFlow::MethodCallNode call) {
|
||||
call.getMethodName() = ["match", "matchAll"] and
|
||||
call.getNumArgument() = 1 and
|
||||
@@ -1006,6 +1012,7 @@ private predicate isUsedAsNonMatchObject(DataFlow::MethodCallNode call) {
|
||||
/**
|
||||
* Holds if `value` is used in a way that suggests it returns a number.
|
||||
*/
|
||||
overlay[global]
|
||||
pragma[inline]
|
||||
private predicate isUsedAsNumber(DataFlow::LocalSourceNode value) {
|
||||
any(Comparison compare)
|
||||
@@ -1027,6 +1034,7 @@ private predicate isUsedAsNumber(DataFlow::LocalSourceNode value) {
|
||||
/**
|
||||
* Holds if `source` may be interpreted as a regular expression.
|
||||
*/
|
||||
overlay[global]
|
||||
cached
|
||||
predicate isInterpretedAsRegExp(DataFlow::Node source) {
|
||||
Stages::Taint::ref() and
|
||||
@@ -1073,6 +1081,7 @@ predicate isInterpretedAsRegExp(DataFlow::Node source) {
|
||||
* Gets a node whose value may flow (inter-procedurally) to `re`, where it is interpreted
|
||||
* as a part of a regular expression.
|
||||
*/
|
||||
overlay[global]
|
||||
private DataFlow::Node regExpSource(DataFlow::Node re, DataFlow::TypeBackTracker t) {
|
||||
t.start() and
|
||||
re = result and
|
||||
@@ -1090,6 +1099,7 @@ private DataFlow::Node regExpSource(DataFlow::Node re, DataFlow::TypeBackTracker
|
||||
* Gets a node whose value may flow (inter-procedurally) to `re`, where it is interpreted
|
||||
* as a part of a regular expression.
|
||||
*/
|
||||
overlay[global]
|
||||
private DataFlow::Node regExpSource(DataFlow::Node re) {
|
||||
result = regExpSource(re, DataFlow::TypeBackTracker::end())
|
||||
}
|
||||
@@ -1098,6 +1108,7 @@ private DataFlow::Node regExpSource(DataFlow::Node re) {
|
||||
* A node whose value may flow to a position where it is interpreted
|
||||
* as a part of a regular expression.
|
||||
*/
|
||||
overlay[global]
|
||||
abstract class RegExpPatternSource extends DataFlow::Node {
|
||||
/**
|
||||
* Gets a node where the pattern of this node is parsed as a part of
|
||||
@@ -1126,6 +1137,7 @@ abstract class RegExpPatternSource extends DataFlow::Node {
|
||||
/**
|
||||
* A regular expression literal, viewed as the pattern source for itself.
|
||||
*/
|
||||
overlay[global]
|
||||
private class RegExpLiteralPatternSource extends RegExpPatternSource, DataFlow::ValueNode {
|
||||
override RegExpLiteral astNode;
|
||||
|
||||
@@ -1145,6 +1157,7 @@ private class RegExpLiteralPatternSource extends RegExpPatternSource, DataFlow::
|
||||
* A node whose string value may flow to a position where it is interpreted
|
||||
* as a part of a regular expression.
|
||||
*/
|
||||
overlay[global]
|
||||
private class StringRegExpPatternSource extends RegExpPatternSource {
|
||||
DataFlow::Node parse;
|
||||
|
||||
@@ -1169,6 +1182,7 @@ private class StringRegExpPatternSource extends RegExpPatternSource {
|
||||
* A node whose string value may flow to a position where it is interpreted
|
||||
* as a part of a regular expression.
|
||||
*/
|
||||
overlay[global]
|
||||
private class StringConcatRegExpPatternSource extends RegExpPatternSource {
|
||||
DataFlow::Node parse;
|
||||
|
||||
@@ -1331,6 +1345,7 @@ module RegExp {
|
||||
/**
|
||||
* Gets the AST of a regular expression object that can flow to `node`.
|
||||
*/
|
||||
overlay[global]
|
||||
RegExpTerm getRegExpObjectFromNode(DataFlow::Node node) {
|
||||
exists(DataFlow::RegExpCreationNode regexp |
|
||||
regexp.getAReference().flowsTo(node) and
|
||||
@@ -1342,6 +1357,7 @@ module RegExp {
|
||||
* Gets the AST of a regular expression that can flow to `node`,
|
||||
* including `RegExp` objects as well as strings interpreted as regular expressions.
|
||||
*/
|
||||
overlay[global]
|
||||
RegExpTerm getRegExpFromNode(DataFlow::Node node) {
|
||||
result = getRegExpObjectFromNode(node)
|
||||
or
|
||||
|
||||
@@ -73,6 +73,8 @@
|
||||
* expression in `k` induces a re-capture of `x` to reflect the fact that `x`
|
||||
* is incremented between the two `console.log` calls.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
private import semmle.javascript.dataflow.Refinements
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/** Provides classes for working with statements. */
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/** Provides classes for working with ECMAScript 2015-style template expressions. */
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
@@ -58,6 +60,7 @@ class TemplateLiteral extends Expr, @template_literal {
|
||||
*/
|
||||
int getNumElement() { result = count(this.getAnElement()) }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() { this.getAnElement().isImpure() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TemplateLiteral" }
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Provides classes for working with the token-based representation of JavaScript programs.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Provides classes for reasoning about type annotations independently of dialect.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
private import internal.StmtContainers
|
||||
@@ -18,6 +20,7 @@ class TypeAnnotation extends @type_annotation, NodeInStmtContainer {
|
||||
* This can be used to map a type name to the class/interface it refers to, or
|
||||
* associate it with a named type coming from an dependency.
|
||||
*/
|
||||
overlay[global]
|
||||
TypeNameBindingNode getTypeBinding() { result = this }
|
||||
|
||||
/** Holds if this is the `any` type. */
|
||||
@@ -90,6 +93,7 @@ class TypeAnnotation extends @type_annotation, NodeInStmtContainer {
|
||||
*
|
||||
* Holds if this is a reference to the type with qualified name `globalName` relative to the global scope.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated predicate hasQualifiedName(string globalName) {
|
||||
UnderlyingTypes::nodeHasUnderlyingType(this, globalName)
|
||||
}
|
||||
@@ -99,6 +103,7 @@ class TypeAnnotation extends @type_annotation, NodeInStmtContainer {
|
||||
*
|
||||
* Holds if this is a reference to the type exported from `moduleName` under the name `exportedName`.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated predicate hasQualifiedName(string moduleName, string exportedName) {
|
||||
UnderlyingTypes::nodeHasUnderlyingType(this, moduleName, exportedName)
|
||||
}
|
||||
@@ -107,6 +112,7 @@ class TypeAnnotation extends @type_annotation, NodeInStmtContainer {
|
||||
* Holds if this is a reference to the type with qualified name `globalName` relative to the global scope,
|
||||
* or is declared as a subtype thereof, or is a union or intersection containing such a type.
|
||||
*/
|
||||
overlay[global]
|
||||
final predicate hasUnderlyingType(string globalName) {
|
||||
UnderlyingTypes::nodeHasUnderlyingType(this, globalName)
|
||||
}
|
||||
@@ -115,6 +121,7 @@ class TypeAnnotation extends @type_annotation, NodeInStmtContainer {
|
||||
* Holds if this is a reference to the type exported from `moduleName` under the name `exportedName`,
|
||||
* or is declared as a subtype thereof, or is a union or intersection containing such a type.
|
||||
*/
|
||||
overlay[global]
|
||||
final predicate hasUnderlyingType(string moduleName, string exportedName) {
|
||||
UnderlyingTypes::nodeHasUnderlyingType(this, moduleName, exportedName)
|
||||
}
|
||||
@@ -135,6 +142,7 @@ class TypeAnnotation extends @type_annotation, NodeInStmtContainer {
|
||||
*
|
||||
* Note that this has no result for JSDoc type annotations.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated Type getType() { none() }
|
||||
|
||||
/**
|
||||
@@ -142,5 +150,6 @@ class TypeAnnotation extends @type_annotation, NodeInStmtContainer {
|
||||
*
|
||||
* This unfolds nullability modifiers and generic type applications.
|
||||
*/
|
||||
overlay[global]
|
||||
final DataFlow::ClassNode getClass() { UnderlyingTypes::nodeHasUnderlyingClassType(this, result) }
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
/**
|
||||
@@ -31,6 +34,7 @@ class NamespaceDefinition extends Stmt, @namespace_definition, AST::ValueNode {
|
||||
/**
|
||||
* Gets the canonical name of the namespace being defined.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated Namespace getNamespace() { result.getADefinition() = this }
|
||||
}
|
||||
|
||||
@@ -111,11 +115,13 @@ class TypeDefinition extends AstNode, @type_definition {
|
||||
/**
|
||||
* Gets the canonical name of the type being defined.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated TypeName getTypeName() { result.getADefinition() = this }
|
||||
|
||||
/**
|
||||
* Gets the type defined by this declaration.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated Type getType() { ast_node_type(this.getIdentifier(), result) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TypeDefinition" }
|
||||
@@ -221,6 +227,7 @@ class ExternalModuleReference extends Expr, Import, @external_module_reference {
|
||||
}
|
||||
|
||||
/** A literal path expression appearing in an external module reference. */
|
||||
overlay[global]
|
||||
deprecated private class LiteralExternalModulePath extends PathExpr, ConstantString {
|
||||
LiteralExternalModulePath() {
|
||||
exists(ExternalModuleReference emr | this.getParentExpr*() = emr.getExpression())
|
||||
@@ -268,6 +275,7 @@ class TypeAliasDeclaration extends @type_alias_declaration, TypeParameterized, S
|
||||
/**
|
||||
* Gets the canonical name of the type being defined.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated TypeName getTypeName() { result.getADefinition() = this }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TypeAliasDeclaration" }
|
||||
@@ -548,6 +556,7 @@ class LocalNamespaceName extends @local_namespace_name, LexicalName {
|
||||
/**
|
||||
* Gets the canonical name of the namespace referenced by this name.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated Namespace getNamespace() { result = this.getADeclaration().getNamespace() }
|
||||
|
||||
override DeclarationSpace getDeclarationSpace() { result = "namespace" }
|
||||
@@ -568,6 +577,7 @@ class TypeExpr extends ExprOrType, @typeexpr, TypeAnnotation {
|
||||
* Has no result if this occurs in a TypeScript file that was extracted
|
||||
* without type information.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated override Type getType() { ast_node_type(this, result) }
|
||||
|
||||
override Stmt getEnclosingStmt() { result = ExprOrType.super.getEnclosingStmt() }
|
||||
@@ -692,6 +702,7 @@ class TypeAccess extends @typeaccess, TypeExpr, TypeRef {
|
||||
/**
|
||||
* Gets the canonical name of the type being accessed.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated TypeName getTypeName() { ast_node_symbol(this, result) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TypeAccess" }
|
||||
@@ -1379,6 +1390,7 @@ class LocalNamespaceDecl extends VarDecl, NamespaceRef {
|
||||
/**
|
||||
* Gets the canonical name of the namespace being defined or aliased by this name.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated Namespace getNamespace() { ast_node_symbol(this, result) }
|
||||
}
|
||||
|
||||
@@ -1397,6 +1409,7 @@ class NamespaceAccess extends TypeExpr, NamespaceRef, @namespace_access {
|
||||
/**
|
||||
* Gets the canonical name of the namespace being accessed.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated Namespace getNamespace() { ast_node_symbol(this, result) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NamespaceAccess" }
|
||||
@@ -1506,6 +1519,7 @@ class EnumDeclaration extends NamespaceDefinition, @enum_declaration, AST::Value
|
||||
/**
|
||||
* Gets the canonical name of the type being defined.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated TypeName getTypeName() { ast_node_symbol(this, result) }
|
||||
|
||||
/**
|
||||
@@ -1594,6 +1608,7 @@ class EnumMember extends AstNode, @enum_member {
|
||||
/**
|
||||
* Gets the canonical name of the type defined by this enum member.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated TypeName getTypeName() { ast_node_symbol(this, result) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "EnumMember" }
|
||||
@@ -1762,6 +1777,7 @@ class TypeRootFolder extends Folder {
|
||||
/**
|
||||
* Gets the priority with which this type root folder should be used from within the given search root.
|
||||
*/
|
||||
overlay[global]
|
||||
int getSearchPriority(Folder searchRoot) {
|
||||
findNodeModulesFolder(searchRoot, this.getNodeModulesFolder(), result)
|
||||
}
|
||||
@@ -1780,6 +1796,7 @@ class TypeRootFolder extends Folder {
|
||||
* For instance, there may be many AST nodes representing different uses of the
|
||||
* `number` keyword, but there only exists one `number` type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class Type extends @type {
|
||||
/**
|
||||
* Gets a string representation of this type.
|
||||
@@ -1984,6 +2001,7 @@ deprecated class Type extends @type {
|
||||
*
|
||||
* A union type or intersection type, such as `string | number` or `T & U`.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class UnionOrIntersectionType extends Type, @union_or_intersection_type {
|
||||
/**
|
||||
* Gets the `i`th member of this union or intersection, starting at 0.
|
||||
@@ -2012,6 +2030,7 @@ deprecated class UnionOrIntersectionType extends Type, @union_or_intersection_ty
|
||||
* Note that the `boolean` type is represented as the union `true | false`,
|
||||
* but is still displayed as `boolean` in string representations.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class UnionType extends UnionOrIntersectionType, @union_type { }
|
||||
|
||||
/**
|
||||
@@ -2022,6 +2041,7 @@ deprecated class UnionType extends UnionOrIntersectionType, @union_type { }
|
||||
*
|
||||
* An intersection type, such as `T & {x: number}`.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class IntersectionType extends UnionOrIntersectionType, @intersection_type { }
|
||||
|
||||
/**
|
||||
@@ -2040,6 +2060,7 @@ deprecated class IntersectionType extends UnionOrIntersectionType, @intersection
|
||||
* Foreign array-like objects such as `HTMLCollection` are not normal JavaScript arrays,
|
||||
* and their corresponding types are not considered array types either.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class ArrayType extends Type {
|
||||
ArrayType() {
|
||||
this instanceof @tuple_type or
|
||||
@@ -2061,6 +2082,7 @@ deprecated class ArrayType extends Type {
|
||||
*
|
||||
* An array type such as `Array<string>`, or equivalently, `string[]`.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class PlainArrayType extends ArrayType, TypeReference {
|
||||
PlainArrayType() { this.hasQualifiedName("Array") }
|
||||
|
||||
@@ -2075,6 +2097,7 @@ deprecated class PlainArrayType extends ArrayType, TypeReference {
|
||||
*
|
||||
* A read-only array type such as `ReadonlyArray<string>`.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class ReadonlyArrayType extends ArrayType, TypeReference {
|
||||
ReadonlyArrayType() { this.hasQualifiedName("ReadonlyArray") }
|
||||
}
|
||||
@@ -2087,6 +2110,7 @@ deprecated class ReadonlyArrayType extends ArrayType, TypeReference {
|
||||
*
|
||||
* A tuple type, such as `[number, string]`.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class TupleType extends ArrayType, @tuple_type {
|
||||
/**
|
||||
* Gets the `i`th member of this tuple type, starting at 0.
|
||||
@@ -2148,6 +2172,7 @@ deprecated class TupleType extends ArrayType, @tuple_type {
|
||||
*
|
||||
* The predefined `any` type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class AnyType extends Type, @any_type { }
|
||||
|
||||
/**
|
||||
@@ -2158,6 +2183,7 @@ deprecated class AnyType extends Type, @any_type { }
|
||||
*
|
||||
* The predefined `unknown` type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class UnknownType extends Type, @unknown_type { }
|
||||
|
||||
/**
|
||||
@@ -2168,6 +2194,7 @@ deprecated class UnknownType extends Type, @unknown_type { }
|
||||
*
|
||||
* The predefined `string` type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class StringType extends Type, @string_type { }
|
||||
|
||||
/**
|
||||
@@ -2178,6 +2205,7 @@ deprecated class StringType extends Type, @string_type { }
|
||||
*
|
||||
* The predefined `number` type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class NumberType extends Type, @number_type { }
|
||||
|
||||
/**
|
||||
@@ -2188,6 +2216,7 @@ deprecated class NumberType extends Type, @number_type { }
|
||||
*
|
||||
* The predefined `bigint` type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class BigIntType extends Type, @bigint_type { }
|
||||
|
||||
/**
|
||||
@@ -2198,6 +2227,7 @@ deprecated class BigIntType extends Type, @bigint_type { }
|
||||
*
|
||||
* A boolean, number, or string literal type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class LiteralType extends Type, @literal_type {
|
||||
/**
|
||||
* Gets the string value of this literal.
|
||||
@@ -2213,6 +2243,7 @@ deprecated class LiteralType extends Type, @literal_type {
|
||||
*
|
||||
* The boolean literal type `true` or `false`.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class BooleanLiteralType extends LiteralType, @boolean_literal_type {
|
||||
/**
|
||||
* Gets the boolean value represented by this type.
|
||||
@@ -2227,6 +2258,7 @@ deprecated class BooleanLiteralType extends LiteralType, @boolean_literal_type {
|
||||
/**
|
||||
* A number literal as a static type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class NumberLiteralType extends LiteralType, @number_literal_type {
|
||||
override string getStringValue() { type_literal_value(this, result) }
|
||||
|
||||
@@ -2249,6 +2281,7 @@ deprecated class NumberLiteralType extends LiteralType, @number_literal_type {
|
||||
*
|
||||
* A string literal as a static type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class StringLiteralType extends LiteralType, @string_literal_type {
|
||||
override string getStringValue() { type_literal_value(this, result) }
|
||||
}
|
||||
@@ -2261,6 +2294,7 @@ deprecated class StringLiteralType extends LiteralType, @string_literal_type {
|
||||
*
|
||||
* A bigint literal as a static type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class BigIntLiteralType extends LiteralType {
|
||||
override string getStringValue() { type_literal_value(this, result) }
|
||||
|
||||
@@ -2283,6 +2317,7 @@ deprecated class BigIntLiteralType extends LiteralType {
|
||||
*
|
||||
* The `boolean` type, internally represented as the union type `true | false`.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class BooleanType extends UnionType {
|
||||
BooleanType() {
|
||||
this.getAnElementType() instanceof @true_type and
|
||||
@@ -2299,6 +2334,7 @@ deprecated class BooleanType extends UnionType {
|
||||
*
|
||||
* The `string` type or a string literal type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class StringLikeType extends Type {
|
||||
StringLikeType() {
|
||||
this instanceof StringType or
|
||||
@@ -2314,6 +2350,7 @@ deprecated class StringLikeType extends Type {
|
||||
*
|
||||
* The `number` type or a number literal type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class NumberLikeType extends Type {
|
||||
NumberLikeType() {
|
||||
this instanceof NumberType or
|
||||
@@ -2329,6 +2366,7 @@ deprecated class NumberLikeType extends Type {
|
||||
*
|
||||
* The `boolean`, `true,` or `false` type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class BooleanLikeType extends Type {
|
||||
BooleanLikeType() {
|
||||
this instanceof BooleanType or
|
||||
@@ -2344,6 +2382,7 @@ deprecated class BooleanLikeType extends Type {
|
||||
*
|
||||
* The `void` type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class VoidType extends Type, @void_type { }
|
||||
|
||||
/**
|
||||
@@ -2354,6 +2393,7 @@ deprecated class VoidType extends Type, @void_type { }
|
||||
*
|
||||
* The `undefined` type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class UndefinedType extends Type, @undefined_type { }
|
||||
|
||||
/**
|
||||
@@ -2364,6 +2404,7 @@ deprecated class UndefinedType extends Type, @undefined_type { }
|
||||
*
|
||||
* The `null` type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class NullType extends Type, @null_type { }
|
||||
|
||||
/**
|
||||
@@ -2374,6 +2415,7 @@ deprecated class NullType extends Type, @null_type { }
|
||||
*
|
||||
* The `never` type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class NeverType extends Type, @never_type { }
|
||||
|
||||
/**
|
||||
@@ -2384,6 +2426,7 @@ deprecated class NeverType extends Type, @never_type { }
|
||||
*
|
||||
* The `symbol` type or a specific `unique symbol` type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class SymbolType extends Type, @symbol_type { }
|
||||
|
||||
/**
|
||||
@@ -2394,6 +2437,7 @@ deprecated class SymbolType extends Type, @symbol_type { }
|
||||
*
|
||||
* The `symbol` type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class PlainSymbolType extends SymbolType, @plain_symbol_type { }
|
||||
|
||||
/**
|
||||
@@ -2404,6 +2448,7 @@ deprecated class PlainSymbolType extends SymbolType, @plain_symbol_type { }
|
||||
*
|
||||
* A `unique symbol` type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class UniqueSymbolType extends SymbolType, @unique_symbol_type {
|
||||
/**
|
||||
* Gets the canonical name of the variable exposing the symbol.
|
||||
@@ -2438,6 +2483,7 @@ deprecated class UniqueSymbolType extends SymbolType, @unique_symbol_type {
|
||||
*
|
||||
* The `object` type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class ObjectKeywordType extends Type, @objectkeyword_type { }
|
||||
|
||||
/**
|
||||
@@ -2448,6 +2494,7 @@ deprecated class ObjectKeywordType extends Type, @objectkeyword_type { }
|
||||
*
|
||||
* A type that refers to a class, interface, enum, or enum member.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class TypeReference extends Type, @type_reference {
|
||||
/**
|
||||
* Gets the canonical name of the type being referenced.
|
||||
@@ -2506,6 +2553,7 @@ deprecated class TypeReference extends Type, @type_reference {
|
||||
*
|
||||
* A type that refers to a class, possibly with type arguments.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class ClassType extends TypeReference {
|
||||
ClassDefinition declaration;
|
||||
|
||||
@@ -2525,6 +2573,7 @@ deprecated class ClassType extends TypeReference {
|
||||
*
|
||||
* A type that refers to an interface, possibly with type arguents.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class InterfaceType extends TypeReference {
|
||||
InterfaceDeclaration declaration;
|
||||
|
||||
@@ -2544,6 +2593,7 @@ deprecated class InterfaceType extends TypeReference {
|
||||
*
|
||||
* A type that refers to an enum.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class EnumType extends TypeReference {
|
||||
EnumDeclaration declaration;
|
||||
|
||||
@@ -2563,6 +2613,7 @@ deprecated class EnumType extends TypeReference {
|
||||
*
|
||||
* A type that refers to the value of an enum member.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class EnumLiteralType extends TypeReference {
|
||||
EnumMember declaration;
|
||||
|
||||
@@ -2582,6 +2633,7 @@ deprecated class EnumLiteralType extends TypeReference {
|
||||
*
|
||||
* A type that refers to a type alias.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class TypeAliasReference extends TypeReference {
|
||||
TypeAliasReference() { type_alias(this, _) }
|
||||
|
||||
@@ -2601,6 +2653,7 @@ deprecated class TypeAliasReference extends TypeReference {
|
||||
*
|
||||
* An anonymous interface type, such as `{ x: number }`.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class AnonymousInterfaceType extends Type, @object_type { }
|
||||
|
||||
/**
|
||||
@@ -2611,6 +2664,7 @@ deprecated class AnonymousInterfaceType extends Type, @object_type { }
|
||||
*
|
||||
* A type that refers to a type variable.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class TypeVariableType extends Type, @typevariable_type {
|
||||
/**
|
||||
* Gets a syntactic declaration of this type variable.
|
||||
@@ -2656,6 +2710,7 @@ deprecated class TypeVariableType extends Type, @typevariable_type {
|
||||
*
|
||||
* A type that refers to a type variable declared on a class, interface or function.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class CanonicalTypeVariableType extends TypeVariableType, @canonical_type_variable_type {
|
||||
override TypeName getHostType() { result = this.getCanonicalName().getParent() }
|
||||
|
||||
@@ -2681,6 +2736,7 @@ deprecated class CanonicalTypeVariableType extends TypeVariableType, @canonical_
|
||||
* - `<T>(x: T) => T`
|
||||
* - `<S, T>(x: S, y: T) => T`.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class LexicalTypeVariableType extends TypeVariableType, @lexical_type_variable_type {
|
||||
override string getName() {
|
||||
types(this, _, result) // The toString value contains the name.
|
||||
@@ -2703,6 +2759,7 @@ deprecated class LexicalTypeVariableType extends TypeVariableType, @lexical_type
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class ThisType extends Type, @this_type {
|
||||
/**
|
||||
* Gets the type containing the `this` type.
|
||||
@@ -2721,6 +2778,7 @@ deprecated class ThisType extends Type, @this_type {
|
||||
* The type of a named value, `typeof X`, typically denoting the type of
|
||||
* a class constructor, namespace object, enum object, or module object.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class TypeofType extends Type, @typeof_type {
|
||||
/**
|
||||
* Gets the canonical name of the named value.
|
||||
@@ -2801,6 +2859,7 @@ module SignatureKind {
|
||||
*
|
||||
* A function or constructor signature in a TypeScript type.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class CallSignatureType extends @signature_type {
|
||||
/**
|
||||
* Gets a value indicating if this is a function or constructor signature.
|
||||
@@ -2955,6 +3014,7 @@ deprecated class CallSignatureType extends @signature_type {
|
||||
*
|
||||
* A function call signature in a type, that is, a signature without the `new` keyword.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class FunctionCallSignatureType extends CallSignatureType, @function_signature_type { }
|
||||
|
||||
/**
|
||||
@@ -2965,6 +3025,7 @@ deprecated class FunctionCallSignatureType extends CallSignatureType, @function_
|
||||
*
|
||||
* A constructor call signature in a type, that is, a signature with the `new` keyword.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class ConstructorCallSignatureType extends CallSignatureType, @constructor_signature_type
|
||||
{ }
|
||||
|
||||
@@ -2976,6 +3037,7 @@ deprecated class ConstructorCallSignatureType extends CallSignatureType, @constr
|
||||
* - It has one type parameter, say, `T`
|
||||
* - It has a `then` method whose first argument is a callback that takes a `T` as argument.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated private class PromiseTypeName extends TypeName {
|
||||
PromiseTypeName() {
|
||||
// The name must suggest it is a promise.
|
||||
@@ -3005,6 +3067,7 @@ deprecated private class PromiseTypeName extends TypeName {
|
||||
* This includes types whose name and `then` method signature suggest it is a promise,
|
||||
* such as `PromiseLike<T>` and `Thenable<T>`.
|
||||
*/
|
||||
overlay[global]
|
||||
deprecated class PromiseType extends TypeReference {
|
||||
PromiseType() {
|
||||
this.getNumTypeArgument() = 1 and
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/** Provides classes for modeling program variables. */
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
@@ -62,6 +64,7 @@ class LocalScope extends Scope {
|
||||
*/
|
||||
class ModuleScope extends Scope, @module_scope {
|
||||
/** Gets the module that induces this scope. */
|
||||
overlay[global]
|
||||
Module getModule() { result = this.getScopeElement() }
|
||||
|
||||
override string toString() { result = "module scope" }
|
||||
@@ -256,6 +259,7 @@ class VarRef extends @varref, Identifier, BindingPattern, LexicalRef {
|
||||
|
||||
override VarRef getABindingVarRef() { result = this }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() { none() }
|
||||
|
||||
override Expr getUnderlyingReference() { result = this }
|
||||
@@ -543,6 +547,7 @@ class ArrayPattern extends DestructuringPattern, @array_pattern {
|
||||
/** Holds if this array pattern has an omitted element. */
|
||||
predicate hasOmittedElement() { this.elementIsOmitted(_) }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() { this.getAnElement().isImpure() }
|
||||
|
||||
override VarRef getABindingVarRef() {
|
||||
@@ -583,6 +588,7 @@ class ObjectPattern extends DestructuringPattern, @object_pattern {
|
||||
/** Gets the rest property pattern of this object pattern, if any. */
|
||||
override Expr getRest() { result = this.getChildExpr(-1) }
|
||||
|
||||
overlay[global]
|
||||
override predicate isImpure() { this.getAPropertyPattern().isImpure() }
|
||||
|
||||
override VarRef getABindingVarRef() {
|
||||
@@ -640,6 +646,7 @@ class PropertyPattern extends @property, AstNode {
|
||||
ObjectPattern getObjectPattern() { properties(this, result, _, _, _) }
|
||||
|
||||
/** Holds if this pattern is impure, that is, if its evaluation could have side effects. */
|
||||
overlay[global]
|
||||
predicate isImpure() {
|
||||
this.isComputed() and this.getNameExpr().isImpure()
|
||||
or
|
||||
@@ -844,6 +851,7 @@ class SimpleParameter extends Parameter, VarDecl {
|
||||
* Gets a use of this parameter that refers to its initial value as
|
||||
* passed in from the caller.
|
||||
*/
|
||||
overlay[global]
|
||||
VarUse getAnInitialUse() {
|
||||
exists(SsaDefinition ssa |
|
||||
ssa.getAContributingVarDef() = this and
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Provides classes and predicates for working with XML files and their content.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import semmle.files.FileSystem
|
||||
private import codeql.xml.Xml
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* YAML documents are represented as abstract syntax trees whose nodes
|
||||
* are either YAML values or alias nodes referring to another YAML value.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
private import codeql.yaml.Yaml as LibYaml
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
* they represent; additionally, indefinite abstract values record
|
||||
* the source of imprecision that caused them to arise.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.internal.AbstractValuesImpl
|
||||
@@ -97,6 +99,7 @@ class AbstractValue extends TAbstractValue {
|
||||
* In all cases, purely local flow tracking is used to find prototype objects, so
|
||||
* this predicate cannot be relied on to compute all possible prototype objects.
|
||||
*/
|
||||
overlay[global]
|
||||
DefiniteAbstractValue getAPrototype() {
|
||||
exists(AbstractProtoProperty proto |
|
||||
proto.getBase() = this and
|
||||
|
||||
@@ -33,21 +33,25 @@ private import semmle.javascript.internal.CachedStages
|
||||
* Note: For performance reasons, all subclasses of this class should be part
|
||||
* of the standard library. Use `isAdditionalFlowStep` for query-specific flow steps.
|
||||
*/
|
||||
overlay[local]
|
||||
class AdditionalFlowStep extends Unit {
|
||||
/**
|
||||
* Holds if `pred` → `succ` should be considered a value-preserving data flow edge.f
|
||||
*/
|
||||
overlay[global]
|
||||
predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `pred` → `succ` should be considered a value-preserving data flow edge that
|
||||
* crosses calling contexts.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate jumpStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `pred` should be stored in the given `content` of the object `succ`.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate storeStep(DataFlow::Node pred, DataFlow::ContentSet contents, DataFlow::Node succ) {
|
||||
none()
|
||||
}
|
||||
@@ -55,6 +59,7 @@ class AdditionalFlowStep extends Unit {
|
||||
/**
|
||||
* Holds if the given `content` of the object in `pred` should be read into `succ`.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate readStep(DataFlow::Node pred, DataFlow::ContentSet contents, DataFlow::Node succ) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -625,15 +625,19 @@ abstract deprecated class LabeledBarrierGuardNode extends BarrierGuardNode {
|
||||
*
|
||||
* For use with load/store steps in `DataFlow::SharedFlowStep` and TypeTracking.
|
||||
*/
|
||||
overlay[local]
|
||||
module PseudoProperties {
|
||||
/** Holds if `s` is a pseudo-property. */
|
||||
bindingset[s]
|
||||
overlay[caller]
|
||||
predicate isPseudoProperty(string s) { s.matches("$%$") }
|
||||
|
||||
bindingset[s]
|
||||
overlay[caller]
|
||||
private string pseudoProperty(string s) { result = "$" + s + "$" }
|
||||
|
||||
bindingset[s, v]
|
||||
overlay[caller]
|
||||
private string pseudoProperty(string s, string v) { result = "$" + s + "|" + v + "$" }
|
||||
|
||||
/**
|
||||
@@ -680,6 +684,7 @@ module PseudoProperties {
|
||||
* Gets a pseudo-property for the location of a map value where the key is `key`.
|
||||
* The string value of the `key` is encoded in the result, and there is only a result if the string value of `key` is known.
|
||||
*/
|
||||
overlay[caller]
|
||||
pragma[inline]
|
||||
string mapValueKnownKey(DataFlow::Node key) {
|
||||
result = mapValueKey(any(string s | key.mayHaveStringValue(s)))
|
||||
@@ -689,17 +694,20 @@ module PseudoProperties {
|
||||
* Gets a pseudo-property for the location of a map value where the key is `key`.
|
||||
*/
|
||||
bindingset[key]
|
||||
overlay[caller]
|
||||
string mapValueKey(string key) { result = pseudoProperty("mapValue", key) }
|
||||
|
||||
/**
|
||||
* Holds if `prop` equals `mapValueKey(key)` for some value of `key`.
|
||||
*/
|
||||
bindingset[prop]
|
||||
overlay[caller]
|
||||
predicate isMapValueKey(string prop) { prop.matches("$mapValue|%$") }
|
||||
|
||||
/**
|
||||
* Gets a pseudo-property for the location of a map value where the key is `key`.
|
||||
*/
|
||||
overlay[caller]
|
||||
pragma[inline]
|
||||
string mapValue(DataFlow::Node key) {
|
||||
result = mapValueKnownKey(key)
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
* For performance reasons, all subclasses of `CustomAbstractValueDefinition`
|
||||
* should be part of the standard library.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import internal.AbstractValuesImpl
|
||||
@@ -32,6 +34,7 @@ class CustomAbstractValueFromDefinition extends AbstractValue, TCustomAbstractVa
|
||||
|
||||
override predicate isIndefinite(DataFlow::Incompleteness cause) { def.isIndefinite(cause) }
|
||||
|
||||
overlay[global]
|
||||
override DefiniteAbstractValue getAPrototype() { result = def.getAPrototype() }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
@@ -98,6 +101,7 @@ abstract class CustomAbstractValueDefinition extends Locatable {
|
||||
* Gets an abstract value that represents a prototype object of the
|
||||
* induced abstract value.
|
||||
*/
|
||||
overlay[global]
|
||||
AbstractValue getAPrototype() {
|
||||
exists(AbstractProtoProperty proto |
|
||||
proto.getBase() = this.getAbstractValue() and
|
||||
@@ -119,6 +123,7 @@ abstract class CustomAbstractValueDefinition extends Locatable {
|
||||
/**
|
||||
* Flow analysis for custom abstract values.
|
||||
*/
|
||||
overlay[global]
|
||||
class CustomAbstractValueFromDefinitionNode extends DataFlow::AnalyzedNode, DataFlow::ValueNode {
|
||||
CustomAbstractValueFromDefinition val;
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
* Flow through global variables, object properties or function calls is not
|
||||
* modeled (except for immediately invoked functions as explained above).
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
private import internal.CallGraphs
|
||||
@@ -64,9 +66,11 @@ module DataFlow {
|
||||
* `p.getALocalSource()` does _not_ return the corresponding argument, and
|
||||
* `p.isIncomplete("call")` holds.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate isIncomplete(Incompleteness cause) { isIncomplete(this, cause) }
|
||||
|
||||
/** Gets type inference results for this data flow node. */
|
||||
overlay[global]
|
||||
AnalyzedNode analyze() { result = this }
|
||||
|
||||
/** Gets the expression corresponding to this data flow node, if any. */
|
||||
@@ -98,6 +102,7 @@ module DataFlow {
|
||||
* Holds if this data flow node accesses the global variable `g`, either directly
|
||||
* or through the `window` object.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate accessesGlobal(string g) { globalVarRef(g).flowsTo(this) }
|
||||
|
||||
/** Holds if this node may evaluate to the string `s`, possibly through local data flow. */
|
||||
@@ -124,11 +129,13 @@ module DataFlow {
|
||||
int getIntValue() { result = this.asExpr().getIntValue() }
|
||||
|
||||
/** Gets a function value that may reach this node. */
|
||||
overlay[global]
|
||||
final FunctionNode getAFunctionValue() {
|
||||
CallGraph::getAFunctionReference(result, 0).flowsTo(this)
|
||||
}
|
||||
|
||||
/** Gets a function value that may reach this node with the given `imprecision` level. */
|
||||
overlay[global]
|
||||
final FunctionNode getAFunctionValue(int imprecision) {
|
||||
CallGraph::getAFunctionReference(result, imprecision).flowsTo(this)
|
||||
}
|
||||
@@ -137,6 +144,7 @@ module DataFlow {
|
||||
* Gets a function value that may reach this node,
|
||||
* possibly derived from a partial function invocation.
|
||||
*/
|
||||
overlay[global]
|
||||
final FunctionNode getABoundFunctionValue(int boundArgs) {
|
||||
result = this.getAFunctionValue() and boundArgs = 0
|
||||
or
|
||||
@@ -192,6 +200,7 @@ module DataFlow {
|
||||
FlowSteps::identityFunctionStep(result, this)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
private NameResolution::Node getNameResolutionNode() {
|
||||
this = valueNode(result)
|
||||
or
|
||||
@@ -205,6 +214,7 @@ module DataFlow {
|
||||
* Holds if this node is annotated with the given named type,
|
||||
* or is declared as a subtype thereof, or is a union or intersection containing such a type.
|
||||
*/
|
||||
overlay[global]
|
||||
cached
|
||||
predicate hasUnderlyingType(string globalName) {
|
||||
Stages::TypeTracking::ref() and
|
||||
@@ -218,6 +228,7 @@ module DataFlow {
|
||||
* Holds if this node is annotated with the given named type,
|
||||
* or is declared as a subtype thereof, or is a union or intersection containing such a type.
|
||||
*/
|
||||
overlay[global]
|
||||
cached
|
||||
predicate hasUnderlyingType(string moduleName, string typeName) {
|
||||
Stages::TypeTracking::ref() and
|
||||
@@ -466,6 +477,7 @@ module DataFlow {
|
||||
/**
|
||||
* Gets an accessor (`get` or `set` method) that may be invoked by this property reference.
|
||||
*/
|
||||
overlay[global]
|
||||
final DataFlow::FunctionNode getAnAccessorCallee() {
|
||||
result = CallGraph::getAnAccessorCallee(this)
|
||||
}
|
||||
@@ -1762,6 +1774,7 @@ module DataFlow {
|
||||
)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
private class ReflectiveParamsStep extends LegacyPreCallGraphStep {
|
||||
override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) {
|
||||
exists(DataFlow::ReflectiveParametersNode params, DataFlow::FunctionNode f, int i |
|
||||
@@ -1774,6 +1787,7 @@ module DataFlow {
|
||||
}
|
||||
|
||||
/** A taint step from the reflective parameters node to any parameter. */
|
||||
overlay[global]
|
||||
private class ReflectiveParamsTaintStep extends TaintTracking::LegacyTaintStep {
|
||||
override predicate step(DataFlow::Node obj, DataFlow::Node element) {
|
||||
exists(DataFlow::ReflectiveParametersNode params, DataFlow::FunctionNode f |
|
||||
@@ -1787,6 +1801,7 @@ module DataFlow {
|
||||
/**
|
||||
* Holds if there is a step from `pred` to `succ` through a field accessed through `this` in a class.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate localFieldStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(ClassNode cls, string prop |
|
||||
pred = AccessPath::getAnAssignmentTo(cls.getADirectSuperClass*().getAReceiverNode(), prop) or
|
||||
@@ -1819,6 +1834,7 @@ module DataFlow {
|
||||
* `p.getALocalSource()` does _not_ return the corresponding argument, and
|
||||
* `p.isIncomplete("call")` holds.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate isIncomplete(Node nd, Incompleteness cause) {
|
||||
exists(SsaVariable ssa | nd = TSsaDefNode(ssa.getDefinition()) |
|
||||
defIsIncomplete(ssa.(SsaExplicitDefinition).getDef(), cause)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/** Provides classes and predicates for defining flow summaries. */
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.internal.sharedlib.FlowSummaryImpl as Impl
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
/**
|
||||
* Types inferred by the flow analysis, represented as type tags.
|
||||
*
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* as nodes corresponding to function definitions or nodes corresponding to
|
||||
* parameters.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dependencies.Dependencies
|
||||
@@ -158,6 +160,7 @@ class InvokeNode extends DataFlow::SourceNode instanceof DataFlow::Impl::InvokeN
|
||||
* addEventHandler("click", foo.bind(this, "value of x"))
|
||||
* ```
|
||||
*/
|
||||
overlay[global]
|
||||
ParameterNode getABoundCallbackParameter(int callback, int param) {
|
||||
exists(int boundArgs |
|
||||
result =
|
||||
@@ -178,6 +181,7 @@ class InvokeNode extends DataFlow::SourceNode instanceof DataFlow::Impl::InvokeN
|
||||
private ObjectLiteralNode getOptionsArgument(int i) { result.flowsTo(this.getArgument(i)) }
|
||||
|
||||
/** Gets an abstract value representing possible callees of this call site. */
|
||||
overlay[global]
|
||||
final AbstractValue getACalleeValue() {
|
||||
exists(DataFlow::Node callee, DataFlow::AnalyzedNode analyzed |
|
||||
pragma[only_bind_into](callee) = this.getCalleeNode() and
|
||||
@@ -192,6 +196,7 @@ class InvokeNode extends DataFlow::SourceNode instanceof DataFlow::Impl::InvokeN
|
||||
* To alter the call graph as seen by the interprocedural data flow libraries, override
|
||||
* the `getACallee(int imprecision)` predicate instead.
|
||||
*/
|
||||
overlay[global]
|
||||
final Function getACallee() { result = this.getACallee(0) }
|
||||
|
||||
/**
|
||||
@@ -206,6 +211,7 @@ class InvokeNode extends DataFlow::SourceNode instanceof DataFlow::Impl::InvokeN
|
||||
* This predicate can be overridden to alter the call graph used by the interprocedural
|
||||
* data flow libraries.
|
||||
*/
|
||||
overlay[global]
|
||||
Function getACallee(int imprecision) {
|
||||
result = CallGraph::getACallee(this, imprecision).getFunction()
|
||||
}
|
||||
@@ -214,6 +220,7 @@ class InvokeNode extends DataFlow::SourceNode instanceof DataFlow::Impl::InvokeN
|
||||
* Holds if the approximation of possible callees for this call site is
|
||||
* affected by the given analysis incompleteness `cause`.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate isIndefinite(DataFlow::Incompleteness cause) {
|
||||
this.getACalleeValue().isIndefinite(cause)
|
||||
}
|
||||
@@ -229,6 +236,7 @@ class InvokeNode extends DataFlow::SourceNode instanceof DataFlow::Impl::InvokeN
|
||||
* independent contexts, so tracking flow through it leads to
|
||||
* imprecision.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate isImprecise() {
|
||||
this.isIndefinite("global") and
|
||||
exists(DefiniteAbstractValue v | v = this.getACalleeValue() | not v instanceof AbstractCallable)
|
||||
@@ -238,6 +246,7 @@ class InvokeNode extends DataFlow::SourceNode instanceof DataFlow::Impl::InvokeN
|
||||
* Holds if our approximation of possible callees for this call site is
|
||||
* likely to be incomplete.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate isIncomplete() {
|
||||
// the flow analysis identifies a source of incompleteness other than
|
||||
// global flow (which usually leads to imprecision rather than incompleteness)
|
||||
@@ -248,6 +257,7 @@ class InvokeNode extends DataFlow::SourceNode instanceof DataFlow::Impl::InvokeN
|
||||
* Holds if our approximation of possible callees for this call site is
|
||||
* likely to be imprecise or incomplete.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate isUncertain() { this.isImprecise() or this.isIncomplete() }
|
||||
|
||||
/**
|
||||
@@ -763,7 +773,7 @@ module ModuleImportNode {
|
||||
cached
|
||||
ModuleImportNode moduleImport(string path) {
|
||||
// NB. internal modules may be imported with a "node:" prefix
|
||||
Stages::Imports::ref() and result.getPath() = ["node:" + path, path]
|
||||
result.getPath() = ["node:" + path, path]
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -771,6 +781,7 @@ ModuleImportNode moduleImport(string path) {
|
||||
* `require("lodash")` in a context where a package.json file includes
|
||||
* `"lodash"` as a dependency.
|
||||
*/
|
||||
overlay[global]
|
||||
ModuleImportNode dependencyModuleImport(Dependency dep) {
|
||||
result = dep.getAUse("import").(Import).getImportedModuleNode()
|
||||
}
|
||||
@@ -780,6 +791,7 @@ ModuleImportNode dependencyModuleImport(Dependency dep) {
|
||||
* the given `path`, or accesses `m` as a member on a default or
|
||||
* namespace import from `path`.
|
||||
*/
|
||||
overlay[global]
|
||||
DataFlow::SourceNode moduleMember(string path, string m) {
|
||||
result = moduleImport(path).getAPropertyRead(m)
|
||||
}
|
||||
@@ -861,6 +873,7 @@ module MemberKind {
|
||||
*
|
||||
* Additional patterns can be recognized as class nodes, by extending `DataFlow::ClassNode::Range`.
|
||||
*/
|
||||
overlay[global]
|
||||
class ClassNode extends DataFlow::ValueNode, DataFlow::SourceNode {
|
||||
override AST::ValueNode astNode;
|
||||
AbstractCallable function;
|
||||
@@ -1329,6 +1342,7 @@ class ClassNode extends DataFlow::ValueNode, DataFlow::SourceNode {
|
||||
/**
|
||||
* Helper predicate to get a prototype reference in a file.
|
||||
*/
|
||||
overlay[global]
|
||||
private DataFlow::PropRef getAPrototypeReferenceInFile(string name, File f) {
|
||||
result.getBase() = AccessPath::getAReferenceOrAssignmentTo(name) and
|
||||
result.getPropertyName() = "prototype" and
|
||||
@@ -1338,6 +1352,7 @@ private DataFlow::PropRef getAPrototypeReferenceInFile(string name, File f) {
|
||||
/**
|
||||
* Helper predicate to get an instantiation in a file.
|
||||
*/
|
||||
overlay[global]
|
||||
private DataFlow::NewNode getAnInstantiationInFile(string name, File f) {
|
||||
result = AccessPath::getAReferenceTo(name).(DataFlow::LocalSourceNode).getAnInstantiation() and
|
||||
result.getFile() = f
|
||||
@@ -1346,6 +1361,7 @@ private DataFlow::NewNode getAnInstantiationInFile(string name, File f) {
|
||||
/**
|
||||
* Gets a reference to the function `func`, where there exists a read/write of the "prototype" property on that reference.
|
||||
*/
|
||||
overlay[global]
|
||||
pragma[noinline]
|
||||
private DataFlow::SourceNode getAFunctionValueWithPrototype(AbstractValue func) {
|
||||
exists(result.getAPropertyReference("prototype")) and
|
||||
@@ -1353,6 +1369,7 @@ private DataFlow::SourceNode getAFunctionValueWithPrototype(AbstractValue func)
|
||||
func instanceof AbstractCallable // the join-order goes bad if `func` has type `AbstractFunction`.
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
module ClassNode {
|
||||
/**
|
||||
* A dataflow node that should be considered a class node.
|
||||
@@ -1435,6 +1452,7 @@ module ClassNode {
|
||||
* _.partial(fn, x, y, z)
|
||||
* ```
|
||||
*/
|
||||
overlay[global]
|
||||
class PartialInvokeNode extends DataFlow::Node instanceof PartialInvokeNode::Range {
|
||||
/** Gets a node holding a callback invoked by this partial invocation node. */
|
||||
DataFlow::Node getACallbackNode() {
|
||||
@@ -1470,6 +1488,7 @@ class PartialInvokeNode extends DataFlow::Node instanceof PartialInvokeNode::Ran
|
||||
}
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
module PartialInvokeNode {
|
||||
/**
|
||||
* A data flow node that performs a partial function application.
|
||||
@@ -1717,6 +1736,7 @@ class RegExpCreationNode extends DataFlow::SourceNode {
|
||||
predicate maybeGlobal() { RegExp::maybeGlobal(this.tryGetFlags()) }
|
||||
|
||||
/** Gets a data flow node referring to this regular expression. */
|
||||
overlay[global]
|
||||
private DataFlow::SourceNode getAReference(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result = this
|
||||
@@ -1725,6 +1745,7 @@ class RegExpCreationNode extends DataFlow::SourceNode {
|
||||
}
|
||||
|
||||
/** Gets a data flow node referring to this regular expression. */
|
||||
overlay[global]
|
||||
cached
|
||||
DataFlow::SourceNode getAReference() {
|
||||
Stages::FlowSteps::ref() and
|
||||
@@ -1736,6 +1757,7 @@ class RegExpCreationNode extends DataFlow::SourceNode {
|
||||
* A guard node for a variable in a negative condition, such as `x` in `if(!x)`.
|
||||
* Can be added to a `isBarrier` in a data-flow configuration to block flow through such checks.
|
||||
*/
|
||||
overlay[global]
|
||||
class VarAccessBarrier extends DataFlow::Node {
|
||||
VarAccessBarrier() {
|
||||
exists(ConditionGuardNode guard, SsaRefinementNode refinement |
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
* so the refinement can evaluate to both `true` and `false` for the same
|
||||
* candidate value.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
private import AbstractValues
|
||||
@@ -45,6 +47,7 @@ abstract class RefinementCandidate extends Expr {
|
||||
/**
|
||||
* Gets a refinement value inferred for this expression in context `ctxt`.
|
||||
*/
|
||||
overlay[global]
|
||||
pragma[nomagic]
|
||||
abstract RefinementValue eval(RefinementContext ctxt);
|
||||
}
|
||||
@@ -64,6 +67,7 @@ class Refinement extends Expr instanceof RefinementCandidate {
|
||||
/**
|
||||
* Gets a refinement value inferred for this expression in context `ctxt`.
|
||||
*/
|
||||
overlay[global]
|
||||
RefinementValue eval(RefinementContext ctxt) { result = super.eval(ctxt) }
|
||||
}
|
||||
|
||||
@@ -71,6 +75,7 @@ class Refinement extends Expr instanceof RefinementCandidate {
|
||||
abstract private class LiteralRefinement extends RefinementCandidate, Literal {
|
||||
override SsaSourceVariable getARefinedVar() { none() }
|
||||
|
||||
overlay[global]
|
||||
override RefinementValue eval(RefinementContext ctxt) {
|
||||
ctxt.appliesTo(this) and result = this.eval()
|
||||
}
|
||||
@@ -78,16 +83,19 @@ abstract private class LiteralRefinement extends RefinementCandidate, Literal {
|
||||
/**
|
||||
* Gets the refinement value that represents this literal.
|
||||
*/
|
||||
overlay[global]
|
||||
RefinementValue eval() { result = TAny() }
|
||||
}
|
||||
|
||||
/** A `null` literal, viewed as a refinement expression. */
|
||||
private class NullLiteralRefinement extends LiteralRefinement, NullLiteral {
|
||||
overlay[global]
|
||||
override RefinementValue eval() { result = TValueWithType(TTNull()) }
|
||||
}
|
||||
|
||||
/** A Boolean literal, viewed as a refinement expression. */
|
||||
private class BoolRefinement extends LiteralRefinement, BooleanLiteral {
|
||||
overlay[global]
|
||||
override RefinementValue eval() {
|
||||
exists(boolean b | b.toString() = this.getValue() | result = TBoolConstant(b))
|
||||
}
|
||||
@@ -95,11 +103,13 @@ private class BoolRefinement extends LiteralRefinement, BooleanLiteral {
|
||||
|
||||
/** A constant string, viewed as a refinement expression. */
|
||||
private class StringRefinement extends LiteralRefinement, ConstantString {
|
||||
overlay[global]
|
||||
override RefinementValue eval() { result = TStringConstant(this.getStringValue()) }
|
||||
}
|
||||
|
||||
/** A numeric literal, viewed as a refinement expression. */
|
||||
abstract private class NumberRefinement extends LiteralRefinement, NumberLiteral {
|
||||
overlay[global]
|
||||
override RefinementValue eval() { result = TValueWithType(TTNumber()) }
|
||||
}
|
||||
|
||||
@@ -112,6 +122,7 @@ abstract private class NumberRefinement extends LiteralRefinement, NumberLiteral
|
||||
private class IntRefinement extends NumberRefinement, NumberLiteral {
|
||||
IntRefinement() { this.getValue().toInt() = 0 }
|
||||
|
||||
overlay[global]
|
||||
override RefinementValue eval() { result = TIntConstant(this.getValue().toInt()) }
|
||||
}
|
||||
|
||||
@@ -123,6 +134,7 @@ private class UndefinedInRefinement extends RefinementCandidate,
|
||||
{
|
||||
override SsaSourceVariable getARefinedVar() { none() }
|
||||
|
||||
overlay[global]
|
||||
override RefinementValue eval(RefinementContext ctxt) {
|
||||
ctxt.appliesTo(this) and
|
||||
result = TValueWithType(TTUndefined())
|
||||
@@ -135,6 +147,7 @@ private class VariableRefinement extends RefinementCandidate, VarUse {
|
||||
|
||||
override SsaSourceVariable getARefinedVar() { result = this.getVariable() }
|
||||
|
||||
overlay[global]
|
||||
override RefinementValue eval(RefinementContext ctxt) {
|
||||
ctxt.appliesTo(this) and
|
||||
result = ctxt.(VarRefinementContext).getAValue()
|
||||
@@ -149,6 +162,7 @@ private class ParRefinement extends RefinementCandidate, ParExpr {
|
||||
result = this.getExpression().(RefinementCandidate).getARefinedVar()
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
override RefinementValue eval(RefinementContext ctxt) {
|
||||
result = this.getExpression().(RefinementCandidate).eval(ctxt)
|
||||
}
|
||||
@@ -162,6 +176,7 @@ private class TypeofRefinement extends RefinementCandidate, TypeofExpr {
|
||||
result = this.getOperand().(RefinementCandidate).getARefinedVar()
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
override RefinementValue eval(RefinementContext ctxt) {
|
||||
exists(RefinementValue opVal |
|
||||
opVal = this.getOperand().(RefinementCandidate).eval(ctxt) and
|
||||
@@ -182,6 +197,7 @@ private class EqRefinement extends RefinementCandidate, EqualityTest {
|
||||
result = this.getRightOperand().(RefinementCandidate).getARefinedVar()
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
override RefinementValue eval(RefinementContext ctxt) {
|
||||
exists(RefinementCandidate l, RefinementValue lv, RefinementCandidate r, RefinementValue rv |
|
||||
l = this.getLeftOperand() and
|
||||
@@ -220,6 +236,7 @@ private class IndexRefinement extends RefinementCandidate, IndexExpr {
|
||||
result = this.getIndex().(RefinementCandidate).getARefinedVar()
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
override RefinementValue eval(RefinementContext ctxt) {
|
||||
exists(
|
||||
RefinementCandidate base, RefinementValue baseVal, RefinementCandidate index,
|
||||
@@ -242,6 +259,7 @@ private class IndexRefinement extends RefinementCandidate, IndexExpr {
|
||||
* if any.
|
||||
*/
|
||||
bindingset[s, i]
|
||||
overlay[global]
|
||||
private RefinementValue evalIndex(StringConstant s, IntConstant i) {
|
||||
result = TStringConstant(s.getValue().charAt(i.getValue()))
|
||||
}
|
||||
@@ -249,6 +267,7 @@ private RefinementValue evalIndex(StringConstant s, IntConstant i) {
|
||||
/**
|
||||
* A context in which a refinement expression is analyzed.
|
||||
*/
|
||||
overlay[global]
|
||||
newtype TRefinementContext =
|
||||
/**
|
||||
* A refinement context associated with refinement `ref`, specifying that variable `var`
|
||||
@@ -266,6 +285,7 @@ newtype TRefinementContext =
|
||||
/**
|
||||
* A context in which a refinement expression is analyzed.
|
||||
*/
|
||||
overlay[global]
|
||||
class RefinementContext extends TRefinementContext {
|
||||
/**
|
||||
* Holds if refinement expression `cand` might be analyzed in this context.
|
||||
@@ -280,6 +300,7 @@ class RefinementContext extends TRefinementContext {
|
||||
* A refinement context specifying that some variable is assumed to have one particular
|
||||
* abstract value.
|
||||
*/
|
||||
overlay[global]
|
||||
class VarRefinementContext extends RefinementContext, TVarRefinementContext {
|
||||
override predicate appliesTo(RefinementCandidate cand) {
|
||||
exists(AnalyzedRefinement ref, SsaSourceVariable var |
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
* Note that unlike `TypeTracking.qll`, this library only performs
|
||||
* local tracking within a function.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.TypeTracking
|
||||
@@ -192,6 +194,7 @@ class SourceNode extends DataFlow::Node instanceof SourceNode::Range {
|
||||
*
|
||||
* See `TypeTracker` for more details about how to use this.
|
||||
*/
|
||||
overlay[global]
|
||||
pragma[inline]
|
||||
DataFlow::SourceNode track(TypeTracker t2, TypeTracker t) { t = t2.step(this, result) }
|
||||
|
||||
@@ -200,6 +203,7 @@ class SourceNode extends DataFlow::Node instanceof SourceNode::Range {
|
||||
*
|
||||
* See `TypeBackTracker` for more details about how to use this.
|
||||
*/
|
||||
overlay[global]
|
||||
pragma[inline]
|
||||
DataFlow::SourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) {
|
||||
t2 = t.step(result, this)
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* Provides a representation for abstract values.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
import semmle.javascript.dataflow.AbstractValues
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
* to the same value have the same access paths, so access paths are neither sound nor
|
||||
* complete as an approximation of expression semantics.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
private import semmle.javascript.internal.CachedStages
|
||||
|
||||
@@ -5,6 +5,7 @@ private import semmle.javascript.dataflow.internal.DataFlowPrivate
|
||||
/**
|
||||
* Gets a data-flow node synthesized using `AdditionalFlowInternal#needsSynthesizedNode`.
|
||||
*/
|
||||
overlay[local]
|
||||
DataFlow::Node getSynthesizedNode(AstNode node, string tag) {
|
||||
result = TGenericSynthesizedNode(node, tag, _)
|
||||
}
|
||||
@@ -12,6 +13,7 @@ DataFlow::Node getSynthesizedNode(AstNode node, string tag) {
|
||||
/**
|
||||
* An extension to `AdditionalFlowStep` with additional internal-only predicates.
|
||||
*/
|
||||
overlay[local]
|
||||
class AdditionalFlowInternal extends DataFlow::AdditionalFlowStep {
|
||||
/**
|
||||
* Holds if a data-flow node should be synthesized for the pair `(node, tag)`.
|
||||
@@ -25,10 +27,12 @@ class AdditionalFlowInternal extends DataFlow::AdditionalFlowStep {
|
||||
/**
|
||||
* Holds if `node` should only permit flow of values stored in `contents`.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate expectsContent(DataFlow::Node node, DataFlow::ContentSet contents) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `node` should not permit flow of values stored in `contents`.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate clearsContent(DataFlow::Node node, DataFlow::ContentSet contents) { none() }
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.frameworks.data.internal.ApiGraphModels as ApiGraphModels
|
||||
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
|
||||
@@ -333,12 +336,14 @@ module Public {
|
||||
/**
|
||||
* A content set containing only the given content.
|
||||
*/
|
||||
overlay[caller]
|
||||
pragma[inline]
|
||||
ContentSet singleton(Content content) { result.asSingleton() = content }
|
||||
|
||||
/**
|
||||
* A content set corresponding to the given property name.
|
||||
*/
|
||||
overlay[caller]
|
||||
pragma[inline]
|
||||
ContentSet property(PropertyName name) { result.asSingleton().asPropertyName() = name }
|
||||
|
||||
@@ -399,6 +404,7 @@ module Public {
|
||||
* If `bound` is too large, it is truncated to the greatest lower bound we can represent.
|
||||
*/
|
||||
bindingset[bound]
|
||||
overlay[caller]
|
||||
ContentSet arrayElementLowerBoundFromInt(int bound) {
|
||||
result = arrayElementLowerBound(bound.minimum(getMaxPreciseArrayIndex() + 1))
|
||||
}
|
||||
@@ -409,6 +415,7 @@ module Public {
|
||||
* If `n` is too large, it is truncated to the greatest lower bound we can represent.
|
||||
*/
|
||||
bindingset[n]
|
||||
overlay[caller]
|
||||
ContentSet arrayElementFromInt(int n) {
|
||||
result = arrayElementKnown(n)
|
||||
or
|
||||
@@ -448,6 +455,7 @@ module Public {
|
||||
* If `key` is not one of the keys we track precisely, this is mapped to the unknown key instead.
|
||||
*/
|
||||
bindingset[key]
|
||||
overlay[caller]
|
||||
ContentSet mapValueFromKey(string key) {
|
||||
result = mapValueWithKnownKey(key)
|
||||
or
|
||||
@@ -510,6 +518,7 @@ module Public {
|
||||
* are mapped to their corresponding content sets (which are no longer seen as property names).
|
||||
*/
|
||||
bindingset[propertyName]
|
||||
overlay[caller]
|
||||
ContentSet fromLegacyProperty(string propertyName) {
|
||||
result = fromLegacyPseudoProperty(propertyName)
|
||||
or
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* Contains the raw data type underlying `DataFlow::Node`.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import codeql.util.Boolean
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.internal.CallGraphs
|
||||
private import semmle.javascript.dataflow.internal.DataFlowNode
|
||||
@@ -310,6 +313,7 @@ private predicate returnNodeImpl(DataFlow::Node node, ReturnKind kind) {
|
||||
kind = MkExceptionalReturnKind()
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
private DataFlow::Node getAnOutNodeImpl(DataFlowCall call, ReturnKind kind) {
|
||||
kind = MkNormalReturnKind() and result = call.asOrdinaryCall()
|
||||
or
|
||||
@@ -336,10 +340,12 @@ class ReturnNode extends DataFlow::Node {
|
||||
}
|
||||
|
||||
/** A node that receives an output from a call. */
|
||||
overlay[global]
|
||||
class OutNode extends DataFlow::Node {
|
||||
OutNode() { this = getAnOutNodeImpl(_, _) }
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { result = getAnOutNodeImpl(call, kind) }
|
||||
|
||||
cached
|
||||
@@ -416,9 +422,11 @@ abstract class LibraryCallable extends string {
|
||||
LibraryCallable() { any() }
|
||||
|
||||
/** Gets a call to this library callable. */
|
||||
overlay[global]
|
||||
DataFlow::InvokeNode getACall() { none() }
|
||||
|
||||
/** Same as `getACall()` except this does not depend on the call graph or API graph. */
|
||||
overlay[global]
|
||||
DataFlow::InvokeNode getACallSimple() { none() }
|
||||
}
|
||||
|
||||
@@ -432,6 +440,7 @@ abstract class LibraryCallableInternal extends LibraryCallable {
|
||||
*
|
||||
* Same as `getACall()` but is evaluated later and may depend negatively on `getACall()`.
|
||||
*/
|
||||
overlay[global]
|
||||
DataFlow::InvokeNode getACallStage2() { none() }
|
||||
}
|
||||
|
||||
@@ -467,6 +476,7 @@ predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition
|
||||
isParameterNodeImpl(p, c, pos)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
private predicate isArgumentNodeImpl(Node n, DataFlowCall call, ArgumentPosition pos) {
|
||||
n = call.asOrdinaryCall().getArgument(pos.asPositional())
|
||||
or
|
||||
@@ -523,6 +533,7 @@ private predicate isArgumentNodeImpl(Node n, DataFlowCall call, ArgumentPosition
|
||||
)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
predicate isArgumentNode(ArgumentNode n, DataFlowCall call, ArgumentPosition pos) {
|
||||
isArgumentNodeImpl(n, call, pos)
|
||||
}
|
||||
@@ -545,11 +556,13 @@ DataFlowCallable nodeGetEnclosingCallable(Node node) {
|
||||
node instanceof DataFlow::XmlAttributeNode and result.asFileCallable() = node.getFile()
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
newtype TDataFlowType =
|
||||
TFunctionType(Function f) or
|
||||
TInstanceType(DataFlow::ClassNode cls) or
|
||||
TAnyType()
|
||||
|
||||
overlay[global]
|
||||
class DataFlowType extends TDataFlowType {
|
||||
string toDebugString() {
|
||||
result =
|
||||
@@ -575,6 +588,7 @@ class DataFlowType extends TDataFlowType {
|
||||
/**
|
||||
* Holds if `t1` is strictly stronger than `t2`.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) {
|
||||
// 't1' is a subclass of 't2'
|
||||
t1.asInstanceOfClass() = t2.asInstanceOfClass().getADirectSubClass+()
|
||||
@@ -584,6 +598,7 @@ predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) {
|
||||
t2 = TAnyType()
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
private DataFlowType getPreciseType(Node node) {
|
||||
exists(Function f |
|
||||
(node = TValueNode(f) or node = TFunctionSelfReferenceNode(f)) and
|
||||
@@ -598,6 +613,7 @@ private DataFlowType getPreciseType(Node node) {
|
||||
result = getPreciseType(node.(PostUpdateNode).getPreUpdateNode())
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
DataFlowType getNodeType(Node node) {
|
||||
result = getPreciseType(node)
|
||||
or
|
||||
@@ -681,19 +697,23 @@ predicate neverSkipInPathGraph(Node node) {
|
||||
node.asExpr() instanceof VarRef
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
string ppReprType(DataFlowType t) { none() }
|
||||
|
||||
overlay[global]
|
||||
pragma[inline]
|
||||
private predicate compatibleTypesWithAny(DataFlowType t1, DataFlowType t2) {
|
||||
t1 != TAnyType() and
|
||||
t2 = TAnyType()
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
pragma[nomagic]
|
||||
private predicate compatibleTypes1(DataFlowType t1, DataFlowType t2) {
|
||||
t1.asInstanceOfClass().getADirectSubClass+() = t2.asInstanceOfClass()
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
pragma[inline]
|
||||
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
|
||||
t1 = t2
|
||||
@@ -767,6 +787,7 @@ ContentApprox getContentApprox(Content c) {
|
||||
c instanceof MkCapturedContent and result = TApproxCapturedContent()
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
cached
|
||||
private newtype TDataFlowCall =
|
||||
MkOrdinaryCall(DataFlow::InvokeNode node) or
|
||||
@@ -791,6 +812,7 @@ private newtype TDataFlowCall =
|
||||
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
class DataFlowCall extends TDataFlowCall {
|
||||
DataFlowCallable getEnclosingCallable() { none() } // Overridden in subclass
|
||||
|
||||
@@ -816,6 +838,7 @@ class DataFlowCall extends TDataFlowCall {
|
||||
Location getLocation() { none() } // Overridden in subclass
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
private class OrdinaryCall extends DataFlowCall, MkOrdinaryCall {
|
||||
private DataFlow::InvokeNode node;
|
||||
|
||||
@@ -832,6 +855,7 @@ private class OrdinaryCall extends DataFlowCall, MkOrdinaryCall {
|
||||
override Location getLocation() { result = node.getLocation() }
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
private class PartialCall extends DataFlowCall, MkPartialCall {
|
||||
private DataFlow::PartialInvokeNode node;
|
||||
private DataFlow::Node callback;
|
||||
@@ -851,6 +875,7 @@ private class PartialCall extends DataFlowCall, MkPartialCall {
|
||||
override Location getLocation() { result = node.getLocation() }
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
private class BoundCall extends DataFlowCall, MkBoundCall {
|
||||
private DataFlow::InvokeNode node;
|
||||
private int boundArgs;
|
||||
@@ -868,6 +893,7 @@ private class BoundCall extends DataFlowCall, MkBoundCall {
|
||||
override Location getLocation() { result = node.getLocation() }
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
private class AccessorCall extends DataFlowCall, MkAccessorCall {
|
||||
private DataFlow::PropRef ref;
|
||||
|
||||
@@ -882,6 +908,7 @@ private class AccessorCall extends DataFlowCall, MkAccessorCall {
|
||||
override Location getLocation() { result = ref.getLocation() }
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
class SummaryCall extends DataFlowCall, MkSummaryCall {
|
||||
private FlowSummaryImpl::Public::SummarizedCallable enclosingCallable;
|
||||
private FlowSummaryImpl::Private::SummaryNode receiver;
|
||||
@@ -908,6 +935,7 @@ class SummaryCall extends DataFlowCall, MkSummaryCall {
|
||||
* This is to help ensure captured variables can flow into the lambda in cases where
|
||||
* we can't find its call sites.
|
||||
*/
|
||||
overlay[global]
|
||||
private class ImpliedLambdaCall extends DataFlowCall, MkImpliedLambdaCall {
|
||||
private Function function;
|
||||
|
||||
@@ -981,6 +1009,7 @@ class DataFlowExpr = Expr;
|
||||
|
||||
Node exprNode(DataFlowExpr expr) { result = DataFlow::exprNode(expr) }
|
||||
|
||||
overlay[global]
|
||||
pragma[nomagic]
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
|
||||
ppos = apos
|
||||
@@ -993,6 +1022,7 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
|
||||
// are only using these in cases where either the call or callee is generated by a flow summary.
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
pragma[inline]
|
||||
DataFlowCallable viableCallable(DataFlowCall node) {
|
||||
// Note: we never include call edges externs here, as it negatively affects the field-flow branch limit,
|
||||
@@ -1021,6 +1051,7 @@ DataFlowCallable viableCallable(DataFlowCall node) {
|
||||
result.asSourceCallableNotExterns() = node.asImpliedLambdaCall()
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
private DataFlowCall getACallOnThis(DataFlow::ClassNode cls) {
|
||||
result.asOrdinaryCall() = cls.getAReceiverNode().getAPropertyRead().getACall()
|
||||
or
|
||||
@@ -1029,6 +1060,7 @@ private DataFlowCall getACallOnThis(DataFlow::ClassNode cls) {
|
||||
result.asPartialCall().getACallbackNode() = cls.getAReceiverNode().getAPropertyRead()
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
private predicate downwardCall(DataFlowCall call) {
|
||||
exists(DataFlow::ClassNode cls |
|
||||
call = getACallOnThis(cls) and
|
||||
@@ -1041,9 +1073,11 @@ private predicate downwardCall(DataFlowCall call) {
|
||||
* Holds if the set of viable implementations that can be called by `call`
|
||||
* might be improved by knowing the call context.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate mayBenefitFromCallContext(DataFlowCall call) { downwardCall(call) }
|
||||
|
||||
/** Gets the type of the receiver of `call`. */
|
||||
overlay[global]
|
||||
private DataFlowType getThisArgumentType(DataFlowCall call) {
|
||||
exists(DataFlow::Node node |
|
||||
isArgumentNodeImpl(node, call, MkThisParameter()) and
|
||||
@@ -1052,6 +1086,7 @@ private DataFlowType getThisArgumentType(DataFlowCall call) {
|
||||
}
|
||||
|
||||
/** Gets the type of the 'this' parameter of `call`. */
|
||||
overlay[global]
|
||||
private DataFlowType getThisParameterType(DataFlowCallable callable) {
|
||||
exists(DataFlow::Node node |
|
||||
isParameterNodeImpl(node, callable, MkThisParameter()) and
|
||||
@@ -1063,6 +1098,7 @@ private DataFlowType getThisParameterType(DataFlowCallable callable) {
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference.
|
||||
*/
|
||||
overlay[global]
|
||||
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
||||
mayBenefitFromCallContext(call) and
|
||||
result = viableCallable(call) and
|
||||
@@ -1071,16 +1107,19 @@ DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
||||
}
|
||||
|
||||
bindingset[node, fun]
|
||||
overlay[caller]
|
||||
pragma[inline_late]
|
||||
private predicate sameContainerAsEnclosingContainer(Node node, Function fun) {
|
||||
node.getContainer() = fun.getEnclosingContainer()
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
abstract private class BarrierGuardAdapter extends DataFlow::Node {
|
||||
// Note: avoid depending on DataFlow::FlowLabel here as it will cause these barriers to be re-evaluated
|
||||
predicate blocksExpr(boolean outcome, Expr e) { none() }
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
deprecated private class BarrierGuardAdapterSubclass extends BarrierGuardAdapter instanceof DataFlow::AdditionalBarrierGuardNode
|
||||
{
|
||||
override predicate blocksExpr(boolean outcome, Expr e) { super.blocks(outcome, e) }
|
||||
@@ -1092,6 +1131,7 @@ deprecated private class BarrierGuardAdapterSubclass extends BarrierGuardAdapter
|
||||
*
|
||||
* The standard library contains no subclasses of that class; this is for backwards compatibility only.
|
||||
*/
|
||||
overlay[global]
|
||||
pragma[nomagic]
|
||||
private predicate legacyBarrier(DataFlow::Node node) {
|
||||
node = MakeBarrierGuard<BarrierGuardAdapter>::getABarrierNode()
|
||||
@@ -1100,6 +1140,7 @@ private predicate legacyBarrier(DataFlow::Node node) {
|
||||
/**
|
||||
* Holds if `node` should be removed from the local data flow graph, for compatibility with legacy code.
|
||||
*/
|
||||
overlay[global]
|
||||
pragma[nomagic]
|
||||
private predicate isBlockedLegacyNode(Node node) {
|
||||
// Ignore captured variable nodes for those variables that are handled by the captured-variable library.
|
||||
@@ -1155,6 +1196,7 @@ private predicate imprecisePostUpdateStep(DataFlow::PostUpdateNode postUpdate, D
|
||||
* Holds if there is a value-preserving steps `node1` -> `node2` that might
|
||||
* be cross function boundaries.
|
||||
*/
|
||||
overlay[global]
|
||||
private predicate valuePreservingStep(Node node1, Node node2) {
|
||||
node1.getASuccessor() = node2 and
|
||||
not isBlockedLegacyNode(node1) and
|
||||
@@ -1223,10 +1265,12 @@ private predicate useUseFlow(Node node1, Node node2) {
|
||||
)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
predicate simpleLocalFlowStep(Node node1, Node node2, string model) {
|
||||
simpleLocalFlowStep(node1, node2) and model = ""
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
predicate simpleLocalFlowStep(Node node1, Node node2) {
|
||||
valuePreservingStep(node1, node2) and
|
||||
nodeGetEnclosingCallable(pragma[only_bind_out](node1)) =
|
||||
@@ -1314,6 +1358,7 @@ private predicate excludedJumpStep(Node node1, Node node2) {
|
||||
* that does not follow a call edge. For example, a step through a global
|
||||
* variable.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate jumpStep(Node node1, Node node2) {
|
||||
valuePreservingStep(node1, node2) and
|
||||
node1.getContainer() != node2.getContainer() and
|
||||
@@ -1330,6 +1375,7 @@ predicate jumpStep(Node node1, Node node2) {
|
||||
* `node1` references an object with a content `c.getAReadContent()` whose
|
||||
* value ends up in `node2`.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate readStep(Node node1, ContentSet c, Node node2) {
|
||||
exists(DataFlow::PropRead read |
|
||||
node1 = read.getBase() and
|
||||
@@ -1487,6 +1533,7 @@ private int firstSpreadArgumentIndex(InvokeExpr expr) {
|
||||
* `node2` references an object with a content `c.getAStoreContent()` that
|
||||
* contains the value of `node1`.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate storeStep(Node node1, ContentSet c, Node node2) {
|
||||
exists(DataFlow::PropWrite write |
|
||||
node1 = write.getRhs() and
|
||||
@@ -1545,6 +1592,7 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
|
||||
* any value stored inside `f` is cleared at the pre-update node associated with `x`
|
||||
* in `x.f = newValue`.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate clearsContent(Node n, ContentSet c) {
|
||||
FlowSummaryPrivate::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), c)
|
||||
or
|
||||
@@ -1578,6 +1626,7 @@ predicate clearsContent(Node n, ContentSet c) {
|
||||
* Holds if the value that is being tracked is expected to be stored inside content `c`
|
||||
* at node `n`.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate expectsContent(Node n, ContentSet c) {
|
||||
FlowSummaryPrivate::Steps::summaryExpectsContent(n.(FlowSummaryNode).getSummaryNode(), c)
|
||||
or
|
||||
@@ -1602,6 +1651,7 @@ abstract class NodeRegion extends Unit {
|
||||
/**
|
||||
* Holds if the node `n` is unreachable when the call context is `call`.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate isUnreachableInCall(NodeRegion n, DataFlowCall call) {
|
||||
none() // TODO: could be useful, but not currently implemented for JS
|
||||
}
|
||||
@@ -1635,6 +1685,7 @@ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c)
|
||||
}
|
||||
|
||||
/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
|
||||
overlay[global]
|
||||
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
|
||||
call.isSummaryCall(_, receiver.(FlowSummaryNode).getSummaryNode()) and exists(kind)
|
||||
or
|
||||
@@ -1646,6 +1697,7 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
|
||||
/** Extra data-flow steps needed for lambda flow analysis. */
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
|
||||
|
||||
overlay[global]
|
||||
class ArgumentNode extends DataFlow::Node {
|
||||
ArgumentNode() { isArgumentNodeImpl(this, _, _) }
|
||||
|
||||
|
||||
@@ -519,22 +519,23 @@ private module CachedSteps {
|
||||
predicate receiverPropWrite(Function f, string prop, DataFlow::Node rhs) {
|
||||
DataFlow::thisNode(f).hasPropertyWrite(prop, rhs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a step from `pred` to `succ` through a call to an identity function.
|
||||
*/
|
||||
cached
|
||||
predicate identityFunctionStep(DataFlow::Node pred, DataFlow::CallNode succ) {
|
||||
exists(DataFlow::GlobalVarRefNode global |
|
||||
global.getName() = "Object" and
|
||||
succ.(DataFlow::MethodCallNode).calls(global, ["freeze", "seal"]) and
|
||||
pred = succ.getArgument(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import CachedSteps
|
||||
|
||||
/**
|
||||
* Holds if there is a step from `pred` to `succ` through a call to an identity function.
|
||||
*/
|
||||
overlay[local]
|
||||
cached
|
||||
predicate identityFunctionStep(DataFlow::Node pred, DataFlow::CallNode succ) {
|
||||
exists(DataFlow::GlobalVarRefNode global |
|
||||
global.getName() = "Object" and
|
||||
succ.(DataFlow::MethodCallNode).calls(global, ["freeze", "seal"]) and
|
||||
pred = succ.getArgument(0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility class that is equivalent to `boolean` but does not require type joining.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Provides JS specific classes and predicates for defining flow summaries.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.internal.DataFlowPrivate
|
||||
@@ -140,6 +142,7 @@ string encodeArgumentPosition(ArgumentPosition pos) {
|
||||
ReturnKind getStandardReturnValueKind() { result = MkNormalReturnKind() and Stage::ref() }
|
||||
|
||||
private module FlowSummaryStepInput implements Private::StepsInputSig {
|
||||
overlay[global]
|
||||
DataFlowCall getACall(SummarizedCallable sc) {
|
||||
exists(LibraryCallable callable | callable = sc |
|
||||
result.asOrdinaryCall() =
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
private import javascript as js
|
||||
private import semmle.javascript.dataflow.internal.DataFlowNode
|
||||
private import semmle.javascript.dataflow.internal.VariableOrThis
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import DataFlowNode
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* JavaScript's old SSA library is still responsible for the ordinary SSA flow.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
private import javascript as js
|
||||
private import codeql.ssa.Ssa
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Models imports through the NPM `lazy-cache` package.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
@@ -58,6 +60,7 @@ module LazyCache {
|
||||
}
|
||||
|
||||
/** A constant path element appearing in a call to a lazy-cache object. */
|
||||
overlay[global]
|
||||
deprecated private class LazyCachePathExpr extends PathExpr, ConstantString {
|
||||
LazyCachePathExpr() { this = any(LazyCacheImport rp).getArgument(0) }
|
||||
|
||||
|
||||
@@ -181,9 +181,11 @@ module LodashUnderscore {
|
||||
}
|
||||
}
|
||||
|
||||
overlay[local]
|
||||
private class LodashEach extends DataFlow::SummarizedCallable {
|
||||
LodashEach() { this = "_.each-like" }
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::CallNode getACall() {
|
||||
result = member(["each", "eachRight", "forEach", "forEachRight", "every", "some"]).getACall()
|
||||
}
|
||||
@@ -195,9 +197,11 @@ module LodashUnderscore {
|
||||
}
|
||||
}
|
||||
|
||||
overlay[local]
|
||||
private class LodashMap extends DataFlow::SummarizedCallable {
|
||||
LodashMap() { this = "_.map" }
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::CallNode getACall() { result = member("map").getACall() }
|
||||
|
||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
@@ -212,9 +216,11 @@ module LodashUnderscore {
|
||||
}
|
||||
}
|
||||
|
||||
overlay[local]
|
||||
private class LodashFlatMap extends DataFlow::SummarizedCallable {
|
||||
LodashFlatMap() { this = "_.flatMap" }
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::CallNode getACall() { result = member("flatMap").getACall() }
|
||||
|
||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
@@ -232,9 +238,11 @@ module LodashUnderscore {
|
||||
}
|
||||
}
|
||||
|
||||
overlay[local]
|
||||
private class LodashFlatMapDeep extends DataFlow::SummarizedCallable {
|
||||
LodashFlatMapDeep() { this = "_.flatMapDeep" }
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::CallNode getACall() {
|
||||
result = member(["flatMapDeep", "flatMapDepth"]).getACall()
|
||||
}
|
||||
@@ -254,9 +262,11 @@ module LodashUnderscore {
|
||||
}
|
||||
}
|
||||
|
||||
overlay[local]
|
||||
private class LodashReduce extends DataFlow::SummarizedCallable {
|
||||
LodashReduce() { this = "_.reduce-like" }
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::CallNode getACall() { result = member(["reduce", "reduceRight"]).getACall() }
|
||||
|
||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
@@ -271,9 +281,11 @@ module LodashUnderscore {
|
||||
}
|
||||
}
|
||||
|
||||
overlay[local]
|
||||
private class LoashSortBy extends DataFlow::SummarizedCallable {
|
||||
LoashSortBy() { this = "_.sortBy-like" }
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::CallNode getACall() { result = member(["sortBy", "orderBy"]).getACall() }
|
||||
|
||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
@@ -287,9 +299,11 @@ module LodashUnderscore {
|
||||
}
|
||||
}
|
||||
|
||||
overlay[local]
|
||||
private class LodashMinMaxBy extends DataFlow::SummarizedCallable {
|
||||
LodashMinMaxBy() { this = "_.minBy / _.maxBy" }
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::CallNode getACall() { result = member(["minBy", "maxBy"]).getACall() }
|
||||
|
||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
@@ -299,9 +313,11 @@ module LodashUnderscore {
|
||||
}
|
||||
}
|
||||
|
||||
overlay[local]
|
||||
private class LodashPartition extends DataFlow::SummarizedCallable {
|
||||
LodashPartition() { this = "_.partition" }
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::CallNode getACall() { result = member("partition").getACall() }
|
||||
|
||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
@@ -311,9 +327,11 @@ module LodashUnderscore {
|
||||
}
|
||||
}
|
||||
|
||||
overlay[local]
|
||||
private class UnderscoreMapObject extends DataFlow::SummarizedCallable {
|
||||
UnderscoreMapObject() { this = "_.mapObject" }
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::CallNode getACall() { result = member("mapObject").getACall() }
|
||||
|
||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
@@ -330,9 +348,11 @@ module LodashUnderscore {
|
||||
}
|
||||
}
|
||||
|
||||
overlay[local]
|
||||
private class LodashTap extends DataFlow::SummarizedCallable {
|
||||
LodashTap() { this = "_.tap" }
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::CallNode getACall() { result = member("tap").getACall() }
|
||||
|
||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
|
||||
@@ -8,14 +8,17 @@ import semmle.javascript.security.SensitiveActions
|
||||
private import semmle.javascript.dataflow.internal.PreCallGraphStep
|
||||
|
||||
module NodeJSLib {
|
||||
overlay[local]
|
||||
private GlobalVariable processVariable() { variables(result, "process", any(GlobalScope sc)) }
|
||||
|
||||
overlay[local]
|
||||
pragma[nomagic]
|
||||
private GlobalVarAccess processExprInTopLevel(TopLevel tl) {
|
||||
result = processVariable().getAnAccess() and
|
||||
tl = result.getTopLevel()
|
||||
}
|
||||
|
||||
overlay[local]
|
||||
pragma[nomagic]
|
||||
private GlobalVarAccess processExprInNodeModule() {
|
||||
result = processExprInTopLevel(any(NodeModule m))
|
||||
@@ -25,6 +28,7 @@ module NodeJSLib {
|
||||
* An access to the global `process` variable in a Node.js module, interpreted as
|
||||
* an import of the `process` module.
|
||||
*/
|
||||
overlay[local]
|
||||
private class ImplicitProcessImport extends DataFlow::ModuleImportNode::Range {
|
||||
ImplicitProcessImport() { this = DataFlow::exprNode(processExprInNodeModule()) }
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Provides predicates for working with templating libraries.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
|
||||
@@ -45,6 +47,7 @@ module Templating {
|
||||
Locatable getParent() { template_placeholder_tag_info(this, result, _) }
|
||||
|
||||
/** Gets a data flow node representing the value plugged into this placeholder. */
|
||||
overlay[global]
|
||||
DataFlow::TemplatePlaceholderTagNode asDataFlowNode() { result.getTag() = this }
|
||||
|
||||
/** Gets the top-level containing the template expression to be inserted at this placeholder. */
|
||||
@@ -54,6 +57,7 @@ module Templating {
|
||||
* Holds if this performs raw interpolation, that is, inserts its result
|
||||
* in the output without escaping it.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate isRawInterpolation() {
|
||||
this.getRawText()
|
||||
.regexpMatch(getLikelyTemplateSyntax(this.getFile()).getRawInterpolationRegexp())
|
||||
@@ -62,6 +66,7 @@ module Templating {
|
||||
/**
|
||||
* Holds if this performs HTML escaping on the result before inserting it in the template.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate isEscapingInterpolation() {
|
||||
this.getRawText()
|
||||
.regexpMatch(getLikelyTemplateSyntax(this.getFile()).getEscapingInterpolationRegexp())
|
||||
@@ -93,6 +98,7 @@ module Templating {
|
||||
* Holds if this placeholder occurs in the definition of another template, which means the output
|
||||
* is susceptible to code injection.
|
||||
*/
|
||||
overlay[global]
|
||||
predicate isInNestedTemplateContext(string templateType) {
|
||||
templateType = "AngularJS" and
|
||||
AngularJS::isInterpretedByAngularJS(this.getParent()) and
|
||||
@@ -135,6 +141,7 @@ module Templating {
|
||||
*
|
||||
* For example, the call generated from `items | async` would be found by `getAPipeCall("async")`.
|
||||
*/
|
||||
overlay[global]
|
||||
DataFlow::CallNode getAPipeCall(string name) {
|
||||
result.getCalleeNode().asExpr().(PipeRefExpr).getName() = name
|
||||
}
|
||||
@@ -153,16 +160,19 @@ module Templating {
|
||||
Expr getExpression() { result = this.getChildStmt(0).(ExprStmt).getExpr() }
|
||||
|
||||
/** Gets the data flow node representing the initialization of the given variable in this scope. */
|
||||
overlay[global]
|
||||
DataFlow::Node getVariableInit(string name) {
|
||||
result = DataFlow::ssaDefinitionNode(Ssa::implicitInit(this.getScope().getVariable(name)))
|
||||
}
|
||||
|
||||
/** Gets a data flow node corresponding to a use of the given template variable within this top-level. */
|
||||
overlay[global]
|
||||
DataFlow::SourceNode getAVariableUse(string name) {
|
||||
result = this.getScope().getVariable(name).getAnAccess().flow()
|
||||
}
|
||||
|
||||
/** Gets a data flow node corresponding to a use of the given template variable within this top-level. */
|
||||
overlay[global]
|
||||
DataFlow::SourceNode getAnAccessPathUse(string accessPath) {
|
||||
result = this.getAVariableUse(accessPath)
|
||||
or
|
||||
@@ -177,6 +187,7 @@ module Templating {
|
||||
/**
|
||||
* A place where a template is instantiated or rendered.
|
||||
*/
|
||||
overlay[global]
|
||||
class TemplateInstantiation extends DataFlow::Node instanceof TemplateInstantiation::Range {
|
||||
/** Gets a data flow node that refers to the instantiated template string, if any. */
|
||||
DataFlow::SourceNode getOutput() { result = super.getOutput() }
|
||||
@@ -206,6 +217,7 @@ module Templating {
|
||||
}
|
||||
|
||||
/** Companion module to the `TemplateInstantiation` class. */
|
||||
overlay[global]
|
||||
module TemplateInstantiation {
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/** Gets a data flow node that refers to the instantiated template, if any. */
|
||||
@@ -230,6 +242,7 @@ module Templating {
|
||||
}
|
||||
|
||||
/** Gets an API node that may flow to `succ` through a template instantiation. */
|
||||
overlay[global]
|
||||
private API::Node getTemplateInput(DataFlow::SourceNode succ) {
|
||||
exists(TemplateInstantiation inst, API::Node base, string name |
|
||||
base.asSink() = inst.getTemplateParamsNode() and
|
||||
@@ -258,6 +271,7 @@ module Templating {
|
||||
)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
private class TemplateInputStep extends DataFlow::SharedFlowStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
getTemplateInput(succ).asSink() = pred
|
||||
@@ -268,6 +282,7 @@ module Templating {
|
||||
* A data flow step from the expression in a placeholder tag to the tag itself,
|
||||
* representing the value plugged into the template.
|
||||
*/
|
||||
overlay[global]
|
||||
private class TemplatePlaceholderStep extends DataFlow::SharedFlowStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(TemplatePlaceholderTag tag |
|
||||
@@ -281,6 +296,7 @@ module Templating {
|
||||
* A taint step from a `TemplatePlaceholderTag` to the enclosing expression in the
|
||||
* surrounding JavaScript program.
|
||||
*/
|
||||
overlay[global]
|
||||
private class PlaceholderToGeneratedCodeStep extends TaintTracking::SharedTaintStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(TemplatePlaceholderTag tag |
|
||||
@@ -296,6 +312,7 @@ module Templating {
|
||||
final TemplatePlaceholderTag getAPlaceholder() { result.getFile() = this }
|
||||
|
||||
/** Gets a template file referenced by this one via a template inclusion tag, such as `{% include foo %}` */
|
||||
overlay[global]
|
||||
TemplateFile getAnImportedFile() {
|
||||
result = this.getAPlaceholder().(TemplateInclusionTag).getImportedFile()
|
||||
}
|
||||
@@ -314,6 +331,7 @@ module Templating {
|
||||
* - The root folder is considered unknown, and so a heuristic is used to guess the most
|
||||
* likely template file being referenced.
|
||||
*/
|
||||
overlay[global]
|
||||
abstract class TemplateFileReference extends DataFlow::Node {
|
||||
/** Gets the value that identifies the template. */
|
||||
string getValue() {
|
||||
@@ -335,6 +353,7 @@ module Templating {
|
||||
}
|
||||
|
||||
/** Get file argument of a template instantiation, seen as a template file reference. */
|
||||
overlay[global]
|
||||
private class DefaultTemplateFileReference extends TemplateFileReference {
|
||||
DefaultTemplateFileReference() { this = any(TemplateInstantiation inst).getTemplateFileNode() }
|
||||
}
|
||||
@@ -352,6 +371,7 @@ module Templating {
|
||||
* - The root folder is considered unknown, and so a heuristic is used to guess the most
|
||||
* likely template file being referenced.
|
||||
*/
|
||||
overlay[global]
|
||||
abstract class TemplateFileReferenceString extends string {
|
||||
bindingset[this]
|
||||
TemplateFileReferenceString() { this = this }
|
||||
@@ -382,6 +402,7 @@ module Templating {
|
||||
}
|
||||
|
||||
/** The value of a template reference node, as a template reference string. */
|
||||
overlay[global]
|
||||
private class DefaultTemplateReferenceString extends TemplateFileReferenceString {
|
||||
TemplateFileReference r;
|
||||
|
||||
@@ -397,6 +418,7 @@ module Templating {
|
||||
}
|
||||
|
||||
/** The `X` in a path of form `../X`, treated as a separate path string with a different context folder. */
|
||||
overlay[global]
|
||||
private class UpwardTraversalSuffix extends TemplateFileReferenceString {
|
||||
TemplateFileReferenceString original;
|
||||
|
||||
@@ -412,6 +434,7 @@ module Templating {
|
||||
* Gets a "fingerprint" for the given template file, which is used to references
|
||||
* that might refer to it (for pruning purposes only).
|
||||
*/
|
||||
overlay[global]
|
||||
pragma[nomagic]
|
||||
private string getTemplateFileFingerprint(TemplateFile file) {
|
||||
result = file.getStem()
|
||||
@@ -424,6 +447,7 @@ module Templating {
|
||||
* Gets a "fingerprint" for the given string, which must match one of the fingerprints of
|
||||
* the referenced file (for pruning purposes only).
|
||||
*/
|
||||
overlay[global]
|
||||
pragma[nomagic]
|
||||
private string getTemplateRefFingerprint(TemplateFileReferenceString ref) {
|
||||
result = ref.getStem() and not result = ["index", ""]
|
||||
@@ -442,6 +466,7 @@ module Templating {
|
||||
*
|
||||
* This is only used to speed up `getAMatchingTarget` by pruning out pairs that can't match.
|
||||
*/
|
||||
overlay[global]
|
||||
pragma[nomagic]
|
||||
private TemplateFile getAPotentialTarget(TemplateFileReferenceString ref) {
|
||||
getTemplateFileFingerprint(result) = getTemplateRefFingerprint(ref)
|
||||
@@ -467,6 +492,7 @@ module Templating {
|
||||
* Additionally, a file whose stem is `index` matches if `ref` would match the parent folder by
|
||||
* the above rules. For example: `bar` matches `src/bar/index.html`.
|
||||
*/
|
||||
overlay[global]
|
||||
pragma[nomagic]
|
||||
private TemplateFile getAMatchingTarget(TemplateFileReferenceString ref) {
|
||||
result = getAPotentialTarget(ref) and
|
||||
@@ -491,6 +517,7 @@ module Templating {
|
||||
* The string `list` in `A/components/foo.js` will resolve to `A/views/list.html`,
|
||||
* and vice versa in `B/components/foo.js`.
|
||||
*/
|
||||
overlay[global]
|
||||
pragma[nomagic]
|
||||
private int getRankOfMatchingTarget(
|
||||
TemplateFile file, Folder baseFolder, TemplateFileReferenceString ref
|
||||
@@ -508,6 +535,7 @@ module Templating {
|
||||
/**
|
||||
* Gets the template file referred to by `ref` when resolved from `baseFolder`.
|
||||
*/
|
||||
overlay[global]
|
||||
private TemplateFile getBestMatchingTarget(Folder baseFolder, TemplateFileReferenceString ref) {
|
||||
result = max(getAMatchingTarget(ref) as f order by getRankOfMatchingTarget(f, baseFolder, ref))
|
||||
}
|
||||
@@ -599,6 +627,7 @@ module Templating {
|
||||
override string getAPackageName() { result = "dot" }
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
private TemplateSyntax getOwnTemplateSyntaxInFolder(Folder f) {
|
||||
exists(PackageDependencies deps |
|
||||
deps.getADependency(result.getAPackageName(), _) and
|
||||
@@ -606,6 +635,7 @@ module Templating {
|
||||
)
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
private TemplateSyntax getTemplateSyntaxInFolder(Folder f) {
|
||||
result = getOwnTemplateSyntaxInFolder(f)
|
||||
or
|
||||
@@ -613,6 +643,7 @@ module Templating {
|
||||
result = getTemplateSyntaxInFolder(f.getParentContainer())
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
private TemplateSyntax getTemplateSyntaxFromInstantiation(TemplateFile file) {
|
||||
result = any(TemplateInstantiation inst | inst.getTemplateFile() = file).getTemplateSyntax()
|
||||
}
|
||||
@@ -620,6 +651,7 @@ module Templating {
|
||||
/**
|
||||
* Gets a template syntax likely to be used in the given file.
|
||||
*/
|
||||
overlay[global]
|
||||
TemplateSyntax getLikelyTemplateSyntax(TemplateFile file) {
|
||||
result = getTemplateSyntaxFromInstantiation(file)
|
||||
or
|
||||
@@ -632,6 +664,7 @@ module Templating {
|
||||
}
|
||||
|
||||
/** A step through the `safe` pipe, which bypasses HTML escaping. */
|
||||
overlay[global]
|
||||
private class SafePipeStep extends TaintTracking::SharedTaintStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(DataFlow::CallNode call |
|
||||
@@ -645,6 +678,7 @@ module Templating {
|
||||
/**
|
||||
* An EJS-style `include` call within a template tag, such as `<%- include(file, { params }) %>`.
|
||||
*/
|
||||
overlay[global]
|
||||
private class EjsIncludeCallInTemplate extends TemplateInstantiation::Range, DataFlow::CallNode {
|
||||
EjsIncludeCallInTemplate() {
|
||||
exists(TemplatePlaceholderTag tag |
|
||||
@@ -669,6 +703,7 @@ module Templating {
|
||||
*
|
||||
* These API nodes are used in the `getTemplateInput` predicate.
|
||||
*/
|
||||
overlay[global]
|
||||
private class IncludeFunctionAsEntryPoint extends API::EntryPoint {
|
||||
IncludeFunctionAsEntryPoint() { this = "IncludeFunctionAsEntryPoint" }
|
||||
|
||||
@@ -703,6 +738,7 @@ module Templating {
|
||||
string getPath() { result = rawPath.trim().replaceAll("\\", "/").regexpReplaceAll("^\\./", "") }
|
||||
|
||||
/** Gets the file referenced by this inclusion tag. */
|
||||
overlay[global]
|
||||
TemplateFile getImportedFile() {
|
||||
result =
|
||||
this.getPath()
|
||||
@@ -712,6 +748,7 @@ module Templating {
|
||||
}
|
||||
|
||||
/** The imported string from a template inclusion tag. */
|
||||
overlay[global]
|
||||
private class TemplateInclusionPathString extends TemplateFileReferenceString {
|
||||
TemplateInclusionTag tag;
|
||||
|
||||
@@ -723,6 +760,7 @@ module Templating {
|
||||
/**
|
||||
* A call to a member of the `consolidate` library, seen as a template instantiation.
|
||||
*/
|
||||
overlay[global]
|
||||
private class ConsolidateCall extends TemplateInstantiation::Range, API::CallNode {
|
||||
string engine;
|
||||
|
||||
|
||||
@@ -422,9 +422,11 @@ private module ClosureLibraryUri {
|
||||
}
|
||||
}
|
||||
|
||||
overlay[local]
|
||||
private class QueryStringStringification extends DataFlow::SummarizedCallable {
|
||||
QueryStringStringification() { this = "query-string stringification" }
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::InvokeNode getACall() {
|
||||
result =
|
||||
API::moduleImport(["querystring", "query-string", "querystringify", "qs"])
|
||||
|
||||
@@ -48,6 +48,7 @@ private class ThreatModelSourceFromDataExtension extends ThreatModelSource::Rang
|
||||
}
|
||||
}
|
||||
|
||||
overlay[local]
|
||||
private class SummarizedCallableFromModel extends DataFlow::SummarizedCallable {
|
||||
string type;
|
||||
string path;
|
||||
@@ -57,6 +58,7 @@ private class SummarizedCallableFromModel extends DataFlow::SummarizedCallable {
|
||||
this = type + ";" + path
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
override DataFlow::InvokeNode getACall() { ModelOutput::resolvedSummaryBase(type, path, result) }
|
||||
|
||||
override predicate propagatesFlow(
|
||||
|
||||
@@ -62,6 +62,8 @@
|
||||
* should be prefixed with a tilde character (`~`). For example, `~Bar` can be used to indicate that
|
||||
* the type is not intended to match a static type.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import codeql.util.Unit
|
||||
private import ApiGraphModelsSpecific as Specific
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Defines extensible predicates for contributing library models from data extensions.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
/**
|
||||
* Holds if the value at `(type, path)` should be seen as a flow
|
||||
|
||||
@@ -41,6 +41,7 @@ class Location = JS::Location;
|
||||
* The model generator must explicitly generate the step between `(package)` and `(package).foo`, for example.
|
||||
*/
|
||||
bindingset[rawType]
|
||||
overlay[caller]
|
||||
predicate parseTypeString(string rawType, string package, string qualifiedName) {
|
||||
exists(string regexp |
|
||||
regexp = "('[^']+'|[^.]+)(.*)" and
|
||||
@@ -55,6 +56,7 @@ predicate parseTypeString(string rawType, string package, string qualifiedName)
|
||||
/**
|
||||
* Holds if models describing `package` may be relevant for the analysis of this database.
|
||||
*/
|
||||
overlay[local]
|
||||
predicate isPackageUsed(string package) {
|
||||
package = "global"
|
||||
or
|
||||
@@ -68,6 +70,7 @@ predicate isPackageUsed(string package) {
|
||||
}
|
||||
|
||||
bindingset[type]
|
||||
overlay[local]
|
||||
predicate isTypeUsed(string type) {
|
||||
exists(string package |
|
||||
parseTypeString(type, package, _) and
|
||||
@@ -79,8 +82,10 @@ predicate isTypeUsed(string type) {
|
||||
* Holds if `type` can be obtained from an instance of `otherType` due to
|
||||
* language semantics modeled by `getExtraNodeFromType`.
|
||||
*/
|
||||
overlay[local]
|
||||
predicate hasImplicitTypeModel(string type, string otherType) { none() }
|
||||
|
||||
overlay[local]
|
||||
pragma[nomagic]
|
||||
private predicate parseRelevantTypeString(string rawType, string package, string qualifiedName) {
|
||||
isRelevantFullPath(rawType, _) and
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
* Provides classes for working with basic blocks, and predicates for computing
|
||||
* liveness information for local variables.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import javascript
|
||||
private import semmle.javascript.internal.StmtContainers
|
||||
|
||||
@@ -40,6 +40,7 @@ module Stages {
|
||||
/**
|
||||
* The `ast` stage.
|
||||
*/
|
||||
overlay[local]
|
||||
cached
|
||||
module Ast {
|
||||
/**
|
||||
@@ -84,6 +85,7 @@ module Stages {
|
||||
/**
|
||||
* The `basicblocks` stage.
|
||||
*/
|
||||
overlay[local]
|
||||
cached
|
||||
module BasicBlocks {
|
||||
/**
|
||||
@@ -110,6 +112,7 @@ module Stages {
|
||||
/**
|
||||
* The part of data flow computed before flow summary nodes.
|
||||
*/
|
||||
overlay[local]
|
||||
cached
|
||||
module EarlyDataFlowStage {
|
||||
/**
|
||||
@@ -134,6 +137,7 @@ module Stages {
|
||||
/**
|
||||
* The `dataflow` stage.
|
||||
*/
|
||||
overlay[local]
|
||||
cached
|
||||
module DataFlowStage {
|
||||
/**
|
||||
@@ -167,8 +171,8 @@ module Stages {
|
||||
or
|
||||
exists(any(DataFlow::PropRef ref).getBase())
|
||||
or
|
||||
exists(any(DataFlow::ClassNode cls))
|
||||
or
|
||||
// exists(any(DataFlow::ClassNode cls)) // Depends on AnalyzedNode
|
||||
// or
|
||||
exists(any(DataFlow::CallNode node).getArgument(_))
|
||||
or
|
||||
exists(any(DataFlow::CallNode node).getAnArgument())
|
||||
@@ -202,8 +206,6 @@ module Stages {
|
||||
or
|
||||
exists(any(Import i).getImportedModule())
|
||||
or
|
||||
exists(DataFlow::moduleImport(_))
|
||||
or
|
||||
exists(any(ReExportDeclaration d).getReExportedModule())
|
||||
or
|
||||
exists(any(Module m).getABulkExportedNode())
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* Provides predicates and classes for relating nodes to their
|
||||
* enclosing `StmtContainer`.
|
||||
*/
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.internal.CachedStages
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
*
|
||||
* (Promise is absent in the table above as there currently are no name clashes with Promise methods)
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.internal.DataFlowNode
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* Note that some of Array methods are modeled in `AmbiguousCoreMethods.qll`, and `toString` is special-cased elsewhere.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.FlowSummary
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Contains flow steps to model flow through `async` functions and the `await` operator.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.internal.DataFlowNode
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.FlowSummary
|
||||
private import semmle.javascript.dataflow.InferredTypes
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Contains flow steps to model flow from a module into a dynamic `import()` expression.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.internal.DataFlowNode
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Contains a summary for propagating exceptions out of callbacks
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import FlowSummaryUtil
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.FlowSummary
|
||||
private import semmle.javascript.dataflow.internal.Contents::Private
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Contains flow steps to model flow through `for..of` loops.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.internal.DataFlowNode
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Contains flow steps to model flow through generator functions.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.internal.DataFlowNode
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Contains flow summaries and steps modeling flow through iterators.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.internal.DataFlowNode
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Contains implicit read steps at the input to any function that converts a deep object to a string, such as `JSON.stringify`.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import FlowSummaryUtil
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Contains flow summaries and steps modeling flow through `Map` objects.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.FlowSummary
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Contains flow summaries and steps modeling flow through `Promise` objects.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.FlowSummary
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Contains flow summaries and steps modeling flow through `Set` objects.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.FlowSummary
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Contains flow summaries and steps modeling flow through string methods.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.FlowSummary
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
private import semmle.javascript.dataflow.FlowSummary
|
||||
private import semmle.javascript.dataflow.InferredTypes
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*
|
||||
* For now, the `URLSearchParams` object is modeled as a `Map` object.
|
||||
*/
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import javascript
|
||||
|
||||
|
||||
Reference in New Issue
Block a user