Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ef60057

Browse files
committed
Python: Add API graph support for subclasses
1 parent b39cbf8 commit ef60057

2 files changed

Lines changed: 30 additions & 0 deletions

File tree

python/ql/src/semmle/python/ApiGraphs.qll

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ module API {
9292
*/
9393
Node getReturn() { result = getASuccessor(Label::return()) }
9494

95+
/**
96+
* Gets a node representing a subclass of the class represented by this node.
97+
*/
98+
Node getASubclass() { result = getASuccessor(Label::subclass()) }
99+
95100
/**
96101
* Gets a string representation of the lexicographically least among all shortest access paths
97102
* from the root to this node.
@@ -358,6 +363,12 @@ module API {
358363
// Calling a node that is a use of `base`
359364
lbl = Label::return() and
360365
ref = pred.getACall()
366+
or
367+
// Subclassing a node
368+
lbl = Label::subclass() and
369+
exists(DataFlow::Node superclass | pred.flowsTo(superclass) |
370+
ref.asExpr().(ClassExpr).getABase() = superclass.asExpr()
371+
)
361372
)
362373
}
363374

@@ -468,4 +479,6 @@ private module Label {
468479

469480
/** Gets the `return` edge label. */
470481
string return() { result = "getReturn()" }
482+
483+
string subclass() { result = "getASubclass()" }
471484
}

python/ql/test/experimental/dataflow/ApiGraphs/test.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,20 @@ def f():
7979
from unknown import * #$ use=moduleImport("unknown")
8080

8181
hello() #$ MISSING: use=moduleImport("unknown").getMember("hello").getReturn()
82+
83+
84+
# Subclasses
85+
86+
from flask.views import View #$ use=moduleImport("flask").getMember("views").getMember("View")
87+
88+
class MyView(View): #$ use=moduleImport("flask").getMember("views").getMember("View").getASubclass()
89+
pass
90+
91+
instance = MyView() #$ use=moduleImport("flask").getMember("views").getMember("View").getASubclass().getReturn()
92+
93+
def internal():
94+
from pflask.views import View #$ use=moduleImport("pflask").getMember("views").getMember("View")
95+
class IntMyView(View): #$ use=moduleImport("pflask").getMember("views").getMember("View").getASubclass()
96+
pass
97+
98+
int_instance = IntMyView() #$ use=moduleImport("pflask").getMember("views").getMember("View").getASubclass().getReturn()

0 commit comments

Comments
 (0)