@@ -16,7 +16,7 @@ import python
1616 * For sequences, the index must be an int, which are hashable, so we don't need to treat them specially.
1717 * For numpy arrays, the index may be a list, which are not hashable and needs to be treated specially.
1818 */
19-
19+
2020predicate numpy_array_type ( ClassObject na ) {
2121 exists ( ModuleObject np | np .getName ( ) = "numpy" or np .getName ( ) = "numpy.core" |
2222 na .getAnImproperSuperType ( ) = np .getAttribute ( "ndarray" )
@@ -51,9 +51,31 @@ predicate is_unhashable(ControlFlowNode f, ClassObject cls, ControlFlowNode orig
5151 )
5252}
5353
54+ /**
55+ * Holds if `f` is inside a `try` that catches `TypeError`. For example:
56+ *
57+ * try:
58+ * ... f ...
59+ * except TypeError:
60+ * ...
61+ *
62+ * This predicate is used to eliminate false positive results. If `hash`
63+ * is called on an unhashable object then a `TypeError` will be thrown.
64+ * But this is not a bug if the code catches the `TypeError` and handles
65+ * it.
66+ */
67+ predicate typeerror_is_caught ( ControlFlowNode f ) {
68+ exists ( Try try , CheckClass c |
69+ try .getBody ( ) .contains ( f .getNode ( ) ) and
70+ c .getName ( ) = "TypeError" and
71+ try .getAHandler ( ) .getType ( ) .refersTo ( c ) )
72+ }
73+
5474from ControlFlowNode f , ClassObject c , ControlFlowNode origin
55- where
56- explicitly_hashed ( f ) and is_unhashable ( f , c , origin )
57- or
58- unhashable_subscript ( f , c , origin )
75+ where
76+ not typeerror_is_caught ( f )
77+ and
78+ ( explicitly_hashed ( f ) and is_unhashable ( f , c , origin )
79+ or
80+ unhashable_subscript ( f , c , origin ) )
5981select f .getNode ( ) , "This $@ of $@ is unhashable." , origin , "instance" , c , c .getQualifiedName ( )
0 commit comments