Skip to content

Commit 1eb0ca4

Browse files
committed
JS: make ClassNode::Range abstract
1 parent 3cb2341 commit 1eb0ca4

1 file changed

Lines changed: 82 additions & 49 deletions

File tree

  • javascript/ql/src/semmle/javascript/dataflow

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

Lines changed: 82 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ class ClassNode extends DataFlow::SourceNode {
502502
/**
503503
* Gets a description of the class.
504504
*/
505-
string desribe() { result = impl.describe() }
505+
string describe() { result = impl.describe() }
506506

507507
/**
508508
* Gets the constructor function of this class.
@@ -535,79 +535,88 @@ class ClassNode extends DataFlow::SourceNode {
535535
}
536536

537537
module ClassNode {
538-
class Range extends DataFlow::SourceNode, DataFlow::ValueNode {
539-
Range() {
540-
astNode instanceof ClassDefinition
541-
or
542-
astNode instanceof Function and
543-
exists(getAPropertyReference("prototype"))
544-
}
545-
538+
/**
539+
* A dataflow node that should be considered a class node.
540+
*
541+
* Subclass this to introduce new kinds of class nodes. If you want to refine
542+
* the definition of existing class nodes, subclass `DataFlow::ClassNode` instead.
543+
*/
544+
abstract class Range extends DataFlow::SourceNode {
546545
/**
547546
* Gets the name of the class, if it has one.
548547
*/
549-
string getName() {
550-
result = astNode.(ClassDefinition).getName()
551-
or
552-
result = astNode.(Function).getName()
553-
}
548+
abstract string getName();
554549

555550
/**
556551
* Gets a description of the class.
557552
*/
558-
string describe() {
559-
result = astNode.(ClassDefinition).describe()
560-
or
561-
result = astNode.(Function).describe()
562-
}
553+
abstract string describe();
563554

564555
/**
565556
* Gets the constructor function of this class.
566557
*/
567-
FunctionNode getConstructor() {
568-
result = astNode.(ClassDefinition).getConstructor().getBody().flow()
569-
or
570-
result = this
571-
}
558+
abstract FunctionNode getConstructor();
572559

573560
/**
574561
* Gets an instance method with the given name, if any.
575562
*/
576-
FunctionNode getInstanceMethod(string name) {
563+
abstract FunctionNode getInstanceMethod(string name);
564+
565+
/**
566+
* Gets an instance method of this class.
567+
*
568+
* The constructor is not considered an instance method.
569+
*/
570+
abstract FunctionNode getAnInstanceMethod();
571+
572+
/**
573+
* Gets the static method of this class with the given name.
574+
*/
575+
abstract FunctionNode getStaticMethod(string name);
576+
577+
/**
578+
* Gets a static method of this class.
579+
*
580+
* The constructor is not considered a static method.
581+
*/
582+
abstract FunctionNode getAStaticMethod();
583+
}
584+
585+
/**
586+
* An ES6 class as a `ClassNode` instance.
587+
*/
588+
private class ES6Class extends Range, DataFlow::ValueNode {
589+
override ClassDefinition astNode;
590+
591+
override string getName() { result = astNode.getName() }
592+
593+
override string describe() { result = astNode.describe() }
594+
595+
override FunctionNode getConstructor() { result = astNode.getConstructor().getBody().flow() }
596+
597+
override FunctionNode getInstanceMethod(string name) {
577598
exists(MethodDeclaration method |
578-
method = astNode.(ClassDefinition).getMethod(name) and
599+
method = astNode.getMethod(name) and
579600
not method.isStatic() and
580601
not method.isAmbient() and
581602
not method instanceof ConstructorDeclaration and
582603
result = method.getBody().flow()
583604
)
584-
or
585-
result = getAPrototypeReference().getAPropertyWrite(name).getRhs().getALocalSource()
586605
}
587606

588-
/**
589-
* Gets an instance method of this class.
590-
*
591-
* The constructor is not considered an instance method.
592-
*/
593-
FunctionNode getAnInstanceMethod() {
607+
override FunctionNode getAnInstanceMethod() {
594608
exists(MethodDeclaration method |
595-
method = astNode.(ClassDefinition).getAMethod() and
609+
method = astNode.getAMethod() and
596610
not method.isStatic() and
597611
not method.isAmbient() and
598612
not method instanceof ConstructorDeclaration and
599613
result = method.getBody().flow()
600614
)
601-
or
602-
result = getAPrototypeReference().getAPropertyWrite().getRhs().getALocalSource()
603615
}
604616

605-
/**
606-
* Gets the static method of this class with the given name.
607-
*/
608-
FunctionNode getStaticMethod(string name) {
617+
override FunctionNode getStaticMethod(string name) {
609618
exists(MethodDeclaration method |
610-
method = astNode.(ClassDefinition).getMethod(name) and
619+
method = astNode.getMethod(name) and
611620
method.isStatic() and
612621
not method.isAmbient() and
613622
result = method.getBody().flow()
@@ -616,19 +625,43 @@ module ClassNode {
616625
result = getAPropertyWrite(name).getRhs().getALocalSource()
617626
}
618627

619-
/**
620-
* Gets a static method of this class.
621-
*
622-
* The constructor is not considered a static method.
623-
*/
624-
FunctionNode getAStaticMethod() {
628+
override FunctionNode getAStaticMethod() {
625629
exists(MethodDeclaration method |
626630
method = astNode.(ClassDefinition).getAMethod() and
627631
method.isStatic() and
628632
not method.isAmbient() and
629633
result = method.getBody().flow()
630634
)
631-
or
635+
}
636+
}
637+
638+
/**
639+
* A function definition with prototype manipulation as a `ClassNode` instance.
640+
*/
641+
class FunctionStyleClass extends Range, DataFlow::ValueNode {
642+
override Function astNode;
643+
644+
FunctionStyleClass() { exists(getAPropertyReference("prototype")) }
645+
646+
override string getName() { result = astNode.getName() }
647+
648+
override string describe() { result = astNode.describe() }
649+
650+
override FunctionNode getConstructor() { result = this }
651+
652+
override FunctionNode getInstanceMethod(string name) {
653+
result = getAPrototypeReference().getAPropertyWrite(name).getRhs().getALocalSource()
654+
}
655+
656+
override FunctionNode getAnInstanceMethod() {
657+
result = getAPrototypeReference().getAPropertyWrite().getRhs().getALocalSource()
658+
}
659+
660+
override FunctionNode getStaticMethod(string name) {
661+
result = getAPropertyWrite(name).getRhs().getALocalSource()
662+
}
663+
664+
override FunctionNode getAStaticMethod() {
632665
result = getAPropertyWrite().getRhs().getALocalSource()
633666
}
634667

0 commit comments

Comments
 (0)