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

Skip to content

Commit 67e9edb

Browse files
committed
Python: Add PropertyValue
+ Extend PropertyInternal.getSetter to handle non-decorator + Add PropertyInternal.getDeleter It seems like a bit hacky way to do things, since we're not using the PropertySetterOrDeleter class at all, but for now I'll leave it be.
1 parent e747add commit 67e9edb

4 files changed

Lines changed: 64 additions & 10 deletions

File tree

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

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,39 @@ class PropertyInternal extends ObjectInternal, TProperty {
2020
this = TProperty(_, _, result)
2121
}
2222

23+
private CallNode getCall() { this = TProperty(result, _, _) }
24+
2325
/** Gets the setter function of this property */
2426
CallableObjectInternal getSetter() {
27+
// @x.setter
2528
exists(CallNode call, AttrNode setter |
26-
call.getFunction() = setter and
29+
call.getFunction() = setter and
2730
PointsToInternal::pointsTo(setter.getObject("setter"), this.getContext(), this, _) and
2831
PointsToInternal::pointsTo(call.getArg(0), this.getContext(), result, _)
2932
)
33+
or
34+
// x = property(getter, setter, deleter)
35+
exists(ControlFlowNode setter_arg |
36+
setter_arg = getCall().getArg(1) or setter_arg = getCall().getArgByName("fset")
37+
|
38+
PointsToInternal::pointsTo(setter_arg, this.getContext(), result, _)
39+
)
40+
}
41+
42+
/** Gets the setter function of this property */
43+
CallableObjectInternal getDeleter() {
44+
exists(CallNode call, AttrNode setter |
45+
call.getFunction() = setter and
46+
PointsToInternal::pointsTo(setter.getObject("deleter"), this.getContext(), this, _) and
47+
PointsToInternal::pointsTo(call.getArg(0), this.getContext(), result, _)
48+
)
49+
or
50+
// x = property(getter, setter, deleter)
51+
exists(ControlFlowNode deleter_arg |
52+
deleter_arg = getCall().getArg(2) or deleter_arg = getCall().getArgByName("fdel")
53+
|
54+
PointsToInternal::pointsTo(deleter_arg, this.getContext(), result, _)
55+
)
3056
}
3157

3258
private Context getContext() { this = TProperty(_,result, _) }

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,34 @@ class NumericValue extends Value {
669669
}
670670
}
671671

672+
/** A Python property:
673+
* @property
674+
* def f():
675+
* ....
676+
*
677+
* https://docs.python.org/3/howto/descriptor.html#properties
678+
* https://docs.python.org/3/library/functions.html#property
679+
*/
680+
class PropertyValue extends Value {
681+
682+
PropertyValue() {
683+
this instanceof PropertyInternal
684+
}
685+
686+
CallableValue getGetter(){
687+
result = this.(PropertyInternal).getGetter()
688+
}
689+
690+
CallableValue getSetter(){
691+
result = this.(PropertyInternal).getSetter()
692+
}
693+
694+
CallableValue getDeleter(){
695+
result = this.(PropertyInternal).getDeleter()
696+
}
697+
698+
}
699+
672700
/** A method-resolution-order sequence of classes */
673701
class MRO extends TClassList {
674702

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
| test.py:6:5:6:16 | Function x | getter | test.py:5:6:5:13 | Property x |
2-
| test.py:11:5:11:23 | Function x | setter | test.py:5:6:5:13 | Property x |
3-
| test.py:15:5:15:16 | Function x | deleter | test.py:5:6:5:13 | Property x |
4-
| test.py:21:5:21:16 | Function x | getter | test.py:20:6:20:13 | Property x |
5-
| test.py:28:5:28:19 | Function getx | getter | test.py:37:9:37:59 | Property getx |
6-
| test.py:31:5:31:26 | Function setx | setter | test.py:37:9:37:59 | Property getx |
7-
| test.py:34:5:34:19 | Function delx | deleter | test.py:37:9:37:59 | Property getx |
8-
| test.py:41:5:41:19 | Function getx | getter | test.py:44:9:44:22 | Property getx |
1+
| test.py:6:5:6:16 | Function WithDecorator.x | getter | test.py:5:6:5:13 | property x |
2+
| test.py:11:5:11:23 | Function WithDecorator.x | setter | test.py:5:6:5:13 | property x |
3+
| test.py:15:5:15:16 | Function WithDecorator.x | deleter | test.py:5:6:5:13 | property x |
4+
| test.py:21:5:21:16 | Function WithDecoratorOnlyGetter.x | getter | test.py:20:6:20:13 | property x |
5+
| test.py:28:5:28:19 | Function WithoutDecorator.getx | getter | test.py:37:9:37:59 | property getx |
6+
| test.py:31:5:31:26 | Function WithoutDecorator.setx | setter | test.py:37:9:37:59 | property getx |
7+
| test.py:34:5:34:19 | Function WithoutDecorator.delx | deleter | test.py:37:9:37:59 | property getx |
8+
| test.py:41:5:41:19 | Function WithoutDecoratorOnlyGetter.getx | getter | test.py:44:9:44:22 | property getx |

python/ql/test/library-tests/descriptors/Properties.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import python
22
import semmle.python.types.Descriptors
33

4-
from PropertyObject p, string method_name, FunctionObject method
4+
from PropertyValue p, string method_name, FunctionValue method
55
where
66
method_name = "getter" and method = p.getGetter()
77
or

0 commit comments

Comments
 (0)