1111
1212import csharp
1313import semmle.code.csharp.frameworks.System
14+ import semmle.code.csharp.frameworks.system.Collections
15+ import semmle.code.csharp.frameworks.system.collections.Generic
1416
15- predicate dictionary ( ConstructedType constructed ) {
16- exists ( UnboundGenericType dict |
17- dict .hasFullyQualifiedName ( "System.Collections.Generic" , "Dictionary`2" ) and
18- constructed = dict .getAConstructedGeneric ( )
17+ /**
18+ * Holds if `t` is a dictionary type.
19+ */
20+ predicate dictionary ( ValueOrRefType t ) {
21+ exists ( Type base | base = t .getABaseType * ( ) .getUnboundDeclaration ( ) |
22+ base instanceof SystemCollectionsGenericIDictionaryInterface or
23+ base instanceof SystemCollectionsGenericIReadOnlyDictionaryInterface or
24+ base instanceof SystemCollectionsIDictionaryInterface
1925 )
2026}
2127
22- predicate hashtable ( Class c ) { c .hasFullyQualifiedName ( "System.Collections" , "Hashtable" ) }
28+ /**
29+ * Holds if `c` is a hashset type.
30+ */
31+ predicate hashSet ( ValueOrRefType t ) {
32+ t .getABaseType * ( ) .getUnboundDeclaration ( ) instanceof SystemCollectionsGenericHashSetClass
33+ }
2334
24- predicate hashstructure ( Type t ) { hashtable ( t ) or dictionary ( t ) }
35+ predicate hashStructure ( Type t ) { dictionary ( t ) or hashSet ( t ) }
2536
26- predicate hashAdd ( Expr e ) {
37+ /**
38+ * Holds if the expression `e` relies on `GetHashCode()` implementation.
39+ * That is, if the call assumes that `e1.Equals(e2)` implies `e1.GetHashCode() == e2.GetHashCode()`.
40+ */
41+ predicate usesHashing ( Expr e ) {
2742 exists ( MethodCall mc , string name |
28- ( name = "Add" or name = "ContainsKey" ) and
43+ name = [ "Add" , "Contains" , "ContainsKey" , "Remove" , "TryAdd" , "TryGetValue" ] and
2944 mc .getArgument ( 0 ) = e and
3045 mc .getTarget ( ) .hasName ( name ) and
31- hashstructure ( mc .getTarget ( ) .getDeclaringType ( ) )
46+ hashStructure ( mc .getTarget ( ) .getDeclaringType ( ) )
47+ )
48+ or
49+ exists ( IndexerCall ic |
50+ ic .getArgument ( 0 ) = e and
51+ dictionary ( ic .getTarget ( ) .getDeclaringType ( ) )
3252 )
3353}
3454
@@ -46,7 +66,7 @@ predicate hashCall(Expr e) {
4666
4767from Expr e , Type t
4868where
49- ( hashAdd ( e ) or hashCall ( e ) ) and
69+ ( usesHashing ( e ) or hashCall ( e ) ) and
5070 e .getType ( ) = t and
5171 eqWithoutHash ( t )
5272select e ,
0 commit comments