mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge pull request #20424 from asgerf/js/overlay-manual-v4
JS: Add overlay annotations
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Provides classes and predicates for the 'js/useless-expression' query.
|
* Provides classes and predicates for the 'js/useless-expression' query.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
import DOMProperties
|
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.
|
* Holds if there exists a getter for a property called `name` anywhere in the program.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate isGetterProperty(string name) {
|
predicate isGetterProperty(string name) {
|
||||||
// there is a call of the form `Object.defineProperty(..., name, descriptor)` ...
|
// there is a call of the form `Object.defineProperty(..., name, descriptor)` ...
|
||||||
exists(CallToObjectDefineProperty defProp | name = defProp.getPropertyName() |
|
exists(CallToObjectDefineProperty defProp | name = defProp.getPropertyName() |
|
||||||
@@ -85,6 +88,7 @@ predicate isGetterProperty(string name) {
|
|||||||
/**
|
/**
|
||||||
* A property access that may invoke a getter.
|
* A property access that may invoke a getter.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
class GetterPropertyAccess extends PropAccess {
|
class GetterPropertyAccess extends PropAccess {
|
||||||
override predicate isImpure() { isGetterProperty(this.getPropertyName()) }
|
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
|
* even if they do, the call itself is useless and should be flagged by this
|
||||||
* query.
|
* query.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate noSideEffects(Expr e) {
|
predicate noSideEffects(Expr e) {
|
||||||
e.isPure()
|
e.isPure()
|
||||||
or
|
or
|
||||||
@@ -148,6 +153,7 @@ predicate isCompoundExpression(Expr e) {
|
|||||||
/**
|
/**
|
||||||
* Holds if the expression `e` should be reported as having no effect.
|
* Holds if the expression `e` should be reported as having no effect.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate hasNoEffect(Expr e) {
|
predicate hasNoEffect(Expr e) {
|
||||||
noSideEffects(e) and
|
noSideEffects(e) and
|
||||||
inVoidContext(e) and
|
inVoidContext(e) and
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Provides a predicate for identifying unused index variables in loops.
|
* Provides a predicate for identifying unused index variables in loops.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
* Provides classes for working with
|
* Provides classes for working with
|
||||||
* [Asynchronous Module Definitions](https://github.com/amdjs/amdjs-api/wiki/AMD).
|
* [Asynchronous Module Definitions](https://github.com/amdjs/amdjs-api/wiki/AMD).
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import semmle.javascript.internal.CachedStages
|
private import semmle.javascript.internal.CachedStages
|
||||||
@@ -62,9 +64,11 @@ class AmdModuleDefinition extends CallExpr instanceof AmdModuleDefinition::Range
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** DEPRECATED. Use `getDependencyExpr` instead. */
|
/** DEPRECATED. Use `getDependencyExpr` instead. */
|
||||||
|
overlay[global]
|
||||||
deprecated PathExpr getDependency(int i) { result = this.getDependencyExpr(i) }
|
deprecated PathExpr getDependency(int i) { result = this.getDependencyExpr(i) }
|
||||||
|
|
||||||
/** DEPRECATED. Use `getADependencyExpr` instead. */
|
/** DEPRECATED. Use `getADependencyExpr` instead. */
|
||||||
|
overlay[global]
|
||||||
deprecated PathExpr getADependency() { result = this.getADependencyExpr() }
|
deprecated PathExpr getADependency() { result = this.getADependencyExpr() }
|
||||||
|
|
||||||
/** Gets the `i`th dependency of this module definition. */
|
/** 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
|
* Gets an abstract value representing one or more values that may flow
|
||||||
* into this module's `module.exports` property.
|
* into this module's `module.exports` property.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
DefiniteAbstractValue getAModuleExportsValue() {
|
DefiniteAbstractValue getAModuleExportsValue() {
|
||||||
result = [this.getAnImplicitExportsValue(), this.getAnExplicitExportsValue()]
|
result = [this.getAnImplicitExportsValue(), this.getAnExplicitExportsValue()]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
pragma[noinline, nomagic]
|
pragma[noinline, nomagic]
|
||||||
private AbstractValue getAnImplicitExportsValue() {
|
private AbstractValue getAnImplicitExportsValue() {
|
||||||
// implicit exports: anything that is returned from the factory function
|
// implicit exports: anything that is returned from the factory function
|
||||||
result = this.getModuleExpr().analyze().getAValue()
|
result = this.getModuleExpr().analyze().getAValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private AbstractValue getAnExplicitExportsValue() {
|
private AbstractValue getAnExplicitExportsValue() {
|
||||||
// explicit exports: anything assigned to `module.exports`
|
// 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"] }
|
private predicate isPseudoDependency(string s) { s = ["exports", "require", "module"] }
|
||||||
|
|
||||||
/** An AMD dependency, considered as a path expression. */
|
/** An AMD dependency, considered as a path expression. */
|
||||||
|
overlay[global]
|
||||||
private class AmdDependencyPath extends PathExprCandidate {
|
private class AmdDependencyPath extends PathExprCandidate {
|
||||||
AmdDependencyPath() {
|
AmdDependencyPath() {
|
||||||
exists(AmdModuleDefinition amd |
|
exists(AmdModuleDefinition amd |
|
||||||
@@ -239,6 +247,7 @@ private class AmdDependencyPath extends PathExprCandidate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A constant path element appearing in an AMD dependency expression. */
|
/** A constant path element appearing in an AMD dependency expression. */
|
||||||
|
overlay[global]
|
||||||
deprecated private class ConstantAmdDependencyPathElement extends PathExpr, ConstantString {
|
deprecated private class ConstantAmdDependencyPathElement extends PathExpr, ConstantString {
|
||||||
ConstantAmdDependencyPathElement() { this = any(AmdDependencyPath amd).getAPart() }
|
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
|
* Specifically, we look for files whose absolute path ends with the imported path, possibly
|
||||||
* adding well-known JavaScript file extensions like `.js`.
|
* adding well-known JavaScript file extensions like `.js`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private File guessTarget() {
|
private File guessTarget() {
|
||||||
exists(FilePath imported, string abspath, string dirname, string basename |
|
exists(FilePath imported, string abspath, string dirname, string basename |
|
||||||
this.targetCandidate(result, abspath, imported, dirname, 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
|
* 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`.
|
* `dirname` and `basename` to the dirname and basename (respectively) of `imported`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private predicate targetCandidate(
|
private predicate targetCandidate(
|
||||||
File f, string abspath, FilePath imported, string dirname, string basename
|
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.
|
* Gets the module whose absolute path matches this import, if there is only a single such module.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private Module resolveByAbsolutePath() {
|
private Module resolveByAbsolutePath() {
|
||||||
result.getFile() = unique(File file | file = this.guessTarget())
|
result.getFile() = unique(File file | file = this.guessTarget())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override Module getImportedModule() {
|
override Module getImportedModule() {
|
||||||
result = super.getImportedModule()
|
result = super.getImportedModule()
|
||||||
or
|
or
|
||||||
@@ -348,14 +361,12 @@ private class AmdDependencyImport extends Import {
|
|||||||
*/
|
*/
|
||||||
class AmdModule extends Module {
|
class AmdModule extends Module {
|
||||||
cached
|
cached
|
||||||
AmdModule() {
|
AmdModule() { exists(unique(AmdModuleDefinition def | amdModuleTopLevel(def, this))) }
|
||||||
Stages::DataFlowStage::ref() and
|
|
||||||
exists(unique(AmdModuleDefinition def | amdModuleTopLevel(def, this)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the definition of this module. */
|
/** Gets the definition of this module. */
|
||||||
AmdModuleDefinition getDefine() { amdModuleTopLevel(result, this) }
|
AmdModuleDefinition getDefine() { amdModuleTopLevel(result, this) }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::Node getAnExportedValue(string name) {
|
override DataFlow::Node getAnExportedValue(string name) {
|
||||||
exists(DataFlow::PropWrite pwn | result = pwn.getRhs() |
|
exists(DataFlow::PropWrite pwn | result = pwn.getRhs() |
|
||||||
pwn.getBase().analyze().getAValue() = this.getDefine().getAModuleExportsValue() and
|
pwn.getBase().analyze().getAValue() = this.getDefine().getAModuleExportsValue() and
|
||||||
@@ -363,6 +374,7 @@ class AmdModule extends Module {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::Node getABulkExportedNode() {
|
override DataFlow::Node getABulkExportedNode() {
|
||||||
// Assigned to `module.exports` via the factory's `module` parameter
|
// Assigned to `module.exports` via the factory's `module` parameter
|
||||||
exists(AbstractModuleObject m, DataFlow::PropWrite write |
|
exists(AbstractModuleObject m, DataFlow::PropWrite write |
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Provides classes for working with the AST-based representation of JavaScript programs.
|
* Provides classes for working with the AST-based representation of JavaScript programs.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import internal.StmtContainers
|
private import internal.StmtContainers
|
||||||
@@ -172,6 +174,7 @@ class AstNode extends @ast_node, NodeInStmtContainer {
|
|||||||
* The TypeScript compiler emits no code for ambient declarations, but they
|
* The TypeScript compiler emits no code for ambient declarations, but they
|
||||||
* can affect name resolution and type checking at compile-time.
|
* can affect name resolution and type checking at compile-time.
|
||||||
*/
|
*/
|
||||||
|
overlay[caller?]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate isAmbient() {
|
predicate isAmbient() {
|
||||||
this.isAmbientInternal()
|
this.isAmbientInternal()
|
||||||
@@ -470,9 +473,12 @@ module AST {
|
|||||||
*/
|
*/
|
||||||
class ValueNode extends AstNode, @dataflownode {
|
class ValueNode extends AstNode, @dataflownode {
|
||||||
/** Gets type inference results for this element. */
|
/** Gets type inference results for this element. */
|
||||||
|
overlay[global]
|
||||||
DataFlow::AnalyzedNode analyze() { result = DataFlow::valueNode(this).analyze() }
|
DataFlow::AnalyzedNode analyze() { result = DataFlow::valueNode(this).analyze() }
|
||||||
|
|
||||||
/** Gets the data flow node associated with this program element. */
|
/** Gets the data flow node associated with this program element. */
|
||||||
|
overlay[caller]
|
||||||
|
pragma[inline]
|
||||||
DataFlow::ValueNode flow() { result = DataFlow::valueNode(this) }
|
DataFlow::ValueNode flow() { result = DataFlow::valueNode(this) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -481,6 +487,7 @@ module AST {
|
|||||||
* This can be used to map an expression to the class it refers to, or
|
* 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.
|
* associate it with a named value coming from an dependency.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
ExprNameBindingNode getNameBinding() { result = this }
|
ExprNameBindingNode getNameBinding() { result = this }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -490,6 +497,7 @@ module AST {
|
|||||||
* (according to the type system), or to associate it with a named type coming
|
* (according to the type system), or to associate it with a named type coming
|
||||||
* from a dependency.
|
* from a dependency.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
TypeNameBindingNode getTypeBinding() { TypeResolution::valueHasType(this, result) }
|
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
|
* 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.
|
* import specifier `x as y` forms part of the preamble.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import internal.StmtContainers
|
private import internal.StmtContainers
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
* Class declarations and class expressions are modeled by (QL) classes `ClassDeclaration`
|
* Class declarations and class expressions are modeled by (QL) classes `ClassDeclaration`
|
||||||
* and `ClassExpression`, respectively, which are both subclasses of `ClassDefinition`.
|
* and `ClassExpression`, respectively, which are both subclasses of `ClassDefinition`.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
@@ -119,6 +121,7 @@ class ClassOrInterface extends @class_or_interface, TypeParameterized {
|
|||||||
*
|
*
|
||||||
* Anonymous classes and interfaces do not have a canonical name.
|
* Anonymous classes and interfaces do not have a canonical name.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated TypeName getTypeName() { result.getADefinition() = this }
|
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.
|
* Gets the definition of the super class of this class, if it can be determined.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
ClassDefinition getSuperClassDefinition() {
|
ClassDefinition getSuperClassDefinition() {
|
||||||
result = this.getSuperClass().analyze().getAValue().(AbstractClass).getClass()
|
result = this.getSuperClass().analyze().getAValue().(AbstractClass).getClass()
|
||||||
}
|
}
|
||||||
@@ -580,6 +584,7 @@ class MemberDeclaration extends @property, Documentable {
|
|||||||
int getMemberIndex() { properties(this, _, result, _, _) }
|
int getMemberIndex() { properties(this, _, result, _, _) }
|
||||||
|
|
||||||
/** Holds if the name of this member is computed by an impure expression. */
|
/** Holds if the name of this member is computed by an impure expression. */
|
||||||
|
overlay[global]
|
||||||
predicate hasImpureNameExpr() { this.isComputed() and this.getNameExpr().isImpure() }
|
predicate hasImpureNameExpr() { this.isComputed() and this.getNameExpr().isImpure() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Provides classes for working with the Closure-Library module system.
|
* Provides classes for working with the Closure-Library module system.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
@@ -40,6 +42,7 @@ module Closure {
|
|||||||
/**
|
/**
|
||||||
* A reference to a Closure namespace.
|
* A reference to a Closure namespace.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class ClosureNamespaceRef extends DataFlow::Node instanceof ClosureNamespaceRef::Range {
|
deprecated class ClosureNamespaceRef extends DataFlow::Node instanceof ClosureNamespaceRef::Range {
|
||||||
/**
|
/**
|
||||||
* Gets the namespace being referenced.
|
* Gets the namespace being referenced.
|
||||||
@@ -47,6 +50,7 @@ module Closure {
|
|||||||
string getClosureNamespace() { result = super.getClosureNamespace() }
|
string getClosureNamespace() { result = super.getClosureNamespace() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
deprecated module ClosureNamespaceRef {
|
deprecated module ClosureNamespaceRef {
|
||||||
/**
|
/**
|
||||||
* A reference to a Closure namespace.
|
* A reference to a Closure namespace.
|
||||||
@@ -64,9 +68,11 @@ module Closure {
|
|||||||
/**
|
/**
|
||||||
* A data flow node that returns the value of a closure namespace.
|
* A data flow node that returns the value of a closure namespace.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class ClosureNamespaceAccess extends ClosureNamespaceRef instanceof ClosureNamespaceAccess::Range
|
deprecated class ClosureNamespaceAccess extends ClosureNamespaceRef instanceof ClosureNamespaceAccess::Range
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
deprecated module ClosureNamespaceAccess {
|
deprecated module ClosureNamespaceAccess {
|
||||||
/**
|
/**
|
||||||
* A data flow node that returns the value of a closure namespace.
|
* 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.
|
* A call to a method on the `goog.` namespace, as a closure reference.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
abstract deprecated private class DefaultNamespaceRef extends DataFlow::MethodCallNode,
|
abstract deprecated private class DefaultNamespaceRef extends DataFlow::MethodCallNode,
|
||||||
ClosureNamespaceRef::Range
|
ClosureNamespaceRef::Range
|
||||||
{
|
{
|
||||||
@@ -91,6 +98,7 @@ module Closure {
|
|||||||
* Holds if `node` is the data flow node corresponding to the expression in
|
* Holds if `node` is the data flow node corresponding to the expression in
|
||||||
* a top-level expression statement.
|
* a top-level expression statement.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated private predicate isTopLevelExpr(DataFlow::Node node) {
|
deprecated private predicate isTopLevelExpr(DataFlow::Node node) {
|
||||||
any(TopLevel tl).getAChildStmt().(ExprStmt).getExpr().flow() = node
|
any(TopLevel tl).getAChildStmt().(ExprStmt).getExpr().flow() = node
|
||||||
}
|
}
|
||||||
@@ -98,6 +106,7 @@ module Closure {
|
|||||||
/**
|
/**
|
||||||
* A top-level call to `goog.provide`.
|
* A top-level call to `goog.provide`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated private class DefaultClosureProvideCall extends DefaultNamespaceRef {
|
deprecated private class DefaultClosureProvideCall extends DefaultNamespaceRef {
|
||||||
DefaultClosureProvideCall() {
|
DefaultClosureProvideCall() {
|
||||||
this.getMethodName() = "provide" and
|
this.getMethodName() = "provide" and
|
||||||
@@ -108,12 +117,14 @@ module Closure {
|
|||||||
/**
|
/**
|
||||||
* A top-level call to `goog.provide`.
|
* A top-level call to `goog.provide`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class ClosureProvideCall extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureProvideCall
|
deprecated class ClosureProvideCall extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureProvideCall
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A call to `goog.require`.
|
* A call to `goog.require`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated private class DefaultClosureRequireCall extends DefaultNamespaceRef,
|
deprecated private class DefaultClosureRequireCall extends DefaultNamespaceRef,
|
||||||
ClosureNamespaceAccess::Range
|
ClosureNamespaceAccess::Range
|
||||||
{
|
{
|
||||||
@@ -123,12 +134,14 @@ module Closure {
|
|||||||
/**
|
/**
|
||||||
* A call to `goog.require`.
|
* A call to `goog.require`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class ClosureRequireCall extends ClosureNamespaceAccess, DataFlow::MethodCallNode instanceof DefaultClosureRequireCall
|
deprecated class ClosureRequireCall extends ClosureNamespaceAccess, DataFlow::MethodCallNode instanceof DefaultClosureRequireCall
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A top-level call to `goog.module` or `goog.declareModuleId`.
|
* A top-level call to `goog.module` or `goog.declareModuleId`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated private class DefaultClosureModuleDeclaration extends DefaultNamespaceRef {
|
deprecated private class DefaultClosureModuleDeclaration extends DefaultNamespaceRef {
|
||||||
DefaultClosureModuleDeclaration() {
|
DefaultClosureModuleDeclaration() {
|
||||||
(this.getMethodName() = "module" or this.getMethodName() = "declareModuleId") and
|
(this.getMethodName() = "module" or this.getMethodName() = "declareModuleId") and
|
||||||
@@ -139,6 +152,7 @@ module Closure {
|
|||||||
/**
|
/**
|
||||||
* A top-level call to `goog.module` or `goog.declareModuleId`.
|
* A top-level call to `goog.module` or `goog.declareModuleId`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class ClosureModuleDeclaration extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureModuleDeclaration
|
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.
|
* Gets the call to `goog.module` or `goog.declareModuleId` in this module.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated ClosureModuleDeclaration getModuleDeclaration() { result.getTopLevel() = this }
|
deprecated ClosureModuleDeclaration getModuleDeclaration() { result.getTopLevel() = this }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -181,6 +196,7 @@ module Closure {
|
|||||||
result = this.getScope().getVariable("exports")
|
result = this.getScope().getVariable("exports")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::Node getAnExportedValue(string name) {
|
override DataFlow::Node getAnExportedValue(string name) {
|
||||||
exists(DataFlow::PropWrite write, Expr base |
|
exists(DataFlow::PropWrite write, Expr base |
|
||||||
result = write.getRhs() and
|
result = write.getRhs() and
|
||||||
@@ -193,6 +209,7 @@ module Closure {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::Node getABulkExportedNode() {
|
override DataFlow::Node getABulkExportedNode() {
|
||||||
result = this.getExportsVariable().getAnAssignedExpr().flow()
|
result = this.getExportsVariable().getAnAssignedExpr().flow()
|
||||||
}
|
}
|
||||||
@@ -232,6 +249,7 @@ module Closure {
|
|||||||
/**
|
/**
|
||||||
* Holds if `name` is a closure namespace, including proper namespace prefixes.
|
* Holds if `name` is a closure namespace, including proper namespace prefixes.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
predicate isClosureNamespace(string name) {
|
predicate isClosureNamespace(string name) {
|
||||||
exists(string namespace |
|
exists(string namespace |
|
||||||
@@ -253,6 +271,7 @@ module Closure {
|
|||||||
* Holds if a prefix of `name` is a closure namespace.
|
* Holds if a prefix of `name` is a closure namespace.
|
||||||
*/
|
*/
|
||||||
bindingset[name]
|
bindingset[name]
|
||||||
|
overlay[global]
|
||||||
private predicate hasClosureNamespacePrefix(string name) {
|
private predicate hasClosureNamespacePrefix(string name) {
|
||||||
isClosureNamespace(name.substring(0, name.indexOf(".")))
|
isClosureNamespace(name.substring(0, name.indexOf(".")))
|
||||||
or
|
or
|
||||||
@@ -262,6 +281,7 @@ module Closure {
|
|||||||
/**
|
/**
|
||||||
* Gets the closure namespace path addressed by the given data flow node, if any.
|
* Gets the closure namespace path addressed by the given data flow node, if any.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
string getClosureNamespaceFromSourceNode(DataFlow::SourceNode node) {
|
string getClosureNamespaceFromSourceNode(DataFlow::SourceNode node) {
|
||||||
node = AccessPath::getAReferenceOrAssignmentTo(result) and
|
node = AccessPath::getAReferenceOrAssignmentTo(result) and
|
||||||
hasClosureNamespacePrefix(result)
|
hasClosureNamespacePrefix(result)
|
||||||
@@ -270,6 +290,7 @@ module Closure {
|
|||||||
/**
|
/**
|
||||||
* Gets the closure namespace path written to by the given property write, if any.
|
* Gets the closure namespace path written to by the given property write, if any.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
string getWrittenClosureNamespace(DataFlow::PropWrite node) {
|
string getWrittenClosureNamespace(DataFlow::PropWrite node) {
|
||||||
node.getRhs() = AccessPath::getAnAssignmentTo(result) and
|
node.getRhs() = AccessPath::getAnAssignmentTo(result) and
|
||||||
hasClosureNamespacePrefix(result)
|
hasClosureNamespacePrefix(result)
|
||||||
@@ -278,6 +299,7 @@ module Closure {
|
|||||||
/**
|
/**
|
||||||
* Gets a data flow node that refers to the given value exported from a Closure module.
|
* Gets a data flow node that refers to the given value exported from a Closure module.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
DataFlow::SourceNode moduleImport(string moduleName) {
|
DataFlow::SourceNode moduleImport(string moduleName) {
|
||||||
getClosureNamespaceFromSourceNode(result) = moduleName
|
getClosureNamespaceFromSourceNode(result) = moduleName
|
||||||
}
|
}
|
||||||
@@ -285,6 +307,7 @@ module Closure {
|
|||||||
/**
|
/**
|
||||||
* A call to `goog.bind`, as a partial function invocation.
|
* A call to `goog.bind`, as a partial function invocation.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private class BindCall extends DataFlow::PartialInvokeNode::Range, DataFlow::CallNode {
|
private class BindCall extends DataFlow::PartialInvokeNode::Range, DataFlow::CallNode {
|
||||||
BindCall() { this = moduleImport("goog.bind").getACall() }
|
BindCall() { this = moduleImport("goog.bind").getACall() }
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/** Provides classes for working with JavaScript comments. */
|
/** Provides classes for working with JavaScript comments. */
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Provides classes for working with expressions that evaluate to constant values.
|
* Provides classes for working with expressions that evaluate to constant values.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import semmle.javascript.internal.CachedStages
|
private import semmle.javascript.internal.CachedStages
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/** Provides classes and predicates for working with variable definitions and uses. */
|
/** Provides classes and predicates for working with variable definitions and uses. */
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
@@ -231,6 +233,7 @@ class VarUse extends ControlFlowNode, @varref instanceof RValue {
|
|||||||
*
|
*
|
||||||
* For global variables, each definition is considered to reach each use.
|
* For global variables, each definition is considered to reach each use.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
VarDef getADef() {
|
VarDef getADef() {
|
||||||
result = this.getSsaVariable().getDefinition().getAContributingVarDef() or
|
result = this.getSsaVariable().getDefinition().getAContributingVarDef() or
|
||||||
result.getAVariable() = this.getVariable().(GlobalVariable)
|
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.
|
* This predicate is only defined for variables that can be SSA-converted.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
SsaVariable getSsaVariable() { result.getAUse() = this }
|
SsaVariable getSsaVariable() { result.getAUse() = this }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Provides classes for working with E4X.
|
* Provides classes for working with E4X.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/** Provides classes for working with ECMAScript 2015 modules. */
|
/** Provides classes for working with ECMAScript 2015 modules. */
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import semmle.javascript.internal.CachedStages
|
private import semmle.javascript.internal.CachedStages
|
||||||
@@ -29,11 +31,13 @@ class ES2015Module extends Module {
|
|||||||
/** Gets an export declaration in this module. */
|
/** Gets an export declaration in this module. */
|
||||||
ExportDeclaration getAnExport() { result.getTopLevel() = this }
|
ExportDeclaration getAnExport() { result.getTopLevel() = this }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::Node getAnExportedValue(string name) {
|
override DataFlow::Node getAnExportedValue(string name) {
|
||||||
exists(ExportDeclaration ed | ed = this.getAnExport() and result = ed.getSourceNode(name))
|
exists(ExportDeclaration ed | ed = this.getAnExport() and result = ed.getSourceNode(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if this module exports variable `v` under the name `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) }
|
predicate exportsAs(LexicalName v, string name) { this.getAnExport().exportsAs(v, name) }
|
||||||
|
|
||||||
override predicate isStrict() {
|
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
|
* 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.
|
* ambiguities, so we only allow the standard interpretation in that case.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate hasBothNamedAndDefaultExports() {
|
predicate hasBothNamedAndDefaultExports() {
|
||||||
hasNamedExports(this) and
|
hasNamedExports(this) and
|
||||||
hasDefaultExport(this)
|
hasDefaultExport(this)
|
||||||
@@ -59,6 +64,7 @@ class ES2015Module extends Module {
|
|||||||
/**
|
/**
|
||||||
* Holds if `mod` contains one or more named export declarations other than `default`.
|
* Holds if `mod` contains one or more named export declarations other than `default`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private predicate hasNamedExports(ES2015Module mod) {
|
private predicate hasNamedExports(ES2015Module mod) {
|
||||||
mod.getAnExport().(ExportNamedDeclaration).getASpecifier().getExportedName() != "default"
|
mod.getAnExport().(ExportNamedDeclaration).getASpecifier().getExportedName() != "default"
|
||||||
or
|
or
|
||||||
@@ -71,6 +77,7 @@ private predicate hasNamedExports(ES2015Module mod) {
|
|||||||
/**
|
/**
|
||||||
* Holds if this module contains a default export.
|
* Holds if this module contains a default export.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private predicate hasDefaultExport(ES2015Module mod) {
|
private predicate hasDefaultExport(ES2015Module mod) {
|
||||||
// export default foo;
|
// export default foo;
|
||||||
mod.getAnExport() instanceof ExportDefaultDeclaration
|
mod.getAnExport() instanceof ExportDefaultDeclaration
|
||||||
@@ -172,6 +179,7 @@ class ImportDeclaration extends Stmt, Import, @import_declaration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A literal path expression appearing in an `import` declaration. */
|
/** A literal path expression appearing in an `import` declaration. */
|
||||||
|
overlay[global]
|
||||||
deprecated private class LiteralImportPath extends PathExpr, ConstantString {
|
deprecated private class LiteralImportPath extends PathExpr, ConstantString {
|
||||||
LiteralImportPath() { exists(ImportDeclaration req | this = req.getChildExpr(-1)) }
|
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 {
|
class ImportSpecifier extends Expr, @import_specifier {
|
||||||
/** Gets the import declaration in which this specifier appears. */
|
/** Gets the import declaration in which this specifier appears. */
|
||||||
|
overlay[global]
|
||||||
ImportDeclaration getImportDeclaration() { result.getASpecifier() = this }
|
ImportDeclaration getImportDeclaration() { result.getASpecifier() = this }
|
||||||
|
|
||||||
/** Gets the imported symbol; undefined for default and namespace import specifiers. */
|
/** Gets the imported symbol; undefined for default and namespace import specifiers. */
|
||||||
@@ -297,6 +306,7 @@ class BulkImportDeclaration extends ImportDeclaration {
|
|||||||
* import console, { log } from 'console';
|
* import console, { log } from 'console';
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
class SelectiveImportDeclaration extends ImportDeclaration {
|
class SelectiveImportDeclaration extends ImportDeclaration {
|
||||||
SelectiveImportDeclaration() { not this instanceof BulkImportDeclaration }
|
SelectiveImportDeclaration() { not this instanceof BulkImportDeclaration }
|
||||||
|
|
||||||
@@ -330,9 +340,11 @@ class SelectiveImportDeclaration extends ImportDeclaration {
|
|||||||
*/
|
*/
|
||||||
abstract class ExportDeclaration extends Stmt, @export_declaration {
|
abstract class ExportDeclaration extends Stmt, @export_declaration {
|
||||||
/** Gets the module to which this export declaration belongs. */
|
/** Gets the module to which this export declaration belongs. */
|
||||||
|
overlay[global]
|
||||||
ES2015Module getEnclosingModule() { this = result.getAnExport() }
|
ES2015Module getEnclosingModule() { this = result.getAnExport() }
|
||||||
|
|
||||||
/** Holds if this export declaration exports variable `v` under the name `name`. */
|
/** Holds if this export declaration exports variable `v` under the name `name`. */
|
||||||
|
overlay[global]
|
||||||
abstract predicate exportsAs(LexicalName v, string name);
|
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
|
* 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.
|
* to module `a` or possibly to some other module from which `a` re-exports.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
abstract DataFlow::Node getSourceNode(string name);
|
abstract DataFlow::Node getSourceNode(string name);
|
||||||
|
|
||||||
/** Holds if is declared with the `type` keyword, so only types are exported. */
|
/** 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. */
|
/** Gets the name of the module from which this declaration re-exports. */
|
||||||
override ConstantString getImportedPath() { result = this.getChildExpr(0) }
|
override ConstantString getImportedPath() { result = this.getChildExpr(0) }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate exportsAs(LexicalName v, string name) {
|
override predicate exportsAs(LexicalName v, string name) {
|
||||||
this.getReExportedES2015Module().exportsAs(v, name) and
|
this.getReExportedES2015Module().exportsAs(v, name) and
|
||||||
not isShadowedFromBulkExport(this, name)
|
not isShadowedFromBulkExport(this, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::Node getSourceNode(string name) {
|
override DataFlow::Node getSourceNode(string name) {
|
||||||
result = this.getReExportedES2015Module().getAnExport().getSourceNode(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,
|
* At runtime, the interface `X` will have been removed, so `X` is actually re-exported anyway,
|
||||||
* but we ignore this subtlety.
|
* but we ignore this subtlety.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private predicate isShadowedFromBulkExport(BulkReExportDeclaration reExport, string name) {
|
private predicate isShadowedFromBulkExport(BulkReExportDeclaration reExport, string name) {
|
||||||
exists(ExportNamedDeclaration other | other.getTopLevel() = reExport.getEnclosingModule() |
|
exists(ExportNamedDeclaration other | other.getTopLevel() = reExport.getEnclosingModule() |
|
||||||
other.getAnExportedDecl().getName() = name
|
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. */
|
/** Gets the operand statement or expression that is exported by this declaration. */
|
||||||
ExprOrStmt getOperand() { result = this.getChild(0) }
|
ExprOrStmt getOperand() { result = this.getChild(0) }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate exportsAs(LexicalName v, string name) {
|
override predicate exportsAs(LexicalName v, string name) {
|
||||||
name = "default" and v = this.getADecl().getVariable()
|
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) {
|
override DataFlow::Node getSourceNode(string name) {
|
||||||
name = "default" and result = DataFlow::valueNode(this.getOperand())
|
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. */
|
/** Gets the variable declaration, if any, exported by this named export. */
|
||||||
VarDecl getADecl() { result = this.getAnExportedDecl() }
|
VarDecl getADecl() { result = this.getAnExportedDecl() }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate exportsAs(LexicalName v, string name) {
|
override predicate exportsAs(LexicalName v, string name) {
|
||||||
exists(LexicalDecl vd | vd = this.getAnExportedDecl() |
|
exists(LexicalDecl vd | vd = this.getAnExportedDecl() |
|
||||||
name = vd.getName() and v = vd.getALexicalName()
|
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) {
|
override DataFlow::Node getSourceNode(string name) {
|
||||||
exists(VarDef d | d.getTarget() = this.getADecl() |
|
exists(VarDef d | d.getTarget() = this.getADecl() |
|
||||||
name = d.getTarget().(VarDecl).getName() and
|
name = d.getTarget().(VarDecl).getName() and
|
||||||
@@ -555,6 +575,7 @@ class ExportNamedDeclaration extends ExportDeclaration, @export_named_declaratio
|
|||||||
|
|
||||||
private import semmle.javascript.dataflow.internal.PreCallGraphStep
|
private import semmle.javascript.dataflow.internal.PreCallGraphStep
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
private class ExportNamespaceStep extends PreCallGraphStep {
|
private class ExportNamespaceStep extends PreCallGraphStep {
|
||||||
override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
|
||||||
exists(ExportNamedDeclaration exprt, ExportNamespaceSpecifier spec |
|
exists(ExportNamedDeclaration exprt, ExportNamespaceSpecifier spec |
|
||||||
@@ -572,6 +593,7 @@ private class ExportNamespaceStep extends PreCallGraphStep {
|
|||||||
private class TypeOnlyExportDeclaration extends ExportNamedDeclaration {
|
private class TypeOnlyExportDeclaration extends ExportNamedDeclaration {
|
||||||
TypeOnlyExportDeclaration() { this.isTypeOnly() }
|
TypeOnlyExportDeclaration() { this.isTypeOnly() }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate exportsAs(LexicalName v, string name) {
|
override predicate exportsAs(LexicalName v, string name) {
|
||||||
super.exportsAs(v, name) and
|
super.exportsAs(v, name) and
|
||||||
not v instanceof Variable
|
not v instanceof Variable
|
||||||
@@ -745,9 +767,11 @@ abstract class ReExportDeclaration extends ExportDeclaration {
|
|||||||
abstract ConstantString getImportedPath();
|
abstract ConstantString getImportedPath();
|
||||||
|
|
||||||
/** Gets the module from which this declaration re-exports, if it is an ES2015 module. */
|
/** Gets the module from which this declaration re-exports, if it is an ES2015 module. */
|
||||||
|
overlay[global]
|
||||||
ES2015Module getReExportedES2015Module() { result = this.getReExportedModule() }
|
ES2015Module getReExportedES2015Module() { result = this.getReExportedModule() }
|
||||||
|
|
||||||
/** Gets the module from which this declaration re-exports. */
|
/** Gets the module from which this declaration re-exports. */
|
||||||
|
overlay[global]
|
||||||
cached
|
cached
|
||||||
Module getReExportedModule() {
|
Module getReExportedModule() {
|
||||||
Stages::Imports::ref() and
|
Stages::Imports::ref() and
|
||||||
@@ -756,6 +780,7 @@ abstract class ReExportDeclaration extends ExportDeclaration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A literal path expression appearing in a re-export declaration. */
|
/** A literal path expression appearing in a re-export declaration. */
|
||||||
|
overlay[global]
|
||||||
deprecated private class LiteralReExportPath extends PathExpr, ConstantString {
|
deprecated private class LiteralReExportPath extends PathExpr, ConstantString {
|
||||||
LiteralReExportPath() { exists(ReExportDeclaration bred | this = bred.getImportedPath()) }
|
LiteralReExportPath() { exists(ReExportDeclaration bred | this = bred.getImportedPath()) }
|
||||||
|
|
||||||
@@ -795,11 +820,13 @@ class SelectiveReExportDeclaration extends ReExportDeclaration, ExportNamedDecla
|
|||||||
class OriginalExportDeclaration extends ExportDeclaration {
|
class OriginalExportDeclaration extends ExportDeclaration {
|
||||||
OriginalExportDeclaration() { not this instanceof ReExportDeclaration }
|
OriginalExportDeclaration() { not this instanceof ReExportDeclaration }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate exportsAs(LexicalName v, string name) {
|
override predicate exportsAs(LexicalName v, string name) {
|
||||||
this.(ExportDefaultDeclaration).exportsAs(v, name) or
|
this.(ExportDefaultDeclaration).exportsAs(v, name) or
|
||||||
this.(ExportNamedDeclaration).exportsAs(v, name)
|
this.(ExportNamedDeclaration).exportsAs(v, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::Node getSourceNode(string name) {
|
override DataFlow::Node getSourceNode(string name) {
|
||||||
result = this.(ExportDefaultDeclaration).getSourceNode(name) or
|
result = this.(ExportDefaultDeclaration).getSourceNode(name) or
|
||||||
result = this.(ExportNamedDeclaration).getSourceNode(name)
|
result = this.(ExportNamedDeclaration).getSourceNode(name)
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/** Provides classes for working with syntax errors. */
|
/** Provides classes for working with syntax errors. */
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Provides classes for working with expressions.
|
* Provides classes for working with expressions.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import semmle.javascript.internal.CachedStages
|
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) }
|
string getStringValue() { Stages::Ast::ref() and result = getStringValue(this) }
|
||||||
|
|
||||||
/** Holds if this expression is impure, that is, its evaluation could have side effects. */
|
/** Holds if this expression is impure, that is, its evaluation could have side effects. */
|
||||||
|
overlay[global]
|
||||||
predicate isImpure() { any() }
|
predicate isImpure() { any() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this expression is pure, that is, its evaluation is guaranteed
|
* Holds if this expression is pure, that is, its evaluation is guaranteed
|
||||||
* to be side-effect free.
|
* to be side-effect free.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate isPure() { not this.isImpure() }
|
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
|
* Holds if this expression accesses the global variable `g`, either directly
|
||||||
* or through the `window` object.
|
* or through the `window` object.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate accessesGlobal(string g) { this.flow().accessesGlobal(g) }
|
predicate accessesGlobal(string g) { this.flow().accessesGlobal(g) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this expression may evaluate to `s`.
|
* Holds if this expression may evaluate to `s`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate mayHaveStringValue(string s) { this.flow().mayHaveStringValue(s) }
|
predicate mayHaveStringValue(string s) { this.flow().mayHaveStringValue(s) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this expression may evaluate to `b`.
|
* Holds if this expression may evaluate to `b`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate mayHaveBooleanValue(boolean b) { this.flow().mayHaveBooleanValue(b) }
|
predicate mayHaveBooleanValue(boolean b) { this.flow().mayHaveBooleanValue(b) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this expression may refer to the initial value of parameter `p`.
|
* Holds if this expression may refer to the initial value of parameter `p`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate mayReferToParameter(Parameter p) { DataFlow::parameterNode(p).flowsToExpr(this) }
|
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
|
* Has no result if the expression is in a JavaScript file or in a TypeScript
|
||||||
* file that was extracted without type information.
|
* file that was extracted without type information.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated Type getType() { ast_node_type(this, result) }
|
deprecated Type getType() { ast_node_type(this, result) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -240,21 +249,16 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[inline]
|
|
||||||
private Stmt getRawEnclosingStmt(Expr e) {
|
|
||||||
// For performance reasons, we need the enclosing statement without overrides
|
|
||||||
enclosing_stmt(e, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the data-flow node where exceptions thrown by this expression will
|
* Gets the data-flow node where exceptions thrown by this expression will
|
||||||
* propagate if this expression causes an exception to be thrown.
|
* propagate if this expression causes an exception to be thrown.
|
||||||
*/
|
*/
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
DataFlow::Node getExceptionTarget() {
|
DataFlow::Node getExceptionTarget() {
|
||||||
result = getCatchParameterFromStmt(this.getRawEnclosingStmt(this))
|
result = getCatchParameterFromStmt(getRawEnclosingStmt(this))
|
||||||
or
|
or
|
||||||
not exists(getCatchParameterFromStmt(this.getRawEnclosingStmt(this))) and
|
not exists(getCatchParameterFromStmt(getRawEnclosingStmt(this))) and
|
||||||
result =
|
result =
|
||||||
any(DataFlow::FunctionNode f | f.getFunction() = this.getContainer()).getExceptionalReturn()
|
any(DataFlow::FunctionNode f | f.getFunction() = this.getContainer()).getExceptionalReturn()
|
||||||
}
|
}
|
||||||
@@ -267,6 +271,13 @@ private DataFlow::Node getCatchParameterFromStmt(Stmt stmt) {
|
|||||||
DataFlow::parameterNode(stmt.getEnclosingTryCatchStmt().getACatchClause().getAParameter())
|
DataFlow::parameterNode(stmt.getEnclosingTryCatchStmt().getACatchClause().getAParameter())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[caller]
|
||||||
|
pragma[inline]
|
||||||
|
private Stmt getRawEnclosingStmt(Expr e) {
|
||||||
|
// For performance reasons, we need the enclosing statement without overrides
|
||||||
|
enclosing_stmt(e, result)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An identifier.
|
* An identifier.
|
||||||
*
|
*
|
||||||
@@ -301,6 +312,7 @@ class Identifier extends @identifier, ExprOrType {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class Label extends @label, Identifier, Expr {
|
class Label extends @label, Identifier, Expr {
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { none() }
|
override predicate isImpure() { none() }
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "Label" }
|
override string getAPrimaryQlClass() { result = "Label" }
|
||||||
@@ -330,6 +342,7 @@ class Literal extends @literal, Expr {
|
|||||||
*/
|
*/
|
||||||
string getRawValue() { literals(_, result, this) }
|
string getRawValue() { literals(_, result, this) }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { none() }
|
override predicate isImpure() { none() }
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "Literal" }
|
override string getAPrimaryQlClass() { result = "Literal" }
|
||||||
@@ -352,6 +365,7 @@ class ParExpr extends @par_expr, Expr {
|
|||||||
|
|
||||||
override int getIntValue() { result = this.getExpression().getIntValue() }
|
override int getIntValue() { result = this.getExpression().getIntValue() }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { this.getExpression().isImpure() }
|
override predicate isImpure() { this.getExpression().isImpure() }
|
||||||
|
|
||||||
override Expr getUnderlyingValue() { result = this.getExpression().getUnderlyingValue() }
|
override Expr getUnderlyingValue() { result = this.getExpression().getUnderlyingValue() }
|
||||||
@@ -500,6 +514,7 @@ class RegExpLiteral extends @regexp_literal, Literal, RegExpParent {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class ThisExpr extends @this_expr, Expr {
|
class ThisExpr extends @this_expr, Expr {
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { none() }
|
override predicate isImpure() { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -555,6 +570,7 @@ class ArrayExpr extends @array_expr, Expr {
|
|||||||
/** Holds if this array literal has an omitted element. */
|
/** Holds if this array literal has an omitted element. */
|
||||||
predicate hasOmittedElement() { this.elementIsOmitted(_) }
|
predicate hasOmittedElement() { this.elementIsOmitted(_) }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { this.getAnElement().isImpure() }
|
override predicate isImpure() { this.getAnElement().isImpure() }
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "ArrayExpr" }
|
override string getAPrimaryQlClass() { result = "ArrayExpr" }
|
||||||
@@ -597,6 +613,7 @@ class ObjectExpr extends @obj_expr, Expr {
|
|||||||
*/
|
*/
|
||||||
predicate hasTrailingComma() { this.getLastToken().getPreviousToken().getValue() = "," }
|
predicate hasTrailingComma() { this.getLastToken().getPreviousToken().getValue() = "," }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { this.getAProperty().isImpure() }
|
override predicate isImpure() { this.getAProperty().isImpure() }
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "ObjectExpr" }
|
override string getAPrimaryQlClass() { result = "ObjectExpr" }
|
||||||
@@ -664,6 +681,7 @@ class Property extends @property, Documentable {
|
|||||||
* Holds if this property is impure, that is, the evaluation of its name or
|
* Holds if this property is impure, that is, the evaluation of its name or
|
||||||
* its initializer expression could have side effects.
|
* its initializer expression could have side effects.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate isImpure() {
|
predicate isImpure() {
|
||||||
this.isComputed() and this.getNameExpr().isImpure()
|
this.isComputed() and this.getNameExpr().isImpure()
|
||||||
or
|
or
|
||||||
@@ -826,6 +844,7 @@ class FunctionExpr extends @function_expr, Expr, Function {
|
|||||||
Stages::Ast::ref() and result = Expr.super.getContainer()
|
Stages::Ast::ref() and result = Expr.super.getContainer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { none() }
|
override predicate isImpure() { none() }
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "FunctionExpr" }
|
override string getAPrimaryQlClass() { result = "FunctionExpr" }
|
||||||
@@ -846,6 +865,7 @@ class ArrowFunctionExpr extends @arrow_function_expr, Expr, Function {
|
|||||||
|
|
||||||
override StmtContainer getEnclosingContainer() { result = Expr.super.getContainer() }
|
override StmtContainer getEnclosingContainer() { result = Expr.super.getContainer() }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { none() }
|
override predicate isImpure() { none() }
|
||||||
|
|
||||||
override Function getThisBinder() {
|
override Function getThisBinder() {
|
||||||
@@ -877,6 +897,7 @@ class SeqExpr extends @seq_expr, Expr {
|
|||||||
/** Gets the last expression in this sequence. */
|
/** Gets the last expression in this sequence. */
|
||||||
Expr getLastOperand() { result = this.getOperand(this.getNumOperands() - 1) }
|
Expr getLastOperand() { result = this.getOperand(this.getNumOperands() - 1) }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { this.getAnOperand().isImpure() }
|
override predicate isImpure() { this.getAnOperand().isImpure() }
|
||||||
|
|
||||||
override Expr getUnderlyingValue() { result = this.getLastOperand().getUnderlyingValue() }
|
override Expr getUnderlyingValue() { result = this.getLastOperand().getUnderlyingValue() }
|
||||||
@@ -906,6 +927,7 @@ class ConditionalExpr extends @conditional_expr, Expr {
|
|||||||
/** Gets either the 'then' or the 'else' expression of this conditional. */
|
/** Gets either the 'then' or the 'else' expression of this conditional. */
|
||||||
Expr getABranch() { result = this.getConsequent() or result = this.getAlternate() }
|
Expr getABranch() { result = this.getConsequent() or result = this.getAlternate() }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() {
|
override predicate isImpure() {
|
||||||
this.getCondition().isImpure() or
|
this.getCondition().isImpure() or
|
||||||
this.getABranch().isImpure()
|
this.getABranch().isImpure()
|
||||||
@@ -985,6 +1007,7 @@ class InvokeExpr extends @invokeexpr, Expr {
|
|||||||
*
|
*
|
||||||
* This predicate is an approximation, computed using only local data flow.
|
* This predicate is an approximation, computed using only local data flow.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate hasOptionArgument(int i, string name, Expr value) {
|
predicate hasOptionArgument(int i, string name, Expr value) {
|
||||||
value = this.flow().(DataFlow::InvokeNode).getOptionArgument(i, name).asExpr()
|
value = this.flow().(DataFlow::InvokeNode).getOptionArgument(i, name).asExpr()
|
||||||
}
|
}
|
||||||
@@ -997,6 +1020,7 @@ class InvokeExpr extends @invokeexpr, Expr {
|
|||||||
*
|
*
|
||||||
* This predicate is only populated for files extracted with full TypeScript extraction.
|
* This predicate is only populated for files extracted with full TypeScript extraction.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated CallSignatureType getResolvedSignature() { invoke_expr_signature(this, result) }
|
deprecated CallSignatureType getResolvedSignature() { invoke_expr_signature(this, result) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1014,6 +1038,7 @@ class InvokeExpr extends @invokeexpr, Expr {
|
|||||||
*
|
*
|
||||||
* This predicate is only populated for files extracted with full TypeScript extraction.
|
* This predicate is only populated for files extracted with full TypeScript extraction.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated CanonicalFunctionName getResolvedCalleeName() { ast_node_symbol(this, result) }
|
deprecated CanonicalFunctionName getResolvedCalleeName() { ast_node_symbol(this, result) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1022,6 +1047,7 @@ class InvokeExpr extends @invokeexpr, Expr {
|
|||||||
* Note that the resolved function may be overridden in a subclass and thus is not
|
* Note that the resolved function may be overridden in a subclass and thus is not
|
||||||
* necessarily the actual target of this invocation at runtime.
|
* necessarily the actual target of this invocation at runtime.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
Function getResolvedCallee() { TypeResolution::callTarget(this, result) }
|
Function getResolvedCallee() { TypeResolution::callTarget(this, result) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1156,6 +1182,7 @@ class DotExpr extends @dot_expr, PropAccess {
|
|||||||
/** Gets the identifier specifying the name of the accessed property. */
|
/** Gets the identifier specifying the name of the accessed property. */
|
||||||
Identifier getProperty() { result = this.getChildExpr(1) }
|
Identifier getProperty() { result = this.getChildExpr(1) }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { this.getBase().isImpure() }
|
override predicate isImpure() { this.getBase().isImpure() }
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "DotExpr" }
|
override string getAPrimaryQlClass() { result = "DotExpr" }
|
||||||
@@ -1176,6 +1203,7 @@ class IndexExpr extends @index_expr, PropAccess {
|
|||||||
|
|
||||||
override string getPropertyName() { result = this.getIndex().(Literal).getValue() }
|
override string getPropertyName() { result = this.getIndex().(Literal).getValue() }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() {
|
override predicate isImpure() {
|
||||||
this.getBase().isImpure() or
|
this.getBase().isImpure() or
|
||||||
this.getIndex().isImpure()
|
this.getIndex().isImpure()
|
||||||
@@ -1201,6 +1229,7 @@ class UnaryExpr extends @unaryexpr, Expr {
|
|||||||
/** Gets the operator of this expression. */
|
/** Gets the operator of this expression. */
|
||||||
string getOperator() { none() }
|
string getOperator() { none() }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { this.getOperand().isImpure() }
|
override predicate isImpure() { this.getOperand().isImpure() }
|
||||||
|
|
||||||
override ControlFlowNode getFirstControlFlowNode() {
|
override ControlFlowNode getFirstControlFlowNode() {
|
||||||
@@ -1302,6 +1331,7 @@ class VoidExpr extends @void_expr, UnaryExpr {
|
|||||||
class DeleteExpr extends @delete_expr, UnaryExpr {
|
class DeleteExpr extends @delete_expr, UnaryExpr {
|
||||||
override string getOperator() { result = "delete" }
|
override string getOperator() { result = "delete" }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { any() }
|
override predicate isImpure() { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1352,6 +1382,7 @@ class BinaryExpr extends @binaryexpr, Expr {
|
|||||||
/** Gets the operator of this expression. */
|
/** Gets the operator of this expression. */
|
||||||
string getOperator() { none() }
|
string getOperator() { none() }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { this.getAnOperand().isImpure() }
|
override predicate isImpure() { this.getAnOperand().isImpure() }
|
||||||
|
|
||||||
override ControlFlowNode getFirstControlFlowNode() {
|
override ControlFlowNode getFirstControlFlowNode() {
|
||||||
@@ -1617,13 +1648,19 @@ private string getConstantString(Expr e) {
|
|||||||
result = e.(TemplateElement).getValue()
|
result = e.(TemplateElement).getValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate hasConstantStringValue(Expr e) {
|
||||||
|
exists(getConstantString(e))
|
||||||
|
or
|
||||||
|
hasAllConstantLeafs(e.getUnderlyingValue())
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `add` is a string-concatenation where all the transitive leafs have a constant string value.
|
* Holds if `add` is a string-concatenation where all the transitive leafs have a constant string value.
|
||||||
*/
|
*/
|
||||||
private predicate hasAllConstantLeafs(AddExpr add) {
|
private predicate hasAllConstantLeafs(AddExpr add) {
|
||||||
forex(Expr leaf | leaf = getAnAddOperand*(add) and not exists(getAnAddOperand(leaf)) |
|
hasConstantStringValue(add.getLeftOperand()) and
|
||||||
exists(getConstantString(leaf))
|
hasConstantStringValue(add.getRightOperand())
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2233,6 +2270,7 @@ class YieldExpr extends @yield_expr, Expr {
|
|||||||
/** Holds if this is a `yield*` expression. */
|
/** Holds if this is a `yield*` expression. */
|
||||||
predicate isDelegating() { is_delegating(this) }
|
predicate isDelegating() { is_delegating(this) }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { any() }
|
override predicate isImpure() { any() }
|
||||||
|
|
||||||
override ControlFlowNode getFirstControlFlowNode() {
|
override ControlFlowNode getFirstControlFlowNode() {
|
||||||
@@ -2289,6 +2327,7 @@ class ComprehensionExpr extends @comprehension_expr, Expr {
|
|||||||
/** Gets the body expression of this comprehension. */
|
/** Gets the body expression of this comprehension. */
|
||||||
Expr getBody() { result = this.getChildExpr(0) }
|
Expr getBody() { result = this.getChildExpr(0) }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() {
|
override predicate isImpure() {
|
||||||
this.getABlock().isImpure() or
|
this.getABlock().isImpure() or
|
||||||
this.getAFilter().isImpure() or
|
this.getAFilter().isImpure() or
|
||||||
@@ -2349,6 +2388,7 @@ class ComprehensionBlock extends @comprehension_block, Expr {
|
|||||||
/** Gets the domain over which this comprehension block iterates. */
|
/** Gets the domain over which this comprehension block iterates. */
|
||||||
Expr getDomain() { result = this.getChildExpr(1) }
|
Expr getDomain() { result = this.getChildExpr(1) }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() {
|
override predicate isImpure() {
|
||||||
this.getIterator().isImpure() or
|
this.getIterator().isImpure() or
|
||||||
this.getDomain().isImpure()
|
this.getDomain().isImpure()
|
||||||
@@ -2675,6 +2715,7 @@ class AwaitExpr extends @await_expr, Expr {
|
|||||||
/** Gets the operand of this `await` expression. */
|
/** Gets the operand of this `await` expression. */
|
||||||
Expr getOperand() { result = this.getChildExpr(0) }
|
Expr getOperand() { result = this.getChildExpr(0) }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { any() }
|
override predicate isImpure() { any() }
|
||||||
|
|
||||||
override ControlFlowNode getFirstControlFlowNode() {
|
override ControlFlowNode getFirstControlFlowNode() {
|
||||||
@@ -2698,6 +2739,7 @@ class AwaitExpr extends @await_expr, Expr {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class FunctionSentExpr extends @function_sent_expr, Expr {
|
class FunctionSentExpr extends @function_sent_expr, Expr {
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { none() }
|
override predicate isImpure() { none() }
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "FunctionSentExpr" }
|
override string getAPrimaryQlClass() { result = "FunctionSentExpr" }
|
||||||
@@ -2857,6 +2899,7 @@ class DynamicImportExpr extends @dynamic_import, Expr, Import {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A literal path expression appearing in a dynamic import. */
|
/** A literal path expression appearing in a dynamic import. */
|
||||||
|
overlay[global]
|
||||||
deprecated private class LiteralDynamicImportPath extends PathExpr, ConstantString {
|
deprecated private class LiteralDynamicImportPath extends PathExpr, ConstantString {
|
||||||
LiteralDynamicImportPath() {
|
LiteralDynamicImportPath() {
|
||||||
exists(DynamicImportExpr di | this.getParentExpr*() = di.getSource())
|
exists(DynamicImportExpr di | this.getParentExpr*() = di.getSource())
|
||||||
@@ -2919,6 +2962,7 @@ class OptionalChainRoot extends ChainElem {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class ImportMetaExpr extends @import_meta_expr, Expr {
|
class ImportMetaExpr extends @import_meta_expr, Expr {
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { none() }
|
override predicate isImpure() { none() }
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "ImportMetaExpr" }
|
override string getAPrimaryQlClass() { result = "ImportMetaExpr" }
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Provides classes for reasoning about `extend`-like functions.
|
* Provides classes for reasoning about `extend`-like functions.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
@@ -169,6 +171,7 @@ private class FunctionalExtendCallShallow extends ExtendCall {
|
|||||||
*
|
*
|
||||||
* Since all object properties are preserved, we model this as a value-preserving step.
|
* Since all object properties are preserved, we model this as a value-preserving step.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private class ExtendCallStep extends PreCallGraphStep {
|
private class ExtendCallStep extends PreCallGraphStep {
|
||||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
exists(ExtendCall extend |
|
exists(ExtendCall extend |
|
||||||
@@ -184,6 +187,7 @@ private import semmle.javascript.dataflow.internal.PreCallGraphStep
|
|||||||
/**
|
/**
|
||||||
* A step through a cloning library, such as `clone` or `fclone`.
|
* A step through a cloning library, such as `clone` or `fclone`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private class CloneStep extends PreCallGraphStep {
|
private class CloneStep extends PreCallGraphStep {
|
||||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
exists(DataFlow::CallNode call |
|
exists(DataFlow::CallNode call |
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
* Array.prototype.length;
|
* Array.prototype.length;
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/** Provides classes for working with files and folders. */
|
/** Provides classes for working with files and folders. */
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import NodeModuleResolutionImpl
|
private import NodeModuleResolutionImpl
|
||||||
@@ -33,12 +35,14 @@ module Folder = Impl::Folder;
|
|||||||
/** A folder. */
|
/** A folder. */
|
||||||
class Folder extends Container, Impl::Folder {
|
class Folder extends Container, Impl::Folder {
|
||||||
/** Gets the file or subfolder in this folder that has the given `name`, if any. */
|
/** Gets the file or subfolder in this folder that has the given `name`, if any. */
|
||||||
|
overlay[global]
|
||||||
Container getChildContainer(string name) {
|
Container getChildContainer(string name) {
|
||||||
result = this.getAChildContainer() and
|
result = this.getAChildContainer() and
|
||||||
result.getBaseName() = name
|
result.getBaseName() = name
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the file in this folder that has the given `stem` and `extension`, if any. */
|
/** Gets the file in this folder that has the given `stem` and `extension`, if any. */
|
||||||
|
overlay[global]
|
||||||
File getFile(string stem, string extension) {
|
File getFile(string stem, string extension) {
|
||||||
result = this.getAChildContainer() and
|
result = this.getAChildContainer() and
|
||||||
result.getStem() = stem 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. */
|
/** Like `getFile` except `d.ts` is treated as a single extension. */
|
||||||
|
overlay[global]
|
||||||
private File getFileLongExtension(string stem, string extension) {
|
private File getFileLongExtension(string stem, string extension) {
|
||||||
not (stem.matches("%.d") and extension = "ts") and
|
not (stem.matches("%.d") and extension = "ts") and
|
||||||
result = this.getFile(stem, extension)
|
result = this.getFile(stem, extension)
|
||||||
@@ -65,6 +70,7 @@ class Folder extends Container, Impl::Folder {
|
|||||||
*
|
*
|
||||||
* HTML files will not be found by this method.
|
* HTML files will not be found by this method.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
File getJavaScriptFile(string stem) {
|
File getJavaScriptFile(string stem) {
|
||||||
result =
|
result =
|
||||||
min(int p, string ext |
|
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`.
|
* 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.
|
* This could be a single `.ts` file or a pair of `.js` and `.d.ts` files.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
File getJavaScriptFileOrTypings(string stem) {
|
File getJavaScriptFileOrTypings(string stem) {
|
||||||
exists(File jsFile | jsFile = this.getJavaScriptFile(stem) |
|
exists(File jsFile | jsFile = this.getJavaScriptFile(stem) |
|
||||||
result = jsFile
|
result = jsFile
|
||||||
@@ -88,6 +95,7 @@ class Folder extends Container, Impl::Folder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a subfolder contained in this folder. */
|
/** Gets a subfolder contained in this folder. */
|
||||||
|
overlay[global]
|
||||||
Folder getASubFolder() { result = this.getAChildContainer() }
|
Folder getASubFolder() { result = this.getAChildContainer() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/** Provides classes for working with functions. */
|
/** Provides classes for working with functions. */
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
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.
|
* This predicate is only populated for files extracted with full TypeScript extraction.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated CanonicalFunctionName getCanonicalName() { ast_node_symbol(this, result) }
|
deprecated CanonicalFunctionName getCanonicalName() { ast_node_symbol(this, result) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the call signature of this function, as determined by the TypeScript compiler, if any.
|
* 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) }
|
deprecated CallSignatureType getCallSignature() { declared_function_signature(this, result) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Provides predicates for associating qualified names with data flow nodes.
|
* Provides predicates for associating qualified names with data flow nodes.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import semmle.javascript.dataflow.InferredTypes
|
private import semmle.javascript.dataflow.InferredTypes
|
||||||
@@ -204,6 +206,7 @@ module AccessPath {
|
|||||||
* Holds if the global `accessPath` is only assigned to from one file, not counting
|
* Holds if the global `accessPath` is only assigned to from one file, not counting
|
||||||
* self-assignments.
|
* self-assignments.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate isAssignedInUniqueFile(string accessPath) {
|
predicate isAssignedInUniqueFile(string accessPath) {
|
||||||
strictcount(File f | isAssignedInFile(accessPath, f)) = 1
|
strictcount(File f | isAssignedInFile(accessPath, f)) = 1
|
||||||
}
|
}
|
||||||
@@ -354,6 +357,7 @@ module AccessPath {
|
|||||||
* Gets a variable that is relevant for the computations in the `GetLaterAccess` module.
|
* Gets a variable that is relevant for the computations in the `GetLaterAccess` module.
|
||||||
* This predicate restricts as much as it can, but without depending on `getAVariableRef`.
|
* This predicate restricts as much as it can, but without depending on `getAVariableRef`.
|
||||||
*/
|
*/
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private SsaVariable getARelevantVariableSimple() {
|
private SsaVariable getARelevantVariableSimple() {
|
||||||
// The variable might be used where `getLaterBaseAccess()` is called.
|
// The variable might be used where `getLaterBaseAccess()` is called.
|
||||||
@@ -405,6 +409,7 @@ module AccessPath {
|
|||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
DataFlow::Node getAReferenceTo(Root root, string path) {
|
DataFlow::Node getAReferenceTo(Root root, string path) {
|
||||||
path = fromReference(result, root) and
|
path = fromReference(result, root) and
|
||||||
@@ -428,6 +433,7 @@ module AccessPath {
|
|||||||
* })(NS = NS || {});
|
* })(NS = NS || {});
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
DataFlow::Node getAReferenceTo(string path) {
|
DataFlow::Node getAReferenceTo(string path) {
|
||||||
path = fromReference(result, DataFlow::globalAccessPathRootPseudoNode())
|
path = fromReference(result, DataFlow::globalAccessPathRootPseudoNode())
|
||||||
@@ -449,6 +455,7 @@ module AccessPath {
|
|||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
DataFlow::Node getAnAssignmentTo(Root root, string path) {
|
DataFlow::Node getAnAssignmentTo(Root root, string path) {
|
||||||
path = fromRhs(result, root) and
|
path = fromRhs(result, root) and
|
||||||
@@ -470,6 +477,7 @@ module AccessPath {
|
|||||||
* })(foo = foo || {});
|
* })(foo = foo || {});
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
DataFlow::Node getAnAssignmentTo(string path) {
|
DataFlow::Node getAnAssignmentTo(string path) {
|
||||||
path = fromRhs(result, DataFlow::globalAccessPathRootPseudoNode())
|
path = fromRhs(result, DataFlow::globalAccessPathRootPseudoNode())
|
||||||
@@ -480,6 +488,7 @@ module AccessPath {
|
|||||||
*
|
*
|
||||||
* See `getAReferenceTo` and `getAnAssignmentTo` for more details.
|
* See `getAReferenceTo` and `getAnAssignmentTo` for more details.
|
||||||
*/
|
*/
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
DataFlow::Node getAReferenceOrAssignmentTo(string path) {
|
DataFlow::Node getAReferenceOrAssignmentTo(string path) {
|
||||||
result = getAReferenceTo(path)
|
result = getAReferenceTo(path)
|
||||||
@@ -492,6 +501,7 @@ module AccessPath {
|
|||||||
*
|
*
|
||||||
* See `getAReferenceTo` and `getAnAssignmentTo` for more details.
|
* See `getAReferenceTo` and `getAnAssignmentTo` for more details.
|
||||||
*/
|
*/
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
DataFlow::Node getAReferenceOrAssignmentTo(Root root, string path) {
|
DataFlow::Node getAReferenceOrAssignmentTo(Root root, string path) {
|
||||||
result = getAReferenceTo(root, path)
|
result = getAReferenceTo(root, path)
|
||||||
@@ -502,6 +512,7 @@ module AccessPath {
|
|||||||
/**
|
/**
|
||||||
* Holds if there is a step from `pred` to `succ` through an assignment to an access path.
|
* Holds if there is a step from `pred` to `succ` through an assignment to an access path.
|
||||||
*/
|
*/
|
||||||
|
overlay[caller?]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
exists(string name, Root root |
|
exists(string name, Root root |
|
||||||
@@ -519,6 +530,7 @@ module AccessPath {
|
|||||||
/**
|
/**
|
||||||
* Gets a `SourceNode` that refers to the same value or access path as the given node.
|
* Gets a `SourceNode` that refers to the same value or access path as the given node.
|
||||||
*/
|
*/
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
DataFlow::SourceNode getAnAliasedSourceNode(DataFlow::Node node) {
|
DataFlow::SourceNode getAnAliasedSourceNode(DataFlow::Node node) {
|
||||||
exists(DataFlow::SourceNode root, string accessPath |
|
exists(DataFlow::SourceNode root, string accessPath |
|
||||||
@@ -657,7 +669,7 @@ module AccessPath {
|
|||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
predicate hasDominatingWrite(DataFlow::PropRead read) {
|
predicate hasDominatingWrite(DataFlow::PropRead read) {
|
||||||
Stages::TypeTracking::ref() and
|
Stages::DataFlowStage::ref() and
|
||||||
// within the same basic block.
|
// within the same basic block.
|
||||||
exists(ReachableBasicBlock bb, Root root, string path, int ranking |
|
exists(ReachableBasicBlock bb, Root root, string path, int ranking |
|
||||||
read.asExpr() = rankedAccessPath(bb, root, path, ranking, AccessPathRead()) and
|
read.asExpr() = rankedAccessPath(bb, root, path, ranking, AccessPathRead()) and
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/** Provides classes for working with HTML documents. */
|
/** Provides classes for working with HTML documents. */
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
@@ -283,6 +285,7 @@ module HTML {
|
|||||||
/**
|
/**
|
||||||
* A path string arising from the `src` attribute of a `script` tag.
|
* A path string arising from the `src` attribute of a `script` tag.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated private class ScriptSrcPath extends PathString {
|
deprecated private class ScriptSrcPath extends PathString {
|
||||||
ScriptSrcPath() { scriptSrc(this, _) }
|
ScriptSrcPath() { scriptSrc(this, _) }
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/** Provides classes for working with JSDoc comments. */
|
/** Provides classes for working with JSDoc comments. */
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import semmle.javascript.internal.CachedStages
|
private import semmle.javascript.internal.CachedStages
|
||||||
@@ -627,6 +629,7 @@ module JSDoc {
|
|||||||
/**
|
/**
|
||||||
* A statement container which may declare JSDoc name aliases.
|
* A statement container which may declare JSDoc name aliases.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class Environment extends StmtContainer {
|
deprecated class Environment extends StmtContainer {
|
||||||
/**
|
/**
|
||||||
* Gets the fully qualified name aliased by the given unqualified name
|
* Gets the fully qualified name aliased by the given unqualified name
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Provides classes for working with JSON data.
|
* Provides classes for working with JSON data.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Provides classes for working with JSX code.
|
* Provides classes for working with JSX code.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
* This information is only available for snapshots that have been extracted with
|
* This information is only available for snapshots that have been extracted with
|
||||||
* the `--extract-program-text` flag.
|
* the `--extract-program-text` flag.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/** Provides classes for working with locations and program elements that have locations. */
|
/** Provides classes for working with locations and program elements that have locations. */
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
@@ -30,6 +32,7 @@ final class Location extends @location_default {
|
|||||||
int getNumLines() { result = this.getEndLine() - this.getStartLine() + 1 }
|
int getNumLines() { result = this.getEndLine() - this.getStartLine() + 1 }
|
||||||
|
|
||||||
/** Holds if this location starts before location `that`. */
|
/** Holds if this location starts before location `that`. */
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate startsBefore(Location that) {
|
predicate startsBefore(Location that) {
|
||||||
exists(string f, int sl1, int sc1, int sl2, int sc2 |
|
exists(string f, int sl1, int sc1, int sl2, int sc2 |
|
||||||
@@ -43,6 +46,7 @@ final class Location extends @location_default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if this location ends after location `that`. */
|
/** Holds if this location ends after location `that`. */
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate endsAfter(Location that) {
|
predicate endsAfter(Location that) {
|
||||||
exists(string f, int el1, int ec1, int el2, int ec2 |
|
exists(string f, int el1, int ec1, int el2, int ec2 |
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
* ECMAScript 2015-style modules, and the older CommonJS and AMD-style
|
* ECMAScript 2015-style modules, and the older CommonJS and AMD-style
|
||||||
* modules.
|
* modules.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import semmle.javascript.internal.CachedStages
|
private import semmle.javascript.internal.CachedStages
|
||||||
@@ -23,9 +25,11 @@ abstract class Module extends TopLevel {
|
|||||||
Import getAnImport() { result.getTopLevel() = this }
|
Import getAnImport() { result.getTopLevel() = this }
|
||||||
|
|
||||||
/** Gets a module from which this module imports. */
|
/** Gets a module from which this module imports. */
|
||||||
|
overlay[global]
|
||||||
Module getAnImportedModule() { result = this.getAnImport().getImportedModule() }
|
Module getAnImportedModule() { result = this.getAnImport().getImportedModule() }
|
||||||
|
|
||||||
/** Gets a symbol exported by this module. */
|
/** Gets a symbol exported by this module. */
|
||||||
|
overlay[global]
|
||||||
string getAnExportedSymbol() { exists(this.getAnExportedValue(result)) }
|
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
|
* Symbols defined in another module that are re-exported by
|
||||||
* this module are only sometimes considered.
|
* this module are only sometimes considered.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
cached
|
cached
|
||||||
abstract DataFlow::Node getAnExportedValue(string name);
|
abstract DataFlow::Node getAnExportedValue(string name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a value that is exported as the whole exports object of this module.
|
* Gets a value that is exported as the whole exports object of this module.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
cached
|
cached
|
||||||
DataFlow::Node getABulkExportedNode() { none() } // overridden in subclasses
|
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,
|
* 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.
|
* as the interaction between different module types is not standardized.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
DataFlow::Node getDefaultOrBulkExport() {
|
DataFlow::Node getDefaultOrBulkExport() {
|
||||||
result = [this.getAnExportedValue("default"), this.getABulkExportedNode()]
|
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
|
* This predicate is not part of the public API, it is only exposed to allow
|
||||||
* overriding by subclasses.
|
* overriding by subclasses.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated predicate searchRoot(PathExpr path, Folder searchRoot, int priority) {
|
deprecated predicate searchRoot(PathExpr path, Folder searchRoot, int priority) {
|
||||||
path.getEnclosingModule() = this and
|
path.getEnclosingModule() = this and
|
||||||
priority = 0 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
|
* resolves to a folder containing a main module (such as `index.js`), then
|
||||||
* that file is the result.
|
* that file is the result.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated File resolve(PathExpr path) {
|
deprecated File resolve(PathExpr path) {
|
||||||
path.getEnclosingModule() = this and
|
path.getEnclosingModule() = this and
|
||||||
(
|
(
|
||||||
@@ -124,6 +133,7 @@ abstract class Import extends AstNode {
|
|||||||
abstract Module getEnclosingModule();
|
abstract Module getEnclosingModule();
|
||||||
|
|
||||||
/** DEPRECATED. Use `getImportedPathExpr` instead. */
|
/** DEPRECATED. Use `getImportedPathExpr` instead. */
|
||||||
|
overlay[global]
|
||||||
deprecated PathExpr getImportedPath() { result = this.getImportedPathExpr() }
|
deprecated PathExpr getImportedPath() { result = this.getImportedPathExpr() }
|
||||||
|
|
||||||
/** Gets the (unresolved) path that this import refers to. */
|
/** 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
|
* Any externs module whose name exactly matches the imported
|
||||||
* path is assumed to be a possible target of the import.
|
* path is assumed to be a possible target of the import.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
Module resolveExternsImport() {
|
Module resolveExternsImport() {
|
||||||
result.isExterns() and result.getName() = this.getImportedPathString()
|
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.
|
* Gets the module the path of this import resolves to.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
Module resolveImportedPath() { result.getFile() = this.getImportedFile() }
|
Module resolveImportedPath() { result.getFile() = this.getImportedFile() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the module the path of this import resolves to.
|
* Gets the module the path of this import resolves to.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
File getImportedFile() { result = ImportPathResolver::resolveExpr(this.getImportedPathExpr()) }
|
File getImportedFile() { result = ImportPathResolver::resolveExpr(this.getImportedPathExpr()) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DEPRECATED. Use `getImportedModule()` instead.
|
* DEPRECATED. Use `getImportedModule()` instead.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated Module resolveFromTypeScriptSymbol() {
|
deprecated Module resolveFromTypeScriptSymbol() {
|
||||||
exists(CanonicalName symbol |
|
exists(CanonicalName symbol |
|
||||||
ast_node_symbol(this, symbol) and
|
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
|
* behavior of Node.js imports, which prefer core modules such as `fs` over any
|
||||||
* source module of the same name.
|
* source module of the same name.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
cached
|
cached
|
||||||
Module getImportedModule() {
|
Module getImportedModule() {
|
||||||
Stages::Imports::ref() and
|
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
|
* in cases where it would cause ambiguity between named exports and properties
|
||||||
* of a default export.
|
* of a default export.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
final DataFlow::Node getImportedModuleNodeStrict() {
|
final DataFlow::Node getImportedModuleNodeStrict() {
|
||||||
result = this.getImportedModuleNode() and
|
result = this.getImportedModuleNode() and
|
||||||
not (
|
not (
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Provides classes for working with NPM module definitions and dependencies.
|
* Provides classes for working with NPM module definitions and dependencies.
|
||||||
*/
|
*/
|
||||||
|
overlay[local?]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import NodeModuleResolutionImpl
|
private import NodeModuleResolutionImpl
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ private import semmle.javascript.dataflow.internal.DataFlowNode
|
|||||||
* process.stdout.write(fs.readFileSync(process.argv[i], 'utf8'));
|
* process.stdout.write(fs.readFileSync(process.argv[i], 'utf8'));
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
class NodeModule extends Module {
|
class NodeModule extends Module {
|
||||||
NodeModule() {
|
NodeModule() {
|
||||||
is_module(this) and
|
is_module(this) and
|
||||||
@@ -36,11 +37,13 @@ class NodeModule extends Module {
|
|||||||
* Gets an abstract value representing one or more values that may flow
|
* Gets an abstract value representing one or more values that may flow
|
||||||
* into this module's `module.exports` property.
|
* into this module's `module.exports` property.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
DefiniteAbstractValue getAModuleExportsValue() {
|
DefiniteAbstractValue getAModuleExportsValue() {
|
||||||
result = this.getAModuleExportsProperty().getAValue()
|
result = this.getAModuleExportsProperty().getAValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private AbstractProperty getAModuleExportsProperty() {
|
private AbstractProperty getAModuleExportsProperty() {
|
||||||
result.getBase().(AbstractModuleObject).getModule() = this and
|
result.getBase().(AbstractModuleObject).getModule() = this and
|
||||||
@@ -52,12 +55,14 @@ class NodeModule extends Module {
|
|||||||
* For performance this predicate only computes relevant expressions (in `getAModuleExportsCandidate`).
|
* For performance this predicate only computes relevant expressions (in `getAModuleExportsCandidate`).
|
||||||
* So if using this predicate - consider expanding the list of relevant expressions.
|
* So if using this predicate - consider expanding the list of relevant expressions.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
DataFlow::AnalyzedNode getAModuleExportsNode() {
|
DataFlow::AnalyzedNode getAModuleExportsNode() {
|
||||||
result = getAModuleExportsCandidate() and
|
result = getAModuleExportsCandidate() and
|
||||||
result.getAValue() = this.getAModuleExportsValue()
|
result.getAValue() = this.getAModuleExportsValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a symbol exported by this module. */
|
/** Gets a symbol exported by this module. */
|
||||||
|
overlay[global]
|
||||||
override string getAnExportedSymbol() {
|
override string getAnExportedSymbol() {
|
||||||
result = super.getAnExportedSymbol()
|
result = super.getAnExportedSymbol()
|
||||||
or
|
or
|
||||||
@@ -70,6 +75,7 @@ class NodeModule extends Module {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::Node getAnExportedValue(string name) {
|
override DataFlow::Node getAnExportedValue(string name) {
|
||||||
// a property write whose base is `exports` or `module.exports`
|
// a property write whose base is `exports` or `module.exports`
|
||||||
exists(DataFlow::PropWrite pwn | result = pwn.getRhs() |
|
exists(DataFlow::PropWrite pwn | result = pwn.getRhs() |
|
||||||
@@ -114,6 +120,7 @@ class NodeModule extends Module {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::Node getABulkExportedNode() {
|
override DataFlow::Node getABulkExportedNode() {
|
||||||
Stages::Imports::ref() and
|
Stages::Imports::ref() and
|
||||||
exists(DataFlow::PropWrite write |
|
exists(DataFlow::PropWrite write |
|
||||||
@@ -124,6 +131,7 @@ class NodeModule extends Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a symbol that the module object inherits from its prototypes. */
|
/** Gets a symbol that the module object inherits from its prototypes. */
|
||||||
|
overlay[global]
|
||||||
private string getAnImplicitlyExportedSymbol() {
|
private string getAnImplicitlyExportedSymbol() {
|
||||||
exists(ExternalConstructor ec | ec = this.getPrototypeOfExportedExpr() |
|
exists(ExternalConstructor ec | ec = this.getPrototypeOfExportedExpr() |
|
||||||
result = ec.getAMember().getName()
|
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. */
|
/** Gets an externs declaration of the prototype object of a value exported by this module. */
|
||||||
|
overlay[global]
|
||||||
private ExternalConstructor getPrototypeOfExportedExpr() {
|
private ExternalConstructor getPrototypeOfExportedExpr() {
|
||||||
exists(AbstractValue exported | exported = this.getAModuleExportsValue() |
|
exists(AbstractValue exported | exported = this.getAModuleExportsValue() |
|
||||||
result instanceof ObjectExternal
|
result instanceof ObjectExternal
|
||||||
@@ -146,6 +155,7 @@ class NodeModule extends Module {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
deprecated override predicate searchRoot(PathExpr path, Folder searchRoot, int priority) {
|
deprecated override predicate searchRoot(PathExpr path, Folder searchRoot, int priority) {
|
||||||
path.getEnclosingModule() = this and
|
path.getEnclosingModule() = this and
|
||||||
exists(string pathval | pathval = path.getValue() |
|
exists(string pathval | pathval = path.getValue() |
|
||||||
@@ -224,6 +234,7 @@ predicate findNodeModulesFolder(Folder f, Folder nodeModules, int distance) {
|
|||||||
/**
|
/**
|
||||||
* A Node.js `require` variable.
|
* A Node.js `require` variable.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
private class RequireVariable extends Variable {
|
private class RequireVariable extends Variable {
|
||||||
RequireVariable() {
|
RequireVariable() {
|
||||||
this = any(ModuleScope m).getVariable("require")
|
this = any(ModuleScope m).getVariable("require")
|
||||||
@@ -236,6 +247,7 @@ private class RequireVariable extends Variable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
private predicate isModuleModule(EarlyStageNode nd) {
|
private predicate isModuleModule(EarlyStageNode nd) {
|
||||||
exists(ImportDeclaration imp | imp.getRawImportPath() = "module" |
|
exists(ImportDeclaration imp | imp.getRawImportPath() = "module" |
|
||||||
nd = TDestructuredModuleImportNode(imp)
|
nd = TDestructuredModuleImportNode(imp)
|
||||||
@@ -249,6 +261,7 @@ private predicate isModuleModule(EarlyStageNode nd) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
private predicate isCreateRequire(EarlyStageNode nd) {
|
private predicate isCreateRequire(EarlyStageNode nd) {
|
||||||
exists(PropAccess prop |
|
exists(PropAccess prop |
|
||||||
isModuleModule(TValueNode(prop.getBase())) and
|
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.
|
* Holds if `nd` may refer to `require`, either directly or modulo local data flow.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
cached
|
cached
|
||||||
private predicate isRequire(EarlyStageNode nd) {
|
private predicate isRequire(EarlyStageNode nd) {
|
||||||
exists(VarAccess access |
|
exists(VarAccess access |
|
||||||
@@ -320,6 +334,7 @@ private predicate isRequire(EarlyStageNode nd) {
|
|||||||
* require('fs')
|
* require('fs')
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
class Require extends CallExpr, Import {
|
class Require extends CallExpr, Import {
|
||||||
Require() { isRequire(TValueNode(this.getCallee())) }
|
Require() { isRequire(TValueNode(this.getCallee())) }
|
||||||
|
|
||||||
|
|||||||
@@ -186,11 +186,13 @@ module Promises {
|
|||||||
/**
|
/**
|
||||||
* Gets the pseudo-field used to describe resolved values in a promise.
|
* Gets the pseudo-field used to describe resolved values in a promise.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
string valueProp() { result = "$PromiseResolveField$" }
|
string valueProp() { result = "$PromiseResolveField$" }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the pseudo-field used to describe rejected values in a promise.
|
* Gets the pseudo-field used to describe rejected values in a promise.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
string errorProp() { result = "$PromiseRejectField$" }
|
string errorProp() { result = "$PromiseRejectField$" }
|
||||||
|
|
||||||
/** A property set containing the pseudo-properites of a promise object. */
|
/** A property set containing the pseudo-properites of a promise object. */
|
||||||
@@ -236,6 +238,7 @@ module PromiseTypeTracking {
|
|||||||
*
|
*
|
||||||
* These type-tracking steps are already included in the default type-tracking steps (through `PreCallGraphStep`).
|
* These type-tracking steps are already included in the default type-tracking steps (through `PreCallGraphStep`).
|
||||||
*/
|
*/
|
||||||
|
overlay[caller?]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
DataFlow::Node promiseStep(DataFlow::Node pred, StepSummary summary) {
|
DataFlow::Node promiseStep(DataFlow::Node pred, StepSummary summary) {
|
||||||
exists(string field | field = Promises::valueProp() |
|
exists(string field | field = Promises::valueProp() |
|
||||||
@@ -254,6 +257,7 @@ module PromiseTypeTracking {
|
|||||||
* Gets the result from a single step through a promise, from `pred` with tracker `t2` to `result` with tracker `t`.
|
* Gets the result from a single step through a promise, from `pred` with tracker `t2` to `result` with tracker `t`.
|
||||||
* This can be loading a resolved value from a promise, storing a value in a promise, or copying a resolved value from one promise to another.
|
* This can be loading a resolved value from a promise, storing a value in a promise, or copying a resolved value from one promise to another.
|
||||||
*/
|
*/
|
||||||
|
overlay[caller?]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
DataFlow::SourceNode promiseStep(
|
DataFlow::SourceNode promiseStep(
|
||||||
DataFlow::SourceNode pred, DataFlow::TypeTracker t, DataFlow::TypeTracker t2
|
DataFlow::SourceNode pred, DataFlow::TypeTracker t, DataFlow::TypeTracker t2
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
* Regular expression literals are represented as an abstract syntax tree of regular expression
|
* Regular expression literals are represented as an abstract syntax tree of regular expression
|
||||||
* terms.
|
* terms.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import semmle.javascript.dataflow.InferredTypes
|
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
|
* /[a-z]+/g; // YES - Regexp literals are always used as regexp
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate isUsedAsRegExp() {
|
predicate isUsedAsRegExp() {
|
||||||
exists(RegExpParent parent | parent = this.getRootTerm().getParent() |
|
exists(RegExpParent parent | parent = this.getRootTerm().getParent() |
|
||||||
parent instanceof RegExpLiteral
|
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`.
|
* Holds if `func` is a method defined on `String.prototype` with name `name`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private predicate isNativeStringMethod(Function func, string name) {
|
private predicate isNativeStringMethod(Function func, string name) {
|
||||||
exists(ExternalInstanceMemberDecl decl |
|
exists(ExternalInstanceMemberDecl decl |
|
||||||
decl.hasQualifiedName("String", name) and
|
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`,
|
* Holds if `name` is the name of a property on a Match object returned by `String.prototype.match`,
|
||||||
* not including array indices.
|
* not including array indices.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private predicate isMatchObjectProperty(string name) {
|
private predicate isMatchObjectProperty(string name) {
|
||||||
any(ExternalInstanceMemberDecl decl).hasQualifiedName("Array", name)
|
any(ExternalInstanceMemberDecl decl).hasQualifiedName("Array", name)
|
||||||
or
|
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. */
|
/** 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) {
|
private predicate isUsedAsNonMatchObject(DataFlow::MethodCallNode call) {
|
||||||
call.getMethodName() = ["match", "matchAll"] and
|
call.getMethodName() = ["match", "matchAll"] and
|
||||||
call.getNumArgument() = 1 and
|
call.getNumArgument() = 1 and
|
||||||
@@ -1006,10 +1012,11 @@ private predicate isUsedAsNonMatchObject(DataFlow::MethodCallNode call) {
|
|||||||
/**
|
/**
|
||||||
* Holds if `value` is used in a way that suggests it returns a number.
|
* Holds if `value` is used in a way that suggests it returns a number.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate isUsedAsNumber(DataFlow::LocalSourceNode value) {
|
private predicate isUsedAsNumber(DataFlow::LocalSourceNode value) {
|
||||||
any(Comparison compare)
|
any(Comparison compare)
|
||||||
.hasOperands(value.getALocalUse().asExpr(), any(Expr e | e.analyze().getAType() = TTNumber()))
|
.hasOperands(value.getALocalUse().asExpr(), any(Expr e | canBeNumber(e.analyze())))
|
||||||
or
|
or
|
||||||
value.flowsToExpr(any(ArithmeticExpr e).getAnOperand())
|
value.flowsToExpr(any(ArithmeticExpr e).getAnOperand())
|
||||||
or
|
or
|
||||||
@@ -1024,20 +1031,31 @@ private predicate isUsedAsNumber(DataFlow::LocalSourceNode value) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindingset[node]
|
||||||
|
overlay[global]
|
||||||
|
pragma[inline_late]
|
||||||
|
private predicate canBeString(DataFlow::AnalyzedNode node) { node.getAType() = TTString() }
|
||||||
|
|
||||||
|
bindingset[node]
|
||||||
|
overlay[global]
|
||||||
|
pragma[inline_late]
|
||||||
|
private predicate canBeNumber(DataFlow::AnalyzedNode node) { node.getAType() = TTNumber() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `source` may be interpreted as a regular expression.
|
* Holds if `source` may be interpreted as a regular expression.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
cached
|
cached
|
||||||
predicate isInterpretedAsRegExp(DataFlow::Node source) {
|
predicate isInterpretedAsRegExp(DataFlow::Node source) {
|
||||||
Stages::Taint::ref() and
|
Stages::Taint::ref() and
|
||||||
source.analyze().getAType() = TTString() and
|
canBeString(source) and
|
||||||
(
|
(
|
||||||
// The first argument to an invocation of `RegExp` (with or without `new`).
|
// The first argument to an invocation of `RegExp` (with or without `new`).
|
||||||
source = DataFlow::globalVarRef("RegExp").getAnInvocation().getArgument(0)
|
source = DataFlow::globalVarRef("RegExp").getAnInvocation().getArgument(0)
|
||||||
or
|
or
|
||||||
// The argument of a call that coerces the argument to a regular expression.
|
// The argument of a call that coerces the argument to a regular expression.
|
||||||
exists(DataFlow::MethodCallNode mce, string methodName |
|
exists(DataFlow::MethodCallNode mce, string methodName |
|
||||||
mce.getReceiver().analyze().getAType() = TTString() and
|
canBeString(mce.getReceiver()) and
|
||||||
mce.getMethodName() = methodName and
|
mce.getMethodName() = methodName and
|
||||||
not exists(Function func | func = mce.getACallee() |
|
not exists(Function func | func = mce.getACallee() |
|
||||||
not isNativeStringMethod(func, methodName)
|
not isNativeStringMethod(func, methodName)
|
||||||
@@ -1073,6 +1091,7 @@ predicate isInterpretedAsRegExp(DataFlow::Node source) {
|
|||||||
* Gets a node whose value may flow (inter-procedurally) to `re`, where it is interpreted
|
* Gets a node whose value may flow (inter-procedurally) to `re`, where it is interpreted
|
||||||
* as a part of a regular expression.
|
* as a part of a regular expression.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private DataFlow::Node regExpSource(DataFlow::Node re, DataFlow::TypeBackTracker t) {
|
private DataFlow::Node regExpSource(DataFlow::Node re, DataFlow::TypeBackTracker t) {
|
||||||
t.start() and
|
t.start() and
|
||||||
re = result and
|
re = result and
|
||||||
@@ -1090,6 +1109,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
|
* Gets a node whose value may flow (inter-procedurally) to `re`, where it is interpreted
|
||||||
* as a part of a regular expression.
|
* as a part of a regular expression.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private DataFlow::Node regExpSource(DataFlow::Node re) {
|
private DataFlow::Node regExpSource(DataFlow::Node re) {
|
||||||
result = regExpSource(re, DataFlow::TypeBackTracker::end())
|
result = regExpSource(re, DataFlow::TypeBackTracker::end())
|
||||||
}
|
}
|
||||||
@@ -1098,6 +1118,7 @@ private DataFlow::Node regExpSource(DataFlow::Node re) {
|
|||||||
* A node whose value may flow to a position where it is interpreted
|
* A node whose value may flow to a position where it is interpreted
|
||||||
* as a part of a regular expression.
|
* as a part of a regular expression.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
abstract class RegExpPatternSource extends DataFlow::Node {
|
abstract class RegExpPatternSource extends DataFlow::Node {
|
||||||
/**
|
/**
|
||||||
* Gets a node where the pattern of this node is parsed as a part of
|
* Gets a node where the pattern of this node is parsed as a part of
|
||||||
@@ -1126,6 +1147,7 @@ abstract class RegExpPatternSource extends DataFlow::Node {
|
|||||||
/**
|
/**
|
||||||
* A regular expression literal, viewed as the pattern source for itself.
|
* A regular expression literal, viewed as the pattern source for itself.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private class RegExpLiteralPatternSource extends RegExpPatternSource, DataFlow::ValueNode {
|
private class RegExpLiteralPatternSource extends RegExpPatternSource, DataFlow::ValueNode {
|
||||||
override RegExpLiteral astNode;
|
override RegExpLiteral astNode;
|
||||||
|
|
||||||
@@ -1145,6 +1167,7 @@ private class RegExpLiteralPatternSource extends RegExpPatternSource, DataFlow::
|
|||||||
* A node whose string value may flow to a position where it is interpreted
|
* A node whose string value may flow to a position where it is interpreted
|
||||||
* as a part of a regular expression.
|
* as a part of a regular expression.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private class StringRegExpPatternSource extends RegExpPatternSource {
|
private class StringRegExpPatternSource extends RegExpPatternSource {
|
||||||
DataFlow::Node parse;
|
DataFlow::Node parse;
|
||||||
|
|
||||||
@@ -1169,6 +1192,7 @@ private class StringRegExpPatternSource extends RegExpPatternSource {
|
|||||||
* A node whose string value may flow to a position where it is interpreted
|
* A node whose string value may flow to a position where it is interpreted
|
||||||
* as a part of a regular expression.
|
* as a part of a regular expression.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private class StringConcatRegExpPatternSource extends RegExpPatternSource {
|
private class StringConcatRegExpPatternSource extends RegExpPatternSource {
|
||||||
DataFlow::Node parse;
|
DataFlow::Node parse;
|
||||||
|
|
||||||
@@ -1331,6 +1355,7 @@ module RegExp {
|
|||||||
/**
|
/**
|
||||||
* Gets the AST of a regular expression object that can flow to `node`.
|
* Gets the AST of a regular expression object that can flow to `node`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
RegExpTerm getRegExpObjectFromNode(DataFlow::Node node) {
|
RegExpTerm getRegExpObjectFromNode(DataFlow::Node node) {
|
||||||
exists(DataFlow::RegExpCreationNode regexp |
|
exists(DataFlow::RegExpCreationNode regexp |
|
||||||
regexp.getAReference().flowsTo(node) and
|
regexp.getAReference().flowsTo(node) and
|
||||||
@@ -1342,6 +1367,7 @@ module RegExp {
|
|||||||
* Gets the AST of a regular expression that can flow to `node`,
|
* Gets the AST of a regular expression that can flow to `node`,
|
||||||
* including `RegExp` objects as well as strings interpreted as regular expressions.
|
* including `RegExp` objects as well as strings interpreted as regular expressions.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
RegExpTerm getRegExpFromNode(DataFlow::Node node) {
|
RegExpTerm getRegExpFromNode(DataFlow::Node node) {
|
||||||
result = getRegExpObjectFromNode(node)
|
result = getRegExpObjectFromNode(node)
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -73,6 +73,8 @@
|
|||||||
* expression in `k` induces a re-capture of `x` to reflect the fact that `x`
|
* expression in `k` induces a re-capture of `x` to reflect the fact that `x`
|
||||||
* is incremented between the two `console.log` calls.
|
* is incremented between the two `console.log` calls.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import semmle.javascript.dataflow.Refinements
|
private import semmle.javascript.dataflow.Refinements
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/** Provides classes for working with statements. */
|
/** Provides classes for working with statements. */
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/** Provides classes for working with ECMAScript 2015-style template expressions. */
|
/** Provides classes for working with ECMAScript 2015-style template expressions. */
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
@@ -58,6 +60,7 @@ class TemplateLiteral extends Expr, @template_literal {
|
|||||||
*/
|
*/
|
||||||
int getNumElement() { result = count(this.getAnElement()) }
|
int getNumElement() { result = count(this.getAnElement()) }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { this.getAnElement().isImpure() }
|
override predicate isImpure() { this.getAnElement().isImpure() }
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "TemplateLiteral" }
|
override string getAPrimaryQlClass() { result = "TemplateLiteral" }
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Provides classes for working with the token-based representation of JavaScript programs.
|
* Provides classes for working with the token-based representation of JavaScript programs.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Provides classes for reasoning about type annotations independently of dialect.
|
* Provides classes for reasoning about type annotations independently of dialect.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import internal.StmtContainers
|
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
|
* 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.
|
* associate it with a named type coming from an dependency.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
TypeNameBindingNode getTypeBinding() { result = this }
|
TypeNameBindingNode getTypeBinding() { result = this }
|
||||||
|
|
||||||
/** Holds if this is the `any` type. */
|
/** 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.
|
* 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) {
|
deprecated predicate hasQualifiedName(string globalName) {
|
||||||
UnderlyingTypes::nodeHasUnderlyingType(this, 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`.
|
* 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) {
|
deprecated predicate hasQualifiedName(string moduleName, string exportedName) {
|
||||||
UnderlyingTypes::nodeHasUnderlyingType(this, moduleName, 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,
|
* 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.
|
* or is declared as a subtype thereof, or is a union or intersection containing such a type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
final predicate hasUnderlyingType(string globalName) {
|
final predicate hasUnderlyingType(string globalName) {
|
||||||
UnderlyingTypes::nodeHasUnderlyingType(this, 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`,
|
* 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.
|
* 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) {
|
final predicate hasUnderlyingType(string moduleName, string exportedName) {
|
||||||
UnderlyingTypes::nodeHasUnderlyingType(this, moduleName, 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.
|
* Note that this has no result for JSDoc type annotations.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated Type getType() { none() }
|
deprecated Type getType() { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -142,5 +150,6 @@ class TypeAnnotation extends @type_annotation, NodeInStmtContainer {
|
|||||||
*
|
*
|
||||||
* This unfolds nullability modifiers and generic type applications.
|
* This unfolds nullability modifiers and generic type applications.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
final DataFlow::ClassNode getClass() { UnderlyingTypes::nodeHasUnderlyingClassType(this, result) }
|
final DataFlow::ClassNode getClass() { UnderlyingTypes::nodeHasUnderlyingClassType(this, result) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,6 +34,7 @@ class NamespaceDefinition extends Stmt, @namespace_definition, AST::ValueNode {
|
|||||||
/**
|
/**
|
||||||
* Gets the canonical name of the namespace being defined.
|
* Gets the canonical name of the namespace being defined.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated Namespace getNamespace() { result.getADefinition() = this }
|
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.
|
* Gets the canonical name of the type being defined.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated TypeName getTypeName() { result.getADefinition() = this }
|
deprecated TypeName getTypeName() { result.getADefinition() = this }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the type defined by this declaration.
|
* Gets the type defined by this declaration.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated Type getType() { ast_node_type(this.getIdentifier(), result) }
|
deprecated Type getType() { ast_node_type(this.getIdentifier(), result) }
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "TypeDefinition" }
|
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. */
|
/** A literal path expression appearing in an external module reference. */
|
||||||
|
overlay[global]
|
||||||
deprecated private class LiteralExternalModulePath extends PathExpr, ConstantString {
|
deprecated private class LiteralExternalModulePath extends PathExpr, ConstantString {
|
||||||
LiteralExternalModulePath() {
|
LiteralExternalModulePath() {
|
||||||
exists(ExternalModuleReference emr | this.getParentExpr*() = emr.getExpression())
|
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.
|
* Gets the canonical name of the type being defined.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated TypeName getTypeName() { result.getADefinition() = this }
|
deprecated TypeName getTypeName() { result.getADefinition() = this }
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "TypeAliasDeclaration" }
|
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.
|
* Gets the canonical name of the namespace referenced by this name.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated Namespace getNamespace() { result = this.getADeclaration().getNamespace() }
|
deprecated Namespace getNamespace() { result = this.getADeclaration().getNamespace() }
|
||||||
|
|
||||||
override DeclarationSpace getDeclarationSpace() { result = "namespace" }
|
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
|
* Has no result if this occurs in a TypeScript file that was extracted
|
||||||
* without type information.
|
* without type information.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated override Type getType() { ast_node_type(this, result) }
|
deprecated override Type getType() { ast_node_type(this, result) }
|
||||||
|
|
||||||
override Stmt getEnclosingStmt() { result = ExprOrType.super.getEnclosingStmt() }
|
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.
|
* Gets the canonical name of the type being accessed.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated TypeName getTypeName() { ast_node_symbol(this, result) }
|
deprecated TypeName getTypeName() { ast_node_symbol(this, result) }
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "TypeAccess" }
|
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.
|
* Gets the canonical name of the namespace being defined or aliased by this name.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated Namespace getNamespace() { ast_node_symbol(this, result) }
|
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.
|
* Gets the canonical name of the namespace being accessed.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated Namespace getNamespace() { ast_node_symbol(this, result) }
|
deprecated Namespace getNamespace() { ast_node_symbol(this, result) }
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "NamespaceAccess" }
|
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.
|
* Gets the canonical name of the type being defined.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated TypeName getTypeName() { ast_node_symbol(this, result) }
|
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.
|
* Gets the canonical name of the type defined by this enum member.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated TypeName getTypeName() { ast_node_symbol(this, result) }
|
deprecated TypeName getTypeName() { ast_node_symbol(this, result) }
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "EnumMember" }
|
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.
|
* Gets the priority with which this type root folder should be used from within the given search root.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
int getSearchPriority(Folder searchRoot) {
|
int getSearchPriority(Folder searchRoot) {
|
||||||
findNodeModulesFolder(searchRoot, this.getNodeModulesFolder(), result)
|
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
|
* For instance, there may be many AST nodes representing different uses of the
|
||||||
* `number` keyword, but there only exists one `number` type.
|
* `number` keyword, but there only exists one `number` type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class Type extends @type {
|
deprecated class Type extends @type {
|
||||||
/**
|
/**
|
||||||
* Gets a string representation of this 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`.
|
* A union type or intersection type, such as `string | number` or `T & U`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class UnionOrIntersectionType extends Type, @union_or_intersection_type {
|
deprecated class UnionOrIntersectionType extends Type, @union_or_intersection_type {
|
||||||
/**
|
/**
|
||||||
* Gets the `i`th member of this union or intersection, starting at 0.
|
* 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`,
|
* Note that the `boolean` type is represented as the union `true | false`,
|
||||||
* but is still displayed as `boolean` in string representations.
|
* but is still displayed as `boolean` in string representations.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class UnionType extends UnionOrIntersectionType, @union_type { }
|
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}`.
|
* An intersection type, such as `T & {x: number}`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class IntersectionType extends UnionOrIntersectionType, @intersection_type { }
|
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,
|
* Foreign array-like objects such as `HTMLCollection` are not normal JavaScript arrays,
|
||||||
* and their corresponding types are not considered array types either.
|
* and their corresponding types are not considered array types either.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class ArrayType extends Type {
|
deprecated class ArrayType extends Type {
|
||||||
ArrayType() {
|
ArrayType() {
|
||||||
this instanceof @tuple_type or
|
this instanceof @tuple_type or
|
||||||
@@ -2061,6 +2082,7 @@ deprecated class ArrayType extends Type {
|
|||||||
*
|
*
|
||||||
* An array type such as `Array<string>`, or equivalently, `string[]`.
|
* An array type such as `Array<string>`, or equivalently, `string[]`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class PlainArrayType extends ArrayType, TypeReference {
|
deprecated class PlainArrayType extends ArrayType, TypeReference {
|
||||||
PlainArrayType() { this.hasQualifiedName("Array") }
|
PlainArrayType() { this.hasQualifiedName("Array") }
|
||||||
|
|
||||||
@@ -2075,6 +2097,7 @@ deprecated class PlainArrayType extends ArrayType, TypeReference {
|
|||||||
*
|
*
|
||||||
* A read-only array type such as `ReadonlyArray<string>`.
|
* A read-only array type such as `ReadonlyArray<string>`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class ReadonlyArrayType extends ArrayType, TypeReference {
|
deprecated class ReadonlyArrayType extends ArrayType, TypeReference {
|
||||||
ReadonlyArrayType() { this.hasQualifiedName("ReadonlyArray") }
|
ReadonlyArrayType() { this.hasQualifiedName("ReadonlyArray") }
|
||||||
}
|
}
|
||||||
@@ -2087,6 +2110,7 @@ deprecated class ReadonlyArrayType extends ArrayType, TypeReference {
|
|||||||
*
|
*
|
||||||
* A tuple type, such as `[number, string]`.
|
* A tuple type, such as `[number, string]`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class TupleType extends ArrayType, @tuple_type {
|
deprecated class TupleType extends ArrayType, @tuple_type {
|
||||||
/**
|
/**
|
||||||
* Gets the `i`th member of this tuple type, starting at 0.
|
* 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.
|
* The predefined `any` type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class AnyType extends Type, @any_type { }
|
deprecated class AnyType extends Type, @any_type { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2158,6 +2183,7 @@ deprecated class AnyType extends Type, @any_type { }
|
|||||||
*
|
*
|
||||||
* The predefined `unknown` type.
|
* The predefined `unknown` type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class UnknownType extends Type, @unknown_type { }
|
deprecated class UnknownType extends Type, @unknown_type { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2168,6 +2194,7 @@ deprecated class UnknownType extends Type, @unknown_type { }
|
|||||||
*
|
*
|
||||||
* The predefined `string` type.
|
* The predefined `string` type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class StringType extends Type, @string_type { }
|
deprecated class StringType extends Type, @string_type { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2178,6 +2205,7 @@ deprecated class StringType extends Type, @string_type { }
|
|||||||
*
|
*
|
||||||
* The predefined `number` type.
|
* The predefined `number` type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class NumberType extends Type, @number_type { }
|
deprecated class NumberType extends Type, @number_type { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2188,6 +2216,7 @@ deprecated class NumberType extends Type, @number_type { }
|
|||||||
*
|
*
|
||||||
* The predefined `bigint` type.
|
* The predefined `bigint` type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class BigIntType extends Type, @bigint_type { }
|
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.
|
* A boolean, number, or string literal type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class LiteralType extends Type, @literal_type {
|
deprecated class LiteralType extends Type, @literal_type {
|
||||||
/**
|
/**
|
||||||
* Gets the string value of this literal.
|
* 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`.
|
* The boolean literal type `true` or `false`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class BooleanLiteralType extends LiteralType, @boolean_literal_type {
|
deprecated class BooleanLiteralType extends LiteralType, @boolean_literal_type {
|
||||||
/**
|
/**
|
||||||
* Gets the boolean value represented by this 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.
|
* A number literal as a static type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class NumberLiteralType extends LiteralType, @number_literal_type {
|
deprecated class NumberLiteralType extends LiteralType, @number_literal_type {
|
||||||
override string getStringValue() { type_literal_value(this, result) }
|
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.
|
* A string literal as a static type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class StringLiteralType extends LiteralType, @string_literal_type {
|
deprecated class StringLiteralType extends LiteralType, @string_literal_type {
|
||||||
override string getStringValue() { type_literal_value(this, result) }
|
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.
|
* A bigint literal as a static type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class BigIntLiteralType extends LiteralType {
|
deprecated class BigIntLiteralType extends LiteralType {
|
||||||
override string getStringValue() { type_literal_value(this, result) }
|
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`.
|
* The `boolean` type, internally represented as the union type `true | false`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class BooleanType extends UnionType {
|
deprecated class BooleanType extends UnionType {
|
||||||
BooleanType() {
|
BooleanType() {
|
||||||
this.getAnElementType() instanceof @true_type and
|
this.getAnElementType() instanceof @true_type and
|
||||||
@@ -2299,6 +2334,7 @@ deprecated class BooleanType extends UnionType {
|
|||||||
*
|
*
|
||||||
* The `string` type or a string literal type.
|
* The `string` type or a string literal type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class StringLikeType extends Type {
|
deprecated class StringLikeType extends Type {
|
||||||
StringLikeType() {
|
StringLikeType() {
|
||||||
this instanceof StringType or
|
this instanceof StringType or
|
||||||
@@ -2314,6 +2350,7 @@ deprecated class StringLikeType extends Type {
|
|||||||
*
|
*
|
||||||
* The `number` type or a number literal type.
|
* The `number` type or a number literal type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class NumberLikeType extends Type {
|
deprecated class NumberLikeType extends Type {
|
||||||
NumberLikeType() {
|
NumberLikeType() {
|
||||||
this instanceof NumberType or
|
this instanceof NumberType or
|
||||||
@@ -2329,6 +2366,7 @@ deprecated class NumberLikeType extends Type {
|
|||||||
*
|
*
|
||||||
* The `boolean`, `true,` or `false` type.
|
* The `boolean`, `true,` or `false` type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class BooleanLikeType extends Type {
|
deprecated class BooleanLikeType extends Type {
|
||||||
BooleanLikeType() {
|
BooleanLikeType() {
|
||||||
this instanceof BooleanType or
|
this instanceof BooleanType or
|
||||||
@@ -2344,6 +2382,7 @@ deprecated class BooleanLikeType extends Type {
|
|||||||
*
|
*
|
||||||
* The `void` type.
|
* The `void` type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class VoidType extends Type, @void_type { }
|
deprecated class VoidType extends Type, @void_type { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2354,6 +2393,7 @@ deprecated class VoidType extends Type, @void_type { }
|
|||||||
*
|
*
|
||||||
* The `undefined` type.
|
* The `undefined` type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class UndefinedType extends Type, @undefined_type { }
|
deprecated class UndefinedType extends Type, @undefined_type { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2364,6 +2404,7 @@ deprecated class UndefinedType extends Type, @undefined_type { }
|
|||||||
*
|
*
|
||||||
* The `null` type.
|
* The `null` type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class NullType extends Type, @null_type { }
|
deprecated class NullType extends Type, @null_type { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2374,6 +2415,7 @@ deprecated class NullType extends Type, @null_type { }
|
|||||||
*
|
*
|
||||||
* The `never` type.
|
* The `never` type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class NeverType extends Type, @never_type { }
|
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.
|
* The `symbol` type or a specific `unique symbol` type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class SymbolType extends Type, @symbol_type { }
|
deprecated class SymbolType extends Type, @symbol_type { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2394,6 +2437,7 @@ deprecated class SymbolType extends Type, @symbol_type { }
|
|||||||
*
|
*
|
||||||
* The `symbol` type.
|
* The `symbol` type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class PlainSymbolType extends SymbolType, @plain_symbol_type { }
|
deprecated class PlainSymbolType extends SymbolType, @plain_symbol_type { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2404,6 +2448,7 @@ deprecated class PlainSymbolType extends SymbolType, @plain_symbol_type { }
|
|||||||
*
|
*
|
||||||
* A `unique symbol` type.
|
* A `unique symbol` type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class UniqueSymbolType extends SymbolType, @unique_symbol_type {
|
deprecated class UniqueSymbolType extends SymbolType, @unique_symbol_type {
|
||||||
/**
|
/**
|
||||||
* Gets the canonical name of the variable exposing the symbol.
|
* 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.
|
* The `object` type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class ObjectKeywordType extends Type, @objectkeyword_type { }
|
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.
|
* A type that refers to a class, interface, enum, or enum member.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class TypeReference extends Type, @type_reference {
|
deprecated class TypeReference extends Type, @type_reference {
|
||||||
/**
|
/**
|
||||||
* Gets the canonical name of the type being referenced.
|
* 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.
|
* A type that refers to a class, possibly with type arguments.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class ClassType extends TypeReference {
|
deprecated class ClassType extends TypeReference {
|
||||||
ClassDefinition declaration;
|
ClassDefinition declaration;
|
||||||
|
|
||||||
@@ -2525,6 +2573,7 @@ deprecated class ClassType extends TypeReference {
|
|||||||
*
|
*
|
||||||
* A type that refers to an interface, possibly with type arguents.
|
* A type that refers to an interface, possibly with type arguents.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class InterfaceType extends TypeReference {
|
deprecated class InterfaceType extends TypeReference {
|
||||||
InterfaceDeclaration declaration;
|
InterfaceDeclaration declaration;
|
||||||
|
|
||||||
@@ -2544,6 +2593,7 @@ deprecated class InterfaceType extends TypeReference {
|
|||||||
*
|
*
|
||||||
* A type that refers to an enum.
|
* A type that refers to an enum.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class EnumType extends TypeReference {
|
deprecated class EnumType extends TypeReference {
|
||||||
EnumDeclaration declaration;
|
EnumDeclaration declaration;
|
||||||
|
|
||||||
@@ -2563,6 +2613,7 @@ deprecated class EnumType extends TypeReference {
|
|||||||
*
|
*
|
||||||
* A type that refers to the value of an enum member.
|
* A type that refers to the value of an enum member.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class EnumLiteralType extends TypeReference {
|
deprecated class EnumLiteralType extends TypeReference {
|
||||||
EnumMember declaration;
|
EnumMember declaration;
|
||||||
|
|
||||||
@@ -2582,6 +2633,7 @@ deprecated class EnumLiteralType extends TypeReference {
|
|||||||
*
|
*
|
||||||
* A type that refers to a type alias.
|
* A type that refers to a type alias.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class TypeAliasReference extends TypeReference {
|
deprecated class TypeAliasReference extends TypeReference {
|
||||||
TypeAliasReference() { type_alias(this, _) }
|
TypeAliasReference() { type_alias(this, _) }
|
||||||
|
|
||||||
@@ -2601,6 +2653,7 @@ deprecated class TypeAliasReference extends TypeReference {
|
|||||||
*
|
*
|
||||||
* An anonymous interface type, such as `{ x: number }`.
|
* An anonymous interface type, such as `{ x: number }`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class AnonymousInterfaceType extends Type, @object_type { }
|
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.
|
* A type that refers to a type variable.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class TypeVariableType extends Type, @typevariable_type {
|
deprecated class TypeVariableType extends Type, @typevariable_type {
|
||||||
/**
|
/**
|
||||||
* Gets a syntactic declaration of this type variable.
|
* 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.
|
* 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 {
|
deprecated class CanonicalTypeVariableType extends TypeVariableType, @canonical_type_variable_type {
|
||||||
override TypeName getHostType() { result = this.getCanonicalName().getParent() }
|
override TypeName getHostType() { result = this.getCanonicalName().getParent() }
|
||||||
|
|
||||||
@@ -2681,6 +2736,7 @@ deprecated class CanonicalTypeVariableType extends TypeVariableType, @canonical_
|
|||||||
* - `<T>(x: T) => T`
|
* - `<T>(x: T) => T`
|
||||||
* - `<S, T>(x: S, y: T) => T`.
|
* - `<S, T>(x: S, y: T) => T`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class LexicalTypeVariableType extends TypeVariableType, @lexical_type_variable_type {
|
deprecated class LexicalTypeVariableType extends TypeVariableType, @lexical_type_variable_type {
|
||||||
override string getName() {
|
override string getName() {
|
||||||
types(this, _, result) // The toString value contains the name.
|
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 {
|
deprecated class ThisType extends Type, @this_type {
|
||||||
/**
|
/**
|
||||||
* Gets the type containing the `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
|
* The type of a named value, `typeof X`, typically denoting the type of
|
||||||
* a class constructor, namespace object, enum object, or module object.
|
* a class constructor, namespace object, enum object, or module object.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class TypeofType extends Type, @typeof_type {
|
deprecated class TypeofType extends Type, @typeof_type {
|
||||||
/**
|
/**
|
||||||
* Gets the canonical name of the named value.
|
* Gets the canonical name of the named value.
|
||||||
@@ -2801,6 +2859,7 @@ module SignatureKind {
|
|||||||
*
|
*
|
||||||
* A function or constructor signature in a TypeScript type.
|
* A function or constructor signature in a TypeScript type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class CallSignatureType extends @signature_type {
|
deprecated class CallSignatureType extends @signature_type {
|
||||||
/**
|
/**
|
||||||
* Gets a value indicating if this is a function or constructor signature.
|
* 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.
|
* 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 { }
|
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.
|
* 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
|
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 one type parameter, say, `T`
|
||||||
* - It has a `then` method whose first argument is a callback that takes a `T` as argument.
|
* - 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 {
|
deprecated private class PromiseTypeName extends TypeName {
|
||||||
PromiseTypeName() {
|
PromiseTypeName() {
|
||||||
// The name must suggest it is a promise.
|
// 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,
|
* This includes types whose name and `then` method signature suggest it is a promise,
|
||||||
* such as `PromiseLike<T>` and `Thenable<T>`.
|
* such as `PromiseLike<T>` and `Thenable<T>`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
deprecated class PromiseType extends TypeReference {
|
deprecated class PromiseType extends TypeReference {
|
||||||
PromiseType() {
|
PromiseType() {
|
||||||
this.getNumTypeArgument() = 1 and
|
this.getNumTypeArgument() = 1 and
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/** Provides classes for modeling program variables. */
|
/** Provides classes for modeling program variables. */
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
@@ -62,6 +64,7 @@ class LocalScope extends Scope {
|
|||||||
*/
|
*/
|
||||||
class ModuleScope extends Scope, @module_scope {
|
class ModuleScope extends Scope, @module_scope {
|
||||||
/** Gets the module that induces this scope. */
|
/** Gets the module that induces this scope. */
|
||||||
|
overlay[global]
|
||||||
Module getModule() { result = this.getScopeElement() }
|
Module getModule() { result = this.getScopeElement() }
|
||||||
|
|
||||||
override string toString() { result = "module scope" }
|
override string toString() { result = "module scope" }
|
||||||
@@ -256,6 +259,7 @@ class VarRef extends @varref, Identifier, BindingPattern, LexicalRef {
|
|||||||
|
|
||||||
override VarRef getABindingVarRef() { result = this }
|
override VarRef getABindingVarRef() { result = this }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { none() }
|
override predicate isImpure() { none() }
|
||||||
|
|
||||||
override Expr getUnderlyingReference() { result = this }
|
override Expr getUnderlyingReference() { result = this }
|
||||||
@@ -543,6 +547,7 @@ class ArrayPattern extends DestructuringPattern, @array_pattern {
|
|||||||
/** Holds if this array pattern has an omitted element. */
|
/** Holds if this array pattern has an omitted element. */
|
||||||
predicate hasOmittedElement() { this.elementIsOmitted(_) }
|
predicate hasOmittedElement() { this.elementIsOmitted(_) }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { this.getAnElement().isImpure() }
|
override predicate isImpure() { this.getAnElement().isImpure() }
|
||||||
|
|
||||||
override VarRef getABindingVarRef() {
|
override VarRef getABindingVarRef() {
|
||||||
@@ -583,6 +588,7 @@ class ObjectPattern extends DestructuringPattern, @object_pattern {
|
|||||||
/** Gets the rest property pattern of this object pattern, if any. */
|
/** Gets the rest property pattern of this object pattern, if any. */
|
||||||
override Expr getRest() { result = this.getChildExpr(-1) }
|
override Expr getRest() { result = this.getChildExpr(-1) }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override predicate isImpure() { this.getAPropertyPattern().isImpure() }
|
override predicate isImpure() { this.getAPropertyPattern().isImpure() }
|
||||||
|
|
||||||
override VarRef getABindingVarRef() {
|
override VarRef getABindingVarRef() {
|
||||||
@@ -640,6 +646,7 @@ class PropertyPattern extends @property, AstNode {
|
|||||||
ObjectPattern getObjectPattern() { properties(this, result, _, _, _) }
|
ObjectPattern getObjectPattern() { properties(this, result, _, _, _) }
|
||||||
|
|
||||||
/** Holds if this pattern is impure, that is, if its evaluation could have side effects. */
|
/** Holds if this pattern is impure, that is, if its evaluation could have side effects. */
|
||||||
|
overlay[global]
|
||||||
predicate isImpure() {
|
predicate isImpure() {
|
||||||
this.isComputed() and this.getNameExpr().isImpure()
|
this.isComputed() and this.getNameExpr().isImpure()
|
||||||
or
|
or
|
||||||
@@ -844,6 +851,7 @@ class SimpleParameter extends Parameter, VarDecl {
|
|||||||
* Gets a use of this parameter that refers to its initial value as
|
* Gets a use of this parameter that refers to its initial value as
|
||||||
* passed in from the caller.
|
* passed in from the caller.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
VarUse getAnInitialUse() {
|
VarUse getAnInitialUse() {
|
||||||
exists(SsaDefinition ssa |
|
exists(SsaDefinition ssa |
|
||||||
ssa.getAContributingVarDef() = this and
|
ssa.getAContributingVarDef() = this and
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Provides classes and predicates for working with XML files and their content.
|
* Provides classes and predicates for working with XML files and their content.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import semmle.files.FileSystem
|
import semmle.files.FileSystem
|
||||||
private import codeql.xml.Xml
|
private import codeql.xml.Xml
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
* YAML documents are represented as abstract syntax trees whose nodes
|
* YAML documents are represented as abstract syntax trees whose nodes
|
||||||
* are either YAML values or alias nodes referring to another YAML value.
|
* are either YAML values or alias nodes referring to another YAML value.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import codeql.yaml.Yaml as LibYaml
|
private import codeql.yaml.Yaml as LibYaml
|
||||||
|
|||||||
@@ -37,6 +37,8 @@
|
|||||||
* they represent; additionally, indefinite abstract values record
|
* they represent; additionally, indefinite abstract values record
|
||||||
* the source of imprecision that caused them to arise.
|
* the source of imprecision that caused them to arise.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.dataflow.internal.AbstractValuesImpl
|
private import semmle.javascript.dataflow.internal.AbstractValuesImpl
|
||||||
@@ -57,6 +59,7 @@ class AbstractValue extends TAbstractValue {
|
|||||||
* Gets the Boolean value some concrete value represented by this
|
* Gets the Boolean value some concrete value represented by this
|
||||||
* abstract value coerces to.
|
* abstract value coerces to.
|
||||||
*/
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
abstract boolean getBooleanValue();
|
abstract boolean getBooleanValue();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,6 +100,7 @@ class AbstractValue extends TAbstractValue {
|
|||||||
* In all cases, purely local flow tracking is used to find prototype objects, so
|
* 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.
|
* this predicate cannot be relied on to compute all possible prototype objects.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
DefiniteAbstractValue getAPrototype() {
|
DefiniteAbstractValue getAPrototype() {
|
||||||
exists(AbstractProtoProperty proto |
|
exists(AbstractProtoProperty proto |
|
||||||
proto.getBase() = this and
|
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
|
* Note: For performance reasons, all subclasses of this class should be part
|
||||||
* of the standard library. Use `isAdditionalFlowStep` for query-specific flow steps.
|
* of the standard library. Use `isAdditionalFlowStep` for query-specific flow steps.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
class AdditionalFlowStep extends Unit {
|
class AdditionalFlowStep extends Unit {
|
||||||
/**
|
/**
|
||||||
* Holds if `pred` → `succ` should be considered a value-preserving data flow edge.f
|
* 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() }
|
predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `pred` → `succ` should be considered a value-preserving data flow edge that
|
* Holds if `pred` → `succ` should be considered a value-preserving data flow edge that
|
||||||
* crosses calling contexts.
|
* crosses calling contexts.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate jumpStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
|
predicate jumpStep(DataFlow::Node pred, DataFlow::Node succ) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `pred` should be stored in the given `content` of the object `succ`.
|
* 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) {
|
predicate storeStep(DataFlow::Node pred, DataFlow::ContentSet contents, DataFlow::Node succ) {
|
||||||
none()
|
none()
|
||||||
}
|
}
|
||||||
@@ -55,6 +59,7 @@ class AdditionalFlowStep extends Unit {
|
|||||||
/**
|
/**
|
||||||
* Holds if the given `content` of the object in `pred` should be read into `succ`.
|
* 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) {
|
predicate readStep(DataFlow::Node pred, DataFlow::ContentSet contents, DataFlow::Node succ) {
|
||||||
none()
|
none()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -625,15 +625,19 @@ abstract deprecated class LabeledBarrierGuardNode extends BarrierGuardNode {
|
|||||||
*
|
*
|
||||||
* For use with load/store steps in `DataFlow::SharedFlowStep` and TypeTracking.
|
* For use with load/store steps in `DataFlow::SharedFlowStep` and TypeTracking.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
module PseudoProperties {
|
module PseudoProperties {
|
||||||
/** Holds if `s` is a pseudo-property. */
|
/** Holds if `s` is a pseudo-property. */
|
||||||
bindingset[s]
|
bindingset[s]
|
||||||
|
overlay[caller]
|
||||||
predicate isPseudoProperty(string s) { s.matches("$%$") }
|
predicate isPseudoProperty(string s) { s.matches("$%$") }
|
||||||
|
|
||||||
bindingset[s]
|
bindingset[s]
|
||||||
|
overlay[caller]
|
||||||
private string pseudoProperty(string s) { result = "$" + s + "$" }
|
private string pseudoProperty(string s) { result = "$" + s + "$" }
|
||||||
|
|
||||||
bindingset[s, v]
|
bindingset[s, v]
|
||||||
|
overlay[caller]
|
||||||
private string pseudoProperty(string s, string v) { result = "$" + s + "|" + v + "$" }
|
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`.
|
* 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.
|
* 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]
|
pragma[inline]
|
||||||
string mapValueKnownKey(DataFlow::Node key) {
|
string mapValueKnownKey(DataFlow::Node key) {
|
||||||
result = mapValueKey(any(string s | key.mayHaveStringValue(s)))
|
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`.
|
* Gets a pseudo-property for the location of a map value where the key is `key`.
|
||||||
*/
|
*/
|
||||||
bindingset[key]
|
bindingset[key]
|
||||||
|
overlay[caller]
|
||||||
string mapValueKey(string key) { result = pseudoProperty("mapValue", key) }
|
string mapValueKey(string key) { result = pseudoProperty("mapValue", key) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `prop` equals `mapValueKey(key)` for some value of `key`.
|
* Holds if `prop` equals `mapValueKey(key)` for some value of `key`.
|
||||||
*/
|
*/
|
||||||
bindingset[prop]
|
bindingset[prop]
|
||||||
|
overlay[caller]
|
||||||
predicate isMapValueKey(string prop) { prop.matches("$mapValue|%$") }
|
predicate isMapValueKey(string prop) { prop.matches("$mapValue|%$") }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a pseudo-property for the location of a map value where the key is `key`.
|
* Gets a pseudo-property for the location of a map value where the key is `key`.
|
||||||
*/
|
*/
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
string mapValue(DataFlow::Node key) {
|
string mapValue(DataFlow::Node key) {
|
||||||
result = mapValueKnownKey(key)
|
result = mapValueKnownKey(key)
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
* For performance reasons, all subclasses of `CustomAbstractValueDefinition`
|
* For performance reasons, all subclasses of `CustomAbstractValueDefinition`
|
||||||
* should be part of the standard library.
|
* should be part of the standard library.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import internal.AbstractValuesImpl
|
private import internal.AbstractValuesImpl
|
||||||
@@ -32,6 +34,7 @@ class CustomAbstractValueFromDefinition extends AbstractValue, TCustomAbstractVa
|
|||||||
|
|
||||||
override predicate isIndefinite(DataFlow::Incompleteness cause) { def.isIndefinite(cause) }
|
override predicate isIndefinite(DataFlow::Incompleteness cause) { def.isIndefinite(cause) }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DefiniteAbstractValue getAPrototype() { result = def.getAPrototype() }
|
override DefiniteAbstractValue getAPrototype() { result = def.getAPrototype() }
|
||||||
|
|
||||||
override predicate hasLocationInfo(
|
override predicate hasLocationInfo(
|
||||||
@@ -98,6 +101,7 @@ abstract class CustomAbstractValueDefinition extends Locatable {
|
|||||||
* Gets an abstract value that represents a prototype object of the
|
* Gets an abstract value that represents a prototype object of the
|
||||||
* induced abstract value.
|
* induced abstract value.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
AbstractValue getAPrototype() {
|
AbstractValue getAPrototype() {
|
||||||
exists(AbstractProtoProperty proto |
|
exists(AbstractProtoProperty proto |
|
||||||
proto.getBase() = this.getAbstractValue() and
|
proto.getBase() = this.getAbstractValue() and
|
||||||
@@ -119,6 +123,7 @@ abstract class CustomAbstractValueDefinition extends Locatable {
|
|||||||
/**
|
/**
|
||||||
* Flow analysis for custom abstract values.
|
* Flow analysis for custom abstract values.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
class CustomAbstractValueFromDefinitionNode extends DataFlow::AnalyzedNode, DataFlow::ValueNode {
|
class CustomAbstractValueFromDefinitionNode extends DataFlow::AnalyzedNode, DataFlow::ValueNode {
|
||||||
CustomAbstractValueFromDefinition val;
|
CustomAbstractValueFromDefinition val;
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
* Flow through global variables, object properties or function calls is not
|
* Flow through global variables, object properties or function calls is not
|
||||||
* modeled (except for immediately invoked functions as explained above).
|
* modeled (except for immediately invoked functions as explained above).
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import internal.CallGraphs
|
private import internal.CallGraphs
|
||||||
@@ -64,9 +66,11 @@ module DataFlow {
|
|||||||
* `p.getALocalSource()` does _not_ return the corresponding argument, and
|
* `p.getALocalSource()` does _not_ return the corresponding argument, and
|
||||||
* `p.isIncomplete("call")` holds.
|
* `p.isIncomplete("call")` holds.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate isIncomplete(Incompleteness cause) { isIncomplete(this, cause) }
|
predicate isIncomplete(Incompleteness cause) { isIncomplete(this, cause) }
|
||||||
|
|
||||||
/** Gets type inference results for this data flow node. */
|
/** Gets type inference results for this data flow node. */
|
||||||
|
overlay[global]
|
||||||
AnalyzedNode analyze() { result = this }
|
AnalyzedNode analyze() { result = this }
|
||||||
|
|
||||||
/** Gets the expression corresponding to this data flow node, if any. */
|
/** Gets the expression corresponding to this data flow node, if any. */
|
||||||
@@ -124,11 +128,13 @@ module DataFlow {
|
|||||||
int getIntValue() { result = this.asExpr().getIntValue() }
|
int getIntValue() { result = this.asExpr().getIntValue() }
|
||||||
|
|
||||||
/** Gets a function value that may reach this node. */
|
/** Gets a function value that may reach this node. */
|
||||||
|
overlay[global]
|
||||||
final FunctionNode getAFunctionValue() {
|
final FunctionNode getAFunctionValue() {
|
||||||
CallGraph::getAFunctionReference(result, 0).flowsTo(this)
|
CallGraph::getAFunctionReference(result, 0).flowsTo(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a function value that may reach this node with the given `imprecision` level. */
|
/** Gets a function value that may reach this node with the given `imprecision` level. */
|
||||||
|
overlay[global]
|
||||||
final FunctionNode getAFunctionValue(int imprecision) {
|
final FunctionNode getAFunctionValue(int imprecision) {
|
||||||
CallGraph::getAFunctionReference(result, imprecision).flowsTo(this)
|
CallGraph::getAFunctionReference(result, imprecision).flowsTo(this)
|
||||||
}
|
}
|
||||||
@@ -137,6 +143,7 @@ module DataFlow {
|
|||||||
* Gets a function value that may reach this node,
|
* Gets a function value that may reach this node,
|
||||||
* possibly derived from a partial function invocation.
|
* possibly derived from a partial function invocation.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
final FunctionNode getABoundFunctionValue(int boundArgs) {
|
final FunctionNode getABoundFunctionValue(int boundArgs) {
|
||||||
result = this.getAFunctionValue() and boundArgs = 0
|
result = this.getAFunctionValue() and boundArgs = 0
|
||||||
or
|
or
|
||||||
@@ -192,6 +199,7 @@ module DataFlow {
|
|||||||
FlowSteps::identityFunctionStep(result, this)
|
FlowSteps::identityFunctionStep(result, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
private NameResolution::Node getNameResolutionNode() {
|
private NameResolution::Node getNameResolutionNode() {
|
||||||
this = valueNode(result)
|
this = valueNode(result)
|
||||||
or
|
or
|
||||||
@@ -205,6 +213,7 @@ module DataFlow {
|
|||||||
* Holds if this node is annotated with the given named type,
|
* 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.
|
* or is declared as a subtype thereof, or is a union or intersection containing such a type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
cached
|
cached
|
||||||
predicate hasUnderlyingType(string globalName) {
|
predicate hasUnderlyingType(string globalName) {
|
||||||
Stages::TypeTracking::ref() and
|
Stages::TypeTracking::ref() and
|
||||||
@@ -218,6 +227,7 @@ module DataFlow {
|
|||||||
* Holds if this node is annotated with the given named type,
|
* 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.
|
* or is declared as a subtype thereof, or is a union or intersection containing such a type.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
cached
|
cached
|
||||||
predicate hasUnderlyingType(string moduleName, string typeName) {
|
predicate hasUnderlyingType(string moduleName, string typeName) {
|
||||||
Stages::TypeTracking::ref() and
|
Stages::TypeTracking::ref() and
|
||||||
@@ -466,6 +476,7 @@ module DataFlow {
|
|||||||
/**
|
/**
|
||||||
* Gets an accessor (`get` or `set` method) that may be invoked by this property reference.
|
* Gets an accessor (`get` or `set` method) that may be invoked by this property reference.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
final DataFlow::FunctionNode getAnAccessorCallee() {
|
final DataFlow::FunctionNode getAnAccessorCallee() {
|
||||||
result = CallGraph::getAnAccessorCallee(this)
|
result = CallGraph::getAnAccessorCallee(this)
|
||||||
}
|
}
|
||||||
@@ -1419,11 +1430,13 @@ module DataFlow {
|
|||||||
* This predicate is only defined for expressions, properties, and for statements that declare
|
* This predicate is only defined for expressions, properties, and for statements that declare
|
||||||
* a function, a class, or a TypeScript namespace or enum.
|
* a function, a class, or a TypeScript namespace or enum.
|
||||||
*/
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
ValueNode valueNode(AstNode nd) { result.getAstNode() = nd }
|
ValueNode valueNode(AstNode nd) { result.getAstNode() = nd }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the data flow node corresponding to `e`.
|
* Gets the data flow node corresponding to `e`.
|
||||||
*/
|
*/
|
||||||
|
overlay[caller?]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
ExprNode exprNode(Expr e) { result = valueNode(e) }
|
ExprNode exprNode(Expr e) { result = valueNode(e) }
|
||||||
|
|
||||||
@@ -1762,6 +1775,7 @@ module DataFlow {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
private class ReflectiveParamsStep extends LegacyPreCallGraphStep {
|
private class ReflectiveParamsStep extends LegacyPreCallGraphStep {
|
||||||
override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) {
|
override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) {
|
||||||
exists(DataFlow::ReflectiveParametersNode params, DataFlow::FunctionNode f, int i |
|
exists(DataFlow::ReflectiveParametersNode params, DataFlow::FunctionNode f, int i |
|
||||||
@@ -1774,6 +1788,7 @@ module DataFlow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A taint step from the reflective parameters node to any parameter. */
|
/** A taint step from the reflective parameters node to any parameter. */
|
||||||
|
overlay[global]
|
||||||
private class ReflectiveParamsTaintStep extends TaintTracking::LegacyTaintStep {
|
private class ReflectiveParamsTaintStep extends TaintTracking::LegacyTaintStep {
|
||||||
override predicate step(DataFlow::Node obj, DataFlow::Node element) {
|
override predicate step(DataFlow::Node obj, DataFlow::Node element) {
|
||||||
exists(DataFlow::ReflectiveParametersNode params, DataFlow::FunctionNode f |
|
exists(DataFlow::ReflectiveParametersNode params, DataFlow::FunctionNode f |
|
||||||
@@ -1787,6 +1802,7 @@ module DataFlow {
|
|||||||
/**
|
/**
|
||||||
* Holds if there is a step from `pred` to `succ` through a field accessed through `this` in a class.
|
* 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) {
|
predicate localFieldStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
exists(ClassNode cls, string prop |
|
exists(ClassNode cls, string prop |
|
||||||
pred = AccessPath::getAnAssignmentTo(cls.getADirectSuperClass*().getAReceiverNode(), prop) or
|
pred = AccessPath::getAnAssignmentTo(cls.getADirectSuperClass*().getAReceiverNode(), prop) or
|
||||||
@@ -1819,6 +1835,7 @@ module DataFlow {
|
|||||||
* `p.getALocalSource()` does _not_ return the corresponding argument, and
|
* `p.getALocalSource()` does _not_ return the corresponding argument, and
|
||||||
* `p.isIncomplete("call")` holds.
|
* `p.isIncomplete("call")` holds.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate isIncomplete(Node nd, Incompleteness cause) {
|
predicate isIncomplete(Node nd, Incompleteness cause) {
|
||||||
exists(SsaVariable ssa | nd = TSsaDefNode(ssa.getDefinition()) |
|
exists(SsaVariable ssa | nd = TSsaDefNode(ssa.getDefinition()) |
|
||||||
defIsIncomplete(ssa.(SsaExplicitDefinition).getDef(), cause)
|
defIsIncomplete(ssa.(SsaExplicitDefinition).getDef(), cause)
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/** Provides classes and predicates for defining flow summaries. */
|
/** Provides classes and predicates for defining flow summaries. */
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.dataflow.internal.sharedlib.FlowSummaryImpl as Impl
|
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.
|
* Types inferred by the flow analysis, represented as type tags.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
* as nodes corresponding to function definitions or nodes corresponding to
|
* as nodes corresponding to function definitions or nodes corresponding to
|
||||||
* parameters.
|
* parameters.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.dependencies.Dependencies
|
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"))
|
* addEventHandler("click", foo.bind(this, "value of x"))
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
ParameterNode getABoundCallbackParameter(int callback, int param) {
|
ParameterNode getABoundCallbackParameter(int callback, int param) {
|
||||||
exists(int boundArgs |
|
exists(int boundArgs |
|
||||||
result =
|
result =
|
||||||
@@ -178,6 +181,7 @@ class InvokeNode extends DataFlow::SourceNode instanceof DataFlow::Impl::InvokeN
|
|||||||
private ObjectLiteralNode getOptionsArgument(int i) { result.flowsTo(this.getArgument(i)) }
|
private ObjectLiteralNode getOptionsArgument(int i) { result.flowsTo(this.getArgument(i)) }
|
||||||
|
|
||||||
/** Gets an abstract value representing possible callees of this call site. */
|
/** Gets an abstract value representing possible callees of this call site. */
|
||||||
|
overlay[global]
|
||||||
final AbstractValue getACalleeValue() {
|
final AbstractValue getACalleeValue() {
|
||||||
exists(DataFlow::Node callee, DataFlow::AnalyzedNode analyzed |
|
exists(DataFlow::Node callee, DataFlow::AnalyzedNode analyzed |
|
||||||
pragma[only_bind_into](callee) = this.getCalleeNode() and
|
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
|
* To alter the call graph as seen by the interprocedural data flow libraries, override
|
||||||
* the `getACallee(int imprecision)` predicate instead.
|
* the `getACallee(int imprecision)` predicate instead.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
final Function getACallee() { result = this.getACallee(0) }
|
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
|
* This predicate can be overridden to alter the call graph used by the interprocedural
|
||||||
* data flow libraries.
|
* data flow libraries.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
Function getACallee(int imprecision) {
|
Function getACallee(int imprecision) {
|
||||||
result = CallGraph::getACallee(this, imprecision).getFunction()
|
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
|
* Holds if the approximation of possible callees for this call site is
|
||||||
* affected by the given analysis incompleteness `cause`.
|
* affected by the given analysis incompleteness `cause`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate isIndefinite(DataFlow::Incompleteness cause) {
|
predicate isIndefinite(DataFlow::Incompleteness cause) {
|
||||||
this.getACalleeValue().isIndefinite(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
|
* independent contexts, so tracking flow through it leads to
|
||||||
* imprecision.
|
* imprecision.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate isImprecise() {
|
predicate isImprecise() {
|
||||||
this.isIndefinite("global") and
|
this.isIndefinite("global") and
|
||||||
exists(DefiniteAbstractValue v | v = this.getACalleeValue() | not v instanceof AbstractCallable)
|
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
|
* Holds if our approximation of possible callees for this call site is
|
||||||
* likely to be incomplete.
|
* likely to be incomplete.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate isIncomplete() {
|
predicate isIncomplete() {
|
||||||
// the flow analysis identifies a source of incompleteness other than
|
// the flow analysis identifies a source of incompleteness other than
|
||||||
// global flow (which usually leads to imprecision rather than incompleteness)
|
// 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
|
* Holds if our approximation of possible callees for this call site is
|
||||||
* likely to be imprecise or incomplete.
|
* likely to be imprecise or incomplete.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate isUncertain() { this.isImprecise() or this.isIncomplete() }
|
predicate isUncertain() { this.isImprecise() or this.isIncomplete() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -763,7 +773,7 @@ module ModuleImportNode {
|
|||||||
cached
|
cached
|
||||||
ModuleImportNode moduleImport(string path) {
|
ModuleImportNode moduleImport(string path) {
|
||||||
// NB. internal modules may be imported with a "node:" prefix
|
// 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
|
* `require("lodash")` in a context where a package.json file includes
|
||||||
* `"lodash"` as a dependency.
|
* `"lodash"` as a dependency.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
ModuleImportNode dependencyModuleImport(Dependency dep) {
|
ModuleImportNode dependencyModuleImport(Dependency dep) {
|
||||||
result = dep.getAUse("import").(Import).getImportedModuleNode()
|
result = dep.getAUse("import").(Import).getImportedModuleNode()
|
||||||
}
|
}
|
||||||
@@ -861,6 +872,7 @@ module MemberKind {
|
|||||||
*
|
*
|
||||||
* Additional patterns can be recognized as class nodes, by extending `DataFlow::ClassNode::Range`.
|
* Additional patterns can be recognized as class nodes, by extending `DataFlow::ClassNode::Range`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
class ClassNode extends DataFlow::ValueNode, DataFlow::SourceNode {
|
class ClassNode extends DataFlow::ValueNode, DataFlow::SourceNode {
|
||||||
override AST::ValueNode astNode;
|
override AST::ValueNode astNode;
|
||||||
AbstractCallable function;
|
AbstractCallable function;
|
||||||
@@ -1329,6 +1341,7 @@ class ClassNode extends DataFlow::ValueNode, DataFlow::SourceNode {
|
|||||||
/**
|
/**
|
||||||
* Helper predicate to get a prototype reference in a file.
|
* Helper predicate to get a prototype reference in a file.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private DataFlow::PropRef getAPrototypeReferenceInFile(string name, File f) {
|
private DataFlow::PropRef getAPrototypeReferenceInFile(string name, File f) {
|
||||||
result.getBase() = AccessPath::getAReferenceOrAssignmentTo(name) and
|
result.getBase() = AccessPath::getAReferenceOrAssignmentTo(name) and
|
||||||
result.getPropertyName() = "prototype" and
|
result.getPropertyName() = "prototype" and
|
||||||
@@ -1338,6 +1351,7 @@ private DataFlow::PropRef getAPrototypeReferenceInFile(string name, File f) {
|
|||||||
/**
|
/**
|
||||||
* Helper predicate to get an instantiation in a file.
|
* Helper predicate to get an instantiation in a file.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private DataFlow::NewNode getAnInstantiationInFile(string name, File f) {
|
private DataFlow::NewNode getAnInstantiationInFile(string name, File f) {
|
||||||
result = AccessPath::getAReferenceTo(name).(DataFlow::LocalSourceNode).getAnInstantiation() and
|
result = AccessPath::getAReferenceTo(name).(DataFlow::LocalSourceNode).getAnInstantiation() and
|
||||||
result.getFile() = f
|
result.getFile() = f
|
||||||
@@ -1346,6 +1360,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.
|
* Gets a reference to the function `func`, where there exists a read/write of the "prototype" property on that reference.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private DataFlow::SourceNode getAFunctionValueWithPrototype(AbstractValue func) {
|
private DataFlow::SourceNode getAFunctionValueWithPrototype(AbstractValue func) {
|
||||||
exists(result.getAPropertyReference("prototype")) and
|
exists(result.getAPropertyReference("prototype")) and
|
||||||
@@ -1353,6 +1368,7 @@ private DataFlow::SourceNode getAFunctionValueWithPrototype(AbstractValue func)
|
|||||||
func instanceof AbstractCallable // the join-order goes bad if `func` has type `AbstractFunction`.
|
func instanceof AbstractCallable // the join-order goes bad if `func` has type `AbstractFunction`.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
module ClassNode {
|
module ClassNode {
|
||||||
/**
|
/**
|
||||||
* A dataflow node that should be considered a class node.
|
* A dataflow node that should be considered a class node.
|
||||||
@@ -1435,6 +1451,7 @@ module ClassNode {
|
|||||||
* _.partial(fn, x, y, z)
|
* _.partial(fn, x, y, z)
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
class PartialInvokeNode extends DataFlow::Node instanceof PartialInvokeNode::Range {
|
class PartialInvokeNode extends DataFlow::Node instanceof PartialInvokeNode::Range {
|
||||||
/** Gets a node holding a callback invoked by this partial invocation node. */
|
/** Gets a node holding a callback invoked by this partial invocation node. */
|
||||||
DataFlow::Node getACallbackNode() {
|
DataFlow::Node getACallbackNode() {
|
||||||
@@ -1470,6 +1487,7 @@ class PartialInvokeNode extends DataFlow::Node instanceof PartialInvokeNode::Ran
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
module PartialInvokeNode {
|
module PartialInvokeNode {
|
||||||
/**
|
/**
|
||||||
* A data flow node that performs a partial function application.
|
* A data flow node that performs a partial function application.
|
||||||
@@ -1717,6 +1735,7 @@ class RegExpCreationNode extends DataFlow::SourceNode {
|
|||||||
predicate maybeGlobal() { RegExp::maybeGlobal(this.tryGetFlags()) }
|
predicate maybeGlobal() { RegExp::maybeGlobal(this.tryGetFlags()) }
|
||||||
|
|
||||||
/** Gets a data flow node referring to this regular expression. */
|
/** Gets a data flow node referring to this regular expression. */
|
||||||
|
overlay[global]
|
||||||
private DataFlow::SourceNode getAReference(DataFlow::TypeTracker t) {
|
private DataFlow::SourceNode getAReference(DataFlow::TypeTracker t) {
|
||||||
t.start() and
|
t.start() and
|
||||||
result = this
|
result = this
|
||||||
@@ -1725,6 +1744,7 @@ class RegExpCreationNode extends DataFlow::SourceNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a data flow node referring to this regular expression. */
|
/** Gets a data flow node referring to this regular expression. */
|
||||||
|
overlay[global]
|
||||||
cached
|
cached
|
||||||
DataFlow::SourceNode getAReference() {
|
DataFlow::SourceNode getAReference() {
|
||||||
Stages::FlowSteps::ref() and
|
Stages::FlowSteps::ref() and
|
||||||
@@ -1736,6 +1756,7 @@ class RegExpCreationNode extends DataFlow::SourceNode {
|
|||||||
* A guard node for a variable in a negative condition, such as `x` in `if(!x)`.
|
* 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.
|
* Can be added to a `isBarrier` in a data-flow configuration to block flow through such checks.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
class VarAccessBarrier extends DataFlow::Node {
|
class VarAccessBarrier extends DataFlow::Node {
|
||||||
VarAccessBarrier() {
|
VarAccessBarrier() {
|
||||||
exists(ConditionGuardNode guard, SsaRefinementNode refinement |
|
exists(ConditionGuardNode guard, SsaRefinementNode refinement |
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
* so the refinement can evaluate to both `true` and `false` for the same
|
* so the refinement can evaluate to both `true` and `false` for the same
|
||||||
* candidate value.
|
* candidate value.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import AbstractValues
|
private import AbstractValues
|
||||||
@@ -45,6 +47,7 @@ abstract class RefinementCandidate extends Expr {
|
|||||||
/**
|
/**
|
||||||
* Gets a refinement value inferred for this expression in context `ctxt`.
|
* Gets a refinement value inferred for this expression in context `ctxt`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
abstract RefinementValue eval(RefinementContext ctxt);
|
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`.
|
* Gets a refinement value inferred for this expression in context `ctxt`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
RefinementValue eval(RefinementContext ctxt) { result = super.eval(ctxt) }
|
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 {
|
abstract private class LiteralRefinement extends RefinementCandidate, Literal {
|
||||||
override SsaSourceVariable getARefinedVar() { none() }
|
override SsaSourceVariable getARefinedVar() { none() }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override RefinementValue eval(RefinementContext ctxt) {
|
override RefinementValue eval(RefinementContext ctxt) {
|
||||||
ctxt.appliesTo(this) and result = this.eval()
|
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.
|
* Gets the refinement value that represents this literal.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
RefinementValue eval() { result = TAny() }
|
RefinementValue eval() { result = TAny() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A `null` literal, viewed as a refinement expression. */
|
/** A `null` literal, viewed as a refinement expression. */
|
||||||
private class NullLiteralRefinement extends LiteralRefinement, NullLiteral {
|
private class NullLiteralRefinement extends LiteralRefinement, NullLiteral {
|
||||||
|
overlay[global]
|
||||||
override RefinementValue eval() { result = TValueWithType(TTNull()) }
|
override RefinementValue eval() { result = TValueWithType(TTNull()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A Boolean literal, viewed as a refinement expression. */
|
/** A Boolean literal, viewed as a refinement expression. */
|
||||||
private class BoolRefinement extends LiteralRefinement, BooleanLiteral {
|
private class BoolRefinement extends LiteralRefinement, BooleanLiteral {
|
||||||
|
overlay[global]
|
||||||
override RefinementValue eval() {
|
override RefinementValue eval() {
|
||||||
exists(boolean b | b.toString() = this.getValue() | result = TBoolConstant(b))
|
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. */
|
/** A constant string, viewed as a refinement expression. */
|
||||||
private class StringRefinement extends LiteralRefinement, ConstantString {
|
private class StringRefinement extends LiteralRefinement, ConstantString {
|
||||||
|
overlay[global]
|
||||||
override RefinementValue eval() { result = TStringConstant(this.getStringValue()) }
|
override RefinementValue eval() { result = TStringConstant(this.getStringValue()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A numeric literal, viewed as a refinement expression. */
|
/** A numeric literal, viewed as a refinement expression. */
|
||||||
abstract private class NumberRefinement extends LiteralRefinement, NumberLiteral {
|
abstract private class NumberRefinement extends LiteralRefinement, NumberLiteral {
|
||||||
|
overlay[global]
|
||||||
override RefinementValue eval() { result = TValueWithType(TTNumber()) }
|
override RefinementValue eval() { result = TValueWithType(TTNumber()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,6 +122,7 @@ abstract private class NumberRefinement extends LiteralRefinement, NumberLiteral
|
|||||||
private class IntRefinement extends NumberRefinement, NumberLiteral {
|
private class IntRefinement extends NumberRefinement, NumberLiteral {
|
||||||
IntRefinement() { this.getValue().toInt() = 0 }
|
IntRefinement() { this.getValue().toInt() = 0 }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override RefinementValue eval() { result = TIntConstant(this.getValue().toInt()) }
|
override RefinementValue eval() { result = TIntConstant(this.getValue().toInt()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,6 +134,7 @@ private class UndefinedInRefinement extends RefinementCandidate,
|
|||||||
{
|
{
|
||||||
override SsaSourceVariable getARefinedVar() { none() }
|
override SsaSourceVariable getARefinedVar() { none() }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override RefinementValue eval(RefinementContext ctxt) {
|
override RefinementValue eval(RefinementContext ctxt) {
|
||||||
ctxt.appliesTo(this) and
|
ctxt.appliesTo(this) and
|
||||||
result = TValueWithType(TTUndefined())
|
result = TValueWithType(TTUndefined())
|
||||||
@@ -135,6 +147,7 @@ private class VariableRefinement extends RefinementCandidate, VarUse {
|
|||||||
|
|
||||||
override SsaSourceVariable getARefinedVar() { result = this.getVariable() }
|
override SsaSourceVariable getARefinedVar() { result = this.getVariable() }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override RefinementValue eval(RefinementContext ctxt) {
|
override RefinementValue eval(RefinementContext ctxt) {
|
||||||
ctxt.appliesTo(this) and
|
ctxt.appliesTo(this) and
|
||||||
result = ctxt.(VarRefinementContext).getAValue()
|
result = ctxt.(VarRefinementContext).getAValue()
|
||||||
@@ -149,6 +162,7 @@ private class ParRefinement extends RefinementCandidate, ParExpr {
|
|||||||
result = this.getExpression().(RefinementCandidate).getARefinedVar()
|
result = this.getExpression().(RefinementCandidate).getARefinedVar()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override RefinementValue eval(RefinementContext ctxt) {
|
override RefinementValue eval(RefinementContext ctxt) {
|
||||||
result = this.getExpression().(RefinementCandidate).eval(ctxt)
|
result = this.getExpression().(RefinementCandidate).eval(ctxt)
|
||||||
}
|
}
|
||||||
@@ -162,6 +176,7 @@ private class TypeofRefinement extends RefinementCandidate, TypeofExpr {
|
|||||||
result = this.getOperand().(RefinementCandidate).getARefinedVar()
|
result = this.getOperand().(RefinementCandidate).getARefinedVar()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override RefinementValue eval(RefinementContext ctxt) {
|
override RefinementValue eval(RefinementContext ctxt) {
|
||||||
exists(RefinementValue opVal |
|
exists(RefinementValue opVal |
|
||||||
opVal = this.getOperand().(RefinementCandidate).eval(ctxt) and
|
opVal = this.getOperand().(RefinementCandidate).eval(ctxt) and
|
||||||
@@ -182,6 +197,7 @@ private class EqRefinement extends RefinementCandidate, EqualityTest {
|
|||||||
result = this.getRightOperand().(RefinementCandidate).getARefinedVar()
|
result = this.getRightOperand().(RefinementCandidate).getARefinedVar()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override RefinementValue eval(RefinementContext ctxt) {
|
override RefinementValue eval(RefinementContext ctxt) {
|
||||||
exists(RefinementCandidate l, RefinementValue lv, RefinementCandidate r, RefinementValue rv |
|
exists(RefinementCandidate l, RefinementValue lv, RefinementCandidate r, RefinementValue rv |
|
||||||
l = this.getLeftOperand() and
|
l = this.getLeftOperand() and
|
||||||
@@ -220,6 +236,7 @@ private class IndexRefinement extends RefinementCandidate, IndexExpr {
|
|||||||
result = this.getIndex().(RefinementCandidate).getARefinedVar()
|
result = this.getIndex().(RefinementCandidate).getARefinedVar()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override RefinementValue eval(RefinementContext ctxt) {
|
override RefinementValue eval(RefinementContext ctxt) {
|
||||||
exists(
|
exists(
|
||||||
RefinementCandidate base, RefinementValue baseVal, RefinementCandidate index,
|
RefinementCandidate base, RefinementValue baseVal, RefinementCandidate index,
|
||||||
@@ -242,6 +259,7 @@ private class IndexRefinement extends RefinementCandidate, IndexExpr {
|
|||||||
* if any.
|
* if any.
|
||||||
*/
|
*/
|
||||||
bindingset[s, i]
|
bindingset[s, i]
|
||||||
|
overlay[global]
|
||||||
private RefinementValue evalIndex(StringConstant s, IntConstant i) {
|
private RefinementValue evalIndex(StringConstant s, IntConstant i) {
|
||||||
result = TStringConstant(s.getValue().charAt(i.getValue()))
|
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.
|
* A context in which a refinement expression is analyzed.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
newtype TRefinementContext =
|
newtype TRefinementContext =
|
||||||
/**
|
/**
|
||||||
* A refinement context associated with refinement `ref`, specifying that variable `var`
|
* 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.
|
* A context in which a refinement expression is analyzed.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
class RefinementContext extends TRefinementContext {
|
class RefinementContext extends TRefinementContext {
|
||||||
/**
|
/**
|
||||||
* Holds if refinement expression `cand` might be analyzed in this context.
|
* 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
|
* A refinement context specifying that some variable is assumed to have one particular
|
||||||
* abstract value.
|
* abstract value.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
class VarRefinementContext extends RefinementContext, TVarRefinementContext {
|
class VarRefinementContext extends RefinementContext, TVarRefinementContext {
|
||||||
override predicate appliesTo(RefinementCandidate cand) {
|
override predicate appliesTo(RefinementCandidate cand) {
|
||||||
exists(AnalyzedRefinement ref, SsaSourceVariable var |
|
exists(AnalyzedRefinement ref, SsaSourceVariable var |
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
* Note that unlike `TypeTracking.qll`, this library only performs
|
* Note that unlike `TypeTracking.qll`, this library only performs
|
||||||
* local tracking within a function.
|
* local tracking within a function.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.dataflow.TypeTracking
|
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.
|
* See `TypeTracker` for more details about how to use this.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
DataFlow::SourceNode track(TypeTracker t2, TypeTracker t) { t = t2.step(this, result) }
|
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.
|
* See `TypeBackTracker` for more details about how to use this.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
DataFlow::SourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) {
|
DataFlow::SourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) {
|
||||||
t2 = t.step(result, this)
|
t2 = t.step(result, this)
|
||||||
|
|||||||
@@ -92,10 +92,15 @@ class AnalyzedNode extends DataFlow::Node {
|
|||||||
PrimitiveType getAPrimitiveType() { result = this.getAValue().toPrimitive().getType() }
|
PrimitiveType getAPrimitiveType() { result = this.getAValue().toPrimitive().getType() }
|
||||||
|
|
||||||
/** Gets a Boolean value that this node evaluates to. */
|
/** Gets a Boolean value that this node evaluates to. */
|
||||||
|
bindingset[this]
|
||||||
|
overlay[caller?]
|
||||||
|
pragma[inline_late]
|
||||||
boolean getABooleanValue() { result = this.getAValue().getBooleanValue() }
|
boolean getABooleanValue() { result = this.getAValue().getBooleanValue() }
|
||||||
|
|
||||||
/** Gets the unique Boolean value that this node evaluates to, if any. */
|
/** Gets the unique Boolean value that this node evaluates to, if any. */
|
||||||
boolean getTheBooleanValue() { forex(boolean bv | bv = this.getABooleanValue() | result = bv) }
|
overlay[caller?]
|
||||||
|
pragma[inline]
|
||||||
|
boolean getTheBooleanValue() { result = unique( | | this.getABooleanValue()) }
|
||||||
|
|
||||||
/** Gets the unique type inferred for this node, if any. */
|
/** Gets the unique type inferred for this node, if any. */
|
||||||
InferredType getTheType() { result = unique(InferredType t | t = this.getAType()) }
|
InferredType getTheType() { result = unique(InferredType t | t = this.getAType()) }
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
*
|
*
|
||||||
* Provides a representation for abstract values.
|
* Provides a representation for abstract values.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
import semmle.javascript.dataflow.AbstractValues
|
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
|
* to the same value have the same access paths, so access paths are neither sound nor
|
||||||
* complete as an approximation of expression semantics.
|
* complete as an approximation of expression semantics.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import semmle.javascript.internal.CachedStages
|
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`.
|
* Gets a data-flow node synthesized using `AdditionalFlowInternal#needsSynthesizedNode`.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
DataFlow::Node getSynthesizedNode(AstNode node, string tag) {
|
DataFlow::Node getSynthesizedNode(AstNode node, string tag) {
|
||||||
result = TGenericSynthesizedNode(node, 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.
|
* An extension to `AdditionalFlowStep` with additional internal-only predicates.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
class AdditionalFlowInternal extends DataFlow::AdditionalFlowStep {
|
class AdditionalFlowInternal extends DataFlow::AdditionalFlowStep {
|
||||||
/**
|
/**
|
||||||
* Holds if a data-flow node should be synthesized for the pair `(node, tag)`.
|
* 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`.
|
* Holds if `node` should only permit flow of values stored in `contents`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate expectsContent(DataFlow::Node node, DataFlow::ContentSet contents) { none() }
|
predicate expectsContent(DataFlow::Node node, DataFlow::ContentSet contents) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `node` should not permit flow of values stored in `contents`.
|
* Holds if `node` should not permit flow of values stored in `contents`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate clearsContent(DataFlow::Node node, DataFlow::ContentSet contents) { none() }
|
predicate clearsContent(DataFlow::Node node, DataFlow::ContentSet contents) { none() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -358,25 +358,18 @@ module MakeStateBarrierGuard<
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a logical `and` expression, or parenthesized expression, that contains `guard`.
|
* Gets any of the ancestors of `guard` that preserves the value of `possibleOutcome`. Includes the guard itself.
|
||||||
*/
|
*/
|
||||||
private Expr getALogicalAndParent(BarrierGuard guard) {
|
private Expr getALogicalOperatorParent(BarrierGuard guard, boolean possibleOutcome) {
|
||||||
barrierGuardIsRelevant(guard) and result = guard.asExpr()
|
barrierGuardIsRelevant(guard) and result = guard.asExpr() and possibleOutcome = [true, false]
|
||||||
or
|
or
|
||||||
result.(LogAndExpr).getAnOperand() = getALogicalAndParent(guard)
|
result.(LogOrExpr).getAnOperand() = getALogicalOperatorParent(guard, possibleOutcome) and
|
||||||
|
possibleOutcome = false
|
||||||
or
|
or
|
||||||
result.getUnderlyingValue() = getALogicalAndParent(guard)
|
result.(LogAndExpr).getAnOperand() = getALogicalOperatorParent(guard, possibleOutcome) and
|
||||||
}
|
possibleOutcome = true
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a logical `or` expression, or parenthesized expression, that contains `guard`.
|
|
||||||
*/
|
|
||||||
private Expr getALogicalOrParent(BarrierGuard guard) {
|
|
||||||
barrierGuardIsRelevant(guard) and result = guard.asExpr()
|
|
||||||
or
|
or
|
||||||
result.(LogOrExpr).getAnOperand() = getALogicalOrParent(guard)
|
result.getUnderlyingValue() = getALogicalOperatorParent(guard, possibleOutcome)
|
||||||
or
|
|
||||||
result.getUnderlyingValue() = getALogicalOrParent(guard)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final private class FinalFunction = Function;
|
final private class FinalFunction = Function;
|
||||||
@@ -394,15 +387,7 @@ module MakeStateBarrierGuard<
|
|||||||
exists(BarrierGuard guard |
|
exists(BarrierGuard guard |
|
||||||
barrierGuardIsRelevant(guard) and
|
barrierGuardIsRelevant(guard) and
|
||||||
exists(Expr e |
|
exists(Expr e |
|
||||||
exists(Expr returnExpr |
|
exists(Expr returnExpr | returnExpr = getALogicalOperatorParent(guard, guardOutcome) |
|
||||||
returnExpr = guard.asExpr()
|
|
||||||
or
|
|
||||||
// ad hoc support for conjunctions:
|
|
||||||
getALogicalAndParent(guard) = returnExpr and guardOutcome = true
|
|
||||||
or
|
|
||||||
// ad hoc support for disjunctions:
|
|
||||||
getALogicalOrParent(guard) = returnExpr and guardOutcome = false
|
|
||||||
|
|
|
||||||
exists(SsaExplicitDefinition ssa |
|
exists(SsaExplicitDefinition ssa |
|
||||||
ssa.getDef().getSource() = returnExpr and
|
ssa.getDef().getSource() = returnExpr and
|
||||||
ssa.getVariable().getAUse() = this.getAReturnedExpr()
|
ssa.getVariable().getAUse() = this.getAReturnedExpr()
|
||||||
|
|||||||
@@ -97,9 +97,14 @@ module CallGraph {
|
|||||||
not exists(read.getPropertyName()) and
|
not exists(read.getPropertyName()) and
|
||||||
result = read and
|
result = read and
|
||||||
// there exists only local reads of the object, nothing else.
|
// there exists only local reads of the object, nothing else.
|
||||||
forex(DataFlow::Node ref | ref = obj.getALocalUse() and exists(ref.asExpr()) |
|
objectOnlyUsedForPropRead(obj)
|
||||||
ref = [obj, any(DataFlow::PropRead r).getBase()]
|
)
|
||||||
)
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate objectOnlyUsedForPropRead(DataFlow::ObjectLiteralNode obj) {
|
||||||
|
forex(DataFlow::Node ref | ref = obj.getALocalUse() and exists(ref.asExpr()) |
|
||||||
|
ref = [obj, any(DataFlow::PropRead r).getBase()]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.frameworks.data.internal.ApiGraphModels as ApiGraphModels
|
private import semmle.javascript.frameworks.data.internal.ApiGraphModels as ApiGraphModels
|
||||||
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
|
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
|
||||||
@@ -194,6 +197,7 @@ module Public {
|
|||||||
*/
|
*/
|
||||||
class ContentSet extends TContentSet {
|
class ContentSet extends TContentSet {
|
||||||
/** Gets a content that may be stored into when storing into this set. */
|
/** Gets a content that may be stored into when storing into this set. */
|
||||||
|
overlay[caller?]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getAStoreContent() {
|
Content getAStoreContent() {
|
||||||
result = this.asSingleton()
|
result = this.asSingleton()
|
||||||
@@ -333,12 +337,14 @@ module Public {
|
|||||||
/**
|
/**
|
||||||
* A content set containing only the given content.
|
* A content set containing only the given content.
|
||||||
*/
|
*/
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
ContentSet singleton(Content content) { result.asSingleton() = content }
|
ContentSet singleton(Content content) { result.asSingleton() = content }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A content set corresponding to the given property name.
|
* A content set corresponding to the given property name.
|
||||||
*/
|
*/
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
ContentSet property(PropertyName name) { result.asSingleton().asPropertyName() = name }
|
ContentSet property(PropertyName name) { result.asSingleton().asPropertyName() = name }
|
||||||
|
|
||||||
@@ -399,6 +405,7 @@ module Public {
|
|||||||
* If `bound` is too large, it is truncated to the greatest lower bound we can represent.
|
* If `bound` is too large, it is truncated to the greatest lower bound we can represent.
|
||||||
*/
|
*/
|
||||||
bindingset[bound]
|
bindingset[bound]
|
||||||
|
overlay[caller]
|
||||||
ContentSet arrayElementLowerBoundFromInt(int bound) {
|
ContentSet arrayElementLowerBoundFromInt(int bound) {
|
||||||
result = arrayElementLowerBound(bound.minimum(getMaxPreciseArrayIndex() + 1))
|
result = arrayElementLowerBound(bound.minimum(getMaxPreciseArrayIndex() + 1))
|
||||||
}
|
}
|
||||||
@@ -409,6 +416,7 @@ module Public {
|
|||||||
* If `n` is too large, it is truncated to the greatest lower bound we can represent.
|
* If `n` is too large, it is truncated to the greatest lower bound we can represent.
|
||||||
*/
|
*/
|
||||||
bindingset[n]
|
bindingset[n]
|
||||||
|
overlay[caller]
|
||||||
ContentSet arrayElementFromInt(int n) {
|
ContentSet arrayElementFromInt(int n) {
|
||||||
result = arrayElementKnown(n)
|
result = arrayElementKnown(n)
|
||||||
or
|
or
|
||||||
@@ -448,6 +456,7 @@ module Public {
|
|||||||
* If `key` is not one of the keys we track precisely, this is mapped to the unknown key instead.
|
* If `key` is not one of the keys we track precisely, this is mapped to the unknown key instead.
|
||||||
*/
|
*/
|
||||||
bindingset[key]
|
bindingset[key]
|
||||||
|
overlay[caller]
|
||||||
ContentSet mapValueFromKey(string key) {
|
ContentSet mapValueFromKey(string key) {
|
||||||
result = mapValueWithKnownKey(key)
|
result = mapValueWithKnownKey(key)
|
||||||
or
|
or
|
||||||
@@ -510,6 +519,7 @@ module Public {
|
|||||||
* are mapped to their corresponding content sets (which are no longer seen as property names).
|
* are mapped to their corresponding content sets (which are no longer seen as property names).
|
||||||
*/
|
*/
|
||||||
bindingset[propertyName]
|
bindingset[propertyName]
|
||||||
|
overlay[caller]
|
||||||
ContentSet fromLegacyProperty(string propertyName) {
|
ContentSet fromLegacyProperty(string propertyName) {
|
||||||
result = fromLegacyPseudoProperty(propertyName)
|
result = fromLegacyPseudoProperty(propertyName)
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
*
|
*
|
||||||
* Contains the raw data type underlying `DataFlow::Node`.
|
* Contains the raw data type underlying `DataFlow::Node`.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import codeql.util.Boolean
|
private import codeql.util.Boolean
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.dataflow.internal.CallGraphs
|
private import semmle.javascript.dataflow.internal.CallGraphs
|
||||||
private import semmle.javascript.dataflow.internal.DataFlowNode
|
private import semmle.javascript.dataflow.internal.DataFlowNode
|
||||||
@@ -310,6 +313,7 @@ private predicate returnNodeImpl(DataFlow::Node node, ReturnKind kind) {
|
|||||||
kind = MkExceptionalReturnKind()
|
kind = MkExceptionalReturnKind()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
private DataFlow::Node getAnOutNodeImpl(DataFlowCall call, ReturnKind kind) {
|
private DataFlow::Node getAnOutNodeImpl(DataFlowCall call, ReturnKind kind) {
|
||||||
kind = MkNormalReturnKind() and result = call.asOrdinaryCall()
|
kind = MkNormalReturnKind() and result = call.asOrdinaryCall()
|
||||||
or
|
or
|
||||||
@@ -336,10 +340,12 @@ class ReturnNode extends DataFlow::Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A node that receives an output from a call. */
|
/** A node that receives an output from a call. */
|
||||||
|
overlay[global]
|
||||||
class OutNode extends DataFlow::Node {
|
class OutNode extends DataFlow::Node {
|
||||||
OutNode() { this = getAnOutNodeImpl(_, _) }
|
OutNode() { this = getAnOutNodeImpl(_, _) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { result = getAnOutNodeImpl(call, kind) }
|
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { result = getAnOutNodeImpl(call, kind) }
|
||||||
|
|
||||||
cached
|
cached
|
||||||
@@ -416,9 +422,11 @@ abstract class LibraryCallable extends string {
|
|||||||
LibraryCallable() { any() }
|
LibraryCallable() { any() }
|
||||||
|
|
||||||
/** Gets a call to this library callable. */
|
/** Gets a call to this library callable. */
|
||||||
|
overlay[global]
|
||||||
DataFlow::InvokeNode getACall() { none() }
|
DataFlow::InvokeNode getACall() { none() }
|
||||||
|
|
||||||
/** Same as `getACall()` except this does not depend on the call graph or API graph. */
|
/** Same as `getACall()` except this does not depend on the call graph or API graph. */
|
||||||
|
overlay[global]
|
||||||
DataFlow::InvokeNode getACallSimple() { none() }
|
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()`.
|
* Same as `getACall()` but is evaluated later and may depend negatively on `getACall()`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
DataFlow::InvokeNode getACallStage2() { none() }
|
DataFlow::InvokeNode getACallStage2() { none() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,6 +476,7 @@ predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition
|
|||||||
isParameterNodeImpl(p, c, pos)
|
isParameterNodeImpl(p, c, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
private predicate isArgumentNodeImpl(Node n, DataFlowCall call, ArgumentPosition pos) {
|
private predicate isArgumentNodeImpl(Node n, DataFlowCall call, ArgumentPosition pos) {
|
||||||
n = call.asOrdinaryCall().getArgument(pos.asPositional())
|
n = call.asOrdinaryCall().getArgument(pos.asPositional())
|
||||||
or
|
or
|
||||||
@@ -523,6 +533,7 @@ private predicate isArgumentNodeImpl(Node n, DataFlowCall call, ArgumentPosition
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
predicate isArgumentNode(ArgumentNode n, DataFlowCall call, ArgumentPosition pos) {
|
predicate isArgumentNode(ArgumentNode n, DataFlowCall call, ArgumentPosition pos) {
|
||||||
isArgumentNodeImpl(n, call, pos)
|
isArgumentNodeImpl(n, call, pos)
|
||||||
}
|
}
|
||||||
@@ -545,11 +556,13 @@ DataFlowCallable nodeGetEnclosingCallable(Node node) {
|
|||||||
node instanceof DataFlow::XmlAttributeNode and result.asFileCallable() = node.getFile()
|
node instanceof DataFlow::XmlAttributeNode and result.asFileCallable() = node.getFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
newtype TDataFlowType =
|
newtype TDataFlowType =
|
||||||
TFunctionType(Function f) or
|
TFunctionType(Function f) or
|
||||||
TInstanceType(DataFlow::ClassNode cls) or
|
TInstanceType(DataFlow::ClassNode cls) or
|
||||||
TAnyType()
|
TAnyType()
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
class DataFlowType extends TDataFlowType {
|
class DataFlowType extends TDataFlowType {
|
||||||
string toDebugString() {
|
string toDebugString() {
|
||||||
result =
|
result =
|
||||||
@@ -575,6 +588,7 @@ class DataFlowType extends TDataFlowType {
|
|||||||
/**
|
/**
|
||||||
* Holds if `t1` is strictly stronger than `t2`.
|
* Holds if `t1` is strictly stronger than `t2`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) {
|
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) {
|
||||||
// 't1' is a subclass of 't2'
|
// 't1' is a subclass of 't2'
|
||||||
t1.asInstanceOfClass() = t2.asInstanceOfClass().getADirectSubClass+()
|
t1.asInstanceOfClass() = t2.asInstanceOfClass().getADirectSubClass+()
|
||||||
@@ -584,6 +598,7 @@ predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) {
|
|||||||
t2 = TAnyType()
|
t2 = TAnyType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
private DataFlowType getPreciseType(Node node) {
|
private DataFlowType getPreciseType(Node node) {
|
||||||
exists(Function f |
|
exists(Function f |
|
||||||
(node = TValueNode(f) or node = TFunctionSelfReferenceNode(f)) and
|
(node = TValueNode(f) or node = TFunctionSelfReferenceNode(f)) and
|
||||||
@@ -598,6 +613,7 @@ private DataFlowType getPreciseType(Node node) {
|
|||||||
result = getPreciseType(node.(PostUpdateNode).getPreUpdateNode())
|
result = getPreciseType(node.(PostUpdateNode).getPreUpdateNode())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
DataFlowType getNodeType(Node node) {
|
DataFlowType getNodeType(Node node) {
|
||||||
result = getPreciseType(node)
|
result = getPreciseType(node)
|
||||||
or
|
or
|
||||||
@@ -681,19 +697,23 @@ predicate neverSkipInPathGraph(Node node) {
|
|||||||
node.asExpr() instanceof VarRef
|
node.asExpr() instanceof VarRef
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
string ppReprType(DataFlowType t) { none() }
|
string ppReprType(DataFlowType t) { none() }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private predicate compatibleTypesWithAny(DataFlowType t1, DataFlowType t2) {
|
private predicate compatibleTypesWithAny(DataFlowType t1, DataFlowType t2) {
|
||||||
t1 != TAnyType() and
|
t1 != TAnyType() and
|
||||||
t2 = TAnyType()
|
t2 = TAnyType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate compatibleTypes1(DataFlowType t1, DataFlowType t2) {
|
private predicate compatibleTypes1(DataFlowType t1, DataFlowType t2) {
|
||||||
t1.asInstanceOfClass().getADirectSubClass+() = t2.asInstanceOfClass()
|
t1.asInstanceOfClass().getADirectSubClass+() = t2.asInstanceOfClass()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
|
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
|
||||||
t1 = t2
|
t1 = t2
|
||||||
@@ -742,6 +762,7 @@ class ContentApprox extends TContentApprox {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
ContentApprox getContentApprox(Content c) {
|
ContentApprox getContentApprox(Content c) {
|
||||||
c instanceof MkPropertyContent and result = TApproxPropertyContent()
|
c instanceof MkPropertyContent and result = TApproxPropertyContent()
|
||||||
@@ -767,6 +788,7 @@ ContentApprox getContentApprox(Content c) {
|
|||||||
c instanceof MkCapturedContent and result = TApproxCapturedContent()
|
c instanceof MkCapturedContent and result = TApproxCapturedContent()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
cached
|
cached
|
||||||
private newtype TDataFlowCall =
|
private newtype TDataFlowCall =
|
||||||
MkOrdinaryCall(DataFlow::InvokeNode node) or
|
MkOrdinaryCall(DataFlow::InvokeNode node) or
|
||||||
@@ -791,6 +813,7 @@ private newtype TDataFlowCall =
|
|||||||
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
|
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
class DataFlowCall extends TDataFlowCall {
|
class DataFlowCall extends TDataFlowCall {
|
||||||
DataFlowCallable getEnclosingCallable() { none() } // Overridden in subclass
|
DataFlowCallable getEnclosingCallable() { none() } // Overridden in subclass
|
||||||
|
|
||||||
@@ -816,6 +839,7 @@ class DataFlowCall extends TDataFlowCall {
|
|||||||
Location getLocation() { none() } // Overridden in subclass
|
Location getLocation() { none() } // Overridden in subclass
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
private class OrdinaryCall extends DataFlowCall, MkOrdinaryCall {
|
private class OrdinaryCall extends DataFlowCall, MkOrdinaryCall {
|
||||||
private DataFlow::InvokeNode node;
|
private DataFlow::InvokeNode node;
|
||||||
|
|
||||||
@@ -832,6 +856,7 @@ private class OrdinaryCall extends DataFlowCall, MkOrdinaryCall {
|
|||||||
override Location getLocation() { result = node.getLocation() }
|
override Location getLocation() { result = node.getLocation() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
private class PartialCall extends DataFlowCall, MkPartialCall {
|
private class PartialCall extends DataFlowCall, MkPartialCall {
|
||||||
private DataFlow::PartialInvokeNode node;
|
private DataFlow::PartialInvokeNode node;
|
||||||
private DataFlow::Node callback;
|
private DataFlow::Node callback;
|
||||||
@@ -851,6 +876,7 @@ private class PartialCall extends DataFlowCall, MkPartialCall {
|
|||||||
override Location getLocation() { result = node.getLocation() }
|
override Location getLocation() { result = node.getLocation() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
private class BoundCall extends DataFlowCall, MkBoundCall {
|
private class BoundCall extends DataFlowCall, MkBoundCall {
|
||||||
private DataFlow::InvokeNode node;
|
private DataFlow::InvokeNode node;
|
||||||
private int boundArgs;
|
private int boundArgs;
|
||||||
@@ -868,6 +894,7 @@ private class BoundCall extends DataFlowCall, MkBoundCall {
|
|||||||
override Location getLocation() { result = node.getLocation() }
|
override Location getLocation() { result = node.getLocation() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
private class AccessorCall extends DataFlowCall, MkAccessorCall {
|
private class AccessorCall extends DataFlowCall, MkAccessorCall {
|
||||||
private DataFlow::PropRef ref;
|
private DataFlow::PropRef ref;
|
||||||
|
|
||||||
@@ -882,6 +909,7 @@ private class AccessorCall extends DataFlowCall, MkAccessorCall {
|
|||||||
override Location getLocation() { result = ref.getLocation() }
|
override Location getLocation() { result = ref.getLocation() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
class SummaryCall extends DataFlowCall, MkSummaryCall {
|
class SummaryCall extends DataFlowCall, MkSummaryCall {
|
||||||
private FlowSummaryImpl::Public::SummarizedCallable enclosingCallable;
|
private FlowSummaryImpl::Public::SummarizedCallable enclosingCallable;
|
||||||
private FlowSummaryImpl::Private::SummaryNode receiver;
|
private FlowSummaryImpl::Private::SummaryNode receiver;
|
||||||
@@ -908,6 +936,7 @@ class SummaryCall extends DataFlowCall, MkSummaryCall {
|
|||||||
* This is to help ensure captured variables can flow into the lambda in cases where
|
* This is to help ensure captured variables can flow into the lambda in cases where
|
||||||
* we can't find its call sites.
|
* we can't find its call sites.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private class ImpliedLambdaCall extends DataFlowCall, MkImpliedLambdaCall {
|
private class ImpliedLambdaCall extends DataFlowCall, MkImpliedLambdaCall {
|
||||||
private Function function;
|
private Function function;
|
||||||
|
|
||||||
@@ -981,6 +1010,7 @@ class DataFlowExpr = Expr;
|
|||||||
|
|
||||||
Node exprNode(DataFlowExpr expr) { result = DataFlow::exprNode(expr) }
|
Node exprNode(DataFlowExpr expr) { result = DataFlow::exprNode(expr) }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
|
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
|
||||||
ppos = apos
|
ppos = apos
|
||||||
@@ -993,6 +1023,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.
|
// are only using these in cases where either the call or callee is generated by a flow summary.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
DataFlowCallable viableCallable(DataFlowCall node) {
|
DataFlowCallable viableCallable(DataFlowCall node) {
|
||||||
// Note: we never include call edges externs here, as it negatively affects the field-flow branch limit,
|
// Note: we never include call edges externs here, as it negatively affects the field-flow branch limit,
|
||||||
@@ -1021,6 +1052,7 @@ DataFlowCallable viableCallable(DataFlowCall node) {
|
|||||||
result.asSourceCallableNotExterns() = node.asImpliedLambdaCall()
|
result.asSourceCallableNotExterns() = node.asImpliedLambdaCall()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
private DataFlowCall getACallOnThis(DataFlow::ClassNode cls) {
|
private DataFlowCall getACallOnThis(DataFlow::ClassNode cls) {
|
||||||
result.asOrdinaryCall() = cls.getAReceiverNode().getAPropertyRead().getACall()
|
result.asOrdinaryCall() = cls.getAReceiverNode().getAPropertyRead().getACall()
|
||||||
or
|
or
|
||||||
@@ -1029,6 +1061,7 @@ private DataFlowCall getACallOnThis(DataFlow::ClassNode cls) {
|
|||||||
result.asPartialCall().getACallbackNode() = cls.getAReceiverNode().getAPropertyRead()
|
result.asPartialCall().getACallbackNode() = cls.getAReceiverNode().getAPropertyRead()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
private predicate downwardCall(DataFlowCall call) {
|
private predicate downwardCall(DataFlowCall call) {
|
||||||
exists(DataFlow::ClassNode cls |
|
exists(DataFlow::ClassNode cls |
|
||||||
call = getACallOnThis(cls) and
|
call = getACallOnThis(cls) and
|
||||||
@@ -1041,9 +1074,11 @@ private predicate downwardCall(DataFlowCall call) {
|
|||||||
* Holds if the set of viable implementations that can be called by `call`
|
* Holds if the set of viable implementations that can be called by `call`
|
||||||
* might be improved by knowing the call context.
|
* might be improved by knowing the call context.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate mayBenefitFromCallContext(DataFlowCall call) { downwardCall(call) }
|
predicate mayBenefitFromCallContext(DataFlowCall call) { downwardCall(call) }
|
||||||
|
|
||||||
/** Gets the type of the receiver of `call`. */
|
/** Gets the type of the receiver of `call`. */
|
||||||
|
overlay[global]
|
||||||
private DataFlowType getThisArgumentType(DataFlowCall call) {
|
private DataFlowType getThisArgumentType(DataFlowCall call) {
|
||||||
exists(DataFlow::Node node |
|
exists(DataFlow::Node node |
|
||||||
isArgumentNodeImpl(node, call, MkThisParameter()) and
|
isArgumentNodeImpl(node, call, MkThisParameter()) and
|
||||||
@@ -1052,6 +1087,7 @@ private DataFlowType getThisArgumentType(DataFlowCall call) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the type of the 'this' parameter of `call`. */
|
/** Gets the type of the 'this' parameter of `call`. */
|
||||||
|
overlay[global]
|
||||||
private DataFlowType getThisParameterType(DataFlowCallable callable) {
|
private DataFlowType getThisParameterType(DataFlowCallable callable) {
|
||||||
exists(DataFlow::Node node |
|
exists(DataFlow::Node node |
|
||||||
isParameterNodeImpl(node, callable, MkThisParameter()) and
|
isParameterNodeImpl(node, callable, MkThisParameter()) and
|
||||||
@@ -1063,6 +1099,7 @@ private DataFlowType getThisParameterType(DataFlowCallable callable) {
|
|||||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
* 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.
|
* restricted to those `call`s for which a context might make a difference.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
||||||
mayBenefitFromCallContext(call) and
|
mayBenefitFromCallContext(call) and
|
||||||
result = viableCallable(call) and
|
result = viableCallable(call) and
|
||||||
@@ -1071,16 +1108,19 @@ DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bindingset[node, fun]
|
bindingset[node, fun]
|
||||||
|
overlay[caller]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate sameContainerAsEnclosingContainer(Node node, Function fun) {
|
private predicate sameContainerAsEnclosingContainer(Node node, Function fun) {
|
||||||
node.getContainer() = fun.getEnclosingContainer()
|
node.getContainer() = fun.getEnclosingContainer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
abstract private class BarrierGuardAdapter extends DataFlow::Node {
|
abstract private class BarrierGuardAdapter extends DataFlow::Node {
|
||||||
// Note: avoid depending on DataFlow::FlowLabel here as it will cause these barriers to be re-evaluated
|
// Note: avoid depending on DataFlow::FlowLabel here as it will cause these barriers to be re-evaluated
|
||||||
predicate blocksExpr(boolean outcome, Expr e) { none() }
|
predicate blocksExpr(boolean outcome, Expr e) { none() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
deprecated private class BarrierGuardAdapterSubclass extends BarrierGuardAdapter instanceof DataFlow::AdditionalBarrierGuardNode
|
deprecated private class BarrierGuardAdapterSubclass extends BarrierGuardAdapter instanceof DataFlow::AdditionalBarrierGuardNode
|
||||||
{
|
{
|
||||||
override predicate blocksExpr(boolean outcome, Expr e) { super.blocks(outcome, e) }
|
override predicate blocksExpr(boolean outcome, Expr e) { super.blocks(outcome, e) }
|
||||||
@@ -1092,6 +1132,7 @@ deprecated private class BarrierGuardAdapterSubclass extends BarrierGuardAdapter
|
|||||||
*
|
*
|
||||||
* The standard library contains no subclasses of that class; this is for backwards compatibility only.
|
* The standard library contains no subclasses of that class; this is for backwards compatibility only.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate legacyBarrier(DataFlow::Node node) {
|
private predicate legacyBarrier(DataFlow::Node node) {
|
||||||
node = MakeBarrierGuard<BarrierGuardAdapter>::getABarrierNode()
|
node = MakeBarrierGuard<BarrierGuardAdapter>::getABarrierNode()
|
||||||
@@ -1100,6 +1141,7 @@ private predicate legacyBarrier(DataFlow::Node node) {
|
|||||||
/**
|
/**
|
||||||
* Holds if `node` should be removed from the local data flow graph, for compatibility with legacy code.
|
* Holds if `node` should be removed from the local data flow graph, for compatibility with legacy code.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate isBlockedLegacyNode(Node node) {
|
private predicate isBlockedLegacyNode(Node node) {
|
||||||
// Ignore captured variable nodes for those variables that are handled by the captured-variable library.
|
// Ignore captured variable nodes for those variables that are handled by the captured-variable library.
|
||||||
@@ -1155,6 +1197,7 @@ private predicate imprecisePostUpdateStep(DataFlow::PostUpdateNode postUpdate, D
|
|||||||
* Holds if there is a value-preserving steps `node1` -> `node2` that might
|
* Holds if there is a value-preserving steps `node1` -> `node2` that might
|
||||||
* be cross function boundaries.
|
* be cross function boundaries.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private predicate valuePreservingStep(Node node1, Node node2) {
|
private predicate valuePreservingStep(Node node1, Node node2) {
|
||||||
node1.getASuccessor() = node2 and
|
node1.getASuccessor() = node2 and
|
||||||
not isBlockedLegacyNode(node1) and
|
not isBlockedLegacyNode(node1) and
|
||||||
@@ -1223,10 +1266,12 @@ private predicate useUseFlow(Node node1, Node node2) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
predicate simpleLocalFlowStep(Node node1, Node node2, string model) {
|
predicate simpleLocalFlowStep(Node node1, Node node2, string model) {
|
||||||
simpleLocalFlowStep(node1, node2) and model = ""
|
simpleLocalFlowStep(node1, node2) and model = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
predicate simpleLocalFlowStep(Node node1, Node node2) {
|
predicate simpleLocalFlowStep(Node node1, Node node2) {
|
||||||
valuePreservingStep(node1, node2) and
|
valuePreservingStep(node1, node2) and
|
||||||
nodeGetEnclosingCallable(pragma[only_bind_out](node1)) =
|
nodeGetEnclosingCallable(pragma[only_bind_out](node1)) =
|
||||||
@@ -1314,6 +1359,7 @@ private predicate excludedJumpStep(Node node1, Node node2) {
|
|||||||
* that does not follow a call edge. For example, a step through a global
|
* that does not follow a call edge. For example, a step through a global
|
||||||
* variable.
|
* variable.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate jumpStep(Node node1, Node node2) {
|
predicate jumpStep(Node node1, Node node2) {
|
||||||
valuePreservingStep(node1, node2) and
|
valuePreservingStep(node1, node2) and
|
||||||
node1.getContainer() != node2.getContainer() and
|
node1.getContainer() != node2.getContainer() and
|
||||||
@@ -1330,6 +1376,7 @@ predicate jumpStep(Node node1, Node node2) {
|
|||||||
* `node1` references an object with a content `c.getAReadContent()` whose
|
* `node1` references an object with a content `c.getAReadContent()` whose
|
||||||
* value ends up in `node2`.
|
* value ends up in `node2`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate readStep(Node node1, ContentSet c, Node node2) {
|
predicate readStep(Node node1, ContentSet c, Node node2) {
|
||||||
exists(DataFlow::PropRead read |
|
exists(DataFlow::PropRead read |
|
||||||
node1 = read.getBase() and
|
node1 = read.getBase() and
|
||||||
@@ -1447,6 +1494,7 @@ private predicate stringifiedNode(Node node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the post-update node for which `node` is the corresponding pre-update node. */
|
/** Gets the post-update node for which `node` is the corresponding pre-update node. */
|
||||||
|
pragma[nomagic]
|
||||||
private Node getPostUpdateForStore(Node base) {
|
private Node getPostUpdateForStore(Node base) {
|
||||||
exists(Expr expr |
|
exists(Expr expr |
|
||||||
base = TValueNode(expr) and
|
base = TValueNode(expr) and
|
||||||
@@ -1469,6 +1517,7 @@ private Node getPostUpdateForStore(Node base) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets node to target with a store to the given `base` object.. */
|
/** Gets node to target with a store to the given `base` object.. */
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
private Node getStoreTarget(DataFlow::Node base) {
|
private Node getStoreTarget(DataFlow::Node base) {
|
||||||
result = getPostUpdateForStore(base)
|
result = getPostUpdateForStore(base)
|
||||||
@@ -1487,6 +1536,7 @@ private int firstSpreadArgumentIndex(InvokeExpr expr) {
|
|||||||
* `node2` references an object with a content `c.getAStoreContent()` that
|
* `node2` references an object with a content `c.getAStoreContent()` that
|
||||||
* contains the value of `node1`.
|
* contains the value of `node1`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate storeStep(Node node1, ContentSet c, Node node2) {
|
predicate storeStep(Node node1, ContentSet c, Node node2) {
|
||||||
exists(DataFlow::PropWrite write |
|
exists(DataFlow::PropWrite write |
|
||||||
node1 = write.getRhs() and
|
node1 = write.getRhs() and
|
||||||
@@ -1545,6 +1595,7 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
|
|||||||
* any value stored inside `f` is cleared at the pre-update node associated with `x`
|
* any value stored inside `f` is cleared at the pre-update node associated with `x`
|
||||||
* in `x.f = newValue`.
|
* in `x.f = newValue`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate clearsContent(Node n, ContentSet c) {
|
predicate clearsContent(Node n, ContentSet c) {
|
||||||
FlowSummaryPrivate::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), c)
|
FlowSummaryPrivate::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), c)
|
||||||
or
|
or
|
||||||
@@ -1578,6 +1629,7 @@ predicate clearsContent(Node n, ContentSet c) {
|
|||||||
* Holds if the value that is being tracked is expected to be stored inside content `c`
|
* Holds if the value that is being tracked is expected to be stored inside content `c`
|
||||||
* at node `n`.
|
* at node `n`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate expectsContent(Node n, ContentSet c) {
|
predicate expectsContent(Node n, ContentSet c) {
|
||||||
FlowSummaryPrivate::Steps::summaryExpectsContent(n.(FlowSummaryNode).getSummaryNode(), c)
|
FlowSummaryPrivate::Steps::summaryExpectsContent(n.(FlowSummaryNode).getSummaryNode(), c)
|
||||||
or
|
or
|
||||||
@@ -1602,6 +1654,7 @@ abstract class NodeRegion extends Unit {
|
|||||||
/**
|
/**
|
||||||
* Holds if the node `n` is unreachable when the call context is `call`.
|
* Holds if the node `n` is unreachable when the call context is `call`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate isUnreachableInCall(NodeRegion n, DataFlowCall call) {
|
predicate isUnreachableInCall(NodeRegion n, DataFlowCall call) {
|
||||||
none() // TODO: could be useful, but not currently implemented for JS
|
none() // TODO: could be useful, but not currently implemented for JS
|
||||||
}
|
}
|
||||||
@@ -1635,6 +1688,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. */
|
/** 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) {
|
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
|
||||||
call.isSummaryCall(_, receiver.(FlowSummaryNode).getSummaryNode()) and exists(kind)
|
call.isSummaryCall(_, receiver.(FlowSummaryNode).getSummaryNode()) and exists(kind)
|
||||||
or
|
or
|
||||||
@@ -1646,6 +1700,7 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
|
|||||||
/** Extra data-flow steps needed for lambda flow analysis. */
|
/** Extra data-flow steps needed for lambda flow analysis. */
|
||||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
|
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
class ArgumentNode extends DataFlow::Node {
|
class ArgumentNode extends DataFlow::Node {
|
||||||
ArgumentNode() { isArgumentNodeImpl(this, _, _) }
|
ArgumentNode() { isArgumentNodeImpl(this, _, _) }
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ private predicate legacyPostUpdateStep(DataFlow::Node pred, DataFlow::Node succ)
|
|||||||
* Holds if data can flow in one step from `pred` to `succ`, taking
|
* Holds if data can flow in one step from `pred` to `succ`, taking
|
||||||
* additional steps from the configuration into account.
|
* additional steps from the configuration into account.
|
||||||
*/
|
*/
|
||||||
|
overlay[caller?]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
deprecated predicate localFlowStep(
|
deprecated predicate localFlowStep(
|
||||||
DataFlow::Node pred, DataFlow::Node succ, DataFlow::Configuration configuration,
|
DataFlow::Node pred, DataFlow::Node succ, DataFlow::Configuration configuration,
|
||||||
@@ -523,6 +524,7 @@ private module CachedSteps {
|
|||||||
/**
|
/**
|
||||||
* Holds if there is a step from `pred` to `succ` through a call to an identity function.
|
* Holds if there is a step from `pred` to `succ` through a call to an identity function.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
cached
|
cached
|
||||||
predicate identityFunctionStep(DataFlow::Node pred, DataFlow::CallNode succ) {
|
predicate identityFunctionStep(DataFlow::Node pred, DataFlow::CallNode succ) {
|
||||||
exists(DataFlow::GlobalVarRefNode global |
|
exists(DataFlow::GlobalVarRefNode global |
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Provides JS specific classes and predicates for defining flow summaries.
|
* Provides JS specific classes and predicates for defining flow summaries.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.dataflow.internal.DataFlowPrivate
|
private import semmle.javascript.dataflow.internal.DataFlowPrivate
|
||||||
@@ -140,6 +142,7 @@ string encodeArgumentPosition(ArgumentPosition pos) {
|
|||||||
ReturnKind getStandardReturnValueKind() { result = MkNormalReturnKind() and Stage::ref() }
|
ReturnKind getStandardReturnValueKind() { result = MkNormalReturnKind() and Stage::ref() }
|
||||||
|
|
||||||
private module FlowSummaryStepInput implements Private::StepsInputSig {
|
private module FlowSummaryStepInput implements Private::StepsInputSig {
|
||||||
|
overlay[global]
|
||||||
DataFlowCall getACall(SummarizedCallable sc) {
|
DataFlowCall getACall(SummarizedCallable sc) {
|
||||||
exists(LibraryCallable callable | callable = sc |
|
exists(LibraryCallable callable | callable = sc |
|
||||||
result.asOrdinaryCall() =
|
result.asOrdinaryCall() =
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript as js
|
private import javascript as js
|
||||||
private import semmle.javascript.dataflow.internal.DataFlowNode
|
private import semmle.javascript.dataflow.internal.DataFlowNode
|
||||||
private import semmle.javascript.dataflow.internal.VariableOrThis
|
private import semmle.javascript.dataflow.internal.VariableOrThis
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import DataFlowNode
|
private import DataFlowNode
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
*
|
*
|
||||||
* JavaScript's old SSA library is still responsible for the ordinary SSA flow.
|
* JavaScript's old SSA library is still responsible for the ordinary SSA flow.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript as js
|
private import javascript as js
|
||||||
private import codeql.ssa.Ssa
|
private import codeql.ssa.Ssa
|
||||||
@@ -94,6 +96,7 @@ module SsaDataflowInput implements DataFlowIntegrationInputSig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[caller?]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate guardDirectlyControlsBlock(Guard guard, js::Cfg::BasicBlock bb, GuardValue branch) {
|
predicate guardDirectlyControlsBlock(Guard guard, js::Cfg::BasicBlock bb, GuardValue branch) {
|
||||||
exists(js::ConditionGuardNode g |
|
exists(js::ConditionGuardNode g |
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ private import AngularJS
|
|||||||
/**
|
/**
|
||||||
* Holds if `nd` is a reference to the `angular` variable.
|
* Holds if `nd` is a reference to the `angular` variable.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
DataFlow::SourceNode angular() {
|
DataFlow::SourceNode angular() {
|
||||||
// either as a global
|
// either as a global
|
||||||
result = DataFlow::globalVarRef("angular")
|
result = DataFlow::globalVarRef("angular")
|
||||||
|
|||||||
@@ -172,6 +172,7 @@ module AsyncPackage {
|
|||||||
DataFlow::FunctionNode getFinalCallback() { result = this.getCallback(finalCallbackIndex) }
|
DataFlow::FunctionNode getFinalCallback() { result = this.getCallback(finalCallbackIndex) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[local?]
|
||||||
private class IterationCallFlowSummary extends DataFlow::SummarizedCallable {
|
private class IterationCallFlowSummary extends DataFlow::SummarizedCallable {
|
||||||
private int callbackArgIndex;
|
private int callbackArgIndex;
|
||||||
|
|
||||||
@@ -219,6 +220,7 @@ module AsyncPackage {
|
|||||||
*
|
*
|
||||||
* For example: `data -> result` in `async.sortBy(data, orderingFn, (err, result) => {})`.
|
* For example: `data -> result` in `async.sortBy(data, orderingFn, (err, result) => {})`.
|
||||||
*/
|
*/
|
||||||
|
overlay[local?]
|
||||||
private class IterationPreserveTaintStepFlowSummary extends DataFlow::SummarizedCallable {
|
private class IterationPreserveTaintStepFlowSummary extends DataFlow::SummarizedCallable {
|
||||||
IterationPreserveTaintStepFlowSummary() { this = "async.sortBy" }
|
IterationPreserveTaintStepFlowSummary() { this = "async.sortBy" }
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Models imports through the NPM `lazy-cache` package.
|
* Models imports through the NPM `lazy-cache` package.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
@@ -43,7 +45,7 @@ module LazyCache {
|
|||||||
pragma[noopt]
|
pragma[noopt]
|
||||||
override DataFlow::Node getImportedModuleNode() {
|
override DataFlow::Node getImportedModuleNode() {
|
||||||
this instanceof LazyCacheImport and
|
this instanceof LazyCacheImport and
|
||||||
result = this.flow()
|
result = DataFlow::valueNode(this)
|
||||||
or
|
or
|
||||||
exists(LazyCacheVariable variable, Expr base, PropAccess access, string localName |
|
exists(LazyCacheVariable variable, Expr base, PropAccess access, string localName |
|
||||||
// To avoid recursion, this should not depend on `SourceNode`.
|
// To avoid recursion, this should not depend on `SourceNode`.
|
||||||
@@ -52,12 +54,13 @@ module LazyCache {
|
|||||||
access.getBase() = base and
|
access.getBase() = base and
|
||||||
localName = this.getLocalAlias() and
|
localName = this.getLocalAlias() and
|
||||||
access.getPropertyName() = localName and
|
access.getPropertyName() = localName and
|
||||||
result = access.flow()
|
result = DataFlow::valueNode(access)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A constant path element appearing in a call to a lazy-cache object. */
|
/** A constant path element appearing in a call to a lazy-cache object. */
|
||||||
|
overlay[global]
|
||||||
deprecated private class LazyCachePathExpr extends PathExpr, ConstantString {
|
deprecated private class LazyCachePathExpr extends PathExpr, ConstantString {
|
||||||
LazyCachePathExpr() { this = any(LazyCacheImport rp).getArgument(0) }
|
LazyCachePathExpr() { this = any(LazyCacheImport rp).getArgument(0) }
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ module LodashUnderscore {
|
|||||||
/**
|
/**
|
||||||
* A data flow node that accesses a given member of `lodash` or `underscore`.
|
* A data flow node that accesses a given member of `lodash` or `underscore`.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
abstract class Member extends DataFlow::SourceNode {
|
abstract class Member extends DataFlow::SourceNode {
|
||||||
/** Gets the name of the accessed member. */
|
/** Gets the name of the accessed member. */
|
||||||
abstract string getName();
|
abstract string getName();
|
||||||
@@ -17,6 +18,7 @@ module LodashUnderscore {
|
|||||||
/**
|
/**
|
||||||
* An import of `lodash` or `underscore` accessing a given member of that package.
|
* An import of `lodash` or `underscore` accessing a given member of that package.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
private class DefaultMember extends Member {
|
private class DefaultMember extends Member {
|
||||||
string name;
|
string name;
|
||||||
|
|
||||||
@@ -39,12 +41,14 @@ module LodashUnderscore {
|
|||||||
* In addition to normal imports, this supports per-method imports such as `require("lodash.map")` and `require("lodash/map")`.
|
* In addition to normal imports, this supports per-method imports such as `require("lodash.map")` and `require("lodash/map")`.
|
||||||
* In addition, the global variable `_` is assumed to refer to `lodash` or `underscore`.
|
* In addition, the global variable `_` is assumed to refer to `lodash` or `underscore`.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
DataFlow::SourceNode member(string name) { result.(Member).getName() = name }
|
DataFlow::SourceNode member(string name) { result.(Member).getName() = name }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `name` is the name of a member exported from the `lodash` package
|
* Holds if `name` is the name of a member exported from the `lodash` package
|
||||||
* which has a corresponding `lodash.xxx` NPM package.
|
* which has a corresponding `lodash.xxx` NPM package.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
private predicate isLodashMember(string name) {
|
private predicate isLodashMember(string name) {
|
||||||
// Can be generated using Object.keys(require('lodash'))
|
// Can be generated using Object.keys(require('lodash'))
|
||||||
name =
|
name =
|
||||||
@@ -181,9 +185,11 @@ module LodashUnderscore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
private class LodashEach extends DataFlow::SummarizedCallable {
|
private class LodashEach extends DataFlow::SummarizedCallable {
|
||||||
LodashEach() { this = "_.each-like" }
|
LodashEach() { this = "_.each-like" }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::CallNode getACall() {
|
override DataFlow::CallNode getACall() {
|
||||||
result = member(["each", "eachRight", "forEach", "forEachRight", "every", "some"]).getACall()
|
result = member(["each", "eachRight", "forEach", "forEachRight", "every", "some"]).getACall()
|
||||||
}
|
}
|
||||||
@@ -195,9 +201,11 @@ module LodashUnderscore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
private class LodashMap extends DataFlow::SummarizedCallable {
|
private class LodashMap extends DataFlow::SummarizedCallable {
|
||||||
LodashMap() { this = "_.map" }
|
LodashMap() { this = "_.map" }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::CallNode getACall() { result = member("map").getACall() }
|
override DataFlow::CallNode getACall() { result = member("map").getACall() }
|
||||||
|
|
||||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||||
@@ -212,9 +220,11 @@ module LodashUnderscore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
private class LodashFlatMap extends DataFlow::SummarizedCallable {
|
private class LodashFlatMap extends DataFlow::SummarizedCallable {
|
||||||
LodashFlatMap() { this = "_.flatMap" }
|
LodashFlatMap() { this = "_.flatMap" }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::CallNode getACall() { result = member("flatMap").getACall() }
|
override DataFlow::CallNode getACall() { result = member("flatMap").getACall() }
|
||||||
|
|
||||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||||
@@ -232,9 +242,11 @@ module LodashUnderscore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
private class LodashFlatMapDeep extends DataFlow::SummarizedCallable {
|
private class LodashFlatMapDeep extends DataFlow::SummarizedCallable {
|
||||||
LodashFlatMapDeep() { this = "_.flatMapDeep" }
|
LodashFlatMapDeep() { this = "_.flatMapDeep" }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::CallNode getACall() {
|
override DataFlow::CallNode getACall() {
|
||||||
result = member(["flatMapDeep", "flatMapDepth"]).getACall()
|
result = member(["flatMapDeep", "flatMapDepth"]).getACall()
|
||||||
}
|
}
|
||||||
@@ -254,9 +266,11 @@ module LodashUnderscore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
private class LodashReduce extends DataFlow::SummarizedCallable {
|
private class LodashReduce extends DataFlow::SummarizedCallable {
|
||||||
LodashReduce() { this = "_.reduce-like" }
|
LodashReduce() { this = "_.reduce-like" }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::CallNode getACall() { result = member(["reduce", "reduceRight"]).getACall() }
|
override DataFlow::CallNode getACall() { result = member(["reduce", "reduceRight"]).getACall() }
|
||||||
|
|
||||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||||
@@ -271,9 +285,11 @@ module LodashUnderscore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
private class LoashSortBy extends DataFlow::SummarizedCallable {
|
private class LoashSortBy extends DataFlow::SummarizedCallable {
|
||||||
LoashSortBy() { this = "_.sortBy-like" }
|
LoashSortBy() { this = "_.sortBy-like" }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::CallNode getACall() { result = member(["sortBy", "orderBy"]).getACall() }
|
override DataFlow::CallNode getACall() { result = member(["sortBy", "orderBy"]).getACall() }
|
||||||
|
|
||||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||||
@@ -287,9 +303,11 @@ module LodashUnderscore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
private class LodashMinMaxBy extends DataFlow::SummarizedCallable {
|
private class LodashMinMaxBy extends DataFlow::SummarizedCallable {
|
||||||
LodashMinMaxBy() { this = "_.minBy / _.maxBy" }
|
LodashMinMaxBy() { this = "_.minBy / _.maxBy" }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::CallNode getACall() { result = member(["minBy", "maxBy"]).getACall() }
|
override DataFlow::CallNode getACall() { result = member(["minBy", "maxBy"]).getACall() }
|
||||||
|
|
||||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||||
@@ -299,9 +317,11 @@ module LodashUnderscore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
private class LodashPartition extends DataFlow::SummarizedCallable {
|
private class LodashPartition extends DataFlow::SummarizedCallable {
|
||||||
LodashPartition() { this = "_.partition" }
|
LodashPartition() { this = "_.partition" }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::CallNode getACall() { result = member("partition").getACall() }
|
override DataFlow::CallNode getACall() { result = member("partition").getACall() }
|
||||||
|
|
||||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||||
@@ -311,9 +331,11 @@ module LodashUnderscore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
private class UnderscoreMapObject extends DataFlow::SummarizedCallable {
|
private class UnderscoreMapObject extends DataFlow::SummarizedCallable {
|
||||||
UnderscoreMapObject() { this = "_.mapObject" }
|
UnderscoreMapObject() { this = "_.mapObject" }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::CallNode getACall() { result = member("mapObject").getACall() }
|
override DataFlow::CallNode getACall() { result = member("mapObject").getACall() }
|
||||||
|
|
||||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||||
@@ -330,9 +352,11 @@ module LodashUnderscore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
private class LodashTap extends DataFlow::SummarizedCallable {
|
private class LodashTap extends DataFlow::SummarizedCallable {
|
||||||
LodashTap() { this = "_.tap" }
|
LodashTap() { this = "_.tap" }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::CallNode getACall() { result = member("tap").getACall() }
|
override DataFlow::CallNode getACall() { result = member("tap").getACall() }
|
||||||
|
|
||||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||||
@@ -342,6 +366,7 @@ module LodashUnderscore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[local?]
|
||||||
private class LodashGroupBy extends DataFlow::SummarizedCallable {
|
private class LodashGroupBy extends DataFlow::SummarizedCallable {
|
||||||
LodashGroupBy() { this = "_.groupBy" }
|
LodashGroupBy() { this = "_.groupBy" }
|
||||||
|
|
||||||
|
|||||||
@@ -8,14 +8,17 @@ import semmle.javascript.security.SensitiveActions
|
|||||||
private import semmle.javascript.dataflow.internal.PreCallGraphStep
|
private import semmle.javascript.dataflow.internal.PreCallGraphStep
|
||||||
|
|
||||||
module NodeJSLib {
|
module NodeJSLib {
|
||||||
|
overlay[local]
|
||||||
private GlobalVariable processVariable() { variables(result, "process", any(GlobalScope sc)) }
|
private GlobalVariable processVariable() { variables(result, "process", any(GlobalScope sc)) }
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private GlobalVarAccess processExprInTopLevel(TopLevel tl) {
|
private GlobalVarAccess processExprInTopLevel(TopLevel tl) {
|
||||||
result = processVariable().getAnAccess() and
|
result = processVariable().getAnAccess() and
|
||||||
tl = result.getTopLevel()
|
tl = result.getTopLevel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private GlobalVarAccess processExprInNodeModule() {
|
private GlobalVarAccess processExprInNodeModule() {
|
||||||
result = processExprInTopLevel(any(NodeModule m))
|
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 access to the global `process` variable in a Node.js module, interpreted as
|
||||||
* an import of the `process` module.
|
* an import of the `process` module.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
private class ImplicitProcessImport extends DataFlow::ModuleImportNode::Range {
|
private class ImplicitProcessImport extends DataFlow::ModuleImportNode::Range {
|
||||||
ImplicitProcessImport() { this = DataFlow::exprNode(processExprInNodeModule()) }
|
ImplicitProcessImport() { this = DataFlow::exprNode(processExprInNodeModule()) }
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
* Subclass `PropertyProjection` to refine the behavior of the analysis on existing property projections.
|
* Subclass `PropertyProjection` to refine the behavior of the analysis on existing property projections.
|
||||||
* Subclass `CustomPropertyProjection` to introduce new kinds of property projections.
|
* Subclass `CustomPropertyProjection` to introduce new kinds of property projections.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
@@ -137,6 +139,7 @@ private class VarArgsPropertyProjection extends PropertyProjection::Range {
|
|||||||
/**
|
/**
|
||||||
* A taint step for a property projection.
|
* A taint step for a property projection.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private class PropertyProjectionTaintStep extends TaintTracking::SharedTaintStep {
|
private class PropertyProjectionTaintStep extends TaintTracking::SharedTaintStep {
|
||||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
// reading from a tainted object yields a tainted result
|
// reading from a tainted object yields a tainted result
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Provides predicates for working with templating libraries.
|
* Provides predicates for working with templating libraries.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
@@ -45,6 +47,7 @@ module Templating {
|
|||||||
Locatable getParent() { template_placeholder_tag_info(this, result, _) }
|
Locatable getParent() { template_placeholder_tag_info(this, result, _) }
|
||||||
|
|
||||||
/** Gets a data flow node representing the value plugged into this placeholder. */
|
/** Gets a data flow node representing the value plugged into this placeholder. */
|
||||||
|
overlay[global]
|
||||||
DataFlow::TemplatePlaceholderTagNode asDataFlowNode() { result.getTag() = this }
|
DataFlow::TemplatePlaceholderTagNode asDataFlowNode() { result.getTag() = this }
|
||||||
|
|
||||||
/** Gets the top-level containing the template expression to be inserted at this placeholder. */
|
/** 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
|
* Holds if this performs raw interpolation, that is, inserts its result
|
||||||
* in the output without escaping it.
|
* in the output without escaping it.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate isRawInterpolation() {
|
predicate isRawInterpolation() {
|
||||||
this.getRawText()
|
this.getRawText()
|
||||||
.regexpMatch(getLikelyTemplateSyntax(this.getFile()).getRawInterpolationRegexp())
|
.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.
|
* Holds if this performs HTML escaping on the result before inserting it in the template.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate isEscapingInterpolation() {
|
predicate isEscapingInterpolation() {
|
||||||
this.getRawText()
|
this.getRawText()
|
||||||
.regexpMatch(getLikelyTemplateSyntax(this.getFile()).getEscapingInterpolationRegexp())
|
.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
|
* Holds if this placeholder occurs in the definition of another template, which means the output
|
||||||
* is susceptible to code injection.
|
* is susceptible to code injection.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
predicate isInNestedTemplateContext(string templateType) {
|
predicate isInNestedTemplateContext(string templateType) {
|
||||||
templateType = "AngularJS" and
|
templateType = "AngularJS" and
|
||||||
AngularJS::isInterpretedByAngularJS(this.getParent()) 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")`.
|
* For example, the call generated from `items | async` would be found by `getAPipeCall("async")`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
DataFlow::CallNode getAPipeCall(string name) {
|
DataFlow::CallNode getAPipeCall(string name) {
|
||||||
result.getCalleeNode().asExpr().(PipeRefExpr).getName() = name
|
result.getCalleeNode().asExpr().(PipeRefExpr).getName() = name
|
||||||
}
|
}
|
||||||
@@ -153,16 +160,19 @@ module Templating {
|
|||||||
Expr getExpression() { result = this.getChildStmt(0).(ExprStmt).getExpr() }
|
Expr getExpression() { result = this.getChildStmt(0).(ExprStmt).getExpr() }
|
||||||
|
|
||||||
/** Gets the data flow node representing the initialization of the given variable in this scope. */
|
/** Gets the data flow node representing the initialization of the given variable in this scope. */
|
||||||
|
overlay[global]
|
||||||
DataFlow::Node getVariableInit(string name) {
|
DataFlow::Node getVariableInit(string name) {
|
||||||
result = DataFlow::ssaDefinitionNode(Ssa::implicitInit(this.getScope().getVariable(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. */
|
/** 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) {
|
DataFlow::SourceNode getAVariableUse(string name) {
|
||||||
result = this.getScope().getVariable(name).getAnAccess().flow()
|
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. */
|
/** 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) {
|
DataFlow::SourceNode getAnAccessPathUse(string accessPath) {
|
||||||
result = this.getAVariableUse(accessPath)
|
result = this.getAVariableUse(accessPath)
|
||||||
or
|
or
|
||||||
@@ -177,6 +187,7 @@ module Templating {
|
|||||||
/**
|
/**
|
||||||
* A place where a template is instantiated or rendered.
|
* A place where a template is instantiated or rendered.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
class TemplateInstantiation extends DataFlow::Node instanceof TemplateInstantiation::Range {
|
class TemplateInstantiation extends DataFlow::Node instanceof TemplateInstantiation::Range {
|
||||||
/** Gets a data flow node that refers to the instantiated template string, if any. */
|
/** Gets a data flow node that refers to the instantiated template string, if any. */
|
||||||
DataFlow::SourceNode getOutput() { result = super.getOutput() }
|
DataFlow::SourceNode getOutput() { result = super.getOutput() }
|
||||||
@@ -206,6 +217,7 @@ module Templating {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Companion module to the `TemplateInstantiation` class. */
|
/** Companion module to the `TemplateInstantiation` class. */
|
||||||
|
overlay[global]
|
||||||
module TemplateInstantiation {
|
module TemplateInstantiation {
|
||||||
abstract class Range extends DataFlow::Node {
|
abstract class Range extends DataFlow::Node {
|
||||||
/** Gets a data flow node that refers to the instantiated template, if any. */
|
/** 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. */
|
/** Gets an API node that may flow to `succ` through a template instantiation. */
|
||||||
|
overlay[global]
|
||||||
private API::Node getTemplateInput(DataFlow::SourceNode succ) {
|
private API::Node getTemplateInput(DataFlow::SourceNode succ) {
|
||||||
exists(TemplateInstantiation inst, API::Node base, string name |
|
exists(TemplateInstantiation inst, API::Node base, string name |
|
||||||
base.asSink() = inst.getTemplateParamsNode() and
|
base.asSink() = inst.getTemplateParamsNode() and
|
||||||
@@ -258,6 +271,7 @@ module Templating {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
private class TemplateInputStep extends DataFlow::SharedFlowStep {
|
private class TemplateInputStep extends DataFlow::SharedFlowStep {
|
||||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
getTemplateInput(succ).asSink() = pred
|
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,
|
* A data flow step from the expression in a placeholder tag to the tag itself,
|
||||||
* representing the value plugged into the template.
|
* representing the value plugged into the template.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private class TemplatePlaceholderStep extends DataFlow::SharedFlowStep {
|
private class TemplatePlaceholderStep extends DataFlow::SharedFlowStep {
|
||||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
exists(TemplatePlaceholderTag tag |
|
exists(TemplatePlaceholderTag tag |
|
||||||
@@ -281,6 +296,7 @@ module Templating {
|
|||||||
* A taint step from a `TemplatePlaceholderTag` to the enclosing expression in the
|
* A taint step from a `TemplatePlaceholderTag` to the enclosing expression in the
|
||||||
* surrounding JavaScript program.
|
* surrounding JavaScript program.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private class PlaceholderToGeneratedCodeStep extends TaintTracking::SharedTaintStep {
|
private class PlaceholderToGeneratedCodeStep extends TaintTracking::SharedTaintStep {
|
||||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
exists(TemplatePlaceholderTag tag |
|
exists(TemplatePlaceholderTag tag |
|
||||||
@@ -296,6 +312,7 @@ module Templating {
|
|||||||
final TemplatePlaceholderTag getAPlaceholder() { result.getFile() = this }
|
final TemplatePlaceholderTag getAPlaceholder() { result.getFile() = this }
|
||||||
|
|
||||||
/** Gets a template file referenced by this one via a template inclusion tag, such as `{% include foo %}` */
|
/** Gets a template file referenced by this one via a template inclusion tag, such as `{% include foo %}` */
|
||||||
|
overlay[global]
|
||||||
TemplateFile getAnImportedFile() {
|
TemplateFile getAnImportedFile() {
|
||||||
result = this.getAPlaceholder().(TemplateInclusionTag).getImportedFile()
|
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
|
* - The root folder is considered unknown, and so a heuristic is used to guess the most
|
||||||
* likely template file being referenced.
|
* likely template file being referenced.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
abstract class TemplateFileReference extends DataFlow::Node {
|
abstract class TemplateFileReference extends DataFlow::Node {
|
||||||
/** Gets the value that identifies the template. */
|
/** Gets the value that identifies the template. */
|
||||||
string getValue() {
|
string getValue() {
|
||||||
@@ -335,6 +353,7 @@ module Templating {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Get file argument of a template instantiation, seen as a template file reference. */
|
/** Get file argument of a template instantiation, seen as a template file reference. */
|
||||||
|
overlay[global]
|
||||||
private class DefaultTemplateFileReference extends TemplateFileReference {
|
private class DefaultTemplateFileReference extends TemplateFileReference {
|
||||||
DefaultTemplateFileReference() { this = any(TemplateInstantiation inst).getTemplateFileNode() }
|
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
|
* - The root folder is considered unknown, and so a heuristic is used to guess the most
|
||||||
* likely template file being referenced.
|
* likely template file being referenced.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
abstract class TemplateFileReferenceString extends string {
|
abstract class TemplateFileReferenceString extends string {
|
||||||
bindingset[this]
|
bindingset[this]
|
||||||
TemplateFileReferenceString() { this = this }
|
TemplateFileReferenceString() { this = this }
|
||||||
@@ -382,6 +402,7 @@ module Templating {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** The value of a template reference node, as a template reference string. */
|
/** The value of a template reference node, as a template reference string. */
|
||||||
|
overlay[global]
|
||||||
private class DefaultTemplateReferenceString extends TemplateFileReferenceString {
|
private class DefaultTemplateReferenceString extends TemplateFileReferenceString {
|
||||||
TemplateFileReference r;
|
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. */
|
/** 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 {
|
private class UpwardTraversalSuffix extends TemplateFileReferenceString {
|
||||||
TemplateFileReferenceString original;
|
TemplateFileReferenceString original;
|
||||||
|
|
||||||
@@ -412,6 +434,7 @@ module Templating {
|
|||||||
* Gets a "fingerprint" for the given template file, which is used to references
|
* Gets a "fingerprint" for the given template file, which is used to references
|
||||||
* that might refer to it (for pruning purposes only).
|
* that might refer to it (for pruning purposes only).
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private string getTemplateFileFingerprint(TemplateFile file) {
|
private string getTemplateFileFingerprint(TemplateFile file) {
|
||||||
result = file.getStem()
|
result = file.getStem()
|
||||||
@@ -424,6 +447,7 @@ module Templating {
|
|||||||
* Gets a "fingerprint" for the given string, which must match one of the fingerprints of
|
* Gets a "fingerprint" for the given string, which must match one of the fingerprints of
|
||||||
* the referenced file (for pruning purposes only).
|
* the referenced file (for pruning purposes only).
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private string getTemplateRefFingerprint(TemplateFileReferenceString ref) {
|
private string getTemplateRefFingerprint(TemplateFileReferenceString ref) {
|
||||||
result = ref.getStem() and not result = ["index", ""]
|
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.
|
* This is only used to speed up `getAMatchingTarget` by pruning out pairs that can't match.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private TemplateFile getAPotentialTarget(TemplateFileReferenceString ref) {
|
private TemplateFile getAPotentialTarget(TemplateFileReferenceString ref) {
|
||||||
getTemplateFileFingerprint(result) = getTemplateRefFingerprint(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
|
* 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`.
|
* the above rules. For example: `bar` matches `src/bar/index.html`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private TemplateFile getAMatchingTarget(TemplateFileReferenceString ref) {
|
private TemplateFile getAMatchingTarget(TemplateFileReferenceString ref) {
|
||||||
result = getAPotentialTarget(ref) and
|
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`,
|
* The string `list` in `A/components/foo.js` will resolve to `A/views/list.html`,
|
||||||
* and vice versa in `B/components/foo.js`.
|
* and vice versa in `B/components/foo.js`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private int getRankOfMatchingTarget(
|
private int getRankOfMatchingTarget(
|
||||||
TemplateFile file, Folder baseFolder, TemplateFileReferenceString ref
|
TemplateFile file, Folder baseFolder, TemplateFileReferenceString ref
|
||||||
@@ -508,6 +535,7 @@ module Templating {
|
|||||||
/**
|
/**
|
||||||
* Gets the template file referred to by `ref` when resolved from `baseFolder`.
|
* Gets the template file referred to by `ref` when resolved from `baseFolder`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private TemplateFile getBestMatchingTarget(Folder baseFolder, TemplateFileReferenceString ref) {
|
private TemplateFile getBestMatchingTarget(Folder baseFolder, TemplateFileReferenceString ref) {
|
||||||
result = max(getAMatchingTarget(ref) as f order by getRankOfMatchingTarget(f, baseFolder, ref))
|
result = max(getAMatchingTarget(ref) as f order by getRankOfMatchingTarget(f, baseFolder, ref))
|
||||||
}
|
}
|
||||||
@@ -599,6 +627,7 @@ module Templating {
|
|||||||
override string getAPackageName() { result = "dot" }
|
override string getAPackageName() { result = "dot" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
private TemplateSyntax getOwnTemplateSyntaxInFolder(Folder f) {
|
private TemplateSyntax getOwnTemplateSyntaxInFolder(Folder f) {
|
||||||
exists(PackageDependencies deps |
|
exists(PackageDependencies deps |
|
||||||
deps.getADependency(result.getAPackageName(), _) and
|
deps.getADependency(result.getAPackageName(), _) and
|
||||||
@@ -606,6 +635,7 @@ module Templating {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
private TemplateSyntax getTemplateSyntaxInFolder(Folder f) {
|
private TemplateSyntax getTemplateSyntaxInFolder(Folder f) {
|
||||||
result = getOwnTemplateSyntaxInFolder(f)
|
result = getOwnTemplateSyntaxInFolder(f)
|
||||||
or
|
or
|
||||||
@@ -613,6 +643,7 @@ module Templating {
|
|||||||
result = getTemplateSyntaxInFolder(f.getParentContainer())
|
result = getTemplateSyntaxInFolder(f.getParentContainer())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
private TemplateSyntax getTemplateSyntaxFromInstantiation(TemplateFile file) {
|
private TemplateSyntax getTemplateSyntaxFromInstantiation(TemplateFile file) {
|
||||||
result = any(TemplateInstantiation inst | inst.getTemplateFile() = file).getTemplateSyntax()
|
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.
|
* Gets a template syntax likely to be used in the given file.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
TemplateSyntax getLikelyTemplateSyntax(TemplateFile file) {
|
TemplateSyntax getLikelyTemplateSyntax(TemplateFile file) {
|
||||||
result = getTemplateSyntaxFromInstantiation(file)
|
result = getTemplateSyntaxFromInstantiation(file)
|
||||||
or
|
or
|
||||||
@@ -632,6 +664,7 @@ module Templating {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A step through the `safe` pipe, which bypasses HTML escaping. */
|
/** A step through the `safe` pipe, which bypasses HTML escaping. */
|
||||||
|
overlay[global]
|
||||||
private class SafePipeStep extends TaintTracking::SharedTaintStep {
|
private class SafePipeStep extends TaintTracking::SharedTaintStep {
|
||||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||||
exists(DataFlow::CallNode call |
|
exists(DataFlow::CallNode call |
|
||||||
@@ -645,6 +678,7 @@ module Templating {
|
|||||||
/**
|
/**
|
||||||
* An EJS-style `include` call within a template tag, such as `<%- include(file, { params }) %>`.
|
* An EJS-style `include` call within a template tag, such as `<%- include(file, { params }) %>`.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private class EjsIncludeCallInTemplate extends TemplateInstantiation::Range, DataFlow::CallNode {
|
private class EjsIncludeCallInTemplate extends TemplateInstantiation::Range, DataFlow::CallNode {
|
||||||
EjsIncludeCallInTemplate() {
|
EjsIncludeCallInTemplate() {
|
||||||
exists(TemplatePlaceholderTag tag |
|
exists(TemplatePlaceholderTag tag |
|
||||||
@@ -669,6 +703,7 @@ module Templating {
|
|||||||
*
|
*
|
||||||
* These API nodes are used in the `getTemplateInput` predicate.
|
* These API nodes are used in the `getTemplateInput` predicate.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private class IncludeFunctionAsEntryPoint extends API::EntryPoint {
|
private class IncludeFunctionAsEntryPoint extends API::EntryPoint {
|
||||||
IncludeFunctionAsEntryPoint() { this = "IncludeFunctionAsEntryPoint" }
|
IncludeFunctionAsEntryPoint() { this = "IncludeFunctionAsEntryPoint" }
|
||||||
|
|
||||||
@@ -703,6 +738,7 @@ module Templating {
|
|||||||
string getPath() { result = rawPath.trim().replaceAll("\\", "/").regexpReplaceAll("^\\./", "") }
|
string getPath() { result = rawPath.trim().replaceAll("\\", "/").regexpReplaceAll("^\\./", "") }
|
||||||
|
|
||||||
/** Gets the file referenced by this inclusion tag. */
|
/** Gets the file referenced by this inclusion tag. */
|
||||||
|
overlay[global]
|
||||||
TemplateFile getImportedFile() {
|
TemplateFile getImportedFile() {
|
||||||
result =
|
result =
|
||||||
this.getPath()
|
this.getPath()
|
||||||
@@ -712,6 +748,7 @@ module Templating {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** The imported string from a template inclusion tag. */
|
/** The imported string from a template inclusion tag. */
|
||||||
|
overlay[global]
|
||||||
private class TemplateInclusionPathString extends TemplateFileReferenceString {
|
private class TemplateInclusionPathString extends TemplateFileReferenceString {
|
||||||
TemplateInclusionTag tag;
|
TemplateInclusionTag tag;
|
||||||
|
|
||||||
@@ -723,6 +760,7 @@ module Templating {
|
|||||||
/**
|
/**
|
||||||
* A call to a member of the `consolidate` library, seen as a template instantiation.
|
* A call to a member of the `consolidate` library, seen as a template instantiation.
|
||||||
*/
|
*/
|
||||||
|
overlay[global]
|
||||||
private class ConsolidateCall extends TemplateInstantiation::Range, API::CallNode {
|
private class ConsolidateCall extends TemplateInstantiation::Range, API::CallNode {
|
||||||
string engine;
|
string engine;
|
||||||
|
|
||||||
|
|||||||
@@ -422,9 +422,11 @@ private module ClosureLibraryUri {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
private class QueryStringStringification extends DataFlow::SummarizedCallable {
|
private class QueryStringStringification extends DataFlow::SummarizedCallable {
|
||||||
QueryStringStringification() { this = "query-string stringification" }
|
QueryStringStringification() { this = "query-string stringification" }
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::InvokeNode getACall() {
|
override DataFlow::InvokeNode getACall() {
|
||||||
result =
|
result =
|
||||||
API::moduleImport(["querystring", "query-string", "querystringify", "qs"])
|
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 {
|
private class SummarizedCallableFromModel extends DataFlow::SummarizedCallable {
|
||||||
string type;
|
string type;
|
||||||
string path;
|
string path;
|
||||||
@@ -57,6 +58,7 @@ private class SummarizedCallableFromModel extends DataFlow::SummarizedCallable {
|
|||||||
this = type + ";" + path
|
this = type + ";" + path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[global]
|
||||||
override DataFlow::InvokeNode getACall() { ModelOutput::resolvedSummaryBase(type, path, result) }
|
override DataFlow::InvokeNode getACall() { ModelOutput::resolvedSummaryBase(type, path, result) }
|
||||||
|
|
||||||
override predicate propagatesFlow(
|
override predicate propagatesFlow(
|
||||||
|
|||||||
@@ -62,6 +62,8 @@
|
|||||||
* should be prefixed with a tilde character (`~`). For example, `~Bar` can be used to indicate that
|
* 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.
|
* the type is not intended to match a static type.
|
||||||
*/
|
*/
|
||||||
|
overlay[local?]
|
||||||
|
module;
|
||||||
|
|
||||||
private import codeql.util.Unit
|
private import codeql.util.Unit
|
||||||
private import ApiGraphModelsSpecific as Specific
|
private import ApiGraphModelsSpecific as Specific
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Defines extensible predicates for contributing library models from data extensions.
|
* 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
|
* 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.
|
* The model generator must explicitly generate the step between `(package)` and `(package).foo`, for example.
|
||||||
*/
|
*/
|
||||||
bindingset[rawType]
|
bindingset[rawType]
|
||||||
|
overlay[caller]
|
||||||
predicate parseTypeString(string rawType, string package, string qualifiedName) {
|
predicate parseTypeString(string rawType, string package, string qualifiedName) {
|
||||||
exists(string regexp |
|
exists(string regexp |
|
||||||
regexp = "('[^']+'|[^.]+)(.*)" and
|
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.
|
* Holds if models describing `package` may be relevant for the analysis of this database.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
predicate isPackageUsed(string package) {
|
predicate isPackageUsed(string package) {
|
||||||
package = "global"
|
package = "global"
|
||||||
or
|
or
|
||||||
@@ -68,6 +70,7 @@ predicate isPackageUsed(string package) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bindingset[type]
|
bindingset[type]
|
||||||
|
overlay[local]
|
||||||
predicate isTypeUsed(string type) {
|
predicate isTypeUsed(string type) {
|
||||||
exists(string package |
|
exists(string package |
|
||||||
parseTypeString(type, package, _) and
|
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
|
* Holds if `type` can be obtained from an instance of `otherType` due to
|
||||||
* language semantics modeled by `getExtraNodeFromType`.
|
* language semantics modeled by `getExtraNodeFromType`.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
predicate hasImplicitTypeModel(string type, string otherType) { none() }
|
predicate hasImplicitTypeModel(string type, string otherType) { none() }
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parseRelevantTypeString(string rawType, string package, string qualifiedName) {
|
private predicate parseRelevantTypeString(string rawType, string package, string qualifiedName) {
|
||||||
isRelevantFullPath(rawType, _) and
|
isRelevantFullPath(rawType, _) and
|
||||||
@@ -190,6 +195,7 @@ API::Node getExtraSuccessorFromNode(API::Node node, AccessPathTokenBase token) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bindingset[node]
|
bindingset[node]
|
||||||
|
overlay[caller?]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private API::Node getAGuardedRouteHandlerApprox(API::Node node) {
|
private API::Node getAGuardedRouteHandlerApprox(API::Node node) {
|
||||||
// For now just get any routing node with the same root (i.e. the same web app), as
|
// For now just get any routing node with the same root (i.e. the same web app), as
|
||||||
@@ -230,6 +236,7 @@ private predicate blockFuzzyCall(DataFlow::CallNode call) {
|
|||||||
isCommonBuiltinMethodName(call.getCalleeName())
|
isCommonBuiltinMethodName(call.getCalleeName())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[caller?]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
API::Node getAFuzzySuccessor(API::Node node) {
|
API::Node getAFuzzySuccessor(API::Node node) {
|
||||||
result = node.getAMember() and
|
result = node.getAMember() and
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
* Provides classes for working with basic blocks, and predicates for computing
|
* Provides classes for working with basic blocks, and predicates for computing
|
||||||
* liveness information for local variables.
|
* liveness information for local variables.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
import javascript
|
import javascript
|
||||||
private import semmle.javascript.internal.StmtContainers
|
private import semmle.javascript.internal.StmtContainers
|
||||||
@@ -318,6 +320,7 @@ module Public {
|
|||||||
/**
|
/**
|
||||||
* Holds if this basic block strictly dominates `bb`.
|
* Holds if this basic block strictly dominates `bb`.
|
||||||
*/
|
*/
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate strictlyDominates(ReachableBasicBlock bb) { this = immediateDominator+(bb) }
|
predicate strictlyDominates(ReachableBasicBlock bb) { this = immediateDominator+(bb) }
|
||||||
|
|
||||||
@@ -326,12 +329,14 @@ module Public {
|
|||||||
*
|
*
|
||||||
* This predicate is reflexive: each reachable basic block dominates itself.
|
* This predicate is reflexive: each reachable basic block dominates itself.
|
||||||
*/
|
*/
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate dominates(ReachableBasicBlock bb) { this = immediateDominator*(bb) }
|
predicate dominates(ReachableBasicBlock bb) { this = immediateDominator*(bb) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this basic block strictly post-dominates `bb`.
|
* Holds if this basic block strictly post-dominates `bb`.
|
||||||
*/
|
*/
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate strictlyPostDominates(ReachableBasicBlock bb) { this = immediatePostDominator+(bb) }
|
predicate strictlyPostDominates(ReachableBasicBlock bb) { this = immediatePostDominator+(bb) }
|
||||||
|
|
||||||
@@ -340,6 +345,7 @@ module Public {
|
|||||||
*
|
*
|
||||||
* This predicate is reflexive: each reachable basic block post-dominates itself.
|
* This predicate is reflexive: each reachable basic block post-dominates itself.
|
||||||
*/
|
*/
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate postDominates(ReachableBasicBlock bb) { this = immediatePostDominator*(bb) }
|
predicate postDominates(ReachableBasicBlock bb) { this = immediatePostDominator*(bb) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ module Stages {
|
|||||||
/**
|
/**
|
||||||
* The `ast` stage.
|
* The `ast` stage.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
cached
|
cached
|
||||||
module Ast {
|
module Ast {
|
||||||
/**
|
/**
|
||||||
@@ -84,6 +85,7 @@ module Stages {
|
|||||||
/**
|
/**
|
||||||
* The `basicblocks` stage.
|
* The `basicblocks` stage.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
cached
|
cached
|
||||||
module BasicBlocks {
|
module BasicBlocks {
|
||||||
/**
|
/**
|
||||||
@@ -110,6 +112,7 @@ module Stages {
|
|||||||
/**
|
/**
|
||||||
* The part of data flow computed before flow summary nodes.
|
* The part of data flow computed before flow summary nodes.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
cached
|
cached
|
||||||
module EarlyDataFlowStage {
|
module EarlyDataFlowStage {
|
||||||
/**
|
/**
|
||||||
@@ -134,6 +137,7 @@ module Stages {
|
|||||||
/**
|
/**
|
||||||
* The `dataflow` stage.
|
* The `dataflow` stage.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
cached
|
cached
|
||||||
module DataFlowStage {
|
module DataFlowStage {
|
||||||
/**
|
/**
|
||||||
@@ -167,8 +171,6 @@ module Stages {
|
|||||||
or
|
or
|
||||||
exists(any(DataFlow::PropRef ref).getBase())
|
exists(any(DataFlow::PropRef ref).getBase())
|
||||||
or
|
or
|
||||||
exists(any(DataFlow::ClassNode cls))
|
|
||||||
or
|
|
||||||
exists(any(DataFlow::CallNode node).getArgument(_))
|
exists(any(DataFlow::CallNode node).getArgument(_))
|
||||||
or
|
or
|
||||||
exists(any(DataFlow::CallNode node).getAnArgument())
|
exists(any(DataFlow::CallNode node).getAnArgument())
|
||||||
@@ -202,8 +204,6 @@ module Stages {
|
|||||||
or
|
or
|
||||||
exists(any(Import i).getImportedModule())
|
exists(any(Import i).getImportedModule())
|
||||||
or
|
or
|
||||||
exists(DataFlow::moduleImport(_))
|
|
||||||
or
|
|
||||||
exists(any(ReExportDeclaration d).getReExportedModule())
|
exists(any(ReExportDeclaration d).getReExportedModule())
|
||||||
or
|
or
|
||||||
exists(any(Module m).getABulkExportedNode())
|
exists(any(Module m).getABulkExportedNode())
|
||||||
|
|||||||
@@ -6,10 +6,16 @@ private predicate isOverlay() { databaseMetadata("isOverlay", "true") }
|
|||||||
|
|
||||||
overlay[local]
|
overlay[local]
|
||||||
private string getFileFromEntity(@locatable node) {
|
private string getFileFromEntity(@locatable node) {
|
||||||
exists(@location loc, @file file |
|
exists(@location loc |
|
||||||
hasLocation(node, loc) and
|
hasLocation(node, loc)
|
||||||
locations_default(loc, file, _, _, _, _) and
|
or
|
||||||
files(file, result)
|
json_locations(node, loc)
|
||||||
|
or
|
||||||
|
yaml_locations(node, loc)
|
||||||
|
or
|
||||||
|
xmllocations(node, loc)
|
||||||
|
|
|
||||||
|
result = getFileFromLocation(loc)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,3 +34,23 @@ overlay[discard_entity]
|
|||||||
private predicate discardEntity(@locatable node) {
|
private predicate discardEntity(@locatable node) {
|
||||||
exists(string file | discardableEntity(file, node) and discardFile(file))
|
exists(string file | discardableEntity(file, node) and discardFile(file))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
|
private string getFileFromLocation(@location loc) {
|
||||||
|
exists(@file file |
|
||||||
|
locations_default(loc, file, _, _, _, _) and
|
||||||
|
files(file, result)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `loc` is in the `file` and is part of the overlay base database. */
|
||||||
|
overlay[local]
|
||||||
|
private predicate discardableLocation(string file, @location node) {
|
||||||
|
not isOverlay() and file = getFileFromLocation(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `loc` should be discarded, because it is part of the overlay base and is in a file that was also extracted as part of the overlay database. */
|
||||||
|
overlay[discard_entity]
|
||||||
|
private predicate discardLocation(@location loc) {
|
||||||
|
exists(string file | discardableLocation(file, loc) and discardFile(file))
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
* Provides predicates and classes for relating nodes to their
|
* Provides predicates and classes for relating nodes to their
|
||||||
* enclosing `StmtContainer`.
|
* enclosing `StmtContainer`.
|
||||||
*/
|
*/
|
||||||
|
overlay[local]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.internal.CachedStages
|
private import semmle.javascript.internal.CachedStages
|
||||||
@@ -46,6 +48,7 @@ class NodeInStmtContainer extends Locatable, @node_in_stmt_container {
|
|||||||
/**
|
/**
|
||||||
* Gets the function or toplevel to which this node belongs.
|
* Gets the function or toplevel to which this node belongs.
|
||||||
*/
|
*/
|
||||||
|
overlay[caller]
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
final StmtContainer getContainer() { result = getStmtContainer(this) }
|
final StmtContainer getContainer() { result = getStmtContainer(this) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
*
|
*
|
||||||
* (Promise is absent in the table above as there currently are no name clashes with Promise methods)
|
* (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 javascript
|
||||||
private import semmle.javascript.dataflow.internal.DataFlowNode
|
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.
|
* 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 javascript
|
||||||
private import semmle.javascript.dataflow.FlowSummary
|
private import semmle.javascript.dataflow.FlowSummary
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Contains flow steps to model flow through `async` functions and the `await` operator.
|
* Contains flow steps to model flow through `async` functions and the `await` operator.
|
||||||
*/
|
*/
|
||||||
|
overlay[local?]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.dataflow.internal.DataFlowNode
|
private import semmle.javascript.dataflow.internal.DataFlowNode
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
overlay[local?]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.dataflow.FlowSummary
|
private import semmle.javascript.dataflow.FlowSummary
|
||||||
private import semmle.javascript.dataflow.InferredTypes
|
private import semmle.javascript.dataflow.InferredTypes
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Contains flow steps to model flow from a module into a dynamic `import()` expression.
|
* Contains flow steps to model flow from a module into a dynamic `import()` expression.
|
||||||
*/
|
*/
|
||||||
|
overlay[local?]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.dataflow.internal.DataFlowNode
|
private import semmle.javascript.dataflow.internal.DataFlowNode
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Contains a summary for propagating exceptions out of callbacks
|
* Contains a summary for propagating exceptions out of callbacks
|
||||||
*/
|
*/
|
||||||
|
overlay[local?]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import FlowSummaryUtil
|
private import FlowSummaryUtil
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
overlay[local?]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.dataflow.FlowSummary
|
private import semmle.javascript.dataflow.FlowSummary
|
||||||
private import semmle.javascript.dataflow.internal.Contents::Private
|
private import semmle.javascript.dataflow.internal.Contents::Private
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Contains flow steps to model flow through `for..of` loops.
|
* Contains flow steps to model flow through `for..of` loops.
|
||||||
*/
|
*/
|
||||||
|
overlay[local?]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.dataflow.internal.DataFlowNode
|
private import semmle.javascript.dataflow.internal.DataFlowNode
|
||||||
@@ -48,12 +50,18 @@ class ForOfLoopStep extends AdditionalFlowInternal {
|
|||||||
) {
|
) {
|
||||||
exists(ForOfStmt stmt |
|
exists(ForOfStmt stmt |
|
||||||
pred = getSynthesizedNode(stmt, "for-of-map-key") and
|
pred = getSynthesizedNode(stmt, "for-of-map-key") and
|
||||||
contents.asSingleton().asArrayIndex() = 0
|
contents = arrayIndex0()
|
||||||
or
|
or
|
||||||
pred = getSynthesizedNode(stmt, "for-of-map-value") and
|
pred = getSynthesizedNode(stmt, "for-of-map-value") and
|
||||||
contents.asSingleton().asArrayIndex() = 1
|
contents = arrayIndex1()
|
||||||
|
|
|
|
||||||
succ = DataFlow::lvalueNode(stmt.getLValue())
|
succ = DataFlow::lvalueNode(stmt.getLValue())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlow::ContentSet arrayIndex0() { result.asSingleton().asArrayIndex() = 0 }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlow::ContentSet arrayIndex1() { result.asSingleton().asArrayIndex() = 1 }
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Contains flow steps to model flow through generator functions.
|
* Contains flow steps to model flow through generator functions.
|
||||||
*/
|
*/
|
||||||
|
overlay[local?]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.dataflow.internal.DataFlowNode
|
private import semmle.javascript.dataflow.internal.DataFlowNode
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Contains flow summaries and steps modeling flow through iterators.
|
* Contains flow summaries and steps modeling flow through iterators.
|
||||||
*/
|
*/
|
||||||
|
overlay[local?]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.dataflow.internal.DataFlowNode
|
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`.
|
* 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 javascript
|
||||||
private import FlowSummaryUtil
|
private import FlowSummaryUtil
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Contains flow summaries and steps modeling flow through `Map` objects.
|
* Contains flow summaries and steps modeling flow through `Map` objects.
|
||||||
*/
|
*/
|
||||||
|
overlay[local?]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.dataflow.FlowSummary
|
private import semmle.javascript.dataflow.FlowSummary
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Contains flow summaries and steps modeling flow through `Promise` objects.
|
* Contains flow summaries and steps modeling flow through `Promise` objects.
|
||||||
*/
|
*/
|
||||||
|
overlay[local?]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.dataflow.FlowSummary
|
private import semmle.javascript.dataflow.FlowSummary
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Contains flow summaries and steps modeling flow through `Set` objects.
|
* Contains flow summaries and steps modeling flow through `Set` objects.
|
||||||
*/
|
*/
|
||||||
|
overlay[local?]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.dataflow.FlowSummary
|
private import semmle.javascript.dataflow.FlowSummary
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Contains flow summaries and steps modeling flow through string methods.
|
* Contains flow summaries and steps modeling flow through string methods.
|
||||||
*/
|
*/
|
||||||
|
overlay[local?]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.dataflow.FlowSummary
|
private import semmle.javascript.dataflow.FlowSummary
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
overlay[local?]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
private import semmle.javascript.dataflow.FlowSummary
|
private import semmle.javascript.dataflow.FlowSummary
|
||||||
private import semmle.javascript.dataflow.InferredTypes
|
private import semmle.javascript.dataflow.InferredTypes
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
*
|
*
|
||||||
* For now, the `URLSearchParams` object is modeled as a `Map` object.
|
* For now, the `URLSearchParams` object is modeled as a `Map` object.
|
||||||
*/
|
*/
|
||||||
|
overlay[local?]
|
||||||
|
module;
|
||||||
|
|
||||||
private import javascript
|
private import javascript
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import javascript
|
import javascript
|
||||||
import semmle.javascript.dataflow.FlowSummary
|
import semmle.javascript.dataflow.FlowSummary
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
class MkSummary extends SummarizedCallable {
|
class MkSummary extends SummarizedCallable {
|
||||||
private CallExpr mkSummary;
|
private CallExpr mkSummary;
|
||||||
|
|
||||||
|
|||||||
@@ -14,12 +14,26 @@
|
|||||||
|
|
||||||
import Clones
|
import Clones
|
||||||
|
|
||||||
|
bindingset[init]
|
||||||
|
pragma[inline_late]
|
||||||
|
private Property getPropertyFromInitializerStrict(Expr init) { result.getInit() = init }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate duplicateProperties(
|
||||||
|
DuplicatePropertyInitDetector dup, Property prop1, Property prop2
|
||||||
|
) {
|
||||||
|
exists(Expr init2 |
|
||||||
|
dup.same(init2) and
|
||||||
|
prop1 = getPropertyFromInitializerStrict(dup) and
|
||||||
|
prop2 = getPropertyFromInitializerStrict(init2)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
from ObjectExpr oe, int i, int j, Property p, Property q, DuplicatePropertyInitDetector dpid
|
from ObjectExpr oe, int i, int j, Property p, Property q, DuplicatePropertyInitDetector dpid
|
||||||
where
|
where
|
||||||
|
duplicateProperties(dpid, p, q) and
|
||||||
p = oe.getProperty(i) and
|
p = oe.getProperty(i) and
|
||||||
q = oe.getProperty(j) and
|
q = oe.getProperty(j) and
|
||||||
dpid = p.getInit() and
|
|
||||||
dpid.same(q.getInit()) and
|
|
||||||
i < j and
|
i < j and
|
||||||
// only report the next duplicate
|
// only report the next duplicate
|
||||||
not exists(int mid | mid in [i + 1 .. j - 1] | dpid.same(oe.getProperty(mid).getInit()))
|
not exists(int mid | mid in [i + 1 .. j - 1] | dpid.same(oe.getProperty(mid).getInit()))
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import javascript
|
import javascript
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
class TestAmdModuleRange extends AmdModuleDefinition::Range {
|
class TestAmdModuleRange extends AmdModuleDefinition::Range {
|
||||||
TestAmdModuleRange() { this.getCallee().(PropAccess).getQualifiedName() = "test.amd.range" }
|
TestAmdModuleRange() { this.getCallee().(PropAccess).getQualifiedName() = "test.amd.range" }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import semmle.javascript.dataflow.internal.FlowSteps as FlowSteps
|
|||||||
import semmle.javascript.dataflow.internal.AbstractPropertiesImpl as AbstractPropertiesImpl
|
import semmle.javascript.dataflow.internal.AbstractPropertiesImpl as AbstractPropertiesImpl
|
||||||
import semmle.javascript.dataflow.CustomAbstractValueDefinitions
|
import semmle.javascript.dataflow.CustomAbstractValueDefinitions
|
||||||
|
|
||||||
|
overlay[local]
|
||||||
class MyCustomAbstractValueDefinition extends CustomAbstractValueDefinition {
|
class MyCustomAbstractValueDefinition extends CustomAbstractValueDefinition {
|
||||||
DataFlow::ValueNode node;
|
DataFlow::ValueNode node;
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user