aboutsummaryrefslogtreecommitdiffhomepage
path: root/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentContext.java
blob: 85d17e7c06608ba1a17922b4451b98dcc654c086 (plain)
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
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();
}