@@ -12,6 +12,7 @@ private import semmle.python.objects.ObjectInternal
1212private import semmle.python.pointsto.PointsTo
1313private import semmle.python.pointsto.PointsToContext
1414private import semmle.python.pointsto.MRO
15+ private import semmle.python.types.Builtins
1516
1617/* Use the term `ObjectSource` to refer to DB entity. Either a CFG node
1718 * for Python objects, or `@py_cobject` entity for built-in objects.
@@ -85,7 +86,7 @@ class Value extends TObject {
8586 filepath = "" and bl = 0 and bc = 0 and el = 0 and ec = 0
8687 }
8788
88- /** Gets the name of this value, if it has one.
89+ /** Gets the name of this value, if it has one.
8990 * Note this is the innate name of the
9091 * object, not necessarily all the names by which it can be called.
9192 */
@@ -228,7 +229,7 @@ class CallableValue extends Value {
228229 cached ControlFlowNode getArgumentForCall ( CallNode call , int n ) {
229230 exists ( ObjectInternal called , int offset |
230231 PointsToInternal:: pointsTo ( call .getFunction ( ) , _, called , _) and
231- called .functionAndOffset ( this , offset )
232+ called .functionAndOffset ( this , offset )
232233 |
233234 call .getArg ( n - offset ) = result
234235 or
@@ -316,13 +317,13 @@ class ClassValue extends Value {
316317 result = Types:: getBase ( this , n )
317318 }
318319
319- /** Holds if this class is a new style class.
320+ /** Holds if this class is a new style class.
320321 A new style class is one that implicitly or explicitly inherits from `object`. */
321322 predicate isNewStyle ( ) {
322323 Types:: isNewStyle ( this )
323324 }
324325
325- /** Holds if this class is an old style class.
326+ /** Holds if this class is an old style class.
326327 An old style class is one that does not inherit from `object`. */
327328 predicate isOldStyle ( ) {
328329 Types:: isOldStyle ( this )
@@ -333,6 +334,20 @@ class ClassValue extends Value {
333334 result = this .( PythonClassObjectInternal ) .getScope ( )
334335 }
335336
337+ /** Holds if this class has the attribute `name`, including
338+ * attributes declared by super classes.
339+ */
340+ predicate hasAttribute ( string name ) {
341+ this .getMro ( ) .declares ( name )
342+ }
343+
344+ /** Holds if this class declares the attribute `name`,
345+ * *not* including attributes declared by super classes.
346+ */
347+ predicate declaresAttribute ( string name ) {
348+ this .( ClassObjectInternal ) .getClassDeclaration ( ) .declaresAttribute ( name )
349+ }
350+
336351}
337352
338353/** A method-resolution-order sequence of classes */
@@ -347,5 +362,87 @@ class MRO extends TClassList {
347362 result = this .( ClassList ) .getItem ( n )
348363 }
349364
365+ /** Holds if any class in this MRO declares the attribute `name` */
366+ predicate declares ( string name ) {
367+ this .( ClassList ) .declares ( name )
368+ }
369+
370+ /** Gets the length of this MRO */
371+ int length ( ) {
372+ result = this .( ClassList ) .length ( )
373+ }
374+
375+ /** Holds if this MRO contains `cls` */
376+ predicate contains ( ClassValue cls ) {
377+ this .( ClassList ) .contains ( cls )
378+ }
379+
380+ /** Gets the value from scanning for the attribute `name` in this MRO. */
381+ Value lookup ( string name ) {
382+ this .( ClassList ) .lookup ( name , result , _)
383+ }
384+
385+ /** Gets the MRO formed by removing all classes before `cls`
386+ * from this MRO.
387+ */
388+ MRO startingAt ( ClassValue cls ) {
389+ result = this .( ClassList ) .startingAt ( cls )
390+ }
391+
350392}
351393
394+
395+ module ClassValue {
396+
397+ /** Get the `ClassValue` for the `bool` class. */
398+ ClassValue bool ( ) {
399+ result = TBuiltinClassObject ( Builtin:: special ( "bool" ) )
400+ }
401+
402+ /** Get the `ClassValue` for the class of Python functions. */
403+ ClassValue function ( ) {
404+ result = TBuiltinClassObject ( Builtin:: special ( "FunctionType" ) )
405+ }
406+
407+ /** Get the `ClassValue` for the class of builtin functions. */
408+ ClassValue builtinFunction ( ) {
409+ result = Value:: named ( "len" ) .getClass ( )
410+ }
411+
412+ /** Get the `ClassValue` for the `int` class. */
413+ ClassValue int_ ( ) {
414+ result = TBuiltinClassObject ( Builtin:: special ( "int" ) )
415+ }
416+
417+ /** Get the `ClassValue` for the `float` class. */
418+ ClassValue float_ ( ) {
419+ result = TBuiltinClassObject ( Builtin:: builtin ( "float" ) )
420+ }
421+
422+ /** Get the `ClassValue` for the `bytes` class (also called `str` in Python 2). */
423+ ClassValue bytes ( ) {
424+ result = TBuiltinClassObject ( Builtin:: special ( "bytes" ) )
425+ }
426+
427+ /** Get the `ClassValue` for the class of unicode strings.
428+ * `str` in Python 3 and `unicode` in Python 2. */
429+ ClassValue unicode ( ) {
430+ result = TBuiltinClassObject ( Builtin:: special ( "unicode" ) )
431+ }
432+
433+ /** Get the `ClassValue` for the `classmethod` class. */
434+ ClassValue classmethod ( ) {
435+ result = TBuiltinClassObject ( Builtin:: special ( "ClassMethod" ) )
436+ }
437+
438+ /** Get the `ClassValue` for the `staticmethod` class. */
439+ ClassValue staticmethod ( ) {
440+ result = TBuiltinClassObject ( Builtin:: special ( "StaticMethod" ) )
441+ }
442+
443+ /** Get the `ClassValue` for the class of modules. */
444+ ClassValue module_ ( ) {
445+ result = TBuiltinClassObject ( Builtin:: special ( "ModuleType" ) )
446+ }
447+
448+ }
0 commit comments