@@ -3,7 +3,6 @@ private import semmle.python.pointsto.PointsTo
33
44/** Helper class for UndefinedClassAttribute.ql and MaybeUndefinedClassAttribute.ql */
55class CheckClass extends ClassObject {
6-
76 private predicate ofInterest ( ) {
87 not this .unknowableAttributes ( ) and
98 not this .getPyClass ( ) .isProbableMixin ( ) and
@@ -19,7 +18,8 @@ class CheckClass extends ClassObject {
1918 forall ( ClassObject sup |
2019 sup = this .getAnImproperSuperType ( ) and
2120 sup .declaresAttribute ( "__init__" ) and
22- not sup = theObjectType ( ) |
21+ not sup = theObjectType ( )
22+ |
2323 sup .declaredAttribute ( "__init__" ) instanceof PyFunctionObject
2424 )
2525 }
@@ -32,108 +32,111 @@ class CheckClass extends ClassObject {
3232 }
3333
3434 predicate sometimesDefines ( string name ) {
35- this .alwaysDefines ( name ) or
36- exists ( SelfAttributeStore sa |
37- sa .getScope ( ) .getScope + ( ) = this .getAnImproperSuperType ( ) .getPyClass ( ) |
35+ this .alwaysDefines ( name )
36+ or
37+ exists ( SelfAttributeStore sa |
38+ sa .getScope ( ) .getScope + ( ) = this .getAnImproperSuperType ( ) .getPyClass ( )
39+ |
3840 name = sa .getName ( )
3941 )
4042 }
4143
4244 private predicate selfDictAssigns ( ) {
43- exists ( Assign a , SelfAttributeRead self_dict , Subscript sub |
45+ exists ( Assign a , SelfAttributeRead self_dict , Subscript sub |
4446 self_dict .getName ( ) = "__dict__" and
45- (
46- self_dict = sub .getObject ( )
47- or
48- /* Indirect assignment via temporary variable */
49- exists ( SsaVariable v |
50- v .getAUse ( ) = sub .getObject ( ) .getAFlowNode ( ) and
51- v .getDefinition ( ) .( DefinitionNode ) .getValue ( ) = self_dict .getAFlowNode ( )
52- )
47+ (
48+ self_dict = sub .getObject ( )
49+ or
50+ /* Indirect assignment via temporary variable */
51+ exists ( SsaVariable v |
52+ v .getAUse ( ) = sub .getObject ( ) .getAFlowNode ( ) and
53+ v .getDefinition ( ) .( DefinitionNode ) .getValue ( ) = self_dict .getAFlowNode ( )
54+ )
5355 ) and
5456 a .getATarget ( ) = sub and
55- exists ( FunctionObject meth | meth = this .lookupAttribute ( _) and a .getScope ( ) = meth .getFunction ( ) )
57+ exists ( FunctionObject meth |
58+ meth = this .lookupAttribute ( _) and a .getScope ( ) = meth .getFunction ( )
59+ )
5660 )
5761 }
5862
59- pragma [ nomagic]
63+ pragma [ nomagic]
6064 private predicate monkeyPatched ( string name ) {
6165 exists ( Attribute a |
62- a .getCtx ( ) instanceof Store and
63- PointsTo:: points_to ( a .getObject ( ) .getAFlowNode ( ) , _, this , _, _) and a .getName ( ) = name
66+ a .getCtx ( ) instanceof Store and
67+ PointsTo:: points_to ( a .getObject ( ) .getAFlowNode ( ) , _, this , _, _) and
68+ a .getName ( ) = name
6469 )
6570 }
6671
6772 private predicate selfSetattr ( ) {
68- exists ( Call c , Name setattr , Name self , Function method |
69- ( method .getScope ( ) = this .getPyClass ( ) or
70- method .getScope ( ) = this .getASuperType ( ) .getPyClass ( )
71- ) and
72- c .getScope ( ) = method and
73- c .getFunc ( ) = setattr and
74- setattr .getId ( ) = "setattr" and
75- c .getArg ( 0 ) = self and
76- self .getId ( ) = "self"
77- )
73+ exists ( Call c , Name setattr , Name self , Function method |
74+ (
75+ method .getScope ( ) = this .getPyClass ( ) or
76+ method .getScope ( ) = this .getASuperType ( ) .getPyClass ( )
77+ ) and
78+ c .getScope ( ) = method and
79+ c .getFunc ( ) = setattr and
80+ setattr .getId ( ) = "setattr" and
81+ c .getArg ( 0 ) = self and
82+ self .getId ( ) = "self"
83+ )
7884 }
7985
80- predicate interestingUndefined ( SelfAttributeRead a ) {
81- exists ( string name | name = a .getName ( ) |
82- interestingContext ( a , name ) and
83- not this .definedInBlock ( a .getAFlowNode ( ) .getBasicBlock ( ) , name )
84- )
85- }
86-
87- private predicate interestingContext ( SelfAttributeRead a , string name ) {
88- name = a .getName ( ) and
89- this .ofInterest ( ) and
90- this .getPyClass ( ) = a .getScope ( ) .getScope ( ) and
91- not a .locallyDefined ( ) and
92- not a .guardedByHasattr ( ) and
93- a .getScope ( ) .isPublic ( ) and
94- not this .monkeyPatched ( name ) and
95- not attribute_assigned_in_method ( lookupAttribute ( "setUp" ) , name )
96- }
86+ predicate interestingUndefined ( SelfAttributeRead a ) {
87+ exists ( string name | name = a .getName ( ) |
88+ interestingContext ( a , name ) and
89+ not this .definedInBlock ( a .getAFlowNode ( ) .getBasicBlock ( ) , name )
90+ )
91+ }
9792
98- private predicate probablyAbstract ( ) {
99- this .getName ( ) .matches ( "Abstract%" )
100- or
101- this .isAbstract ( )
102- }
93+ private predicate interestingContext ( SelfAttributeRead a , string name ) {
94+ name = a .getName ( ) and
95+ this .ofInterest ( ) and
96+ this .getPyClass ( ) = a .getScope ( ) .getScope ( ) and
97+ not a .locallyDefined ( ) and
98+ not a .guardedByHasattr ( ) and
99+ a .getScope ( ) .isPublic ( ) and
100+ not this .monkeyPatched ( name ) and
101+ not attribute_assigned_in_method ( lookupAttribute ( "setUp" ) , name )
102+ }
103103
104- private pragma [ nomagic] predicate definitionInBlock ( BasicBlock b , string name ) {
105- exists ( SelfAttributeStore sa |
106- sa .getAFlowNode ( ) .getBasicBlock ( ) = b and sa .getName ( ) = name and sa .getClass ( ) = this .getPyClass ( )
107- )
108- or
109- exists ( FunctionObject method | this .lookupAttribute ( _) = method |
110- attribute_assigned_in_method ( method , name ) and
111- b = method .getACall ( ) .getBasicBlock ( )
112- )
113- }
104+ private predicate probablyAbstract ( ) {
105+ this .getName ( ) .matches ( "Abstract%" )
106+ or
107+ this .isAbstract ( )
108+ }
114109
115- private pragma [ nomagic] predicate definedInBlock ( BasicBlock b , string name ) {
116- // manual specialisation: this is only called from interestingUndefined,
117- // so we can push the context in from there, which must apply to a
118- // SelfAttributeRead in the same scope
119- exists ( SelfAttributeRead a |
120- a . getScope ( ) = b . getScope ( ) and name = a . getName ( ) |
121- interestingContext ( a , name )
122- )
123- and
124- this . definitionInBlock ( b , name )
125- or
126- exists ( BasicBlock prev | this . definedInBlock ( prev , name ) and prev . getASuccessor ( ) = b )
127- }
110+ pragma [ nomagic]
111+ private predicate definitionInBlock ( BasicBlock b , string name ) {
112+ exists ( SelfAttributeStore sa |
113+ sa . getAFlowNode ( ) . getBasicBlock ( ) = b and
114+ sa . getName ( ) = name and
115+ sa . getClass ( ) = this . getPyClass ( )
116+ )
117+ or
118+ exists ( FunctionObject method | this . lookupAttribute ( _ ) = method |
119+ attribute_assigned_in_method ( method , name ) and
120+ b = method . getACall ( ) . getBasicBlock ( )
121+ )
122+ }
128123
124+ pragma [ nomagic]
125+ private predicate definedInBlock ( BasicBlock b , string name ) {
126+ // manual specialisation: this is only called from interestingUndefined,
127+ // so we can push the context in from there, which must apply to a
128+ // SelfAttributeRead in the same scope
129+ exists ( SelfAttributeRead a | a .getScope ( ) = b .getScope ( ) and name = a .getName ( ) |
130+ interestingContext ( a , name )
131+ ) and
132+ this .definitionInBlock ( b , name )
133+ or
134+ exists ( BasicBlock prev | this .definedInBlock ( prev , name ) and prev .getASuccessor ( ) = b )
135+ }
129136}
130137
131-
132138private Object object_getattribute ( ) {
133139 result .asBuiltin ( ) = theObjectType ( ) .asBuiltin ( ) .getMember ( "__getattribute__" )
134140}
135141
136- private predicate auto_name ( string name ) {
137- name = "__class__" or name = "__dict__"
138- }
139-
142+ private predicate auto_name ( string name ) { name = "__class__" or name = "__dict__" }
0 commit comments