Standard Analyses

SemmleCode Professional comes with a wide range of pre-packaged analyses, from architectural properties and metrics, to statement-level checks for likely bugs and violations of best practice.


Hashed value without hashCode definition

This query finds classes whose values are stored in a hashing data structure, and which define an equals method but no hashCode method. The contract of the hashCode method requires that two objects that equals considers equal should have the same hash code, which is likely to be violated by such classes.

Consider the following example class:

    class Point {
        int x;
        int y;

        Point(int x, int y) {
	    this.x = x;
    	    this.y = y;
        }

        public boolean equals(Object o) {
	    if(!(o instanceof Point))
	        return false;
        	Point q = (Point)o;
	    return x == q.x && y == q.y;
        }
    }

This class defines an equals method that checks two Point objects for structural equality. For example, if we construct two objects of this class with the same coordinate values

    Point p = new Point(23, 42);
    Point q = new Point(23, 42);

then p.equals(q) will return true. However, class Point does not override the default implementation of method hashCode, hence p.hashCode() and q.hashCode() will not necessarily be equal.

This violates the contract of the hashCode method, hence objects of type Point should not be stored in hashing data structures.

How to Interpret the Query Results

The query flags any such class with a warning if it is used in what appears to be a hashing data structure, and also displays the list of generated warnings in the result view.

How to Address the Query Results

Every class that implements a custom equals method should also provide an implementation of hashCode. A possible implementation for Point is

    public int hashCode() {
        int hash = 7;
        hash = 31*hash + x;
        hash = 31*hash + y;
        return hash;
    }

Since the hash code is computed from exactly the same fields that are considered in the equals method, its contract is fulfilled. In the example, the hash code for both p and q is 7482.

Source Code
import default

/** A class that defines an equals method but no hashCode method */
class EqNoHash extends Class {
  EqNoHash() {
    this.getAMethod() instanceof EqualsMethod and
    not this.getAMethod() instanceof HashCodeMethod and
    this.getSourceDeclaration().fromSource()
  }
}

/** is e an expression in which t is used in a hashing data structure? */
predicate usedInHash(RefType t, Expr e) {
  exists(RefType s |
           s.getName().matches("%Hash%") and
           (   exists(MethodAccess ma | 
                        ma.getQualifier().getType() = s and
                        ma.getArgument(0).getType() = t and
                        e = ma) 
            or exists(ConstructorCall cc |
                        cc.getType() = s and
                        ((ParameterizedType)s).getTypeArgument(0) = t and
                        cc = e)))
}

from EqNoHash t, Expr e
where usedInHash(t, e)
select e, "Objects of this type are stored in hashing data structure, "
          + "but it does not have an explicit definition of hashCode()"
References