package tracematches; import java.util.*; public aspect HashSetTest { /** * This version is better in a way that it checks if the modification really changed the hash code * of the collection in question. Also it works for arbitrary objects, not just collections. * BUT it uses let(). */ tracematch(HashSet s, Object o, int hashCode) { sym add before : call(* Collection.add(Object)) && target(s) && args(o) && let(hashCode, o.hashCode()); sym remove before : call(* Collection.remove(Object)) && target(s) && args(o); sym cont before: call(* Collection.contai*(..)) && target(s) && args(o); add cont { if(hashCode!=o.hashCode()) { if(System.getProperty("TMTEST_ACTIVE")!=null) { System.out.println("HashCode changed for Object "+o+" while being in a HashSet."); } } } } } class RealTest { public static void main(String[] args) { Set s = new HashSet(); Collection c = new ArrayList(); //safe, but not detected s.add(c); s.remove(c); System.out.println("allowed modification"); c.add("allowed modification");//is removed due to inconsistent typing (something is added to an ArrayList, not a HashSet) System.out.println(s.contains(c)); c.clear(); //unsafe s.add(c); System.out.println("this should trigger an error"); c.add("this should trigger an error");//is removed due to inconsistent typing (something is added to an ArrayList, not a HashSet) System.out.println(s.contains(c)); //safe Collection c2 = new ArrayList(); s.contains(c2); //safe Set s2 = new HashSet(); s2.contains(c); } }