File: LockEffectAnnotations.java

package info (click to toggle)
checker-framework-java 3.2.0%2Bds-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 23,104 kB
  • sloc: java: 145,916; xml: 839; sh: 518; makefile: 404; perl: 26
file content (155 lines) | stat: -rw-r--r-- 4,992 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package chapter;

import java.util.concurrent.locks.ReentrantLock;
import org.checkerframework.checker.lock.qual.GuardSatisfied;
import org.checkerframework.checker.lock.qual.GuardedBy;
import org.checkerframework.checker.lock.qual.GuardedByBottom;
import org.checkerframework.checker.lock.qual.GuardedByUnknown;
import org.checkerframework.checker.lock.qual.LockingFree;
import org.checkerframework.checker.lock.qual.MayReleaseLocks;
import org.checkerframework.checker.lock.qual.ReleasesNoLocks;
import org.checkerframework.dataflow.qual.Pure;
import org.checkerframework.dataflow.qual.SideEffectFree;

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

    private @GuardedBy({}) MyClass myField;

    private final ReentrantLock myLock2 = new ReentrantLock();
    private @GuardedBy("myLock2") MyClass x3;

    // This method does not use locks or synchronization but cannot
    // be annotated as @SideEffectFree since it alters myField.
    @LockingFree
    void myMethod5() {
        myField = new MyClass();
    }

    @SideEffectFree
    int mySideEffectFreeMethod() {
        return 0;
    }

    @MayReleaseLocks
    void myUnlockingMethod() {
        myLock2.unlock();
    }

    @MayReleaseLocks
    void myReleaseLocksEmptyMethod() {}

    @MayReleaseLocks
    // :: error: (guardsatisfied.with.mayreleaselocks)
    void methodGuardSatisfiedReceiver(@GuardSatisfied LockEffectAnnotations this) {}

    @MayReleaseLocks
    // :: error: (guardsatisfied.with.mayreleaselocks)
    void methodGuardSatisfiedParameter(@GuardSatisfied Object o) {}

    @MayReleaseLocks
    void myOtherMethod() {
        if (myLock2.tryLock()) {
            x3.field = new Object(); // OK: the lock is held
            myMethod5();
            x3.field = new Object(); // OK: the lock is still held since myMethod is locking-free
            mySideEffectFreeMethod();
            x3.field = new Object(); // OK: the lock is still held since mySideEffectFreeMethod is
            // side-effect-free
            myUnlockingMethod();
            // :: error: (lock.not.held)
            x3.field = new Object(); // ILLEGAL: myLockingMethod is not locking-free
        }
        if (myLock2.tryLock()) {
            x3.field = new Object(); // OK: the lock is held
            myReleaseLocksEmptyMethod();
            // :: error: (lock.not.held)
            x3.field =
                    new Object(); // ILLEGAL: even though myUnannotatedEmptyMethod is empty, since
            // myReleaseLocksEmptyMethod() is annotated with @MayReleaseLocks and the Lock Checker
            // no longer knows the state of the lock.
            if (myLock2.isHeldByCurrentThread()) {
                x3.field = new Object(); // OK: the lock is known to be held
            }
        }
    }

    @ReleasesNoLocks
    void innerClassTest() {
        class InnerClass {
            @MayReleaseLocks
            void innerClassMethod() {}
        }

        InnerClass ic = new InnerClass();
        // :: error: (method.guarantee.violated)
        ic.innerClassMethod();
    }

    @MayReleaseLocks
    synchronized void mayReleaseLocksSynchronizedMethod() {}

    @ReleasesNoLocks
    synchronized void releasesNoLocksSynchronizedMethod() {}

    @LockingFree
    // :: error: (lockingfree.synchronized.method)
    synchronized void lockingFreeSynchronizedMethod() {}

    @SideEffectFree
    // :: error: (lockingfree.synchronized.method)
    synchronized void sideEffectFreeSynchronizedMethod() {}

    @Pure
    // :: error: (lockingfree.synchronized.method)
    synchronized void pureSynchronizedMethod() {}

    @MayReleaseLocks
    void mayReleaseLocksMethodWithSynchronizedBlock() {
        synchronized (this) {
        }
    }

    @ReleasesNoLocks
    void releasesNoLocksMethodWithSynchronizedBlock() {
        synchronized (this) {
        }
    }

    @LockingFree
    void lockingFreeMethodWithSynchronizedBlock() {
        // :: error: (synchronized.block.in.lockingfree.method)
        synchronized (this) {
        }
    }

    @SideEffectFree
    void sideEffectFreeMethodWithSynchronizedBlock() {
        // :: error: (synchronized.block.in.lockingfree.method)
        synchronized (this) {
        }
    }

    @Pure
    void pureMethodWithSynchronizedBlock() {
        // :: error: (synchronized.block.in.lockingfree.method)
        synchronized (this) {
        }
    }

    @GuardedByUnknown class MyClass2 {}

    // :: error: (expression.unparsable.type.invalid) :: error: (super.invocation.invalid)
    // :: warning: (inconsistent.constructor.type)
    @GuardedBy("lock") class MyClass3 {}

    @GuardedBy({}) class MyClass4 {}
    // :: error: (guardsatisfied.location.disallowed) :: error: (super.invocation.invalid)
    // :: warning: (inconsistent.constructor.type)
    @GuardSatisfied class MyClass5 {}

    // :: error: (super.invocation.invalid) :: warning: (inconsistent.constructor.type)
    @GuardedByBottom class MyClass6 {}
}