| package org.checkerframework.dataflow.cfg.node; |
| |
| import javax.lang.model.element.Element; |
| import javax.lang.model.element.ExecutableElement; |
| |
| import org.checkerframework.javacutil.TreeUtils; |
| |
| import com.sun.source.tree.ExpressionTree; |
| import com.sun.source.tree.MethodTree; |
| import com.sun.source.tree.Tree; |
| import com.sun.source.tree.VariableTree; |
| |
| /** |
| * An assignment context for a node, which represents the place to which the |
| * node with this context is 'assigned' to. An 'assignment' (as we use the term |
| * here) can occur for Java assignments, method calls (for all the actual |
| * parameters which get assigned to their formal parameters) or method return |
| * statements. |
| * |
| * <p> |
| * The main use of {@link AssignmentContext} is to be able to get the declared |
| * type of the left-hand side of the assignment for proper type-refinement. |
| * |
| * @author Stefan Heule |
| */ |
| public abstract class AssignmentContext { |
| |
| /** |
| * An assignment context for an assignment 'lhs = rhs'. |
| */ |
| public static class AssignmentLhsContext extends AssignmentContext { |
| |
| protected final Node node; |
| |
| public AssignmentLhsContext(Node node) { |
| this.node = node; |
| } |
| |
| @Override |
| public Element getElementForType() { |
| Tree tree = node.getTree(); |
| if (tree == null) { |
| return null; |
| } else if (tree instanceof ExpressionTree) { |
| return TreeUtils.elementFromUse((ExpressionTree) tree); |
| } else if (tree instanceof VariableTree) { |
| return TreeUtils.elementFromDeclaration((VariableTree) tree); |
| } else { |
| assert false : "unexpected tree"; |
| return null; |
| } |
| } |
| |
| @Override |
| public Tree getContextTree() { |
| return node.getTree(); |
| } |
| } |
| |
| /** |
| * An assignment context for a method parameter. |
| */ |
| public static class MethodParameterContext extends AssignmentContext { |
| |
| protected final ExecutableElement method; |
| protected final int paramNum; |
| |
| public MethodParameterContext(ExecutableElement method, int paramNum) { |
| this.method = method; |
| this.paramNum = paramNum; |
| } |
| |
| @Override |
| public Element getElementForType() { |
| return method.getParameters().get(paramNum); |
| } |
| |
| @Override |
| public Tree getContextTree() { |
| // TODO: what is the right assignment context? We might not have |
| // a tree for the invoked method. |
| return null; |
| } |
| } |
| |
| /** |
| * An assignment context for method return statements. |
| */ |
| public static class MethodReturnContext extends AssignmentContext { |
| |
| protected final ExecutableElement method; |
| protected final Tree ret; |
| |
| public MethodReturnContext(MethodTree method) { |
| this.method = TreeUtils.elementFromDeclaration(method); |
| this.ret = method.getReturnType(); |
| } |
| |
| @Override |
| public Element getElementForType() { |
| return method; |
| } |
| |
| @Override |
| public Tree getContextTree() { |
| return ret; |
| } |
| } |
| |
| /** |
| * An assignment context for lambda return statements. |
| */ |
| public static class LambdaReturnContext extends AssignmentContext { |
| |
| protected final ExecutableElement method; |
| |
| public LambdaReturnContext(ExecutableElement method) { |
| this.method = method; |
| } |
| |
| @Override |
| public Element getElementForType() { |
| return method; |
| } |
| |
| @Override |
| public Tree getContextTree() { |
| // TODO: what is the right assignment context? We might not have |
| // a tree for the invoked method. |
| return null; |
| } |
| } |
| |
| /** |
| * Returns an {@link Element} that has the type of this assignment context. |
| */ |
| public abstract Element getElementForType(); |
| |
| public abstract Tree getContextTree(); |
| } |