Skip to content

Commit e18b635

Browse files
committed
JS: add getADirectSuperClass()
1 parent c82690f commit e18b635

File tree

6 files changed

+72
-0
lines changed

6 files changed

+72
-0
lines changed

javascript/ql/src/semmle/javascript/dataflow/Nodes.qll

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,18 @@ class ClassNode extends DataFlow::SourceNode {
538538
* The constructor is not considered a static method.
539539
*/
540540
FunctionNode getAStaticMethod() { result = impl.getAStaticMethod() }
541+
542+
/**
543+
* Gets a direct super class of this class.
544+
*/
545+
ClassNode getADirectSuperClass() {
546+
result.getConstructor().getAstNode() = impl
547+
.getASuperClassNode()
548+
.analyze()
549+
.getAValue()
550+
.(AbstractCallable)
551+
.getFunction()
552+
}
541553
}
542554

543555
module ClassNode {
@@ -586,6 +598,12 @@ module ClassNode {
586598
* The constructor is not considered a static method.
587599
*/
588600
abstract FunctionNode getAStaticMethod();
601+
602+
/**
603+
* Gets a dataflow node representing a class to be used as the super-class
604+
* of this node.
605+
*/
606+
abstract DataFlow::Node getASuperClassNode();
589607
}
590608

591609
/**
@@ -635,6 +653,8 @@ module ClassNode {
635653
result = method.getBody().flow()
636654
)
637655
}
656+
657+
override DataFlow::Node getASuperClassNode() { result = astNode.getSuperClass().flow() }
638658
}
639659

640660
/**
@@ -680,5 +700,22 @@ module ClassNode {
680700
result = call.getASourceOperand()
681701
)
682702
}
703+
704+
override DataFlow::Node getASuperClassNode() {
705+
// C.prototype = Object.create(D.prototype)
706+
exists(DataFlow::InvokeNode objectCreate, DataFlow::PropRead superProto |
707+
getAPropertySource("prototype") = objectCreate and
708+
objectCreate = DataFlow::globalVarRef("Object").getAMemberCall("create") and
709+
superProto.flowsTo(objectCreate.getArgument(0)) and
710+
superProto.getPropertyName() = "prototype" and
711+
result = superProto.getBase()
712+
)
713+
or
714+
// C.prototype = new D()
715+
exists(DataFlow::NewNode newCall |
716+
getAPropertySource("prototype") = newCall and
717+
result = newCall.getCalleeNode()
718+
)
719+
}
683720
}
684721
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
| tst.js:4:17:4:21 | () {} | A.instanceMethod |
2+
| tst.js:7:6:7:10 | () {} | A.bar |
3+
| tst.js:15:19:15:31 | function() {} | B.foo |
4+
| tst.js:19:19:19:31 | function() {} | C.bar |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import javascript
2+
3+
from DataFlow::ClassNode cls, string name
4+
select cls.getAnInstanceMethod(name), cls.getName() + "." + name
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
| tst.js:11:1:11:21 | class A ... ds A {} | A2 | tst.js:3:1:8:1 | class A ... () {}\\n} | A |
2+
| tst.js:13:1:13:15 | function B() {} | B | tst.js:3:1:8:1 | class A ... () {}\\n} | A |
3+
| tst.js:17:1:17:15 | function C() {} | C | tst.js:13:1:13:15 | function B() {} | B |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import javascript
2+
3+
from DataFlow::ClassNode cls, DataFlow::ClassNode sup
4+
where sup = cls.getADirectSuperClass()
5+
select cls, cls.getName(), sup, sup.getName()
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import * as dummy from 'dummy'; // treat as module
2+
3+
class A {
4+
instanceMethod() {}
5+
static staticMethod() {}
6+
7+
bar() {}
8+
}
9+
10+
11+
class A2 extends A {}
12+
13+
function B() {}
14+
B.prototype = Object.create(A.prototype);
15+
B.prototype.foo = function() {}
16+
17+
function C() {}
18+
C.prototype = new B();
19+
C.prototype.bar = function() {}

0 commit comments

Comments
 (0)