mirror of
https://github.com/github/codeql.git
synced 2026-04-26 09:15:12 +02:00
JS: Make Closure concepts based on AST instead
This commit is contained in:
@@ -5,17 +5,49 @@
|
||||
import javascript
|
||||
|
||||
module Closure {
|
||||
/** A call to `goog.require` */
|
||||
class RequireCallExpr extends CallExpr {
|
||||
RequireCallExpr() { this.getCallee().(PropAccess).getQualifiedName() = "goog.require" }
|
||||
|
||||
/** Gets the imported namespace name. */
|
||||
string getClosureNamespace() { result = this.getArgument(0).getStringValue() }
|
||||
}
|
||||
|
||||
/** A call to `goog.provide` */
|
||||
class ProvideCallExpr extends CallExpr {
|
||||
ProvideCallExpr() { this.getCallee().(PropAccess).getQualifiedName() = "goog.provide" }
|
||||
|
||||
/** Gets the imported namespace name. */
|
||||
string getClosureNamespace() { result = this.getArgument(0).getStringValue() }
|
||||
}
|
||||
|
||||
/** A call to `goog.module` or `goog.declareModuleId`. */
|
||||
private class ModuleDeclarationCall extends CallExpr {
|
||||
private string kind;
|
||||
|
||||
ModuleDeclarationCall() {
|
||||
this.getCallee().(PropAccess).getQualifiedName() = kind and
|
||||
kind = ["goog.module", "goog.declareModuleId"]
|
||||
}
|
||||
|
||||
/** Gets the declared namespace. */
|
||||
string getClosureNamespace() { result = this.getArgument(0).getStringValue() }
|
||||
|
||||
/** Gets the string `goog.module` or `goog.declareModuleId` depending on which method is being called. */
|
||||
string getModuleKind() { result = kind }
|
||||
}
|
||||
|
||||
/**
|
||||
* A reference to a Closure namespace.
|
||||
*/
|
||||
class ClosureNamespaceRef extends DataFlow::Node instanceof ClosureNamespaceRef::Range {
|
||||
deprecated class ClosureNamespaceRef extends DataFlow::Node instanceof ClosureNamespaceRef::Range {
|
||||
/**
|
||||
* Gets the namespace being referenced.
|
||||
*/
|
||||
string getClosureNamespace() { result = super.getClosureNamespace() }
|
||||
}
|
||||
|
||||
module ClosureNamespaceRef {
|
||||
deprecated module ClosureNamespaceRef {
|
||||
/**
|
||||
* A reference to a Closure namespace.
|
||||
*
|
||||
@@ -32,10 +64,10 @@ module Closure {
|
||||
/**
|
||||
* A data flow node that returns the value of a closure namespace.
|
||||
*/
|
||||
class ClosureNamespaceAccess extends ClosureNamespaceRef instanceof ClosureNamespaceAccess::Range {
|
||||
}
|
||||
deprecated class ClosureNamespaceAccess extends ClosureNamespaceRef instanceof ClosureNamespaceAccess::Range
|
||||
{ }
|
||||
|
||||
module ClosureNamespaceAccess {
|
||||
deprecated module ClosureNamespaceAccess {
|
||||
/**
|
||||
* A data flow node that returns the value of a closure namespace.
|
||||
*
|
||||
@@ -47,7 +79,7 @@ module Closure {
|
||||
/**
|
||||
* A call to a method on the `goog.` namespace, as a closure reference.
|
||||
*/
|
||||
abstract private class DefaultNamespaceRef extends DataFlow::MethodCallNode,
|
||||
abstract deprecated private class DefaultNamespaceRef extends DataFlow::MethodCallNode,
|
||||
ClosureNamespaceRef::Range
|
||||
{
|
||||
DefaultNamespaceRef() { this = DataFlow::globalVarRef("goog").getAMethodCall() }
|
||||
@@ -59,14 +91,14 @@ module Closure {
|
||||
* Holds if `node` is the data flow node corresponding to the expression in
|
||||
* a top-level expression statement.
|
||||
*/
|
||||
private predicate isTopLevelExpr(DataFlow::Node node) {
|
||||
deprecated private predicate isTopLevelExpr(DataFlow::Node node) {
|
||||
any(TopLevel tl).getAChildStmt().(ExprStmt).getExpr().flow() = node
|
||||
}
|
||||
|
||||
/**
|
||||
* A top-level call to `goog.provide`.
|
||||
*/
|
||||
private class DefaultClosureProvideCall extends DefaultNamespaceRef {
|
||||
deprecated private class DefaultClosureProvideCall extends DefaultNamespaceRef {
|
||||
DefaultClosureProvideCall() {
|
||||
this.getMethodName() = "provide" and
|
||||
isTopLevelExpr(this)
|
||||
@@ -76,13 +108,14 @@ module Closure {
|
||||
/**
|
||||
* A top-level call to `goog.provide`.
|
||||
*/
|
||||
class ClosureProvideCall extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureProvideCall
|
||||
deprecated class ClosureProvideCall extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureProvideCall
|
||||
{ }
|
||||
|
||||
/**
|
||||
* A call to `goog.require`.
|
||||
*/
|
||||
private class DefaultClosureRequireCall extends DefaultNamespaceRef, ClosureNamespaceAccess::Range
|
||||
deprecated private class DefaultClosureRequireCall extends DefaultNamespaceRef,
|
||||
ClosureNamespaceAccess::Range
|
||||
{
|
||||
DefaultClosureRequireCall() { this.getMethodName() = "require" }
|
||||
}
|
||||
@@ -90,13 +123,13 @@ module Closure {
|
||||
/**
|
||||
* A call to `goog.require`.
|
||||
*/
|
||||
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`.
|
||||
*/
|
||||
private class DefaultClosureModuleDeclaration extends DefaultNamespaceRef {
|
||||
deprecated private class DefaultClosureModuleDeclaration extends DefaultNamespaceRef {
|
||||
DefaultClosureModuleDeclaration() {
|
||||
(this.getMethodName() = "module" or this.getMethodName() = "declareModuleId") and
|
||||
isTopLevelExpr(this)
|
||||
@@ -106,41 +139,29 @@ module Closure {
|
||||
/**
|
||||
* A top-level call to `goog.module` or `goog.declareModuleId`.
|
||||
*/
|
||||
class ClosureModuleDeclaration extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureModuleDeclaration
|
||||
deprecated class ClosureModuleDeclaration extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureModuleDeclaration
|
||||
{ }
|
||||
|
||||
private GlobalVariable googVariable() { variables(result, "goog", any(GlobalScope sc)) }
|
||||
|
||||
pragma[nomagic]
|
||||
private MethodCallExpr googModuleDeclExpr() {
|
||||
result.getReceiver() = googVariable().getAnAccess() and
|
||||
result.getMethodName() = ["module", "declareModuleId"]
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private MethodCallExpr googModuleDeclExprInContainer(StmtContainer container) {
|
||||
result = googModuleDeclExpr() and
|
||||
container = result.getContainer()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private ClosureRequireCall getARequireInTopLevel(ClosureModule m) { result.getTopLevel() = m }
|
||||
private RequireCallExpr getARequireInTopLevel(ClosureModule m) { result.getTopLevel() = m }
|
||||
|
||||
/**
|
||||
* A module using the Closure module system, declared using `goog.module()` or `goog.declareModuleId()`.
|
||||
*/
|
||||
class ClosureModule extends Module {
|
||||
ClosureModule() { exists(googModuleDeclExprInContainer(this)) }
|
||||
private ModuleDeclarationCall decl;
|
||||
|
||||
ClosureModule() { decl.getTopLevel() = this }
|
||||
|
||||
/**
|
||||
* Gets the call to `goog.module` or `goog.declareModuleId` in this module.
|
||||
*/
|
||||
ClosureModuleDeclaration getModuleDeclaration() { result.getTopLevel() = this }
|
||||
deprecated ClosureModuleDeclaration getModuleDeclaration() { result.getTopLevel() = this }
|
||||
|
||||
/**
|
||||
* Gets the namespace of this module.
|
||||
*/
|
||||
string getClosureNamespace() { result = this.getModuleDeclaration().getClosureNamespace() }
|
||||
string getClosureNamespace() { result = decl.getClosureNamespace() }
|
||||
|
||||
override Module getAnImportedModule() {
|
||||
result.(ClosureModule).getClosureNamespace() =
|
||||
@@ -156,7 +177,7 @@ module Closure {
|
||||
* Has no result for ES6 modules using `goog.declareModuleId`.
|
||||
*/
|
||||
Variable getExportsVariable() {
|
||||
this.getModuleDeclaration().getMethodName() = "module" and
|
||||
decl.getModuleKind() = "goog.module" and
|
||||
result = this.getScope().getVariable("exports")
|
||||
}
|
||||
|
||||
@@ -185,15 +206,15 @@ module Closure {
|
||||
ClosureScript() {
|
||||
not this instanceof ClosureModule and
|
||||
(
|
||||
any(ClosureProvideCall provide).getTopLevel() = this
|
||||
any(ProvideCallExpr provide).getTopLevel() = this
|
||||
or
|
||||
any(ClosureRequireCall require).getTopLevel() = this
|
||||
any(RequireCallExpr require).getTopLevel() = this
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the identifier of a namespace required by this module. */
|
||||
string getARequiredNamespace() {
|
||||
exists(ClosureRequireCall require |
|
||||
exists(RequireCallExpr require |
|
||||
require.getTopLevel() = this and
|
||||
result = require.getClosureNamespace()
|
||||
)
|
||||
@@ -201,7 +222,7 @@ module Closure {
|
||||
|
||||
/** Gets the identifer of a namespace provided by this module. */
|
||||
string getAProvidedNamespace() {
|
||||
exists(ClosureProvideCall require |
|
||||
exists(ProvideCallExpr require |
|
||||
require.getTopLevel() = this and
|
||||
result = require.getClosureNamespace()
|
||||
)
|
||||
@@ -213,7 +234,13 @@ module Closure {
|
||||
*/
|
||||
pragma[noinline]
|
||||
predicate isClosureNamespace(string name) {
|
||||
exists(string namespace | namespace = any(ClosureNamespaceRef ref).getClosureNamespace() |
|
||||
exists(string namespace |
|
||||
namespace =
|
||||
[
|
||||
any(RequireCallExpr ref).getClosureNamespace(),
|
||||
any(ModuleDeclarationCall c).getClosureNamespace()
|
||||
]
|
||||
|
|
||||
name = namespace.substring(0, namespace.indexOf("."))
|
||||
or
|
||||
name = namespace
|
||||
|
||||
@@ -34,7 +34,7 @@ module AccessPath {
|
||||
not this.accessesGlobal(_) and
|
||||
not this instanceof DataFlow::PropRead and
|
||||
not this instanceof PropertyProjection and
|
||||
not this instanceof Closure::ClosureNamespaceAccess and
|
||||
not this.asExpr() instanceof Closure::RequireCallExpr and
|
||||
not this = DataFlow::parameterNode(any(ImmediatelyInvokedFunctionExpr iife).getAParameter()) and
|
||||
not FlowSteps::identityFunctionStep(_, this)
|
||||
}
|
||||
@@ -139,8 +139,8 @@ module AccessPath {
|
||||
result = join(fromReference(prop.getBase(), root), "[number]")
|
||||
)
|
||||
or
|
||||
exists(Closure::ClosureNamespaceAccess acc | node = acc |
|
||||
result = acc.getClosureNamespace() and
|
||||
exists(Closure::RequireCallExpr req | node = req.flow() |
|
||||
result = req.getClosureNamespace() and
|
||||
root.isGlobal()
|
||||
)
|
||||
or
|
||||
|
||||
Reference in New Issue
Block a user