import java.util.concurrent.locks.*;
import org.checkerframework.checker.lock.qual.*;
import org.checkerframework.framework.qual.AnnotatedFor;
public class BasicTest {
class MyClass {
public Object field;
}
MyClass myUnannotatedMethod(MyClass param) {
return param;
}
void myUnannotatedMethod2() {}
@AnnotatedFor("lock")
MyClass myAnnotatedMethod(MyClass param) {
return param;
}
@AnnotatedFor("lock")
void myAnnotatedMethod2() {}
final @GuardedBy({}) ReentrantLock lockField = new ReentrantLock();
@GuardedBy("lockField") MyClass m;
@GuardedBy({}) MyClass o1 = new MyClass(), p1;
@AnnotatedFor("lock")
@MayReleaseLocks
void testFields() {
// Test in two ways that return values are @GuardedByUnknown.
// The first way is more durable as cannot.dereference is tied specifically to @GuardedByUnknown (and @GuardedByBottom, but it is unlikely to become the default for return values on unannotated methods).
//:: error: (lock.not.held)
myUnannotatedMethod(o1).field = new Object();
// The second way is less durable because the default for fields is currently @GuardedBy({}) but
// could be changed to @GuardedByUnknown.
//:: error: (assignment.type.incompatible)
p1 = myUnannotatedMethod(o1);
// Now test that an unannotated method behaves as if it's annotated with @MayReleaseLocks
lockField.lock();
myAnnotatedMethod2();
m.field = new Object();
myUnannotatedMethod2();
//:: error: (lock.not.held)
m.field = new Object();
}
void unannotatedReleaseLock(ReentrantLock lock) {
lock.unlock();
}
@AnnotatedFor("lock")
@MayReleaseLocks
void testLocalVariables() {
MyClass o2 = new MyClass(), p2;
p2 = myUnannotatedMethod(o2);
MyClass o3 = new MyClass();
myAnnotatedMethod(o3);
// Now test that an unannotated method behaves as if it's annotated with @MayReleaseLocks
final @GuardedBy({}) ReentrantLock lock = new ReentrantLock();
@GuardedBy("lock") MyClass q = new MyClass();
lock.lock();
myAnnotatedMethod2();
q.field = new Object();
// Should behave as @MayReleaseLocks, and *should* reset @LockHeld assumption about local variable lock.
myUnannotatedMethod2();
//:: error: (lock.not.held)
q.field = new Object();
lock.lock();
// Should behave as @MayReleaseLocks, and *should* reset @LockHeld assumption about local variable lock.
unannotatedReleaseLock(lock);
//:: error: (lock.not.held)
q.field = new Object();
}
}