@@ -7,25 +7,31 @@ predicate comparison_using_is(Compare comp, ControlFlowNode left, Cmpop op, Cont
77 )
88}
99
10- predicate overrides_eq_or_cmp ( ClassObject c ) {
10+ predicate overrides_eq_or_cmp ( ClassValue c ) {
1111 major_version ( ) = 2 and c .hasAttribute ( "__eq__" )
1212 or
13- c .declaresAttribute ( "__eq__" ) and not c = theObjectType ( )
13+ c .declaresAttribute ( "__eq__" ) and not c = Value :: named ( "object" )
1414 or
15- exists ( ClassObject sup |
16- sup = c .getASuperType ( ) and not sup = theObjectType ( ) |
15+ exists ( ClassValue sup |
16+ sup = c .getASuperType ( ) and not sup = Value :: named ( "object" ) |
1717 sup .declaresAttribute ( "__eq__" )
1818 )
1919 or
2020 major_version ( ) = 2 and c .hasAttribute ( "__cmp__" )
2121}
2222
23- predicate invalid_to_use_is_portably ( ClassObject c ) {
23+ predicate probablySingleton ( ClassValue cls ) {
24+ strictcount ( Value inst | inst .getClass ( ) = cls ) = 1
25+ or
26+ cls = Value:: named ( "None" ) .getClass ( )
27+ }
28+
29+ predicate invalid_to_use_is_portably ( ClassValue c ) {
2430 overrides_eq_or_cmp ( c ) and
2531 /* Exclude type/builtin-function/bool as it is legitimate to compare them using 'is' but they implement __eq__ */
26- not c = theTypeType ( ) and not c = theBuiltinFunctionType ( ) and not c = theBoolType ( ) and
32+ not c = Value :: named ( "type" ) and not c = ClassValue :: builtinFunction ( ) and not c = Value :: named ( "bool" ) and
2733 /* OK to compare with 'is' if a singleton */
28- not exists ( c . getProbableSingletonInstance ( ) )
34+ not probablySingleton ( c )
2935}
3036
3137predicate simple_constant ( ControlFlowNode f ) {
@@ -72,30 +78,30 @@ predicate universally_interned_constant(Expr e) {
7278 )
7379}
7480
75- private predicate comparison_both_types ( Compare comp , Cmpop op , ClassObject cls1 , ClassObject cls2 ) {
81+ private predicate comparison_both_types ( Compare comp , Cmpop op , ClassValue cls1 , ClassValue cls2 ) {
7682 exists ( ControlFlowNode op1 , ControlFlowNode op2 |
7783 comparison_using_is ( comp , op1 , op , op2 ) or comparison_using_is ( comp , op2 , op , op1 ) |
78- op1 .refersTo ( _ , cls1 , _ ) and
79- op2 .refersTo ( _ , cls2 , _ )
84+ op1 .inferredValue ( ) . getClass ( ) = cls1 and
85+ op2 .inferredValue ( ) . getClass ( ) = cls2
8086 )
8187}
8288
83- private predicate comparison_one_type ( Compare comp , Cmpop op , ClassObject cls ) {
89+ private predicate comparison_one_type ( Compare comp , Cmpop op , ClassValue cls ) {
8490 not comparison_both_types ( comp , _, _, _) and
8591 exists ( ControlFlowNode operand |
8692 comparison_using_is ( comp , operand , op , _) or comparison_using_is ( comp , _, op , operand ) |
87- operand .refersTo ( _ , cls , _ )
93+ operand .inferredValue ( ) . getClass ( ) = cls
8894 )
8995}
9096
91- predicate invalid_portable_is_comparison ( Compare comp , Cmpop op , ClassObject cls ) {
97+ predicate invalid_portable_is_comparison ( Compare comp , Cmpop op , ClassValue cls ) {
9298 /* OK to use 'is' when defining '__eq__' */
9399 not exists ( Function eq | eq .getName ( ) = "__eq__" or eq .getName ( ) = "__ne__" | eq = comp .getScope ( ) .getScope * ( ) )
94100 and
95101 (
96102 comparison_one_type ( comp , op , cls ) and invalid_to_use_is_portably ( cls )
97103 or
98- exists ( ClassObject other | comparison_both_types ( comp , op , cls , other ) |
104+ exists ( ClassValue other | comparison_both_types ( comp , op , cls , other ) |
99105 invalid_to_use_is_portably ( cls ) and
100106 invalid_to_use_is_portably ( other )
101107 )
@@ -123,9 +129,9 @@ predicate invalid_portable_is_comparison(Compare comp, Cmpop op, ClassObject cls
123129}
124130
125131private predicate enum_member ( AstNode obj ) {
126- exists ( ClassObject cls , AssignStmt asgn |
132+ exists ( ClassValue cls , AssignStmt asgn |
127133 cls .getASuperType ( ) .getName ( ) = "Enum" |
128- cls .getPyClass ( ) = asgn .getScope ( ) and
134+ cls .getScope ( ) = asgn .getScope ( ) and
129135 asgn .getValue ( ) = obj
130136 )
131137}
0 commit comments