import java.util.concurrent.locks.ReentrantLock;
import org.checkerframework.checker.lock.qual.GuardedBy;
import org.checkerframework.checker.lock.qual.GuardedByUnknown;

public class TestConcurrentSemantics1 {
  /* This class tests the following critical scenario.
   *
   * Suppose the following lines from method1 are executed on thread A.
   *
   * <pre>{@code
   * @GuardedBy("lock1") MyClass local;
   * m = local;
   * }</pre>
   *
   * Then a context switch occurs to method2 on thread B and the following lines are executed:
   *
   * <pre>{@code
   * @GuardedBy("lock2") MyClass local;
   * m = local;
   * }</pre>
   *
   * Then a context switch back to method1 on thread A occurs and the following lines are executed:
   *
   * <pre>{@code
   * lock1.lock();
   * m.field = new Object();
   * }</pre>
   *
   * In this case, it is absolutely critical that the dereference above not be allowed.
   *
   */

  @GuardedByUnknown MyClass m;
  final ReentrantLock lock1 = new ReentrantLock();
  final ReentrantLock lock2 = new ReentrantLock();

  void method1() {
    @GuardedBy("lock1") MyClass local = new MyClass();
    m = local;
    lock1.lock();
    // :: error: (lock.not.held)
    m.field = new Object();
  }

  void method2() {
    @GuardedBy("lock2") MyClass local = new MyClass();
    m = local;
  }

  class MyClass {
    Object field = new Object();
  }
}
