Compare commits

...

2 Commits

Author SHA1 Message Date
Philip Ginsbach
8cdd8b6ae0 use instanceof extensions in javascript 2021-05-12 18:58:45 +01:00
Erik Krogh Kristensen
0194af9432 convert field based range pattern to casting based range pattern 2021-05-12 16:49:43 +02:00
16 changed files with 108 additions and 164 deletions

View File

@@ -6,16 +6,13 @@ import javascript
module Base64 { module Base64 {
/** A call to a base64 encoder. */ /** A call to a base64 encoder. */
class Encode extends DataFlow::Node { class Encode extends DataFlow::Node instanceof Encode::Range {
Encode::Range encode;
Encode() { this = encode }
/** Gets the input passed to the encoder. */ /** Gets the input passed to the encoder. */
DataFlow::Node getInput() { result = encode.getInput() } DataFlow::Node getInput() { result = this.(Encode::Range).getInput() }
/** Gets the base64-encoded output of the encoder. */ /** Gets the base64-encoded output of the encoder. */
DataFlow::Node getOutput() { result = encode.getOutput() } DataFlow::Node getOutput() { result = this.(Encode::Range).getOutput() }
} }
module Encode { module Encode {
@@ -34,16 +31,13 @@ module Base64 {
} }
/** A call to a base64 decoder. */ /** A call to a base64 decoder. */
class Decode extends DataFlow::Node { class Decode extends DataFlow::Node instanceof Decode::Range {
Decode::Range encode;
Decode() { this = encode }
/** Gets the base64-encoded input passed to the decoder. */ /** Gets the base64-encoded input passed to the decoder. */
DataFlow::Node getInput() { result = encode.getInput() } DataFlow::Node getInput() { result = this.(Decode::Range).getInput() }
/** Gets the output of the decoder. */ /** Gets the output of the decoder. */
DataFlow::Node getOutput() { result = encode.getOutput() } DataFlow::Node getOutput() { result = this.(Decode::Range).getOutput() }
} }
module Decode { module Decode {

View File

@@ -8,15 +8,14 @@ module Closure {
/** /**
* A reference to a Closure namespace. * A reference to a Closure namespace.
*/ */
class ClosureNamespaceRef extends DataFlow::Node { class ClosureNamespaceRef extends DataFlow::Node instanceof ClosureNamespaceRef::Range {
ClosureNamespaceRef::Range range;
ClosureNamespaceRef() { this = range }
/** /**
* Gets the namespace being referenced. * Gets the namespace being referenced.
*/ */
string getClosureNamespace() { result = range.getClosureNamespace() } string getClosureNamespace() {
result = this.(ClosureNamespaceRef::Range).getClosureNamespace()
}
} }
module ClosureNamespaceRef { module ClosureNamespaceRef {
@@ -36,8 +35,7 @@ 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.
*/ */
class ClosureNamespaceAccess extends ClosureNamespaceRef { class ClosureNamespaceAccess extends ClosureNamespaceRef instanceof ClosureNamespaceAccess::Range {
override ClosureNamespaceAccess::Range range;
} }
module ClosureNamespaceAccess { module ClosureNamespaceAccess {
@@ -80,8 +78,7 @@ module Closure {
/** /**
* A top-level call to `goog.provide`. * A top-level call to `goog.provide`.
*/ */
class ClosureProvideCall extends ClosureNamespaceRef, DataFlow::MethodCallNode { class ClosureProvideCall extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureProvideCall {
override DefaultClosureProvideCall range;
} }
/** /**
@@ -94,8 +91,7 @@ module Closure {
/** /**
* A call to `goog.require`. * A call to `goog.require`.
*/ */
class ClosureRequireCall extends ClosureNamespaceAccess, DataFlow::MethodCallNode { class ClosureRequireCall extends ClosureNamespaceAccess, DataFlow::MethodCallNode instanceof DefaultClosureRequireCall {
override DefaultClosureRequireCall range;
} }
/** /**
@@ -111,8 +107,7 @@ module Closure {
/** /**
* A top-level call to `goog.module` or `goog.declareModuleId`. * A top-level call to `goog.module` or `goog.declareModuleId`.
*/ */
class ClosureModuleDeclaration extends ClosureNamespaceRef, DataFlow::MethodCallNode { class ClosureModuleDeclaration extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureModuleDeclaration {
override DefaultClosureModuleDeclaration range;
} }
private GlobalVariable googVariable() { variables(result, "goog", any(GlobalScope sc)) } private GlobalVariable googVariable() { variables(result, "goog", any(GlobalScope sc)) }

View File

@@ -16,16 +16,13 @@ private import javascript
* ~A.indexOf(B) * ~A.indexOf(B)
* ``` * ```
*/ */
class InclusionTest extends DataFlow::Node { class InclusionTest extends DataFlow::Node instanceof InclusionTest::Range {
InclusionTest::Range range;
InclusionTest() { this = range }
/** Gets the `A` in `A.includes(B)`. */ /** Gets the `A` in `A.includes(B)`. */
DataFlow::Node getContainerNode() { result = range.getContainerNode() } DataFlow::Node getContainerNode() { result = this.(InclusionTest::Range).getContainerNode() }
/** Gets the `B` in `A.includes(B)`. */ /** Gets the `B` in `A.includes(B)`. */
DataFlow::Node getContainedNode() { result = range.getContainedNode() } DataFlow::Node getContainedNode() { result = this.(InclusionTest::Range).getContainedNode() }
/** /**
* Gets the polarity of the check. * Gets the polarity of the check.
@@ -33,7 +30,7 @@ class InclusionTest extends DataFlow::Node {
* If the polarity is `false` the check returns `true` if the container does not contain * If the polarity is `false` the check returns `true` if the container does not contain
* the given element. * the given element.
*/ */
boolean getPolarity() { result = range.getPolarity() } boolean getPolarity() { result = this.(InclusionTest::Range).getPolarity() }
} }
module InclusionTest { module InclusionTest {

View File

@@ -9,27 +9,24 @@ import javascript
* *
* Additional candidates can be added by subclassing `MembershipCandidate::Range` * Additional candidates can be added by subclassing `MembershipCandidate::Range`
*/ */
class MembershipCandidate extends DataFlow::Node { class MembershipCandidate extends DataFlow::Node instanceof MembershipCandidate::Range {
MembershipCandidate::Range range;
MembershipCandidate() { this = range }
/** /**
* Gets the expression that performs the membership test, if any. * Gets the expression that performs the membership test, if any.
*/ */
DataFlow::Node getTest() { result = range.getTest() } DataFlow::Node getTest() { result = this.(MembershipCandidate::Range).getTest() }
/** /**
* Gets a string that this candidate is tested against, if * Gets a string that this candidate is tested against, if
* it can be determined. * it can be determined.
*/ */
string getAMemberString() { result = range.getAMemberString() } string getAMemberString() { result = this.(MembershipCandidate::Range).getAMemberString() }
/** /**
* Gets a node that this candidate is tested against, if * Gets a node that this candidate is tested against, if
* it can be determined. * it can be determined.
*/ */
DataFlow::Node getAMemberNode() { result = range.getAMemberNode() } DataFlow::Node getAMemberNode() { result = this.(MembershipCandidate::Range).getAMemberNode() }
/** /**
* Gets the polarity of the test. * Gets the polarity of the test.
@@ -37,7 +34,7 @@ class MembershipCandidate extends DataFlow::Node {
* If the polarity is `false` the test returns `true` if the * If the polarity is `false` the test returns `true` if the
* collection does not contain this candidate. * collection does not contain this candidate.
*/ */
boolean getTestPolarity() { result = range.getTestPolarity() } boolean getTestPolarity() { result = this.(MembershipCandidate::Range).getTestPolarity() }
} }
/** /**

View File

@@ -8,20 +8,17 @@ module StringOps {
/** /**
* A expression that is equivalent to `A.startsWith(B)` or `!A.startsWith(B)`. * A expression that is equivalent to `A.startsWith(B)` or `!A.startsWith(B)`.
*/ */
class StartsWith extends DataFlow::Node { class StartsWith extends DataFlow::Node instanceof StartsWith::Range {
StartsWith::Range range;
StartsWith() { range = this }
/** /**
* Gets the `A` in `A.startsWith(B)`. * Gets the `A` in `A.startsWith(B)`.
*/ */
DataFlow::Node getBaseString() { result = range.getBaseString() } DataFlow::Node getBaseString() { result = this.(StartsWith::Range).getBaseString() }
/** /**
* Gets the `B` in `A.startsWith(B)`. * Gets the `B` in `A.startsWith(B)`.
*/ */
DataFlow::Node getSubstring() { result = range.getSubstring() } DataFlow::Node getSubstring() { result = this.(StartsWith::Range).getSubstring() }
/** /**
* Gets the polarity of the check. * Gets the polarity of the check.
@@ -29,7 +26,7 @@ module StringOps {
* If the polarity is `false` the check returns `true` if the string does not start * If the polarity is `false` the check returns `true` if the string does not start
* with the given substring. * with the given substring.
*/ */
boolean getPolarity() { result = range.getPolarity() } boolean getPolarity() { result = this.(StartsWith::Range).getPolarity() }
} }
module StartsWith { module StartsWith {
@@ -237,20 +234,17 @@ module StringOps {
/** /**
* An expression that is equivalent to `A.endsWith(B)` or `!A.endsWith(B)`. * An expression that is equivalent to `A.endsWith(B)` or `!A.endsWith(B)`.
*/ */
class EndsWith extends DataFlow::Node { class EndsWith extends DataFlow::Node instanceof EndsWith::Range {
EndsWith::Range range;
EndsWith() { this = range }
/** /**
* Gets the `A` in `A.startsWith(B)`. * Gets the `A` in `A.startsWith(B)`.
*/ */
DataFlow::Node getBaseString() { result = range.getBaseString() } DataFlow::Node getBaseString() { result = this.(EndsWith::Range).getBaseString() }
/** /**
* Gets the `B` in `A.startsWith(B)`. * Gets the `B` in `A.startsWith(B)`.
*/ */
DataFlow::Node getSubstring() { result = range.getSubstring() } DataFlow::Node getSubstring() { result = this.(EndsWith::Range).getSubstring() }
/** /**
* Gets the polarity if the check. * Gets the polarity if the check.
@@ -258,7 +252,7 @@ module StringOps {
* If the polarity is `false` the check returns `true` if the string does not end * If the polarity is `false` the check returns `true` if the string does not end
* with the given substring. * with the given substring.
*/ */
boolean getPolarity() { result = range.getPolarity() } boolean getPolarity() { result = this.(EndsWith::Range).getPolarity() }
} }
module EndsWith { module EndsWith {
@@ -662,10 +656,7 @@ module StringOps {
* if (!match) { ... } // <--- 'match' is the RegExpTest * if (!match) { ... } // <--- 'match' is the RegExpTest
* ``` * ```
*/ */
class RegExpTest extends DataFlow::Node { class RegExpTest extends DataFlow::Node instanceof RegExpTest::Range {
RegExpTest::Range range;
RegExpTest() { this = range }
/** /**
* Gets the AST of the regular expression used in the test, if it can be seen locally. * Gets the AST of the regular expression used in the test, if it can be seen locally.
@@ -673,7 +664,7 @@ module StringOps {
RegExpTerm getRegExp() { RegExpTerm getRegExp() {
result = getRegExpOperand().getALocalSource().(DataFlow::RegExpCreationNode).getRoot() result = getRegExpOperand().getALocalSource().(DataFlow::RegExpCreationNode).getRoot()
or or
result = range.getRegExpOperand(true).asExpr().(StringLiteral).asRegExp() result = this.(RegExpTest::Range).getRegExpOperand(true).asExpr().(StringLiteral).asRegExp()
} }
/** /**
@@ -681,12 +672,12 @@ module StringOps {
* *
* In some cases this represents a string value being coerced to a RegExp object. * In some cases this represents a string value being coerced to a RegExp object.
*/ */
DataFlow::Node getRegExpOperand() { result = range.getRegExpOperand(_) } DataFlow::Node getRegExpOperand() { result = this.(RegExpTest::Range).getRegExpOperand(_) }
/** /**
* Gets the data flow node corresponding to the string being tested against the regular expression. * Gets the data flow node corresponding to the string being tested against the regular expression.
*/ */
DataFlow::Node getStringOperand() { result = range.getStringOperand() } DataFlow::Node getStringOperand() { result = this.(RegExpTest::Range).getStringOperand() }
/** /**
* Gets the return value indicating that the string matched the regular expression. * Gets the return value indicating that the string matched the regular expression.
@@ -694,7 +685,7 @@ module StringOps {
* For example, for `regexp.exec(str) == null`, the polarity is `false`, and for * For example, for `regexp.exec(str) == null`, the polarity is `false`, and for
* `regexp.exec(str) != null` the polarity is `true`. * `regexp.exec(str) != null` the polarity is `true`.
*/ */
boolean getPolarity() { result = range.getPolarity() } boolean getPolarity() { result = this.(RegExpTest::Range).getPolarity() }
} }
/** /**

View File

@@ -701,13 +701,10 @@ class ArrayCreationNode extends DataFlow::ValueNode, DataFlow::SourceNode {
* define(["fs"], function(fs) { ... }); // AMD module * define(["fs"], function(fs) { ... }); // AMD module
* ``` * ```
*/ */
class ModuleImportNode extends DataFlow::SourceNode { class ModuleImportNode extends DataFlow::SourceNode instanceof ModuleImportNode::Range {
ModuleImportNode::Range range;
ModuleImportNode() { this = range }
/** Gets the path of the imported module. */ /** Gets the path of the imported module. */
string getPath() { result = range.getPath() } string getPath() { result = this.(ModuleImportNode::Range).getPath() }
} }
module ModuleImportNode { module ModuleImportNode {
@@ -843,25 +840,22 @@ 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`.
*/ */
class ClassNode extends DataFlow::SourceNode { class ClassNode extends DataFlow::SourceNode instanceof ClassNode::Range {
ClassNode::Range impl;
ClassNode() { this = impl }
/** /**
* Gets the unqualified name of the class, if it has one or one can be determined from the context. * Gets the unqualified name of the class, if it has one or one can be determined from the context.
*/ */
string getName() { result = impl.getName() } string getName() { result = this.(ClassNode::Range).getName() }
/** /**
* Gets a description of the class. * Gets a description of the class.
*/ */
string describe() { result = impl.describe() } string describe() { result = this.(ClassNode::Range).describe() }
/** /**
* Gets the constructor function of this class. * Gets the constructor function of this class.
*/ */
FunctionNode getConstructor() { result = impl.getConstructor() } FunctionNode getConstructor() { result = this.(ClassNode::Range).getConstructor() }
/** /**
* Gets an instance method declared in this class, with the given name, if any. * Gets an instance method declared in this class, with the given name, if any.
@@ -869,7 +863,7 @@ class ClassNode extends DataFlow::SourceNode {
* Does not include methods from superclasses. * Does not include methods from superclasses.
*/ */
FunctionNode getInstanceMethod(string name) { FunctionNode getInstanceMethod(string name) {
result = impl.getInstanceMember(name, MemberKind::method()) result = this.(ClassNode::Range).getInstanceMember(name, MemberKind::method())
} }
/** /**
@@ -879,7 +873,9 @@ class ClassNode extends DataFlow::SourceNode {
* *
* Does not include methods from superclasses. * Does not include methods from superclasses.
*/ */
FunctionNode getAnInstanceMethod() { result = impl.getAnInstanceMember(MemberKind::method()) } FunctionNode getAnInstanceMethod() {
result = this.(ClassNode::Range).getAnInstanceMember(MemberKind::method())
}
/** /**
* Gets the instance method, getter, or setter with the given name and kind. * Gets the instance method, getter, or setter with the given name and kind.
@@ -887,7 +883,7 @@ class ClassNode extends DataFlow::SourceNode {
* Does not include members from superclasses. * Does not include members from superclasses.
*/ */
FunctionNode getInstanceMember(string name, MemberKind kind) { FunctionNode getInstanceMember(string name, MemberKind kind) {
result = impl.getInstanceMember(name, kind) result = this.(ClassNode::Range).getInstanceMember(name, kind)
} }
/** /**
@@ -895,31 +891,35 @@ class ClassNode extends DataFlow::SourceNode {
* *
* Does not include members from superclasses. * Does not include members from superclasses.
*/ */
FunctionNode getAnInstanceMember(MemberKind kind) { result = impl.getAnInstanceMember(kind) } FunctionNode getAnInstanceMember(MemberKind kind) {
result = this.(ClassNode::Range).getAnInstanceMember(kind)
}
/** /**
* Gets an instance method, getter, or setter declared in this class. * Gets an instance method, getter, or setter declared in this class.
* *
* Does not include members from superclasses. * Does not include members from superclasses.
*/ */
FunctionNode getAnInstanceMember() { result = impl.getAnInstanceMember(_) } FunctionNode getAnInstanceMember() { result = this.(ClassNode::Range).getAnInstanceMember(_) }
/** /**
* Gets the static method declared in this class with the given name. * Gets the static method declared in this class with the given name.
*/ */
FunctionNode getStaticMethod(string name) { result = impl.getStaticMethod(name) } FunctionNode getStaticMethod(string name) {
result = this.(ClassNode::Range).getStaticMethod(name)
}
/** /**
* Gets a static method declared in this class. * Gets a static method declared in this class.
* *
* The constructor is not considered a static method. * The constructor is not considered a static method.
*/ */
FunctionNode getAStaticMethod() { result = impl.getAStaticMethod() } FunctionNode getAStaticMethod() { result = this.(ClassNode::Range).getAStaticMethod() }
/** /**
* Gets a dataflow node that refers to the superclass of this class. * Gets a dataflow node that refers to the superclass of this class.
*/ */
DataFlow::Node getASuperClassNode() { result = impl.getASuperClassNode() } DataFlow::Node getASuperClassNode() { result = this.(ClassNode::Range).getASuperClassNode() }
/** /**
* Gets a direct super class of this class. * Gets a direct super class of this class.
@@ -1065,13 +1065,13 @@ class ClassNode extends DataFlow::SourceNode {
* Gets the type annotation for the field `fieldName`, if any. * Gets the type annotation for the field `fieldName`, if any.
*/ */
TypeAnnotation getFieldTypeAnnotation(string fieldName) { TypeAnnotation getFieldTypeAnnotation(string fieldName) {
result = impl.getFieldTypeAnnotation(fieldName) result = this.(ClassNode::Range).getFieldTypeAnnotation(fieldName)
} }
/** /**
* Gets a decorator applied to this class. * Gets a decorator applied to this class.
*/ */
DataFlow::Node getADecorator() { result = impl.getADecorator() } DataFlow::Node getADecorator() { result = this.(ClassNode::Range).getADecorator() }
} }
module ClassNode { module ClassNode {
@@ -1357,10 +1357,7 @@ module ClassNode {
* _.partial(fn, x, y, z) * _.partial(fn, x, y, z)
* ``` * ```
*/ */
class PartialInvokeNode extends DataFlow::Node { class PartialInvokeNode extends DataFlow::Node instanceof PartialInvokeNode::Range {
PartialInvokeNode::Range range;
PartialInvokeNode() { this = 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() {
@@ -1373,26 +1370,26 @@ class PartialInvokeNode extends DataFlow::Node {
* Holds if `argument` is passed as argument `index` to the function in `callback`. * Holds if `argument` is passed as argument `index` to the function in `callback`.
*/ */
predicate isPartialArgument(DataFlow::Node callback, DataFlow::Node argument, int index) { predicate isPartialArgument(DataFlow::Node callback, DataFlow::Node argument, int index) {
range.isPartialArgument(callback, argument, index) this.(PartialInvokeNode::Range).isPartialArgument(callback, argument, index)
} }
/** /**
* Gets a node referring to a bound version of `callback` with `boundArgs` arguments bound. * Gets a node referring to a bound version of `callback` with `boundArgs` arguments bound.
*/ */
DataFlow::SourceNode getBoundFunction(DataFlow::Node callback, int boundArgs) { DataFlow::SourceNode getBoundFunction(DataFlow::Node callback, int boundArgs) {
result = range.getBoundFunction(callback, boundArgs) result = this.(PartialInvokeNode::Range).getBoundFunction(callback, boundArgs)
} }
/** /**
* Gets the node holding the receiver to be passed to the bound function, if specified. * Gets the node holding the receiver to be passed to the bound function, if specified.
*/ */
DataFlow::Node getBoundReceiver() { result = range.getBoundReceiver(_) } DataFlow::Node getBoundReceiver() { result = this.(PartialInvokeNode::Range).getBoundReceiver(_) }
/** /**
* Gets the node holding the receiver to be passed to the bound function, if specified. * Gets the node holding the receiver to be passed to the bound function, if specified.
*/ */
DataFlow::Node getBoundReceiver(DataFlow::Node callback) { DataFlow::Node getBoundReceiver(DataFlow::Node callback) {
result = range.getBoundReceiver(callback) result = this.(PartialInvokeNode::Range).getBoundReceiver(callback)
} }
} }

View File

@@ -32,10 +32,7 @@ module Cheerio {
* Creation of `cheerio` object, a collection of virtual DOM elements * Creation of `cheerio` object, a collection of virtual DOM elements
* with an interface similar to that of a jQuery object. * with an interface similar to that of a jQuery object.
*/ */
class CheerioObjectCreation extends DataFlow::SourceNode { class CheerioObjectCreation extends DataFlow::SourceNode instanceof CheerioObjectCreation::Range {
CheerioObjectCreation::Range range;
CheerioObjectCreation() { this = range }
} }
module CheerioObjectCreation { module CheerioObjectCreation {

View File

@@ -18,25 +18,22 @@ import javascript
* To model additional APIs, extend `ClientRequest::Range` and implement its abstract member * To model additional APIs, extend `ClientRequest::Range` and implement its abstract member
* predicates. * predicates.
*/ */
class ClientRequest extends DataFlow::InvokeNode { class ClientRequest extends DataFlow::InvokeNode instanceof ClientRequest::Range {
ClientRequest::Range self;
ClientRequest() { this = self }
/** /**
* Gets the URL of the request. * Gets the URL of the request.
*/ */
DataFlow::Node getUrl() { result = self.getUrl() } DataFlow::Node getUrl() { result = this.(ClientRequest::Range).getUrl() }
/** /**
* Gets the host of the request. * Gets the host of the request.
*/ */
DataFlow::Node getHost() { result = self.getHost() } DataFlow::Node getHost() { result = this.(ClientRequest::Range).getHost() }
/** /**
* Gets a node that contributes to the data-part this request. * Gets a node that contributes to the data-part this request.
*/ */
DataFlow::Node getADataNode() { result = self.getADataNode() } DataFlow::Node getADataNode() { result = this.(ClientRequest::Range).getADataNode() }
/** /**
* Gets a data flow node that refers to some representation of the response, possibly * Gets a data flow node that refers to some representation of the response, possibly
@@ -60,7 +57,7 @@ class ClientRequest extends DataFlow::InvokeNode {
* - Any value provided by custom implementations of `ClientRequest::Range`. * - Any value provided by custom implementations of `ClientRequest::Range`.
*/ */
DataFlow::Node getAResponseDataNode(string responseType, boolean promise) { DataFlow::Node getAResponseDataNode(string responseType, boolean promise) {
result = self.getAResponseDataNode(responseType, promise) result = this.(ClientRequest::Range).getAResponseDataNode(responseType, promise)
} }
/** /**
@@ -72,7 +69,7 @@ class ClientRequest extends DataFlow::InvokeNode {
/** /**
* Gets a data-flow node that determines where in the file-system the result of the request should be saved. * Gets a data-flow node that determines where in the file-system the result of the request should be saved.
*/ */
DataFlow::Node getASavePath() { result = self.getASavePath() } DataFlow::Node getASavePath() { result = this.(ClientRequest::Range).getASavePath() }
} }
deprecated class CustomClientRequest = ClientRequest::Range; deprecated class CustomClientRequest = ClientRequest::Range;

View File

@@ -8,10 +8,7 @@ import javascript
* A call to a function that constructs a function composition `f(g(h(...)))` from a * A call to a function that constructs a function composition `f(g(h(...)))` from a
* series functions `f, g, h, ...`. * series functions `f, g, h, ...`.
*/ */
class FunctionCompositionCall extends DataFlow::CallNode { class FunctionCompositionCall extends DataFlow::CallNode instanceof FunctionCompositionCall::Range {
FunctionCompositionCall::Range range;
FunctionCompositionCall() { this = range }
/** /**
* Gets the `i`th function in the composition `f(g(h(...)))`, counting from left to right. * Gets the `i`th function in the composition `f(g(h(...)))`, counting from left to right.
@@ -19,7 +16,9 @@ class FunctionCompositionCall extends DataFlow::CallNode {
* Note that this is the opposite of the order in which the function are invoked, * Note that this is the opposite of the order in which the function are invoked,
* that is, `g` occurs later than `f` in `f(g(...))` but is invoked before `f`. * that is, `g` occurs later than `f` in `f(g(...))` but is invoked before `f`.
*/ */
DataFlow::Node getOperandNode(int i) { result = range.getOperandNode(i) } DataFlow::Node getOperandNode(int i) {
result = this.(FunctionCompositionCall::Range).getOperandNode(i)
}
/** Gets a node holding one of the functions to be composed. */ /** Gets a node holding one of the functions to be composed. */
final DataFlow::Node getAnOperandNode() { result = getOperandNode(_) } final DataFlow::Node getAnOperandNode() { result = getOperandNode(_) }
@@ -38,7 +37,7 @@ class FunctionCompositionCall extends DataFlow::CallNode {
final DataFlow::Node getAnOperandFunction() { result = getOperandFunction(_) } final DataFlow::Node getAnOperandFunction() { result = getOperandFunction(_) }
/** Gets the number of functions being composed. */ /** Gets the number of functions being composed. */
int getNumOperand() { result = range.getNumOperand() } int getNumOperand() { result = this.(FunctionCompositionCall::Range).getNumOperand() }
} }
/** /**

View File

@@ -181,8 +181,7 @@ module Electron {
/** /**
* A Node.js-style HTTP or HTTPS request made using an Electron module. * A Node.js-style HTTP or HTTPS request made using an Electron module.
*/ */
class ElectronClientRequest extends NodeJSLib::NodeJSClientRequest { class ElectronClientRequest extends NodeJSLib::NodeJSClientRequest instanceof ElectronClientRequest::Range {
override ElectronClientRequest::Range self;
} }
module ElectronClientRequest { module ElectronClientRequest {

View File

@@ -68,40 +68,40 @@ module EventEmitter {
* An EventEmitter instance that implements the EventEmitter API. * An EventEmitter instance that implements the EventEmitter API.
* Extend EventEmitter::Range to mark something as being an EventEmitter. * Extend EventEmitter::Range to mark something as being an EventEmitter.
*/ */
class EventEmitter extends DataFlow::Node { class EventEmitter extends DataFlow::Node instanceof EventEmitter::Range {
EventEmitter::Range range;
EventEmitter() { this = range }
} }
/** /**
* A registration of an event handler on an EventEmitter. * A registration of an event handler on an EventEmitter.
*/ */
class EventRegistration extends DataFlow::Node { class EventRegistration extends DataFlow::Node instanceof EventRegistration::Range {
EventRegistration::Range range;
EventRegistration() { this = range }
/** Gets the EventEmitter that the event handler is registered on. */ /** Gets the EventEmitter that the event handler is registered on. */
final EventEmitter getEmitter() { result = range.getEmitter() } final EventEmitter getEmitter() { result = this.(EventRegistration::Range).getEmitter() }
/** Gets the name of the channel if possible. */ /** Gets the name of the channel if possible. */
string getChannel() { result = range.getChannel() } string getChannel() { result = this.(EventRegistration::Range).getChannel() }
/** Gets the `i`th parameter in the event handler. */ /** Gets the `i`th parameter in the event handler. */
DataFlow::Node getReceivedItem(int i) { result = range.getReceivedItem(i) } DataFlow::Node getReceivedItem(int i) {
result = this.(EventRegistration::Range).getReceivedItem(i)
}
/** /**
* Gets a value that is returned by the event handler. * Gets a value that is returned by the event handler.
* The default implementation is that no value can be returned. * The default implementation is that no value can be returned.
*/ */
DataFlow::Node getAReturnedValue() { result = range.getAReturnedValue() } DataFlow::Node getAReturnedValue() {
result = this.(EventRegistration::Range).getAReturnedValue()
}
/** /**
* Get a dispatch that this event handler can return a value to. * Get a dispatch that this event handler can return a value to.
* The default implementation is that there exists no such dispatch. * The default implementation is that there exists no such dispatch.
*/ */
EventDispatch getAReturnDispatch() { result = range.getAReturnDispatch() } EventDispatch getAReturnDispatch() {
result = this.(EventRegistration::Range).getAReturnDispatch()
}
} }
module EventRegistration { module EventRegistration {
@@ -140,26 +140,23 @@ module EventRegistration {
/** /**
* A dispatch of an event on an EventEmitter. * A dispatch of an event on an EventEmitter.
*/ */
class EventDispatch extends DataFlow::Node { class EventDispatch extends DataFlow::Node instanceof EventDispatch::Range {
EventDispatch::Range range;
EventDispatch() { this = range }
/** Gets the emitter that the event dispatch happens on. */ /** Gets the emitter that the event dispatch happens on. */
EventEmitter getEmitter() { result = range.getEmitter() } EventEmitter getEmitter() { result = this.(EventDispatch::Range).getEmitter() }
/** Gets the name of the channel if possible. */ /** Gets the name of the channel if possible. */
string getChannel() { result = range.getChannel() } string getChannel() { result = this.(EventDispatch::Range).getChannel() }
/** Gets the `i`th argument that is send to the event handler. */ /** Gets the `i`th argument that is send to the event handler. */
DataFlow::Node getSentItem(int i) { result = range.getSentItem(i) } DataFlow::Node getSentItem(int i) { result = this.(EventDispatch::Range).getSentItem(i) }
/** /**
* Get an EventRegistration that this event dispatch can send an event to. * Get an EventRegistration that this event dispatch can send an event to.
* The default implementation is that the emitters of the dispatch and registration have to be equal. * The default implementation is that the emitters of the dispatch and registration have to be equal.
* Channels are by default ignored. * Channels are by default ignored.
*/ */
EventRegistration getAReceiver() { result = range.getAReceiver() } EventRegistration getAReceiver() { result = this.(EventDispatch::Range).getAReceiver() }
} }
module EventDispatch { module EventDispatch {

View File

@@ -540,16 +540,13 @@ module HTTP {
/** /**
* An object that contains one or more potential route handlers. * An object that contains one or more potential route handlers.
*/ */
class RouteHandlerCandidateContainer extends DataFlow::Node { class RouteHandlerCandidateContainer extends DataFlow::Node instanceof RouteHandlerCandidateContainer::Range {
RouteHandlerCandidateContainer::Range self;
RouteHandlerCandidateContainer() { this = self }
/** /**
* Gets the route handler in this container that is accessed at `access`. * Gets the route handler in this container that is accessed at `access`.
*/ */
DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) { DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) {
result = self.getRouteHandler(access) result = this.(RouteHandlerCandidateContainer::Range).getRouteHandler(access)
} }
} }

View File

@@ -831,8 +831,7 @@ module NodeJSLib {
* A data flow node that is an HTTP or HTTPS client request made by a Node.js application, * A data flow node that is an HTTP or HTTPS client request made by a Node.js application,
* for example `http.request(url)`. * for example `http.request(url)`.
*/ */
class NodeJSClientRequest extends ClientRequest { class NodeJSClientRequest extends ClientRequest instanceof NodeJSClientRequest::Range {
override NodeJSClientRequest::Range self;
} }
module NodeJSClientRequest { module NodeJSClientRequest {

View File

@@ -14,20 +14,17 @@ import javascript
* To model additional APIs, extend `PropertyProjection::Range` and implement its abstract member * To model additional APIs, extend `PropertyProjection::Range` and implement its abstract member
* predicates. * predicates.
*/ */
class PropertyProjection extends DataFlow::CallNode { class PropertyProjection extends DataFlow::CallNode instanceof PropertyProjection::Range {
PropertyProjection::Range self;
PropertyProjection() { this = self }
/** /**
* Gets the argument for the object to project properties from, such as `o` in `_.get(o, 'a.b')`. * Gets the argument for the object to project properties from, such as `o` in `_.get(o, 'a.b')`.
*/ */
DataFlow::Node getObject() { result = self.getObject() } DataFlow::Node getObject() { result = this.(PropertyProjection::Range).getObject() }
/** /**
* Gets an argument that selects the properties to project, such as `'a.b'` in `_.get(o, 'a.b')`. * Gets an argument that selects the properties to project, such as `'a.b'` in `_.get(o, 'a.b')`.
*/ */
DataFlow::Node getASelector() { result = self.getASelector() } DataFlow::Node getASelector() { result = this.(PropertyProjection::Range).getASelector() }
/** /**
* Holds if this call returns the value of a single projected property, as opposed to an object that can contain multiple projected properties. * Holds if this call returns the value of a single projected property, as opposed to an object that can contain multiple projected properties.
@@ -36,7 +33,7 @@ class PropertyProjection extends DataFlow::CallNode {
* - This predicate holds for `_.get({a: 'b'}, 'a')`, which returns `'b'`, * - This predicate holds for `_.get({a: 'b'}, 'a')`, which returns `'b'`,
* - This predicate does not hold for `_.pick({a: 'b', c: 'd'}}, 'a')`, which returns `{a: 'b'}`, * - This predicate does not hold for `_.pick({a: 'b', c: 'd'}}, 'a')`, which returns `{a: 'b'}`,
*/ */
predicate isSingletonProjection() { self.isSingletonProjection() } predicate isSingletonProjection() { this.(PropertyProjection::Range).isSingletonProjection() }
} }
module PropertyProjection { module PropertyProjection {

View File

@@ -56,10 +56,7 @@ module Redux {
/** /**
* Creation of a redux store, usually via a call to `createStore`. * Creation of a redux store, usually via a call to `createStore`.
*/ */
class StoreCreation extends DataFlow::SourceNode { class StoreCreation extends DataFlow::SourceNode instanceof StoreCreation::Range {
StoreCreation::Range range;
StoreCreation() { this = range }
/** Gets a reference to the store. */ /** Gets a reference to the store. */
DataFlow::SourceNode ref() { result = asApiNode().getAUse() } DataFlow::SourceNode ref() { result = asApiNode().getAUse() }
@@ -68,7 +65,7 @@ module Redux {
API::Node asApiNode() { result.getAnImmediateUse() = this } API::Node asApiNode() { result.getAnImmediateUse() = this }
/** Gets the data flow node holding the root reducer for this store. */ /** Gets the data flow node holding the root reducer for this store. */
DataFlow::Node getReducerArg() { result = range.getReducerArg() } DataFlow::Node getReducerArg() { result = this.(StoreCreation::Range).getReducerArg() }
/** Gets a data flow node referring to the root reducer. */ /** Gets a data flow node referring to the root reducer. */
DataFlow::SourceNode getAReducerSource() { result = getReducerArg().(ReducerArg).getASource() } DataFlow::SourceNode getAReducerSource() { result = getReducerArg().(ReducerArg).getASource() }
@@ -423,13 +420,10 @@ module Redux {
* Some action creators dispatch the action to a store, while for others, the value is returned and it is simply assumed to be dispatched * Some action creators dispatch the action to a store, while for others, the value is returned and it is simply assumed to be dispatched
* at some point. We model all action creators as if they dispatch the action they create. * at some point. We model all action creators as if they dispatch the action they create.
*/ */
class ActionCreator extends DataFlow::SourceNode { class ActionCreator extends DataFlow::SourceNode instanceof ActionCreator::Range {
ActionCreator::Range range;
ActionCreator() { this = range }
/** Gets the `type` property of actions created by this action creator, if it is known. */ /** Gets the `type` property of actions created by this action creator, if it is known. */
string getTypeTag() { result = range.getTypeTag() } string getTypeTag() { result = this.(ActionCreator::Range).getTypeTag() }
/** /**
* Gets the middleware function that transforms arguments passed to this function into the * Gets the middleware function that transforms arguments passed to this function into the
@@ -442,7 +436,7 @@ module Redux {
* the action payload. Otherwise, the return value is the payload itself. * the action payload. Otherwise, the return value is the payload itself.
*/ */
DataFlow::FunctionNode getMiddlewareFunction(boolean async) { DataFlow::FunctionNode getMiddlewareFunction(boolean async) {
result = range.getMiddlewareFunction(async) result = this.(ActionCreator::Range).getMiddlewareFunction(async)
} }
/** Gets a data flow node referring to this action creator. */ /** Gets a data flow node referring to this action creator. */

View File

@@ -14,13 +14,10 @@ module ShellJS {
} }
/** A member of the `shelljs` library. */ /** A member of the `shelljs` library. */
class Member extends DataFlow::SourceNode { class Member extends DataFlow::SourceNode instanceof Member::Range {
Member::Range range;
Member() { this = range }
/** Gets the name of `shelljs` member being referenced, such as `cat` in `shelljs.cat`. */ /** Gets the name of `shelljs` member being referenced, such as `cat` in `shelljs.cat`. */
string getName() { result = range.getName() } string getName() { result = this.(Member::Range).getName() }
} }
module Member { module Member {