
org.checkerframework.checker.lock.LockTransfer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of checker Show documentation
Show all versions of checker Show documentation
The Checker Framework enhances Java's type system to
make it more powerful and useful. This lets software developers
detect and prevent errors in their Java programs.
The Checker Framework includes compiler plug-ins ("checkers")
that find bugs or verify their absence. It also permits you to
write your own compiler plug-ins.
package org.checkerframework.checker.lock;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.MethodTree;
import java.util.List;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.type.TypeMirror;
import org.checkerframework.dataflow.analysis.TransferInput;
import org.checkerframework.dataflow.analysis.TransferResult;
import org.checkerframework.dataflow.cfg.UnderlyingAST;
import org.checkerframework.dataflow.cfg.UnderlyingAST.CFGMethod;
import org.checkerframework.dataflow.cfg.UnderlyingAST.Kind;
import org.checkerframework.dataflow.cfg.node.LocalVariableNode;
import org.checkerframework.dataflow.cfg.node.Node;
import org.checkerframework.dataflow.cfg.node.SynchronizedNode;
import org.checkerframework.dataflow.expression.ClassName;
import org.checkerframework.dataflow.expression.JavaExpression;
import org.checkerframework.framework.flow.CFAbstractTransfer;
import org.checkerframework.framework.flow.CFValue;
import org.checkerframework.javacutil.TreeUtils;
/**
* LockTransfer handles constructors, initializers, synchronized methods, and synchronized blocks.
*/
public class LockTransfer extends CFAbstractTransfer {
/** The type factory associated with this transfer function. */
private final LockAnnotatedTypeFactory atypeFactory;
/**
* Create a transfer function for the Lock Checker.
*
* @param analysis the analysis this transfer function belongs to
* @param checker the type-checker this transfer function belongs to
*/
public LockTransfer(LockAnalysis analysis, LockChecker checker) {
// Always run the Lock Checker with -AconcurrentSemantics turned on.
super(analysis, /* useConcurrentSemantics= */ true);
this.atypeFactory = (LockAnnotatedTypeFactory) analysis.getTypeFactory();
}
/**
* Sets a given {@link Node} to @LockHeld in the given {@code store}.
*
* @param store the store to update
* @param node the node that should be @LockHeld
*/
protected void makeLockHeld(LockStore store, Node node) {
JavaExpression internalRepr = JavaExpression.fromNode(node);
store.insertValue(internalRepr, atypeFactory.LOCKHELD);
}
/**
* Sets a given {@link Node} to @LockPossiblyHeld in the given {@code store}.
*
* @param store the store to update
* @param node the node that should be @LockPossiblyHeld
*/
protected void makeLockPossiblyHeld(LockStore store, Node node) {
JavaExpression internalRepr = JavaExpression.fromNode(node);
// insertValue cannot change an annotation to a less specific type (e.g. LockHeld to
// LockPossiblyHeld), so insertLockPossiblyHeld is called.
store.insertLockPossiblyHeld(internalRepr);
}
/** Sets a given {@link Node} {@code node} to LockHeld in the given {@link TransferResult}. */
protected void makeLockHeld(TransferResult result, Node node) {
if (result.containsTwoStores()) {
makeLockHeld(result.getThenStore(), node);
makeLockHeld(result.getElseStore(), node);
} else {
makeLockHeld(result.getRegularStore(), node);
}
}
/**
* Sets a given {@link Node} {@code node} to LockPossiblyHeld in the given {@link TransferResult}.
*/
protected void makeLockPossiblyHeld(TransferResult result, Node node) {
if (result.containsTwoStores()) {
makeLockPossiblyHeld(result.getThenStore(), node);
makeLockPossiblyHeld(result.getElseStore(), node);
} else {
makeLockPossiblyHeld(result.getRegularStore(), node);
}
}
@Override
public LockStore initialStore(UnderlyingAST underlyingAST, List parameters) {
LockStore store = super.initialStore(underlyingAST, parameters);
Kind astKind = underlyingAST.getKind();
// Methods with the 'synchronized' modifier are holding the 'this' lock.
// There is a subtle difference between synchronized methods and constructors/initializers.
// A synchronized method is only taking the intrinsic lock of the current object. It says
// nothing about any fields of the current object.
// Furthermore, since the current object already exists, other objects may be guarded by the
// current object. So a synchronized method can affect the locking behavior of other
// objects.
// A constructor/initializer behaves as if the current object and all its non-static fields
// were held as locks. But in reality no locks are held.
// Furthermore, since the current object is being constructed, no other object can be
// guarded by it or any of its non-static fields.
// Handle synchronized methods and constructors.
if (astKind == UnderlyingAST.Kind.METHOD) {
CFGMethod method = (CFGMethod) underlyingAST;
MethodTree methodTree = method.getMethod();
ExecutableElement methodElement = TreeUtils.elementFromDeclaration(methodTree);
if (methodElement.getModifiers().contains(Modifier.SYNCHRONIZED)) {
ClassTree classTree = method.getClassTree();
TypeMirror classType = TreeUtils.typeOf(classTree);
if (methodElement.getModifiers().contains(Modifier.STATIC)) {
store.insertValue(new ClassName(classType), atypeFactory.LOCKHELD);
} else {
store.insertThisValue(atypeFactory.LOCKHELD, classType);
}
} else if (methodElement.getKind() == ElementKind.CONSTRUCTOR) {
store.setInConstructorOrInitializer();
}
} else if (astKind == Kind.ARBITRARY_CODE) { // Handle initializers
store.setInConstructorOrInitializer();
}
return store;
}
@Override
public TransferResult visitSynchronized(
SynchronizedNode n, TransferInput p) {
TransferResult result = super.visitSynchronized(n, p);
// Handle the entering and leaving of the synchronized block
if (n.getIsStartOfBlock()) {
makeLockHeld(result, n.getExpression());
} else {
makeLockPossiblyHeld(result, n.getExpression());
}
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy