@@ -11,12 +11,18 @@ private import TObject
1111private import semmle.python.objects.ObjectInternal
1212private import semmle.python.pointsto.PointsTo
1313private import semmle.python.pointsto.PointsToContext
14+ private import semmle.python.pointsto.MRO
1415
1516/* Use the term `ObjectSource` to refer to DB entity. Either a CFG node
1617 * for Python objects, or `@py_cobject` entity for built-in objects.
1718 */
1819class ObjectSource = Object ;
1920
21+ /* Aliases for scopes */
22+ class FunctionScope = Function ;
23+ class ClassScope = Class ;
24+ class ModuleScope = Module ;
25+
2026/** Class representing values in the Python program
2127 * Each `Value` is a static approximation to a set of one or more real objects.
2228 */
@@ -41,7 +47,7 @@ class Value extends TObject {
4147 * Strictly, the `Value` representing the class of the objects
4248 * represented by this Value.
4349 */
44- Value getClass ( ) {
50+ ClassValue getClass ( ) {
4551 result = this .( ObjectInternal ) .getClass ( )
4652 }
4753
@@ -87,6 +93,21 @@ class Value extends TObject {
8793 this .( ObjectInternal ) .isMissing ( )
8894 }
8995
96+ predicate hasLocationInfo ( string filepath , int bl , int bc , int el , int ec ) {
97+ this .( ObjectInternal ) .getOrigin ( ) .getLocation ( ) .hasLocationInfo ( filepath , bl , bc , el , ec )
98+ or
99+ not exists ( this .( ObjectInternal ) .getOrigin ( ) ) and
100+ filepath = "" and bl = 0 and bc = 0 and el = 0 and ec = 0
101+ }
102+
103+ /** Gets the name of this value, if it has one.
104+ * Note this is the innate name of the
105+ * object, not necessarily all the names by which it can be called.
106+ */
107+ final string getName ( ) {
108+ result = this .( ObjectInternal ) .getName ( )
109+ }
110+
90111}
91112
92113/** Class representing modules in the Python program
@@ -110,37 +131,63 @@ class ModuleValue extends Value {
110131 py_exports ( this .getScope ( ) , name )
111132 }
112133
113- /** Gets the name of this module */
114- string getName ( ) {
115- result = this .( ModuleObjectInternal ) .getName ( )
116- }
117-
118134 /** Gets the scope for this module, provided that it is a Python module. */
119- Module getScope ( ) {
135+ ModuleScope getScope ( ) {
120136 result = this .( ModuleObjectInternal ) .getSourceModule ( )
121137 }
122138
139+ /** Gets the container path for this module. Will be the file for a Python module,
140+ * the folder for a package and no result for a builtin module.
141+ */
142+ Container getPath ( ) {
143+ result = this .( PackageObjectInternal ) .getFolder ( )
144+ or
145+ result = this .( PythonModuleObjectInternal ) .getSourceModule ( ) .getFile ( )
146+ }
147+
123148}
124149
125150module Module {
126151
127- /** Gets the `ModuleValue` named `name` */
152+ /** Gets the `ModuleValue` named `name`.
153+ *
154+ * Note that the name used to refer to a module is not
155+ * necessarily its name. For example,
156+ * there are modules refered to by the name `os.path`,
157+ * but that are not named `os.path`, for example the module `posixpath`.
158+ * Such that the follwing is true:
159+ * `Module::named("os.path").getName() = "posixpath"
160+ */
128161 ModuleValue named ( string name ) {
129162 result .getName ( ) = name
163+ or
164+ result = named ( name , _)
165+ }
166+
167+ /* Prevent runaway recursion when a module has itself as an attribute. */
168+ private ModuleValue named ( string name , int dots ) {
169+ dots = 0 and not name .charAt ( _) = "." and
170+ result .getName ( ) = name
171+ or
172+ dots <= 3 and
173+ exists ( string modname , string attrname |
174+ name = modname + "." + attrname |
175+ result = named ( modname , dots - 1 ) .attr ( attrname )
176+ )
130177 }
131178
132179}
133180
134181module Value {
135182
136183 /** Gets the `Value` named `name`.
137- * If has at least one '.' in `name`, then the part of
184+ * If there is at least one '.' in `name`, then the part of
138185 * the name to the left of the rightmost '.' is interpreted as a module name
139186 * and the part after the rightmost '.' as an attribute of that module.
140- * For example, `Value::named("os.path.join")` is the `Value` representing the function
141- * `join` in the module `os.path`.
187+ * For example, `Value::named("os.path.join")` is the `Value` representing the
188+ * `join` function of the `os.path` module .
142189 * If there is no '.' in `name`, then the `Value` returned is the builtin
143- * object of that name.
190+ * object of that name.
144191 * For example `Value::named("len")` is the `Value` representing the `len` built-in function.
145192 */
146193 Value named ( string name ) {
@@ -150,6 +197,12 @@ module Value {
150197 )
151198 or
152199 result = ObjectInternal:: builtin ( name )
200+ or
201+ name = "None" and result = ObjectInternal:: none_ ( )
202+ or
203+ name = "True" and result = TTrue ( )
204+ or
205+ name = "False" and result = TFalse ( )
153206 }
154207
155208}
@@ -171,9 +224,8 @@ class CallableValue extends Value {
171224 this .( CallableObjectInternal ) .neverReturns ( )
172225 }
173226
174-
175227 /** Gets the scope for this function, provided that it is a Python function. */
176- Function getScope ( ) {
228+ FunctionScope getScope ( ) {
177229 result = this .( PythonFunctionObjectInternal ) .getScope ( )
178230 }
179231
@@ -252,5 +304,63 @@ class ClassValue extends Value {
252304 this .( ClassObjectInternal ) .lookup ( name , result , _)
253305 }
254306
307+ predicate isCallable ( ) {
308+ this .( ClassObjectInternal ) .lookup ( "__call__" , _, _)
309+ }
310+
311+ /** Gets the qualified name for this class.
312+ * Should return the same name as the `__qualname__` attribute on classes in Python 3.
313+ */
314+ string getQualifiedName ( ) {
315+ result = this .( ClassObjectInternal ) .getBuiltin ( ) .getName ( )
316+ or
317+ result = this .( PythonClassObjectInternal ) .getScope ( ) .getQualifiedName ( )
318+ }
319+
320+ /** Gets the MRO for this class */
321+ MRO getMro ( ) {
322+ result = Types:: getMro ( this )
323+ }
324+
325+ predicate failedInference ( string reason ) {
326+ Types:: failedInference ( this , reason )
327+ }
328+
329+ /** Gets the nth base class of this class */
330+ ClassValue getBaseType ( int n ) {
331+ result = Types:: getBase ( this , n )
332+ }
333+
334+ /** Holds if this class is a new style class.
335+ A new style class is one that implicitly or explicitly inherits from `object`. */
336+ predicate isNewStyle ( ) {
337+ Types:: isNewStyle ( this )
338+ }
339+
340+ /** Holds if this class is an old style class.
341+ An old style class is one that does not inherit from `object`. */
342+ predicate isOldStyle ( ) {
343+ Types:: isOldStyle ( this )
344+ }
345+
346+ /** Gets the scope associated with this class, if it is not a builtin class */
347+ ClassScope getScope ( ) {
348+ result = this .( PythonClassObjectInternal ) .getScope ( )
349+ }
350+
351+ }
352+
353+ /** A method-resolution-order sequence of classes */
354+ class MRO extends TClassList {
355+
356+ string toString ( ) {
357+ result = this .( ClassList ) .toString ( )
358+ }
359+
360+ /** Gets the `n`th class in this MRO */
361+ ClassValue getItem ( int n ) {
362+ result = this .( ClassList ) .getItem ( n )
363+ }
364+
255365}
256366
0 commit comments