package tracematches;

import java.util.*;

public class ASyncIteration {
	
	
	public static void main(String[] args) {
		
		final Collection c = new ArrayList();
		Collection sc = Collections.synchronizedCollection(c); //this needs to stay

		synchronized (sc) {
			//this is ok but not recognized statically as such
			Iterator iter = sc.iterator();
			System.err.println("ok");
		}
		
		//this not
		Iterator iter = sc.iterator();
		
		//this is ok
		final Collection c1 = new ArrayList();
		Iterator iter1 = c1.iterator();
	}
	
	
	
	
	/**
	 * Tests a property mentioned in (see {@link Collections#synchronizedCollection(Collection)}),
	 * which says that one should only iterate over a synchronized collection from within
	 * a synchronized block.
	 */
	
	static aspect SyncCheck{
		
		/*
		 * Those tracechecks check that one does not directly access a Map or Collection
		 * that has been put into Collections.synchronized*(..).
		 */		
		
		pointcut createSync(): call(* Collections.synchr*(..));
		
		//most common supertype of Map anc Collection is Object unfortunately
		tracematch(Object sync) {
			
			sym sync after returning(sync): createSync();
			
			sym asyncIteration before: call(* Collection+.iterator()) && target(sync) && if(!Thread.holdsLock(sync));			

			sync asyncIteration {
				if(System.getProperty("TMTEST_ACTIVE")!=null) {
					throw new IllegalStateException("Collection "+System.identityHashCode(sync)+
						" is synchronized. You may only iterate from within a synchronized block.");
				}
			}
			
		}

	}
			
}