JS: introduce DataFlow::ClassNode

This commit is contained in:
Asger F
2019-01-11 16:46:45 +00:00
parent 4398670ecc
commit 5b7675d972
7 changed files with 162 additions and 0 deletions

View File

@@ -465,3 +465,138 @@ DataFlow::SourceNode moduleMember(string path, string m) {
result = DataFlow::ssaDefinitionNode(ssa)
)
}
/**
* A data flow node corresponding to a class definition or a function definition
* acting as a class.
*
* The following patterns are recognized as classes and methods:
* ```
* class C {
* method()
* }
*
* function F() {}
*
* F.prototype.method = function() {}
*
* F.prototype = {
* method: function() {}
* }
*
* extend(F.prototype, {
* method: function() {}
* });
* ```
*/
class ClassNode extends DataFlow::SourceNode, DataFlow::ValueNode {
ClassNode() {
astNode instanceof ClassDefinition
or
astNode instanceof Function and
exists(getAPropertyReference("prototype"))
}
/**
* Gets the name of the class, if it has one.
*/
string getName() {
result = astNode.(ClassDefinition).getName()
or
result = astNode.(Function).getName()
}
/**
* Gets a description of the class.
*/
string describe() {
result = astNode.(ClassDefinition).describe()
or
result = astNode.(Function).describe()
}
/**
* Gets the constructor function of this class.
*/
FunctionNode getConstructor() {
result = astNode.(ClassDefinition).getConstructor().getBody().flow()
or
result = this
}
/**
* Gets an instance method with the given name, if any.
*/
FunctionNode getInstanceMethod(string name) {
exists(MethodDeclaration method |
method = astNode.(ClassDefinition).getMethod(name) and
not method.isStatic() and
not method.isAmbient() and
not method instanceof ConstructorDeclaration and
result = method.getBody().flow()
)
or
result = getAPrototypeReference().getAPropertyWrite(name).getRhs().getALocalSource()
}
/**
* Gets an instance method of this class.
*
* The constructor is not considered an instance method.
*/
FunctionNode getAnInstanceMethod() {
exists(MethodDeclaration method |
method = astNode.(ClassDefinition).getAMethod() and
not method.isStatic() and
not method.isAmbient() and
not method instanceof ConstructorDeclaration and
result = method.getBody().flow()
)
or
result = getAPrototypeReference().getAPropertyWrite().getRhs().getALocalSource()
}
/**
* Gets the static method of this class with the given name.
*/
FunctionNode getStaticMethod(string name) {
exists(MethodDeclaration method |
method = astNode.(ClassDefinition).getMethod(name) and
method.isStatic() and
not method.isAmbient() and
result = method.getBody().flow()
)
or
result = getAPropertyWrite(name).getRhs().getALocalSource()
}
/**
* Gets a static method of this class.
*
* The constructor is not considered a static method.
*/
FunctionNode getAStaticMethod() {
exists(MethodDeclaration method |
method = astNode.(ClassDefinition).getAMethod() and
method.isStatic() and
not method.isAmbient() and
result = method.getBody().flow()
)
or
result = getAPropertyWrite().getRhs().getALocalSource()
}
/**
* Gets a reference to the prototype of this class.
*/
private DataFlow::SourceNode getAPrototypeReference() {
result = getAPropertyRead("prototype")
or
result = getAPropertySource("prototype")
or
exists(ExtendCall call |
call.getDestinationOperand() = getAPropertyRead("prototype") and
result = call.getASourceOperand()
)
}
}