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.
This commit is contained in:
Rasmus Wriedt Larsen
2020-02-13 12:04:46 +01:00
parent e747add485
commit 67e9edb820
4 changed files with 64 additions and 10 deletions

View File

@@ -20,13 +20,39 @@ class PropertyInternal extends ObjectInternal, TProperty {
this = TProperty(_, _, result)
}
private CallNode getCall() { this = TProperty(result, _, _) }
/** Gets the setter function of this property */
CallableObjectInternal getSetter() {
// @x.setter
exists(CallNode call, AttrNode setter |
call.getFunction() = setter and
call.getFunction() = setter and
PointsToInternal::pointsTo(setter.getObject("setter"), this.getContext(), this, _) and
PointsToInternal::pointsTo(call.getArg(0), this.getContext(), result, _)
)
or
// x = property(getter, setter, deleter)
exists(ControlFlowNode setter_arg |
setter_arg = getCall().getArg(1) or setter_arg = getCall().getArgByName("fset")
|
PointsToInternal::pointsTo(setter_arg, this.getContext(), result, _)
)
}
/** Gets the setter function of this property */
CallableObjectInternal getDeleter() {
exists(CallNode call, AttrNode setter |
call.getFunction() = setter and
PointsToInternal::pointsTo(setter.getObject("deleter"), this.getContext(), this, _) and
PointsToInternal::pointsTo(call.getArg(0), this.getContext(), result, _)
)
or
// x = property(getter, setter, deleter)
exists(ControlFlowNode deleter_arg |
deleter_arg = getCall().getArg(2) or deleter_arg = getCall().getArgByName("fdel")
|
PointsToInternal::pointsTo(deleter_arg, this.getContext(), result, _)
)
}
private Context getContext() { this = TProperty(_,result, _) }

View File

@@ -669,6 +669,34 @@ class NumericValue extends Value {
}
}
/** A Python property:
* @property
* def f():
* ....
*
* https://docs.python.org/3/howto/descriptor.html#properties
* https://docs.python.org/3/library/functions.html#property
*/
class PropertyValue extends Value {
PropertyValue() {
this instanceof PropertyInternal
}
CallableValue getGetter(){
result = this.(PropertyInternal).getGetter()
}
CallableValue getSetter(){
result = this.(PropertyInternal).getSetter()
}
CallableValue getDeleter(){
result = this.(PropertyInternal).getDeleter()
}
}
/** A method-resolution-order sequence of classes */
class MRO extends TClassList {

View File

@@ -1,8 +1,8 @@
| test.py:6:5:6:16 | Function x | getter | test.py:5:6:5:13 | Property x |
| test.py:11:5:11:23 | Function x | setter | test.py:5:6:5:13 | Property x |
| test.py:15:5:15:16 | Function x | deleter | test.py:5:6:5:13 | Property x |
| test.py:21:5:21:16 | Function x | getter | test.py:20:6:20:13 | Property x |
| test.py:28:5:28:19 | Function getx | getter | test.py:37:9:37:59 | Property getx |
| test.py:31:5:31:26 | Function setx | setter | test.py:37:9:37:59 | Property getx |
| test.py:34:5:34:19 | Function delx | deleter | test.py:37:9:37:59 | Property getx |
| test.py:41:5:41:19 | Function getx | getter | test.py:44:9:44:22 | Property getx |
| test.py:6:5:6:16 | Function WithDecorator.x | getter | test.py:5:6:5:13 | property x |
| test.py:11:5:11:23 | Function WithDecorator.x | setter | test.py:5:6:5:13 | property x |
| test.py:15:5:15:16 | Function WithDecorator.x | deleter | test.py:5:6:5:13 | property x |
| test.py:21:5:21:16 | Function WithDecoratorOnlyGetter.x | getter | test.py:20:6:20:13 | property x |
| test.py:28:5:28:19 | Function WithoutDecorator.getx | getter | test.py:37:9:37:59 | property getx |
| test.py:31:5:31:26 | Function WithoutDecorator.setx | setter | test.py:37:9:37:59 | property getx |
| test.py:34:5:34:19 | Function WithoutDecorator.delx | deleter | test.py:37:9:37:59 | property getx |
| test.py:41:5:41:19 | Function WithoutDecoratorOnlyGetter.getx | getter | test.py:44:9:44:22 | property getx |

View File

@@ -1,7 +1,7 @@
import python
import semmle.python.types.Descriptors
from PropertyObject p, string method_name, FunctionObject method
from PropertyValue p, string method_name, FunctionValue method
where
method_name = "getter" and method = p.getGetter()
or