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

Skip to content

Commit 15bc4cd

Browse files
committed
Python: Add override helpers to Value classes
1 parent aba3ac7 commit 15bc4cd

4 files changed

Lines changed: 89 additions & 0 deletions

File tree

python/ql/src/semmle/python/objects/ObjectAPI.qll

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,18 @@ class Value extends TObject {
105105
or
106106
this instanceof AbsentModuleAttributeObjectInternal
107107
}
108+
109+
/** Whether this overrides v. In this context, "overrides" means that this object
110+
* is a named attribute of a some class C and `v` is a named attribute of another
111+
* class S, both attributes having the same name, and S is a super class of C.
112+
*/
113+
predicate overrides(Value v) {
114+
exists(ClassValue my_class, ClassValue other_class, string name |
115+
my_class.declaredAttribute(name) = this and
116+
other_class.declaredAttribute(name) = v and
117+
my_class.getABaseType+() = other_class
118+
)
119+
}
108120
}
109121

110122
/** Class representing modules in the Python program
@@ -461,6 +473,14 @@ abstract class FunctionValue extends CallableValue {
461473

462474
/** Gets the maximum number of parameters that can be correctly passed to this function */
463475
abstract int maxParameters();
476+
477+
predicate isOverridingMethod() {
478+
exists(Value f | this.overrides(f))
479+
}
480+
481+
predicate isOverriddenMethod() {
482+
exists(Value f | f.overrides(this))
483+
}
464484
}
465485

466486
/** Class representing Python functions */
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
| test.py:3:5:3:20 | Function Wat.upper | overriding | not overridden |
2+
| test.py:6:1:6:26 | Function outside_func | not overriding | overridden |
3+
| test.py:11:11:11:29 | Function Base.lambda | not overriding | overridden |
4+
| test.py:13:24:13:36 | Function Base.lambda | not overriding | not overridden |
5+
| test.py:17:5:17:21 | Function Base.normal | not overriding | overridden |
6+
| test.py:28:5:28:21 | Function Sub2.foo | overriding | overridden |
7+
| test.py:31:5:31:24 | Function Sub2.tricky | overriding | not overridden |
8+
| test.py:36:5:36:21 | Function Sub2Sub.foo | overriding | not overridden |
9+
| test.py:39:5:39:18 | Function Sub2Sub.baz | overriding | not overridden |
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import python
2+
3+
from PythonFunctionValue f, string overriding, string overridden
4+
where
5+
(if f.isOverridingMethod() then overriding = "overriding" else overriding = "not overriding") and
6+
(if f.isOverriddenMethod() then overridden = "overridden" else overridden = "not overridden")
7+
select f, overriding, overridden
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
class Wat(str):
2+
3+
def upper(self):
4+
return self.lower()
5+
6+
def outside_func(self, x):
7+
print(x)
8+
9+
class Base(object):
10+
11+
foo = lambda self, x: x+1
12+
13+
bar = staticmethod(lambda x: x+1)
14+
15+
baz = 123
16+
17+
def normal(self):
18+
pass
19+
20+
tricky = outside_func
21+
22+
class Sub(Base):
23+
24+
normal = False
25+
26+
class Sub2(Base):
27+
28+
def foo(self, y):
29+
return y * 100
30+
31+
def tricky(self, x):
32+
print('nice!', x)
33+
34+
class Sub2Sub(Sub2):
35+
36+
def foo(self, z):
37+
return z / 123
38+
39+
def baz(self):
40+
print('python is a bit crazy sometimes')
41+
42+
43+
ws = Wat('asdf')
44+
print(ws.upper(), len(ws))
45+
46+
b = Base()
47+
print(b.foo(1))
48+
print(b.bar(10))
49+
50+
51+
ss = SubSub()
52+
print(ss.foo(1))
53+
ss.baz()

0 commit comments

Comments
 (0)