aboutsummaryrefslogtreecommitdiffhomepage
path: root/third_party/checker_framework_dataflow
diff options
context:
space:
mode:
authorGravatar Liam Miller-Cushon <cushon@google.com>2017-10-15 23:31:56 -0700
committerGravatar Damien Martin-Guillerez <dmarting@google.com>2017-10-16 14:16:39 +0200
commit6bf3f268f4a01963a2ee13f60178664bb056a802 (patch)
tree32a870dc293e07af88f52b241c75d9cbd462f63f /third_party/checker_framework_dataflow
parent80a34dc97799961201e6dce20fd58dd08022c032 (diff)
Update checker framework dataflow and javacutils to 2.1.14
Change-Id: I62ad827fc4bbd54d022097003af63e351e44b98c
Diffstat (limited to 'third_party/checker_framework_dataflow')
-rw-r--r--third_party/checker_framework_dataflow/dataflow-1.8.10.jarbin289725 -> 0 bytes
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/AbstractValue.java16
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/Analysis.java649
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/AnalysisResult.java176
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/ConditionalTransferResult.java87
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/FlowExpressions.java563
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/RegularTransferResult.java78
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/Store.java81
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferFunction.java38
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferInput.java183
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferResult.java90
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGBuilder.java3914
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGDOTVisualizer.java304
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGVisualizer.java167
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/ControlFlowGraph.java77
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/DOTCFGVisualizer.java511
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/JavaSource2CFGDOT.java220
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/UnderlyingAST.java37
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/Block.java10
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/BlockImpl.java12
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ConditionalBlock.java32
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ConditionalBlockImpl.java22
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ExceptionBlock.java21
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ExceptionBlockImpl.java18
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/RegularBlock.java19
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/RegularBlockImpl.java18
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SingleSuccessorBlock.java14
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SingleSuccessorBlockImpl.java12
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SpecialBlock.java13
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SpecialBlockImpl.java4
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AbstractNodeVisitor.java28
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayAccessNode.java14
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayCreationNode.java21
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayTypeNode.java13
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssertionErrorNode.java11
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentContext.java42
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentNode.java20
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BinaryOperationNode.java52
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseAndNode.java45
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseComplementNode.java36
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseOrNode.java45
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseXorNode.java45
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BooleanLiteralNode.java6
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/CaseNode.java13
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/CharacterLiteralNode.java6
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ClassNameNode.java50
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalAndNode.java43
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalNotNode.java32
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalOrNode.java43
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/DoubleLiteralNode.java6
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/EqualToNode.java43
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ExplicitThisLiteralNode.java7
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FieldAccessNode.java17
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatLiteralNode.java6
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatingDivisionNode.java45
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatingRemainderNode.java45
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FunctionalInterfaceNode.java16
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/GreaterThanNode.java45
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/GreaterThanOrEqualNode.java45
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ImplicitThisLiteralNode.java6
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/InstanceOfNode.java13
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerDivisionNode.java45
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerLiteralNode.java6
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerRemainderNode.java45
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LeftShiftNode.java45
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LessThanNode.java44
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LessThanOrEqualNode.java45
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LocalVariableNode.java19
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LongLiteralNode.java6
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MarkerNode.java19
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MethodAccessNode.java12
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MethodInvocationNode.java27
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NarrowingConversionNode.java18
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/Node.java93
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NodeVisitor.java15
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NotEqualNode.java45
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullChkNode.java83
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullLiteralNode.java6
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalAdditionNode.java48
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalMinusNode.java36
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalMultiplicationNode.java45
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalPlusNode.java36
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalSubtractionNode.java45
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ObjectCreationNode.java13
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/PackageNameNode.java35
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ParameterizedTypeNode.java16
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/PrimitiveTypeNode.java13
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ReturnNode.java23
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ShortLiteralNode.java13
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SignedRightShiftNode.java45
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConcatenateAssignmentNode.java7
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConcatenateNode.java45
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConversionNode.java22
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringLiteralNode.java6
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SuperNode.java11
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SynchronizedNode.java12
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/TernaryExpressionNode.java24
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ThisLiteralNode.java3
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ThrowNode.java11
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/TypeCastNode.java12
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/UnaryOperationNode.java45
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/UnsignedRightShiftNode.java45
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ValueLiteralNode.java38
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/VariableDeclarationNode.java11
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/WideningConversionNode.java18
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/playground/ConstantPropagationPlayground.java16
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/Constant.java29
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationStore.java44
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationTransfer.java26
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/Deterministic.java141
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/LockingFree.java19
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/Pure.java23
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/SideEffectFree.java81
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/TerminatesExecution.java32
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/HashCodeUtils.java7
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/MostlySingleton.java127
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/NodeUtils.java29
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/PurityChecker.java159
-rw-r--r--third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/PurityUtils.java57
119 files changed, 4862 insertions, 5424 deletions
diff --git a/third_party/checker_framework_dataflow/dataflow-1.8.10.jar b/third_party/checker_framework_dataflow/dataflow-1.8.10.jar
deleted file mode 100644
index 4cbe8f1f3d..0000000000
--- a/third_party/checker_framework_dataflow/dataflow-1.8.10.jar
+++ /dev/null
Binary files differ
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/AbstractValue.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/AbstractValue.java
index 2dbcbd4b03..25b78075da 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/AbstractValue.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/AbstractValue.java
@@ -4,23 +4,21 @@ package org.checkerframework.dataflow.analysis;
* An abstract value used in the org.checkerframework.dataflow analysis.
*
* @author Stefan Heule
- *
*/
public interface AbstractValue<V extends AbstractValue<V>> {
/**
* Compute the least upper bound of two stores.
*
- * <p>
+ * <p><em>Important</em>: This method must fulfill the following contract:
*
- * <em>Important</em>: This method must fulfill the following contract:
* <ul>
- * <li>Does not change {@code this}.</li>
- * <li>Does not change {@code other}.</li>
- * <li>Returns a fresh object which is not aliased yet.</li>
- * <li>Returns an object of the same (dynamic) type as {@code this}, even if
- * the signature is more permissive.</li>
- * <li>Is commutative.</li>
+ * <li>Does not change {@code this}.
+ * <li>Does not change {@code other}.
+ * <li>Returns a fresh object which is not aliased yet.
+ * <li>Returns an object of the same (dynamic) type as {@code this}, even if the signature is
+ * more permissive.
+ * <li>Is commutative.
* </ul>
*/
V leastUpperBound(V other);
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/Analysis.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/Analysis.java
index fa07247e68..2e81b4af4a 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/Analysis.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/Analysis.java
@@ -4,7 +4,25 @@ package org.checkerframework.dataflow.analysis;
import org.checkerframework.checker.nullness.qual.Nullable;
*/
+import com.sun.source.tree.ClassTree;
import com.sun.source.tree.LambdaExpressionTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.VariableTree;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.PriorityQueue;
+import java.util.Set;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Types;
import org.checkerframework.dataflow.cfg.ControlFlowGraph;
import org.checkerframework.dataflow.cfg.UnderlyingAST;
import org.checkerframework.dataflow.cfg.UnderlyingAST.CFGLambda;
@@ -19,46 +37,20 @@ import org.checkerframework.dataflow.cfg.node.AssignmentNode;
import org.checkerframework.dataflow.cfg.node.LocalVariableNode;
import org.checkerframework.dataflow.cfg.node.Node;
import org.checkerframework.dataflow.cfg.node.ReturnNode;
-
import org.checkerframework.javacutil.ElementUtils;
import org.checkerframework.javacutil.Pair;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.PriorityQueue;
-import java.util.Set;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Element;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.Types;
-
-import com.sun.source.tree.ClassTree;
-import com.sun.source.tree.MethodTree;
-import com.sun.source.tree.Tree;
-import com.sun.source.tree.VariableTree;
-
/**
* An implementation of an iterative algorithm to solve a org.checkerframework.dataflow problem,
* given a control flow graph and a transfer function.
*
* @author Stefan Heule
- *
- * @param <A>
- * The abstract value type to be tracked by the analysis.
- * @param <S>
- * The store type used in the analysis.
- * @param <T>
- * The transfer function type that is used to approximated runtime
- * behavior.
+ * @param <A> the abstract value type to be tracked by the analysis
+ * @param <S> the store type used in the analysis
+ * @param <T> the transfer function type that is used to approximated runtime behavior
*/
-public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends TransferFunction<A, S>> {
+public class Analysis<
+ A extends AbstractValue<A>, S extends Store<S>, T extends TransferFunction<A, S>> {
/** Is the analysis currently running? */
protected boolean isRunning = false;
@@ -75,27 +67,30 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
/** Instance of the types utility. */
protected final Types types;
- /**
- * Then stores before every basic block (assumed to be 'no information' if
- * not present).
- */
+ /** Then stores before every basic block (assumed to be 'no information' if not present). */
protected IdentityHashMap<Block, S> thenStores;
+ /** Else stores before every basic block (assumed to be 'no information' if not present). */
+ protected IdentityHashMap<Block, S> elseStores;
+
/**
- * Else stores before every basic block (assumed to be 'no information' if
- * not present).
+ * Number of times every block has been analyzed since the last time widening was applied. Null,
+ * if maxCountBeforeWidening is -1 which implies widening isn't used for this analysis.
*/
- protected IdentityHashMap<Block, S> elseStores;
+ protected IdentityHashMap<Block, Integer> blockCount;
/**
- * The transfer inputs before every basic block (assumed to be 'no information' if
- * not present).
+ * Number of times a block can be analyzed before widening. -1 implies that widening shouldn't
+ * be used.
*/
- protected IdentityHashMap<Block, TransferInput<A, S>> inputs;
+ protected final int maxCountBeforeWidening;
/**
- * The stores after every return statement.
+ * The transfer inputs before every basic block (assumed to be 'no information' if not present).
*/
+ protected IdentityHashMap<Block, TransferInput<A, S>> inputs;
+
+ /** The stores after every return statement. */
protected IdentityHashMap<ReturnNode, TransferResult<A, S>> storesAtReturnStatements;
/** The worklist used for the fix-point iteration. */
@@ -108,25 +103,22 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
public HashMap<Element, A> finalLocalValues;
/**
- * The node that is currently handled in the analysis (if it is running).
- * The following invariant holds:
+ * The node that is currently handled in the analysis (if it is running). The following
+ * invariant holds:
*
* <pre>
- * !isRunning ==&gt; (currentNode == null)
+ * !isRunning &rArr; (currentNode == null)
* </pre>
*/
protected Node currentNode;
/**
- * The tree that is currently being looked at. The transfer function can set
- * this tree to make sure that calls to {@code getValue} will not return
- * information for this given tree.
+ * The tree that is currently being looked at. The transfer function can set this tree to make
+ * sure that calls to {@code getValue} will not return information for this given tree.
*/
protected Tree currentTree;
- /**
- * The current transfer input when the analysis is running.
- */
+ /** The current transfer input when the analysis is running. */
protected TransferInput<A, S> currentInput;
public Tree getCurrentTree() {
@@ -139,12 +131,10 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
/**
* Construct an object that can perform a org.checkerframework.dataflow analysis over a control
- * flow graph. The transfer function is set later using
- * {@code setTransferFunction}.
+ * flow graph. The transfer function is set later using {@code setTransferFunction}.
*/
public Analysis(ProcessingEnvironment env) {
- this.env = env;
- types = env.getTypeUtils();
+ this(env, null, -1);
}
/**
@@ -152,7 +142,18 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
* flow graph, given a transfer function.
*/
public Analysis(ProcessingEnvironment env, T transfer) {
- this(env);
+ this(env, transfer, -1);
+ }
+
+ /**
+ * Construct an object that can perform a org.checkerframework.dataflow analysis over a control
+ * flow graph, given a transfer function.
+ */
+ public Analysis(ProcessingEnvironment env, T transfer, int maxCountBeforeWidening) {
+ this.env = env;
+ types = env.getTypeUtils();
+ this.transferFunction = transfer;
+ this.maxCountBeforeWidening = maxCountBeforeWidening;
this.transferFunction = transfer;
}
@@ -173,10 +174,7 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
}
/**
- * Perform the actual analysis. Should only be called once after the object
- * has been created.
- *
- * @param cfg
+ * Perform the actual analysis. Should only be called once after the object has been created.
*/
public void performAnalysis(ControlFlowGraph cfg) {
assert isRunning == false;
@@ -188,101 +186,116 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
Block b = worklist.poll();
switch (b.getType()) {
- case REGULAR_BLOCK: {
- RegularBlock rb = (RegularBlock) b;
-
- // apply transfer function to contents
- TransferInput<A, S> inputBefore = getInputBefore(rb);
- currentInput = inputBefore.copy();
- TransferResult<A, S> transferResult = null;
- Node lastNode = null;
- boolean addToWorklistAgain = false;
- for (Node n : rb.getContents()) {
- transferResult = callTransferFunction(n, currentInput);
- addToWorklistAgain |= updateNodeValues(n, transferResult);
- currentInput = new TransferInput<>(n, this, transferResult);
- lastNode = n;
- }
- // loop will run at least one, making transferResult non-null
-
- // propagate store to successors
- Block succ = rb.getSuccessor();
- assert succ != null : "regular basic block without non-exceptional successor unexpected";
- propagateStoresTo(succ, lastNode, currentInput, rb.getFlowRule(), addToWorklistAgain);
- break;
- }
-
- case EXCEPTION_BLOCK: {
- ExceptionBlock eb = (ExceptionBlock) b;
-
- // apply transfer function to content
- TransferInput<A, S> inputBefore = getInputBefore(eb);
- currentInput = inputBefore.copy();
- Node node = eb.getNode();
- TransferResult<A, S> transferResult = callTransferFunction(
- node, currentInput);
- boolean addToWorklistAgain = updateNodeValues(node, transferResult);
-
- // propagate store to successor
- Block succ = eb.getSuccessor();
- if (succ != null) {
- currentInput = new TransferInput<>(node, this, transferResult);
- // TODO? Variable wasn't used.
- // Store.FlowRule storeFlow = eb.getFlowRule();
- propagateStoresTo(succ, node, currentInput, eb.getFlowRule(), addToWorklistAgain);
- }
+ case REGULAR_BLOCK:
+ {
+ RegularBlock rb = (RegularBlock) b;
+
+ // apply transfer function to contents
+ TransferInput<A, S> inputBefore = getInputBefore(rb);
+ currentInput = inputBefore.copy();
+ TransferResult<A, S> transferResult = null;
+ Node lastNode = null;
+ boolean addToWorklistAgain = false;
+ for (Node n : rb.getContents()) {
+ transferResult = callTransferFunction(n, currentInput);
+ addToWorklistAgain |= updateNodeValues(n, transferResult);
+ currentInput = new TransferInput<>(n, this, transferResult);
+ lastNode = n;
+ }
+ // loop will run at least one, making transferResult non-null
+
+ // propagate store to successors
+ Block succ = rb.getSuccessor();
+ assert succ != null
+ : "regular basic block without non-exceptional successor unexpected";
+ propagateStoresTo(
+ succ, lastNode, currentInput, rb.getFlowRule(), addToWorklistAgain);
+ break;
+ }
- // propagate store to exceptional successors
- for (Entry<TypeMirror, Set<Block>> e : eb.getExceptionalSuccessors()
- .entrySet()) {
- TypeMirror cause = e.getKey();
- S exceptionalStore = transferResult
- .getExceptionalStore(cause);
- if (exceptionalStore != null) {
- for (Block exceptionSucc : e.getValue()) {
- addStoreBefore(exceptionSucc, node, exceptionalStore, Store.Kind.BOTH,
- addToWorklistAgain);
+ case EXCEPTION_BLOCK:
+ {
+ ExceptionBlock eb = (ExceptionBlock) b;
+
+ // apply transfer function to content
+ TransferInput<A, S> inputBefore = getInputBefore(eb);
+ currentInput = inputBefore.copy();
+ Node node = eb.getNode();
+ TransferResult<A, S> transferResult =
+ callTransferFunction(node, currentInput);
+ boolean addToWorklistAgain = updateNodeValues(node, transferResult);
+
+ // propagate store to successor
+ Block succ = eb.getSuccessor();
+ if (succ != null) {
+ currentInput = new TransferInput<>(node, this, transferResult);
+ // TODO? Variable wasn't used.
+ // Store.FlowRule storeFlow = eb.getFlowRule();
+ propagateStoresTo(
+ succ, node, currentInput, eb.getFlowRule(), addToWorklistAgain);
}
- } else {
- for (Block exceptionSucc : e.getValue()) {
- addStoreBefore(exceptionSucc, node, inputBefore.copy().getRegularStore(),
- Store.Kind.BOTH, addToWorklistAgain);
+
+ // propagate store to exceptional successors
+ for (Entry<TypeMirror, Set<Block>> e :
+ eb.getExceptionalSuccessors().entrySet()) {
+ TypeMirror cause = e.getKey();
+ S exceptionalStore = transferResult.getExceptionalStore(cause);
+ if (exceptionalStore != null) {
+ for (Block exceptionSucc : e.getValue()) {
+ addStoreBefore(
+ exceptionSucc,
+ node,
+ exceptionalStore,
+ Store.Kind.BOTH,
+ addToWorklistAgain);
+ }
+ } else {
+ for (Block exceptionSucc : e.getValue()) {
+ addStoreBefore(
+ exceptionSucc,
+ node,
+ inputBefore.copy().getRegularStore(),
+ Store.Kind.BOTH,
+ addToWorklistAgain);
+ }
+ }
}
+ break;
}
- }
- break;
- }
- case CONDITIONAL_BLOCK: {
- ConditionalBlock cb = (ConditionalBlock) b;
+ case CONDITIONAL_BLOCK:
+ {
+ ConditionalBlock cb = (ConditionalBlock) b;
- // get store before
- TransferInput<A, S> inputBefore = getInputBefore(cb);
- TransferInput<A, S> input = inputBefore.copy();
+ // get store before
+ TransferInput<A, S> inputBefore = getInputBefore(cb);
+ TransferInput<A, S> input = inputBefore.copy();
- // propagate store to successor
- Block thenSucc = cb.getThenSuccessor();
- Block elseSucc = cb.getElseSuccessor();
+ // propagate store to successor
+ Block thenSucc = cb.getThenSuccessor();
+ Block elseSucc = cb.getElseSuccessor();
- propagateStoresTo(thenSucc, null, input, cb.getThenFlowRule(), false);
- propagateStoresTo(elseSucc, null, input, cb.getElseFlowRule(), false);
- break;
- }
+ propagateStoresTo(thenSucc, null, input, cb.getThenFlowRule(), false);
+ propagateStoresTo(elseSucc, null, input, cb.getElseFlowRule(), false);
+ break;
+ }
- case SPECIAL_BLOCK: {
- // special basic blocks are empty and cannot throw exceptions,
- // thus there is no need to perform any analysis.
- SpecialBlock sb = (SpecialBlock) b;
- Block succ = sb.getSuccessor();
- if (succ != null) {
- propagateStoresTo(succ, null, getInputBefore(b), sb.getFlowRule(), false);
- }
- break;
- }
+ case SPECIAL_BLOCK:
+ {
+ // special basic blocks are empty and cannot throw exceptions,
+ // thus there is no need to perform any analysis.
+ SpecialBlock sb = (SpecialBlock) b;
+ Block succ = sb.getSuccessor();
+ if (succ != null) {
+ propagateStoresTo(
+ succ, null, getInputBefore(b), sb.getFlowRule(), false);
+ }
+ break;
+ }
- default:
- assert false;
- break;
+ default:
+ assert false;
+ break;
}
}
@@ -291,78 +304,104 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
}
/**
- * Propagate the stores in currentInput to the successor block, succ, according to the
- * flowRule.
+ * Propagate the stores in currentInput to the successor block, succ, according to the flowRule.
*/
- protected void propagateStoresTo(Block succ, Node node, TransferInput<A, S> currentInput,
- Store.FlowRule flowRule, boolean addToWorklistAgain) {
+ protected void propagateStoresTo(
+ Block succ,
+ Node node,
+ TransferInput<A, S> currentInput,
+ Store.FlowRule flowRule,
+ boolean addToWorklistAgain) {
switch (flowRule) {
- case EACH_TO_EACH:
- if (currentInput.containsTwoStores()) {
- addStoreBefore(succ, node, currentInput.getThenStore(), Store.Kind.THEN,
+ case EACH_TO_EACH:
+ if (currentInput.containsTwoStores()) {
+ addStoreBefore(
+ succ,
+ node,
+ currentInput.getThenStore(),
+ Store.Kind.THEN,
+ addToWorklistAgain);
+ addStoreBefore(
+ succ,
+ node,
+ currentInput.getElseStore(),
+ Store.Kind.ELSE,
+ addToWorklistAgain);
+ } else {
+ addStoreBefore(
+ succ,
+ node,
+ currentInput.getRegularStore(),
+ Store.Kind.BOTH,
+ addToWorklistAgain);
+ }
+ break;
+ case THEN_TO_BOTH:
+ addStoreBefore(
+ succ,
+ node,
+ currentInput.getThenStore(),
+ Store.Kind.BOTH,
addToWorklistAgain);
- addStoreBefore(succ, node, currentInput.getElseStore(), Store.Kind.ELSE,
+ break;
+ case ELSE_TO_BOTH:
+ addStoreBefore(
+ succ,
+ node,
+ currentInput.getElseStore(),
+ Store.Kind.BOTH,
addToWorklistAgain);
- } else {
- addStoreBefore(succ, node, currentInput.getRegularStore(), Store.Kind.BOTH,
+ break;
+ case THEN_TO_THEN:
+ addStoreBefore(
+ succ,
+ node,
+ currentInput.getThenStore(),
+ Store.Kind.THEN,
addToWorklistAgain);
- }
- break;
- case THEN_TO_BOTH:
- addStoreBefore(succ, node, currentInput.getThenStore(), Store.Kind.BOTH,
- addToWorklistAgain);
- break;
- case ELSE_TO_BOTH:
- addStoreBefore(succ, node, currentInput.getElseStore(), Store.Kind.BOTH,
- addToWorklistAgain);
- break;
- case THEN_TO_THEN:
- addStoreBefore(succ, node, currentInput.getThenStore(), Store.Kind.THEN,
- addToWorklistAgain);
- break;
- case ELSE_TO_ELSE:
- addStoreBefore(succ, node, currentInput.getElseStore(), Store.Kind.ELSE,
- addToWorklistAgain);
- break;
+ break;
+ case ELSE_TO_ELSE:
+ addStoreBefore(
+ succ,
+ node,
+ currentInput.getElseStore(),
+ Store.Kind.ELSE,
+ addToWorklistAgain);
+ break;
}
}
/**
- * Updates the value of node {@code node} to the value of the
- * {@code transferResult}. Returns true if the node's value changed, or a
- * store was updated.
+ * Updates the value of node {@code node} to the value of the {@code transferResult}. Returns
+ * true if the node's value changed, or a store was updated.
*/
protected boolean updateNodeValues(Node node, TransferResult<A, S> transferResult) {
- A newVal = transferResult.getResultValue();
- boolean nodeValueChanged = false;
+ A newVal = transferResult.getResultValue();
+ boolean nodeValueChanged = false;
- if (newVal != null) {
- A oldVal = nodeValues.get(node);
- nodeValues.put(node, newVal);
- nodeValueChanged = !Objects.equals(oldVal, newVal);
- }
+ if (newVal != null) {
+ A oldVal = nodeValues.get(node);
+ nodeValues.put(node, newVal);
+ nodeValueChanged = !Objects.equals(oldVal, newVal);
+ }
- return nodeValueChanged || transferResult.storeChanged();
+ return nodeValueChanged || transferResult.storeChanged();
}
/**
- * Call the transfer function for node {@code node}, and set that node as
- * current node first.
+ * Call the transfer function for node {@code node}, and set that node as current node first.
*/
- protected TransferResult<A, S> callTransferFunction(Node node,
- TransferInput<A, S> store) {
+ protected TransferResult<A, S> callTransferFunction(Node node, TransferInput<A, S> store) {
if (node.isLValue()) {
// TODO: should the default behavior be to return either a regular
// transfer result or a conditional transfer result (depending on
// store.hasTwoStores()), or is the following correct?
- return new RegularTransferResult<A, S>(null,
- store.getRegularStore());
+ return new RegularTransferResult<A, S>(null, store.getRegularStore());
}
store.node = node;
currentNode = node;
- TransferResult<A, S> transferResult = node.accept(transferFunction,
- store);
+ TransferResult<A, S> transferResult = node.accept(transferFunction, store);
currentNode = null;
if (node instanceof ReturnNode) {
// save a copy of the store to later check if some property held at
@@ -389,6 +428,7 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
this.cfg = cfg;
thenStores = new IdentityHashMap<>();
elseStores = new IdentityHashMap<>();
+ blockCount = maxCountBeforeWidening == -1 ? null : new IdentityHashMap<Block, Integer>();
inputs = new IdentityHashMap<>();
storesAtReturnStatements = new IdentityHashMap<>();
worklist = new Worklist(cfg);
@@ -428,8 +468,7 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
}
/**
- * Add a basic block to the worklist. If <code>b</code> is already present,
- * the method does nothing.
+ * Add a basic block to the worklist. If {@code b} is already present, the method does nothing.
*/
protected void addToWorklist(Block b) {
// TODO: use a more efficient way to check if b is already present
@@ -439,74 +478,84 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
}
/**
- * Add a store before the basic block <code>b</code> by merging with the
- * existing stores for that location.
+ * Add a store before the basic block {@code b} by merging with the existing stores for that
+ * location.
*/
- protected void addStoreBefore(Block b, Node node, S s, Store.Kind kind,
- boolean addBlockToWorklist) {
+ protected void addStoreBefore(
+ Block b, Node node, S s, Store.Kind kind, boolean addBlockToWorklist) {
S thenStore = getStoreBefore(b, Store.Kind.THEN);
S elseStore = getStoreBefore(b, Store.Kind.ELSE);
-
- switch (kind) {
- case THEN: {
- // Update the then store
- S newThenStore = (thenStore != null) ?
- thenStore.leastUpperBound(s) : s;
- if (!newThenStore.equals(thenStore)) {
- thenStores.put(b, newThenStore);
- if (elseStore != null) {
- inputs.put(b, new TransferInput<>(node, this, newThenStore, elseStore));
- addBlockToWorklist = true;
- }
+ boolean shouldWiden = false;
+ if (blockCount != null) {
+ Integer count = blockCount.get(b);
+ if (count == null) {
+ count = 0;
}
- break;
- }
- case ELSE: {
- // Update the else store
- S newElseStore = (elseStore != null) ?
- elseStore.leastUpperBound(s) : s;
- if (!newElseStore.equals(elseStore)) {
- elseStores.put(b, newElseStore);
- if (thenStore != null) {
- inputs.put(b, new TransferInput<>(node, this, thenStore, newElseStore));
- addBlockToWorklist = true;
- }
+ shouldWiden = count >= maxCountBeforeWidening;
+ if (shouldWiden) {
+ blockCount.put(b, 0);
+ } else {
+ blockCount.put(b, count + 1);
}
- break;
}
- case BOTH:
- if (thenStore == elseStore) {
- // Currently there is only one regular store
- S newStore = (thenStore != null) ?
- thenStore.leastUpperBound(s) : s;
- if (!newStore.equals(thenStore)) {
- thenStores.put(b, newStore);
- elseStores.put(b, newStore);
- inputs.put(b, new TransferInput<>(node, this, newStore));
- addBlockToWorklist = true;
- }
- } else {
- boolean storeChanged = false;
- S newThenStore = (thenStore != null) ?
- thenStore.leastUpperBound(s) : s;
- if (!newThenStore.equals(thenStore)) {
- thenStores.put(b, newThenStore);
- storeChanged = true;
+ switch (kind) {
+ case THEN:
+ {
+ // Update the then store
+ S newThenStore = mergeStores(s, thenStore, shouldWiden);
+ if (!newThenStore.equals(thenStore)) {
+ thenStores.put(b, newThenStore);
+ if (elseStore != null) {
+ inputs.put(b, new TransferInput<>(node, this, newThenStore, elseStore));
+ addBlockToWorklist = true;
+ }
+ }
+ break;
}
-
- S newElseStore = (elseStore != null) ?
- elseStore.leastUpperBound(s) : s;
- if (!newElseStore.equals(elseStore)) {
- elseStores.put(b, newElseStore);
- storeChanged = true;
+ case ELSE:
+ {
+ // Update the else store
+ S newElseStore = mergeStores(s, elseStore, shouldWiden);
+ if (!newElseStore.equals(elseStore)) {
+ elseStores.put(b, newElseStore);
+ if (thenStore != null) {
+ inputs.put(b, new TransferInput<>(node, this, thenStore, newElseStore));
+ addBlockToWorklist = true;
+ }
+ }
+ break;
}
+ case BOTH:
+ if (thenStore == elseStore) {
+ // Currently there is only one regular store
+ S newStore = mergeStores(s, thenStore, shouldWiden);
+ if (!newStore.equals(thenStore)) {
+ thenStores.put(b, newStore);
+ elseStores.put(b, newStore);
+ inputs.put(b, new TransferInput<>(node, this, newStore));
+ addBlockToWorklist = true;
+ }
+ } else {
+ boolean storeChanged = false;
+
+ S newThenStore = mergeStores(s, thenStore, shouldWiden);
+ if (!newThenStore.equals(thenStore)) {
+ thenStores.put(b, newThenStore);
+ storeChanged = true;
+ }
+
+ S newElseStore = mergeStores(s, elseStore, shouldWiden);
+ if (!newElseStore.equals(elseStore)) {
+ elseStores.put(b, newElseStore);
+ storeChanged = true;
+ }
- if (storeChanged) {
- inputs.put(b, new TransferInput<>(node, this, newThenStore, newElseStore));
- addBlockToWorklist = true;
+ if (storeChanged) {
+ inputs.put(b, new TransferInput<>(node, this, newThenStore, newElseStore));
+ addBlockToWorklist = true;
+ }
}
- }
}
if (addBlockToWorklist) {
@@ -514,17 +563,26 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
}
}
+ private S mergeStores(S newStore, S previousStore, boolean shouldWiden) {
+ if (previousStore == null) {
+ return newStore;
+ } else if (shouldWiden) {
+ return newStore.widenedUpperBound(previousStore);
+ } else {
+ return newStore.leastUpperBound(previousStore);
+ }
+ }
+
/**
- * A worklist is a priority queue of blocks in which the order is given
- * by depth-first ordering to place non-loop predecessors ahead of successors.
+ * A worklist is a priority queue of blocks in which the order is given by depth-first ordering
+ * to place non-loop predecessors ahead of successors.
*/
protected static class Worklist {
/** Map all blocks in the CFG to their depth-first order. */
protected IdentityHashMap<Block, Integer> depthFirstOrder;
- /** Comparator to allow priority queue to order blocks by their depth-first
- order. */
+ /** Comparator to allow priority queue to order blocks by their depth-first order. */
public class DFOComparator implements Comparator<Block> {
@Override
public int compare(Block b1, Block b2) {
@@ -535,7 +593,6 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
/** The backing priority queue. */
protected PriorityQueue<Block> queue;
-
public Worklist(ControlFlowGraph cfg) {
depthFirstOrder = new IdentityHashMap<>();
int count = 1;
@@ -569,43 +626,39 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
}
/**
- * Read the {@link TransferInput} for a particular basic block (or {@code null} if
- * none exists yet).
+ * Read the {@link TransferInput} for a particular basic block (or {@code null} if none exists
+ * yet).
*/
public /*@Nullable*/ TransferInput<A, S> getInput(Block b) {
return getInputBefore(b);
}
/**
- * @return The transfer input corresponding to the location right before the basic
- * block <code>b</code>.
+ * @return the transfer input corresponding to the location right before the basic block {@code
+ * b}.
*/
protected /*@Nullable*/ TransferInput<A, S> getInputBefore(Block b) {
return inputs.get(b);
}
- /**
- * @return The store corresponding to the location right before the basic
- * block <code>b</code>.
- */
+ /** @return the store corresponding to the location right before the basic block {@code b}. */
protected /*@Nullable*/ S getStoreBefore(Block b, Store.Kind kind) {
switch (kind) {
- case THEN:
- return readFromStore(thenStores, b);
- case ELSE:
- return readFromStore(elseStores, b);
- default:
- assert false;
- return null;
+ case THEN:
+ return readFromStore(thenStores, b);
+ case ELSE:
+ return readFromStore(elseStores, b);
+ default:
+ assert false;
+ return null;
}
}
/**
- * Read the {@link Store} for a particular basic block from a map of stores
- * (or {@code null} if none exists yet).
+ * Read the {@link Store} for a particular basic block from a map of stores (or {@code null} if
+ * none exists yet).
*/
- protected static <S> /*@Nullable*/ S readFromStore(Map<Block, S> stores,
- Block b) {
+ protected static <S> /*@Nullable*/ S readFromStore(Map<Block, S> stores, Block b) {
return stores.get(b);
}
@@ -615,24 +668,24 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
}
/**
- * @return The abstract value for {@link Node} {@code n}, or {@code null} if
- * no information is available. Note that if the analysis has not
- * finished yet, this value might not represent the final value for
- * this node.
+ * @return the abstract value for {@link Node} {@code n}, or {@code null} if no information is
+ * available. Note that if the analysis has not finished yet, this value might not represent
+ * the final value for this node.
*/
public /*@Nullable*/ A getValue(Node n) {
if (isRunning) {
// we do not yet have a org.checkerframework.dataflow fact about the current node
- if (currentNode == n
+ if (currentNode == null
+ || currentNode == n
|| (currentTree != null && currentTree == n.getTree())) {
return null;
}
// check that 'n' is a subnode of 'node'. Check immediate operands
// first for efficiency.
- assert currentNode != null;
assert !n.isLValue() : "Did not expect an lvalue, but got " + n;
- if (!(currentNode != n && (currentNode.getOperands().contains(n) || currentNode
- .getTransitiveOperands().contains(n)))) {
+ if (!(currentNode != n
+ && (currentNode.getOperands().contains(n)
+ || currentNode.getTransitiveOperands().contains(n)))) {
return null;
}
return nodeValues.get(n);
@@ -641,10 +694,9 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
}
/**
- * @return The abstract value for {@link Tree} {@code t}, or {@code null} if
- * no information is available. Note that if the analysis has not
- * finished yet, this value might not represent the final value for
- * this node.
+ * @return the abstract value for {@link Tree} {@code t}, or {@code null} if no information is
+ * available. Note that if the analysis has not finished yet, this value might not represent
+ * the final value for this node.
*/
public /*@Nullable*/ A getValue(Tree t) {
// we do not yet have a org.checkerframework.dataflow fact about the current node
@@ -658,24 +710,22 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
return getValue(nodeCorrespondingToTree);
}
- /**
- * Get the {@link Node} for a given {@link Tree}.
- */
+ /** Get the {@link Node} for a given {@link Tree}. */
public Node getNodeForTree(Tree t) {
return cfg.getNodeCorrespondingToTree(t);
}
/**
- * Get the {@link MethodTree} of the current CFG if the argument {@link Tree} maps
- * to a {@link Node} in the CFG or null otherwise.
+ * Get the {@link MethodTree} of the current CFG if the argument {@link Tree} maps to a {@link
+ * Node} in the CFG or null otherwise.
*/
public /*@Nullable*/ MethodTree getContainingMethod(Tree t) {
return cfg.getContainingMethod(t);
}
/**
- * Get the {@link ClassTree} of the current CFG if the argument {@link Tree} maps
- * to a {@link Node} in the CFG or null otherwise.
+ * Get the {@link ClassTree} of the current CFG if the argument {@link Tree} maps to a {@link
+ * Node} in the CFG or null otherwise.
*/
public /*@Nullable*/ ClassTree getContainingClass(Tree t) {
return cfg.getContainingClass(t);
@@ -684,8 +734,7 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
public List<Pair<ReturnNode, TransferResult<A, S>>> getReturnStatementStores() {
List<Pair<ReturnNode, TransferResult<A, S>>> result = new ArrayList<>();
for (ReturnNode returnNode : cfg.getReturnNodes()) {
- TransferResult<A, S> store = storesAtReturnStatements
- .get(returnNode);
+ TransferResult<A, S> store = storesAtReturnStatements.get(returnNode);
result.add(Pair.of(returnNode, store));
}
return result;
@@ -698,9 +747,8 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
}
/**
- * @return The regular exit store, or {@code null}, if there is no such
- * store (because the method cannot exit through the regular exit
- * block).
+ * @return the regular exit store, or {@code null}, if there is no such store (because the
+ * method cannot exit through the regular exit block).
*/
public /*@Nullable*/ S getRegularExitStore() {
SpecialBlock regularExitBlock = cfg.getRegularExitBlock();
@@ -713,8 +761,7 @@ public class Analysis<A extends AbstractValue<A>, S extends Store<S>, T extends
}
public S getExceptionalExitStore() {
- S exceptionalExitStore = inputs.get(cfg.getExceptionalExitBlock())
- .getRegularStore();
+ S exceptionalExitStore = inputs.get(cfg.getExceptionalExitBlock()).getRegularStore();
return exceptionalExitStore;
}
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/AnalysisResult.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/AnalysisResult.java
index 42b8d2f2ba..48f376dbea 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/AnalysisResult.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/AnalysisResult.java
@@ -4,29 +4,24 @@ package org.checkerframework.dataflow.analysis;
import org.checkerframework.checker.nullness.qual.Nullable;
*/
-import org.checkerframework.dataflow.cfg.block.Block;
-import org.checkerframework.dataflow.cfg.block.ExceptionBlock;
-import org.checkerframework.dataflow.cfg.block.RegularBlock;
-import org.checkerframework.dataflow.cfg.node.Node;
-
+import com.sun.source.tree.Tree;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Map.Entry;
-
import javax.lang.model.element.Element;
-
-import com.sun.source.tree.Tree;
+import org.checkerframework.dataflow.cfg.block.Block;
+import org.checkerframework.dataflow.cfg.block.ExceptionBlock;
+import org.checkerframework.dataflow.cfg.block.RegularBlock;
+import org.checkerframework.dataflow.cfg.node.Node;
/**
* An {@link AnalysisResult} represents the result of a org.checkerframework.dataflow analysis by
- * providing the abstract values given a node or a tree. Note that it does not
- * keep track of custom results computed by some analysis.
+ * providing the abstract values given a node or a tree. Note that it does not keep track of custom
+ * results computed by some analysis.
*
* @author Stefan Heule
- *
- * @param <A>
- * type of the abstract value that is tracked.
+ * @param <A> type of the abstract value that is tracked
*/
public class AnalysisResult<A extends AbstractValue<A>, S extends Store<S>> {
@@ -39,26 +34,22 @@ public class AnalysisResult<A extends AbstractValue<A>, S extends Store<S>> {
/** Map from (effectively final) local variable elements to their abstract value. */
protected final HashMap<Element, A> finalLocalValues;
- /**
- * The stores before every method call.
- */
+ /** The stores before every method call. */
protected final IdentityHashMap<Block, TransferInput<A, S>> stores;
- /**
- * Initialize with a given node-value mapping.
- */
- public AnalysisResult(Map<Node, A> nodeValues,
+ /** Initialize with a given node-value mapping. */
+ public AnalysisResult(
+ Map<Node, A> nodeValues,
IdentityHashMap<Block, TransferInput<A, S>> stores,
- IdentityHashMap<Tree, Node> treeLookup, HashMap<Element, A> finalLocalValues) {
+ IdentityHashMap<Tree, Node> treeLookup,
+ HashMap<Element, A> finalLocalValues) {
this.nodeValues = new IdentityHashMap<>(nodeValues);
this.treeLookup = new IdentityHashMap<>(treeLookup);
this.stores = stores;
this.finalLocalValues = finalLocalValues;
}
- /**
- * Initialize empty result.
- */
+ /** Initialize empty result. */
public AnalysisResult() {
nodeValues = new IdentityHashMap<>();
treeLookup = new IdentityHashMap<>();
@@ -66,9 +57,7 @@ public class AnalysisResult<A extends AbstractValue<A>, S extends Store<S>> {
finalLocalValues = new HashMap<>();
}
- /**
- * Combine with another analysis result.
- */
+ /** Combine with another analysis result. */
public void combine(AnalysisResult<A, S> other) {
for (Entry<Node, A> e : other.nodeValues.entrySet()) {
nodeValues.put(e.getKey(), e.getValue());
@@ -84,68 +73,68 @@ public class AnalysisResult<A extends AbstractValue<A>, S extends Store<S>> {
}
}
- /**
- * @return The value of effectively final local variables.
- */
+ /** @return the value of effectively final local variables */
public HashMap<Element, A> getFinalLocalValues() {
return finalLocalValues;
}
/**
- * @return The abstract value for {@link Node} {@code n}, or {@code null} if
- * no information is available.
+ * @return the abstract value for {@link Node} {@code n}, or {@code null} if no information is
+ * available.
*/
public /*@Nullable*/ A getValue(Node n) {
return nodeValues.get(n);
}
/**
- * @return The abstract value for {@link Tree} {@code t}, or {@code null} if
- * no information is available.
+ * @return the abstract value for {@link Tree} {@code t}, or {@code null} if no information is
+ * available.
*/
public /*@Nullable*/ A getValue(Tree t) {
A val = getValue(treeLookup.get(t));
return val;
}
- /**
- * @return The {@link Node} for a given {@link Tree}.
- */
+ /** @return the {@link Node} for a given {@link Tree}. */
public /*@Nullable*/ Node getNodeForTree(Tree tree) {
return treeLookup.get(tree);
}
- /**
- * @return The store immediately before a given {@link Tree}.
- */
+ /** @return the store immediately before a given {@link Tree}. */
public S getStoreBefore(Tree tree) {
Node node = getNodeForTree(tree);
if (node == null) {
return null;
}
+ return getStoreBefore(node);
+ }
+
+ /** @return the store immediately before a given {@link Node}. */
+ public S getStoreBefore(Node node) {
return runAnalysisFor(node, true);
}
- /**
- * @return The store immediately after a given {@link Tree}.
- */
+ /** @return the store immediately after a given {@link Tree}. */
public S getStoreAfter(Tree tree) {
Node node = getNodeForTree(tree);
if (node == null) {
return null;
}
+ return getStoreAfter(node);
+ }
+
+ /** @return the store immediately after a given {@link Node}. */
+ public S getStoreAfter(Node node) {
return runAnalysisFor(node, false);
}
/**
- * Runs the analysis again within the block of {@code node} and returns the
- * store at the location of {@code node}. If {@code before} is true, then
- * the store immediately before the {@link Node} {@code node} is returned.
- * Otherwise, the store after {@code node} is returned.
+ * Runs the analysis again within the block of {@code node} and returns the store at the
+ * location of {@code node}. If {@code before} is true, then the store immediately before the
+ * {@link Node} {@code node} is returned. Otherwise, the store after {@code node} is returned.
*
- * <p>
- * If the given {@link Node} cannot be reached (in the control flow graph),
- * then {@code null} is returned.
+ * <p>If the given {@link Node} cannot be reached (in the control flow graph), then {@code null}
+ * is returned.
*/
protected S runAnalysisFor(Node node, boolean before) {
Block block = node.getBlock();
@@ -157,10 +146,9 @@ public class AnalysisResult<A extends AbstractValue<A>, S extends Store<S>> {
}
/**
- * Runs the analysis again within the block of {@code node} and returns the
- * store at the location of {@code node}. If {@code before} is true, then
- * the store immediately before the {@link Node} {@code node} is returned.
- * Otherwise, the store after {@code node} is returned.
+ * Runs the analysis again within the block of {@code node} and returns the store at the
+ * location of {@code node}. If {@code before} is true, then the store immediately before the
+ * {@link Node} {@code node} is returned. Otherwise, the store after {@code node} is returned.
*/
public static <A extends AbstractValue<A>, S extends Store<S>> S runAnalysisFor(
Node node, boolean before, TransferInput<A, S> transferInput) {
@@ -176,49 +164,51 @@ public class AnalysisResult<A extends AbstractValue<A>, S extends Store<S>> {
analysis.isRunning = true;
try {
switch (block.getType()) {
- case REGULAR_BLOCK: {
- RegularBlock rb = (RegularBlock) block;
-
- // Apply transfer function to contents until we found the node
- // we
- // are looking for.
- TransferInput<A, S> store = transferInput;
- TransferResult<A, S> transferResult = null;
- for (Node n : rb.getContents()) {
- analysis.currentNode = n;
- if (n == node && before) {
- return store.getRegularStore();
+ case REGULAR_BLOCK:
+ {
+ RegularBlock rb = (RegularBlock) block;
+
+ // Apply transfer function to contents until we found the node
+ // we
+ // are looking for.
+ TransferInput<A, S> store = transferInput;
+ TransferResult<A, S> transferResult = null;
+ for (Node n : rb.getContents()) {
+ analysis.currentNode = n;
+ if (n == node && before) {
+ return store.getRegularStore();
+ }
+ transferResult = analysis.callTransferFunction(n, store);
+ if (n == node) {
+ return transferResult.getRegularStore();
+ }
+ store = new TransferInput<>(n, analysis, transferResult);
+ }
+ // This point should never be reached. If the block of 'node' is
+ // 'block', then 'node' must be part of the contents of 'block'.
+ assert false;
+ return null;
}
- transferResult = analysis.callTransferFunction(n, store);
- if (n == node) {
+
+ case EXCEPTION_BLOCK:
+ {
+ ExceptionBlock eb = (ExceptionBlock) block;
+
+ // apply transfer function to content
+ assert eb.getNode() == node;
+ if (before) {
+ return transferInput.getRegularStore();
+ }
+ analysis.currentNode = node;
+ TransferResult<A, S> transferResult =
+ analysis.callTransferFunction(node, transferInput);
return transferResult.getRegularStore();
}
- store = new TransferInput<>(n, analysis, transferResult);
- }
- // This point should never be reached. If the block of 'node' is
- // 'block', then 'node' must be part of the contents of 'block'.
- assert false;
- return null;
- }
-
- case EXCEPTION_BLOCK: {
- ExceptionBlock eb = (ExceptionBlock) block;
-
- // apply transfer function to content
- assert eb.getNode() == node;
- if (before) {
- return transferInput.getRegularStore();
- }
- analysis.currentNode = node;
- TransferResult<A, S> transferResult = analysis
- .callTransferFunction(node, transferInput);
- return transferResult.getRegularStore();
- }
- default:
- // Only regular blocks and exceptional blocks can hold nodes.
- assert false;
- break;
+ default:
+ // Only regular blocks and exceptional blocks can hold nodes.
+ assert false;
+ break;
}
return null;
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/ConditionalTransferResult.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/ConditionalTransferResult.java
index c49357a3ff..99a8a525ec 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/ConditionalTransferResult.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/ConditionalTransferResult.java
@@ -1,19 +1,15 @@
package org.checkerframework.dataflow.analysis;
import java.util.Map;
-
import javax.lang.model.type.TypeMirror;
/**
- * Implementation of a {@link TransferResult} with two non-exceptional store;
- * one for the 'then' edge and one for 'else'. The result of
- * {@code getRegularStore} will be the least upper bound of the two underlying
- * stores.
+ * Implementation of a {@link TransferResult} with two non-exceptional store; one for the 'then'
+ * edge and one for 'else'. The result of {@code getRegularStore} will be the least upper bound of
+ * the two underlying stores.
*
* @author Stefan Heule
- *
- * @param <S>
- * The {@link Store} used to keep track of intermediate results.
+ * @param <S> the {@link Store} used to keep track of intermediate results
*/
public class ConditionalTransferResult<A extends AbstractValue<A>, S extends Store<S>>
extends TransferResult<A, S> {
@@ -27,25 +23,21 @@ public class ConditionalTransferResult<A extends AbstractValue<A>, S extends Sto
protected S elseStore;
/**
- * Create a {@code ConditionalTransferResult} with {@code thenStore} as the
- * resulting store if the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} evaluates to
- * {@code true} and {@code elseStore} otherwise.
- *
- * For the meaning of storeChanged, see
- * {@link org.checkerframework.dataflow.analysis.TransferResult#storeChanged}.
+ * Create a {@code ConditionalTransferResult} with {@code thenStore} as the resulting store if
+ * the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} evaluates to {@code
+ * true} and {@code elseStore} otherwise.
*
- * <p>
+ * <p>For the meaning of storeChanged, see {@link
+ * org.checkerframework.dataflow.analysis.TransferResult#storeChanged}.
*
- * <em>Exceptions</em>: If the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} throws an
- * exception, then it is assumed that no special handling is necessary and
- * the store before the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} will be passed along any
- * exceptional edge.
+ * <p><em>Exceptions</em>: If the corresponding {@link
+ * org.checkerframework.dataflow.cfg.node.Node} throws an exception, then it is assumed that no
+ * special handling is necessary and the store before the corresponding {@link
+ * org.checkerframework.dataflow.cfg.node.Node} will be passed along any exceptional edge.
*
- * <p>
- *
- * <em>Aliasing</em>: {@code thenStore} and {@code elseStore} are not
- * allowed to be used anywhere outside of this class (including use through
- * aliases). Complete control over the objects is transfered to this class.
+ * <p><em>Aliasing</em>: {@code thenStore} and {@code elseStore} are not allowed to be used
+ * anywhere outside of this class (including use through aliases). Complete control over the
+ * objects is transfered to this class.
*/
public ConditionalTransferResult(A value, S thenStore, S elseStore, boolean storeChanged) {
super(value);
@@ -59,27 +51,27 @@ public class ConditionalTransferResult<A extends AbstractValue<A>, S extends Sto
}
/**
- * Create a {@code ConditionalTransferResult} with {@code thenStore} as the
- * resulting store if the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} evaluates to
- * {@code true} and {@code elseStore} otherwise.
- *
- * <p>
+ * Create a {@code ConditionalTransferResult} with {@code thenStore} as the resulting store if
+ * the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} evaluates to {@code
+ * true} and {@code elseStore} otherwise.
*
- * <em>Exceptions</em>: If the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} throws an
- * exception, then the corresponding store in {@code exceptionalStores} is
- * used. If no exception is found in {@code exceptionalStores}, then it is
- * assumed that no special handling is necessary and the store before the
- * corresponding {@link org.checkerframework.dataflow.cfg.node.Node} will be passed along any exceptional edge.
+ * <p><em>Exceptions</em>: If the corresponding {@link
+ * org.checkerframework.dataflow.cfg.node.Node} throws an exception, then the corresponding
+ * store in {@code exceptionalStores} is used. If no exception is found in {@code
+ * exceptionalStores}, then it is assumed that no special handling is necessary and the store
+ * before the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} will be passed
+ * along any exceptional edge.
*
- * <p>
- *
- * <em>Aliasing</em>: {@code thenStore}, {@code elseStore}, and any store in
- * {@code exceptionalStores} are not allowed to be used anywhere outside of
- * this class (including use through aliases). Complete control over the
- * objects is transfered to this class.
+ * <p><em>Aliasing</em>: {@code thenStore}, {@code elseStore}, and any store in {@code
+ * exceptionalStores} are not allowed to be used anywhere outside of this class (including use
+ * through aliases). Complete control over the objects is transfered to this class.
*/
- public ConditionalTransferResult(A value, S thenStore, S elseStore,
- Map<TypeMirror, S> exceptionalStores, boolean storeChanged) {
+ public ConditionalTransferResult(
+ A value,
+ S thenStore,
+ S elseStore,
+ Map<TypeMirror, S> exceptionalStores,
+ boolean storeChanged) {
super(value);
this.exceptionalStores = exceptionalStores;
this.thenStore = thenStore;
@@ -87,8 +79,8 @@ public class ConditionalTransferResult<A extends AbstractValue<A>, S extends Sto
this.storeChanged = storeChanged;
}
- public ConditionalTransferResult(A value, S thenStore, S elseStore,
- Map<TypeMirror, S> exceptionalStores) {
+ public ConditionalTransferResult(
+ A value, S thenStore, S elseStore, Map<TypeMirror, S> exceptionalStores) {
this(value, thenStore, elseStore, exceptionalStores, false);
}
@@ -126,12 +118,9 @@ public class ConditionalTransferResult<A extends AbstractValue<A>, S extends Sto
return result.toString();
}
- /**
- * @see org.checkerframework.dataflow.analysis.TransferResult#storeChanged()
- */
+ /** @see org.checkerframework.dataflow.analysis.TransferResult#storeChanged() */
@Override
public boolean storeChanged() {
- return storeChanged;
+ return storeChanged;
}
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/FlowExpressions.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/FlowExpressions.java
index 54828c7d31..85ad7b4b00 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/FlowExpressions.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/FlowExpressions.java
@@ -1,6 +1,25 @@
package org.checkerframework.dataflow.analysis;
+import com.sun.source.tree.ArrayAccessTree;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.IdentifierTree;
+import com.sun.source.tree.LiteralTree;
+import com.sun.source.tree.MemberSelectTree;
+import com.sun.source.tree.MethodInvocationTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.util.TreePath;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
import org.checkerframework.dataflow.cfg.node.ArrayAccessNode;
+import org.checkerframework.dataflow.cfg.node.ArrayCreationNode;
import org.checkerframework.dataflow.cfg.node.ClassNameNode;
import org.checkerframework.dataflow.cfg.node.ExplicitThisLiteralNode;
import org.checkerframework.dataflow.cfg.node.FieldAccessNode;
@@ -15,41 +34,33 @@ import org.checkerframework.dataflow.cfg.node.ValueLiteralNode;
import org.checkerframework.dataflow.cfg.node.WideningConversionNode;
import org.checkerframework.dataflow.util.HashCodeUtils;
import org.checkerframework.dataflow.util.PurityUtils;
-
import org.checkerframework.javacutil.AnnotationProvider;
import org.checkerframework.javacutil.ElementUtils;
+import org.checkerframework.javacutil.ErrorReporter;
+import org.checkerframework.javacutil.InternalUtils;
import org.checkerframework.javacutil.TreeUtils;
+import org.checkerframework.javacutil.TypeAnnotationUtils;
import org.checkerframework.javacutil.TypesUtils;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-
/**
- * Collection of classes and helper functions to represent Java expressions
- * about which the org.checkerframework.dataflow analysis can possibly infer facts. Expressions
- * include:
+ * Collection of classes and helper functions to represent Java expressions about which the
+ * org.checkerframework.dataflow analysis can possibly infer facts. Expressions include:
+ *
* <ul>
- * <li>Field accesses (e.g., <em>o.f</em>)</li>
- * <li>Local variables (e.g., <em>l</em>)</li>
- * <li>This reference (e.g., <em>this</em>)</li>
- * <li>Pure method calls (e.g., <em>o.m()</em>)</li>
- * <li>Unknown other expressions to mark that something else was present.</li>
+ * <li>Field accesses (e.g., <em>o.f</em>)
+ * <li>Local variables (e.g., <em>l</em>)
+ * <li>This reference (e.g., <em>this</em>)
+ * <li>Pure method calls (e.g., <em>o.m()</em>)
+ * <li>Unknown other expressions to mark that something else was present.
* </ul>
*
* @author Stefan Heule
- *
*/
public class FlowExpressions {
/**
- * @return The internal representation (as {@link FieldAccess}) of a
- * {@link FieldAccessNode}. Can contain {@link Unknown} as receiver.
+ * @return the internal representation (as {@link FieldAccess}) of a {@link FieldAccessNode}.
+ * Can contain {@link Unknown} as receiver.
*/
public static FieldAccess internalReprOfFieldAccess(
AnnotationProvider provider, FieldAccessNode node) {
@@ -64,8 +75,8 @@ public class FlowExpressions {
}
/**
- * @return The internal representation (as {@link FieldAccess}) of a
- * {@link FieldAccessNode}. Can contain {@link Unknown} as receiver.
+ * @return the internal representation (as {@link FieldAccess}) of a {@link FieldAccessNode}.
+ * Can contain {@link Unknown} as receiver.
*/
public static ArrayAccess internalReprOfArrayAccess(
AnnotationProvider provider, ArrayAccessNode node) {
@@ -75,26 +86,25 @@ public class FlowExpressions {
}
/**
- * We ignore operations such as widening and
- * narrowing when computing the internal representation.
+ * We ignore operations such as widening and narrowing when computing the internal
+ * representation.
*
- * @return The internal representation (as {@link Receiver}) of any
- * {@link Node}. Might contain {@link Unknown}.
+ * @return the internal representation (as {@link Receiver}) of any {@link Node}. Might contain
+ * {@link Unknown}.
*/
- public static Receiver internalReprOf(AnnotationProvider provider,
- Node receiverNode) {
+ public static Receiver internalReprOf(AnnotationProvider provider, Node receiverNode) {
return internalReprOf(provider, receiverNode, false);
}
/**
- * We ignore operations such as widening and
- * narrowing when computing the internal representation.
+ * We ignore operations such as widening and narrowing when computing the internal
+ * representation.
*
- * @return The internal representation (as {@link Receiver}) of any
- * {@link Node}. Might contain {@link Unknown}.
+ * @return the internal representation (as {@link Receiver}) of any {@link Node}. Might contain
+ * {@link Unknown}.
*/
- public static Receiver internalReprOf(AnnotationProvider provider,
- Node receiverNode, boolean allowNonDeterminitic) {
+ public static Receiver internalReprOf(
+ AnnotationProvider provider, Node receiverNode, boolean allowNonDeterministic) {
Receiver receiver = null;
if (receiverNode instanceof FieldAccessNode) {
FieldAccessNode fan = (FieldAccessNode) receiverNode;
@@ -103,6 +113,12 @@ public class FlowExpressions {
// For some reason, "className.this" is considered a field access.
// We right this wrong here.
receiver = new ThisReference(fan.getReceiver().getType());
+ } else if (fan.getFieldName().equals("class")) {
+ // "className.class" is considered a field access. This makes sense,
+ // since .class is similar to a field access which is the equivalent
+ // of a call to getClass(). However for the purposes of dataflow
+ // analysis, and value stores, this is the equivalent of a ClassNameNode.
+ receiver = new ClassName(fan.getReceiver().getType());
} else {
receiver = internalReprOfFieldAccess(provider, fan);
}
@@ -120,26 +136,25 @@ public class FlowExpressions {
receiver = internalReprOfArrayAccess(provider, a);
} else if (receiverNode instanceof StringConversionNode) {
// ignore string conversion
- return internalReprOf(provider,
- ((StringConversionNode) receiverNode).getOperand());
+ return internalReprOf(provider, ((StringConversionNode) receiverNode).getOperand());
} else if (receiverNode instanceof WideningConversionNode) {
// ignore widening
- return internalReprOf(provider,
- ((WideningConversionNode) receiverNode).getOperand());
+ return internalReprOf(provider, ((WideningConversionNode) receiverNode).getOperand());
} else if (receiverNode instanceof NarrowingConversionNode) {
// ignore narrowing
- return internalReprOf(provider,
- ((NarrowingConversionNode) receiverNode).getOperand());
+ return internalReprOf(provider, ((NarrowingConversionNode) receiverNode).getOperand());
} else if (receiverNode instanceof ClassNameNode) {
ClassNameNode cn = (ClassNameNode) receiverNode;
receiver = new ClassName(cn.getType());
} else if (receiverNode instanceof ValueLiteralNode) {
ValueLiteralNode vn = (ValueLiteralNode) receiverNode;
receiver = new ValueLiteral(vn.getType(), vn);
+ } else if (receiverNode instanceof ArrayCreationNode) {
+ ArrayCreationNode an = (ArrayCreationNode) receiverNode;
+ receiver = new ArrayCreation(an.getType(), an.getDimensions(), an.getInitializers());
} else if (receiverNode instanceof MethodInvocationNode) {
MethodInvocationNode mn = (MethodInvocationNode) receiverNode;
- ExecutableElement invokedMethod = TreeUtils.elementFromUse(mn
- .getTree());
+ ExecutableElement invokedMethod = TreeUtils.elementFromUse(mn.getTree());
// check if this represents a boxing operation of a constant, in which
// case we treat the method call as deterministic, because there is no way
@@ -153,21 +168,20 @@ public class FlowExpressions {
}
}
- if (PurityUtils.isDeterministic(provider, invokedMethod) || allowNonDeterminitic || considerDeterministic) {
+ if (PurityUtils.isDeterministic(provider, invokedMethod)
+ || allowNonDeterministic
+ || considerDeterministic) {
List<Receiver> parameters = new ArrayList<>();
for (Node p : mn.getArguments()) {
parameters.add(internalReprOf(provider, p));
}
Receiver methodReceiver;
if (ElementUtils.isStatic(invokedMethod)) {
- methodReceiver = new ClassName(mn.getTarget().getReceiver()
- .getType());
+ methodReceiver = new ClassName(mn.getTarget().getReceiver().getType());
} else {
- methodReceiver = internalReprOf(provider, mn.getTarget()
- .getReceiver());
+ methodReceiver = internalReprOf(provider, mn.getTarget().getReceiver());
}
- receiver = new PureMethodCall(mn.getType(), invokedMethod,
- methodReceiver, parameters);
+ receiver = new MethodCall(mn.getType(), invokedMethod, methodReceiver, parameters);
}
}
@@ -177,7 +191,209 @@ public class FlowExpressions {
return receiver;
}
- public static abstract class Receiver {
+ /**
+ * @return the internal representation (as {@link Receiver}) of any {@link ExpressionTree}.
+ * Might contain {@link Unknown}.
+ */
+ public static Receiver internalReprOf(
+ AnnotationProvider provider, ExpressionTree receiverTree) {
+ return internalReprOf(provider, receiverTree, true);
+ }
+ /**
+ * We ignore operations such as widening and narrowing when computing the internal
+ * representation.
+ *
+ * @return the internal representation (as {@link Receiver}) of any {@link ExpressionTree}.
+ * Might contain {@link Unknown}.
+ */
+ public static Receiver internalReprOf(
+ AnnotationProvider provider,
+ ExpressionTree receiverTree,
+ boolean allowNonDeterministic) {
+ Receiver receiver;
+ switch (receiverTree.getKind()) {
+ case ARRAY_ACCESS:
+ ArrayAccessTree a = (ArrayAccessTree) receiverTree;
+ Receiver arrayAccessExpression = internalReprOf(provider, a.getExpression());
+ Receiver index = internalReprOf(provider, a.getIndex());
+ receiver = new ArrayAccess(InternalUtils.typeOf(a), arrayAccessExpression, index);
+ break;
+ case BOOLEAN_LITERAL:
+ case CHAR_LITERAL:
+ case DOUBLE_LITERAL:
+ case FLOAT_LITERAL:
+ case INT_LITERAL:
+ case LONG_LITERAL:
+ case NULL_LITERAL:
+ case STRING_LITERAL:
+ LiteralTree vn = (LiteralTree) receiverTree;
+ receiver = new ValueLiteral(InternalUtils.typeOf(receiverTree), vn.getValue());
+ break;
+ case NEW_ARRAY:
+ receiver =
+ new ArrayCreation(
+ InternalUtils.typeOf(receiverTree),
+ Collections.<Node>emptyList(),
+ Collections.<Node>emptyList());
+ break;
+ case METHOD_INVOCATION:
+ MethodInvocationTree mn = (MethodInvocationTree) receiverTree;
+ ExecutableElement invokedMethod = TreeUtils.elementFromUse(mn);
+ if (PurityUtils.isDeterministic(provider, invokedMethod) || allowNonDeterministic) {
+ List<Receiver> parameters = new ArrayList<>();
+ for (ExpressionTree p : mn.getArguments()) {
+ parameters.add(internalReprOf(provider, p));
+ }
+ Receiver methodReceiver;
+ if (ElementUtils.isStatic(invokedMethod)) {
+ methodReceiver = new ClassName(InternalUtils.typeOf(mn.getMethodSelect()));
+ } else {
+ methodReceiver = internalReprOf(provider, mn.getMethodSelect());
+ }
+ TypeMirror type = InternalUtils.typeOf(mn);
+ receiver = new MethodCall(type, invokedMethod, methodReceiver, parameters);
+ } else {
+ receiver = null;
+ }
+ break;
+ case MEMBER_SELECT:
+ receiver = internalRepOfMemberSelect(provider, (MemberSelectTree) receiverTree);
+ break;
+ case IDENTIFIER:
+ IdentifierTree identifierTree = (IdentifierTree) receiverTree;
+ TypeMirror typeOfId = InternalUtils.typeOf(identifierTree);
+ if (identifierTree.getName().contentEquals("this")
+ || identifierTree.getName().contentEquals("super")) {
+ receiver = new ThisReference(typeOfId);
+ break;
+ }
+ Element ele = TreeUtils.elementFromUse(identifierTree);
+ switch (ele.getKind()) {
+ case LOCAL_VARIABLE:
+ case RESOURCE_VARIABLE:
+ case EXCEPTION_PARAMETER:
+ case PARAMETER:
+ receiver = new LocalVariable(ele);
+ break;
+ case FIELD:
+ // Implicit access expression, such as "this" or a class name
+ Receiver fieldAccessExpression;
+ TypeMirror enclosingType = ElementUtils.enclosingClass(ele).asType();
+ if (ElementUtils.isStatic(ele)) {
+ fieldAccessExpression = new ClassName(enclosingType);
+ } else {
+ fieldAccessExpression = new ThisReference(enclosingType);
+ }
+ receiver =
+ new FieldAccess(
+ fieldAccessExpression, typeOfId, (VariableElement) ele);
+ break;
+ case CLASS:
+ case ENUM:
+ case ANNOTATION_TYPE:
+ case INTERFACE:
+ receiver = new ClassName(ele.asType());
+ break;
+ default:
+ receiver = null;
+ }
+ break;
+ default:
+ receiver = null;
+ }
+
+ if (receiver == null) {
+ receiver = new Unknown(InternalUtils.typeOf(receiverTree));
+ }
+ return receiver;
+ }
+
+ /**
+ * Returns the implicit receiver of ele.
+ *
+ * <p>Returns either a new ClassName or a new ThisReference depending on whether ele is static
+ * or not. The passed element must be a field, method, or class.
+ *
+ * @param ele field, method, or class
+ * @return either a new ClassName or a new ThisReference depending on whether ele is static or
+ * not
+ */
+ public static Receiver internalRepOfImplicitReceiver(Element ele) {
+ TypeMirror enclosingType = ElementUtils.enclosingClass(ele).asType();
+ if (ElementUtils.isStatic(ele)) {
+ return new ClassName(enclosingType);
+ } else {
+ return new ThisReference(enclosingType);
+ }
+ }
+
+ /**
+ * Returns either a new ClassName or ThisReference Receiver object for the enclosingType
+ *
+ * <p>The Tree should be an expression or a statement that does not have a receiver or an
+ * implicit receiver. For example, a local variable declaration.
+ *
+ * @param path TreePath to tree
+ * @param enclosingType type of the enclosing type
+ * @return a new ClassName or ThisReference that is a Receiver object for the enclosingType
+ */
+ public static Receiver internalRepOfPseudoReceiver(TreePath path, TypeMirror enclosingType) {
+ if (TreeUtils.isTreeInStaticScope(path)) {
+ return new ClassName(enclosingType);
+ } else {
+ return new ThisReference(enclosingType);
+ }
+ }
+
+ private static Receiver internalRepOfMemberSelect(
+ AnnotationProvider provider, MemberSelectTree memberSelectTree) {
+ TypeMirror expressionType = InternalUtils.typeOf(memberSelectTree.getExpression());
+ if (TreeUtils.isClassLiteral(memberSelectTree)) {
+ return new ClassName(expressionType);
+ }
+ Element ele = TreeUtils.elementFromUse(memberSelectTree);
+ switch (ele.getKind()) {
+ case METHOD:
+ case CONSTRUCTOR:
+ return internalReprOf(provider, memberSelectTree.getExpression());
+ case CLASS: // o instanceof MyClass.InnerClass
+ case ENUM:
+ case INTERFACE: // o instanceof MyClass.InnerInterface
+ case ANNOTATION_TYPE:
+ return new ClassName(expressionType);
+ case ENUM_CONSTANT:
+ case FIELD:
+ Receiver r = internalReprOf(provider, memberSelectTree.getExpression());
+ return new FieldAccess(r, ElementUtils.getType(ele), (VariableElement) ele);
+ default:
+ ErrorReporter.errorAbort(
+ "Unexpected element kind: %s element: %s", ele.getKind(), ele);
+ return null;
+ }
+ }
+
+ /**
+ * Returns Receiver objects for the formal parameters of the method in which path is enclosed.
+ *
+ * @param annotationProvider annotationProvider
+ * @param path TreePath that is enclosed by the method
+ * @return list of Receiver objects for the formal parameters of the method in which path is
+ * enclosed
+ */
+ public static List<Receiver> getParametersOfEnclosingMethod(
+ AnnotationProvider annotationProvider, TreePath path) {
+ MethodTree methodTree = TreeUtils.enclosingMethod(path);
+ if (methodTree == null) {
+ return null;
+ }
+ List<Receiver> internalArguments = new ArrayList<>();
+ for (VariableTree arg : methodTree.getParameters()) {
+ internalArguments.add(internalReprOf(annotationProvider, new LocalVariableNode(arg)));
+ }
+ return internalArguments;
+ }
+
+ public abstract static class Receiver {
protected final TypeMirror type;
public Receiver(TypeMirror type) {
@@ -196,38 +412,32 @@ public class FlowExpressions {
}
/**
- * Returns true if and only if the value this expression stands for
- * cannot be changed by a method call. This is the case for local
- * variables, the self reference as well as final field accesses for
- * whose receiver {@link #isUnmodifiableByOtherCode} is true.
+ * Returns true if and only if the value this expression stands for cannot be changed by a
+ * method call. This is the case for local variables, the self reference as well as final
+ * field accesses for whose receiver {@link #isUnmodifiableByOtherCode} is true.
*/
public abstract boolean isUnmodifiableByOtherCode();
- /**
- * @return True if and only if the two receiver are syntactically
- * identical.
- */
+ /** @return true if and only if the two receiver are syntactically identical */
public boolean syntacticEquals(Receiver other) {
return other == this;
}
/**
- * @return True if and only if this receiver contains a receiver that is
- * syntactically equal to {@code other}.
+ * @return true if and only if this receiver contains a receiver that is syntactically equal
+ * to {@code other}.
*/
public boolean containsSyntacticEqualReceiver(Receiver other) {
return syntacticEquals(other);
}
/**
- * Returns true if and only if {@code other} appear anywhere in this
- * receiver or an expression appears in this receiver such that
- * {@code other} might alias this expression, and that expression is
- * modifiable.
+ * Returns true if and only if {@code other} appears anywhere in this receiver or an
+ * expression appears in this receiver such that {@code other} might alias this expression,
+ * and that expression is modifiable.
*
- * <p>
- * This is always true, except for cases where the Java type information
- * prevents aliasing and none of the subexpressions can alias 'other'.
+ * <p>This is always true, except for cases where the Java type information prevents
+ * aliasing and none of the subexpressions can alias 'other'.
*/
public boolean containsModifiableAliasOf(Store<?> store, Receiver other) {
return this.equals(other) || store.canAlias(this, other);
@@ -252,8 +462,7 @@ public class FlowExpressions {
this.field = node.getElement();
}
- public FieldAccess(Receiver receiver, TypeMirror type,
- VariableElement fieldElement) {
+ public FieldAccess(Receiver receiver, TypeMirror type, VariableElement fieldElement) {
super(type);
this.receiver = receiver;
this.field = fieldElement;
@@ -273,8 +482,7 @@ public class FlowExpressions {
return false;
}
FieldAccess fa = (FieldAccess) obj;
- return fa.getField().equals(getField())
- && fa.getReceiver().equals(getReceiver());
+ return fa.getField().equals(getField()) && fa.getReceiver().equals(getReceiver());
}
@Override
@@ -290,8 +498,7 @@ public class FlowExpressions {
@Override
public boolean containsSyntacticEqualReceiver(Receiver other) {
- return syntacticEquals(other)
- || receiver.containsSyntacticEqualReceiver(other);
+ return syntacticEquals(other) || receiver.containsSyntacticEqualReceiver(other);
}
@Override
@@ -301,13 +508,17 @@ public class FlowExpressions {
}
FieldAccess fa = (FieldAccess) other;
return super.syntacticEquals(other)
- || fa.getField().equals(getField())
- && fa.getReceiver().syntacticEquals(getReceiver());
+ || (fa.getField().equals(getField())
+ && fa.getReceiver().syntacticEquals(getReceiver()));
}
@Override
public String toString() {
- return receiver + "." + field;
+ if (receiver instanceof ClassName) {
+ return receiver.getType() + "." + field;
+ } else {
+ return receiver + "." + field;
+ }
}
@Override
@@ -363,12 +574,10 @@ public class FlowExpressions {
}
/**
- * A ClassName represents the occurrence of a class as part of a static
- * field access or method invocation.
+ * A ClassName represents the occurrence of a class as part of a static field access or method
+ * invocation.
*/
public static class ClassName extends Receiver {
- protected Element element;
-
public ClassName(TypeMirror type) {
super(type);
}
@@ -389,7 +598,7 @@ public class FlowExpressions {
@Override
public String toString() {
- return getType().toString();
+ return getType().toString() + ".class";
}
@Override
@@ -447,7 +656,6 @@ public class FlowExpressions {
public boolean isUnmodifiableByOtherCode() {
return false;
}
-
}
public static class LocalVariable extends Receiver {
@@ -469,7 +677,17 @@ public class FlowExpressions {
return false;
}
LocalVariable other = (LocalVariable) obj;
- return other.element.equals(element);
+ VarSymbol vs = (VarSymbol) element;
+ VarSymbol vsother = (VarSymbol) other.element;
+ // Use TypeAnnotationUtils.unannotatedType(type).toString().equals(...) instead of Types.isSameType(...)
+ // because Types requires a processing environment, and FlowExpressions is
+ // designed to be independent of processing environment. See also
+ // calls to getType().toString() in FlowExpressions.
+ return vsother.name.contentEquals(vs.name)
+ && TypeAnnotationUtils.unannotatedType(vsother.type)
+ .toString()
+ .equals(TypeAnnotationUtils.unannotatedType(vs.type).toString())
+ && vsother.owner.toString().equals(vs.owner.toString());
}
public Element getElement() {
@@ -478,7 +696,11 @@ public class FlowExpressions {
@Override
public int hashCode() {
- return HashCodeUtils.hash(element);
+ VarSymbol vs = (VarSymbol) element;
+ return HashCodeUtils.hash(
+ vs.name.toString(),
+ TypeAnnotationUtils.unannotatedType(vs.type).toString(),
+ vs.owner.toString());
}
@Override
@@ -497,7 +719,7 @@ public class FlowExpressions {
return false;
}
LocalVariable l = (LocalVariable) other;
- return l.getElement().equals(getElement());
+ return l.equals(this);
}
@Override
@@ -542,11 +764,9 @@ public class FlowExpressions {
}
ValueLiteral other = (ValueLiteral) obj;
if (value == null) {
- return type.toString().equals(other.type.toString())
- && other.value == null;
+ return type.toString().equals(other.type.toString()) && other.value == null;
}
- return type.toString().equals(other.type.toString())
- && value.equals(other.value);
+ return type.toString().equals(other.type.toString()) && value.equals(other.value);
}
@Override
@@ -573,23 +793,24 @@ public class FlowExpressions {
public boolean containsModifiableAliasOf(Store<?> store, Receiver other) {
return false; // not modifiable
}
+
+ public Object getValue() {
+ return value;
+ }
}
- /**
- * A method call, typically a deterministic one. However, this is not
- * enforced and non-pure methods are also possible. It is the clients
- * responsibility to ensure that using non-deterministic methods is done in
- * a sound way. The CF allows non-deterministic methods to be used in
- * postconditions such as EnsuresNonNull.
- */
- public static class PureMethodCall extends Receiver {
+ /** A method call. */
+ public static class MethodCall extends Receiver {
protected final Receiver receiver;
protected final List<Receiver> parameters;
- protected final Element method;
+ protected final ExecutableElement method;
- public PureMethodCall(TypeMirror type, Element method,
- Receiver receiver, List<Receiver> parameters) {
+ public MethodCall(
+ TypeMirror type,
+ ExecutableElement method,
+ Receiver receiver,
+ List<Receiver> parameters) {
super(type);
this.receiver = receiver;
this.parameters = parameters;
@@ -612,6 +833,24 @@ public class FlowExpressions {
return false;
}
+ /** @return the method call receiver (for inspection only - do not modify) */
+ public Receiver getReceiver() {
+ return receiver;
+ }
+
+ /**
+ * @return the method call parameters (for inspection only - do not modify any of the
+ * parameters)
+ */
+ public List<Receiver> getParameters() {
+ return Collections.unmodifiableList(parameters);
+ }
+
+ /** @return the ExecutableElement for the method call */
+ public ExecutableElement getElement() {
+ return method;
+ }
+
@Override
public boolean isUnmodifiableByOtherCode() {
return false;
@@ -624,10 +863,10 @@ public class FlowExpressions {
@Override
public boolean syntacticEquals(Receiver other) {
- if (!(other instanceof PureMethodCall)) {
+ if (!(other instanceof MethodCall)) {
return false;
}
- PureMethodCall otherMethod = (PureMethodCall) other;
+ MethodCall otherMethod = (MethodCall) other;
if (!receiver.syntacticEquals(otherMethod.receiver)) {
return false;
}
@@ -668,10 +907,10 @@ public class FlowExpressions {
@Override
public boolean equals(Object obj) {
- if (obj == null || !(obj instanceof PureMethodCall)) {
+ if (obj == null || !(obj instanceof MethodCall)) {
return false;
}
- PureMethodCall other = (PureMethodCall) obj;
+ MethodCall other = (MethodCall) obj;
int i = 0;
for (Receiver p : parameters) {
if (!p.equals(other.parameters.get(i))) {
@@ -679,8 +918,7 @@ public class FlowExpressions {
}
i++;
}
- return receiver.equals(other.receiver)
- && method.equals(other.method);
+ return receiver.equals(other.receiver) && method.equals(other.method);
}
@Override
@@ -695,7 +933,11 @@ public class FlowExpressions {
@Override
public String toString() {
StringBuilder result = new StringBuilder();
- result.append(receiver.toString());
+ if (receiver instanceof ClassName) {
+ result.append(receiver.getType());
+ } else {
+ result.append(receiver);
+ }
result.append(".");
String methodName = method.getSimpleName().toString();
result.append(methodName);
@@ -713,9 +955,7 @@ public class FlowExpressions {
}
}
- /**
- * A deterministic method call.
- */
+ /** A deterministic method call. */
public static class ArrayAccess extends Receiver {
protected final Receiver receiver;
@@ -753,7 +993,8 @@ public class FlowExpressions {
@Override
public boolean containsSyntacticEqualReceiver(Receiver other) {
- return syntacticEquals(other) || receiver.syntacticEquals(other)
+ return syntacticEquals(other)
+ || receiver.syntacticEquals(other)
|| index.syntacticEquals(other);
}
@@ -801,4 +1042,102 @@ public class FlowExpressions {
return result.toString();
}
}
+
+ public static class ArrayCreation extends Receiver {
+
+ protected List<Node> dimensions;
+ protected List<Node> initializers;
+
+ public ArrayCreation(TypeMirror type, List<Node> dimensions, List<Node> initializers) {
+ super(type);
+ this.dimensions = dimensions;
+ this.initializers = initializers;
+ }
+
+ public List<Node> getDimensions() {
+ return dimensions;
+ }
+
+ public List<Node> getInitializers() {
+ return initializers;
+ }
+
+ @Override
+ public boolean containsOfClass(Class<? extends Receiver> clazz) {
+ for (Node n : dimensions) {
+ if (n.getClass().equals(clazz)) return true;
+ }
+ for (Node n : initializers) {
+ if (n.getClass().equals(clazz)) return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isUnmodifiableByOtherCode() {
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((dimensions == null) ? 0 : dimensions.hashCode());
+ result = prime * result + ((initializers == null) ? 0 : initializers.hashCode());
+ result = prime * result + HashCodeUtils.hash(getType().toString());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || !(obj instanceof ArrayCreation)) {
+ return false;
+ }
+ ArrayCreation other = (ArrayCreation) obj;
+ return this.dimensions.equals(other.getDimensions())
+ && this.initializers.equals(other.getInitializers())
+ && getType().toString().equals(other.getType().toString());
+ }
+
+ @Override
+ public boolean syntacticEquals(Receiver other) {
+ return this.equals(other);
+ }
+
+ @Override
+ public boolean containsSyntacticEqualReceiver(Receiver other) {
+ return syntacticEquals(other);
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("new " + type);
+ if (!dimensions.isEmpty()) {
+ boolean needComma = false;
+ sb.append(" (");
+ for (Node dim : dimensions) {
+ if (needComma) {
+ sb.append(", ");
+ }
+ sb.append(dim);
+ needComma = true;
+ }
+ sb.append(")");
+ }
+ if (!initializers.isEmpty()) {
+ boolean needComma = false;
+ sb.append(" = {");
+ for (Node init : initializers) {
+ if (needComma) {
+ sb.append(", ");
+ }
+ sb.append(init);
+ needComma = true;
+ }
+ sb.append("}");
+ }
+ return sb.toString();
+ }
+ }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/RegularTransferResult.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/RegularTransferResult.java
index 8872e7f808..b4044fae83 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/RegularTransferResult.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/RegularTransferResult.java
@@ -1,43 +1,36 @@
package org.checkerframework.dataflow.analysis;
import java.util.Map;
-
import javax.lang.model.type.TypeMirror;
/**
- * Implementation of a {@link TransferResult} with just one non-exceptional
- * store. The result of {@code getThenStore} and {@code getElseStore} is equal
- * to the only underlying store.
+ * Implementation of a {@link TransferResult} with just one non-exceptional store. The result of
+ * {@code getThenStore} and {@code getElseStore} is equal to the only underlying store.
*
* @author Stefan Heule
- *
- * @param <S>
- * The {@link Store} used to keep track of intermediate results.
+ * @param <S> the {@link Store} used to keep track of intermediate results
*/
public class RegularTransferResult<A extends AbstractValue<A>, S extends Store<S>>
extends TransferResult<A, S> {
/** The regular result store. */
protected S store;
- final private boolean storeChanged;
+
+ private final boolean storeChanged;
/**
- * Create a {@code TransferResult} with {@code resultStore} as the resulting
- * store. If the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} is a boolean node, then
+ * Create a {@code TransferResult} with {@code resultStore} as the resulting store. If the
+ * corresponding {@link org.checkerframework.dataflow.cfg.node.Node} is a boolean node, then
* {@code resultStore} is used for both the 'then' and 'else' edge.
*
- * <p>
- *
- * <em>Exceptions</em>: If the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} throws an
- * exception, then it is assumed that no special handling is necessary and
- * the store before the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} will be passed along any
- * exceptional edge.
- *
- * <p>
+ * <p><em>Exceptions</em>: If the corresponding {@link
+ * org.checkerframework.dataflow.cfg.node.Node} throws an exception, then it is assumed that no
+ * special handling is necessary and the store before the corresponding {@link
+ * org.checkerframework.dataflow.cfg.node.Node} will be passed along any exceptional edge.
*
- * <em>Aliasing</em>: {@code resultStore} is not allowed to be used anywhere
- * outside of this class (including use through aliases). Complete control
- * over the object is transfered to this class.
+ * <p><em>Aliasing</em>: {@code resultStore} is not allowed to be used anywhere outside of this
+ * class (including use through aliases). Complete control over the object is transfered to this
+ * class.
*/
public RegularTransferResult(A value, S resultStore, boolean storeChanged) {
super(value);
@@ -50,38 +43,33 @@ public class RegularTransferResult<A extends AbstractValue<A>, S extends Store<S
}
/**
- * Create a {@code TransferResult} with {@code resultStore} as the resulting
- * store. If the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} is a boolean node, then
+ * Create a {@code TransferResult} with {@code resultStore} as the resulting store. If the
+ * corresponding {@link org.checkerframework.dataflow.cfg.node.Node} is a boolean node, then
* {@code resultStore} is used for both the 'then' and 'else' edge.
*
- * For the meaning of storeChanged, see
- * {@link org.checkerframework.dataflow.analysis.TransferResult#storeChanged}.
+ * <p>For the meaning of storeChanged, see {@link
+ * org.checkerframework.dataflow.analysis.TransferResult#storeChanged}.
*
- * <p>
+ * <p><em>Exceptions</em>: If the corresponding {@link
+ * org.checkerframework.dataflow.cfg.node.Node} throws an exception, then the corresponding
+ * store in {@code exceptionalStores} is used. If no exception is found in {@code
+ * exceptionalStores}, then it is assumed that no special handling is necessary and the store
+ * before the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} will be passed
+ * along any exceptional edge.
*
- * <em>Exceptions</em>: If the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} throws an
- * exception, then the corresponding store in {@code exceptionalStores} is
- * used. If no exception is found in {@code exceptionalStores}, then it is
- * assumed that no special handling is necessary and the store before the
- * corresponding {@link org.checkerframework.dataflow.cfg.node.Node} will be passed along any exceptional edge.
- *
- * <p>
- *
- * <em>Aliasing</em>: {@code resultStore} and any store in
- * {@code exceptionalStores} are not allowed to be used anywhere outside of
- * this class (including use through aliases). Complete control over the
- * objects is transfered to this class.
+ * <p><em>Aliasing</em>: {@code resultStore} and any store in {@code exceptionalStores} are not
+ * allowed to be used anywhere outside of this class (including use through aliases). Complete
+ * control over the objects is transfered to this class.
*/
- public RegularTransferResult(A value, S resultStore,
- Map<TypeMirror, S> exceptionalStores, boolean storeChanged) {
+ public RegularTransferResult(
+ A value, S resultStore, Map<TypeMirror, S> exceptionalStores, boolean storeChanged) {
super(value);
this.store = resultStore;
this.storeChanged = storeChanged;
this.exceptionalStores = exceptionalStores;
}
- public RegularTransferResult(A value, S resultStore,
- Map<TypeMirror, S> exceptionalStores) {
+ public RegularTransferResult(A value, S resultStore, Map<TypeMirror, S> exceptionalStores) {
this(value, resultStore, exceptionalStores, false);
}
@@ -120,11 +108,9 @@ public class RegularTransferResult<A extends AbstractValue<A>, S extends Store<S
return result.toString();
}
- /**
- * @see org.checkerframework.dataflow.analysis.TransferResult#storeChanged()
- */
+ /** @see org.checkerframework.dataflow.analysis.TransferResult#storeChanged() */
@Override
public boolean storeChanged() {
- return storeChanged;
+ return storeChanged;
}
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/Store.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/Store.java
index 90c7f20b9c..5d714da889 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/Store.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/Store.java
@@ -1,15 +1,15 @@
package org.checkerframework.dataflow.analysis;
+import org.checkerframework.dataflow.cfg.CFGVisualizer;
+
/**
* A store is used to keep track of the information that the org.checkerframework.dataflow analysis
* has accumulated at any given point in time.
*
* @author Stefan Heule
- *
- * @param <S>
- * The type of the store returned by {@code copy} and that is used in
- * {@code leastUpperBound}. Usually it is the implementing class
- * itself, e.g. in {@code T extends Store<T>}.
+ * @param <S> the type of the store returned by {@code copy} and that is used in {@code
+ * leastUpperBound}. Usually it is the implementing class itself, e.g. in {@code T extends
+ * Store<T>}.
*/
public interface Store<S extends Store<S>> {
@@ -24,47 +24,68 @@ public interface Store<S extends Store<S>> {
BOTH
}
- // A flow rule describes how stores flow along one edge between basic blocks.
+ /** A flow rule describes how stores flow along one edge between basic blocks. */
public static enum FlowRule {
- EACH_TO_EACH, // The normal case, then store flows to the then store
- // and else store flows to the else store.
- THEN_TO_BOTH, // Then store flows to both then and else of successor.
- ELSE_TO_BOTH, // Else store flows to both then and else of successor.
- THEN_TO_THEN, // Then store flows to the then of successor. Else store is ignored.
- ELSE_TO_ELSE, // Else store flows to the else of successor. Then store is ignored.
+ EACH_TO_EACH, // The normal case, then store flows to the then store
+ // and else store flows to the else store.
+ THEN_TO_BOTH, // Then store flows to both then and else of successor.
+ ELSE_TO_BOTH, // Else store flows to both then and else of successor.
+ THEN_TO_THEN, // Then store flows to the then of successor. Else store is ignored.
+ ELSE_TO_ELSE, // Else store flows to the else of successor. Then store is ignored.
}
- /** @return An exact copy of this store. */
+ /** @return an exact copy of this store. */
S copy();
/**
* Compute the least upper bound of two stores.
*
- * <p>
+ * <p><em>Important</em>: This method must fulfill the following contract:
*
- * <em>Important</em>: This method must fulfill the following contract:
* <ul>
- * <li>Does not change {@code this}.</li>
- * <li>Does not change {@code other}.</li>
- * <li>Returns a fresh object which is not aliased yet.</li>
- * <li>Returns an object of the same (dynamic) type as {@code this}, even if
- * the signature is more permissive.</li>
- * <li>Is commutative.</li>
+ * <li>Does not change {@code this}.
+ * <li>Does not change {@code other}.
+ * <li>Returns a fresh object which is not aliased yet.
+ * <li>Returns an object of the same (dynamic) type as {@code this}, even if the signature is
+ * more permissive.
+ * <li>Is commutative.
* </ul>
*/
S leastUpperBound(S other);
/**
- * Can the objects {@code a} and {@code b} be aliases? Returns a
- * conservative answer (i.e., returns {@code true} if not enough information
- * is available to determine aliasing).
+ * Compute an upper bound of two stores that is wider than the least upper bound of the two
+ * stores. Used to jump to a higher abstraction to allow faster termination of the fixed point
+ * computations in {@link Analysis}. {@code previous} must be the previous store.
+ *
+ * <p>A particular analysis might not require widening and should implement this method by
+ * calling leastUpperBound.
+ *
+ * <p><em>Important</em>: This method must fulfill the following contract:
+ *
+ * <ul>
+ * <li>Does not change {@code this}.
+ * <li>Does not change {@code previous}.
+ * <li>Returns a fresh object which is not aliased yet.
+ * <li>Returns an object of the same (dynamic) type as {@code this}, even if the signature is
+ * more permissive.
+ * <li>Is commutative.
+ * </ul>
+ *
+ * @param previous must be the previous store
*/
- boolean canAlias(FlowExpressions.Receiver a,
- FlowExpressions.Receiver b);
+ S widenedUpperBound(S previous);
- /** @return Whether the Store supports DOT graph output. */
- boolean hasDOToutput();
+ /**
+ * Can the objects {@code a} and {@code b} be aliases? Returns a conservative answer (i.e.,
+ * returns {@code true} if not enough information is available to determine aliasing).
+ */
+ boolean canAlias(FlowExpressions.Receiver a, FlowExpressions.Receiver b);
- /** @return The store encoded as a DOT graph for visualization. */
- String toDOToutput();
+ /**
+ * Delegate visualization responsibility to a visualizer.
+ *
+ * @param viz the visualizer to visualize this store
+ */
+ void visualize(CFGVisualizer<?, S, ?> viz);
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferFunction.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferFunction.java
index e21ab5646a..a10a766b33 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferFunction.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferFunction.java
@@ -4,46 +4,38 @@ package org.checkerframework.dataflow.analysis;
import org.checkerframework.checker.nullness.qual.Nullable;
*/
+import java.util.List;
import org.checkerframework.dataflow.cfg.UnderlyingAST;
import org.checkerframework.dataflow.cfg.node.LocalVariableNode;
import org.checkerframework.dataflow.cfg.node.Node;
import org.checkerframework.dataflow.cfg.node.NodeVisitor;
-import java.util.List;
-
/**
- * Interface of a transfer function for the abstract interpretation used for the
- * flow analysis.
+ * Interface of a transfer function for the abstract interpretation used for the flow analysis.
*
- * <p>
+ * <p>A transfer function consists of the following components:
*
- * A transfer function consists of the following components:
* <ul>
- * <li>A method {@code initialStore} that determines which initial store should
- * be used in the org.checkerframework.dataflow analysis.</li>
- * <li>A function for every {@link Node} type that determines the behavior of
- * the org.checkerframework.dataflow analysis in that case. This method takes a {@link Node} and an
- * incoming store, and produces a {@link RegularTransferResult}.</li>
+ * <li>A method {@code initialStore} that determines which initial store should be used in the
+ * org.checkerframework.dataflow analysis.
+ * <li>A function for every {@link Node} type that determines the behavior of the
+ * org.checkerframework.dataflow analysis in that case. This method takes a {@link Node} and
+ * an incoming store, and produces a {@link RegularTransferResult}.
* </ul>
*
- * <p>
- *
- * <em>Important</em>: The individual transfer functions ( {@code visit*}) are
- * allowed to use (and modify) the stores contained in the argument passed; the
- * ownership is transfered from the caller to that function.
+ * <p><em>Important</em>: The individual transfer functions ( {@code visit*}) are allowed to use
+ * (and modify) the stores contained in the argument passed; the ownership is transfered from the
+ * caller to that function.
*
* @author Stefan Heule
- *
- * @param <S>
- * The {@link Store} used to keep track of intermediate results.
+ * @param <S> the {@link Store} used to keep track of intermediate results
*/
public interface TransferFunction<A extends AbstractValue<A>, S extends Store<S>>
extends NodeVisitor<TransferResult<A, S>, TransferInput<A, S>> {
/**
- * @return The initial store to be used by the org.checkerframework.dataflow analysis.
- * {@code parameters} is only set if the underlying AST is a method.
+ * @return the initial store to be used by the org.checkerframework.dataflow analysis. {@code
+ * parameters} is only set if the underlying AST is a method.
*/
- S initialStore(UnderlyingAST underlyingAST,
- /*@Nullable*/ List<LocalVariableNode> parameters);
+ S initialStore(UnderlyingAST underlyingAST, /*@Nullable*/ List<LocalVariableNode> parameters);
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferInput.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferInput.java
index 7314b35e13..f827ad302d 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferInput.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferInput.java
@@ -8,79 +8,65 @@ import org.checkerframework.dataflow.cfg.node.Node;
import org.checkerframework.dataflow.util.HashCodeUtils;
/**
- * {@code TransferInput} is used as the input type of the individual transfer
- * functions of a {@link TransferFunction}. It also contains a reference to the
- * node for which the transfer function will be applied.
+ * {@code TransferInput} is used as the input type of the individual transfer functions of a {@link
+ * TransferFunction}. It also contains a reference to the node for which the transfer function will
+ * be applied.
*
- * <p>
- *
- * A {@code TransferInput} contains one or two stores. If two stores are
- * present, one belongs to 'then', and the other to 'else'.
+ * <p>A {@code TransferInput} contains one or two stores. If two stores are present, one belongs to
+ * 'then', and the other to 'else'.
*
* @author Stefan Heule
- *
- * @param <S>
- * The {@link Store} used to keep track of intermediate results.
+ * @param <S> the {@link Store} used to keep track of intermediate results
*/
public class TransferInput<A extends AbstractValue<A>, S extends Store<S>> {
- /**
- * The corresponding node.
- */
+ /** The corresponding node. */
protected Node node;
/**
- * The regular result store (or {@code null} if none is present). The
- * following invariant is maintained:
+ * The regular result store (or {@code null} if none is present). The following invariant is
+ * maintained:
*
- * <pre>
- * store == null &lt;==&gt; thenStore != null &amp;&amp; elseStore != null
- * </pre>
+ * <pre>{@code
+ * store == null &hArr; thenStore != null &amp;&amp; elseStore != null
+ * }</pre>
*/
protected final /*@Nullable*/ S store;
/**
- * The 'then' result store (or {@code null} if none is present). The
- * following invariant is maintained:
+ * The 'then' result store (or {@code null} if none is present). The following invariant is
+ * maintained:
*
- * <pre>
- * store == null &lt;==&gt; thenStore != null &amp;&amp; elseStore != null
- * </pre>
+ * <pre>{@code
+ * store == null &hArr; thenStore != null &amp;&amp; elseStore != null
+ * }</pre>
*/
protected final /*@Nullable*/ S thenStore;
/**
- * The 'else' result store (or {@code null} if none is present). The
- * following invariant is maintained:
+ * The 'else' result store (or {@code null} if none is present). The following invariant is
+ * maintained:
*
- * <pre>
- * store == null &lt;==&gt; thenStore != null &amp;&amp; elseStore != null
- * </pre>
+ * <pre>{@code
+ * store == null &hArr; thenStore != null &amp;&amp; elseStore != null
+ * }</pre>
*/
protected final /*@Nullable*/ S elseStore;
- /**
- * The corresponding analysis class to get intermediate flow results.
- */
+ /** The corresponding analysis class to get intermediate flow results. */
protected final Analysis<A, S, ?> analysis;
/**
- * Create a {@link TransferInput}, given a {@link TransferResult} and a
- * node-value mapping.
- *
- * <p>
+ * Create a {@link TransferInput}, given a {@link TransferResult} and a node-value mapping.
*
- * <em>Aliasing</em>: The stores returned by any methods of {@code to} will
- * be stored internally and are not allowed to be used elsewhere. Full
- * control of them is transfered to this object.
+ * <p><em>Aliasing</em>: The stores returned by any methods of {@code to} will be stored
+ * internally and are not allowed to be used elsewhere. Full control of them is transfered to
+ * this object.
*
- * <p>
- *
- * The node-value mapping {@code nodeValues} is provided by the analysis and
- * is only read from within this {@link TransferInput}.
+ * <p>The node-value mapping {@code nodeValues} is provided by the analysis and is only read
+ * from within this {@link TransferInput}.
*/
- public TransferInput(Node n, Analysis<A, S, ?> analysis,
- TransferResult<A, S> to) {
+ public TransferInput(Node n, Analysis<A, S, ?> analysis, TransferResult<A, S> to) {
node = n;
this.analysis = analysis;
if (to.containsTwoStores()) {
@@ -96,16 +82,11 @@ public class TransferInput<A extends AbstractValue<A>, S extends Store<S>> {
/**
* Create a {@link TransferInput}, given a store and a node-value mapping.
*
- * <p>
- *
- * <em>Aliasing</em>: The store {@code s} will be stored internally and is
- * not allowed to be used elsewhere. Full control over {@code s} is
- * transfered to this object.
+ * <p><em>Aliasing</em>: The store {@code s} will be stored internally and is not allowed to be
+ * used elsewhere. Full control over {@code s} is transfered to this object.
*
- * <p>
- *
- * The node-value mapping {@code nodeValues} is provided by the analysis and
- * is only read from within this {@link TransferInput}.
+ * <p>The node-value mapping {@code nodeValues} is provided by the analysis and is only read
+ * from within this {@link TransferInput}.
*/
public TransferInput(Node n, Analysis<A, S, ?> analysis, S s) {
node = n;
@@ -115,14 +96,10 @@ public class TransferInput<A extends AbstractValue<A>, S extends Store<S>> {
}
/**
- * Create a {@link TransferInput}, given two stores and a node-value
- * mapping.
- *
- * <p>
+ * Create a {@link TransferInput}, given two stores and a node-value mapping.
*
- * <em>Aliasing</em>: The two stores {@code s1} and {@code s2} will be
- * stored internally and are not allowed to be used elsewhere. Full control
- * of them is transfered to this object.
+ * <p><em>Aliasing</em>: The two stores {@code s1} and {@code s2} will be stored internally and
+ * are not allowed to be used elsewhere. Full control of them is transfered to this object.
*/
public TransferInput(Node n, Analysis<A, S, ?> analysis, S s1, S s2) {
node = n;
@@ -132,9 +109,7 @@ public class TransferInput<A extends AbstractValue<A>, S extends Store<S>> {
store = null;
}
- /**
- * Copy constructor.
- */
+ /** Copy constructor. */
protected TransferInput(TransferInput<A, S> from) {
this.node = from.node;
this.analysis = from.analysis;
@@ -148,27 +123,24 @@ public class TransferInput<A extends AbstractValue<A>, S extends Store<S>> {
}
}
- /**
- * @return The {@link Node} for this {@link TransferInput}.
- */
+ /** @return the {@link Node} for this {@link TransferInput}. */
public Node getNode() {
return node;
}
/**
- * @return The abstract value of {@link Node} {@code n}, which is required
- * to be a 'sub-node' (that is, a direct or indirect child) of the
- * node this transfer input is associated with. Furthermore,
- * {@code n} cannot be a l-value node. Returns {@code null} if no
- * value if available.
+ * @return the abstract value of {@link Node} {@code n}, which is required to be a 'sub-node'
+ * (that is, a direct or indirect child) of the node this transfer input is associated with.
+ * Furthermore, {@code n} cannot be a l-value node. Returns {@code null} if no value if
+ * available.
*/
public /*@Nullable*/ A getValueOfSubNode(Node n) {
return analysis.getValue(n);
}
/**
- * @return The regular result store produced if no exception is thrown by
- * the {@link Node} corresponding to this transfer function result.
+ * @return the regular result store produced if no exception is thrown by the {@link Node}
+ * corresponding to this transfer function result
*/
public S getRegularStore() {
if (store == null) {
@@ -179,8 +151,8 @@ public class TransferInput<A extends AbstractValue<A>, S extends Store<S>> {
}
/**
- * @return The result store produced if the {@link Node} this result belongs
- * to evaluates to {@code true}.
+ * @return the result store produced if the {@link Node} this result belongs to evaluates to
+ * {@code true}.
*/
public S getThenStore() {
if (store == null) {
@@ -190,8 +162,8 @@ public class TransferInput<A extends AbstractValue<A>, S extends Store<S>> {
}
/**
- * @return The result store produced if the {@link Node} this result belongs
- * to evaluates to {@code false}.
+ * @return the result store produced if the {@link Node} this result belongs to evaluates to
+ * {@code false}.
*/
public S getElseStore() {
if (store == null) {
@@ -203,21 +175,19 @@ public class TransferInput<A extends AbstractValue<A>, S extends Store<S>> {
}
/**
- * @return {@code true} if and only if this transfer input contains two
- * stores that are potentially not equal. Note that the result
- * {@code true} does not imply that {@code getRegularStore} cannot
- * be called (or vice versa for {@code false}). Rather, it indicates
- * that {@code getThenStore} or {@code getElseStore} can be used to
- * give more precise results. Otherwise, if the result is
- * {@code false}, then all three methods {@code getRegularStore},
- * {@code getThenStore}, and {@code getElseStore} return equivalent
- * stores.
+ * @return {@code true} if and only if this transfer input contains two stores that are
+ * potentially not equal. Note that the result {@code true} does not imply that {@code
+ * getRegularStore} cannot be called (or vice versa for {@code false}). Rather, it indicates
+ * that {@code getThenStore} or {@code getElseStore} can be used to give more precise
+ * results. Otherwise, if the result is {@code false}, then all three methods {@code
+ * getRegularStore}, {@code getThenStore}, and {@code getElseStore} return equivalent
+ * stores.
*/
public boolean containsTwoStores() {
return (thenStore != null && elseStore != null);
}
- /** @return An exact copy of this store. */
+ /** @return an exact copy of this store. */
public TransferInput<A, S> copy() {
return new TransferInput<>(this);
}
@@ -225,25 +195,22 @@ public class TransferInput<A extends AbstractValue<A>, S extends Store<S>> {
/**
* Compute the least upper bound of two stores.
*
- * <p>
- *
- * <em>Important</em>: This method must fulfill the same contract as
- * {@code leastUpperBound} of {@link Store}.
+ * <p><em>Important</em>: This method must fulfill the same contract as {@code leastUpperBound}
+ * of {@link Store}.
*/
public TransferInput<A, S> leastUpperBound(TransferInput<A, S> other) {
if (store == null) {
S newThenStore = thenStore.leastUpperBound(other.getThenStore());
S newElseStore = elseStore.leastUpperBound(other.getElseStore());
- return new TransferInput<>(node, analysis, newThenStore,
- newElseStore);
+ return new TransferInput<>(node, analysis, newThenStore, newElseStore);
} else {
if (other.store == null) {
// make sure we do not lose precision and keep two stores if at
// least one of the two TransferInput's has two stores.
return other.leastUpperBound(this);
}
- return new TransferInput<>(node, analysis,
- store.leastUpperBound(other.getRegularStore()));
+ return new TransferInput<>(
+ node, analysis, store.leastUpperBound(other.getRegularStore()));
}
}
@@ -254,8 +221,8 @@ public class TransferInput<A extends AbstractValue<A>, S extends Store<S>> {
TransferInput<A, S> other = (TransferInput<A, S>) o;
if (containsTwoStores()) {
if (other.containsTwoStores()) {
- return getThenStore().equals(other.getThenStore()) &&
- getElseStore().equals(other.getElseStore());
+ return getThenStore().equals(other.getThenStore())
+ && getElseStore().equals(other.getElseStore());
}
} else {
if (!other.containsTwoStores()) {
@@ -268,7 +235,8 @@ public class TransferInput<A extends AbstractValue<A>, S extends Store<S>> {
@Override
public int hashCode() {
- return HashCodeUtils.hash(this.analysis, this.node, this.store, this.thenStore, this.elseStore);
+ return HashCodeUtils.hash(
+ this.analysis, this.node, this.store, this.thenStore, this.elseStore);
}
@Override
@@ -279,23 +247,4 @@ public class TransferInput<A extends AbstractValue<A>, S extends Store<S>> {
return "[" + store + "]";
}
}
-
- public boolean hasDOToutput() {
- return true;
- }
-
- public String toDOToutput() {
- if (store == null) {
- if (thenStore.hasDOToutput()) {
- return "[then=" + thenStore.toDOToutput() + ", else=" + elseStore.toDOToutput() + "]";
- }
- return "[then=" + thenStore + ", else=" + elseStore + "]";
- } else {
- if (store.hasDOToutput()) {
- return "[" + store.toDOToutput() + "]";
- }
- return "[" + store + "]";
- }
- }
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferResult.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferResult.java
index d083372917..7c178a13fc 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferResult.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/analysis/TransferResult.java
@@ -5,38 +5,32 @@ import org.checkerframework.checker.nullness.qual.Nullable;
*/
import java.util.Map;
-
import javax.lang.model.type.TypeMirror;
/**
- * {@code TransferResult} is used as the result type of the individual transfer
- * functions of a {@link TransferFunction}. It always belongs to the result of
- * the individual transfer function for a particular {@link org.checkerframework.dataflow.cfg.node.Node}, even though
- * that {@code org.checkerframework.dataflow.cfg.node.Node} is not explicitly store in {@code TransferResult}.
- *
- * <p>
+ * {@code TransferResult} is used as the result type of the individual transfer functions of a
+ * {@link TransferFunction}. It always belongs to the result of the individual transfer function for
+ * a particular {@link org.checkerframework.dataflow.cfg.node.Node}, even though that {@code
+ * org.checkerframework.dataflow.cfg.node.Node} is not explicitly store in {@code TransferResult}.
*
- * A {@code TransferResult} contains one or two stores (for 'then' and 'else'),
- * and zero or more stores with a cause ({@link TypeMirror}).
+ * <p>A {@code TransferResult} contains one or two stores (for 'then' and 'else'), and zero or more
+ * stores with a cause ({@link TypeMirror}).
*
* @author Stefan Heule
- *
- * @param <S>
- * The {@link Store} used to keep track of intermediate results.
+ * @param <S> the {@link Store} used to keep track of intermediate results
*/
-abstract public class TransferResult<A extends AbstractValue<A>, S extends Store<S>> {
+public abstract class TransferResult<A extends AbstractValue<A>, S extends Store<S>> {
/**
- * The stores in case the basic block throws an exception (or {@code null}
- * if the corresponding {@link org.checkerframework.dataflow.cfg.node.Node} does not throw any exceptions). Does
- * not necessarily contain a store for every exception, in which case the
- * in-store will be used.
+ * The stores in case the basic block throws an exception (or {@code null} if the corresponding
+ * {@link org.checkerframework.dataflow.cfg.node.Node} does not throw any exceptions). Does not
+ * necessarily contain a store for every exception, in which case the in-store will be used.
*/
protected /*@Nullable*/ Map<TypeMirror, S> exceptionalStores;
/**
- * The abstract value of the {@link org.checkerframework.dataflow.cfg.node.Node} associated with this
- * {@link TransferResult}, or {@code null} if no value has been produced.
+ * The abstract value of the {@link org.checkerframework.dataflow.cfg.node.Node} associated with
+ * this {@link TransferResult}, or {@code null} if no value has been produced.
*/
protected /*@Nullable*/ A resultValue;
@@ -44,9 +38,7 @@ abstract public class TransferResult<A extends AbstractValue<A>, S extends Store
this.resultValue = resultValue;
}
- /**
- * @return The abstract value produced by the transfer function.
- */
+ /** @return the abstract value produced by the transfer function */
public A getResultValue() {
return resultValue;
}
@@ -56,30 +48,29 @@ abstract public class TransferResult<A extends AbstractValue<A>, S extends Store
}
/**
- * @return The regular result store produced if no exception is thrown by
- * the {@link org.checkerframework.dataflow.cfg.node.Node} corresponding to this transfer function result.
+ * @return the regular result store produced if no exception is thrown by the {@link
+ * org.checkerframework.dataflow.cfg.node.Node} corresponding to this transfer function
+ * result.
*/
- abstract public S getRegularStore();
+ public abstract S getRegularStore();
/**
- * @return The result store produced if the {@link org.checkerframework.dataflow.cfg.node.Node} this result belongs
- * to evaluates to {@code true}.
+ * @return the result store produced if the {@link org.checkerframework.dataflow.cfg.node.Node}
+ * this result belongs to evaluates to {@code true}.
*/
- abstract public S getThenStore();
+ public abstract S getThenStore();
/**
- * @return The result store produced if the {@link org.checkerframework.dataflow.cfg.node.Node} this result belongs
- * to evaluates to {@code false}.
+ * @return the result store produced if the {@link org.checkerframework.dataflow.cfg.node.Node}
+ * this result belongs to evaluates to {@code false}.
*/
- abstract public S getElseStore();
+ public abstract S getElseStore();
/**
- * @return The store that flows along the outgoing exceptional edge labeled
- * with {@code exception} (or {@code null} if no special handling is
- * required for exceptional edges).
+ * @return the store that flows along the outgoing exceptional edge labeled with {@code
+ * exception} (or {@code null} if no special handling is required for exceptional edges).
*/
- public /*@Nullable*/ S getExceptionalStore(
- TypeMirror exception) {
+ public /*@Nullable*/ S getExceptionalStore(TypeMirror exception) {
if (exceptionalStores == null) {
return null;
}
@@ -87,8 +78,7 @@ abstract public class TransferResult<A extends AbstractValue<A>, S extends Store
}
/**
- * @return Returns a Map of {@link TypeMirror} to {@link Store}.
- *
+ * @return a Map of {@link TypeMirror} to {@link Store}
* @see TransferResult#getExceptionalStore(TypeMirror)
*/
public Map<TypeMirror, S> getExceptionalStores() {
@@ -96,21 +86,19 @@ abstract public class TransferResult<A extends AbstractValue<A>, S extends Store
}
/**
- * @return {@code true} if and only if this transfer result contains two
- * stores that are potentially not equal. Note that the result
- * {@code true} does not imply that {@code getRegularStore} cannot
- * be called (or vice versa for {@code false}). Rather, it indicates
- * that {@code getThenStore} or {@code getElseStore} can be used to
- * give more precise results. Otherwise, if the result is
- * {@code false}, then all three methods {@code getRegularStore},
- * {@code getThenStore}, and {@code getElseStore} return equivalent
- * stores.
+ * @return {@code true} if and only if this transfer result contains two stores that are
+ * potentially not equal. Note that the result {@code true} does not imply that {@code
+ * getRegularStore} cannot be called (or vice versa for {@code false}). Rather, it indicates
+ * that {@code getThenStore} or {@code getElseStore} can be used to give more precise
+ * results. Otherwise, if the result is {@code false}, then all three methods {@code
+ * getRegularStore}, {@code getThenStore}, and {@code getElseStore} return equivalent
+ * stores.
*/
- abstract public boolean containsTwoStores();
+ public abstract boolean containsTwoStores();
/**
- * @return {@code true} if and only if the transfer function returning this
- * transfer result changed the regularStore, elseStore, or thenStore.
+ * @return {@code true} if and only if the transfer function returning this transfer result
+ * changed the regularStore, elseStore, or thenStore.
*/
- abstract public boolean storeChanged();
+ public abstract boolean storeChanged();
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGBuilder.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGBuilder.java
index 7b6804a080..55daff24ff 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGBuilder.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGBuilder.java
@@ -4,10 +4,95 @@ package org.checkerframework.dataflow.cfg;
import org.checkerframework.checker.nullness.qual.Nullable;
*/
+import com.sun.source.tree.AnnotatedTypeTree;
+import com.sun.source.tree.AnnotationTree;
+import com.sun.source.tree.ArrayAccessTree;
+import com.sun.source.tree.ArrayTypeTree;
+import com.sun.source.tree.AssertTree;
+import com.sun.source.tree.AssignmentTree;
+import com.sun.source.tree.BinaryTree;
+import com.sun.source.tree.BlockTree;
+import com.sun.source.tree.BreakTree;
+import com.sun.source.tree.CaseTree;
+import com.sun.source.tree.CatchTree;
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.CompoundAssignmentTree;
+import com.sun.source.tree.ConditionalExpressionTree;
+import com.sun.source.tree.ContinueTree;
+import com.sun.source.tree.DoWhileLoopTree;
+import com.sun.source.tree.EmptyStatementTree;
+import com.sun.source.tree.EnhancedForLoopTree;
+import com.sun.source.tree.ErroneousTree;
+import com.sun.source.tree.ExpressionStatementTree;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.ForLoopTree;
+import com.sun.source.tree.IdentifierTree;
+import com.sun.source.tree.IfTree;
+import com.sun.source.tree.ImportTree;
+import com.sun.source.tree.InstanceOfTree;
+import com.sun.source.tree.LabeledStatementTree;
+import com.sun.source.tree.LambdaExpressionTree;
+import com.sun.source.tree.LiteralTree;
+import com.sun.source.tree.MemberReferenceTree;
+import com.sun.source.tree.MemberSelectTree;
+import com.sun.source.tree.MethodInvocationTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.ModifiersTree;
+import com.sun.source.tree.NewArrayTree;
+import com.sun.source.tree.NewClassTree;
+import com.sun.source.tree.ParameterizedTypeTree;
+import com.sun.source.tree.ParenthesizedTree;
+import com.sun.source.tree.PrimitiveTypeTree;
+import com.sun.source.tree.ReturnTree;
+import com.sun.source.tree.StatementTree;
+import com.sun.source.tree.SwitchTree;
+import com.sun.source.tree.SynchronizedTree;
+import com.sun.source.tree.ThrowTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.Tree.Kind;
+import com.sun.source.tree.TryTree;
+import com.sun.source.tree.TypeCastTree;
+import com.sun.source.tree.TypeParameterTree;
+import com.sun.source.tree.UnaryTree;
+import com.sun.source.tree.UnionTypeTree;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.tree.WhileLoopTree;
+import com.sun.source.tree.WildcardTree;
+import com.sun.source.util.TreePath;
+import com.sun.source.util.TreePathScanner;
+import com.sun.source.util.Trees;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.util.Context;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.ReferenceType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.UnionType;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
import org.checkerframework.dataflow.analysis.Store;
import org.checkerframework.dataflow.cfg.CFGBuilder.ExtendedNode.ExtendedNodeType;
import org.checkerframework.dataflow.cfg.UnderlyingAST.CFGMethod;
@@ -91,7 +176,6 @@ import org.checkerframework.dataflow.cfg.node.VariableDeclarationNode;
import org.checkerframework.dataflow.cfg.node.WideningConversionNode;
import org.checkerframework.dataflow.qual.TerminatesExecution;
import org.checkerframework.dataflow.util.MostlySingleton;
-
import org.checkerframework.javacutil.AnnotationProvider;
import org.checkerframework.javacutil.BasicAnnotationProvider;
import org.checkerframework.javacutil.ElementUtils;
@@ -101,122 +185,29 @@ import org.checkerframework.javacutil.TreeUtils;
import org.checkerframework.javacutil.TypesUtils;
import org.checkerframework.javacutil.trees.TreeBuilder;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Name;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.PrimitiveType;
-import javax.lang.model.type.ReferenceType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.TypeVariable;
-import javax.lang.model.type.UnionType;
-import javax.lang.model.util.Elements;
-import javax.lang.model.util.Types;
-
-import com.sun.source.tree.AnnotatedTypeTree;
-import com.sun.source.tree.AnnotationTree;
-import com.sun.source.tree.ArrayAccessTree;
-import com.sun.source.tree.ArrayTypeTree;
-import com.sun.source.tree.AssertTree;
-import com.sun.source.tree.AssignmentTree;
-import com.sun.source.tree.BinaryTree;
-import com.sun.source.tree.BlockTree;
-import com.sun.source.tree.BreakTree;
-import com.sun.source.tree.CaseTree;
-import com.sun.source.tree.CatchTree;
-import com.sun.source.tree.ClassTree;
-import com.sun.source.tree.CompilationUnitTree;
-import com.sun.source.tree.CompoundAssignmentTree;
-import com.sun.source.tree.ConditionalExpressionTree;
-import com.sun.source.tree.ContinueTree;
-import com.sun.source.tree.DoWhileLoopTree;
-import com.sun.source.tree.EmptyStatementTree;
-import com.sun.source.tree.EnhancedForLoopTree;
-import com.sun.source.tree.ErroneousTree;
-import com.sun.source.tree.ExpressionStatementTree;
-import com.sun.source.tree.ExpressionTree;
-import com.sun.source.tree.ForLoopTree;
-import com.sun.source.tree.IdentifierTree;
-import com.sun.source.tree.IfTree;
-import com.sun.source.tree.ImportTree;
-import com.sun.source.tree.InstanceOfTree;
-import com.sun.source.tree.LabeledStatementTree;
-import com.sun.source.tree.LambdaExpressionTree;
-import com.sun.source.tree.LiteralTree;
-import com.sun.source.tree.MemberReferenceTree;
-import com.sun.source.tree.MemberSelectTree;
-import com.sun.source.tree.MethodInvocationTree;
-import com.sun.source.tree.MethodTree;
-import com.sun.source.tree.ModifiersTree;
-import com.sun.source.tree.NewArrayTree;
-import com.sun.source.tree.NewClassTree;
-import com.sun.source.tree.ParameterizedTypeTree;
-import com.sun.source.tree.ParenthesizedTree;
-import com.sun.source.tree.PrimitiveTypeTree;
-import com.sun.source.tree.ReturnTree;
-import com.sun.source.tree.StatementTree;
-import com.sun.source.tree.SwitchTree;
-import com.sun.source.tree.SynchronizedTree;
-import com.sun.source.tree.ThrowTree;
-import com.sun.source.tree.Tree;
-import com.sun.source.tree.Tree.Kind;
-import com.sun.source.tree.TryTree;
-import com.sun.source.tree.TypeCastTree;
-import com.sun.source.tree.TypeParameterTree;
-import com.sun.source.tree.UnaryTree;
-import com.sun.source.tree.UnionTypeTree;
-import com.sun.source.tree.VariableTree;
-import com.sun.source.tree.WhileLoopTree;
-import com.sun.source.tree.WildcardTree;
-import com.sun.source.util.TreePath;
-import com.sun.source.util.TreePathScanner;
-import com.sun.source.util.Trees;
-
/**
- * Builds the control flow graph of some Java code (either a method, or an
- * arbitrary statement).
+ * Builds the control flow graph of some Java code (either a method, or an arbitrary statement).
*
- * <p>
+ * <p>The translation of the AST to the CFG is split into three phases:
*
- * The translation of the AST to the CFG is split into three phases:
* <ol>
- * <li><em>Phase one.</em> In the first phase, the AST is translated into a
- * sequence of {@link org.checkerframework.dataflow.cfg.CFGBuilder.ExtendedNode}s. An extended node can either be a
- * {@link Node}, or one of several meta elements such as a conditional or
- * unconditional jump or a node with additional information about exceptions.
- * Some of the extended nodes contain labels (e.g., for the jump target), and
- * phase one additionally creates a mapping from labels to extended nodes.
- * Finally, the list of leaders is computed: A leader is an extended node which
- * will give rise to a basic block in phase two.</li>
- * <li><em>Phase two.</em> In this phase, the sequence of extended nodes is
- * translated to a graph of control flow blocks that contain nodes. The meta
- * elements from phase one are translated into the correct edges.</li>
- * <li><em>Phase three.</em> The control flow graph generated in phase two can
- * contain degenerate basic blocks such as empty regular basic blocks or
- * conditional basic blocks that have the same block as both 'then' and 'else'
- * successor. This phase removes these cases while preserving the control flow
- * structure.</li>
+ * <li><em>Phase one.</em> In the first phase, the AST is translated into a sequence of {@link
+ * org.checkerframework.dataflow.cfg.CFGBuilder.ExtendedNode}s. An extended node can either be
+ * a {@link Node}, or one of several meta elements such as a conditional or unconditional jump
+ * or a node with additional information about exceptions. Some of the extended nodes contain
+ * labels (e.g., for the jump target), and phase one additionally creates a mapping from
+ * labels to extended nodes. Finally, the list of leaders is computed: A leader is an extended
+ * node which will give rise to a basic block in phase two.
+ * <li><em>Phase two.</em> In this phase, the sequence of extended nodes is translated to a graph
+ * of control flow blocks that contain nodes. The meta elements from phase one are translated
+ * into the correct edges.
+ * <li><em>Phase three.</em> The control flow graph generated in phase two can contain degenerate
+ * basic blocks such as empty regular basic blocks or conditional basic blocks that have the
+ * same block as both 'then' and 'else' successor. This phase removes these cases while
+ * preserving the control flow structure.
* </ol>
*
* @author Stefan Heule
- *
*/
public class CFGBuilder {
@@ -233,116 +224,128 @@ public class CFGBuilder {
}
/**
- * Class declarations that have been encountered when building the
- * control-flow graph for a method.
+ * Class declarations that have been encountered when building the control-flow graph for a
+ * method.
*/
- protected List<ClassTree> declaredClasses;
+ protected final List<ClassTree> declaredClasses = new LinkedList<>();
public List<ClassTree> getDeclaredClasses() {
return declaredClasses;
}
/**
- * Lambdas encountered when building the control-flow graph for
- * a method, variable initializer, or initializer.
+ * Lambdas encountered when building the control-flow graph for a method, variable initializer,
+ * or initializer.
*/
- protected List<LambdaExpressionTree> declaredLambdas;
+ protected final List<LambdaExpressionTree> declaredLambdas = new LinkedList<>();
public List<LambdaExpressionTree> getDeclaredLambdas() {
return declaredLambdas;
}
- /**
- * Build the control flow graph of some code.
- */
+ /** Build the control flow graph of some code. */
public static ControlFlowGraph build(
- CompilationUnitTree root, ProcessingEnvironment env,
- UnderlyingAST underlyingAST, boolean assumeAssertionsEnabled, boolean assumeAssertionsDisabled) {
- return new CFGBuilder(assumeAssertionsEnabled, assumeAssertionsDisabled).run(root, env, underlyingAST);
+ CompilationUnitTree root,
+ ProcessingEnvironment env,
+ UnderlyingAST underlyingAST,
+ boolean assumeAssertionsEnabled,
+ boolean assumeAssertionsDisabled) {
+ return new CFGBuilder(assumeAssertionsEnabled, assumeAssertionsDisabled)
+ .run(root, env, underlyingAST);
}
/**
- * Build the control flow graph of some code (method, initializer block, ...).
- * bodyPath is the TreePath to the body of that code.
+ * Build the control flow graph of some code (method, initializer block, ...). bodyPath is the
+ * TreePath to the body of that code.
*/
public static ControlFlowGraph build(
- TreePath bodyPath, ProcessingEnvironment env,
- UnderlyingAST underlyingAST, boolean assumeAssertionsEnabled, boolean assumeAssertionsDisabled) {
- return new CFGBuilder(assumeAssertionsEnabled, assumeAssertionsDisabled).run(bodyPath, env, underlyingAST);
+ TreePath bodyPath,
+ ProcessingEnvironment env,
+ UnderlyingAST underlyingAST,
+ boolean assumeAssertionsEnabled,
+ boolean assumeAssertionsDisabled) {
+ return new CFGBuilder(assumeAssertionsEnabled, assumeAssertionsDisabled)
+ .run(bodyPath, env, underlyingAST);
}
- /**
- * Build the control flow graph of a method.
- */
+ /** Build the control flow graph of a method. */
public static ControlFlowGraph build(
- CompilationUnitTree root, ProcessingEnvironment env,
- MethodTree tree, ClassTree classTree, boolean assumeAssertionsEnabled, boolean assumeAssertionsDisabled) {
- return new CFGBuilder(assumeAssertionsEnabled, assumeAssertionsDisabled).run(root, env, tree, classTree);
+ CompilationUnitTree root,
+ ProcessingEnvironment env,
+ MethodTree tree,
+ ClassTree classTree,
+ boolean assumeAssertionsEnabled,
+ boolean assumeAssertionsDisabled) {
+ return new CFGBuilder(assumeAssertionsEnabled, assumeAssertionsDisabled)
+ .run(root, env, tree, classTree);
}
- /**
- * Build the control flow graph of some code.
- */
+ /** Build the control flow graph of some code. */
public static ControlFlowGraph build(
- CompilationUnitTree root, ProcessingEnvironment env,
- UnderlyingAST underlyingAST) {
+ CompilationUnitTree root, ProcessingEnvironment env, UnderlyingAST underlyingAST) {
return new CFGBuilder(false, false).run(root, env, underlyingAST);
}
- /**
- * Build the control flow graph of a method.
- */
+ /** Build the control flow graph of a method. */
public static ControlFlowGraph build(
- CompilationUnitTree root, ProcessingEnvironment env,
- MethodTree tree, ClassTree classTree) {
+ CompilationUnitTree root,
+ ProcessingEnvironment env,
+ MethodTree tree,
+ ClassTree classTree) {
return new CFGBuilder(false, false).run(root, env, tree, classTree);
}
- /**
- * Build the control flow graph of some code.
- */
+ /** Build the control flow graph of some code. */
public ControlFlowGraph run(
- CompilationUnitTree root, ProcessingEnvironment env,
- UnderlyingAST underlyingAST) {
- declaredClasses = new LinkedList<>();
- declaredLambdas = new LinkedList<>();
+ CompilationUnitTree root, ProcessingEnvironment env, UnderlyingAST underlyingAST) {
+ declaredClasses.clear();
+ declaredLambdas.clear();
TreeBuilder builder = new TreeBuilder(env);
AnnotationProvider annotationProvider = new BasicAnnotationProvider();
- PhaseOneResult phase1result = new CFGTranslationPhaseOne().process(
- root, env, underlyingAST, exceptionalExitLabel, builder, annotationProvider);
- ControlFlowGraph phase2result = new CFGTranslationPhaseTwo()
- .process(phase1result);
- ControlFlowGraph phase3result = CFGTranslationPhaseThree
- .process(phase2result);
+ PhaseOneResult phase1result =
+ new CFGTranslationPhaseOne()
+ .process(
+ root,
+ env,
+ underlyingAST,
+ exceptionalExitLabel,
+ builder,
+ annotationProvider);
+ ControlFlowGraph phase2result = new CFGTranslationPhaseTwo().process(phase1result);
+ ControlFlowGraph phase3result = CFGTranslationPhaseThree.process(phase2result);
return phase3result;
}
/**
- * Build the control flow graph of some code (method, initializer block, ...).
- * bodyPath is the TreePath to the body of that code.
+ * Build the control flow graph of some code (method, initializer block, ...). bodyPath is the
+ * TreePath to the body of that code.
*/
public ControlFlowGraph run(
- TreePath bodyPath, ProcessingEnvironment env,
- UnderlyingAST underlyingAST) {
- declaredClasses = new LinkedList<>();
+ TreePath bodyPath, ProcessingEnvironment env, UnderlyingAST underlyingAST) {
+ declaredClasses.clear();
TreeBuilder builder = new TreeBuilder(env);
AnnotationProvider annotationProvider = new BasicAnnotationProvider();
- PhaseOneResult phase1result = new CFGTranslationPhaseOne().process(
- bodyPath, env, underlyingAST, exceptionalExitLabel, builder, annotationProvider);
- ControlFlowGraph phase2result = new CFGTranslationPhaseTwo()
- .process(phase1result);
- ControlFlowGraph phase3result = CFGTranslationPhaseThree
- .process(phase2result);
+ PhaseOneResult phase1result =
+ new CFGTranslationPhaseOne()
+ .process(
+ bodyPath,
+ env,
+ underlyingAST,
+ exceptionalExitLabel,
+ builder,
+ annotationProvider);
+ ControlFlowGraph phase2result = new CFGTranslationPhaseTwo().process(phase1result);
+ ControlFlowGraph phase3result = CFGTranslationPhaseThree.process(phase2result);
return phase3result;
}
- /**
- * Build the control flow graph of a method.
- */
+ /** Build the control flow graph of a method. */
public ControlFlowGraph run(
- CompilationUnitTree root, ProcessingEnvironment env,
- MethodTree tree, ClassTree classTree) {
+ CompilationUnitTree root,
+ ProcessingEnvironment env,
+ MethodTree tree,
+ ClassTree classTree) {
UnderlyingAST underlyingAST = new CFGMethod(tree, classTree);
return run(root, env, underlyingAST);
}
@@ -358,25 +361,21 @@ public class CFGBuilder {
protected final Label regularExitLabel = new Label();
/**
- * An extended node can be one of several things (depending on its
- * {@code type}):
+ * An extended node can be one of several things (depending on its {@code type}):
+ *
* <ul>
- * <li><em>NODE</em>. An extended node of this type is just a wrapper for a
- * {@link Node} (that cannot throw exceptions).</li>
- * <li><em>EXCEPTION_NODE</em>. A wrapper for a {@link Node} which can throw
- * exceptions. It contains a label for every possible exception type the
- * node might throw.</li>
- * <li><em>UNCONDITIONAL_JUMP</em>. An unconditional jump to a label.</li>
- * <li><em>TWO_TARGET_CONDITIONAL_JUMP</em>. A conditional jump with two
- * targets for both the 'then' and 'else' branch.</li>
+ * <li><em>NODE</em>. An extended node of this type is just a wrapper for a {@link Node} (that
+ * cannot throw exceptions).
+ * <li><em>EXCEPTION_NODE</em>. A wrapper for a {@link Node} which can throw exceptions. It
+ * contains a label for every possible exception type the node might throw.
+ * <li><em>UNCONDITIONAL_JUMP</em>. An unconditional jump to a label.
+ * <li><em>TWO_TARGET_CONDITIONAL_JUMP</em>. A conditional jump with two targets for both the
+ * 'then' and 'else' branch.
* </ul>
*/
- protected static abstract class ExtendedNode {
+ protected abstract static class ExtendedNode {
- /**
- * The basic block this extended node belongs to (as determined in phase
- * two).
- */
+ /** The basic block this extended node belongs to (as determined in phase two). */
protected BlockImpl block;
/** Type of this node. */
@@ -391,7 +390,10 @@ public class CFGBuilder {
/** Extended node types (description see above). */
public enum ExtendedNodeType {
- NODE, EXCEPTION_NODE, UNCONDITIONAL_JUMP, CONDITIONAL_JUMP
+ NODE,
+ EXCEPTION_NODE,
+ UNCONDITIONAL_JUMP,
+ CONDITIONAL_JUMP
}
public ExtendedNodeType getType() {
@@ -407,8 +409,8 @@ public class CFGBuilder {
}
/**
- * @return The node contained in this extended node (only applicable if
- * the type is {@code NODE} or {@code EXCEPTION_NODE}).
+ * @return the node contained in this extended node (only applicable if the type is {@code
+ * NODE} or {@code EXCEPTION_NODE}).
*/
public Node getNode() {
assert false;
@@ -416,9 +418,8 @@ public class CFGBuilder {
}
/**
- * @return The label associated with this extended node (only applicable
- * if type is {@link ExtendedNodeType#CONDITIONAL_JUMP} or
- * {@link ExtendedNodeType#UNCONDITIONAL_JUMP}).
+ * @return the label associated with this extended node (only applicable if type is {@link
+ * ExtendedNodeType#CONDITIONAL_JUMP} or {@link ExtendedNodeType#UNCONDITIONAL_JUMP}).
*/
public Label getLabel() {
assert false;
@@ -439,9 +440,7 @@ public class CFGBuilder {
}
}
- /**
- * An extended node of type {@code NODE}.
- */
+ /** An extended node of type {@code NODE}. */
protected static class NodeHolder extends ExtendedNode {
protected Node node;
@@ -460,21 +459,19 @@ public class CFGBuilder {
public String toString() {
return "NodeHolder(" + node + ")";
}
-
}
- /**
- * An extended node of type {@code EXCEPTION_NODE}.
- */
+ /** An extended node of type {@code EXCEPTION_NODE}. */
protected static class NodeWithExceptionsHolder extends ExtendedNode {
protected Node node;
- // Map from exception type to labels of successors that may
- // be reached as a result of that exception.
+ /**
+ * Map from exception type to labels of successors that may be reached as a result of that
+ * exception.
+ */
protected Map<TypeMirror, Set<Label>> exceptions;
- public NodeWithExceptionsHolder(Node node,
- Map<TypeMirror, Set<Label>> exceptions) {
+ public NodeWithExceptionsHolder(Node node, Map<TypeMirror, Set<Label>> exceptions) {
super(ExtendedNodeType.EXCEPTION_NODE);
this.node = node;
this.exceptions = exceptions;
@@ -493,19 +490,15 @@ public class CFGBuilder {
public String toString() {
return "NodeWithExceptionsHolder(" + node + ")";
}
-
}
/**
* An extended node of type {@link ExtendedNodeType#CONDITIONAL_JUMP}.
*
- * <p>
- *
- * <em>Important:</em> In the list of extended nodes, there should not be
- * any labels that point to a conditional jump. Furthermore, the node
- * directly ahead of any conditional jump has to be a
- * {@link NodeWithExceptionsHolder} or {@link NodeHolder}, and the node held
- * by that extended node is required to be of boolean type.
+ * <p><em>Important:</em> In the list of extended nodes, there should not be any labels that
+ * point to a conditional jump. Furthermore, the node directly ahead of any conditional jump has
+ * to be a {@link NodeWithExceptionsHolder} or {@link NodeHolder}, and the node held by that
+ * extended node is required to be of boolean type.
*/
protected static class ConditionalJump extends ExtendedNode {
@@ -547,14 +540,11 @@ public class CFGBuilder {
@Override
public String toString() {
- return "TwoTargetConditionalJump(" + getThenLabel() + ","
- + getElseLabel() + ")";
+ return "TwoTargetConditionalJump(" + getThenLabel() + "," + getElseLabel() + ")";
}
}
- /**
- * An extended node of type {@link ExtendedNodeType#UNCONDITIONAL_JUMP}.
- */
+ /** An extended node of type {@link ExtendedNodeType#UNCONDITIONAL_JUMP}. */
protected static class UnconditionalJump extends ExtendedNode {
protected Label jumpTarget;
@@ -576,9 +566,9 @@ public class CFGBuilder {
}
/**
- * A label is used to refer to other extended nodes using a mapping from
- * labels to extended nodes. Labels get their names either from labeled
- * statements in the source code or from internally generated unique names.
+ * A label is used to refer to other extended nodes using a mapping from labels to extended
+ * nodes. Labels get their names either from labeled statements in the source code or from
+ * internally generated unique names.
*/
protected static class Label {
private static int uid = 0;
@@ -599,8 +589,7 @@ public class CFGBuilder {
}
/**
- * Return a new unique label name that cannot be confused with a Java
- * source code label.
+ * Return a new unique label name that cannot be confused with a Java source code label.
*
* @return a new unique label name
*/
@@ -610,27 +599,26 @@ public class CFGBuilder {
}
/**
- * A TryFrame takes a thrown exception type and maps it to a set
- * of possible control-flow successors.
+ * A TryFrame takes a thrown exception type and maps it to a set of possible control-flow
+ * successors.
*/
protected static interface TryFrame {
/**
- * Given a type of thrown exception, add the set of possible control
- * flow successor {@link Label}s to the argument set. Return true
- * if the exception is known to be caught by one of those labels and
- * false if it may propagate still further.
+ * Given a type of thrown exception, add the set of possible control flow successor {@link
+ * Label}s to the argument set. Return true if the exception is known to be caught by one of
+ * those labels and false if it may propagate still further.
*/
public boolean possibleLabels(TypeMirror thrown, Set<Label> labels);
}
/**
- * A TryCatchFrame contains an ordered list of catch labels that apply
- * to exceptions with specific types.
+ * A TryCatchFrame contains an ordered list of catch labels that apply to exceptions with
+ * specific types.
*/
protected static class TryCatchFrame implements TryFrame {
protected Types types;
- // An ordered list of pairs because catch blocks are ordered.
+ /** An ordered list of pairs because catch blocks are ordered. */
protected List<Pair<TypeMirror, Label>> catchLabels;
public TryCatchFrame(Types types, List<Pair<TypeMirror, Label>> catchLabels) {
@@ -639,10 +627,9 @@ public class CFGBuilder {
}
/**
- * Given a type of thrown exception, add the set of possible control
- * flow successor {@link Label}s to the argument set. Return true
- * if the exception is known to be caught by one of those labels and
- * false if it may propagate still further.
+ * Given a type of thrown exception, add the set of possible control flow successor {@link
+ * Label}s to the argument set. Return true if the exception is known to be caught by one of
+ * those labels and false if it may propagate still further.
*/
@Override
public boolean possibleLabels(TypeMirror thrown, Set<Label> labels) {
@@ -666,11 +653,11 @@ public class CFGBuilder {
// declared types, so they do not overlap on any non-null value.
while (!(thrown instanceof DeclaredType)) {
- assert thrown instanceof TypeVariable :
- "thrown type must be a variable or a declared type";
- thrown = ((TypeVariable)thrown).getUpperBound();
+ assert thrown instanceof TypeVariable
+ : "thrown type must be a variable or a declared type";
+ thrown = ((TypeVariable) thrown).getUpperBound();
}
- DeclaredType declaredThrown = (DeclaredType)thrown;
+ DeclaredType declaredThrown = (DeclaredType) thrown;
assert thrown != null : "thrown type must be bounded by a declared type";
for (Pair<TypeMirror, Label> pair : catchLabels) {
@@ -678,7 +665,7 @@ public class CFGBuilder {
boolean canApply = false;
if (caught instanceof DeclaredType) {
- DeclaredType declaredCaught = (DeclaredType)caught;
+ DeclaredType declaredCaught = (DeclaredType) caught;
if (types.isSubtype(declaredThrown, declaredCaught)) {
// No later catch blocks can apply.
labels.add(pair.second);
@@ -687,13 +674,13 @@ public class CFGBuilder {
canApply = true;
}
} else {
- assert caught instanceof UnionType :
- "caught type must be a union or a declared type";
- UnionType caughtUnion = (UnionType)caught;
+ assert caught instanceof UnionType
+ : "caught type must be a union or a declared type";
+ UnionType caughtUnion = (UnionType) caught;
for (TypeMirror alternative : caughtUnion.getAlternatives()) {
- assert alternative instanceof DeclaredType :
- "alternatives of an caught union type must be declared types";
- DeclaredType declaredAlt = (DeclaredType)alternative;
+ assert alternative instanceof DeclaredType
+ : "alternatives of an caught union type must be declared types";
+ DeclaredType declaredAlt = (DeclaredType) alternative;
if (types.isSubtype(declaredThrown, declaredAlt)) {
// No later catch blocks can apply.
labels.add(pair.second);
@@ -713,10 +700,8 @@ public class CFGBuilder {
}
}
- /**
- * A TryFinallyFrame applies to exceptions of any type
- */
- protected class TryFinallyFrame implements TryFrame {
+ /** A TryFinallyFrame applies to exceptions of any type */
+ protected static class TryFinallyFrame implements TryFrame {
protected Label finallyLabel;
public TryFinallyFrame(Label finallyLabel) {
@@ -731,9 +716,8 @@ public class CFGBuilder {
}
/**
- * An exception stack represents the set of all try-catch blocks
- * in effect at a given point in a program. It maps an exception
- * type to a set of Labels and it maps a block exit (via return or
+ * An exception stack represents the set of all try-catch blocks in effect at a given point in a
+ * program. It maps an exception type to a set of Labels and it maps a block exit (via return or
* fall-through) to a single Label.
*/
protected static class TryStack {
@@ -754,8 +738,8 @@ public class CFGBuilder {
}
/**
- * Returns the set of possible {@link Label}s where control may
- * transfer when an exception of the given type is thrown.
+ * Returns the set of possible {@link Label}s where control may transfer when an exception
+ * of the given type is thrown.
*/
public Set<Label> possibleLabels(TypeMirror thrown) {
// Work up from the innermost frame until the exception is known to
@@ -776,31 +760,29 @@ public class CFGBuilder {
/* --------------------------------------------------------- */
/**
- * Class that performs phase three of the translation process. In
- * particular, the following degenerate cases of basic blocks are removed:
+ * Class that performs phase three of the translation process. In particular, the following
+ * degenerate cases of basic blocks are removed:
*
* <ol>
- * <li>Empty regular basic blocks: These blocks will be removed and their
- * predecessors linked directly to the successor.</li>
- * <li>Conditional basic blocks that have the same basic block as the 'then'
- * and 'else' successor: The conditional basic block will be removed in this
- * case.</li>
- * <li>Two consecutive, non-empty, regular basic blocks where the second
- * block has exactly one predecessor (namely the other of the two blocks):
- * In this case, the two blocks are merged.</li>
- * <li>Some basic blocks might not be reachable from the entryBlock. These
- * basic blocks are removed, and the list of predecessors (in the
- * doubly-linked structure of basic blocks) are adapted correctly.</li>
+ * <li>Empty regular basic blocks: These blocks will be removed and their predecessors linked
+ * directly to the successor.
+ * <li>Conditional basic blocks that have the same basic block as the 'then' and 'else'
+ * successor: The conditional basic block will be removed in this case.
+ * <li>Two consecutive, non-empty, regular basic blocks where the second block has exactly one
+ * predecessor (namely the other of the two blocks): In this case, the two blocks are
+ * merged.
+ * <li>Some basic blocks might not be reachable from the entryBlock. These basic blocks are
+ * removed, and the list of predecessors (in the doubly-linked structure of basic blocks)
+ * are adapted correctly.
* </ol>
*
- * Eliminating the second type of degenerate cases might introduce cases of
- * the third problem. These are also removed.
+ * Eliminating the second type of degenerate cases might introduce cases of the third problem.
+ * These are also removed.
*/
public static class CFGTranslationPhaseThree {
/**
- * A simple wrapper object that holds a basic block and allows to set
- * one of its successors.
+ * A simple wrapper object that holds a basic block and allows to set one of its successors.
*/
protected interface PredecessorHolder {
void setSuccessor(BlockImpl b);
@@ -811,11 +793,10 @@ public class CFGBuilder {
/**
* Perform phase three on the control flow graph {@code cfg}.
*
- * @param cfg
- * The control flow graph. Ownership is transfered to this
- * method and the caller is not allowed to read or modify
- * {@code cfg} after the call to {@code process} any more.
- * @return The resulting control flow graph.
+ * @param cfg the control flow graph. Ownership is transfered to this method and the caller
+ * is not allowed to read or modify {@code cfg} after the call to {@code process} any
+ * more.
+ * @return the resulting control flow graph
*/
public static ControlFlowGraph process(ControlFlowGraph cfg) {
Set<Block> worklist = cfg.getAllBlocks();
@@ -845,8 +826,7 @@ public class CFGBuilder {
if (b.isEmpty()) {
Set<RegularBlockImpl> empty = new HashSet<>();
Set<PredecessorHolder> predecessors = new HashSet<>();
- BlockImpl succ = computeNeighborhoodOfEmptyBlock(b,
- empty, predecessors);
+ BlockImpl succ = computeNeighborhoodOfEmptyBlock(b, empty, predecessors);
for (RegularBlockImpl e : empty) {
succ.removePredecessor(e);
dontVisit.add(e);
@@ -871,8 +851,7 @@ public class CFGBuilder {
assert cb.getPredecessors().size() == 1;
if (cb.getThenSuccessor() == cb.getElseSuccessor()) {
BlockImpl pred = cb.getPredecessors().iterator().next();
- PredecessorHolder predecessorHolder = getPredecessorHolder(
- pred, cb);
+ PredecessorHolder predecessorHolder = getPredecessorHolder(pred, cb);
BlockImpl succ = (BlockImpl) cb.getThenSuccessor();
succ.removePredecessor(cb);
predecessorHolder.setSuccessor(succ);
@@ -901,24 +880,19 @@ public class CFGBuilder {
}
/**
- * Compute the set of empty regular basic blocks {@code empty}, starting
- * at {@code start} and going both forward and backwards. Furthermore,
- * compute the predecessors of these empty blocks ({@code predecessors}
- * ), and their single successor (return value).
+ * Compute the set of empty regular basic blocks {@code empty}, starting at {@code start}
+ * and going both forward and backwards. Furthermore, compute the predecessors of these
+ * empty blocks ({@code predecessors} ), and their single successor (return value).
*
- * @param start
- * The starting point of the search (an empty, regular basic
- * block).
- * @param empty
- * An empty set to be filled by this method with all empty
- * basic blocks found (including {@code start}).
- * @param predecessors
- * An empty set to be filled by this method with all
- * predecessors.
- * @return The single successor of the set of the empty basic blocks.
+ * @param start the starting point of the search (an empty, regular basic block)
+ * @param empty an empty set to be filled by this method with all empty basic blocks found
+ * (including {@code start}).
+ * @param predecessors an empty set to be filled by this method with all predecessors
+ * @return the single successor of the set of the empty basic blocks
*/
protected static BlockImpl computeNeighborhoodOfEmptyBlock(
- RegularBlockImpl start, Set<RegularBlockImpl> empty,
+ RegularBlockImpl start,
+ Set<RegularBlockImpl> empty,
Set<PredecessorHolder> predecessors) {
// get empty neighborhood that come before 'start'
@@ -929,8 +903,7 @@ public class CFGBuilder {
while (succ.getType() == BlockType.REGULAR_BLOCK) {
RegularBlockImpl cur = (RegularBlockImpl) succ;
if (cur.isEmpty()) {
- computeNeighborhoodOfEmptyBlockBackwards(cur, empty,
- predecessors);
+ computeNeighborhoodOfEmptyBlockBackwards(cur, empty, predecessors);
assert empty.contains(cur) : "cur ought to be in empty";
succ = (BlockImpl) cur.getSuccessor();
if (succ == cur) {
@@ -945,138 +918,132 @@ public class CFGBuilder {
}
/**
- * Compute the set of empty regular basic blocks {@code empty}, starting
- * at {@code start} and looking only backwards in the control flow
- * graph. Furthermore, compute the predecessors of these empty blocks (
- * {@code predecessors}).
+ * Compute the set of empty regular basic blocks {@code empty}, starting at {@code start}
+ * and looking only backwards in the control flow graph. Furthermore, compute the
+ * predecessors of these empty blocks ( {@code predecessors}).
*
- * @param start
- * The starting point of the search (an empty, regular basic
- * block).
- * @param empty
- * A set to be filled by this method with all empty basic
- * blocks found (including {@code start}).
- * @param predecessors
- * A set to be filled by this method with all predecessors.
+ * @param start the starting point of the search (an empty, regular basic block)
+ * @param empty a set to be filled by this method with all empty basic blocks found
+ * (including {@code start}).
+ * @param predecessors a set to be filled by this method with all predecessors
*/
protected static void computeNeighborhoodOfEmptyBlockBackwards(
- RegularBlockImpl start, Set<RegularBlockImpl> empty,
+ RegularBlockImpl start,
+ Set<RegularBlockImpl> empty,
Set<PredecessorHolder> predecessors) {
RegularBlockImpl cur = start;
empty.add(cur);
for (final BlockImpl pred : cur.getPredecessors()) {
switch (pred.getType()) {
- case SPECIAL_BLOCK:
- // add pred correctly to predecessor list
- predecessors.add(getPredecessorHolder(pred, cur));
- break;
- case CONDITIONAL_BLOCK:
- // add pred correctly to predecessor list
- predecessors.add(getPredecessorHolder(pred, cur));
- break;
- case EXCEPTION_BLOCK:
- // add pred correctly to predecessor list
- predecessors.add(getPredecessorHolder(pred, cur));
- break;
- case REGULAR_BLOCK:
- RegularBlockImpl r = (RegularBlockImpl) pred;
- if (r.isEmpty()) {
- // recursively look backwards
- if (!empty.contains(r)) {
- computeNeighborhoodOfEmptyBlockBackwards(r, empty,
- predecessors);
- }
- } else {
+ case SPECIAL_BLOCK:
// add pred correctly to predecessor list
predecessors.add(getPredecessorHolder(pred, cur));
- }
- break;
+ break;
+ case CONDITIONAL_BLOCK:
+ // add pred correctly to predecessor list
+ predecessors.add(getPredecessorHolder(pred, cur));
+ break;
+ case EXCEPTION_BLOCK:
+ // add pred correctly to predecessor list
+ predecessors.add(getPredecessorHolder(pred, cur));
+ break;
+ case REGULAR_BLOCK:
+ RegularBlockImpl r = (RegularBlockImpl) pred;
+ if (r.isEmpty()) {
+ // recursively look backwards
+ if (!empty.contains(r)) {
+ computeNeighborhoodOfEmptyBlockBackwards(r, empty, predecessors);
+ }
+ } else {
+ // add pred correctly to predecessor list
+ predecessors.add(getPredecessorHolder(pred, cur));
+ }
+ break;
}
}
}
/**
- * Return a predecessor holder that can be used to set the successor of
- * {@code pred} in the place where previously the edge pointed to
- * {@code cur}. Additionally, the predecessor holder also takes care of
- * unlinking (i.e., removing the {@code pred} from {@code cur's}
+ * Return a predecessor holder that can be used to set the successor of {@code pred} in the
+ * place where previously the edge pointed to {@code cur}. Additionally, the predecessor
+ * holder also takes care of unlinking (i.e., removing the {@code pred} from {@code cur's}
* predecessors).
*/
protected static PredecessorHolder getPredecessorHolder(
final BlockImpl pred, final BlockImpl cur) {
switch (pred.getType()) {
- case SPECIAL_BLOCK:
- SingleSuccessorBlockImpl s = (SingleSuccessorBlockImpl) pred;
- return singleSuccessorHolder(s, cur);
- case CONDITIONAL_BLOCK:
- // add pred correctly to predecessor list
- final ConditionalBlockImpl c = (ConditionalBlockImpl) pred;
- if (c.getThenSuccessor() == cur) {
- return new PredecessorHolder() {
- @Override
- public void setSuccessor(BlockImpl b) {
- c.setThenSuccessor(b);
- cur.removePredecessor(pred);
- }
-
- @Override
- public BlockImpl getBlock() {
- return c;
- }
- };
- } else {
- assert c.getElseSuccessor() == cur;
- return new PredecessorHolder() {
- @Override
- public void setSuccessor(BlockImpl b) {
- c.setElseSuccessor(b);
- cur.removePredecessor(pred);
- }
-
- @Override
- public BlockImpl getBlock() {
- return c;
- }
- };
- }
- case EXCEPTION_BLOCK:
- // add pred correctly to predecessor list
- final ExceptionBlockImpl e = (ExceptionBlockImpl) pred;
- if (e.getSuccessor() == cur) {
- return singleSuccessorHolder(e, cur);
- } else {
- Set<Entry<TypeMirror, Set<Block>>> entrySet = e
- .getExceptionalSuccessors().entrySet();
- for (final Entry<TypeMirror, Set<Block>> entry : entrySet) {
- if (entry.getValue().contains(cur)) {
- return new PredecessorHolder() {
- @Override
- public void setSuccessor(BlockImpl b) {
- e.addExceptionalSuccessor(b, entry.getKey());
- cur.removePredecessor(pred);
- }
-
- @Override
- public BlockImpl getBlock() {
- return e;
- }
- };
+ case SPECIAL_BLOCK:
+ SingleSuccessorBlockImpl s = (SingleSuccessorBlockImpl) pred;
+ return singleSuccessorHolder(s, cur);
+ case CONDITIONAL_BLOCK:
+ // add pred correctly to predecessor list
+ final ConditionalBlockImpl c = (ConditionalBlockImpl) pred;
+ if (c.getThenSuccessor() == cur) {
+ return new PredecessorHolder() {
+ @Override
+ public void setSuccessor(BlockImpl b) {
+ c.setThenSuccessor(b);
+ cur.removePredecessor(pred);
+ }
+
+ @Override
+ public BlockImpl getBlock() {
+ return c;
+ }
+ };
+ } else {
+ assert c.getElseSuccessor() == cur;
+ return new PredecessorHolder() {
+ @Override
+ public void setSuccessor(BlockImpl b) {
+ c.setElseSuccessor(b);
+ cur.removePredecessor(pred);
+ }
+
+ @Override
+ public BlockImpl getBlock() {
+ return c;
+ }
+ };
+ }
+ case EXCEPTION_BLOCK:
+ // add pred correctly to predecessor list
+ final ExceptionBlockImpl e = (ExceptionBlockImpl) pred;
+ if (e.getSuccessor() == cur) {
+ return singleSuccessorHolder(e, cur);
+ } else {
+ Set<Entry<TypeMirror, Set<Block>>> entrySet =
+ e.getExceptionalSuccessors().entrySet();
+ for (final Entry<TypeMirror, Set<Block>> entry : entrySet) {
+ if (entry.getValue().contains(cur)) {
+ return new PredecessorHolder() {
+ @Override
+ public void setSuccessor(BlockImpl b) {
+ e.addExceptionalSuccessor(b, entry.getKey());
+ cur.removePredecessor(pred);
+ }
+
+ @Override
+ public BlockImpl getBlock() {
+ return e;
+ }
+ };
+ }
}
}
- }
- assert false;
- break;
- case REGULAR_BLOCK:
- RegularBlockImpl r = (RegularBlockImpl) pred;
- return singleSuccessorHolder(r, cur);
+ assert false;
+ break;
+ case REGULAR_BLOCK:
+ RegularBlockImpl r = (RegularBlockImpl) pred;
+ return singleSuccessorHolder(r, cur);
}
return null;
}
/**
- * @return A {@link PredecessorHolder} that sets the successor of a
- * single successor block {@code s}.
+ * @return a {@link PredecessorHolder} that sets the successor of a single successor block
+ * {@code s}.
*/
protected static PredecessorHolder singleSuccessorHolder(
final SingleSuccessorBlockImpl s, final BlockImpl old) {
@@ -1117,23 +1084,18 @@ public class CFGBuilder {
}
}
- /**
- * Class that performs phase two of the translation process.
- */
+ /** Class that performs phase two of the translation process. */
public class CFGTranslationPhaseTwo {
- public CFGTranslationPhaseTwo() {
- }
+ public CFGTranslationPhaseTwo() {}
/**
* Perform phase two of the translation.
*
- * @param in
- * The result of phase one.
- * @return A control flow graph that might still contain degenerate
- * basic block (such as empty regular basic blocks or
- * conditional blocks with the same block as 'then' and 'else'
- * sucessor).
+ * @param in the result of phase one
+ * @return a control flow graph that might still contain degenerate basic block (such as
+ * empty regular basic blocks or conditional blocks with the same block as 'then' and
+ * 'else' sucessor)
*/
public ControlFlowGraph process(PhaseOneResult in) {
@@ -1144,20 +1106,20 @@ public class CFGBuilder {
assert in.nodeList.size() > 0;
// exit blocks
- SpecialBlockImpl regularExitBlock = new SpecialBlockImpl(
- SpecialBlockType.EXIT);
- SpecialBlockImpl exceptionalExitBlock = new SpecialBlockImpl(
- SpecialBlockType.EXCEPTIONAL_EXIT);
+ SpecialBlockImpl regularExitBlock = new SpecialBlockImpl(SpecialBlockType.EXIT);
+ SpecialBlockImpl exceptionalExitBlock =
+ new SpecialBlockImpl(SpecialBlockType.EXCEPTIONAL_EXIT);
// record missing edges that will be added later
- Set<Tuple<? extends SingleSuccessorBlockImpl, Integer, ?>> missingEdges = new MostlySingleton<>();
+ Set<Tuple<? extends SingleSuccessorBlockImpl, Integer, ?>> missingEdges =
+ new MostlySingleton<>();
// missing exceptional edges
- Set<Tuple<ExceptionBlockImpl, Integer, TypeMirror>> missingExceptionalEdges = new HashSet<>();
+ Set<Tuple<ExceptionBlockImpl, Integer, TypeMirror>> missingExceptionalEdges =
+ new HashSet<>();
// create start block
- SpecialBlockImpl startBlock = new SpecialBlockImpl(
- SpecialBlockType.ENTRY);
+ SpecialBlockImpl startBlock = new SpecialBlockImpl(SpecialBlockType.ENTRY);
missingEdges.add(new Tuple<>(startBlock, 0));
// loop through all 'leaders' (while dynamically detecting the
@@ -1166,104 +1128,108 @@ public class CFGBuilder {
int i = 0;
for (ExtendedNode node : nodeList) {
switch (node.getType()) {
- case NODE:
- if (leaders.contains(i)) {
- RegularBlockImpl b = new RegularBlockImpl();
- block.setSuccessor(b);
- block = b;
- }
- block.addNode(node.getNode());
- node.setBlock(block);
-
- // does this node end the execution (modeled as an edge to
- // the exceptional exit block)
- boolean terminatesExecution = node.getTerminatesExecution();
- if (terminatesExecution) {
- block.setSuccessor(exceptionalExitBlock);
+ case NODE:
+ if (leaders.contains(i)) {
+ RegularBlockImpl b = new RegularBlockImpl();
+ block.setSuccessor(b);
+ block = b;
+ }
+ block.addNode(node.getNode());
+ node.setBlock(block);
+
+ // does this node end the execution (modeled as an edge to
+ // the exceptional exit block)
+ boolean terminatesExecution = node.getTerminatesExecution();
+ if (terminatesExecution) {
+ block.setSuccessor(exceptionalExitBlock);
+ block = new RegularBlockImpl();
+ }
+ break;
+ case CONDITIONAL_JUMP:
+ {
+ ConditionalJump cj = (ConditionalJump) node;
+ // Exception nodes may fall through to conditional jumps,
+ // so we set the block which is required for the insertion
+ // of missing edges.
+ node.setBlock(block);
+ assert block != null;
+ final ConditionalBlockImpl cb = new ConditionalBlockImpl();
+ if (cj.getTrueFlowRule() != null) {
+ cb.setThenFlowRule(cj.getTrueFlowRule());
+ }
+ if (cj.getFalseFlowRule() != null) {
+ cb.setElseFlowRule(cj.getFalseFlowRule());
+ }
+ block.setSuccessor(cb);
+ block = new RegularBlockImpl();
+ // use two anonymous SingleSuccessorBlockImpl that set the
+ // 'then' and 'else' successor of the conditional block
+ final Label thenLabel = cj.getThenLabel();
+ final Label elseLabel = cj.getElseLabel();
+ missingEdges.add(
+ new Tuple<>(
+ new SingleSuccessorBlockImpl() {
+ @Override
+ public void setSuccessor(BlockImpl successor) {
+ cb.setThenSuccessor(successor);
+ }
+ },
+ bindings.get(thenLabel)));
+ missingEdges.add(
+ new Tuple<>(
+ new SingleSuccessorBlockImpl() {
+ @Override
+ public void setSuccessor(BlockImpl successor) {
+ cb.setElseSuccessor(successor);
+ }
+ },
+ bindings.get(elseLabel)));
+ break;
+ }
+ case UNCONDITIONAL_JUMP:
+ if (leaders.contains(i)) {
+ RegularBlockImpl b = new RegularBlockImpl();
+ block.setSuccessor(b);
+ block = b;
+ }
+ node.setBlock(block);
+ if (node.getLabel() == regularExitLabel) {
+ block.setSuccessor(regularExitBlock);
+ } else if (node.getLabel() == exceptionalExitLabel) {
+ block.setSuccessor(exceptionalExitBlock);
+ } else {
+ missingEdges.add(new Tuple<>(block, bindings.get(node.getLabel())));
+ }
block = new RegularBlockImpl();
- }
- break;
- case CONDITIONAL_JUMP: {
- ConditionalJump cj = (ConditionalJump) node;
- // Exception nodes may fall through to conditional jumps,
- // so we set the block which is required for the insertion
- // of missing edges.
- node.setBlock(block);
- assert block != null;
- final ConditionalBlockImpl cb = new ConditionalBlockImpl();
- if (cj.getTrueFlowRule() != null) {
- cb.setThenFlowRule(cj.getTrueFlowRule());
- }
- if (cj.getFalseFlowRule() != null) {
- cb.setElseFlowRule(cj.getFalseFlowRule());
- }
- block.setSuccessor(cb);
- block = new RegularBlockImpl();
- // use two anonymous SingleSuccessorBlockImpl that set the
- // 'then' and 'else' successor of the conditional block
- final Label thenLabel = cj.getThenLabel();
- final Label elseLabel = cj.getElseLabel();
- missingEdges.add(new Tuple<>(
- new SingleSuccessorBlockImpl() {
- @Override
- public void setSuccessor(BlockImpl successor) {
- cb.setThenSuccessor(successor);
- }
- }, bindings.get(thenLabel)));
- missingEdges.add(new Tuple<>(
- new SingleSuccessorBlockImpl() {
- @Override
- public void setSuccessor(BlockImpl successor) {
- cb.setElseSuccessor(successor);
- }
- }, bindings.get(elseLabel)));
- break;
- }
- case UNCONDITIONAL_JUMP:
- if (leaders.contains(i)) {
- RegularBlockImpl b = new RegularBlockImpl();
- block.setSuccessor(b);
- block = b;
- }
- node.setBlock(block);
- if (node.getLabel() == regularExitLabel) {
- block.setSuccessor(regularExitBlock);
- } else if (node.getLabel() == exceptionalExitLabel) {
- block.setSuccessor(exceptionalExitBlock);
- } else {
- missingEdges.add(new Tuple<>(block, bindings.get(node
- .getLabel())));
- }
- block = new RegularBlockImpl();
- break;
- case EXCEPTION_NODE:
- NodeWithExceptionsHolder en = (NodeWithExceptionsHolder) node;
- // create new exception block and link with previous block
- ExceptionBlockImpl e = new ExceptionBlockImpl();
- Node nn = en.getNode();
- e.setNode(nn);
- node.setBlock(e);
- block.setSuccessor(e);
- block = new RegularBlockImpl();
-
- // ensure linking between e and next block (normal edge)
- // Note: do not link to the next block for throw statements
- // (these throw exceptions for sure)
- if (!node.getTerminatesExecution())
- missingEdges.add(new Tuple<>(e, i + 1));
-
- // exceptional edges
- for (Entry<TypeMirror, Set<Label>> entry : en.getExceptions()
- .entrySet()) {
- TypeMirror cause = entry.getKey();
- for (Label label : entry.getValue()) {
- Integer target = bindings.get(label);
- missingExceptionalEdges
- .add(new Tuple<ExceptionBlockImpl, Integer, TypeMirror>(
- e, target, cause));
+ break;
+ case EXCEPTION_NODE:
+ NodeWithExceptionsHolder en = (NodeWithExceptionsHolder) node;
+ // create new exception block and link with previous block
+ ExceptionBlockImpl e = new ExceptionBlockImpl();
+ Node nn = en.getNode();
+ e.setNode(nn);
+ node.setBlock(e);
+ block.setSuccessor(e);
+ block = new RegularBlockImpl();
+
+ // ensure linking between e and next block (normal edge)
+ // Note: do not link to the next block for throw statements
+ // (these throw exceptions for sure)
+ if (!node.getTerminatesExecution()) {
+ missingEdges.add(new Tuple<>(e, i + 1));
}
- }
- break;
+
+ // exceptional edges
+ for (Entry<TypeMirror, Set<Label>> entry : en.getExceptions().entrySet()) {
+ TypeMirror cause = entry.getKey();
+ for (Label label : entry.getValue()) {
+ Integer target = bindings.get(label);
+ missingExceptionalEdges.add(
+ new Tuple<ExceptionBlockImpl, Integer, TypeMirror>(
+ e, target, cause));
+ }
+ }
+ break;
}
i++;
}
@@ -1293,8 +1259,14 @@ public class CFGBuilder {
}
}
- return new ControlFlowGraph(startBlock, regularExitBlock, exceptionalExitBlock, in.underlyingAST,
- in.treeLookupMap, in.convertedTreeLookupMap, in.returnNodes);
+ return new ControlFlowGraph(
+ startBlock,
+ regularExitBlock,
+ exceptionalExitBlock,
+ in.underlyingAST,
+ in.treeLookupMap,
+ in.convertedTreeLookupMap,
+ in.returnNodes);
}
}
@@ -1303,8 +1275,8 @@ public class CFGBuilder {
/* --------------------------------------------------------- */
/**
- * A wrapper object to pass around the result of phase one. For a
- * documentation of the fields see {@link CFGTranslationPhaseOne}.
+ * A wrapper object to pass around the result of phase one. For a documentation of the fields
+ * see {@link CFGTranslationPhaseOne}.
*/
protected static class PhaseOneResult {
@@ -1316,11 +1288,14 @@ public class CFGBuilder {
private final Set<Integer> leaders;
private final List<ReturnNode> returnNodes;
- public PhaseOneResult(UnderlyingAST underlyingAST,
+ public PhaseOneResult(
+ UnderlyingAST underlyingAST,
IdentityHashMap<Tree, Node> treeLookupMap,
IdentityHashMap<Tree, Node> convertedTreeLookupMap,
- ArrayList<ExtendedNode> nodeList, Map<Label, Integer> bindings,
- Set<Integer> leaders, List<ReturnNode> returnNodes) {
+ ArrayList<ExtendedNode> nodeList,
+ Map<Label, Integer> bindings,
+ Set<Integer> leaders,
+ List<ReturnNode> returnNodes) {
this.underlyingAST = underlyingAST;
this.treeLookupMap = treeLookupMap;
this.convertedTreeLookupMap = convertedTreeLookupMap;
@@ -1344,8 +1319,10 @@ public class CFGBuilder {
if (n.getType() == ExtendedNodeType.CONDITIONAL_JUMP) {
ConditionalJump t = (ConditionalJump) n;
return "TwoTargetConditionalJump("
- + resolveLabel(t.getThenLabel()) + ","
- + resolveLabel(t.getElseLabel()) + ")";
+ + resolveLabel(t.getThenLabel())
+ + ","
+ + resolveLabel(t.getElseLabel())
+ + ")";
} else if (n.getType() == ExtendedNodeType.UNCONDITIONAL_JUMP) {
return "UnconditionalJump(" + resolveLabel(n.getLabel()) + ")";
} else {
@@ -1360,45 +1337,35 @@ public class CFGBuilder {
}
return nodeToString(nodeList.get(index));
}
-
}
/**
- * Class that performs phase one of the translation process. It generates
- * the following information:
+ * Class that performs phase one of the translation process. It generates the following
+ * information:
+ *
* <ul>
- * <li>A sequence of extended nodes.</li>
- * <li>A set of bindings from {@link Label}s to positions in the node
- * sequence.</li>
- * <li>A set of leader nodes that give rise to basic blocks in phase two.</li>
- * <li>A lookup map that gives the mapping from AST tree nodes to
- * {@link Node}s.</li>
+ * <li>A sequence of extended nodes.
+ * <li>A set of bindings from {@link Label}s to positions in the node sequence.
+ * <li>A set of leader nodes that give rise to basic blocks in phase two.
+ * <li>A lookup map that gives the mapping from AST tree nodes to {@link Node}s.
* </ul>
*
- * <p>
- *
- * The return type of this scanner is {@link Node}. For expressions, the
- * corresponding node is returned to allow linking between different nodes.
- *
- * However, for statements there is usually no single {@link Node} that is
- * created, and thus no node is returned (rather, null is returned).
- *
- * <p>
+ * <p>The return type of this scanner is {@link Node}. For expressions, the corresponding node
+ * is returned to allow linking between different nodes.
*
- * Every {@code visit*} method is assumed to add at least one extended node
- * to the list of nodes (which might only be a jump).
+ * <p>However, for statements there is usually no single {@link Node} that is created, and thus
+ * no node is returned (rather, null is returned).
*
+ * <p>Every {@code visit*} method is assumed to add at least one extended node to the list of
+ * nodes (which might only be a jump).
*/
public class CFGTranslationPhaseOne extends TreePathScanner<Node, Void> {
- public CFGTranslationPhaseOne() {
- }
+ public CFGTranslationPhaseOne() {}
- /**
- * Annotation processing environment and its associated type and tree
- * utilities.
- */
+ /** Annotation processing environment and its associated type and tree utilities. */
protected ProcessingEnvironment env;
+
protected Elements elements;
protected Types types;
protected Trees trees;
@@ -1406,44 +1373,35 @@ public class CFGBuilder {
protected AnnotationProvider annotationProvider;
/**
- * Current {@link Label} to which a break statement with no label should
- * jump, or null if there is no valid destination.
+ * Current {@link Label} to which a break statement with no label should jump, or null if
+ * there is no valid destination.
*/
protected /*@Nullable*/ Label breakTargetL;
/**
- * Map from AST label Names to CFG {@link Label}s for breaks. Each
- * labeled statement creates two CFG {@link Label}s, one for break and
- * one for continue.
+ * Map from AST label Names to CFG {@link Label}s for breaks. Each labeled statement creates
+ * two CFG {@link Label}s, one for break and one for continue.
*/
protected Map<Name, Label> breakLabels;
/**
- * Current {@link Label} to which a continue statement with no label
- * should jump, or null if there is no valid destination.
+ * Current {@link Label} to which a continue statement with no label should jump, or null if
+ * there is no valid destination.
*/
protected /*@Nullable*/ Label continueTargetL;
/**
- * Map from AST label Names to CFG {@link Label}s for continues. Each
- * labeled statement creates two CFG {@link Label}s, one for break and
- * one for continue.
+ * Map from AST label Names to CFG {@link Label}s for continues. Each labeled statement
+ * creates two CFG {@link Label}s, one for break and one for continue.
*/
protected Map<Name, Label> continueLabels;
/**
- * Node yielding the value for the lexically enclosing synchronized statement,
- * or null if there is no such statement.
- */
- protected Node synchronizedExpr;
-
- /**
- * Maps from AST {@link Tree}s to {@link Node}s. Every Tree that produces
- * a value will have at least one corresponding Node. Trees
- * that undergo conversions, such as boxing or unboxing, can map to two
- * distinct Nodes. The Node for the pre-conversion value is stored
- * in the treeLookupMap, while the Node for the post-conversion value
- * is stored in the convertedTreeLookupMap.
+ * Maps from AST {@link Tree}s to {@link Node}s. Every Tree that produces a value will have
+ * at least one corresponding Node. Trees that undergo conversions, such as boxing or
+ * unboxing, can map to two distinct Nodes. The Node for the pre-conversion value is stored
+ * in the treeLookupMap, while the Node for the post-conversion value is stored in the
+ * convertedTreeLookupMap.
*/
protected IdentityHashMap<Tree, Node> treeLookupMap;
@@ -1453,49 +1411,39 @@ public class CFGBuilder {
/** The list of extended nodes. */
protected ArrayList<ExtendedNode> nodeList;
- /**
- * The bindings of labels to positions (i.e., indices) in the
- * {@code nodeList}.
- */
+ /** The bindings of labels to positions (i.e., indices) in the {@code nodeList}. */
protected Map<Label, Integer> bindings;
/** The set of leaders (represented as indices into {@code nodeList}). */
protected Set<Integer> leaders;
/**
- * All return nodes (if any) encountered. Only includes return
- * statements that actually return something
+ * All return nodes (if any) encountered. Only includes return statements that actually
+ * return something
*/
private List<ReturnNode> returnNodes;
- /**
- * Nested scopes of try-catch blocks in force at the current
- * program point.
- */
+ /** Nested scopes of try-catch blocks in force at the current program point. */
private TryStack tryStack;
/**
* Performs the actual work of phase one.
*
- * @param bodyPath
- * path to the body of the underlying AST's method
- * @param env
- * annotation processing environment containing type
- * utilities
- * @param underlyingAST
- * the AST for which the CFG is to be built
- * @param exceptionalExitLabel
- * the label for exceptional exits from the CFG
- * @param treeBuilder
- * builder for new AST nodes
- * @param annotationProvider
- * extracts annotations from AST nodes
- * @return The result of phase one.
+ * @param bodyPath path to the body of the underlying AST's method
+ * @param env annotation processing environment containing type utilities
+ * @param underlyingAST the AST for which the CFG is to be built
+ * @param exceptionalExitLabel the label for exceptional exits from the CFG
+ * @param treeBuilder builder for new AST nodes
+ * @param annotationProvider extracts annotations from AST nodes
+ * @return the result of phase one
*/
public PhaseOneResult process(
- TreePath bodyPath, ProcessingEnvironment env,
- UnderlyingAST underlyingAST, Label exceptionalExitLabel,
- TreeBuilder treeBuilder, AnnotationProvider annotationProvider) {
+ TreePath bodyPath,
+ ProcessingEnvironment env,
+ UnderlyingAST underlyingAST,
+ Label exceptionalExitLabel,
+ TreeBuilder treeBuilder,
+ AnnotationProvider annotationProvider) {
this.env = env;
this.tryStack = new TryStack(exceptionalExitLabel);
this.treeBuilder = treeBuilder;
@@ -1524,25 +1472,39 @@ public class CFGBuilder {
// removed in a later phase.
nodeList.add(new UnconditionalJump(regularExitLabel));
- return new PhaseOneResult(underlyingAST, treeLookupMap,
- convertedTreeLookupMap, nodeList,
- bindings, leaders, returnNodes);
+ return new PhaseOneResult(
+ underlyingAST,
+ treeLookupMap,
+ convertedTreeLookupMap,
+ nodeList,
+ bindings,
+ leaders,
+ returnNodes);
}
public PhaseOneResult process(
- CompilationUnitTree root, ProcessingEnvironment env,
- UnderlyingAST underlyingAST, Label exceptionalExitLabel,
- TreeBuilder treeBuilder, AnnotationProvider annotationProvider) {
+ CompilationUnitTree root,
+ ProcessingEnvironment env,
+ UnderlyingAST underlyingAST,
+ Label exceptionalExitLabel,
+ TreeBuilder treeBuilder,
+ AnnotationProvider annotationProvider) {
trees = Trees.instance(env);
TreePath bodyPath = trees.getPath(root, underlyingAST.getCode());
- return process(bodyPath, env, underlyingAST, exceptionalExitLabel, treeBuilder, annotationProvider);
+ return process(
+ bodyPath,
+ env,
+ underlyingAST,
+ exceptionalExitLabel,
+ treeBuilder,
+ annotationProvider);
}
/**
- * Perform any actions required when CFG translation creates a
- * new Tree that is not part of the original AST.
+ * Perform any actions required when CFG translation creates a new Tree that is not part of
+ * the original AST.
*
- * @param tree the newly created Tree
+ * @param tree the newly created Tree
*/
public void handleArtificialTree(Tree tree) {}
@@ -1553,8 +1515,7 @@ public class CFGBuilder {
/**
* Add a node to the lookup map if it not already present.
*
- * @param node
- * The node to add to the lookup map.
+ * @param node the node to add to the lookup map
*/
protected void addToLookupMap(Node node) {
Tree tree = node.getTree();
@@ -1573,13 +1534,11 @@ public class CFGBuilder {
}
/**
- * Add a node in the post-conversion lookup map. The node
- * should refer to a Tree and that Tree should already be in
- * the pre-conversion lookup map. This method is used to
- * update the Tree-Node mapping with conversion nodes.
+ * Add a node in the post-conversion lookup map. The node should refer to a Tree and that
+ * Tree should already be in the pre-conversion lookup map. This method is used to update
+ * the Tree-Node mapping with conversion nodes.
*
- * @param node
- * The node to add to the lookup map.
+ * @param node the node to add to the lookup map
*/
protected void addToConvertedLookupMap(Node node) {
Tree tree = node.getTree();
@@ -1587,15 +1546,12 @@ public class CFGBuilder {
}
/**
- * Add a node in the post-conversion lookup map. The tree
- * argument should already be in the pre-conversion lookup
- * map. This method is used to update the Tree-Node mapping
- * with conversion nodes.
+ * Add a node in the post-conversion lookup map. The tree argument should already be in the
+ * pre-conversion lookup map. This method is used to update the Tree-Node mapping with
+ * conversion nodes.
*
- * @param tree
- * The tree used as a key in the map.
- * @param node
- * The node to add to the lookup map.
+ * @param tree the tree used as a key in the map
+ * @param node the node to add to the lookup map
*/
protected void addToConvertedLookupMap(Tree tree, Node node) {
assert tree != null;
@@ -1606,9 +1562,8 @@ public class CFGBuilder {
/**
* Extend the list of extended nodes with a node.
*
- * @param node
- * The node to add.
- * @return The same node (for convenience).
+ * @param node the node to add
+ * @return the same node (for convenience)
*/
protected <T extends Node> T extendWithNode(T node) {
addToLookupMap(node);
@@ -1617,54 +1572,46 @@ public class CFGBuilder {
}
/**
- * Extend the list of extended nodes with a node, where
- * <code>node</code> might throw the exception <code>cause</code>.
+ * Extend the list of extended nodes with a node, where {@code node} might throw the
+ * exception {@code cause}.
*
- * @param node
- * The node to add.
- * @param cause
- * An exception that the node might throw.
- * @return The node holder.
+ * @param node the node to add
+ * @param cause an exception that the node might throw
+ * @return the node holder
*/
- protected NodeWithExceptionsHolder extendWithNodeWithException(Node node, TypeMirror cause) {
+ protected NodeWithExceptionsHolder extendWithNodeWithException(
+ Node node, TypeMirror cause) {
addToLookupMap(node);
return extendWithNodeWithExceptions(node, Collections.singleton(cause));
}
/**
- * Extend the list of extended nodes with a node, where
- * <code>node</code> might throw any of the exception in
- * <code>causes</code>.
+ * Extend the list of extended nodes with a node, where {@code node} might throw any of the
+ * exception in {@code causes}.
*
- * @param node
- * The node to add.
- * @param causes
- * Set of exceptions that the node might throw.
- * @return The node holder.
+ * @param node the node to add
+ * @param causes set of exceptions that the node might throw
+ * @return the node holder
*/
- protected NodeWithExceptionsHolder extendWithNodeWithExceptions(Node node,
- Set<TypeMirror> causes) {
+ protected NodeWithExceptionsHolder extendWithNodeWithExceptions(
+ Node node, Set<TypeMirror> causes) {
addToLookupMap(node);
Map<TypeMirror, Set<Label>> exceptions = new HashMap<>();
for (TypeMirror cause : causes) {
exceptions.put(cause, tryStack.possibleLabels(cause));
}
- NodeWithExceptionsHolder exNode = new NodeWithExceptionsHolder(
- node, exceptions);
+ NodeWithExceptionsHolder exNode = new NodeWithExceptionsHolder(node, exceptions);
extendWithExtendedNode(exNode);
return exNode;
}
/**
- * Insert <code>node</code> after <code>pred</code> in
- * the list of extended nodes, or append to the list if
- * <code>pred</code> is not present.
+ * Insert {@code node} after {@code pred} in the list of extended nodes, or append to the
+ * list if {@code pred} is not present.
*
- * @param node
- * The node to add.
- * @param pred
- * The desired predecessor of node.
- * @return The node holder.
+ * @param node the node to add
+ * @param pred the desired predecessor of node
+ * @return the node holder
*/
protected <T extends Node> T insertNodeAfter(T node, Node pred) {
addToLookupMap(node);
@@ -1673,28 +1620,22 @@ public class CFGBuilder {
}
/**
- * Insert a <code>node</code> that might throw the exception
- * <code>cause</code> after <code>pred</code> in the list of
- * extended nodes, or append to the list if <code>pred</code>
- * is not present.
+ * Insert a {@code node} that might throw the exception {@code cause} after {@code pred} in
+ * the list of extended nodes, or append to the list if {@code pred} is not present.
*
- * @param node
- * The node to add.
- * @param causes
- * Set of exceptions that the node might throw.
- * @param pred
- * The desired predecessor of node.
- * @return The node holder.
+ * @param node the node to add
+ * @param causes set of exceptions that the node might throw
+ * @param pred the desired predecessor of node
+ * @return the node holder
*/
- protected NodeWithExceptionsHolder insertNodeWithExceptionsAfter(Node node,
- Set<TypeMirror> causes, Node pred) {
+ protected NodeWithExceptionsHolder insertNodeWithExceptionsAfter(
+ Node node, Set<TypeMirror> causes, Node pred) {
addToLookupMap(node);
Map<TypeMirror, Set<Label>> exceptions = new HashMap<>();
for (TypeMirror cause : causes) {
exceptions.put(cause, tryStack.possibleLabels(cause));
}
- NodeWithExceptionsHolder exNode = new NodeWithExceptionsHolder(
- node, exceptions);
+ NodeWithExceptionsHolder exNode = new NodeWithExceptionsHolder(node, exceptions);
insertExtendedNodeAfter(exNode, pred);
return exNode;
}
@@ -1702,29 +1643,24 @@ public class CFGBuilder {
/**
* Extend the list of extended nodes with an extended node.
*
- * @param n
- * The extended node.
+ * @param n the extended node
*/
protected void extendWithExtendedNode(ExtendedNode n) {
nodeList.add(n);
}
/**
- * Insert <code>n</code> after the node <code>pred</code> in the
- * list of extended nodes, or append <code>n</code> if <code>pred</code>
- * is not present.
+ * Insert {@code n} after the node {@code pred} in the list of extended nodes, or append
+ * {@code n} if {@code pred} is not present.
*
- * @param n
- * The extended node.
- * @param pred
- * The desired predecessor.
+ * @param n the extended node
+ * @param pred the desired predecessor
*/
protected void insertExtendedNodeAfter(ExtendedNode n, Node pred) {
int index = -1;
for (int i = 0; i < nodeList.size(); i++) {
ExtendedNode inList = nodeList.get(i);
- if (inList instanceof NodeHolder ||
- inList instanceof NodeWithExceptionsHolder) {
+ if (inList instanceof NodeHolder || inList instanceof NodeWithExceptionsHolder) {
if (inList.getNode() == pred) {
index = i;
break;
@@ -1733,14 +1669,29 @@ public class CFGBuilder {
}
if (index != -1) {
nodeList.add(index + 1, n);
+ // update bindings
+ for (Entry<Label, Integer> e : bindings.entrySet()) {
+ if (e.getValue() >= index + 1) {
+ bindings.put(e.getKey(), e.getValue() + 1);
+ }
+ }
+ // update leaders
+ Set<Integer> newLeaders = new HashSet<>();
+ for (Integer l : leaders) {
+ if (l >= index + 1) {
+ newLeaders.add(l + 1);
+ } else {
+ newLeaders.add(l);
+ }
+ }
+ leaders = newLeaders;
} else {
nodeList.add(n);
}
}
/**
- * Add the label {@code l} to the extended node that will be placed next
- * in the sequence.
+ * Add the label {@code l} to the extended node that will be placed next in the sequence.
*/
protected void addLabelForNextNode(Label l) {
leaders.add(nodeList.size());
@@ -1752,28 +1703,26 @@ public class CFGBuilder {
/* --------------------------------------------------------- */
protected long uid = 0;
+
protected String uniqueName(String prefix) {
return prefix + "#num" + uid++;
}
/**
- * If the input node is an unboxed primitive type, insert a call to the
- * appropriate valueOf method, otherwise leave it alone.
+ * If the input node is an unboxed primitive type, insert a call to the appropriate valueOf
+ * method, otherwise leave it alone.
*
- * @param node
- * in input node
- * @return a Node representing the boxed version of the input, which may
- * simply be the input node
+ * @param node in input node
+ * @return a Node representing the boxed version of the input, which may simply be the input
+ * node
*/
protected Node box(Node node) {
// For boxing conversion, see JLS 5.1.7
if (TypesUtils.isPrimitive(node.getType())) {
- PrimitiveType primitive = types.getPrimitiveType(node.getType()
- .getKind());
- TypeMirror boxedType = types.getDeclaredType(types
- .boxedClass(primitive));
+ PrimitiveType primitive = types.getPrimitiveType(node.getType().getKind());
+ TypeMirror boxedType = types.getDeclaredType(types.boxedClass(primitive));
- TypeElement boxedElement = (TypeElement)((DeclaredType)boxedType).asElement();
+ TypeElement boxedElement = (TypeElement) ((DeclaredType) boxedType).asElement();
IdentifierTree classTree = treeBuilder.buildClassUse(boxedElement);
handleArtificialTree(classTree);
ClassNameNode className = new ClassNameNode(classTree);
@@ -1787,18 +1736,21 @@ public class CFGBuilder {
insertNodeAfter(valueOfAccess, className);
MethodInvocationTree valueOfCall =
- treeBuilder.buildMethodInvocation(valueOfSelect, (ExpressionTree)node.getTree());
+ treeBuilder.buildMethodInvocation(
+ valueOfSelect, (ExpressionTree) node.getTree());
handleArtificialTree(valueOfCall);
- Node boxed = new MethodInvocationNode(valueOfCall, valueOfAccess,
- Collections.singletonList(node),
- getCurrentPath());
+ Node boxed =
+ new MethodInvocationNode(
+ valueOfCall,
+ valueOfAccess,
+ Collections.singletonList(node),
+ getCurrentPath());
boxed.setInSource(false);
// Add Throwable to account for unchecked exceptions
- TypeElement throwableElement = elements
- .getTypeElement("java.lang.Throwable");
+ TypeElement throwableElement = elements.getTypeElement("java.lang.Throwable");
addToConvertedLookupMap(node.getTree(), boxed);
- insertNodeWithExceptionsAfter(boxed,
- Collections.singleton(throwableElement.asType()), valueOfAccess);
+ insertNodeWithExceptionsAfter(
+ boxed, Collections.singleton(throwableElement.asType()), valueOfAccess);
return boxed;
} else {
return node;
@@ -1806,42 +1758,41 @@ public class CFGBuilder {
}
/**
- * If the input node is a boxed type, unbox it, otherwise leave it
- * alone.
+ * If the input node is a boxed type, unbox it, otherwise leave it alone.
*
- * @param node
- * in input node
- * @return a Node representing the unboxed version of the input, which
- * may simply be the input node
+ * @param node in input node
+ * @return a Node representing the unboxed version of the input, which may simply be the
+ * input node
*/
protected Node unbox(Node node) {
if (TypesUtils.isBoxedPrimitive(node.getType())) {
MemberSelectTree primValueSelect =
- treeBuilder.buildPrimValueMethodAccess(node.getTree());
+ treeBuilder.buildPrimValueMethodAccess(node.getTree());
handleArtificialTree(primValueSelect);
MethodAccessNode primValueAccess = new MethodAccessNode(primValueSelect, node);
primValueAccess.setInSource(false);
// Method access may throw NullPointerException
- TypeElement npeElement = elements
- .getTypeElement("java.lang.NullPointerException");
- insertNodeWithExceptionsAfter(primValueAccess,
- Collections.singleton(npeElement.asType()), node);
+ TypeElement npeElement = elements.getTypeElement("java.lang.NullPointerException");
+ insertNodeWithExceptionsAfter(
+ primValueAccess, Collections.singleton(npeElement.asType()), node);
MethodInvocationTree primValueCall =
- treeBuilder.buildMethodInvocation(primValueSelect);
+ treeBuilder.buildMethodInvocation(primValueSelect);
handleArtificialTree(primValueCall);
- Node unboxed = new MethodInvocationNode(primValueCall, primValueAccess,
- Collections.<Node>emptyList(),
- getCurrentPath());
+ Node unboxed =
+ new MethodInvocationNode(
+ primValueCall,
+ primValueAccess,
+ Collections.<Node>emptyList(),
+ getCurrentPath());
unboxed.setInSource(false);
// Add Throwable to account for unchecked exceptions
- TypeElement throwableElement = elements
- .getTypeElement("java.lang.Throwable");
+ TypeElement throwableElement = elements.getTypeElement("java.lang.Throwable");
addToConvertedLookupMap(node.getTree(), unboxed);
- insertNodeWithExceptionsAfter(unboxed,
- Collections.singleton(throwableElement.asType()), primValueAccess);
+ insertNodeWithExceptionsAfter(
+ unboxed, Collections.singleton(throwableElement.asType()), primValueAccess);
return unboxed;
} else {
return node;
@@ -1879,9 +1830,7 @@ public class CFGBuilder {
};
}
- /**
- * @return the unboxed tree if necessary, as described in JLS 5.1.8
- */
+ /** @return the unboxed tree if necessary, as described in JLS 5.1.8 */
private Node unboxAsNeeded(Node node, boolean boxed) {
return boxed ? unbox(node) : node;
}
@@ -1889,18 +1838,15 @@ public class CFGBuilder {
/**
* Convert the input node to String type, if it isn't already.
*
- * @param node
- * an input node
- * @return a Node with the value promoted to String, which may be the
- * input node
+ * @param node an input node
+ * @return a Node with the value promoted to String, which may be the input node
*/
protected Node stringConversion(Node node) {
// For string conversion, see JLS 5.1.11
- TypeElement stringElement =
- elements.getTypeElement("java.lang.String");
+ TypeElement stringElement = elements.getTypeElement("java.lang.String");
if (!TypesUtils.isString(node.getType())) {
- Node converted = new StringConversionNode(node.getTree(), node,
- stringElement.asType());
+ Node converted =
+ new StringConversionNode(node.getTree(), node, stringElement.asType());
addToConvertedLookupMap(converted);
insertNodeAfter(converted, node);
return converted;
@@ -1912,37 +1858,36 @@ public class CFGBuilder {
/**
* Perform unary numeric promotion on the input node.
*
- * @param node
- * a node producing a value of numeric primitive or boxed
- * type
- * @return a Node with the value promoted to the int, long float or
- * double, which may be the input node
+ * @param node a node producing a value of numeric primitive or boxed type
+ * @return a Node with the value promoted to the int, long float or double, which may be the
+ * input node
*/
protected Node unaryNumericPromotion(Node node) {
// For unary numeric promotion, see JLS 5.6.1
node = unbox(node);
switch (node.getType().getKind()) {
- case BYTE:
- case CHAR:
- case SHORT: {
- TypeMirror intType = types.getPrimitiveType(TypeKind.INT);
- Node widened = new WideningConversionNode(node.getTree(), node, intType);
- addToConvertedLookupMap(widened);
- insertNodeAfter(widened, node);
- return widened;
- }
- default:
- // Nothing to do.
- break;
+ case BYTE:
+ case CHAR:
+ case SHORT:
+ {
+ TypeMirror intType = types.getPrimitiveType(TypeKind.INT);
+ Node widened = new WideningConversionNode(node.getTree(), node, intType);
+ addToConvertedLookupMap(widened);
+ insertNodeAfter(widened, node);
+ return widened;
+ }
+ default:
+ // Nothing to do.
+ break;
}
return node;
}
/**
- * Returns true if the argument type is a numeric primitive or
- * a boxed numeric primitive and false otherwise.
+ * Returns true if the argument type is a numeric primitive or a boxed numeric primitive and
+ * false otherwise.
*/
protected boolean isNumericOrBoxed(TypeMirror type) {
if (TypesUtils.isBoxedPrimitive(type)) {
@@ -1952,12 +1897,12 @@ public class CFGBuilder {
}
/**
- * Compute the type to which two numeric types must be promoted
- * before performing a binary numeric operation on them. The
- * input types must both be numeric and the output type is primitive.
+ * Compute the type to which two numeric types must be promoted before performing a binary
+ * numeric operation on them. The input types must both be numeric and the output type is
+ * primitive.
*
- * @param left the type of the left operand
- * @param right the type of the right operand
+ * @param left the type of the left operand
+ * @param right the type of the right operand
* @return a TypeMirror representing the binary numeric promoted type
*/
protected TypeMirror binaryPromotedType(TypeMirror left, TypeMirror right) {
@@ -1972,24 +1917,18 @@ public class CFGBuilder {
}
/**
- * Perform binary numeric promotion on the input node to make it match
- * the expression type.
+ * Perform binary numeric promotion on the input node to make it match the expression type.
*
- * @param node
- * a node producing a value of numeric primitive or boxed
- * type
- * @param exprType
- * the type to promote the value to
- * @return a Node with the value promoted to the exprType, which may be
- * the input node
+ * @param node a node producing a value of numeric primitive or boxed type
+ * @param exprType the type to promote the value to
+ * @return a Node with the value promoted to the exprType, which may be the input node
*/
protected Node binaryNumericPromotion(Node node, TypeMirror exprType) {
// For binary numeric promotion, see JLS 5.6.2
node = unbox(node);
if (!types.isSameType(node.getType(), exprType)) {
- Node widened = new WideningConversionNode(node.getTree(), node,
- exprType);
+ Node widened = new WideningConversionNode(node.getTree(), node, exprType);
addToConvertedLookupMap(widened);
insertNodeAfter(widened, node);
return widened;
@@ -1999,24 +1938,20 @@ public class CFGBuilder {
}
/**
- * Perform widening primitive conversion on the input node to make it
- * match the destination type.
+ * Perform widening primitive conversion on the input node to make it match the destination
+ * type.
*
- * @param node
- * a node producing a value of numeric primitive type
- * @param destType
- * the type to widen the value to
- * @return a Node with the value widened to the exprType, which may be
- * the input node
+ * @param node a node producing a value of numeric primitive type
+ * @param destType the type to widen the value to
+ * @return a Node with the value widened to the exprType, which may be the input node
*/
protected Node widen(Node node, TypeMirror destType) {
// For widening conversion, see JLS 5.1.2
- assert TypesUtils.isPrimitive(node.getType())
- && TypesUtils.isPrimitive(destType) : "widening must be applied to primitive types";
+ assert TypesUtils.isPrimitive(node.getType()) && TypesUtils.isPrimitive(destType)
+ : "widening must be applied to primitive types";
if (types.isSubtype(node.getType(), destType)
&& !types.isSameType(node.getType(), destType)) {
- Node widened = new WideningConversionNode(node.getTree(), node,
- destType);
+ Node widened = new WideningConversionNode(node.getTree(), node, destType);
addToConvertedLookupMap(widened);
insertNodeAfter(widened, node);
return widened;
@@ -2026,24 +1961,19 @@ public class CFGBuilder {
}
/**
- * Perform narrowing conversion on the input node to make it match the
- * destination type.
+ * Perform narrowing conversion on the input node to make it match the destination type.
*
- * @param node
- * a node producing a value of numeric primitive type
- * @param destType
- * the type to narrow the value to
- * @return a Node with the value narrowed to the exprType, which may be
- * the input node
+ * @param node a node producing a value of numeric primitive type
+ * @param destType the type to narrow the value to
+ * @return a Node with the value narrowed to the exprType, which may be the input node
*/
protected Node narrow(Node node, TypeMirror destType) {
// For narrowing conversion, see JLS 5.1.3
- assert TypesUtils.isPrimitive(node.getType())
- && TypesUtils.isPrimitive(destType) : "narrowing must be applied to primitive types";
+ assert TypesUtils.isPrimitive(node.getType()) && TypesUtils.isPrimitive(destType)
+ : "narrowing must be applied to primitive types";
if (types.isSubtype(destType, node.getType())
&& !types.isSameType(destType, node.getType())) {
- Node narrowed = new NarrowingConversionNode(node.getTree(), node,
- destType);
+ Node narrowed = new NarrowingConversionNode(node.getTree(), node, destType);
addToConvertedLookupMap(narrowed);
insertNodeAfter(narrowed, node);
return narrowed;
@@ -2053,15 +1983,13 @@ public class CFGBuilder {
}
/**
- * Perform narrowing conversion and optionally boxing conversion on the
- * input node to make it match the destination type.
+ * Perform narrowing conversion and optionally boxing conversion on the input node to make
+ * it match the destination type.
*
- * @param node
- * a node producing a value of numeric primitive type
- * @param destType
- * the type to narrow the value to (possibly boxed)
- * @return a Node with the value narrowed and boxed to the destType,
- * which may be the input node
+ * @param node a node producing a value of numeric primitive type
+ * @param destType the type to narrow the value to (possibly boxed)
+ * @return a Node with the value narrowed and boxed to the destType, which may be the input
+ * node
*/
protected Node narrowAndBox(Node node, TypeMirror destType) {
if (TypesUtils.isBoxedPrimitive(destType)) {
@@ -2071,47 +1999,41 @@ public class CFGBuilder {
}
}
-
/**
- * Return whether a conversion from the type of the node to varType
- * requires narrowing.
+ * Return whether a conversion from the type of the node to varType requires narrowing.
*
- * @param varType the type of a variable (or general LHS) to be converted to
- * @param node a node whose value is being converted
- * @return whether this conversion requires narrowing to succeed
+ * @param varType the type of a variable (or general LHS) to be converted to
+ * @param node a node whose value is being converted
+ * @return whether this conversion requires narrowing to succeed
*/
protected boolean conversionRequiresNarrowing(TypeMirror varType, Node node) {
// Narrowing is restricted to cases where the left hand side
// is byte, char, short or Byte, Char, Short and the right
// hand side is a constant.
- TypeMirror unboxedVarType = TypesUtils.isBoxedPrimitive(varType) ? types
- .unboxedType(varType) : varType;
+ TypeMirror unboxedVarType =
+ TypesUtils.isBoxedPrimitive(varType) ? types.unboxedType(varType) : varType;
TypeKind unboxedVarKind = unboxedVarType.getKind();
- boolean isLeftNarrowableTo = unboxedVarKind == TypeKind.BYTE
- || unboxedVarKind == TypeKind.SHORT
- || unboxedVarKind == TypeKind.CHAR;
+ boolean isLeftNarrowableTo =
+ unboxedVarKind == TypeKind.BYTE
+ || unboxedVarKind == TypeKind.SHORT
+ || unboxedVarKind == TypeKind.CHAR;
boolean isRightConstant = node instanceof ValueLiteralNode;
return isLeftNarrowableTo && isRightConstant;
}
-
/**
- * Assignment conversion and method invocation conversion are almost
- * identical, except that assignment conversion allows narrowing. We
- * factor out the common logic here.
+ * Assignment conversion and method invocation conversion are almost identical, except that
+ * assignment conversion allows narrowing. We factor out the common logic here.
*
- * @param node
- * a Node producing a value
- * @param varType
- * the type of a variable
- * @param contextAllowsNarrowing
- * whether to allow narrowing (for assignment conversion) or
- * not (for method invocation conversion)
- * @return a Node with the value converted to the type of the variable,
- * which may be the input node itself
+ * @param node a Node producing a value
+ * @param varType the type of a variable
+ * @param contextAllowsNarrowing whether to allow narrowing (for assignment conversion) or
+ * not (for method invocation conversion)
+ * @return a Node with the value converted to the type of the variable, which may be the
+ * input node itself
*/
- protected Node commonConvert(Node node, TypeMirror varType,
- boolean contextAllowsNarrowing) {
+ protected Node commonConvert(
+ Node node, TypeMirror varType, boolean contextAllowsNarrowing) {
// For assignment conversion, see JLS 5.2
// For method invocation conversion, see JLS 5.3
@@ -2150,8 +2072,7 @@ public class CFGBuilder {
node = unbox(node);
nodeType = node.getType();
- if (types.isSubtype(nodeType, varType)
- && !types.isSameType(nodeType, varType)) {
+ if (types.isSubtype(nodeType, varType) && !types.isSameType(nodeType, varType)) {
node = widen(node, varType);
nodeType = node.getType();
}
@@ -2169,50 +2090,42 @@ public class CFGBuilder {
}
/**
- * Perform assignment conversion so that it can be assigned to a
- * variable of the given type.
+ * Perform assignment conversion so that it can be assigned to a variable of the given type.
*
- * @param node
- * a Node producing a value
- * @param varType
- * the type of a variable
- * @return a Node with the value converted to the type of the variable,
- * which may be the input node itself
+ * @param node a Node producing a value
+ * @param varType the type of a variable
+ * @return a Node with the value converted to the type of the variable, which may be the
+ * input node itself
*/
protected Node assignConvert(Node node, TypeMirror varType) {
return commonConvert(node, varType, true);
}
/**
- * Perform method invocation conversion so that the node can be passed
- * as a formal parameter of the given type.
+ * Perform method invocation conversion so that the node can be passed as a formal parameter
+ * of the given type.
*
- * @param node
- * a Node producing a value
- * @param formalType
- * the type of a formal parameter
- * @return a Node with the value converted to the type of the formal,
- * which may be the input node itself
+ * @param node a Node producing a value
+ * @param formalType the type of a formal parameter
+ * @return a Node with the value converted to the type of the formal, which may be the input
+ * node itself
*/
protected Node methodInvocationConvert(Node node, TypeMirror formalType) {
return commonConvert(node, formalType, false);
}
/**
- * Given a method element and as list of argument expressions, return a
- * list of {@link Node}s representing the arguments converted for a call
- * of the method. This method applies to both method invocations and
- * constructor calls.
+ * Given a method element and as list of argument expressions, return a list of {@link
+ * Node}s representing the arguments converted for a call of the method. This method applies
+ * to both method invocations and constructor calls.
*
- * @param method
- * an ExecutableElement representing a method to be called
- * @param actualExprs
- * a List of argument expressions to a call
- * @return a List of {@link Node}s representing arguments after
- * conversions required by a call to this method.
+ * @param method an ExecutableElement representing a method to be called
+ * @param actualExprs a List of argument expressions to a call
+ * @return a List of {@link Node}s representing arguments after conversions required by a
+ * call to this method
*/
- protected List<Node> convertCallArguments(ExecutableElement method,
- List<? extends ExpressionTree> actualExprs) {
+ protected List<Node> convertCallArguments(
+ ExecutableElement method, List<? extends ExpressionTree> actualExprs) {
// NOTE: It is important to convert one method argument before
// generating CFG nodes for the next argument, since label binding
// expects nodes to be generated in execution order. Therefore,
@@ -2238,48 +2151,46 @@ public class CFGBuilder {
// arguments, then create and append an empty array
for (int i = 0; i < numActuals; i++) {
Node actualVal = scan(actualExprs.get(i), null);
- convertedNodes.add(methodInvocationConvert(actualVal,
- formals.get(i).asType()));
+ convertedNodes.add(
+ methodInvocationConvert(actualVal, formals.get(i).asType()));
}
- Node lastArgument = new ArrayCreationNode(null,
- lastParamType, dimensions, initializers);
+ Node lastArgument =
+ new ArrayCreationNode(null, lastParamType, dimensions, initializers);
extendWithNode(lastArgument);
convertedNodes.add(lastArgument);
} else {
- TypeMirror actualType = InternalUtils.typeOf(actualExprs
- .get(lastArgIndex));
- if (numActuals == numFormals
- && types.isAssignable(actualType, lastParamType)) {
+ TypeMirror actualType = InternalUtils.typeOf(actualExprs.get(lastArgIndex));
+ if (numActuals == numFormals && types.isAssignable(actualType, lastParamType)) {
// Normal call with no array creation, apply method
// invocation conversion to all arguments.
for (int i = 0; i < numActuals; i++) {
Node actualVal = scan(actualExprs.get(i), null);
- convertedNodes.add(methodInvocationConvert(actualVal,
- formals.get(i).asType()));
+ convertedNodes.add(
+ methodInvocationConvert(actualVal, formals.get(i).asType()));
}
} else {
- assert lastParamType instanceof ArrayType :
- "variable argument formal must be an array";
+ assert lastParamType instanceof ArrayType
+ : "variable argument formal must be an array";
// Apply method invocation conversion to lastArgIndex
// arguments and use the remaining ones to initialize
// an array.
for (int i = 0; i < lastArgIndex; i++) {
Node actualVal = scan(actualExprs.get(i), null);
- convertedNodes.add(methodInvocationConvert(actualVal,
- formals.get(i).asType()));
+ convertedNodes.add(
+ methodInvocationConvert(actualVal, formals.get(i).asType()));
}
- TypeMirror elemType =
- ((ArrayType)lastParamType).getComponentType();
+ TypeMirror elemType = ((ArrayType) lastParamType).getComponentType();
for (int i = lastArgIndex; i < numActuals; i++) {
Node actualVal = scan(actualExprs.get(i), null);
initializers.add(assignConvert(actualVal, elemType));
}
- Node lastArgument = new ArrayCreationNode(null,
- lastParamType, dimensions, initializers);
+ Node lastArgument =
+ new ArrayCreationNode(
+ null, lastParamType, dimensions, initializers);
extendWithNode(lastArgument);
convertedNodes.add(lastArgument);
}
@@ -2287,8 +2198,7 @@ public class CFGBuilder {
} else {
for (int i = 0; i < numActuals; i++) {
Node actualVal = scan(actualExprs.get(i), null);
- convertedNodes.add(methodInvocationConvert(actualVal,
- formals.get(i).asType()));
+ convertedNodes.add(methodInvocationConvert(actualVal, formals.get(i).asType()));
}
}
@@ -2296,16 +2206,11 @@ public class CFGBuilder {
}
/**
- * Convert an operand of a conditional expression to the type of the
- * whole expression.
+ * Convert an operand of a conditional expression to the type of the whole expression.
*
- * @param node
- * a node occurring as the second or third operand of
- * a conditional expression
- * @param destType
- * the type to promote the value to
- * @return a Node with the value promoted to the destType, which may be
- * the input node
+ * @param node a node occurring as the second or third operand of a conditional expression
+ * @param destType the type to promote the value to
+ * @return a Node with the value promoted to the destType, which may be the input node
*/
protected Node conditionalExprPromotion(Node node, TypeMirror destType) {
// For rules on converting operands of conditional expressions,
@@ -2320,23 +2225,19 @@ public class CFGBuilder {
// If the operand is a primitive and the whole expression is
// boxed, then apply boxing.
- if (TypesUtils.isPrimitive(nodeType) &&
- TypesUtils.isBoxedPrimitive(destType)) {
+ if (TypesUtils.isPrimitive(nodeType) && TypesUtils.isBoxedPrimitive(destType)) {
return box(node);
}
// If the operand is byte or Byte and the whole expression is
// short, then convert to short.
boolean isBoxedPrimitive = TypesUtils.isBoxedPrimitive(nodeType);
- TypeMirror unboxedNodeType =
- isBoxedPrimitive ? types.unboxedType(nodeType) : nodeType;
+ TypeMirror unboxedNodeType = isBoxedPrimitive ? types.unboxedType(nodeType) : nodeType;
TypeMirror unboxedDestType =
- TypesUtils.isBoxedPrimitive(destType) ?
- types.unboxedType(destType) : destType;
- if (TypesUtils.isNumeric(unboxedNodeType) &&
- TypesUtils.isNumeric(unboxedDestType)) {
- if (unboxedNodeType.getKind() == TypeKind.BYTE &&
- destType.getKind() == TypeKind.SHORT) {
+ TypesUtils.isBoxedPrimitive(destType) ? types.unboxedType(destType) : destType;
+ if (TypesUtils.isNumeric(unboxedNodeType) && TypesUtils.isNumeric(unboxedDestType)) {
+ if (unboxedNodeType.getKind() == TypeKind.BYTE
+ && destType.getKind() == TypeKind.SHORT) {
if (isBoxedPrimitive) {
node = unbox(node);
}
@@ -2346,8 +2247,9 @@ public class CFGBuilder {
// If the operand is Byte, Short or Character and the whole expression
// is the unboxed version of it, then apply unboxing.
TypeKind destKind = destType.getKind();
- if (destKind == TypeKind.BYTE || destKind == TypeKind.CHAR ||
- destKind == TypeKind.SHORT) {
+ if (destKind == TypeKind.BYTE
+ || destKind == TypeKind.CHAR
+ || destKind == TypeKind.SHORT) {
if (isBoxedPrimitive) {
return unbox(node);
} else if (nodeType.getKind() == TypeKind.INT) {
@@ -2359,10 +2261,10 @@ public class CFGBuilder {
}
// For the final case in JLS 15.25, apply boxing but not lub.
- if (TypesUtils.isPrimitive(nodeType) &&
- (destType.getKind() == TypeKind.DECLARED ||
- destType.getKind() == TypeKind.UNION ||
- destType.getKind() == TypeKind.INTERSECTION)) {
+ if (TypesUtils.isPrimitive(nodeType)
+ && (destType.getKind() == TypeKind.DECLARED
+ || destType.getKind() == TypeKind.UNION
+ || destType.getKind() == TypeKind.INTERSECTION)) {
return box(node);
}
@@ -2370,8 +2272,8 @@ public class CFGBuilder {
}
/**
- * Returns the label {@link Name} of the leaf in the argument path, or
- * null if the leaf is not a labeled statement.
+ * Returns the label {@link Name} of the leaf in the argument path, or null if the leaf is
+ * not a labeled statement.
*/
protected /*@Nullable*/ Name getLabel(TreePath path) {
if (path.getParentPath() != null) {
@@ -2413,29 +2315,31 @@ public class CFGBuilder {
// Fifth, if the method is synchronized, lock the receiving
// object or class (15.12.4.5)
ExecutableElement method = TreeUtils.elementFromUse(tree);
+ if (method == null) {
+ // The method wasn't found, e.g. because of a compilation error.
+ return null;
+ }
+
// TODO? Variable wasn't used.
// boolean isBooleanMethod = TypesUtils.isBooleanType(method.getReturnType());
ExpressionTree methodSelect = tree.getMethodSelect();
- assert TreeUtils.isMethodAccess(methodSelect) : "Expected a method access, but got: " + methodSelect;
+ assert TreeUtils.isMethodAccess(methodSelect)
+ : "Expected a method access, but got: " + methodSelect;
List<? extends ExpressionTree> actualExprs = tree.getArguments();
// Look up method to invoke and possibly throw NullPointerException
- Node receiver = getReceiver(methodSelect,
- TreeUtils.enclosingClass(getCurrentPath()));
+ Node receiver = getReceiver(methodSelect, TreeUtils.enclosingClass(getCurrentPath()));
- MethodAccessNode target = new MethodAccessNode(methodSelect,
- receiver);
+ MethodAccessNode target = new MethodAccessNode(methodSelect, receiver);
ExecutableElement element = TreeUtils.elementFromUse(tree);
- if (ElementUtils.isStatic(element) ||
- receiver instanceof ThisLiteralNode) {
+ if (ElementUtils.isStatic(element) || receiver instanceof ThisLiteralNode) {
// No NullPointerException can be thrown, use normal node
extendWithNode(target);
} else {
- TypeElement npeElement = elements
- .getTypeElement("java.lang.NullPointerException");
+ TypeElement npeElement = elements.getTypeElement("java.lang.NullPointerException");
extendWithNodeWithException(target, npeElement.asType());
}
@@ -2454,23 +2358,24 @@ public class CFGBuilder {
// TODO: lock the receiver for synchronized methods
- MethodInvocationNode node = new MethodInvocationNode(tree, target, arguments, getCurrentPath());
+ MethodInvocationNode node =
+ new MethodInvocationNode(tree, target, arguments, getCurrentPath());
Set<TypeMirror> thrownSet = new HashSet<>();
// Add exceptions explicitly mentioned in the throws clause.
List<? extends TypeMirror> thrownTypes = element.getThrownTypes();
thrownSet.addAll(thrownTypes);
// Add Throwable to account for unchecked exceptions
- TypeElement throwableElement = elements
- .getTypeElement("java.lang.Throwable");
+ TypeElement throwableElement = elements.getTypeElement("java.lang.Throwable");
thrownSet.add(throwableElement.asType());
ExtendedNode extendedNode = extendWithNodeWithExceptions(node, thrownSet);
/* Check for the TerminatesExecution annotation. */
Element methodElement = InternalUtils.symbol(tree);
- boolean terminatesExecution = annotationProvider.getDeclAnnotation(
- methodElement, TerminatesExecution.class) != null;
+ boolean terminatesExecution =
+ annotationProvider.getDeclAnnotation(methodElement, TerminatesExecution.class)
+ != null;
if (terminatesExecution) {
extendedNode.setTerminatesExecution(true);
}
@@ -2483,11 +2388,6 @@ public class CFGBuilder {
// see JLS 14.10
- // If assertions are disabled, then nothing is executed.
- if (assumeAssertionsDisabled) {
- return null;
- }
-
// If assertions are enabled, then we can just translate the
// assertion.
if (assumeAssertionsEnabled || assumeAssertionsEnabledFor(tree)) {
@@ -2495,6 +2395,11 @@ public class CFGBuilder {
return null;
}
+ // If assertions are disabled, then nothing is executed.
+ if (assumeAssertionsDisabled) {
+ return null;
+ }
+
// Otherwise, we don't know if assertions are enabled, so we use a
// variable "ea" and case-split on it. One branch does execute the
// assertion, while the other assumes assertions are disabled.
@@ -2505,8 +2410,7 @@ public class CFGBuilder {
Label assertionDisabled = new Label();
extendWithNode(new LocalVariableNode(ea));
- extendWithExtendedNode(new ConditionalJump(assertionEnabled,
- assertionDisabled));
+ extendWithExtendedNode(new ConditionalJump(assertionEnabled, assertionDisabled));
// 'then' branch (i.e. check the assertion)
addLabelForNextNode(assertionEnabled);
@@ -2520,28 +2424,24 @@ public class CFGBuilder {
}
/**
- * Should assertions be assumed to be executed for a given
- * {@link AssertTree}? False by default.
+ * Should assertions be assumed to be executed for a given {@link AssertTree}? False by
+ * default.
*/
protected boolean assumeAssertionsEnabledFor(AssertTree tree) {
return false;
}
- /**
- * The {@link VariableTree} that indicates whether assertions are
- * enabled or not.
- */
+ /** The {@link VariableTree} that indicates whether assertions are enabled or not. */
protected VariableTree ea = null;
/**
- * Get a synthetic {@link VariableTree} that indicates whether assertions are
- * enabled or not.
+ * Get a synthetic {@link VariableTree} that indicates whether assertions are enabled or
+ * not.
*/
protected VariableTree getAssertionsEnabledVariable() {
if (ea == null) {
String name = uniqueName("assertionsEnabled");
- MethodTree enclosingMethod = TreeUtils
- .enclosingMethod(getCurrentPath());
+ MethodTree enclosingMethod = TreeUtils.enclosingMethod(getCurrentPath());
Element owner;
if (enclosingMethod != null) {
owner = TreeUtils.elementFromDeclaration(enclosingMethod);
@@ -2550,16 +2450,16 @@ public class CFGBuilder {
owner = TreeUtils.elementFromDeclaration(enclosingClass);
}
ExpressionTree initializer = null;
- ea = treeBuilder.buildVariableDecl(
- types.getPrimitiveType(TypeKind.BOOLEAN), name, owner,
- initializer);
+ ea =
+ treeBuilder.buildVariableDecl(
+ types.getPrimitiveType(TypeKind.BOOLEAN), name, owner, initializer);
}
return ea;
}
/**
- * Translates an assertion statement to the correct CFG nodes. The
- * translation assumes that assertions are enabled.
+ * Translates an assertion statement to the correct CFG nodes. The translation assumes that
+ * assertions are enabled.
*/
protected void translateAssertWithAssertionsEnabled(AssertTree tree) {
@@ -2578,13 +2478,14 @@ public class CFGBuilder {
if (tree.getDetail() != null) {
detail = scan(tree.getDetail(), null);
}
- TypeElement assertException = elements
- .getTypeElement("java.lang.AssertionError");
- AssertionErrorNode assertNode = new AssertionErrorNode(tree,
- condition, detail, assertException.asType());
+ TypeElement assertException = elements.getTypeElement("java.lang.AssertionError");
+ AssertionErrorNode assertNode =
+ new AssertionErrorNode(tree, condition, detail, assertException.asType());
extendWithNode(assertNode);
- NodeWithExceptionsHolder exNode = extendWithNodeWithException(
- new ThrowNode(null, assertNode, env.getTypeUtils()), assertException.asType());
+ NodeWithExceptionsHolder exNode =
+ extendWithNodeWithException(
+ new ThrowNode(null, assertNode, env.getTypeUtils()),
+ assertException.asType());
exNode.setTerminatesExecution(true);
// then branch (nothing happens)
@@ -2603,8 +2504,7 @@ public class CFGBuilder {
// case 1: field access
if (TreeUtils.isFieldAccess(variable)) {
// visit receiver
- Node receiver = getReceiver(variable,
- TreeUtils.enclosingClass(getCurrentPath()));
+ Node receiver = getReceiver(variable, TreeUtils.enclosingClass(getCurrentPath()));
// visit expression
Node expression = scan(tree.getExpression(), p);
@@ -2615,19 +2515,17 @@ public class CFGBuilder {
target.setLValue();
Element element = TreeUtils.elementFromUse(variable);
- if (ElementUtils.isStatic(element) ||
- receiver instanceof ThisLiteralNode) {
+ if (ElementUtils.isStatic(element) || receiver instanceof ThisLiteralNode) {
// No NullPointerException can be thrown, use normal node
extendWithNode(target);
} else {
- TypeElement npeElement = elements
- .getTypeElement("java.lang.NullPointerException");
+ TypeElement npeElement =
+ elements.getTypeElement("java.lang.NullPointerException");
extendWithNodeWithException(target, npeElement.asType());
}
// add assignment node
- assignmentNode = new AssignmentNode(tree,
- target, expression);
+ assignmentNode = new AssignmentNode(tree, target, expression);
extendWithNode(assignmentNode);
}
@@ -2636,100 +2534,93 @@ public class CFGBuilder {
Node target = scan(variable, p);
target.setLValue();
- assignmentNode = translateAssignment(tree, target,
- tree.getExpression());
+ assignmentNode = translateAssignment(tree, target, tree.getExpression());
}
return assignmentNode;
}
- /**
- * Translate an assignment.
- */
- protected AssignmentNode translateAssignment(Tree tree, Node target,
- ExpressionTree rhs) {
+ /** Translate an assignment. */
+ protected AssignmentNode translateAssignment(Tree tree, Node target, ExpressionTree rhs) {
Node expression = scan(rhs, null);
return translateAssignment(tree, target, expression);
}
- /**
- * Translate an assignment where the RHS has already been scanned.
- */
- protected AssignmentNode translateAssignment(Tree tree, Node target,
- Node expression) {
- assert tree instanceof AssignmentTree
- || tree instanceof VariableTree;
+ /** Translate an assignment where the RHS has already been scanned. */
+ protected AssignmentNode translateAssignment(Tree tree, Node target, Node expression) {
+ assert tree instanceof AssignmentTree || tree instanceof VariableTree;
target.setLValue();
expression = assignConvert(expression, target.getType());
- AssignmentNode assignmentNode = new AssignmentNode(tree, target,
- expression);
+ AssignmentNode assignmentNode = new AssignmentNode(tree, target, expression);
extendWithNode(assignmentNode);
return assignmentNode;
}
/**
- * Note 1: Requires <code>tree</code> to be a field or method access
- * tree.
- * <p>
- * Note 2: Visits the receiver and adds all necessary blocks to the CFG.
+ * Note 1: Requires {@code tree} to be a field or method access tree.
+ *
+ * <p>Note 2: Visits the receiver and adds all necessary blocks to the CFG.
*
- * @param tree
- * the field access tree containing the receiver
- * @param classTree
- * the ClassTree enclosing the field access
- * @return The receiver of the field access.
+ * @param tree the field access tree containing the receiver
+ * @param classTree the ClassTree enclosing the field access
+ * @return the receiver of the field access
*/
- private Node getReceiver(Tree tree, ClassTree classTree) {
- assert TreeUtils.isFieldAccess(tree)
- || TreeUtils.isMethodAccess(tree);
+ private Node getReceiver(ExpressionTree tree, ClassTree classTree) {
+ assert TreeUtils.isFieldAccess(tree) || TreeUtils.isMethodAccess(tree);
if (tree.getKind().equals(Tree.Kind.MEMBER_SELECT)) {
MemberSelectTree mtree = (MemberSelectTree) tree;
return scan(mtree.getExpression(), null);
} else {
- TypeMirror classType = InternalUtils.typeOf(classTree);
- Node node = new ImplicitThisLiteralNode(classType);
- extendWithNode(node);
- return node;
+ Element ele = TreeUtils.elementFromUse(tree);
+ TypeElement declaringClass = ElementUtils.enclosingClass(ele);
+ TypeMirror type = ElementUtils.getType(declaringClass);
+ if (ElementUtils.isStatic(ele)) {
+ Node node = new ClassNameNode(type, declaringClass);
+ extendWithNode(node);
+ return node;
+ } else {
+ Node node = new ImplicitThisLiteralNode(type);
+ extendWithNode(node);
+ return node;
+ }
}
}
/**
- * Map an operation with assignment to the corresponding operation
- * without assignment.
+ * Map an operation with assignment to the corresponding operation without assignment.
*
- * @param kind a Tree.Kind representing an operation with assignment
+ * @param kind a Tree.Kind representing an operation with assignment
* @return the Tree.Kind for the same operation without assignment
*/
protected Tree.Kind withoutAssignment(Tree.Kind kind) {
switch (kind) {
- case DIVIDE_ASSIGNMENT:
- return Tree.Kind.DIVIDE;
- case MULTIPLY_ASSIGNMENT:
- return Tree.Kind.MULTIPLY;
- case REMAINDER_ASSIGNMENT:
- return Tree.Kind.REMAINDER;
- case MINUS_ASSIGNMENT:
- return Tree.Kind.MINUS;
- case PLUS_ASSIGNMENT:
- return Tree.Kind.PLUS;
- case LEFT_SHIFT_ASSIGNMENT:
- return Tree.Kind.LEFT_SHIFT;
- case RIGHT_SHIFT_ASSIGNMENT:
- return Tree.Kind.RIGHT_SHIFT;
- case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT:
- return Tree.Kind.UNSIGNED_RIGHT_SHIFT;
- case AND_ASSIGNMENT:
- return Tree.Kind.AND;
- case OR_ASSIGNMENT:
- return Tree.Kind.OR;
- case XOR_ASSIGNMENT:
- return Tree.Kind.XOR;
- default:
- return Tree.Kind.ERRONEOUS;
+ case DIVIDE_ASSIGNMENT:
+ return Tree.Kind.DIVIDE;
+ case MULTIPLY_ASSIGNMENT:
+ return Tree.Kind.MULTIPLY;
+ case REMAINDER_ASSIGNMENT:
+ return Tree.Kind.REMAINDER;
+ case MINUS_ASSIGNMENT:
+ return Tree.Kind.MINUS;
+ case PLUS_ASSIGNMENT:
+ return Tree.Kind.PLUS;
+ case LEFT_SHIFT_ASSIGNMENT:
+ return Tree.Kind.LEFT_SHIFT;
+ case RIGHT_SHIFT_ASSIGNMENT:
+ return Tree.Kind.RIGHT_SHIFT;
+ case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT:
+ return Tree.Kind.UNSIGNED_RIGHT_SHIFT;
+ case AND_ASSIGNMENT:
+ return Tree.Kind.AND;
+ case OR_ASSIGNMENT:
+ return Tree.Kind.OR;
+ case XOR_ASSIGNMENT:
+ return Tree.Kind.XOR;
+ default:
+ return Tree.Kind.ERRONEOUS;
}
}
-
@Override
public Node visitCompoundAssignment(CompoundAssignmentTree tree, Void p) {
// According the JLS 15.26.2, E1 op= E2 is equivalent to
@@ -2739,84 +2630,193 @@ public class CFGBuilder {
Tree.Kind kind = tree.getKind();
switch (kind) {
- case DIVIDE_ASSIGNMENT:
- case MULTIPLY_ASSIGNMENT:
- case REMAINDER_ASSIGNMENT: {
- // see JLS 15.17 and 15.26.2
- Node targetLHS = scan(tree.getVariable(), p);
- Node value = scan(tree.getExpression(), p);
-
- TypeMirror exprType = InternalUtils.typeOf(tree);
- TypeMirror leftType = InternalUtils.typeOf(tree.getVariable());
- TypeMirror rightType = InternalUtils.typeOf(tree.getExpression());
- TypeMirror promotedType = binaryPromotedType(leftType, rightType);
- Node targetRHS = binaryNumericPromotion(targetLHS, promotedType);
- value = binaryNumericPromotion(value, promotedType);
-
- BinaryTree operTree = treeBuilder.buildBinary(promotedType, withoutAssignment(kind),
- tree.getVariable(), tree.getExpression());
- handleArtificialTree(operTree);
- Node operNode;
- if (kind == Tree.Kind.MULTIPLY_ASSIGNMENT) {
- operNode = new NumericalMultiplicationNode(operTree, targetRHS, value);
- } else if (kind == Tree.Kind.DIVIDE_ASSIGNMENT) {
- if (TypesUtils.isIntegral(exprType)) {
- operNode = new IntegerDivisionNode(operTree, targetRHS, value);
- } else {
- operNode = new FloatingDivisionNode(operTree, targetRHS, value);
- }
- } else {
- assert kind == Kind.REMAINDER_ASSIGNMENT;
- if (TypesUtils.isIntegral(exprType)) {
- operNode = new IntegerRemainderNode(operTree, targetRHS, value);
- } else {
- operNode = new FloatingRemainderNode(operTree, targetRHS, value);
- }
- }
- extendWithNode(operNode);
+ case DIVIDE_ASSIGNMENT:
+ case MULTIPLY_ASSIGNMENT:
+ case REMAINDER_ASSIGNMENT:
+ {
+ // see JLS 15.17 and 15.26.2
+ Node targetLHS = scan(tree.getVariable(), p);
+ Node value = scan(tree.getExpression(), p);
+
+ TypeMirror exprType = InternalUtils.typeOf(tree);
+ TypeMirror leftType = InternalUtils.typeOf(tree.getVariable());
+ TypeMirror rightType = InternalUtils.typeOf(tree.getExpression());
+ TypeMirror promotedType = binaryPromotedType(leftType, rightType);
+ Node targetRHS = binaryNumericPromotion(targetLHS, promotedType);
+ value = binaryNumericPromotion(value, promotedType);
+
+ BinaryTree operTree =
+ treeBuilder.buildBinary(
+ promotedType,
+ withoutAssignment(kind),
+ tree.getVariable(),
+ tree.getExpression());
+ handleArtificialTree(operTree);
+ Node operNode;
+ if (kind == Tree.Kind.MULTIPLY_ASSIGNMENT) {
+ operNode = new NumericalMultiplicationNode(operTree, targetRHS, value);
+ } else if (kind == Tree.Kind.DIVIDE_ASSIGNMENT) {
+ if (TypesUtils.isIntegral(exprType)) {
+ operNode = new IntegerDivisionNode(operTree, targetRHS, value);
+ } else {
+ operNode = new FloatingDivisionNode(operTree, targetRHS, value);
+ }
+ } else {
+ assert kind == Kind.REMAINDER_ASSIGNMENT;
+ if (TypesUtils.isIntegral(exprType)) {
+ operNode = new IntegerRemainderNode(operTree, targetRHS, value);
+ } else {
+ operNode = new FloatingRemainderNode(operTree, targetRHS, value);
+ }
+ }
+ extendWithNode(operNode);
- TypeCastTree castTree = treeBuilder.buildTypeCast(leftType, operTree);
- handleArtificialTree(castTree);
- TypeCastNode castNode = new TypeCastNode(castTree, operNode, leftType);
- castNode.setInSource(false);
- extendWithNode(castNode);
+ TypeCastTree castTree = treeBuilder.buildTypeCast(leftType, operTree);
+ handleArtificialTree(castTree);
+ TypeCastNode castNode = new TypeCastNode(castTree, operNode, leftType);
+ castNode.setInSource(false);
+ extendWithNode(castNode);
- AssignmentNode assignNode = new AssignmentNode(tree, targetLHS, castNode);
- extendWithNode(assignNode);
- return assignNode;
- }
+ AssignmentNode assignNode = new AssignmentNode(tree, targetLHS, castNode);
+ extendWithNode(assignNode);
+ return assignNode;
+ }
- case MINUS_ASSIGNMENT:
- case PLUS_ASSIGNMENT: {
- // see JLS 15.18 and 15.26.2
+ case MINUS_ASSIGNMENT:
+ case PLUS_ASSIGNMENT:
+ {
+ // see JLS 15.18 and 15.26.2
+
+ Node targetLHS = scan(tree.getVariable(), p);
+ Node value = scan(tree.getExpression(), p);
+
+ TypeMirror leftType = InternalUtils.typeOf(tree.getVariable());
+ TypeMirror rightType = InternalUtils.typeOf(tree.getExpression());
+
+ if (TypesUtils.isString(leftType) || TypesUtils.isString(rightType)) {
+ assert (kind == Tree.Kind.PLUS_ASSIGNMENT);
+ Node targetRHS = stringConversion(targetLHS);
+ value = stringConversion(value);
+ Node r = new StringConcatenateAssignmentNode(tree, targetRHS, value);
+ extendWithNode(r);
+ return r;
+ } else {
+ TypeMirror promotedType = binaryPromotedType(leftType, rightType);
+ Node targetRHS = binaryNumericPromotion(targetLHS, promotedType);
+ value = binaryNumericPromotion(value, promotedType);
+
+ BinaryTree operTree =
+ treeBuilder.buildBinary(
+ promotedType,
+ withoutAssignment(kind),
+ tree.getVariable(),
+ tree.getExpression());
+ handleArtificialTree(operTree);
+ Node operNode;
+ if (kind == Tree.Kind.PLUS_ASSIGNMENT) {
+ operNode = new NumericalAdditionNode(operTree, targetRHS, value);
+ } else {
+ assert kind == Kind.MINUS_ASSIGNMENT;
+ operNode = new NumericalSubtractionNode(operTree, targetRHS, value);
+ }
+ extendWithNode(operNode);
+
+ TypeCastTree castTree = treeBuilder.buildTypeCast(leftType, operTree);
+ handleArtificialTree(castTree);
+ TypeCastNode castNode = new TypeCastNode(castTree, operNode, leftType);
+ castNode.setInSource(false);
+ extendWithNode(castNode);
+
+ // Map the compound assignment tree to an assignment node, which
+ // will have the correct type.
+ AssignmentNode assignNode =
+ new AssignmentNode(tree, targetLHS, castNode);
+ extendWithNode(assignNode);
+ return assignNode;
+ }
+ }
- Node targetLHS = scan(tree.getVariable(), p);
- Node value = scan(tree.getExpression(), p);
+ case LEFT_SHIFT_ASSIGNMENT:
+ case RIGHT_SHIFT_ASSIGNMENT:
+ case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT:
+ {
+ // see JLS 15.19 and 15.26.2
+ Node targetLHS = scan(tree.getVariable(), p);
+ Node value = scan(tree.getExpression(), p);
+
+ TypeMirror leftType = InternalUtils.typeOf(tree.getVariable());
+
+ Node targetRHS = unaryNumericPromotion(targetLHS);
+ value = unaryNumericPromotion(value);
+
+ BinaryTree operTree =
+ treeBuilder.buildBinary(
+ leftType,
+ withoutAssignment(kind),
+ tree.getVariable(),
+ tree.getExpression());
+ handleArtificialTree(operTree);
+ Node operNode;
+ if (kind == Tree.Kind.LEFT_SHIFT_ASSIGNMENT) {
+ operNode = new LeftShiftNode(operTree, targetRHS, value);
+ } else if (kind == Tree.Kind.RIGHT_SHIFT_ASSIGNMENT) {
+ operNode = new SignedRightShiftNode(operTree, targetRHS, value);
+ } else {
+ assert kind == Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT;
+ operNode = new UnsignedRightShiftNode(operTree, targetRHS, value);
+ }
+ extendWithNode(operNode);
- TypeMirror leftType = InternalUtils.typeOf(tree.getVariable());
- TypeMirror rightType = InternalUtils.typeOf(tree.getExpression());
+ TypeCastTree castTree = treeBuilder.buildTypeCast(leftType, operTree);
+ handleArtificialTree(castTree);
+ TypeCastNode castNode = new TypeCastNode(castTree, operNode, leftType);
+ castNode.setInSource(false);
+ extendWithNode(castNode);
- if (TypesUtils.isString(leftType) || TypesUtils.isString(rightType)) {
- assert (kind == Tree.Kind.PLUS_ASSIGNMENT);
- Node targetRHS = stringConversion(targetLHS);
- value = stringConversion(value);
- Node r = new StringConcatenateAssignmentNode(tree, targetRHS, value);
- extendWithNode(r);
- return r;
- } else {
- TypeMirror promotedType = binaryPromotedType(leftType, rightType);
- Node targetRHS = binaryNumericPromotion(targetLHS, promotedType);
- value = binaryNumericPromotion(value, promotedType);
+ AssignmentNode assignNode = new AssignmentNode(tree, targetLHS, castNode);
+ extendWithNode(assignNode);
+ return assignNode;
+ }
- BinaryTree operTree = treeBuilder.buildBinary(promotedType, withoutAssignment(kind),
- tree.getVariable(), tree.getExpression());
+ case AND_ASSIGNMENT:
+ case OR_ASSIGNMENT:
+ case XOR_ASSIGNMENT:
+ // see JLS 15.22
+ Node targetLHS = scan(tree.getVariable(), p);
+ Node value = scan(tree.getExpression(), p);
+
+ TypeMirror leftType = InternalUtils.typeOf(tree.getVariable());
+ TypeMirror rightType = InternalUtils.typeOf(tree.getExpression());
+
+ Node targetRHS = null;
+ if (isNumericOrBoxed(leftType) && isNumericOrBoxed(rightType)) {
+ TypeMirror promotedType = binaryPromotedType(leftType, rightType);
+ targetRHS = binaryNumericPromotion(targetLHS, promotedType);
+ value = binaryNumericPromotion(value, promotedType);
+ } else if (TypesUtils.isBooleanType(leftType)
+ && TypesUtils.isBooleanType(rightType)) {
+ targetRHS = unbox(targetLHS);
+ value = unbox(value);
+ } else {
+ assert false
+ : "Both argument to logical operation must be numeric or boolean";
+ }
+
+ BinaryTree operTree =
+ treeBuilder.buildBinary(
+ leftType,
+ withoutAssignment(kind),
+ tree.getVariable(),
+ tree.getExpression());
handleArtificialTree(operTree);
Node operNode;
- if (kind == Tree.Kind.PLUS_ASSIGNMENT) {
- operNode = new NumericalAdditionNode(operTree, targetRHS, value);
+ if (kind == Tree.Kind.AND_ASSIGNMENT) {
+ operNode = new BitwiseAndNode(operTree, targetRHS, value);
+ } else if (kind == Tree.Kind.OR_ASSIGNMENT) {
+ operNode = new BitwiseOrNode(operTree, targetRHS, value);
} else {
- assert kind == Kind.MINUS_ASSIGNMENT;
- operNode = new NumericalSubtractionNode(operTree, targetRHS, value);
+ assert kind == Kind.XOR_ASSIGNMENT;
+ operNode = new BitwiseXorNode(operTree, targetRHS, value);
}
extendWithNode(operNode);
@@ -2826,101 +2826,12 @@ public class CFGBuilder {
castNode.setInSource(false);
extendWithNode(castNode);
- // Map the compound assignment tree to an assignment node, which
- // will have the correct type.
AssignmentNode assignNode = new AssignmentNode(tree, targetLHS, castNode);
extendWithNode(assignNode);
return assignNode;
- }
- }
-
- case LEFT_SHIFT_ASSIGNMENT:
- case RIGHT_SHIFT_ASSIGNMENT:
- case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT: {
- // see JLS 15.19 and 15.26.2
- Node targetLHS = scan(tree.getVariable(), p);
- Node value = scan(tree.getExpression(), p);
-
- TypeMirror leftType = InternalUtils.typeOf(tree.getVariable());
-
- Node targetRHS = unaryNumericPromotion(targetLHS);
- value = unaryNumericPromotion(value);
-
- BinaryTree operTree = treeBuilder.buildBinary(leftType, withoutAssignment(kind),
- tree.getVariable(), tree.getExpression());
- handleArtificialTree(operTree);
- Node operNode;
- if (kind == Tree.Kind.LEFT_SHIFT_ASSIGNMENT) {
- operNode = new LeftShiftNode(operTree, targetRHS, value);
- } else if (kind == Tree.Kind.RIGHT_SHIFT_ASSIGNMENT) {
- operNode = new SignedRightShiftNode(operTree, targetRHS, value);
- } else {
- assert kind == Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT;
- operNode = new UnsignedRightShiftNode(operTree, targetRHS, value);
- }
- extendWithNode(operNode);
-
- TypeCastTree castTree = treeBuilder.buildTypeCast(leftType, operTree);
- handleArtificialTree(castTree);
- TypeCastNode castNode = new TypeCastNode(castTree, operNode, leftType);
- castNode.setInSource(false);
- extendWithNode(castNode);
-
- AssignmentNode assignNode = new AssignmentNode(tree, targetLHS, castNode);
- extendWithNode(assignNode);
- return assignNode;
- }
-
- case AND_ASSIGNMENT:
- case OR_ASSIGNMENT:
- case XOR_ASSIGNMENT:
- // see JLS 15.22
- Node targetLHS = scan(tree.getVariable(), p);
- Node value = scan(tree.getExpression(), p);
-
- TypeMirror leftType = InternalUtils.typeOf(tree.getVariable());
- TypeMirror rightType = InternalUtils.typeOf(tree.getExpression());
-
- Node targetRHS = null;
- if (isNumericOrBoxed(leftType) && isNumericOrBoxed(rightType)) {
- TypeMirror promotedType = binaryPromotedType(leftType, rightType);
- targetRHS = binaryNumericPromotion(targetLHS, promotedType);
- value = binaryNumericPromotion(value, promotedType);
- } else if (TypesUtils.isBooleanType(leftType) &&
- TypesUtils.isBooleanType(rightType)) {
- targetRHS = unbox(targetLHS);
- value = unbox(value);
- } else {
- assert false :
- "Both argument to logical operation must be numeric or boolean";
- }
-
- BinaryTree operTree = treeBuilder.buildBinary(leftType, withoutAssignment(kind),
- tree.getVariable(), tree.getExpression());
- handleArtificialTree(operTree);
- Node operNode;
- if (kind == Tree.Kind.AND_ASSIGNMENT) {
- operNode = new BitwiseAndNode(operTree, targetRHS, value);
- } else if (kind == Tree.Kind.OR_ASSIGNMENT) {
- operNode = new BitwiseOrNode(operTree, targetRHS, value);
- } else {
- assert kind == Kind.XOR_ASSIGNMENT;
- operNode = new BitwiseXorNode(operTree, targetRHS, value);
- }
- extendWithNode(operNode);
-
- TypeCastTree castTree = treeBuilder.buildTypeCast(leftType, operTree);
- handleArtificialTree(castTree);
- TypeCastNode castNode = new TypeCastNode(castTree, operNode, leftType);
- castNode.setInSource(false);
- extendWithNode(castNode);
-
- AssignmentNode assignNode = new AssignmentNode(tree, targetLHS, castNode);
- extendWithNode(assignNode);
- return assignNode;
- default:
- assert false : "unexpected compound assignment type";
- break;
+ default:
+ assert false : "unexpected compound assignment type";
+ break;
}
assert false : "unexpected compound assignment type";
return null;
@@ -2938,235 +2849,246 @@ public class CFGBuilder {
Tree.Kind kind = tree.getKind();
switch (kind) {
- case DIVIDE:
- case MULTIPLY:
- case REMAINDER: {
- // see JLS 15.17
-
- TypeMirror exprType = InternalUtils.typeOf(tree);
- TypeMirror leftType = InternalUtils.typeOf(leftTree);
- TypeMirror rightType = InternalUtils.typeOf(rightTree);
- TypeMirror promotedType = binaryPromotedType(leftType, rightType);
-
- Node left = binaryNumericPromotion(scan(leftTree, p), promotedType);
- Node right = binaryNumericPromotion(scan(rightTree, p), promotedType);
-
- if (kind == Tree.Kind.MULTIPLY) {
- r = new NumericalMultiplicationNode(tree, left, right);
- } else if (kind == Tree.Kind.DIVIDE) {
- if (TypesUtils.isIntegral(exprType)) {
- r = new IntegerDivisionNode(tree, left, right);
- } else {
- r = new FloatingDivisionNode(tree, left, right);
- }
- } else {
- assert kind == Kind.REMAINDER;
- if (TypesUtils.isIntegral(exprType)) {
- r = new IntegerRemainderNode(tree, left, right);
- } else {
- r = new FloatingRemainderNode(tree, left, right);
+ case DIVIDE:
+ case MULTIPLY:
+ case REMAINDER:
+ {
+ // see JLS 15.17
+
+ TypeMirror exprType = InternalUtils.typeOf(tree);
+ TypeMirror leftType = InternalUtils.typeOf(leftTree);
+ TypeMirror rightType = InternalUtils.typeOf(rightTree);
+ TypeMirror promotedType = binaryPromotedType(leftType, rightType);
+
+ Node left = binaryNumericPromotion(scan(leftTree, p), promotedType);
+ Node right = binaryNumericPromotion(scan(rightTree, p), promotedType);
+
+ if (kind == Tree.Kind.MULTIPLY) {
+ r = new NumericalMultiplicationNode(tree, left, right);
+ } else if (kind == Tree.Kind.DIVIDE) {
+ if (TypesUtils.isIntegral(exprType)) {
+ r = new IntegerDivisionNode(tree, left, right);
+ } else {
+ r = new FloatingDivisionNode(tree, left, right);
+ }
+ } else {
+ assert kind == Kind.REMAINDER;
+ if (TypesUtils.isIntegral(exprType)) {
+ r = new IntegerRemainderNode(tree, left, right);
+ } else {
+ r = new FloatingRemainderNode(tree, left, right);
+ }
+ }
+ break;
}
- }
- break;
- }
-
- case MINUS:
- case PLUS: {
- // see JLS 15.18
- // TypeMirror exprType = InternalUtils.typeOf(tree);
- TypeMirror leftType = InternalUtils.typeOf(leftTree);
- TypeMirror rightType = InternalUtils.typeOf(rightTree);
-
- if (TypesUtils.isString(leftType) || TypesUtils.isString(rightType)) {
- assert (kind == Tree.Kind.PLUS);
- Node left = stringConversion(scan(leftTree, p));
- Node right = stringConversion(scan(rightTree, p));
- r = new StringConcatenateNode(tree, left, right);
- } else {
- TypeMirror promotedType = binaryPromotedType(leftType, rightType);
- Node left = binaryNumericPromotion(scan(leftTree, p), promotedType);
- Node right = binaryNumericPromotion(scan(rightTree, p), promotedType);
-
- // TODO: Decide whether to deal with floating-point value
- // set conversion.
- if (kind == Tree.Kind.PLUS) {
- r = new NumericalAdditionNode(tree, left, right);
- } else {
- assert kind == Kind.MINUS;
- r = new NumericalSubtractionNode(tree, left, right);
+ case MINUS:
+ case PLUS:
+ {
+ // see JLS 15.18
+
+ // TypeMirror exprType = InternalUtils.typeOf(tree);
+ TypeMirror leftType = InternalUtils.typeOf(leftTree);
+ TypeMirror rightType = InternalUtils.typeOf(rightTree);
+
+ if (TypesUtils.isString(leftType) || TypesUtils.isString(rightType)) {
+ assert (kind == Tree.Kind.PLUS);
+ Node left = stringConversion(scan(leftTree, p));
+ Node right = stringConversion(scan(rightTree, p));
+ r = new StringConcatenateNode(tree, left, right);
+ } else {
+ TypeMirror promotedType = binaryPromotedType(leftType, rightType);
+ Node left = binaryNumericPromotion(scan(leftTree, p), promotedType);
+ Node right = binaryNumericPromotion(scan(rightTree, p), promotedType);
+
+ // TODO: Decide whether to deal with floating-point value
+ // set conversion.
+ if (kind == Tree.Kind.PLUS) {
+ r = new NumericalAdditionNode(tree, left, right);
+ } else {
+ assert kind == Kind.MINUS;
+ r = new NumericalSubtractionNode(tree, left, right);
+ }
+ }
+ break;
}
- }
- break;
- }
-
- case LEFT_SHIFT:
- case RIGHT_SHIFT:
- case UNSIGNED_RIGHT_SHIFT: {
- // see JLS 15.19
-
- Node left = unaryNumericPromotion(scan(leftTree, p));
- Node right = unaryNumericPromotion(scan(rightTree, p));
-
- if (kind == Tree.Kind.LEFT_SHIFT) {
- r = new LeftShiftNode(tree, left, right);
- } else if (kind == Tree.Kind.RIGHT_SHIFT) {
- r = new SignedRightShiftNode(tree, left, right);
- } else {
- assert kind == Kind.UNSIGNED_RIGHT_SHIFT;
- r = new UnsignedRightShiftNode(tree, left, right);
- }
- break;
- }
-
- case GREATER_THAN:
- case GREATER_THAN_EQUAL:
- case LESS_THAN:
- case LESS_THAN_EQUAL: {
- // see JLS 15.20.1
- TypeMirror leftType = InternalUtils.typeOf(leftTree);
- if (TypesUtils.isBoxedPrimitive(leftType)) {
- leftType = types.unboxedType(leftType);
- }
-
- TypeMirror rightType = InternalUtils.typeOf(rightTree);
- if (TypesUtils.isBoxedPrimitive(rightType)) {
- rightType = types.unboxedType(rightType);
- }
-
- TypeMirror promotedType = binaryPromotedType(leftType, rightType);
- Node left = binaryNumericPromotion(scan(leftTree, p), promotedType);
- Node right = binaryNumericPromotion(scan(rightTree, p), promotedType);
-
- Node node;
- if (kind == Tree.Kind.GREATER_THAN) {
- node = new GreaterThanNode(tree, left, right);
- } else if (kind == Tree.Kind.GREATER_THAN_EQUAL) {
- node = new GreaterThanOrEqualNode(tree, left, right);
- } else if (kind == Tree.Kind.LESS_THAN) {
- node = new LessThanNode(tree, left, right);
- } else {
- assert kind == Tree.Kind.LESS_THAN_EQUAL;
- node = new LessThanOrEqualNode(tree, left, right);
- }
-
- extendWithNode(node);
- return node;
- }
+ case LEFT_SHIFT:
+ case RIGHT_SHIFT:
+ case UNSIGNED_RIGHT_SHIFT:
+ {
+ // see JLS 15.19
+
+ Node left = unaryNumericPromotion(scan(leftTree, p));
+ Node right = unaryNumericPromotion(scan(rightTree, p));
+
+ if (kind == Tree.Kind.LEFT_SHIFT) {
+ r = new LeftShiftNode(tree, left, right);
+ } else if (kind == Tree.Kind.RIGHT_SHIFT) {
+ r = new SignedRightShiftNode(tree, left, right);
+ } else {
+ assert kind == Kind.UNSIGNED_RIGHT_SHIFT;
+ r = new UnsignedRightShiftNode(tree, left, right);
+ }
+ break;
+ }
- case EQUAL_TO:
- case NOT_EQUAL_TO: {
- // see JLS 15.21
- TreeInfo leftInfo = getTreeInfo(leftTree);
- TreeInfo rightInfo = getTreeInfo(rightTree);
- Node left = scan(leftTree, p);
- Node right = scan(rightTree, p);
-
- if (leftInfo.isNumeric() && rightInfo.isNumeric() &&
- !(leftInfo.isBoxed() && rightInfo.isBoxed())) {
- // JLS 15.21.1 numerical equality
- TypeMirror promotedType = binaryPromotedType(leftInfo.unboxedType(),
- rightInfo.unboxedType());
- left = binaryNumericPromotion(left, promotedType);
- right = binaryNumericPromotion(right, promotedType);
- } else if (leftInfo.isBoolean() && rightInfo.isBoolean() &&
- !(leftInfo.isBoxed() && rightInfo.isBoxed())) {
- // JSL 15.21.2 boolean equality
- left = unboxAsNeeded(left, leftInfo.isBoxed());
- right = unboxAsNeeded(right, rightInfo.isBoxed());
- }
+ case GREATER_THAN:
+ case GREATER_THAN_EQUAL:
+ case LESS_THAN:
+ case LESS_THAN_EQUAL:
+ {
+ // see JLS 15.20.1
+ TypeMirror leftType = InternalUtils.typeOf(leftTree);
+ if (TypesUtils.isBoxedPrimitive(leftType)) {
+ leftType = types.unboxedType(leftType);
+ }
- Node node;
- if (kind == Tree.Kind.EQUAL_TO) {
- node = new EqualToNode(tree, left, right);
- } else {
- assert kind == Kind.NOT_EQUAL_TO;
- node = new NotEqualNode(tree, left, right);
- }
- extendWithNode(node);
+ TypeMirror rightType = InternalUtils.typeOf(rightTree);
+ if (TypesUtils.isBoxedPrimitive(rightType)) {
+ rightType = types.unboxedType(rightType);
+ }
- return node;
- }
+ TypeMirror promotedType = binaryPromotedType(leftType, rightType);
+ Node left = binaryNumericPromotion(scan(leftTree, p), promotedType);
+ Node right = binaryNumericPromotion(scan(rightTree, p), promotedType);
+
+ Node node;
+ if (kind == Tree.Kind.GREATER_THAN) {
+ node = new GreaterThanNode(tree, left, right);
+ } else if (kind == Tree.Kind.GREATER_THAN_EQUAL) {
+ node = new GreaterThanOrEqualNode(tree, left, right);
+ } else if (kind == Tree.Kind.LESS_THAN) {
+ node = new LessThanNode(tree, left, right);
+ } else {
+ assert kind == Tree.Kind.LESS_THAN_EQUAL;
+ node = new LessThanOrEqualNode(tree, left, right);
+ }
- case AND:
- case OR:
- case XOR: {
- // see JLS 15.22
- TypeMirror leftType = InternalUtils.typeOf(leftTree);
- TypeMirror rightType = InternalUtils.typeOf(rightTree);
- boolean isBooleanOp = TypesUtils.isBooleanType(leftType) &&
- TypesUtils.isBooleanType(rightType);
-
- Node left;
- Node right;
-
- if (isBooleanOp) {
- left = unbox(scan(leftTree, p));
- right = unbox(scan(rightTree, p));
- } else if (isNumericOrBoxed(leftType) && isNumericOrBoxed(rightType)) {
- TypeMirror promotedType = binaryPromotedType(leftType, rightType);
- left = binaryNumericPromotion(scan(leftTree, p), promotedType);
- right = binaryNumericPromotion(scan(rightTree, p), promotedType);
- } else {
- left = unbox(scan(leftTree, p));
- right = unbox(scan(rightTree, p));
- }
+ extendWithNode(node);
- Node node;
- if (kind == Tree.Kind.AND) {
- node = new BitwiseAndNode(tree, left, right);
- } else if (kind == Tree.Kind.OR) {
- node = new BitwiseOrNode(tree, left, right);
- } else {
- assert kind == Kind.XOR;
- node = new BitwiseXorNode(tree, left, right);
- }
+ return node;
+ }
- extendWithNode(node);
+ case EQUAL_TO:
+ case NOT_EQUAL_TO:
+ {
+ // see JLS 15.21
+ TreeInfo leftInfo = getTreeInfo(leftTree);
+ TreeInfo rightInfo = getTreeInfo(rightTree);
+ Node left = scan(leftTree, p);
+ Node right = scan(rightTree, p);
+
+ if (leftInfo.isNumeric()
+ && rightInfo.isNumeric()
+ && !(leftInfo.isBoxed() && rightInfo.isBoxed())) {
+ // JLS 15.21.1 numerical equality
+ TypeMirror promotedType =
+ binaryPromotedType(
+ leftInfo.unboxedType(), rightInfo.unboxedType());
+ left = binaryNumericPromotion(left, promotedType);
+ right = binaryNumericPromotion(right, promotedType);
+ } else if (leftInfo.isBoolean()
+ && rightInfo.isBoolean()
+ && !(leftInfo.isBoxed() && rightInfo.isBoxed())) {
+ // JSL 15.21.2 boolean equality
+ left = unboxAsNeeded(left, leftInfo.isBoxed());
+ right = unboxAsNeeded(right, rightInfo.isBoxed());
+ }
- return node;
- }
+ Node node;
+ if (kind == Tree.Kind.EQUAL_TO) {
+ node = new EqualToNode(tree, left, right);
+ } else {
+ assert kind == Kind.NOT_EQUAL_TO;
+ node = new NotEqualNode(tree, left, right);
+ }
+ extendWithNode(node);
- case CONDITIONAL_AND:
- case CONDITIONAL_OR: {
- // see JLS 15.23 and 15.24
+ return node;
+ }
- // all necessary labels
- Label rightStartL = new Label();
- Label shortCircuitL = new Label();
+ case AND:
+ case OR:
+ case XOR:
+ {
+ // see JLS 15.22
+ TypeMirror leftType = InternalUtils.typeOf(leftTree);
+ TypeMirror rightType = InternalUtils.typeOf(rightTree);
+ boolean isBooleanOp =
+ TypesUtils.isBooleanType(leftType)
+ && TypesUtils.isBooleanType(rightType);
+
+ Node left;
+ Node right;
+
+ if (isBooleanOp) {
+ left = unbox(scan(leftTree, p));
+ right = unbox(scan(rightTree, p));
+ } else if (isNumericOrBoxed(leftType) && isNumericOrBoxed(rightType)) {
+ TypeMirror promotedType = binaryPromotedType(leftType, rightType);
+ left = binaryNumericPromotion(scan(leftTree, p), promotedType);
+ right = binaryNumericPromotion(scan(rightTree, p), promotedType);
+ } else {
+ left = unbox(scan(leftTree, p));
+ right = unbox(scan(rightTree, p));
+ }
- // left-hand side
- Node left = scan(leftTree, p);
+ Node node;
+ if (kind == Tree.Kind.AND) {
+ node = new BitwiseAndNode(tree, left, right);
+ } else if (kind == Tree.Kind.OR) {
+ node = new BitwiseOrNode(tree, left, right);
+ } else {
+ assert kind == Kind.XOR;
+ node = new BitwiseXorNode(tree, left, right);
+ }
- ConditionalJump cjump;
- if (kind == Tree.Kind.CONDITIONAL_AND) {
- cjump = new ConditionalJump(rightStartL, shortCircuitL);
- cjump.setFalseFlowRule(Store.FlowRule.ELSE_TO_ELSE);
- } else {
- cjump = new ConditionalJump(shortCircuitL, rightStartL);
- cjump.setTrueFlowRule(Store.FlowRule.THEN_TO_THEN);
- }
- extendWithExtendedNode(cjump);
+ extendWithNode(node);
- // right-hand side
- addLabelForNextNode(rightStartL);
- Node right = scan(rightTree, p);
+ return node;
+ }
- // conditional expression itself
- addLabelForNextNode(shortCircuitL);
- Node node;
- if (kind == Tree.Kind.CONDITIONAL_AND) {
- node = new ConditionalAndNode(tree, left, right);
- } else {
- node = new ConditionalOrNode(tree, left, right);
- }
- extendWithNode(node);
- return node;
- }
- default:
- assert false : "unexpected binary tree: " + kind;
- break;
+ case CONDITIONAL_AND:
+ case CONDITIONAL_OR:
+ {
+ // see JLS 15.23 and 15.24
+
+ // all necessary labels
+ Label rightStartL = new Label();
+ Label shortCircuitL = new Label();
+
+ // left-hand side
+ Node left = scan(leftTree, p);
+
+ ConditionalJump cjump;
+ if (kind == Tree.Kind.CONDITIONAL_AND) {
+ cjump = new ConditionalJump(rightStartL, shortCircuitL);
+ cjump.setFalseFlowRule(Store.FlowRule.ELSE_TO_ELSE);
+ } else {
+ cjump = new ConditionalJump(shortCircuitL, rightStartL);
+ cjump.setTrueFlowRule(Store.FlowRule.THEN_TO_THEN);
+ }
+ extendWithExtendedNode(cjump);
+
+ // right-hand side
+ addLabelForNextNode(rightStartL);
+ Node right = scan(rightTree, p);
+
+ // conditional expression itself
+ addLabelForNextNode(shortCircuitL);
+ Node node;
+ if (kind == Tree.Kind.CONDITIONAL_AND) {
+ node = new ConditionalAndNode(tree, left, right);
+ } else {
+ node = new ConditionalOrNode(tree, left, right);
+ }
+ extendWithNode(node);
+ return node;
+ }
+ default:
+ assert false : "unexpected binary tree: " + kind;
+ break;
}
assert r != null : "unexpected binary tree";
return extendWithNode(r);
@@ -3190,8 +3112,7 @@ public class CFGBuilder {
} else {
assert breakLabels.containsKey(label);
- extendWithExtendedNode(new UnconditionalJump(
- breakLabels.get(label)));
+ extendWithExtendedNode(new UnconditionalJump(breakLabels.get(label)));
}
return null;
@@ -3205,9 +3126,9 @@ public class CFGBuilder {
}
private class SwitchBuilder {
- final private SwitchTree switchTree;
- final private Label[] caseBodyLabels;
- final private Void p;
+ private final SwitchTree switchTree;
+ private final Label[] caseBodyLabels;
+ private final Void p;
private Node switchExpr;
private SwitchBuilder(SwitchTree tree, Void p) {
@@ -3219,17 +3140,19 @@ public class CFGBuilder {
public void build() {
Label oldBreakTargetL = breakTargetL;
breakTargetL = new Label();
- int cases = caseBodyLabels.length-1;
- for(int i=0; i<cases; ++i) {
+ int cases = caseBodyLabels.length - 1;
+ for (int i = 0; i < cases; ++i) {
caseBodyLabels[i] = new Label();
}
caseBodyLabels[cases] = breakTargetL;
switchExpr = unbox(scan(switchTree.getExpression(), p));
- extendWithNode(new MarkerNode(switchTree, "start of switch statement", env.getTypeUtils()));
+ extendWithNode(
+ new MarkerNode(
+ switchTree, "start of switch statement", env.getTypeUtils()));
Integer defaultIndex = null;
- for(int i=0; i<cases; ++i) {
+ for (int i = 0; i < cases; ++i) {
CaseTree caseTree = switchTree.getCases().get(i);
if (caseTree.getExpression() == null) {
defaultIndex = i;
@@ -3250,7 +3173,7 @@ public class CFGBuilder {
private void buildCase(CaseTree tree, int index) {
final Label thisBodyL = caseBodyLabels[index];
- final Label nextBodyL = caseBodyLabels[index+1];
+ final Label nextBodyL = caseBodyLabels[index + 1];
final Label nextCaseL = new Label();
ExpressionTree exprTree = tree.getExpression();
@@ -3288,8 +3211,7 @@ public class CFGBuilder {
}
@Override
- public Node visitConditionalExpression(ConditionalExpressionTree tree,
- Void p) {
+ public Node visitConditionalExpression(ConditionalExpressionTree tree, Void p) {
// see JLS 15.25
TypeMirror exprType = InternalUtils.typeOf(tree);
@@ -3327,8 +3249,7 @@ public class CFGBuilder {
} else {
assert continueLabels.containsKey(label);
- extendWithExtendedNode(new UnconditionalJump(
- continueLabels.get(label)));
+ extendWithExtendedNode(new UnconditionalJump(continueLabels.get(label)));
}
return null;
@@ -3387,329 +3308,322 @@ public class CFGBuilder {
}
@Override
- public Node visitExpressionStatement(ExpressionStatementTree tree,
- Void p) {
+ public Node visitExpressionStatement(ExpressionStatementTree tree, Void p) {
return scan(tree.getExpression(), p);
}
@Override
public Node visitEnhancedForLoop(EnhancedForLoopTree tree, Void p) {
- // see JLS 14.14.2
- Name parentLabel = getLabel(getCurrentPath());
-
- Label conditionStart = new Label();
- Label loopEntry = new Label();
- Label loopExit = new Label();
-
- // If the loop is a labeled statement, then its continue
- // target is identical for continues with no label and
- // continues with the loop's label.
- Label updateStart;
- if (parentLabel != null) {
- updateStart = continueLabels.get(parentLabel);
- } else {
- updateStart = new Label();
- }
-
- Label oldBreakTargetL = breakTargetL;
- breakTargetL = loopExit;
-
- Label oldContinueTargetL = continueTargetL;
- continueTargetL = updateStart;
-
- // Distinguish loops over Iterables from loops over arrays.
-
- TypeElement iterableElement = elements.getTypeElement("java.lang.Iterable");
- TypeMirror iterableType = types.erasure(iterableElement.asType());
-
- VariableTree variable = tree.getVariable();
- VariableElement variableElement =
- TreeUtils.elementFromDeclaration(variable);
- ExpressionTree expression = tree.getExpression();
- StatementTree statement = tree.getStatement();
-
- TypeMirror exprType = InternalUtils.typeOf(expression);
-
- if (types.isSubtype(exprType, iterableType)) {
- // Take the upper bound of a type variable or wildcard
- exprType = TypesUtils.upperBound(exprType);
-
- assert (exprType instanceof DeclaredType) : "an Iterable must be a DeclaredType";
- DeclaredType declaredExprType = (DeclaredType) exprType;
- declaredExprType.getTypeArguments();
-
- MemberSelectTree iteratorSelect =
- treeBuilder.buildIteratorMethodAccess(expression);
- handleArtificialTree(iteratorSelect);
-
- MethodInvocationTree iteratorCall =
- treeBuilder.buildMethodInvocation(iteratorSelect);
- handleArtificialTree(iteratorCall);
-
- TypeMirror iteratorType = InternalUtils.typeOf(iteratorCall);
-
- // Declare and initialize a new, unique iterator variable
- VariableTree iteratorVariable =
- treeBuilder.buildVariableDecl(iteratorType, // annotatedIteratorTypeTree,
- uniqueName("iter"),
- variableElement.getEnclosingElement(),
- iteratorCall);
- handleArtificialTree(iteratorVariable);
-
- VariableDeclarationNode iteratorVariableDecl =
- new VariableDeclarationNode(iteratorVariable);
- iteratorVariableDecl.setInSource(false);
-
- extendWithNode(iteratorVariableDecl);
-
- Node expressionNode = scan(expression, p);
-
- MethodAccessNode iteratorAccessNode =
- new MethodAccessNode(iteratorSelect, expressionNode);
- iteratorAccessNode.setInSource(false);
- extendWithNode(iteratorAccessNode);
- MethodInvocationNode iteratorCallNode =
- new MethodInvocationNode(iteratorCall, iteratorAccessNode,
- Collections.<Node>emptyList(), getCurrentPath());
- iteratorCallNode.setInSource(false);
- extendWithNode(iteratorCallNode);
-
- translateAssignment(iteratorVariable,
- new LocalVariableNode(iteratorVariable),
- iteratorCallNode);
-
- // Test the loop ending condition
- addLabelForNextNode(conditionStart);
- IdentifierTree iteratorUse1 =
- treeBuilder.buildVariableUse(iteratorVariable);
- handleArtificialTree(iteratorUse1);
-
- LocalVariableNode iteratorReceiverNode =
- new LocalVariableNode(iteratorUse1);
- iteratorReceiverNode.setInSource(false);
- extendWithNode(iteratorReceiverNode);
-
- MemberSelectTree hasNextSelect =
- treeBuilder.buildHasNextMethodAccess(iteratorUse1);
- handleArtificialTree(hasNextSelect);
-
- MethodAccessNode hasNextAccessNode =
- new MethodAccessNode(hasNextSelect, iteratorReceiverNode);
- hasNextAccessNode.setInSource(false);
- extendWithNode(hasNextAccessNode);
-
- MethodInvocationTree hasNextCall =
- treeBuilder.buildMethodInvocation(hasNextSelect);
- handleArtificialTree(hasNextCall);
-
- MethodInvocationNode hasNextCallNode =
- new MethodInvocationNode(hasNextCall, hasNextAccessNode,
- Collections.<Node>emptyList(), getCurrentPath());
- hasNextCallNode.setInSource(false);
- extendWithNode(hasNextCallNode);
- extendWithExtendedNode(new ConditionalJump(loopEntry, loopExit));
-
- // Loop body, starting with declaration of the loop iteration variable
- addLabelForNextNode(loopEntry);
- extendWithNode(new VariableDeclarationNode(variable));
-
- IdentifierTree iteratorUse2 =
- treeBuilder.buildVariableUse(iteratorVariable);
- handleArtificialTree(iteratorUse2);
-
- LocalVariableNode iteratorReceiverNode2 =
- new LocalVariableNode(iteratorUse2);
- iteratorReceiverNode2.setInSource(false);
- extendWithNode(iteratorReceiverNode2);
-
- MemberSelectTree nextSelect =
- treeBuilder.buildNextMethodAccess(iteratorUse2);
- handleArtificialTree(nextSelect);
-
- MethodAccessNode nextAccessNode =
- new MethodAccessNode(nextSelect, iteratorReceiverNode2);
- nextAccessNode.setInSource(false);
- extendWithNode(nextAccessNode);
-
- MethodInvocationTree nextCall =
- treeBuilder.buildMethodInvocation(nextSelect);
- handleArtificialTree(nextCall);
-
- MethodInvocationNode nextCallNode =
- new MethodInvocationNode(nextCall, nextAccessNode,
- Collections.<Node>emptyList(), getCurrentPath());
- nextCallNode.setInSource(false);
- extendWithNode(nextCallNode);
-
- translateAssignment(variable,
- new LocalVariableNode(variable),
- nextCall);
-
- if (statement != null) {
- scan(statement, p);
- }
-
- // Loop back edge
- addLabelForNextNode(updateStart);
- extendWithExtendedNode(new UnconditionalJump(conditionStart));
-
- } else {
- // TODO: Shift any labels after the initialization of the
- // temporary array variable.
-
- TypeMirror arrayType = InternalUtils.typeOf(expression);
-
- // Declare and initialize a temporary array variable
- VariableTree arrayVariable =
- treeBuilder.buildVariableDecl(arrayType,
- uniqueName("array"),
- variableElement.getEnclosingElement(),
- expression);
- handleArtificialTree(arrayVariable);
-
- VariableDeclarationNode arrayVariableNode =
- new VariableDeclarationNode(arrayVariable);
- arrayVariableNode.setInSource(false);
- extendWithNode(arrayVariableNode);
- Node expressionNode = scan(expression, p);
-
- translateAssignment(arrayVariable,
- new LocalVariableNode(arrayVariable),
- expressionNode);
-
- // Declare and initialize the loop index variable
- TypeMirror intType = types.getPrimitiveType(TypeKind.INT);
-
- LiteralTree zero =
- treeBuilder.buildLiteral(new Integer(0));
- handleArtificialTree(zero);
-
- VariableTree indexVariable =
- treeBuilder.buildVariableDecl(intType,
- uniqueName("index"),
- variableElement.getEnclosingElement(),
- zero);
- handleArtificialTree(indexVariable);
- VariableDeclarationNode indexVariableNode =
- new VariableDeclarationNode(indexVariable);
- indexVariableNode.setInSource(false);
- extendWithNode(indexVariableNode);
- IntegerLiteralNode zeroNode =
- extendWithNode(new IntegerLiteralNode(zero));
-
- translateAssignment(indexVariable,
- new LocalVariableNode(indexVariable),
- zeroNode);
-
- // Compare index to array length
- addLabelForNextNode(conditionStart);
- IdentifierTree indexUse1 =
- treeBuilder.buildVariableUse(indexVariable);
- handleArtificialTree(indexUse1);
- LocalVariableNode indexNode1 =
- new LocalVariableNode(indexUse1);
- indexNode1.setInSource(false);
- extendWithNode(indexNode1);
-
- IdentifierTree arrayUse1 =
- treeBuilder.buildVariableUse(arrayVariable);
- handleArtificialTree(arrayUse1);
- LocalVariableNode arrayNode1 =
- extendWithNode(new LocalVariableNode(arrayUse1));
-
- MemberSelectTree lengthSelect =
- treeBuilder.buildArrayLengthAccess(arrayUse1);
- handleArtificialTree(lengthSelect);
- FieldAccessNode lengthAccessNode =
- new FieldAccessNode(lengthSelect, arrayNode1);
- lengthAccessNode.setInSource(false);
- extendWithNode(lengthAccessNode);
-
- BinaryTree lessThan =
- treeBuilder.buildLessThan(indexUse1, lengthSelect);
- handleArtificialTree(lessThan);
-
- LessThanNode lessThanNode =
- new LessThanNode(lessThan, indexNode1, lengthAccessNode);
- lessThanNode.setInSource(false);
- extendWithNode(lessThanNode);
- extendWithExtendedNode(new ConditionalJump(loopEntry, loopExit));
-
- // Loop body, starting with declaration of the loop iteration variable
- addLabelForNextNode(loopEntry);
- extendWithNode(new VariableDeclarationNode(variable));
-
- IdentifierTree arrayUse2 =
- treeBuilder.buildVariableUse(arrayVariable);
- handleArtificialTree(arrayUse2);
- LocalVariableNode arrayNode2 =
- new LocalVariableNode(arrayUse2);
- arrayNode2.setInSource(false);
- extendWithNode(arrayNode2);
-
- IdentifierTree indexUse2 =
- treeBuilder.buildVariableUse(indexVariable);
- handleArtificialTree(indexUse2);
- LocalVariableNode indexNode2 =
- new LocalVariableNode(indexUse2);
- indexNode2.setInSource(false);
- extendWithNode(indexNode2);
-
- ArrayAccessTree arrayAccess =
- treeBuilder.buildArrayAccess(arrayUse2, indexUse2);
- handleArtificialTree(arrayAccess);
- ArrayAccessNode arrayAccessNode =
- new ArrayAccessNode(arrayAccess, arrayNode2, indexNode2);
- arrayAccessNode.setInSource(false);
- extendWithNode(arrayAccessNode);
- translateAssignment(variable,
- new LocalVariableNode(variable),
- arrayAccessNode);
-
- if (statement != null) {
- scan(statement, p);
- }
-
- // Loop back edge
- addLabelForNextNode(updateStart);
-
- IdentifierTree indexUse3 =
- treeBuilder.buildVariableUse(indexVariable);
- handleArtificialTree(indexUse3);
- LocalVariableNode indexNode3 =
- new LocalVariableNode(indexUse3);
- indexNode3.setInSource(false);
- extendWithNode(indexNode3);
-
- LiteralTree oneTree = treeBuilder.buildLiteral(Integer.valueOf(1));
- handleArtificialTree(oneTree);
- Node one = new IntegerLiteralNode(oneTree);
- one.setInSource(false);
- extendWithNode(one);
-
- BinaryTree addOneTree = treeBuilder.buildBinary(intType, Tree.Kind.PLUS,
- indexUse3, oneTree);
- handleArtificialTree(addOneTree);
- Node addOneNode = new NumericalAdditionNode(addOneTree, indexNode3, one);
- addOneNode.setInSource(false);
- extendWithNode(addOneNode);
-
- AssignmentTree assignTree = treeBuilder.buildAssignment(indexUse3, addOneTree);
- handleArtificialTree(assignTree);
- Node assignNode = new AssignmentNode(assignTree, indexNode3, addOneNode);
- assignNode.setInSource(false);
- extendWithNode(assignNode);
-
- extendWithExtendedNode(new UnconditionalJump(conditionStart));
- }
-
- // Loop exit
- addLabelForNextNode(loopExit);
-
- breakTargetL = oldBreakTargetL;
- continueTargetL = oldContinueTargetL;
-
- return null;
+ // see JLS 14.14.2
+ Name parentLabel = getLabel(getCurrentPath());
+
+ Label conditionStart = new Label();
+ Label loopEntry = new Label();
+ Label loopExit = new Label();
+
+ // If the loop is a labeled statement, then its continue
+ // target is identical for continues with no label and
+ // continues with the loop's label.
+ Label updateStart;
+ if (parentLabel != null) {
+ updateStart = continueLabels.get(parentLabel);
+ } else {
+ updateStart = new Label();
+ }
+
+ Label oldBreakTargetL = breakTargetL;
+ breakTargetL = loopExit;
+
+ Label oldContinueTargetL = continueTargetL;
+ continueTargetL = updateStart;
+
+ // Distinguish loops over Iterables from loops over arrays.
+
+ TypeElement iterableElement = elements.getTypeElement("java.lang.Iterable");
+ TypeMirror iterableType = types.erasure(iterableElement.asType());
+
+ VariableTree variable = tree.getVariable();
+ VariableElement variableElement = TreeUtils.elementFromDeclaration(variable);
+ ExpressionTree expression = tree.getExpression();
+ StatementTree statement = tree.getStatement();
+
+ TypeMirror exprType = InternalUtils.typeOf(expression);
+
+ if (types.isSubtype(exprType, iterableType)) {
+ // Take the upper bound of a type variable or wildcard
+ exprType = TypesUtils.upperBound(exprType);
+
+ assert (exprType instanceof DeclaredType) : "an Iterable must be a DeclaredType";
+ DeclaredType declaredExprType = (DeclaredType) exprType;
+ declaredExprType.getTypeArguments();
+
+ MemberSelectTree iteratorSelect = treeBuilder.buildIteratorMethodAccess(expression);
+ handleArtificialTree(iteratorSelect);
+
+ MethodInvocationTree iteratorCall =
+ treeBuilder.buildMethodInvocation(iteratorSelect);
+ handleArtificialTree(iteratorCall);
+
+ VariableTree iteratorVariable =
+ createEnhancedForLoopIteratorVariable(iteratorCall, variableElement);
+ handleArtificialTree(iteratorVariable);
+
+ VariableDeclarationNode iteratorVariableDecl =
+ new VariableDeclarationNode(iteratorVariable);
+ iteratorVariableDecl.setInSource(false);
+
+ extendWithNode(iteratorVariableDecl);
+
+ Node expressionNode = scan(expression, p);
+
+ MethodAccessNode iteratorAccessNode =
+ new MethodAccessNode(iteratorSelect, expressionNode);
+ iteratorAccessNode.setInSource(false);
+ extendWithNode(iteratorAccessNode);
+ MethodInvocationNode iteratorCallNode =
+ new MethodInvocationNode(
+ iteratorCall,
+ iteratorAccessNode,
+ Collections.<Node>emptyList(),
+ getCurrentPath());
+ iteratorCallNode.setInSource(false);
+ extendWithNode(iteratorCallNode);
+
+ translateAssignment(
+ iteratorVariable,
+ new LocalVariableNode(iteratorVariable),
+ iteratorCallNode);
+
+ // Test the loop ending condition
+ addLabelForNextNode(conditionStart);
+ IdentifierTree iteratorUse1 = treeBuilder.buildVariableUse(iteratorVariable);
+ handleArtificialTree(iteratorUse1);
+
+ LocalVariableNode iteratorReceiverNode = new LocalVariableNode(iteratorUse1);
+ iteratorReceiverNode.setInSource(false);
+ extendWithNode(iteratorReceiverNode);
+
+ MemberSelectTree hasNextSelect = treeBuilder.buildHasNextMethodAccess(iteratorUse1);
+ handleArtificialTree(hasNextSelect);
+
+ MethodAccessNode hasNextAccessNode =
+ new MethodAccessNode(hasNextSelect, iteratorReceiverNode);
+ hasNextAccessNode.setInSource(false);
+ extendWithNode(hasNextAccessNode);
+
+ MethodInvocationTree hasNextCall = treeBuilder.buildMethodInvocation(hasNextSelect);
+ handleArtificialTree(hasNextCall);
+
+ MethodInvocationNode hasNextCallNode =
+ new MethodInvocationNode(
+ hasNextCall,
+ hasNextAccessNode,
+ Collections.<Node>emptyList(),
+ getCurrentPath());
+ hasNextCallNode.setInSource(false);
+ extendWithNode(hasNextCallNode);
+ extendWithExtendedNode(new ConditionalJump(loopEntry, loopExit));
+
+ // Loop body, starting with declaration of the loop iteration variable
+ addLabelForNextNode(loopEntry);
+ extendWithNode(new VariableDeclarationNode(variable));
+
+ IdentifierTree iteratorUse2 = treeBuilder.buildVariableUse(iteratorVariable);
+ handleArtificialTree(iteratorUse2);
+
+ LocalVariableNode iteratorReceiverNode2 = new LocalVariableNode(iteratorUse2);
+ iteratorReceiverNode2.setInSource(false);
+ extendWithNode(iteratorReceiverNode2);
+
+ MemberSelectTree nextSelect = treeBuilder.buildNextMethodAccess(iteratorUse2);
+ handleArtificialTree(nextSelect);
+
+ MethodAccessNode nextAccessNode =
+ new MethodAccessNode(nextSelect, iteratorReceiverNode2);
+ nextAccessNode.setInSource(false);
+ extendWithNode(nextAccessNode);
+
+ MethodInvocationTree nextCall = treeBuilder.buildMethodInvocation(nextSelect);
+ handleArtificialTree(nextCall);
+
+ MethodInvocationNode nextCallNode =
+ new MethodInvocationNode(
+ nextCall,
+ nextAccessNode,
+ Collections.<Node>emptyList(),
+ getCurrentPath());
+ nextCallNode.setInSource(false);
+ extendWithNode(nextCallNode);
+
+ translateAssignment(variable, new LocalVariableNode(variable), nextCall);
+
+ if (statement != null) {
+ scan(statement, p);
+ }
+
+ // Loop back edge
+ addLabelForNextNode(updateStart);
+ extendWithExtendedNode(new UnconditionalJump(conditionStart));
+
+ } else {
+ // TODO: Shift any labels after the initialization of the
+ // temporary array variable.
+
+ VariableTree arrayVariable =
+ createEnhancedForLoopArrayVariable(expression, variableElement);
+ handleArtificialTree(arrayVariable);
+
+ VariableDeclarationNode arrayVariableNode =
+ new VariableDeclarationNode(arrayVariable);
+ arrayVariableNode.setInSource(false);
+ extendWithNode(arrayVariableNode);
+ Node expressionNode = scan(expression, p);
+
+ translateAssignment(
+ arrayVariable, new LocalVariableNode(arrayVariable), expressionNode);
+
+ // Declare and initialize the loop index variable
+ TypeMirror intType = types.getPrimitiveType(TypeKind.INT);
+
+ LiteralTree zero = treeBuilder.buildLiteral(Integer.valueOf(0));
+ handleArtificialTree(zero);
+
+ VariableTree indexVariable =
+ treeBuilder.buildVariableDecl(
+ intType,
+ uniqueName("index"),
+ variableElement.getEnclosingElement(),
+ zero);
+ handleArtificialTree(indexVariable);
+ VariableDeclarationNode indexVariableNode =
+ new VariableDeclarationNode(indexVariable);
+ indexVariableNode.setInSource(false);
+ extendWithNode(indexVariableNode);
+ IntegerLiteralNode zeroNode = extendWithNode(new IntegerLiteralNode(zero));
+
+ translateAssignment(indexVariable, new LocalVariableNode(indexVariable), zeroNode);
+
+ // Compare index to array length
+ addLabelForNextNode(conditionStart);
+ IdentifierTree indexUse1 = treeBuilder.buildVariableUse(indexVariable);
+ handleArtificialTree(indexUse1);
+ LocalVariableNode indexNode1 = new LocalVariableNode(indexUse1);
+ indexNode1.setInSource(false);
+ extendWithNode(indexNode1);
+
+ IdentifierTree arrayUse1 = treeBuilder.buildVariableUse(arrayVariable);
+ handleArtificialTree(arrayUse1);
+ LocalVariableNode arrayNode1 = extendWithNode(new LocalVariableNode(arrayUse1));
+
+ MemberSelectTree lengthSelect = treeBuilder.buildArrayLengthAccess(arrayUse1);
+ handleArtificialTree(lengthSelect);
+ FieldAccessNode lengthAccessNode = new FieldAccessNode(lengthSelect, arrayNode1);
+ lengthAccessNode.setInSource(false);
+ extendWithNode(lengthAccessNode);
+
+ BinaryTree lessThan = treeBuilder.buildLessThan(indexUse1, lengthSelect);
+ handleArtificialTree(lessThan);
+
+ LessThanNode lessThanNode =
+ new LessThanNode(lessThan, indexNode1, lengthAccessNode);
+ lessThanNode.setInSource(false);
+ extendWithNode(lessThanNode);
+ extendWithExtendedNode(new ConditionalJump(loopEntry, loopExit));
+
+ // Loop body, starting with declaration of the loop iteration variable
+ addLabelForNextNode(loopEntry);
+ extendWithNode(new VariableDeclarationNode(variable));
+
+ IdentifierTree arrayUse2 = treeBuilder.buildVariableUse(arrayVariable);
+ handleArtificialTree(arrayUse2);
+ LocalVariableNode arrayNode2 = new LocalVariableNode(arrayUse2);
+ arrayNode2.setInSource(false);
+ extendWithNode(arrayNode2);
+
+ IdentifierTree indexUse2 = treeBuilder.buildVariableUse(indexVariable);
+ handleArtificialTree(indexUse2);
+ LocalVariableNode indexNode2 = new LocalVariableNode(indexUse2);
+ indexNode2.setInSource(false);
+ extendWithNode(indexNode2);
+
+ ArrayAccessTree arrayAccess = treeBuilder.buildArrayAccess(arrayUse2, indexUse2);
+ handleArtificialTree(arrayAccess);
+ ArrayAccessNode arrayAccessNode =
+ new ArrayAccessNode(arrayAccess, arrayNode2, indexNode2);
+ arrayAccessNode.setInSource(false);
+ extendWithNode(arrayAccessNode);
+ translateAssignment(variable, new LocalVariableNode(variable), arrayAccessNode);
+
+ if (statement != null) {
+ scan(statement, p);
+ }
+
+ // Loop back edge
+ addLabelForNextNode(updateStart);
+
+ IdentifierTree indexUse3 = treeBuilder.buildVariableUse(indexVariable);
+ handleArtificialTree(indexUse3);
+ LocalVariableNode indexNode3 = new LocalVariableNode(indexUse3);
+ indexNode3.setInSource(false);
+ extendWithNode(indexNode3);
+
+ LiteralTree oneTree = treeBuilder.buildLiteral(Integer.valueOf(1));
+ handleArtificialTree(oneTree);
+ Node one = new IntegerLiteralNode(oneTree);
+ one.setInSource(false);
+ extendWithNode(one);
+
+ BinaryTree addOneTree =
+ treeBuilder.buildBinary(intType, Tree.Kind.PLUS, indexUse3, oneTree);
+ handleArtificialTree(addOneTree);
+ Node addOneNode = new NumericalAdditionNode(addOneTree, indexNode3, one);
+ addOneNode.setInSource(false);
+ extendWithNode(addOneNode);
+
+ AssignmentTree assignTree = treeBuilder.buildAssignment(indexUse3, addOneTree);
+ handleArtificialTree(assignTree);
+ Node assignNode = new AssignmentNode(assignTree, indexNode3, addOneNode);
+ assignNode.setInSource(false);
+ extendWithNode(assignNode);
+
+ extendWithExtendedNode(new UnconditionalJump(conditionStart));
+ }
+
+ // Loop exit
+ addLabelForNextNode(loopExit);
+
+ breakTargetL = oldBreakTargetL;
+ continueTargetL = oldContinueTargetL;
+
+ return null;
+ }
+
+ protected VariableTree createEnhancedForLoopIteratorVariable(
+ MethodInvocationTree iteratorCall, VariableElement variableElement) {
+ TypeMirror iteratorType = InternalUtils.typeOf(iteratorCall);
+
+ // Declare and initialize a new, unique iterator variable
+ VariableTree iteratorVariable =
+ treeBuilder.buildVariableDecl(
+ iteratorType, // annotatedIteratorTypeTree,
+ uniqueName("iter"),
+ variableElement.getEnclosingElement(),
+ iteratorCall);
+ return iteratorVariable;
+ }
+
+ protected VariableTree createEnhancedForLoopArrayVariable(
+ ExpressionTree expression, VariableElement variableElement) {
+ TypeMirror arrayType = InternalUtils.typeOf(expression);
+
+ // Declare and initialize a temporary array variable
+ VariableTree arrayVariable =
+ treeBuilder.buildVariableDecl(
+ arrayType,
+ uniqueName("array"),
+ variableElement.getEnclosingElement(),
+ expression);
+ return arrayVariable;
}
@Override
@@ -3776,38 +3690,38 @@ public class CFGBuilder {
public Node visitIdentifier(IdentifierTree tree, Void p) {
Node node;
if (TreeUtils.isFieldAccess(tree)) {
- Node receiver = getReceiver(tree,
- TreeUtils.enclosingClass(getCurrentPath()));
+ Node receiver = getReceiver(tree, TreeUtils.enclosingClass(getCurrentPath()));
node = new FieldAccessNode(tree, receiver);
} else {
Element element = TreeUtils.elementFromUse(tree);
switch (element.getKind()) {
- case ANNOTATION_TYPE:
- case CLASS:
- case ENUM:
- case INTERFACE:
- case TYPE_PARAMETER:
- node = new ClassNameNode(tree);
- break;
- case FIELD:
- // Note that "this"/"super" is a field, but not a field access.
- if (element.getSimpleName().contentEquals("this"))
- node = new ExplicitThisLiteralNode(tree);
- else
- node = new SuperNode(tree);
- break;
- case EXCEPTION_PARAMETER:
- case LOCAL_VARIABLE:
- case RESOURCE_VARIABLE:
- case PARAMETER:
- node = new LocalVariableNode(tree);
- break;
- case PACKAGE:
- node = new PackageNameNode(tree);
- break;
- default:
- throw new IllegalArgumentException(
- "unexpected element kind : " + element.getKind());
+ case ANNOTATION_TYPE:
+ case CLASS:
+ case ENUM:
+ case INTERFACE:
+ case TYPE_PARAMETER:
+ node = new ClassNameNode(tree);
+ break;
+ case FIELD:
+ // Note that "this"/"super" is a field, but not a field access.
+ if (element.getSimpleName().contentEquals("this")) {
+ node = new ExplicitThisLiteralNode(tree);
+ } else {
+ node = new SuperNode(tree);
+ }
+ break;
+ case EXCEPTION_PARAMETER:
+ case LOCAL_VARIABLE:
+ case RESOURCE_VARIABLE:
+ case PARAMETER:
+ node = new LocalVariableNode(tree);
+ break;
+ case PACKAGE:
+ node = new PackageNameNode(tree);
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "unexpected element kind : " + element.getKind());
}
}
extendWithNode(node);
@@ -3887,33 +3801,33 @@ public class CFGBuilder {
public Node visitLiteral(LiteralTree tree, Void p) {
Node r = null;
switch (tree.getKind()) {
- case BOOLEAN_LITERAL:
- r = new BooleanLiteralNode(tree);
- break;
- case CHAR_LITERAL:
- r = new CharacterLiteralNode(tree);
- break;
- case DOUBLE_LITERAL:
- r = new DoubleLiteralNode(tree);
- break;
- case FLOAT_LITERAL:
- r = new FloatLiteralNode(tree);
- break;
- case INT_LITERAL:
- r = new IntegerLiteralNode(tree);
- break;
- case LONG_LITERAL:
- r = new LongLiteralNode(tree);
- break;
- case NULL_LITERAL:
- r = new NullLiteralNode(tree);
- break;
- case STRING_LITERAL:
- r = new StringLiteralNode(tree);
- break;
- default:
- assert false : "unexpected literal tree";
- break;
+ case BOOLEAN_LITERAL:
+ r = new BooleanLiteralNode(tree);
+ break;
+ case CHAR_LITERAL:
+ r = new CharacterLiteralNode(tree);
+ break;
+ case DOUBLE_LITERAL:
+ r = new DoubleLiteralNode(tree);
+ break;
+ case FLOAT_LITERAL:
+ r = new FloatLiteralNode(tree);
+ break;
+ case INT_LITERAL:
+ r = new IntegerLiteralNode(tree);
+ break;
+ case LONG_LITERAL:
+ r = new LongLiteralNode(tree);
+ break;
+ case NULL_LITERAL:
+ r = new NullLiteralNode(tree);
+ break;
+ case STRING_LITERAL:
+ r = new StringLiteralNode(tree);
+ break;
+ default:
+ assert false : "unexpected literal tree";
+ break;
}
assert r != null : "unexpected literal tree";
Node result = extendWithNode(r);
@@ -3936,12 +3850,11 @@ public class CFGBuilder {
public Node visitNewArray(NewArrayTree tree, Void p) {
// see JLS 15.10
- ArrayType type = (ArrayType)InternalUtils.typeOf(tree);
+ ArrayType type = (ArrayType) InternalUtils.typeOf(tree);
TypeMirror elemType = type.getComponentType();
List<? extends ExpressionTree> dimensions = tree.getDimensions();
- List<? extends ExpressionTree> initializers = tree
- .getInitializers();
+ List<? extends ExpressionTree> initializers = tree.getInitializers();
List<Node> dimensionNodes = new ArrayList<Node>();
if (dimensions != null) {
@@ -3957,8 +3870,7 @@ public class CFGBuilder {
}
}
- Node node = new ArrayCreationNode(tree, type, dimensionNodes,
- initializerNodes);
+ Node node = new ArrayCreationNode(tree, type, dimensionNodes, initializerNodes);
return extendWithNode(node);
}
@@ -3973,15 +3885,19 @@ public class CFGBuilder {
// We ignore any class body because its methods should
// be visited separately.
+ // TODO: For anonymous classes we want to propagate the current store
+ // to the anonymous class.
+ // See Issues 266, 811.
// Convert constructor arguments
ExecutableElement constructor = TreeUtils.elementFromUse(tree);
List<? extends ExpressionTree> actualExprs = tree.getArguments();
- List<Node> arguments = convertCallArguments(constructor,
- actualExprs);
+ List<Node> arguments = convertCallArguments(constructor, actualExprs);
+ // TODO: for anonymous classes, don't use the identifier alone.
+ // See Issue 890.
Node constructorNode = scan(tree.getIdentifier(), p);
Node node = new ObjectCreationNode(tree, constructorNode, arguments);
@@ -3991,8 +3907,7 @@ public class CFGBuilder {
List<? extends TypeMirror> thrownTypes = constructor.getThrownTypes();
thrownSet.addAll(thrownTypes);
// Add Throwable to account for unchecked exceptions
- TypeElement throwableElement = elements
- .getTypeElement("java.lang.Throwable");
+ TypeElement throwableElement = elements.getTypeElement("java.lang.Throwable");
thrownSet.add(throwableElement.asType());
extendWithNodeWithExceptions(node, thrownSet);
@@ -4001,14 +3916,14 @@ public class CFGBuilder {
}
/**
- * Maps a <code>Tree</code> its directly enclosing <code>ParenthesizedTree</code> if one exists.
+ * Maps a {@code Tree} its directly enclosing {@code ParenthesizedTree} if one exists.
*
- * This map is used by {@link CFGTranslationPhaseOne#addToLookupMap(Node)} to
- * associate a <code>ParenthesizedTree</code> with the dataflow <code>Node</code> that was used
- * during inference. This map is necessary because dataflow does
- * not create a <code>Node</code> for a <code>ParenthesizedTree.</code>
+ * <p>This map is used by {@link CFGTranslationPhaseOne#addToLookupMap(Node)} to associate a
+ * {@code ParenthesizedTree} with the dataflow {@code Node} that was used during inference.
+ * This map is necessary because dataflow does not create a {@code Node} for a {@code
+ * ParenthesizedTree.}
*/
- private Map<Tree, ParenthesizedTree> parenMapping = new HashMap<>();
+ private final Map<Tree, ParenthesizedTree> parenMapping = new HashMap<>();
@Override
public Node visitParenthesized(ParenthesizedTree tree, Void p) {
@@ -4023,17 +3938,30 @@ public class CFGBuilder {
ReturnNode result = null;
if (ret != null) {
Node node = scan(ret, p);
- Tree enclosing = TreeUtils.enclosingOfKind(getCurrentPath(), new HashSet<Kind>(Arrays.asList(Kind.METHOD, Kind.LAMBDA_EXPRESSION)));
+ Tree enclosing =
+ TreeUtils.enclosingOfKind(
+ getCurrentPath(),
+ new HashSet<Kind>(
+ Arrays.asList(Kind.METHOD, Kind.LAMBDA_EXPRESSION)));
if (enclosing.getKind() == Kind.LAMBDA_EXPRESSION) {
LambdaExpressionTree lambdaTree = (LambdaExpressionTree) enclosing;
- TreePath lambdaTreePath = TreePath.getPath(getCurrentPath().getCompilationUnit(), lambdaTree);
- Context ctx = ((JavacProcessingEnvironment)env).getContext();
- Element overriddenElement = com.sun.tools.javac.code.Types.instance(ctx).findDescriptorSymbol(
- ((Type)trees.getTypeMirror(lambdaTreePath)).tsym);
-
- result = new ReturnNode(tree, node, env.getTypeUtils(), lambdaTree, (MethodSymbol)overriddenElement);
+ TreePath lambdaTreePath =
+ TreePath.getPath(getCurrentPath().getCompilationUnit(), lambdaTree);
+ Context ctx = ((JavacProcessingEnvironment) env).getContext();
+ Element overriddenElement =
+ com.sun.tools.javac.code.Types.instance(ctx)
+ .findDescriptorSymbol(
+ ((Type) trees.getTypeMirror(lambdaTreePath)).tsym);
+
+ result =
+ new ReturnNode(
+ tree,
+ node,
+ env.getTypeUtils(),
+ lambdaTree,
+ (MethodSymbol) overriddenElement);
} else {
- result = new ReturnNode(tree, node, env.getTypeUtils(), (MethodTree)enclosing);
+ result = new ReturnNode(tree, node, env.getTypeUtils(), (MethodTree) enclosing);
}
returnNodes.add(result);
extendWithNode(result);
@@ -4051,18 +3979,18 @@ public class CFGBuilder {
Node result = null;
Element element = TreeUtils.elementFromUse(tree);
switch (element.getKind()) {
- case ANNOTATION_TYPE:
- case CLASS:
- case ENUM:
- case INTERFACE:
- result = extendWithNode(new ClassNameNode(tree, expr));
- break;
- case PACKAGE:
- result = extendWithNode(new PackageNameNode(tree, (PackageNameNode) expr));
- break;
- default:
- assert false : "Unexpected element kind: " + element.getKind();
- return null;
+ case ANNOTATION_TYPE:
+ case CLASS:
+ case ENUM:
+ case INTERFACE:
+ result = extendWithNode(new ClassNameNode(tree, expr));
+ break;
+ case PACKAGE:
+ result = extendWithNode(new PackageNameNode(tree, (PackageNameNode) expr));
+ break;
+ default:
+ assert false : "Unexpected element kind: " + element.getKind();
+ return null;
}
return result;
}
@@ -4070,14 +3998,13 @@ public class CFGBuilder {
Node node = new FieldAccessNode(tree, expr);
Element element = TreeUtils.elementFromUse(tree);
- if (ElementUtils.isStatic(element) ||
- expr instanceof ImplicitThisLiteralNode ||
- expr instanceof ExplicitThisLiteralNode) {
+ if (ElementUtils.isStatic(element)
+ || expr instanceof ImplicitThisLiteralNode
+ || expr instanceof ExplicitThisLiteralNode) {
// No NullPointerException can be thrown, use normal node
extendWithNode(node);
} else {
- TypeElement npeElement = elements
- .getTypeElement("java.lang.NullPointerException");
+ TypeElement npeElement = elements.getTypeElement("java.lang.NullPointerException");
extendWithNodeWithException(node, npeElement.asType());
}
@@ -4093,11 +4020,13 @@ public class CFGBuilder {
public Node visitSynchronized(SynchronizedTree tree, Void p) {
// see JLS 14.19
- synchronizedExpr = scan(tree.getExpression(), p);
- SynchronizedNode synchronizedStartNode = new SynchronizedNode(tree, synchronizedExpr, true, env.getTypeUtils());
+ Node synchronizedExpr = scan(tree.getExpression(), p);
+ SynchronizedNode synchronizedStartNode =
+ new SynchronizedNode(tree, synchronizedExpr, true, env.getTypeUtils());
extendWithNode(synchronizedStartNode);
scan(tree.getBlock(), p);
- SynchronizedNode synchronizedEndNode = new SynchronizedNode(tree, synchronizedExpr, false, env.getTypeUtils());
+ SynchronizedNode synchronizedEndNode =
+ new SynchronizedNode(tree, synchronizedExpr, false, env.getTypeUtils());
extendWithNode(synchronizedEndNode);
return null;
@@ -4108,8 +4037,7 @@ public class CFGBuilder {
Node expression = scan(tree.getExpression(), p);
TypeMirror exception = expression.getType();
ThrowNode throwsNode = new ThrowNode(tree, expression, env.getTypeUtils());
- NodeWithExceptionsHolder exNode = extendWithNodeWithException(
- throwsNode, exception);
+ NodeWithExceptionsHolder exNode = extendWithNodeWithException(throwsNode, exception);
exNode.setTerminatesExecution(true);
return throwsNode;
}
@@ -4161,7 +4089,8 @@ public class CFGBuilder {
addLabelForNextNode(catchLabels.get(catchIndex).second);
scan(c, p);
catchIndex++;
- extendWithExtendedNode(new UnconditionalJump(firstNonNull(finallyLabel, doneLabel)));
+ extendWithExtendedNode(
+ new UnconditionalJump(firstNonNull(finallyLabel, doneLabel)));
}
if (finallyLabel != null) {
@@ -4169,10 +4098,10 @@ public class CFGBuilder {
addLabelForNextNode(finallyLabel);
scan(finallyBlock, p);
- TypeMirror throwableType =
- elements.getTypeElement("java.lang.Throwable").asType();
- extendWithNodeWithException(new MarkerNode(tree, "end of finally block", env.getTypeUtils()),
- throwableType);
+ TypeMirror throwableType = elements.getTypeElement("java.lang.Throwable").asType();
+ extendWithNodeWithException(
+ new MarkerNode(tree, "end of finally block", env.getTypeUtils()),
+ throwableType);
}
addLabelForNextNode(doneLabel);
@@ -4222,8 +4151,7 @@ public class CFGBuilder {
public Node visitInstanceOf(InstanceOfTree tree, Void p) {
Node operand = scan(tree.getExpression(), p);
TypeMirror refType = InternalUtils.typeOf(tree.getType());
- InstanceOfNode node = new InstanceOfNode(tree, operand, refType,
- types);
+ InstanceOfNode node = new InstanceOfNode(tree, operand, refType, types);
extendWithNode(node);
return node;
}
@@ -4233,130 +4161,141 @@ public class CFGBuilder {
Node result = null;
Tree.Kind kind = tree.getKind();
switch (kind) {
- case BITWISE_COMPLEMENT:
- case UNARY_MINUS:
- case UNARY_PLUS: {
- // see JLS 15.14 and 15.15
- Node expr = scan(tree.getExpression(), p);
- expr = unaryNumericPromotion(expr);
-
- // TypeMirror exprType = InternalUtils.typeOf(tree);
-
- switch (kind) {
case BITWISE_COMPLEMENT:
- result = extendWithNode(new BitwiseComplementNode(tree,
- expr));
- break;
case UNARY_MINUS:
- result = extendWithNode(new NumericalMinusNode(tree, expr));
- break;
case UNARY_PLUS:
- result = extendWithNode(new NumericalPlusNode(tree, expr));
- break;
- default:
- assert false;
- break;
- }
- break;
- }
-
- case LOGICAL_COMPLEMENT: {
- // see JLS 15.15.6
- Node expr = scan(tree.getExpression(), p);
- result = extendWithNode(new ConditionalNotNode(tree,
- unbox(expr)));
- break;
- }
-
- case POSTFIX_DECREMENT:
- case POSTFIX_INCREMENT: {
- ExpressionTree exprTree = tree.getExpression();
- TypeMirror exprType = InternalUtils.typeOf(exprTree);
- TypeMirror oneType = types.getPrimitiveType(TypeKind.INT);
- Node expr = scan(exprTree, p);
-
- TypeMirror promotedType = binaryPromotedType(exprType, oneType);
-
- LiteralTree oneTree = treeBuilder.buildLiteral(Integer.valueOf(1));
- handleArtificialTree(oneTree);
-
- Node exprRHS = binaryNumericPromotion(expr, promotedType);
- Node one = new IntegerLiteralNode(oneTree);
- one.setInSource(false);
- extendWithNode(one);
- one = binaryNumericPromotion(one, promotedType);
-
- BinaryTree operTree = treeBuilder.buildBinary(promotedType,
- (kind == Tree.Kind.POSTFIX_INCREMENT ? Tree.Kind.PLUS : Tree.Kind.MINUS),
- exprTree, oneTree);
- handleArtificialTree(operTree);
- Node operNode;
- if (kind == Tree.Kind.POSTFIX_INCREMENT) {
- operNode = new NumericalAdditionNode(operTree, exprRHS, one);
- } else {
- assert kind == Tree.Kind.POSTFIX_DECREMENT;
- operNode = new NumericalSubtractionNode(operTree, exprRHS, one);
- }
- extendWithNode(operNode);
-
- Node narrowed = narrowAndBox(operNode, exprType);
- // TODO: By using the assignment as the result of the expression, we
- // act like a pre-increment/decrement. Fix this by saving the initial
- // value of the expression in a temporary.
- AssignmentNode assignNode = new AssignmentNode(tree, expr, narrowed);
- extendWithNode(assignNode);
- result = assignNode;
- break;
- }
- case PREFIX_DECREMENT:
- case PREFIX_INCREMENT: {
- ExpressionTree exprTree = tree.getExpression();
- TypeMirror exprType = InternalUtils.typeOf(exprTree);
- TypeMirror oneType = types.getPrimitiveType(TypeKind.INT);
- Node expr = scan(exprTree, p);
-
- TypeMirror promotedType = binaryPromotedType(exprType, oneType);
+ {
+ // see JLS 15.14 and 15.15
+ Node expr = scan(tree.getExpression(), p);
+ expr = unaryNumericPromotion(expr);
+
+ // TypeMirror exprType = InternalUtils.typeOf(tree);
+
+ switch (kind) {
+ case BITWISE_COMPLEMENT:
+ result = extendWithNode(new BitwiseComplementNode(tree, expr));
+ break;
+ case UNARY_MINUS:
+ result = extendWithNode(new NumericalMinusNode(tree, expr));
+ break;
+ case UNARY_PLUS:
+ result = extendWithNode(new NumericalPlusNode(tree, expr));
+ break;
+ default:
+ assert false;
+ break;
+ }
+ break;
+ }
- LiteralTree oneTree = treeBuilder.buildLiteral(Integer.valueOf(1));
- handleArtificialTree(oneTree);
+ case LOGICAL_COMPLEMENT:
+ {
+ // see JLS 15.15.6
+ Node expr = scan(tree.getExpression(), p);
+ result = extendWithNode(new ConditionalNotNode(tree, unbox(expr)));
+ break;
+ }
- Node exprRHS = binaryNumericPromotion(expr, promotedType);
- Node one = new IntegerLiteralNode(oneTree);
- one.setInSource(false);
- extendWithNode(one);
- one = binaryNumericPromotion(one, promotedType);
-
- BinaryTree operTree = treeBuilder.buildBinary(promotedType,
- (kind == Tree.Kind.PREFIX_INCREMENT ? Tree.Kind.PLUS : Tree.Kind.MINUS),
- exprTree, oneTree);
- handleArtificialTree(operTree);
- Node operNode;
- if (kind == Tree.Kind.PREFIX_INCREMENT) {
- operNode = new NumericalAdditionNode(operTree, exprRHS, one);
- } else {
- assert kind == Tree.Kind.PREFIX_DECREMENT;
- operNode = new NumericalSubtractionNode(operTree, exprRHS, one);
- }
- extendWithNode(operNode);
+ case POSTFIX_DECREMENT:
+ case POSTFIX_INCREMENT:
+ {
+ ExpressionTree exprTree = tree.getExpression();
+ TypeMirror exprType = InternalUtils.typeOf(exprTree);
+ TypeMirror oneType = types.getPrimitiveType(TypeKind.INT);
+ Node expr = scan(exprTree, p);
+
+ TypeMirror promotedType = binaryPromotedType(exprType, oneType);
+
+ LiteralTree oneTree = treeBuilder.buildLiteral(Integer.valueOf(1));
+ handleArtificialTree(oneTree);
+
+ Node exprRHS = binaryNumericPromotion(expr, promotedType);
+ Node one = new IntegerLiteralNode(oneTree);
+ one.setInSource(false);
+ extendWithNode(one);
+ one = binaryNumericPromotion(one, promotedType);
+
+ BinaryTree operTree =
+ treeBuilder.buildBinary(
+ promotedType,
+ (kind == Tree.Kind.POSTFIX_INCREMENT
+ ? Tree.Kind.PLUS
+ : Tree.Kind.MINUS),
+ exprTree,
+ oneTree);
+ handleArtificialTree(operTree);
+ Node operNode;
+ if (kind == Tree.Kind.POSTFIX_INCREMENT) {
+ operNode = new NumericalAdditionNode(operTree, exprRHS, one);
+ } else {
+ assert kind == Tree.Kind.POSTFIX_DECREMENT;
+ operNode = new NumericalSubtractionNode(operTree, exprRHS, one);
+ }
+ extendWithNode(operNode);
+
+ Node narrowed = narrowAndBox(operNode, exprType);
+ // TODO: By using the assignment as the result of the expression, we
+ // act like a pre-increment/decrement. Fix this by saving the initial
+ // value of the expression in a temporary.
+ AssignmentNode assignNode = new AssignmentNode(tree, expr, narrowed);
+ extendWithNode(assignNode);
+ result = assignNode;
+ break;
+ }
+ case PREFIX_DECREMENT:
+ case PREFIX_INCREMENT:
+ {
+ ExpressionTree exprTree = tree.getExpression();
+ TypeMirror exprType = InternalUtils.typeOf(exprTree);
+ TypeMirror oneType = types.getPrimitiveType(TypeKind.INT);
+ Node expr = scan(exprTree, p);
+
+ TypeMirror promotedType = binaryPromotedType(exprType, oneType);
+
+ LiteralTree oneTree = treeBuilder.buildLiteral(Integer.valueOf(1));
+ handleArtificialTree(oneTree);
+
+ Node exprRHS = binaryNumericPromotion(expr, promotedType);
+ Node one = new IntegerLiteralNode(oneTree);
+ one.setInSource(false);
+ extendWithNode(one);
+ one = binaryNumericPromotion(one, promotedType);
+
+ BinaryTree operTree =
+ treeBuilder.buildBinary(
+ promotedType,
+ (kind == Tree.Kind.PREFIX_INCREMENT
+ ? Tree.Kind.PLUS
+ : Tree.Kind.MINUS),
+ exprTree,
+ oneTree);
+ handleArtificialTree(operTree);
+ Node operNode;
+ if (kind == Tree.Kind.PREFIX_INCREMENT) {
+ operNode = new NumericalAdditionNode(operTree, exprRHS, one);
+ } else {
+ assert kind == Tree.Kind.PREFIX_DECREMENT;
+ operNode = new NumericalSubtractionNode(operTree, exprRHS, one);
+ }
+ extendWithNode(operNode);
- Node narrowed = narrowAndBox(operNode, exprType);
- AssignmentNode assignNode = new AssignmentNode(tree, expr, narrowed);
- extendWithNode(assignNode);
- result = assignNode;
- break;
- }
+ Node narrowed = narrowAndBox(operNode, exprType);
+ AssignmentNode assignNode = new AssignmentNode(tree, expr, narrowed);
+ extendWithNode(assignNode);
+ result = assignNode;
+ break;
+ }
- case OTHER:
- default:
- // special node NLLCHK
- if (tree.toString().startsWith("<*nullchk*>")) {
- Node expr = scan(tree.getExpression(), p);
- result = extendWithNode(new NullChkNode(tree, expr));
- break;
- }
+ case OTHER:
+ default:
+ // special node NLLCHK
+ if (tree.toString().startsWith("<*nullchk*>")) {
+ Node expr = scan(tree.getExpression(), p);
+ result = extendWithNode(new NullChkNode(tree, expr));
+ break;
+ }
- assert false : "Unknown kind (" + kind
- + ") of unary expression: " + tree;
+ assert false : "Unknown kind (" + kind + ") of unary expression: " + tree;
}
return result;
@@ -4367,22 +4306,24 @@ public class CFGBuilder {
// see JLS 14.4
- boolean isField = TreeUtils.enclosingOfKind(getCurrentPath(), Kind.BLOCK) == null;
+ boolean isField =
+ getCurrentPath().getParentPath() != null
+ && getCurrentPath().getParentPath().getLeaf().getKind() == Kind.CLASS;
Node node = null;
- ClassTree enclosingClass = TreeUtils
- .enclosingClass(getCurrentPath());
- TypeElement classElem = TreeUtils
- .elementFromDeclaration(enclosingClass);
+ ClassTree enclosingClass = TreeUtils.enclosingClass(getCurrentPath());
+ TypeElement classElem = TreeUtils.elementFromDeclaration(enclosingClass);
Node receiver = new ImplicitThisLiteralNode(classElem.asType());
if (isField) {
ExpressionTree initializer = tree.getInitializer();
assert initializer != null;
- node = translateAssignment(
- tree,
- new FieldAccessNode(tree, TreeUtils.elementFromDeclaration(tree), receiver),
- initializer);
+ node =
+ translateAssignment(
+ tree,
+ new FieldAccessNode(
+ tree, TreeUtils.elementFromDeclaration(tree), receiver),
+ initializer);
} else {
// local variable definition
VariableDeclarationNode decl = new VariableDeclarationNode(tree);
@@ -4392,8 +4333,9 @@ public class CFGBuilder {
ExpressionTree initializer = tree.getInitializer();
if (initializer != null) {
- node = translateAssignment(tree, new LocalVariableNode(tree, receiver),
- initializer);
+ node =
+ translateAssignment(
+ tree, new LocalVariableNode(tree, receiver), initializer);
}
}
@@ -4481,13 +4423,14 @@ public class CFGBuilder {
}
}
- /**
- * A tuple with 4 named elements.
- */
+ /** A tuple with 4 named elements. */
private interface TreeInfo {
boolean isBoxed();
+
boolean isNumeric();
+
boolean isBoolean();
+
TypeMirror unboxedType();
}
@@ -4506,40 +4449,43 @@ public class CFGBuilder {
/* --------------------------------------------------------- */
/**
- * Print a set of {@link Block}s and the edges between them. This is useful
- * for examining the results of phase two.
+ * Print a set of {@link Block}s and the edges between them. This is useful for examining the
+ * results of phase two.
*/
protected static void printBlocks(Set<Block> blocks) {
for (Block b : blocks) {
System.out.print(b.hashCode() + ": " + b);
switch (b.getType()) {
- case REGULAR_BLOCK:
- case SPECIAL_BLOCK: {
- Block succ = ((SingleSuccessorBlockImpl) b).getSuccessor();
- System.out.println(" -> "
- + (succ != null ? succ.hashCode() : "||"));
- break;
- }
- case EXCEPTION_BLOCK: {
- Block succ = ((SingleSuccessorBlockImpl) b).getSuccessor();
- System.out.print(" -> "
- + (succ != null ? succ.hashCode() : "||") + " {");
- for (Map.Entry<TypeMirror, Set<Block>> entry : ((ExceptionBlockImpl) b).getExceptionalSuccessors().entrySet()) {
- System.out.print(entry.getKey() + " : " + entry.getValue() + ", ");
- }
- System.out.println("}");
- break;
- }
- case CONDITIONAL_BLOCK: {
- Block tSucc = ((ConditionalBlockImpl) b).getThenSuccessor();
- Block eSucc = ((ConditionalBlockImpl) b).getElseSuccessor();
- System.out.println(" -> T "
- + (tSucc != null ? tSucc.hashCode() : "||") + " F "
- + (eSucc != null ? eSucc.hashCode() : "||"));
- break;
- }
+ case REGULAR_BLOCK:
+ case SPECIAL_BLOCK:
+ {
+ Block succ = ((SingleSuccessorBlockImpl) b).getSuccessor();
+ System.out.println(" -> " + (succ != null ? succ.hashCode() : "||"));
+ break;
+ }
+ case EXCEPTION_BLOCK:
+ {
+ Block succ = ((SingleSuccessorBlockImpl) b).getSuccessor();
+ System.out.print(" -> " + (succ != null ? succ.hashCode() : "||") + " {");
+ for (Map.Entry<TypeMirror, Set<Block>> entry :
+ ((ExceptionBlockImpl) b).getExceptionalSuccessors().entrySet()) {
+ System.out.print(entry.getKey() + " : " + entry.getValue() + ", ");
+ }
+ System.out.println("}");
+ break;
+ }
+ case CONDITIONAL_BLOCK:
+ {
+ Block tSucc = ((ConditionalBlockImpl) b).getThenSuccessor();
+ Block eSucc = ((ConditionalBlockImpl) b).getElseSuccessor();
+ System.out.println(
+ " -> T "
+ + (tSucc != null ? tSucc.hashCode() : "||")
+ + " F "
+ + (eSucc != null ? eSucc.hashCode() : "||"));
+ break;
+ }
}
}
}
}
-
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGDOTVisualizer.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGDOTVisualizer.java
deleted file mode 100644
index abd482122d..0000000000
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGDOTVisualizer.java
+++ /dev/null
@@ -1,304 +0,0 @@
-package org.checkerframework.dataflow.cfg;
-
-/*>>>
-import org.checkerframework.checker.nullness.qual.Nullable;
-*/
-
-import org.checkerframework.dataflow.analysis.AbstractValue;
-import org.checkerframework.dataflow.analysis.Analysis;
-import org.checkerframework.dataflow.analysis.Store;
-import org.checkerframework.dataflow.analysis.TransferFunction;
-import org.checkerframework.dataflow.analysis.TransferInput;
-import org.checkerframework.dataflow.cfg.block.Block;
-import org.checkerframework.dataflow.cfg.block.Block.BlockType;
-import org.checkerframework.dataflow.cfg.block.ConditionalBlock;
-import org.checkerframework.dataflow.cfg.block.ExceptionBlock;
-import org.checkerframework.dataflow.cfg.block.RegularBlock;
-import org.checkerframework.dataflow.cfg.block.SingleSuccessorBlock;
-import org.checkerframework.dataflow.cfg.block.SpecialBlock;
-import org.checkerframework.dataflow.cfg.node.Node;
-
-import javax.lang.model.type.TypeMirror;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Queue;
-import java.util.Set;
-
-/**
- * Generate a graph description in the DOT language of a control graph.
- *
- * @author Stefan Heule
- *
- */
-public class CFGDOTVisualizer {
-
- /**
- * Output a graph description in the DOT language, representing the control
- * flow graph starting at <code>entry</code>. Does not output verbose information
- * or stores at the beginning of basic blocks.
- *
- * @see #visualize(ControlFlowGraph, Block, Analysis, boolean)
- */
- public static String visualize(ControlFlowGraph cfg, Block entry) {
- return visualize(cfg, entry, null, false);
- }
-
- /**
- * Output a graph description in the DOT language, representing the control
- * flow graph starting at <code>entry</code>.
- *
- * @param entry
- * The entry node of the control flow graph to be represented.
- * @param analysis
- * An analysis containing information about the program
- * represented by the CFG. The information includes {@link Store}
- * s that are valid at the beginning of basic blocks reachable
- * from <code>entry</code> and per-node information for value
- * producing {@link Node}s. Can also be <code>null</code> to
- * indicate that this information should not be output.
- * @param verbose
- * Add more output to the CFG description.
- * @return String representation of the graph in the DOT language.
- */
- public static <A extends AbstractValue<A>, S extends Store<S>, T extends TransferFunction<A, S>> String visualize(
- ControlFlowGraph cfg,
- Block entry,
- /*@Nullable*/ Analysis<A, S, T> analysis,
- boolean verbose) {
- StringBuilder sb1 = new StringBuilder();
- StringBuilder sb2 = new StringBuilder();
- Set<Block> visited = new HashSet<>();
- Queue<Block> worklist = new LinkedList<>();
- Block cur = entry;
- visited.add(entry);
-
- // header
- sb1.append("digraph {\n");
- sb1.append(" node [shape=rectangle];\n\n");
-
- // traverse control flow graph and define all arrows
- while (true) {
- if (cur == null)
- break;
-
- if (cur.getType() == BlockType.CONDITIONAL_BLOCK) {
- ConditionalBlock ccur = ((ConditionalBlock) cur);
- Block thenSuccessor = ccur.getThenSuccessor();
- sb2.append(" " + ccur.getId() + " -> "
- + thenSuccessor.getId());
- sb2.append(" [label=\"then\\n" + ccur.getThenFlowRule() + "\"];\n");
- if (!visited.contains(thenSuccessor)) {
- visited.add(thenSuccessor);
- worklist.add(thenSuccessor);
- }
- Block elseSuccessor = ccur.getElseSuccessor();
- sb2.append(" " + ccur.getId() + " -> "
- + elseSuccessor.getId());
- sb2.append(" [label=\"else\\n" + ccur.getElseFlowRule() + "\"];\n");
- if (!visited.contains(elseSuccessor)) {
- visited.add(elseSuccessor);
- worklist.add(elseSuccessor);
- }
- } else {
- assert cur instanceof SingleSuccessorBlock;
- Block b = ((SingleSuccessorBlock) cur).getSuccessor();
- if (b != null) {
- sb2.append(" " + cur.getId() + " -> " + b.getId());
- sb2.append(" [label=\"" + ((SingleSuccessorBlock) cur).getFlowRule() + "\"];\n");
- if (!visited.contains(b)) {
- visited.add(b);
- worklist.add(b);
- }
- }
- }
-
- // exceptional edges
- if (cur.getType() == BlockType.EXCEPTION_BLOCK) {
- ExceptionBlock ecur = (ExceptionBlock) cur;
- for (Entry<TypeMirror, Set<Block>> e : ecur
- .getExceptionalSuccessors().entrySet()) {
- Set<Block> blocks = e.getValue();
- TypeMirror cause = e.getKey();
- String exception = cause.toString();
- if (exception.startsWith("java.lang.")) {
- exception = exception.replace("java.lang.", "");
- }
-
- for (Block b : blocks) {
- sb2.append(" " + cur.getId() + " -> " + b.getId());
- sb2.append(" [label=\"" + exception + "\"];\n");
- if (!visited.contains(b)) {
- visited.add(b);
- worklist.add(b);
- }
- }
- }
- }
-
- cur = worklist.poll();
- }
-
- IdentityHashMap<Block, List<Integer>> processOrder = getProcessOrder(cfg);
-
- // definition of all nodes including their labels
- for (Block v : visited) {
- sb1.append(" " + v.getId() + " [");
- if (v.getType() == BlockType.CONDITIONAL_BLOCK) {
- sb1.append("shape=polygon sides=8 ");
- } else if (v.getType() == BlockType.SPECIAL_BLOCK) {
- sb1.append("shape=oval ");
- }
- sb1.append("label=\"");
- if (verbose) {
- sb1.append("Process order: " + processOrder.get(v).toString().replaceAll("[\\[\\]]", "") + "\\n");
- }
- sb1.append(visualizeContent(v, analysis, verbose).replace("\\n", "\\l")
- + " \",];\n");
- }
-
- sb1.append("\n");
- sb1.append(sb2);
-
- // footer
- sb1.append("}\n");
-
- return sb1.toString();
- }
-
- private static IdentityHashMap<Block, List<Integer>> getProcessOrder(ControlFlowGraph cfg) {
- IdentityHashMap<Block, List<Integer>> depthFirstOrder = new IdentityHashMap<>();
- int count = 1;
- for (Block b : cfg.getDepthFirstOrderedBlocks()) {
- if (depthFirstOrder.get(b) == null) {
- depthFirstOrder.put(b, new ArrayList<Integer>());
- }
- depthFirstOrder.get(b).add(count++);
- }
- return depthFirstOrder;
- }
-
- /**
- * Produce a string representation of the contests of a basic block.
- *
- * @param bb
- * Basic block to visualize.
- * @return String representation.
- */
- protected static <A extends AbstractValue<A>, S extends Store<S>, T extends TransferFunction<A, S>> String visualizeContent(
- Block bb,
- /*@Nullable*/ Analysis<A, S, T> analysis,
- boolean verbose) {
-
- StringBuilder sb = new StringBuilder();
-
- // loop over contents
- List<Node> contents = new LinkedList<>();
- switch (bb.getType()) {
- case REGULAR_BLOCK:
- contents.addAll(((RegularBlock) bb).getContents());
- break;
- case EXCEPTION_BLOCK:
- contents.add(((ExceptionBlock) bb).getNode());
- break;
- case CONDITIONAL_BLOCK:
- break;
- case SPECIAL_BLOCK:
- break;
- default:
- assert false : "All types of basic blocks covered";
- }
- boolean notFirst = false;
- for (Node t : contents) {
- if (notFirst) {
- sb.append("\\n");
- }
- notFirst = true;
- sb.append(prepareString(visualizeNode(t, analysis)));
- }
-
- // handle case where no contents are present
- boolean centered = false;
- if (sb.length() == 0) {
- centered = true;
- if (bb.getType() == BlockType.SPECIAL_BLOCK) {
- SpecialBlock sbb = (SpecialBlock) bb;
- switch (sbb.getSpecialType()) {
- case ENTRY:
- sb.append("<entry>");
- break;
- case EXIT:
- sb.append("<exit>");
- break;
- case EXCEPTIONAL_EXIT:
- sb.append("<exceptional-exit>");
- break;
- }
- } else if (bb.getType() == BlockType.CONDITIONAL_BLOCK) {
- return "";
- } else {
- return "?? empty ??";
- }
- }
-
- // visualize transfer input if necessary
- if (analysis != null) {
- TransferInput<A, S> input = analysis.getInput(bb);
- StringBuilder sb2 = new StringBuilder();
-
- // split input representation to two lines
- String s = input.toDOToutput().replace("}, else={", "}\\nelse={");
- sb2.append("Before:");
- sb2.append(s.subSequence(1, s.length() - 1));
-
- // separator
- sb2.append("\\n~~~~~~~~~\\n");
- sb2.append(sb);
- sb = sb2;
-
- if (verbose) {
- Node lastNode = null;
- switch (bb.getType()) {
- case REGULAR_BLOCK:
- List<Node> blockContents = ((RegularBlock) bb).getContents();
- lastNode = contents.get(blockContents.size() - 1);
- break;
- case EXCEPTION_BLOCK:
- lastNode = ((ExceptionBlock) bb).getNode();
- break;
- }
- if (lastNode != null) {
- sb2.append("\\n~~~~~~~~~\\n");
- s = analysis.getResult().getStoreAfter(lastNode.getTree()).
- toDOToutput().replace("}, else={", "}\\nelse={");
- sb2.append("After:");
- sb2.append(s);
- }
- }
- }
-
- return sb.toString() + (centered ? "" : "\\n");
- }
-
- protected static <A extends AbstractValue<A>, S extends Store<S>, T extends TransferFunction<A, S>>
- String visualizeNode(Node t, /*@Nullable*/ Analysis<A, S, T> analysis) {
- A value = analysis.getValue(t);
- String valueInfo = "";
- if (value != null) {
- valueInfo = " > " + value.toString();
- }
- return t.toString() + " [ " + visualizeType(t) + " ]" + valueInfo;
- }
-
- protected static String visualizeType(Node t) {
- String name = t.getClass().getSimpleName();
- return name.replace("Node", "");
- }
-
- protected static String prepareString(String s) {
- return s.replace("\"", "\\\"");
- }
-}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGVisualizer.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGVisualizer.java
new file mode 100644
index 0000000000..9378d83726
--- /dev/null
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/CFGVisualizer.java
@@ -0,0 +1,167 @@
+package org.checkerframework.dataflow.cfg;
+
+/*>>>
+import org.checkerframework.checker.nullness.qual.Nullable;
+*/
+
+import java.util.Map;
+import org.checkerframework.dataflow.analysis.AbstractValue;
+import org.checkerframework.dataflow.analysis.Analysis;
+import org.checkerframework.dataflow.analysis.FlowExpressions;
+import org.checkerframework.dataflow.analysis.Store;
+import org.checkerframework.dataflow.analysis.TransferFunction;
+import org.checkerframework.dataflow.cfg.block.Block;
+import org.checkerframework.dataflow.cfg.block.SpecialBlock;
+import org.checkerframework.dataflow.cfg.node.Node;
+
+/**
+ * Perform some visualization on a control flow graph. The particular operations depend on the
+ * implementation.
+ */
+public interface CFGVisualizer<
+ A extends AbstractValue<A>, S extends Store<S>, T extends TransferFunction<A, S>> {
+ /**
+ * Initialization method guaranteed to be called once before the first invocation of {@link
+ * visualize}.
+ *
+ * @param args implementation-dependent options
+ */
+ void init(Map<String, Object> args);
+
+ /**
+ * Output a visualization representing the control flow graph starting at {@code entry}. The
+ * concrete actions are implementation dependent.
+ *
+ * <p>An invocation {@code visualize(cfg, entry, null);} does not output stores at the beginning
+ * of basic blocks.
+ *
+ * @param cfg the CFG to visualize
+ * @param entry the entry node of the control flow graph to be represented
+ * @param analysis an analysis containing information about the program represented by the CFG.
+ * The information includes {@link Store}s that are valid at the beginning of basic blocks
+ * reachable from {@code entry} and per-node information for value producing {@link Node}s.
+ * Can also be {@code null} to indicate that this information should not be output.
+ * @return possible analysis results, e.g. generated file names.
+ */
+ /*@Nullable*/ Map<String, Object> visualize(
+ ControlFlowGraph cfg, Block entry, /*@Nullable*/ Analysis<A, S, T> analysis);
+
+ /**
+ * Delegate the visualization responsibility to the passed {@link Store} instance, which will
+ * call back to this visualizer instance for sub-components.
+ *
+ * @param store the store to visualize
+ */
+ void visualizeStore(S store);
+
+ /**
+ * Called by a {@code CFAbstractStore} to visualize the class name before calling the {@code
+ * CFAbstractStore#internalVisualize()} method.
+ *
+ * @param classCanonicalName the canonical name of the class
+ */
+ void visualizeStoreHeader(String classCanonicalName);
+
+ /**
+ * Called by {@code CFAbstractStore#internalVisualize()} to visualize a local variable.
+ *
+ * @param localVar the local variable
+ * @param value the value of the local variable
+ */
+ void visualizeStoreLocalVar(FlowExpressions.LocalVariable localVar, A value);
+
+ /**
+ * Called by {@code CFAbstractStore#internalVisualize()} to visualize the value of the current
+ * object {@code this} in this Store.
+ *
+ * @param value the value of the current object this
+ */
+ void visualizeStoreThisVal(A value);
+
+ /**
+ * Called by {@code CFAbstractStore#internalVisualize()} to visualize the value of fields
+ * collected by this Store.
+ *
+ * @param fieldAccess the field
+ * @param value the value of the field
+ */
+ void visualizeStoreFieldVals(FlowExpressions.FieldAccess fieldAccess, A value);
+
+ /**
+ * Called by {@code CFAbstractStore#internalVisualize()} to visualize the value of arrays
+ * collected by this Store.
+ *
+ * @param arrayValue the array
+ * @param value the value of the array
+ */
+ void visualizeStoreArrayVal(FlowExpressions.ArrayAccess arrayValue, A value);
+
+ /**
+ * Called by {@code CFAbstractStore#internalVisualize()} to visualize the value of pure method
+ * calls collected by this Store.
+ *
+ * @param methodCall the pure method call
+ * @param value the value of the pure method call
+ */
+ void visualizeStoreMethodVals(FlowExpressions.MethodCall methodCall, A value);
+
+ /**
+ * Called by {@code CFAbstractStore#internalVisualize()} to visualize the value of class names
+ * collected by this Store.
+ *
+ * @param className the class name
+ * @param value the value of the class name
+ */
+ void visualizeStoreClassVals(FlowExpressions.ClassName className, A value);
+
+ /**
+ * Called by {@code CFAbstractStore#internalVisualize()} to visualize the specific information
+ * collected according to the specific kind of Store. Currently, these Stores call this method:
+ * {@code LockStore}, {@code NullnessStore}, and {@code InitializationStore} to visualize
+ * additional information.
+ *
+ * @param keyName the name of the specific information to be visualized
+ * @param value the value of the specific information to be visualized
+ */
+ void visualizeStoreKeyVal(String keyName, Object value);
+
+ /**
+ * Called by {@code CFAbstractStore} to visualize any information after the invocation of {@code
+ * CFAbstractStore#internalVisualize()}.
+ */
+ void visualizeStoreFooter();
+
+ /**
+ * Visualize a block based on the analysis.
+ *
+ * @param bb the block
+ * @param analysis the current analysis
+ */
+ void visualizeBlock(Block bb, /*@Nullable*/ Analysis<A, S, T> analysis);
+
+ /**
+ * Visualize a SpecialBlock.
+ *
+ * @param sbb the special block
+ */
+ void visualizeSpecialBlock(SpecialBlock sbb);
+
+ /**
+ * Visualize the transferInput of a Block based on the analysis.
+ *
+ * @param bb the block
+ * @param analysis the current analysis
+ */
+ void visualizeBlockTransferInput(Block bb, Analysis<A, S, T> analysis);
+
+ /**
+ * Visualize a Node based on the analysis.
+ *
+ * @param t the node
+ * @param analysis the current analysis
+ */
+ void visualizeBlockNode(Node t, /*@Nullable*/ Analysis<A, S, T> analysis);
+
+ /** Shutdown method called once from the shutdown hook of the {@code BaseTypeChecker}. */
+ void shutdown();
+}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/ControlFlowGraph.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/ControlFlowGraph.java
index 759d2616d0..0a2687aec2 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/ControlFlowGraph.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/ControlFlowGraph.java
@@ -7,6 +7,14 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.Set;
import org.checkerframework.dataflow.cfg.block.Block;
import org.checkerframework.dataflow.cfg.block.Block.BlockType;
import org.checkerframework.dataflow.cfg.block.ConditionalBlock;
@@ -17,20 +25,10 @@ import org.checkerframework.dataflow.cfg.block.SpecialBlockImpl;
import org.checkerframework.dataflow.cfg.node.Node;
import org.checkerframework.dataflow.cfg.node.ReturnNode;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Queue;
-import java.util.Set;
-
/**
* A control flow graph (CFG for short) of a single method.
*
* @author Stefan Heule
- *
*/
public class ControlFlowGraph {
@@ -47,12 +45,10 @@ public class ControlFlowGraph {
protected UnderlyingAST underlyingAST;
/**
- * Maps from AST {@link Tree}s to {@link Node}s. Every Tree that produces
- * a value will have at least one corresponding Node. Trees
- * that undergo conversions, such as boxing or unboxing, can map to two
- * distinct Nodes. The Node for the pre-conversion value is stored
- * in treeLookup, while the Node for the post-conversion value
- * is stored in convertedTreeLookup.
+ * Maps from AST {@link Tree}s to {@link Node}s. Every Tree that produces a value will have at
+ * least one corresponding Node. Trees that undergo conversions, such as boxing or unboxing, can
+ * map to two distinct Nodes. The Node for the pre-conversion value is stored in treeLookup,
+ * while the Node for the post-conversion value is stored in convertedTreeLookup.
*/
protected IdentityHashMap<Tree, Node> treeLookup;
@@ -60,12 +56,16 @@ public class ControlFlowGraph {
protected IdentityHashMap<Tree, Node> convertedTreeLookup;
/**
- * All return nodes (if any) encountered. Only includes return
- * statements that actually return something
+ * All return nodes (if any) encountered. Only includes return statements that actually return
+ * something
*/
protected final List<ReturnNode> returnNodes;
- public ControlFlowGraph(SpecialBlock entryBlock, SpecialBlockImpl regularExitBlock, SpecialBlockImpl exceptionalExitBlock, UnderlyingAST underlyingAST,
+ public ControlFlowGraph(
+ SpecialBlock entryBlock,
+ SpecialBlockImpl regularExitBlock,
+ SpecialBlockImpl exceptionalExitBlock,
+ UnderlyingAST underlyingAST,
IdentityHashMap<Tree, Node> treeLookup,
IdentityHashMap<Tree, Node> convertedTreeLookup,
List<ReturnNode> returnNodes) {
@@ -79,10 +79,7 @@ public class ControlFlowGraph {
this.returnNodes = returnNodes;
}
- /**
- * @return The {@link Node} to which the {@link Tree} <code>t</code>
- * corresponds.
- */
+ /** @return the {@link Node} to which the {@link Tree} {@code t} corresponds. */
public Node getNodeCorrespondingToTree(Tree t) {
if (convertedTreeLookup.containsKey(t)) {
return convertedTreeLookup.get(t);
@@ -91,7 +88,7 @@ public class ControlFlowGraph {
}
}
- /** @return The entry block of the control flow graph. */
+ /** @return the entry block of the control flow graph. */
public SpecialBlock getEntryBlock() {
return entryBlock;
}
@@ -108,14 +105,12 @@ public class ControlFlowGraph {
return exceptionalExitBlock;
}
- /** @return The AST this CFG corresponds to. */
+ /** @return the AST this CFG corresponds to. */
public UnderlyingAST getUnderlyingAST() {
return underlyingAST;
}
- /**
- * @return The set of all basic block in this control flow graph.
- */
+ /** @return the set of all basic block in this control flow graph */
public Set<Block> getAllBlocks() {
Set<Block> visited = new HashSet<>();
Queue<Block> worklist = new LinkedList<>();
@@ -124,8 +119,9 @@ public class ControlFlowGraph {
// traverse the whole control flow graph
while (true) {
- if (cur == null)
+ if (cur == null) {
break;
+ }
Queue<Block> succs = new LinkedList<>();
if (cur.getType() == BlockType.CONDITIONAL_BLOCK) {
@@ -161,10 +157,9 @@ public class ControlFlowGraph {
}
/**
- * @return The list of all basic block in this control flow graph
- * in reversed depth-first postorder sequence.
- *
- * Blocks may appear more than once in the sequence.
+ * @return the list of all basic block in this control flow graph in reversed depth-first
+ * postorder sequence.
+ * <p>Blocks may appear more than once in the sequence.
*/
public List<Block> getDepthFirstOrderedBlocks() {
List<Block> dfsOrderResult = new LinkedList<>();
@@ -190,8 +185,8 @@ public class ControlFlowGraph {
/**
* Get a list of all successor Blocks for cur
- * @param cur
- * @return A Deque of successor Blocks
+ *
+ * @return a Deque of successor Blocks
*/
private Deque<Block> getSuccessors(Block cur) {
Deque<Block> succs = new LinkedList<>();
@@ -216,16 +211,14 @@ public class ControlFlowGraph {
return succs;
}
- /**
- * @return The tree-lookup map.
- */
+ /** @return the tree-lookup map */
public IdentityHashMap<Tree, Node> getTreeLookup() {
return new IdentityHashMap<>(treeLookup);
}
/**
- * Get the {@link MethodTree} of the CFG if the argument {@link Tree} maps
- * to a {@link Node} in the CFG or null otherwise.
+ * Get the {@link MethodTree} of the CFG if the argument {@link Tree} maps to a {@link Node} in
+ * the CFG or null otherwise.
*/
public /*@Nullable*/ MethodTree getContainingMethod(Tree t) {
if (treeLookup.containsKey(t)) {
@@ -238,8 +231,8 @@ public class ControlFlowGraph {
}
/**
- * Get the {@link ClassTree} of the CFG if the argument {@link Tree} maps
- * to a {@link Node} in the CFG or null otherwise.
+ * Get the {@link ClassTree} of the CFG if the argument {@link Tree} maps to a {@link Node} in
+ * the CFG or null otherwise.
*/
public /*@Nullable*/ ClassTree getContainingClass(Tree t) {
if (treeLookup.containsKey(t)) {
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/DOTCFGVisualizer.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/DOTCFGVisualizer.java
new file mode 100644
index 0000000000..1eb1cb87a2
--- /dev/null
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/DOTCFGVisualizer.java
@@ -0,0 +1,511 @@
+package org.checkerframework.dataflow.cfg;
+
+/*>>>
+import org.checkerframework.checker.nullness.qual.Nullable;
+*/
+
+import com.sun.tools.javac.tree.JCTree;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Queue;
+import java.util.Set;
+import javax.lang.model.type.TypeMirror;
+import org.checkerframework.dataflow.analysis.AbstractValue;
+import org.checkerframework.dataflow.analysis.Analysis;
+import org.checkerframework.dataflow.analysis.FlowExpressions;
+import org.checkerframework.dataflow.analysis.Store;
+import org.checkerframework.dataflow.analysis.TransferFunction;
+import org.checkerframework.dataflow.analysis.TransferInput;
+import org.checkerframework.dataflow.cfg.UnderlyingAST.CFGMethod;
+import org.checkerframework.dataflow.cfg.UnderlyingAST.CFGStatement;
+import org.checkerframework.dataflow.cfg.block.Block;
+import org.checkerframework.dataflow.cfg.block.Block.BlockType;
+import org.checkerframework.dataflow.cfg.block.ConditionalBlock;
+import org.checkerframework.dataflow.cfg.block.ExceptionBlock;
+import org.checkerframework.dataflow.cfg.block.RegularBlock;
+import org.checkerframework.dataflow.cfg.block.SingleSuccessorBlock;
+import org.checkerframework.dataflow.cfg.block.SpecialBlock;
+import org.checkerframework.dataflow.cfg.node.Node;
+import org.checkerframework.javacutil.ErrorReporter;
+
+/**
+ * Generate a graph description in the DOT language of a control graph.
+ *
+ * @author Stefan Heule
+ */
+public class DOTCFGVisualizer<
+ A extends AbstractValue<A>, S extends Store<S>, T extends TransferFunction<A, S>>
+ implements CFGVisualizer<A, S, T> {
+
+ protected String outdir;
+ protected boolean verbose;
+ protected String checkerName;
+
+ protected StringBuilder sbDigraph;
+ protected StringBuilder sbStore;
+ protected StringBuilder sbBlock;
+
+ /** Mapping from class/method representation to generated dot file. */
+ protected Map<String, String> generated;
+
+ @Override
+ public void init(Map<String, Object> args) {
+ this.outdir = (String) args.get("outdir");
+ {
+ Object verb = args.get("verbose");
+ this.verbose =
+ verb == null
+ ? false
+ : verb instanceof String
+ ? Boolean.getBoolean((String) verb)
+ : (boolean) verb;
+ }
+ this.checkerName = (String) args.get("checkerName");
+
+ this.generated = new HashMap<>();
+
+ this.sbDigraph = new StringBuilder();
+
+ this.sbStore = new StringBuilder();
+
+ this.sbBlock = new StringBuilder();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public /*@Nullable*/ Map<String, Object> visualize(
+ ControlFlowGraph cfg, Block entry, /*@Nullable*/ Analysis<A, S, T> analysis) {
+
+ String dotgraph = generateDotGraph(cfg, entry, analysis);
+
+ String dotfilename = dotOutputFileName(cfg.underlyingAST);
+ // System.err.println("Output to DOT file: " + dotfilename);
+
+ try {
+ FileWriter fstream = new FileWriter(dotfilename);
+ BufferedWriter out = new BufferedWriter(fstream);
+ out.write(dotgraph);
+ out.close();
+ } catch (IOException e) {
+ ErrorReporter.errorAbort(
+ "Error creating dot file: " + dotfilename + "; ensure the path is valid", e);
+ }
+
+ Map<String, Object> res = new HashMap<>();
+ res.put("dotFileName", dotfilename);
+
+ return res;
+ }
+
+ /** Generate the dot representation as String. */
+ protected String generateDotGraph(
+ ControlFlowGraph cfg, Block entry, /*@Nullable*/ Analysis<A, S, T> analysis) {
+ this.sbDigraph.setLength(0);
+ Set<Block> visited = new HashSet<>();
+
+ // header
+ this.sbDigraph.append("digraph {\n");
+
+ Block cur = entry;
+ Queue<Block> worklist = new LinkedList<>();
+ visited.add(entry);
+ // traverse control flow graph and define all arrows
+ while (true) {
+ if (cur == null) {
+ break;
+ }
+
+ if (cur.getType() == BlockType.CONDITIONAL_BLOCK) {
+ ConditionalBlock ccur = ((ConditionalBlock) cur);
+ Block thenSuccessor = ccur.getThenSuccessor();
+ addDotEdge(ccur.getId(), thenSuccessor.getId(), "then\\n" + ccur.getThenFlowRule());
+ if (!visited.contains(thenSuccessor)) {
+ visited.add(thenSuccessor);
+ worklist.add(thenSuccessor);
+ }
+ Block elseSuccessor = ccur.getElseSuccessor();
+ addDotEdge(ccur.getId(), elseSuccessor.getId(), "else\\n" + ccur.getElseFlowRule());
+ if (!visited.contains(elseSuccessor)) {
+ visited.add(elseSuccessor);
+ worklist.add(elseSuccessor);
+ }
+ } else {
+ assert cur instanceof SingleSuccessorBlock;
+ Block b = ((SingleSuccessorBlock) cur).getSuccessor();
+ if (b != null) {
+ addDotEdge(
+ cur.getId(),
+ b.getId(),
+ ((SingleSuccessorBlock) cur).getFlowRule().name());
+ if (!visited.contains(b)) {
+ visited.add(b);
+ worklist.add(b);
+ }
+ }
+ }
+
+ // exceptional edges
+ if (cur.getType() == BlockType.EXCEPTION_BLOCK) {
+ ExceptionBlock ecur = (ExceptionBlock) cur;
+ for (Entry<TypeMirror, Set<Block>> e : ecur.getExceptionalSuccessors().entrySet()) {
+ Set<Block> blocks = e.getValue();
+ TypeMirror cause = e.getKey();
+ String exception = cause.toString();
+ if (exception.startsWith("java.lang.")) {
+ exception = exception.replace("java.lang.", "");
+ }
+
+ for (Block b : blocks) {
+ addDotEdge(cur.getId(), b.getId(), exception);
+ if (!visited.contains(b)) {
+ visited.add(b);
+ worklist.add(b);
+ }
+ }
+ }
+ }
+
+ cur = worklist.poll();
+ }
+
+ generateDotNodes(visited, cfg, analysis);
+
+ // footer
+ this.sbDigraph.append("}\n");
+
+ return this.sbDigraph.toString();
+ }
+
+ protected void generateDotNodes(
+ Set<Block> visited, ControlFlowGraph cfg, /*@Nullable*/ Analysis<A, S, T> analysis) {
+ IdentityHashMap<Block, List<Integer>> processOrder = getProcessOrder(cfg);
+ this.sbDigraph.append(" node [shape=rectangle];\n\n");
+ // definition of all nodes including their labels
+ for (Block v : visited) {
+ this.sbDigraph.append(" " + v.getId() + " [");
+ if (v.getType() == BlockType.CONDITIONAL_BLOCK) {
+ this.sbDigraph.append("shape=polygon sides=8 ");
+ } else if (v.getType() == BlockType.SPECIAL_BLOCK) {
+ this.sbDigraph.append("shape=oval ");
+ }
+ this.sbDigraph.append("label=\"");
+ if (verbose) {
+ this.sbDigraph.append(
+ "Process order: "
+ + processOrder.get(v).toString().replaceAll("[\\[\\]]", "")
+ + "\\n");
+ }
+ visualizeBlock(v, analysis);
+ }
+
+ this.sbDigraph.append("\n");
+ }
+
+ /** @return the file name used for DOT output. */
+ protected String dotOutputFileName(UnderlyingAST ast) {
+ StringBuilder srcloc = new StringBuilder();
+
+ StringBuilder outfile = new StringBuilder(outdir);
+ outfile.append('/');
+ if (ast.getKind() == UnderlyingAST.Kind.ARBITRARY_CODE) {
+ CFGStatement cfgs = (CFGStatement) ast;
+ String clsname = cfgs.getClassTree().getSimpleName().toString();
+ outfile.append(clsname);
+ outfile.append("-initializer-");
+ outfile.append(ast.hashCode());
+
+ srcloc.append('<');
+ srcloc.append(clsname);
+ srcloc.append("::initializer::");
+ srcloc.append(((JCTree) cfgs.getCode()).pos);
+ srcloc.append('>');
+ } else if (ast.getKind() == UnderlyingAST.Kind.METHOD) {
+ CFGMethod cfgm = (CFGMethod) ast;
+ String clsname = cfgm.getClassTree().getSimpleName().toString();
+ String methname = cfgm.getMethod().getName().toString();
+ outfile.append(clsname);
+ outfile.append('-');
+ outfile.append(methname);
+
+ srcloc.append('<');
+ srcloc.append(clsname);
+ srcloc.append("::");
+ srcloc.append(methname);
+ srcloc.append('(');
+ srcloc.append(cfgm.getMethod().getParameters());
+ srcloc.append(")::");
+ srcloc.append(((JCTree) cfgm.getMethod()).pos);
+ srcloc.append('>');
+ } else {
+ ErrorReporter.errorAbort(
+ "Unexpected AST kind: " + ast.getKind() + " value: " + ast.toString());
+ return null;
+ }
+ outfile.append('-');
+ outfile.append(checkerName);
+ outfile.append(".dot");
+
+ // make path safe for Windows
+ String out = outfile.toString().replace("<", "_").replace(">", "");
+
+ generated.put(srcloc.toString(), out);
+
+ return out;
+ }
+
+ protected IdentityHashMap<Block, List<Integer>> getProcessOrder(ControlFlowGraph cfg) {
+ IdentityHashMap<Block, List<Integer>> depthFirstOrder = new IdentityHashMap<>();
+ int count = 1;
+ for (Block b : cfg.getDepthFirstOrderedBlocks()) {
+ if (depthFirstOrder.get(b) == null) {
+ depthFirstOrder.put(b, new ArrayList<Integer>());
+ }
+ depthFirstOrder.get(b).add(count++);
+ }
+ return depthFirstOrder;
+ }
+
+ /**
+ * Produce a representation of the contests of a basic block.
+ *
+ * @param bb basic block to visualize
+ */
+ @Override
+ public void visualizeBlock(Block bb, /*@Nullable*/ Analysis<A, S, T> analysis) {
+
+ this.sbBlock.setLength(0);
+
+ // loop over contents
+ List<Node> contents = new LinkedList<>();
+ switch (bb.getType()) {
+ case REGULAR_BLOCK:
+ contents.addAll(((RegularBlock) bb).getContents());
+ break;
+ case EXCEPTION_BLOCK:
+ contents.add(((ExceptionBlock) bb).getNode());
+ break;
+ case CONDITIONAL_BLOCK:
+ break;
+ case SPECIAL_BLOCK:
+ break;
+ default:
+ assert false : "All types of basic blocks covered";
+ }
+ boolean notFirst = false;
+ for (Node t : contents) {
+ if (notFirst) {
+ this.sbBlock.append("\\n");
+ }
+ notFirst = true;
+ visualizeBlockNode(t, analysis);
+ }
+
+ // handle case where no contents are present
+ boolean centered = false;
+ if (this.sbBlock.length() == 0) {
+ centered = true;
+ if (bb.getType() == BlockType.SPECIAL_BLOCK) {
+ visualizeSpecialBlock((SpecialBlock) bb);
+ } else if (bb.getType() == BlockType.CONDITIONAL_BLOCK) {
+ this.sbDigraph.append(" \",];\n");
+ return;
+ } else {
+ this.sbDigraph.append("?? empty ?? \",];\n");
+ return;
+ }
+ }
+
+ // visualize transfer input if necessary
+ if (analysis != null) {
+ visualizeBlockTransferInput(bb, analysis);
+ }
+
+ this.sbDigraph.append(
+ (this.sbBlock.toString() + (centered ? "" : "\\n")).replace("\\n", "\\l")
+ + " \",];\n");
+ }
+
+ @Override
+ public void visualizeSpecialBlock(SpecialBlock sbb) {
+ switch (sbb.getSpecialType()) {
+ case ENTRY:
+ this.sbBlock.append("<entry>");
+ break;
+ case EXIT:
+ this.sbBlock.append("<exit>");
+ break;
+ case EXCEPTIONAL_EXIT:
+ this.sbBlock.append("<exceptional-exit>");
+ break;
+ }
+ }
+
+ @Override
+ public void visualizeBlockTransferInput(Block bb, Analysis<A, S, T> analysis) {
+ assert analysis != null
+ : "analysis should be non-null when visualizing the transfer input of a block.";
+
+ TransferInput<A, S> input = analysis.getInput(bb);
+ this.sbStore.setLength(0);
+
+ // split input representation to two lines
+ this.sbStore.append("Before:");
+ S thenStore = input.getThenStore();
+ if (!input.containsTwoStores()) {
+ S regularStore = input.getRegularStore();
+ this.sbStore.append('[');
+ visualizeStore(regularStore);
+ this.sbStore.append(']');
+ } else {
+ S elseStore = input.getElseStore();
+ this.sbStore.append("[then=");
+ visualizeStore(thenStore);
+ this.sbStore.append(", else=");
+ visualizeStore(elseStore);
+ this.sbStore.append("]");
+ }
+ // separator
+ this.sbStore.append("\\n~~~~~~~~~\\n");
+
+ // the transfer input before this block is added before the block content
+ this.sbBlock.insert(0, this.sbStore);
+
+ if (verbose) {
+ Node lastNode;
+ switch (bb.getType()) {
+ case REGULAR_BLOCK:
+ List<Node> blockContents = ((RegularBlock) bb).getContents();
+ lastNode = blockContents.get(blockContents.size() - 1);
+ break;
+ case EXCEPTION_BLOCK:
+ lastNode = ((ExceptionBlock) bb).getNode();
+ break;
+ default:
+ lastNode = null;
+ }
+ if (lastNode != null) {
+ this.sbStore.setLength(0);
+ this.sbStore.append("\\n~~~~~~~~~\\n");
+ this.sbStore.append("After:");
+ visualizeStore(analysis.getResult().getStoreAfter(lastNode));
+ this.sbBlock.append(this.sbStore);
+ }
+ }
+ }
+
+ @Override
+ public void visualizeBlockNode(Node t, /*@Nullable*/ Analysis<A, S, T> analysis) {
+ this.sbBlock.append(prepareString(t.toString()) + " [ " + prepareNodeType(t) + " ]");
+ if (analysis != null) {
+ A value = analysis.getValue(t);
+ if (value != null) {
+ this.sbBlock.append(" > " + prepareString(value.toString()));
+ }
+ }
+ }
+
+ protected String prepareNodeType(Node t) {
+ String name = t.getClass().getSimpleName();
+ return name.replace("Node", "");
+ }
+
+ protected String prepareString(String s) {
+ return s.replace("\"", "\\\"");
+ }
+
+ protected void addDotEdge(long sId, long eId, String labelContent) {
+ this.sbDigraph.append(" " + sId + " -> " + eId + " [label=\"" + labelContent + "\"];\n");
+ }
+
+ @Override
+ public void visualizeStore(S store) {
+ store.visualize(this);
+ }
+
+ @Override
+ public void visualizeStoreThisVal(A value) {
+ this.sbStore.append(" this > " + value + "\\n");
+ }
+
+ @Override
+ public void visualizeStoreLocalVar(FlowExpressions.LocalVariable localVar, A value) {
+ this.sbStore.append(" " + localVar + " > " + toStringEscapeDoubleQuotes(value) + "\\n");
+ }
+
+ @Override
+ public void visualizeStoreFieldVals(FlowExpressions.FieldAccess fieldAccess, A value) {
+ this.sbStore.append(" " + fieldAccess + " > " + toStringEscapeDoubleQuotes(value) + "\\n");
+ }
+
+ @Override
+ public void visualizeStoreArrayVal(FlowExpressions.ArrayAccess arrayValue, A value) {
+ this.sbStore.append(" " + arrayValue + " > " + toStringEscapeDoubleQuotes(value) + "\\n");
+ }
+
+ @Override
+ public void visualizeStoreMethodVals(FlowExpressions.MethodCall methodCall, A value) {
+ this.sbStore.append(
+ " " + methodCall.toString().replace("\"", "\\\"") + " > " + value + "\\n");
+ }
+
+ @Override
+ public void visualizeStoreClassVals(FlowExpressions.ClassName className, A value) {
+ this.sbStore.append(" " + className + " > " + toStringEscapeDoubleQuotes(value) + "\\n");
+ }
+
+ @Override
+ public void visualizeStoreKeyVal(String keyName, Object value) {
+ this.sbStore.append(" " + keyName + " = " + value + "\\n");
+ }
+
+ protected String escapeDoubleQuotes(final String str) {
+ return str.replace("\"", "\\\"");
+ }
+
+ protected String toStringEscapeDoubleQuotes(final Object obj) {
+ return escapeDoubleQuotes(String.valueOf(obj));
+ }
+
+ @Override
+ public void visualizeStoreHeader(String classCanonicalName) {
+ this.sbStore.append(classCanonicalName + " (\\n");
+ }
+
+ @Override
+ public void visualizeStoreFooter() {
+ this.sbStore.append(")");
+ }
+
+ /**
+ * Write a file {@code methods.txt} that contains a mapping from source code location to
+ * generated dot file.
+ */
+ @Override
+ public void shutdown() {
+ try {
+ // Open for append, in case of multiple sub-checkers.
+ FileWriter fstream = new FileWriter(outdir + "/methods.txt", true);
+ BufferedWriter out = new BufferedWriter(fstream);
+ for (Map.Entry<String, String> kv : generated.entrySet()) {
+ out.write(kv.getKey());
+ out.append('\t');
+ out.write(kv.getValue());
+ out.append('\n');
+ }
+ out.close();
+ } catch (IOException e) {
+ ErrorReporter.errorAbort(
+ "Error creating methods.txt file in: " + outdir + "; ensure the path is valid",
+ e);
+ }
+ }
+}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/JavaSource2CFGDOT.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/JavaSource2CFGDOT.java
index 8d5ee1c130..fa6ff55dc5 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/JavaSource2CFGDOT.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/JavaSource2CFGDOT.java
@@ -4,38 +4,34 @@ package org.checkerframework.dataflow.cfg;
import org.checkerframework.checker.nullness.qual.Nullable;
*/
-import org.checkerframework.dataflow.analysis.AbstractValue;
-import org.checkerframework.dataflow.analysis.Analysis;
-import org.checkerframework.dataflow.analysis.Store;
-import org.checkerframework.dataflow.analysis.TransferFunction;
-
-import org.checkerframework.javacutil.BasicTypeProcessor;
-import org.checkerframework.javacutil.TreeUtils;
-
-import java.io.BufferedWriter;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.util.TreePathScanner;
+import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.main.JavaCompiler;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Options;
import java.io.File;
-import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Map.Entry;
-
import javax.lang.model.element.ExecutableElement;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.xml.ws.Holder;
-
-import com.sun.source.tree.CompilationUnitTree;
-import com.sun.source.tree.MethodTree;
-import com.sun.source.util.TreePathScanner;
-import com.sun.tools.javac.file.JavacFileManager;
-import com.sun.tools.javac.main.JavaCompiler;
-import com.sun.tools.javac.util.Context;
-import com.sun.tools.javac.util.List;
+import org.checkerframework.dataflow.analysis.AbstractValue;
+import org.checkerframework.dataflow.analysis.Analysis;
+import org.checkerframework.dataflow.analysis.Store;
+import org.checkerframework.dataflow.analysis.TransferFunction;
+import org.checkerframework.javacutil.BasicTypeProcessor;
+import org.checkerframework.javacutil.TreeUtils;
/**
- * Class to generate the DOT representation of the control flow graph of a given
- * method.
+ * Class to generate the DOT representation of the control flow graph of a given method.
*
* @author Stefan Heule
*/
@@ -79,7 +75,7 @@ public class JavaSource2CFGDOT {
i++;
clas = args[i];
} else {
- printError("Unknown command line argument: " + args[i]);
+ printError("Unknown command-line argument: " + args[i]);
error = true;
}
}
@@ -98,50 +94,56 @@ public class JavaSource2CFGDOT {
/** Print usage information. */
protected static void printUsage() {
- System.out
- .println("Generate the control flow graph of a Java method, represented as a DOT graph.");
- System.out
- .println("Parameters: <inputfile> <outputfile> [-method <name>] [-class <name>] [-pdf]");
- System.out
- .println(" -pdf: Also generate the PDF by invoking 'dot'.");
- System.out
- .println(" -method: The method to generate the CFG for (defaults to 'test').");
- System.out
- .println(" -class: The class in which to find the method (defaults to 'Test').");
+ System.out.println(
+ "Generate the control flow graph of a Java method, represented as a DOT graph.");
+ System.out.println(
+ "Parameters: <inputfile> <outputdir> [-method <name>] [-class <name>] [-pdf]");
+ System.out.println(" -pdf: Also generate the PDF by invoking 'dot'.");
+ System.out.println(" -method: The method to generate the CFG for (defaults to 'test').");
+ System.out.println(
+ " -class: The class in which to find the method (defaults to 'Test').");
}
/** Just like method above but without analysis. */
- public static void generateDOTofCFG(String inputFile, String outputFile,
- String method, String clas, boolean pdf) {
- generateDOTofCFG(inputFile, outputFile, method, clas, pdf, null);
+ public static void generateDOTofCFG(
+ String inputFile, String outputDir, String method, String clas, boolean pdf) {
+ generateDOTofCFG(inputFile, outputDir, method, clas, pdf, null);
}
/**
* Generate the DOT representation of the CFG for a method.
*
- * @param inputFile
- * Java source input file.
- * @param outputFile
- * Source output file (without file extension)
- * @param method
- * Method name to generate the CFG for.
- * @param pdf
- * Also generate a PDF?
- * @param analysis
- * Analysis to perform befor the visualization (or
- * <code>null</code> if no analysis is to be performed).
+ * @param inputFile java source input file
+ * @param outputDir source output directory
+ * @param method method name to generate the CFG for
+ * @param pdf also generate a PDF?
+ * @param analysis analysis to perform befor the visualization (or {@code null} if no analysis
+ * is to be performed).
*/
- public static <A extends AbstractValue<A>, S extends Store<S>, T extends TransferFunction<A, S>> void generateDOTofCFG(
- String inputFile, String outputFile, String method, String clas,
- boolean pdf, /*@Nullable*/ Analysis<A, S, T> analysis) {
- Entry<MethodTree, CompilationUnitTree> m = getMethodTreeAndCompilationUnit(inputFile, method, clas);
- generateDOTofCFG(inputFile, outputFile, method, clas, pdf, analysis, m.getKey(), m.getValue());
+ public static <A extends AbstractValue<A>, S extends Store<S>, T extends TransferFunction<A, S>>
+ void generateDOTofCFG(
+ String inputFile,
+ String outputDir,
+ String method,
+ String clas,
+ boolean pdf,
+ /*@Nullable*/ Analysis<A, S, T> analysis) {
+ Entry<MethodTree, CompilationUnitTree> m =
+ getMethodTreeAndCompilationUnit(inputFile, method, clas);
+ generateDOTofCFG(
+ inputFile, outputDir, method, clas, pdf, analysis, m.getKey(), m.getValue());
}
- public static <A extends AbstractValue<A>, S extends Store<S>, T extends TransferFunction<A, S>> void generateDOTofCFG(
- String inputFile, String outputFile, String method, String clas,
- boolean pdf, /*@Nullable*/ Analysis<A, S, T> analysis, MethodTree m,
- CompilationUnitTree r) {
+ public static <A extends AbstractValue<A>, S extends Store<S>, T extends TransferFunction<A, S>>
+ void generateDOTofCFG(
+ String inputFile,
+ String outputDir,
+ String method,
+ String clas,
+ boolean pdf,
+ /*@Nullable*/ Analysis<A, S, T> analysis,
+ MethodTree m,
+ CompilationUnitTree r) {
String fileName = (new File(inputFile)).getName();
System.out.println("Working on " + fileName + "...");
@@ -154,31 +156,25 @@ public class JavaSource2CFGDOT {
if (analysis != null) {
analysis.performAnalysis(cfg);
}
- String s = CFGDOTVisualizer.visualize(cfg, cfg.getEntryBlock(), analysis, false);
- try {
- FileWriter fstream = new FileWriter(outputFile + ".txt");
- BufferedWriter out = new BufferedWriter(fstream);
- out.write(s);
- System.out.println("Finished " + fileName + ".");
- out.close();
- } catch (IOException e) {
- e.printStackTrace();
- System.exit(1);
- }
+ Map<String, Object> args = new HashMap<>();
+ args.put("outdir", outputDir);
+ args.put("checkerName", "");
+
+ CFGVisualizer<A, S, T> viz = new DOTCFGVisualizer<A, S, T>();
+ viz.init(args);
+ Map<String, Object> res = viz.visualize(cfg, cfg.getEntryBlock(), analysis);
+ viz.shutdown();
if (pdf) {
- producePDF(outputFile);
+ producePDF((String) res.get("dotFileName"));
}
}
- /**
- * Invoke DOT to generate a PDF.
- */
+ /** Invoke DOT to generate a PDF. */
protected static void producePDF(String file) {
try {
- String command = "dot -Tpdf \"" + file + ".txt\" -o \"" + file
- + ".pdf\"";
+ String command = "dot -Tpdf \"" + file + ".txt\" -o \"" + file + ".pdf\"";
Process child = Runtime.getRuntime().exec(command);
child.waitFor();
} catch (InterruptedException | IOException e) {
@@ -188,66 +184,65 @@ public class JavaSource2CFGDOT {
}
/**
- * @return The AST of a specific method in a specific class in a specific
- * file (or null if no such method exists).
+ * @return the AST of a specific method in a specific class in a specific file (or null if no
+ * such method exists)
*/
- public static /*@Nullable*/ MethodTree getMethodTree(String file,
- final String method, String clas) {
+ public static /*@Nullable*/ MethodTree getMethodTree(
+ String file, final String method, String clas) {
return getMethodTreeAndCompilationUnit(file, method, clas).getKey();
}
/**
- * @return The AST of a specific method in a specific class as well as the
- * {@link CompilationUnitTree} in a specific file (or null they do
- * not exist).
+ * @return the AST of a specific method in a specific class as well as the {@link
+ * CompilationUnitTree} in a specific file (or null they do not exist).
*/
- public static Entry</*@Nullable*/ MethodTree, /*@Nullable*/ CompilationUnitTree> getMethodTreeAndCompilationUnit(
- String file, final String method, String clas) {
+ public static Entry</*@Nullable*/ MethodTree, /*@Nullable*/ CompilationUnitTree>
+ getMethodTreeAndCompilationUnit(String file, final String method, String clas) {
final Holder<MethodTree> m = new Holder<>();
final Holder<CompilationUnitTree> c = new Holder<>();
- BasicTypeProcessor typeProcessor = new BasicTypeProcessor() {
- @Override
- protected TreePathScanner<?, ?> createTreePathScanner(
- CompilationUnitTree root) {
- c.value = root;
- return new TreePathScanner<Void, Void>() {
+ BasicTypeProcessor typeProcessor =
+ new BasicTypeProcessor() {
@Override
- public Void visitMethod(MethodTree node, Void p) {
- ExecutableElement el = TreeUtils
- .elementFromDeclaration(node);
- if (el.getSimpleName().contentEquals(method)) {
- m.value = node;
- // stop execution by throwing an exception. this
- // makes sure that compilation does not proceed, and
- // thus the AST is not modified by further phases of
- // the compilation (and we save the work to do the
- // compilation).
- throw new RuntimeException();
- }
- return null;
+ protected TreePathScanner<?, ?> createTreePathScanner(
+ CompilationUnitTree root) {
+ c.value = root;
+ return new TreePathScanner<Void, Void>() {
+ @Override
+ public Void visitMethod(MethodTree node, Void p) {
+ ExecutableElement el = TreeUtils.elementFromDeclaration(node);
+ if (el.getSimpleName().contentEquals(method)) {
+ m.value = node;
+ // stop execution by throwing an exception. this
+ // makes sure that compilation does not proceed, and
+ // thus the AST is not modified by further phases of
+ // the compilation (and we save the work to do the
+ // compilation).
+ throw new RuntimeException();
+ }
+ return null;
+ }
+ };
}
};
- }
- };
Context context = new Context();
+ Options.instance(context).put("compilePolicy", "ATTR_ONLY");
JavaCompiler javac = new JavaCompiler(context);
- javac.attrParseOnly = true;
- JavacFileManager fileManager = (JavacFileManager) context
- .get(JavaFileManager.class);
+ JavacFileManager fileManager = (JavacFileManager) context.get(JavaFileManager.class);
- JavaFileObject l = fileManager
- .getJavaFileObjectsFromStrings(List.of(file)).iterator().next();
+ JavaFileObject l =
+ fileManager.getJavaFileObjectsFromStrings(List.of(file)).iterator().next();
PrintStream err = System.err;
try {
// redirect syserr to nothing (and prevent the compiler from issuing
// warnings about our exception.
- System.setErr(new PrintStream(new OutputStream() {
- @Override
- public void write(int b) throws IOException {
- }
- }));
+ System.setErr(
+ new PrintStream(
+ new OutputStream() {
+ @Override
+ public void write(int b) throws IOException {}
+ }));
javac.compile(List.of(l), List.of(clas), List.of(typeProcessor));
} catch (Throwable e) {
// ok
@@ -271,5 +266,4 @@ public class JavaSource2CFGDOT {
}
};
}
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/UnderlyingAST.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/UnderlyingAST.java
index 5f61468e8c..dd646f110d 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/UnderlyingAST.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/UnderlyingAST.java
@@ -6,11 +6,10 @@ import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
/**
- * Represents an abstract syntax tree of type {@link Tree} that underlies a
- * given control flow graph.
+ * Represents an abstract syntax tree of type {@link Tree} that underlies a given control flow
+ * graph.
*
* @author Stefan Heule
- *
*/
public abstract class UnderlyingAST {
public enum Kind {
@@ -19,9 +18,7 @@ public abstract class UnderlyingAST {
/** The underlying code is a lambda expression */
LAMBDA,
- /**
- * The underlying code is an arbitrary Java statement or expression
- */
+ /** The underlying code is an arbitrary Java statement or expression */
ARBITRARY_CODE,
}
@@ -31,18 +28,14 @@ public abstract class UnderlyingAST {
this.kind = kind;
}
- /**
- * @return The code that corresponds to the CFG.
- */
- abstract public Tree getCode();
+ /** @return the code that corresponds to the CFG */
+ public abstract Tree getCode();
public Kind getKind() {
return kind;
}
- /**
- * If the underlying AST is a method.
- */
+ /** If the underlying AST is a method. */
public static class CFGMethod extends UnderlyingAST {
/** The method declaration */
@@ -76,9 +69,7 @@ public abstract class UnderlyingAST {
}
}
- /**
- * If the underlying AST is a lambda.
- */
+ /** If the underlying AST is a lambda. */
public static class CFGLambda extends UnderlyingAST {
private final LambdaExpressionTree lambda;
@@ -103,16 +94,18 @@ public abstract class UnderlyingAST {
}
}
- /**
- * If the underlying AST is a statement or expression.
- */
+ /** If the underlying AST is a statement or expression. */
public static class CFGStatement extends UnderlyingAST {
protected final Tree code;
- public CFGStatement(Tree code) {
+ /** The class tree this method belongs to. */
+ protected final ClassTree classTree;
+
+ public CFGStatement(Tree code, ClassTree classTree) {
super(Kind.ARBITRARY_CODE);
this.code = code;
+ this.classTree = classTree;
}
@Override
@@ -120,6 +113,10 @@ public abstract class UnderlyingAST {
return code;
}
+ public ClassTree getClassTree() {
+ return classTree;
+ }
+
@Override
public String toString() {
return "CFGStatement(\n" + code + "\n)";
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/Block.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/Block.java
index 81edef6b2d..2d58550568 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/Block.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/Block.java
@@ -4,7 +4,6 @@ package org.checkerframework.dataflow.cfg.block;
* Represents a basic block in a control flow graph.
*
* @author Stefan Heule
- *
*/
public interface Block {
@@ -24,14 +23,9 @@ public interface Block {
EXCEPTION_BLOCK,
}
- /**
- * @return The type of this basic block.
- */
+ /** @return the type of this basic block */
BlockType getType();
- /**
- * @return The unique identifier of this block.
- */
+ /** @return the unique identifier of this block */
long getId();
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/BlockImpl.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/BlockImpl.java
index c3df418ecc..0421a1e3f5 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/BlockImpl.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/BlockImpl.java
@@ -6,9 +6,8 @@ import java.util.Set;
/**
* Base class of the {@link Block} implementation hierarchy.
- *
+ *
* @author Stefan Heule
- *
*/
public abstract class BlockImpl implements Block {
@@ -24,9 +23,7 @@ public abstract class BlockImpl implements Block {
/** The set of predecessors. */
protected Set<BlockImpl> predecessors;
- /**
- * @return A fresh identifier.
- */
+ /** @return a fresh identifier */
private static long uniqueID() {
return lastId++;
}
@@ -45,9 +42,7 @@ public abstract class BlockImpl implements Block {
return type;
}
- /**
- * @return The list of predecessors of this basic block.
- */
+ /** @return the list of predecessors of this basic block */
public Set<BlockImpl> getPredecessors() {
return Collections.unmodifiableSet(predecessors);
}
@@ -59,5 +54,4 @@ public abstract class BlockImpl implements Block {
public void removePredecessor(BlockImpl pred) {
predecessors.remove(pred);
}
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ConditionalBlock.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ConditionalBlock.java
index d267c99803..dce04abdfe 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ConditionalBlock.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ConditionalBlock.java
@@ -4,45 +4,27 @@ import org.checkerframework.dataflow.analysis.Store;
import org.checkerframework.dataflow.cfg.node.Node;
/**
- * Represents a conditional basic block that contains exactly one boolean
- * {@link Node}.
+ * Represents a conditional basic block that contains exactly one boolean {@link Node}.
*
* @author Stefan Heule
- *
*/
public interface ConditionalBlock extends Block {
- /**
- * @return The entry block of the then branch.
- */
+ /** @return the entry block of the then branch */
Block getThenSuccessor();
- /**
- * @return The entry block of the else branch.
- */
+ /** @return the entry block of the else branch */
Block getElseSuccessor();
- /**
- * @return The flow rule for information flowing from
- * this block to its then successor.
- */
+ /** @return the flow rule for information flowing from this block to its then successor */
Store.FlowRule getThenFlowRule();
- /**
- * @return The flow rule for information flowing from
- * this block to its else successor.
- */
+ /** @return the flow rule for information flowing from this block to its else successor */
Store.FlowRule getElseFlowRule();
- /**
- * Set the flow rule for information flowing from this block to
- * its then successor.
- */
+ /** Set the flow rule for information flowing from this block to its then successor. */
void setThenFlowRule(Store.FlowRule rule);
- /**
- * Set the flow rule for information flowing from this block to
- * its else successor.
- */
+ /** Set the flow rule for information flowing from this block to its else successor. */
void setElseFlowRule(Store.FlowRule rule);
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ConditionalBlockImpl.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ConditionalBlockImpl.java
index 629bb81070..bd12522983 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ConditionalBlockImpl.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ConditionalBlockImpl.java
@@ -6,7 +6,6 @@ import org.checkerframework.dataflow.analysis.Store;
* Implementation of a conditional basic block.
*
* @author Stefan Heule
- *
*/
public class ConditionalBlockImpl extends BlockImpl implements ConditionalBlock {
@@ -17,34 +16,29 @@ public class ConditionalBlockImpl extends BlockImpl implements ConditionalBlock
protected BlockImpl elseSuccessor;
/**
- * The rules below say that the THEN store before a conditional
- * block flows to BOTH of the stores of the then successor, while
- * the ELSE store before a conditional block flows to BOTH of the
- * stores of the else successor.
+ * The rules below say that the THEN store before a conditional block flows to BOTH of the
+ * stores of the then successor, while the ELSE store before a conditional block flows to BOTH
+ * of the stores of the else successor.
*/
protected Store.FlowRule thenFlowRule = Store.FlowRule.THEN_TO_BOTH;
-
+
protected Store.FlowRule elseFlowRule = Store.FlowRule.ELSE_TO_BOTH;
/**
- * Initialize an empty conditional basic block to be filled with contents
- * and linked to other basic blocks later.
+ * Initialize an empty conditional basic block to be filled with contents and linked to other
+ * basic blocks later.
*/
public ConditionalBlockImpl() {
type = BlockType.CONDITIONAL_BLOCK;
}
- /**
- * Set the then branch successor.
- */
+ /** Set the then branch successor. */
public void setThenSuccessor(BlockImpl b) {
thenSuccessor = b;
b.addPredecessor(this);
}
- /**
- * Set the else branch successor.
- */
+ /** Set the else branch successor. */
public void setElseSuccessor(BlockImpl b) {
elseSuccessor = b;
b.addPredecessor(this);
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ExceptionBlock.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ExceptionBlock.java
index c00a7e1e34..a549c5f03f 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ExceptionBlock.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ExceptionBlock.java
@@ -2,37 +2,26 @@ package org.checkerframework.dataflow.cfg.block;
import java.util.Map;
import java.util.Set;
-
import javax.lang.model.type.TypeMirror;
-
import org.checkerframework.dataflow.cfg.node.Node;
/**
- * Represents a basic block that contains exactly one {@link Node} which can
- * throw an exception. This block has exactly one non-exceptional successor, and
- * one or more exceptional successors.
- *
- * <p>
+ * Represents a basic block that contains exactly one {@link Node} which can throw an exception.
+ * This block has exactly one non-exceptional successor, and one or more exceptional successors.
*
- * The following invariant holds.
+ * <p>The following invariant holds.
*
* <pre>
* getNode().getBlock() == this
* </pre>
*
* @author Stefan Heule
- *
*/
public interface ExceptionBlock extends SingleSuccessorBlock {
- /**
- * @return The node of this block.
- */
+ /** @return the node of this block */
Node getNode();
- /**
- * @return The list of exceptional successor blocks as an unmodifiable map.
- */
+ /** @return the list of exceptional successor blocks as an unmodifiable map */
Map<TypeMirror, Set<Block>> getExceptionalSuccessors();
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ExceptionBlockImpl.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ExceptionBlockImpl.java
index 2148e060cd..2a6c3b4914 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ExceptionBlockImpl.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/ExceptionBlockImpl.java
@@ -5,19 +5,15 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-
import javax.lang.model.type.TypeMirror;
-
import org.checkerframework.dataflow.cfg.node.Node;
/**
* Base class of the {@link Block} implementation hierarchy.
*
* @author Stefan Heule
- *
*/
-public class ExceptionBlockImpl extends SingleSuccessorBlockImpl implements
- ExceptionBlock {
+public class ExceptionBlockImpl extends SingleSuccessorBlockImpl implements ExceptionBlock {
/** Set of exceptional successors. */
protected Map<TypeMirror, Set<Block>> exceptionalSuccessors;
@@ -30,9 +26,7 @@ public class ExceptionBlockImpl extends SingleSuccessorBlockImpl implements
/** The node of this block. */
protected Node node;
- /**
- * Set the node.
- */
+ /** Set the node. */
public void setNode(Node c) {
node = c;
c.setBlock(this);
@@ -43,11 +37,8 @@ public class ExceptionBlockImpl extends SingleSuccessorBlockImpl implements
return node;
}
- /**
- * Add an exceptional successor.
- */
- public void addExceptionalSuccessor(BlockImpl b,
- TypeMirror cause) {
+ /** Add an exceptional successor. */
+ public void addExceptionalSuccessor(BlockImpl b, TypeMirror cause) {
if (exceptionalSuccessors == null) {
exceptionalSuccessors = new HashMap<>();
}
@@ -72,5 +63,4 @@ public class ExceptionBlockImpl extends SingleSuccessorBlockImpl implements
public String toString() {
return "ExceptionBlock(" + node + ")";
}
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/RegularBlock.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/RegularBlock.java
index dd6502fa1a..566449257b 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/RegularBlock.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/RegularBlock.java
@@ -1,38 +1,27 @@
package org.checkerframework.dataflow.cfg.block;
import java.util.List;
-
import org.checkerframework.dataflow.cfg.node.Node;
/**
* A regular basic block that contains a sequence of {@link Node}s.
*
- * <p>
- *
- * The following invariant holds.
+ * <p>The following invariant holds.
*
* <pre>
* forall n in getContents() :: n.getBlock() == this
* </pre>
*
* @author Stefan Heule
- *
*/
public interface RegularBlock extends SingleSuccessorBlock {
- /**
- * @return The unmodifiable sequence of {@link Node}s.
- */
+ /** @return the unmodifiable sequence of {@link Node}s. */
List<Node> getContents();
- /**
- * @return The regular successor block.
- */
+ /** @return the regular successor block */
Block getRegularSuccessor();
- /**
- * Is this block empty (i.e., does it not contain any contents).
- */
+ /** Is this block empty (i.e., does it not contain any contents). */
boolean isEmpty();
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/RegularBlockImpl.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/RegularBlockImpl.java
index 853f2c94f0..b302710d70 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/RegularBlockImpl.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/RegularBlockImpl.java
@@ -3,41 +3,34 @@ package org.checkerframework.dataflow.cfg.block;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
-
import org.checkerframework.dataflow.cfg.node.Node;
/**
* Implementation of a regular basic block.
*
* @author Stefan Heule
- *
*/
-public class RegularBlockImpl extends SingleSuccessorBlockImpl implements
- RegularBlock {
+public class RegularBlockImpl extends SingleSuccessorBlockImpl implements RegularBlock {
/** Internal representation of the contents. */
protected List<Node> contents;
/**
- * Initialize an empty basic block to be filled with contents and linked to
- * other basic blocks later.
+ * Initialize an empty basic block to be filled with contents and linked to other basic blocks
+ * later.
*/
public RegularBlockImpl() {
contents = new LinkedList<>();
type = BlockType.REGULAR_BLOCK;
}
- /**
- * Add a node to the contents of this basic block.
- */
+ /** Add a node to the contents of this basic block. */
public void addNode(Node t) {
contents.add(t);
t.setBlock(this);
}
- /**
- * Add multiple nodes to the contents of this basic block.
- */
+ /** Add multiple nodes to the contents of this basic block. */
public void addNodes(List<? extends Node> ts) {
for (Node t : ts) {
addNode(t);
@@ -63,5 +56,4 @@ public class RegularBlockImpl extends SingleSuccessorBlockImpl implements
public boolean isEmpty() {
return contents.isEmpty();
}
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SingleSuccessorBlock.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SingleSuccessorBlock.java
index 4d56291fe6..038a69d3e4 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SingleSuccessorBlock.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SingleSuccessorBlock.java
@@ -10,23 +10,15 @@ import org.checkerframework.dataflow.analysis.Store;
* A basic block that has at exactly one non-exceptional successor.
*
* @author Stefan Heule
- *
*/
public interface SingleSuccessorBlock extends Block {
- /**
- * @return The non-exceptional successor block, or {@code null} if there is
- * no successor.
- */
+ /** @return the non-exceptional successor block, or {@code null} if there is no successor. */
/*@Nullable*/ Block getSuccessor();
- /**
- * @return The flow rule for information flowing from this block to its successor.
- */
+ /** @return the flow rule for information flowing from this block to its successor */
Store.FlowRule getFlowRule();
- /**
- * Set the flow rule for information flowing from this block to its successor.
- */
+ /** Set the flow rule for information flowing from this block to its successor. */
void setFlowRule(Store.FlowRule rule);
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SingleSuccessorBlockImpl.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SingleSuccessorBlockImpl.java
index 7e5988e2e7..9e8872e850 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SingleSuccessorBlockImpl.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SingleSuccessorBlockImpl.java
@@ -10,17 +10,15 @@ import org.checkerframework.dataflow.analysis.Store;
* Implementation of a non-special basic block.
*
* @author Stefan Heule
- *
*/
-public abstract class SingleSuccessorBlockImpl extends BlockImpl implements
- SingleSuccessorBlock {
+public abstract class SingleSuccessorBlockImpl extends BlockImpl implements SingleSuccessorBlock {
/** Internal representation of the successor. */
protected /*@Nullable*/ BlockImpl successor;
/**
- * The rule below say that EACH store at the end of a single
- * successor block flow to the corresponding store of the successor.
+ * The rule below say that EACH store at the end of a single successor block flow to the
+ * corresponding store of the successor.
*/
protected Store.FlowRule flowRule = Store.FlowRule.EACH_TO_EACH;
@@ -29,9 +27,7 @@ public abstract class SingleSuccessorBlockImpl extends BlockImpl implements
return successor;
}
- /**
- * Set a basic block as the successor of this block.
- */
+ /** Set a basic block as the successor of this block. */
public void setSuccessor(BlockImpl successor) {
this.successor = successor;
successor.addPredecessor(this);
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SpecialBlock.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SpecialBlock.java
index 89154bf604..dac9b4b8c2 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SpecialBlock.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SpecialBlock.java
@@ -2,14 +2,14 @@ package org.checkerframework.dataflow.cfg.block;
/**
* Represents a special basic block; i.e., one of the following:
+ *
* <ul>
- * <li>Entry block of a method.</li>
- * <li>Regular exit block of a method.</li>
- * <li>Exceptional exit block of a method.</li>
+ * <li>Entry block of a method.
+ * <li>Regular exit block of a method.
+ * <li>Exceptional exit block of a method.
* </ul>
*
* @author Stefan Heule
- *
*/
public interface SpecialBlock extends SingleSuccessorBlock {
@@ -26,9 +26,6 @@ public interface SpecialBlock extends SingleSuccessorBlock {
EXCEPTIONAL_EXIT,
}
- /**
- * @return The type of this special basic block.
- */
+ /** @return the type of this special basic block */
SpecialBlockType getSpecialType();
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SpecialBlockImpl.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SpecialBlockImpl.java
index 9b3f8fb8e3..e6f25e8b1b 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SpecialBlockImpl.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/block/SpecialBlockImpl.java
@@ -1,7 +1,6 @@
package org.checkerframework.dataflow.cfg.block;
-public class SpecialBlockImpl extends SingleSuccessorBlockImpl implements
- SpecialBlock {
+public class SpecialBlockImpl extends SingleSuccessorBlockImpl implements SpecialBlock {
/** The type of this special basic block. */
protected SpecialBlockType specialType;
@@ -20,5 +19,4 @@ public class SpecialBlockImpl extends SingleSuccessorBlockImpl implements
public String toString() {
return "SpecialBlock(" + specialType + ")";
}
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AbstractNodeVisitor.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AbstractNodeVisitor.java
index 0f8a998efe..39f1f84074 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AbstractNodeVisitor.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AbstractNodeVisitor.java
@@ -1,28 +1,21 @@
package org.checkerframework.dataflow.cfg.node;
-
/**
- * A default implementation of the node visitor interface. The class introduces
- * several 'summary' methods, that can be overridden to change the behavior of
- * several related visit methods at once. An example is the
- * {@code visitValueLiteral} method, that is called for every
- * {@link ValueLiteralNode}.
- *
- * <p>
+ * A default implementation of the node visitor interface. The class introduces several 'summary'
+ * methods, that can be overridden to change the behavior of several related visit methods at once.
+ * An example is the {@code visitValueLiteral} method, that is called for every {@link
+ * ValueLiteralNode}.
*
- * This is useful to implement a visitor that performs the same operation (e.g.,
- * nothing) for most {@link Node}s and only has special behavior for a few.
+ * <p>This is useful to implement a visitor that performs the same operation (e.g., nothing) for
+ * most {@link Node}s and only has special behavior for a few.
*
* @author Stefan Heule
- *
- * @param <R>
- * Return type of the visitor.
- * @param <P>
- * Parameter type of the visitor.
+ * @param <R> return type of the visitor
+ * @param <P> parameter type of the visitor
*/
public abstract class AbstractNodeVisitor<R, P> implements NodeVisitor<R, P> {
- abstract public R visitNode(Node n, P p);
+ public abstract R visitNode(Node n, P p);
public R visitValueLiteral(ValueLiteralNode n, P p) {
return visitNode(n, p);
@@ -168,8 +161,7 @@ public abstract class AbstractNodeVisitor<R, P> implements NodeVisitor<R, P> {
// Compound assignments
@Override
- public R visitStringConcatenateAssignment(
- StringConcatenateAssignmentNode n, P p) {
+ public R visitStringConcatenateAssignment(StringConcatenateAssignmentNode n, P p) {
return visitNode(n, p);
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayAccessNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayAccessNode.java
index c51d7c1fbf..24ef689ee9 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayAccessNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayAccessNode.java
@@ -1,29 +1,24 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.ArrayAccessTree;
+import com.sun.source.tree.Tree;
import java.util.Collection;
import java.util.LinkedList;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-
import org.checkerframework.javacutil.InternalUtils;
-import com.sun.source.tree.ArrayAccessTree;
-import com.sun.source.tree.Tree;
-
/**
* A node for an array access:
*
* <pre>
- * <em>array ref</em> [ <em>index</em> ]
+ * <em>arrayref</em> [ <em>index</em> ]
* </pre>
*
* We allow array accesses without corresponding AST {@link Tree}s.
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-
public class ArrayAccessNode extends Node {
protected Tree tree;
@@ -68,8 +63,7 @@ public class ArrayAccessNode extends Node {
return false;
}
ArrayAccessNode other = (ArrayAccessNode) obj;
- return getArray().equals(other.getArray())
- && getIndex().equals(other.getIndex());
+ return getArray().equals(other.getArray()) && getIndex().equals(other.getIndex());
}
@Override
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayCreationNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayCreationNode.java
index 4af69077d3..5f277f2a0b 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayCreationNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayCreationNode.java
@@ -4,16 +4,13 @@ package org.checkerframework.dataflow.cfg.node;
import org.checkerframework.checker.nullness.qual.Nullable;
*/
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
+import com.sun.source.tree.NewArrayTree;
+import com.sun.source.tree.Tree;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
-
import javax.lang.model.type.TypeMirror;
-
-import com.sun.source.tree.NewArrayTree;
-import com.sun.source.tree.Tree;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for new array creation
@@ -25,17 +22,21 @@ import com.sun.source.tree.Tree;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class ArrayCreationNode extends Node {
- // The tree is null when an array is created for
- // variable arity method calls.
+ /** The tree is null when an array is created for variable arity method calls. */
protected /*@Nullable*/ NewArrayTree tree;
+ /**
+ * The length of this list is the number of dimensions in the array. Each element is the size of
+ * the given dimension.
+ */
protected List<Node> dimensions;
+
protected List<Node> initializers;
- public ArrayCreationNode(/*@Nullable*/ NewArrayTree tree,
+ public ArrayCreationNode(
+ /*@Nullable*/ NewArrayTree tree,
TypeMirror type,
List<Node> dimensions,
List<Node> initializers) {
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayTypeNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayTypeNode.java
index d7e0cd7f82..dfde575b5e 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayTypeNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ArrayTypeNode.java
@@ -1,24 +1,19 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.ArrayTypeTree;
+import com.sun.source.tree.Tree;
import java.util.Collection;
import java.util.Collections;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-
import org.checkerframework.javacutil.InternalUtils;
-import com.sun.source.tree.ArrayTypeTree;
-import com.sun.source.tree.Tree;
-
/**
- * A node representing a array type used in an expression
- * such as a field access
+ * A node representing a array type used in an expression such as a field access
*
- * <em>type</em> .class
+ * <p><em>type</em> .class
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class ArrayTypeNode extends Node {
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssertionErrorNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssertionErrorNode.java
index efc066a5bf..0b4d747331 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssertionErrorNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssertionErrorNode.java
@@ -1,15 +1,12 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.Tree.Kind;
import java.util.Collection;
import java.util.LinkedList;
-
import javax.lang.model.type.TypeMirror;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-import com.sun.source.tree.Tree;
-import com.sun.source.tree.Tree.Kind;
-
/**
* A node for the {@link AssertionError} when an assertion fails.
*
@@ -19,7 +16,6 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class AssertionErrorNode extends Node {
@@ -66,8 +62,7 @@ public class AssertionErrorNode extends Node {
return false;
}
AssertionErrorNode other = (AssertionErrorNode) obj;
- return getCondition().equals(other.getCondition()) &&
- getDetail().equals(other.getDetail());
+ return getCondition().equals(other.getCondition()) && getDetail().equals(other.getDetail());
}
@Override
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentContext.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentContext.java
index 85d17e7c06..5e6a1606de 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentContext.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentContext.java
@@ -1,33 +1,27 @@
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;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import org.checkerframework.javacutil.TreeUtils;
/**
- * 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.
+ * 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.
+ * <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'.
- */
+ /** An assignment context for an assignment 'lhs = rhs'. */
public static class AssignmentLhsContext extends AssignmentContext {
protected final Node node;
@@ -57,9 +51,7 @@ public abstract class AssignmentContext {
}
}
- /**
- * An assignment context for a method parameter.
- */
+ /** An assignment context for a method parameter. */
public static class MethodParameterContext extends AssignmentContext {
protected final ExecutableElement method;
@@ -83,9 +75,7 @@ public abstract class AssignmentContext {
}
}
- /**
- * An assignment context for method return statements.
- */
+ /** An assignment context for method return statements. */
public static class MethodReturnContext extends AssignmentContext {
protected final ExecutableElement method;
@@ -107,9 +97,7 @@ public abstract class AssignmentContext {
}
}
- /**
- * An assignment context for lambda return statements.
- */
+ /** An assignment context for lambda return statements. */
public static class LambdaReturnContext extends AssignmentContext {
protected final ExecutableElement method;
@@ -131,9 +119,7 @@ public abstract class AssignmentContext {
}
}
- /**
- * Returns an {@link Element} that has the type of this assignment context.
- */
+ /** Returns an {@link Element} that has the type of this assignment context. */
public abstract Element getElementForType();
public abstract Tree getContextTree();
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentNode.java
index d48666a1a6..32723dd8e4 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/AssignmentNode.java
@@ -1,18 +1,15 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.cfg.node.AssignmentContext.AssignmentLhsContext;
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
import com.sun.source.tree.AssignmentTree;
import com.sun.source.tree.CompoundAssignmentTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.UnaryTree;
import com.sun.source.tree.VariableTree;
+import java.util.Collection;
+import java.util.LinkedList;
+import org.checkerframework.dataflow.cfg.node.AssignmentContext.AssignmentLhsContext;
+import org.checkerframework.dataflow.util.HashCodeUtils;
+import org.checkerframework.javacutil.InternalUtils;
/**
* A node for an assignment:
@@ -26,7 +23,6 @@ import com.sun.source.tree.VariableTree;
* We allow assignments without corresponding AST {@link Tree}s.
*
* @author Stefan Heule
- *
*/
public class AssignmentNode extends Node {
@@ -36,8 +32,10 @@ public class AssignmentNode extends Node {
public AssignmentNode(Tree tree, Node target, Node expression) {
super(InternalUtils.typeOf(tree));
- assert tree instanceof AssignmentTree || tree instanceof VariableTree
- || tree instanceof CompoundAssignmentTree || tree instanceof UnaryTree;
+ assert tree instanceof AssignmentTree
+ || tree instanceof VariableTree
+ || tree instanceof CompoundAssignmentTree
+ || tree instanceof UnaryTree;
assert target instanceof FieldAccessNode
|| target instanceof LocalVariableNode
|| target instanceof ArrayAccessNode;
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BinaryOperationNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BinaryOperationNode.java
new file mode 100644
index 0000000000..424747b4ac
--- /dev/null
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BinaryOperationNode.java
@@ -0,0 +1,52 @@
+package org.checkerframework.dataflow.cfg.node;
+
+import com.sun.source.tree.BinaryTree;
+import java.util.Collection;
+import java.util.LinkedList;
+import org.checkerframework.javacutil.InternalUtils;
+
+/**
+ * A node for a binary expression.
+ *
+ * <p>For example:
+ *
+ * <pre>
+ * <em>lefOperandNode</em> <em>operator</em> <em>rightOperandNode</em>
+ * </pre>
+ *
+ * @author charleszhuochen
+ */
+public abstract class BinaryOperationNode extends Node {
+
+ protected final BinaryTree tree;
+ protected final Node left;
+ protected final Node right;
+
+ public BinaryOperationNode(BinaryTree tree, Node left, Node right) {
+ super(InternalUtils.typeOf(tree));
+ this.tree = tree;
+ this.left = left;
+ this.right = right;
+ }
+
+ public Node getLeftOperand() {
+ return left;
+ }
+
+ public Node getRightOperand() {
+ return right;
+ }
+
+ @Override
+ public BinaryTree getTree() {
+ return tree;
+ }
+
+ @Override
+ public Collection<Node> getOperands() {
+ LinkedList<Node> list = new LinkedList<Node>();
+ list.add(getLeftOperand());
+ list.add(getRightOperand());
+ return list;
+ }
+}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseAndNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseAndNode.java
index 82c5f5d5f8..18d7163f22 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseAndNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseAndNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for the bitwise or logical (single bit) and operation:
@@ -19,33 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class BitwiseAndNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
+public class BitwiseAndNode extends BinaryOperationNode {
- public BitwiseAndNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
+ public BitwiseAndNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind() == Kind.AND;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
-
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -72,12 +45,4 @@ public class BitwiseAndNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseComplementNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseComplementNode.java
index 1b8ad73175..a1c2111b8c 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseComplementNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseComplementNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.Collections;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
+import com.sun.source.tree.UnaryTree;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for the bitwise complement operation:
@@ -19,27 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class BitwiseComplementNode extends Node {
+public class BitwiseComplementNode extends UnaryOperationNode {
- protected Tree tree;
- protected Node operand;
-
- public BitwiseComplementNode(Tree tree, Node operand) {
- super(InternalUtils.typeOf(tree));
+ public BitwiseComplementNode(UnaryTree tree, Node operand) {
+ super(tree, operand);
assert tree.getKind() == Kind.BITWISE_COMPLEMENT;
- this.tree = tree;
- this.operand = operand;
- }
-
- public Node getOperand() {
- return operand;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -65,9 +44,4 @@ public class BitwiseComplementNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- return Collections.singletonList(getOperand());
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseOrNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseOrNode.java
index f9763c9b14..66089133f2 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseOrNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseOrNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for the bitwise or logical (single bit) or operation:
@@ -19,33 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class BitwiseOrNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
+public class BitwiseOrNode extends BinaryOperationNode {
- public BitwiseOrNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
+ public BitwiseOrNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind() == Kind.OR;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
-
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -72,12 +45,4 @@ public class BitwiseOrNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseXorNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseXorNode.java
index 848b2f17ec..cdbe0ed93d 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseXorNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BitwiseXorNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for the bitwise or logical (single bit) xor operation:
@@ -19,33 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class BitwiseXorNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
+public class BitwiseXorNode extends BinaryOperationNode {
- public BitwiseXorNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
+ public BitwiseXorNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind() == Kind.XOR;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
-
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -72,12 +45,4 @@ public class BitwiseXorNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BooleanLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BooleanLiteralNode.java
index 8368c87793..7f5a7a1eda 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BooleanLiteralNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/BooleanLiteralNode.java
@@ -1,10 +1,9 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.Collections;
-
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.Tree;
+import java.util.Collection;
+import java.util.Collections;
/**
* A node for a boolean literal:
@@ -15,7 +14,6 @@ import com.sun.source.tree.Tree;
* </pre>
*
* @author Stefan Heule
- *
*/
public class BooleanLiteralNode extends ValueLiteralNode {
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/CaseNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/CaseNode.java
index f5a3d460a5..a694dfb975 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/CaseNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/CaseNode.java
@@ -1,20 +1,16 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.CaseTree;
+import com.sun.source.tree.Tree.Kind;
import java.util.Collection;
import java.util.LinkedList;
-
import javax.lang.model.type.TypeKind;
import javax.lang.model.util.Types;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-import com.sun.source.tree.CaseTree;
-import com.sun.source.tree.Tree.Kind;
-
/**
- * A node for a case in a switch statement. Although
- * a case has no abstract value, it can imply facts about
- * the abstract values of its operands.
+ * A node for a case in a switch statement. Although a case has no abstract value, it can imply
+ * facts about the abstract values of its operands.
*
* <pre>
* case <em>constant</em>:
@@ -22,7 +18,6 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class CaseNode extends Node {
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/CharacterLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/CharacterLiteralNode.java
index 979a4177d8..c1d51c7523 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/CharacterLiteralNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/CharacterLiteralNode.java
@@ -1,10 +1,9 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.Collections;
-
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.Tree;
+import java.util.Collection;
+import java.util.Collections;
/**
* A node for a character literal. For example:
@@ -17,7 +16,6 @@ import com.sun.source.tree.Tree;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class CharacterLiteralNode extends ValueLiteralNode {
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ClassNameNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ClassNameNode.java
index b74965d122..c3e2471309 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ClassNameNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ClassNameNode.java
@@ -4,34 +4,30 @@ package org.checkerframework.dataflow.cfg.node;
import org.checkerframework.checker.nullness.qual.Nullable;
*/
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-import org.checkerframework.javacutil.TreeUtils;
-
-import java.util.Collection;
-import java.util.Collections;
-
-import javax.lang.model.element.Element;
-
+import com.sun.source.tree.ClassTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.Tree;
+import java.util.Collection;
+import java.util.Collections;
+import javax.lang.model.element.Element;
+import javax.lang.model.type.TypeMirror;
+import org.checkerframework.dataflow.util.HashCodeUtils;
+import org.checkerframework.javacutil.InternalUtils;
+import org.checkerframework.javacutil.TreeUtils;
/**
- * A node representing a class name used in an expression
- * such as a static method invocation.
+ * A node representing a class name used in an expression such as a static method invocation.
*
- * parent.<em>class</em> .forName(...)
+ * <p>parent.<em>class</em> .forName(...)
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class ClassNameNode extends Node {
protected final Tree tree;
- // The class named by this node
+ /** The class named by this node */
protected final Element element;
/** The parent name, if any. */
@@ -45,6 +41,17 @@ public class ClassNameNode extends Node {
this.parent = null;
}
+ public ClassNameNode(ClassTree tree) {
+ super(InternalUtils.typeOf(tree));
+ assert tree.getKind() == Tree.Kind.CLASS
+ || tree.getKind() == Tree.Kind.ENUM
+ || tree.getKind() == Tree.Kind.INTERFACE
+ || tree.getKind() == Tree.Kind.ANNOTATION_TYPE;
+ this.tree = tree;
+ this.element = TreeUtils.elementFromDeclaration(tree);
+ this.parent = null;
+ }
+
public ClassNameNode(MemberSelectTree tree, Node parent) {
super(InternalUtils.typeOf(tree));
this.tree = tree;
@@ -52,6 +59,13 @@ public class ClassNameNode extends Node {
this.parent = parent;
}
+ public ClassNameNode(TypeMirror type, Element element) {
+ super(type);
+ this.tree = null;
+ this.element = element;
+ this.parent = null;
+ }
+
public Element getElement() {
return element;
}
@@ -82,11 +96,9 @@ public class ClassNameNode extends Node {
}
ClassNameNode other = (ClassNameNode) obj;
if (getParent() == null) {
- return other.getParent() == null
- && getElement().equals(other.getElement());
+ return other.getParent() == null && getElement().equals(other.getElement());
} else {
- return getParent().equals(other.getParent())
- && getElement().equals(other.getElement());
+ return getParent().equals(other.getParent()) && getElement().equals(other.getElement());
}
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalAndNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalAndNode.java
index dfa9f99c27..fb5145ab89 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalAndNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalAndNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for a conditional and expression:
@@ -19,33 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class ConditionalAndNode extends Node {
-
- protected BinaryTree tree;
- protected Node lhs;
- protected Node rhs;
+public class ConditionalAndNode extends BinaryOperationNode {
- public ConditionalAndNode(BinaryTree tree, Node lhs, Node rhs) {
- super(InternalUtils.typeOf(tree));
+ public ConditionalAndNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind().equals(Kind.CONDITIONAL_AND);
- this.tree = tree;
- this.lhs = lhs;
- this.rhs = rhs;
- }
-
- public Node getLeftOperand() {
- return lhs;
- }
-
- public Node getRightOperand() {
- return rhs;
- }
-
- @Override
- public BinaryTree getTree() {
- return tree;
}
@Override
@@ -72,12 +45,4 @@ public class ConditionalAndNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalNotNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalNotNode.java
index 5143c69c50..6a28c67a16 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalNotNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalNotNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.Collections;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
import com.sun.source.tree.Tree.Kind;
import com.sun.source.tree.UnaryTree;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for a conditional not expression:
@@ -19,27 +13,12 @@ import com.sun.source.tree.UnaryTree;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class ConditionalNotNode extends Node {
-
- protected UnaryTree tree;
- protected Node operand;
+public class ConditionalNotNode extends UnaryOperationNode {
public ConditionalNotNode(UnaryTree tree, Node operand) {
- super(InternalUtils.typeOf(tree));
+ super(tree, operand);
assert tree.getKind().equals(Kind.LOGICAL_COMPLEMENT);
- this.tree = tree;
- this.operand = operand;
- }
-
- public Node getOperand() {
- return operand;
- }
-
- @Override
- public UnaryTree getTree() {
- return tree;
}
@Override
@@ -65,9 +44,4 @@ public class ConditionalNotNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- return Collections.singletonList(getOperand());
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalOrNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalOrNode.java
index 2da33fadf6..e5cb0bfc13 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalOrNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ConditionalOrNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for a conditional or expression:
@@ -18,33 +12,12 @@ import com.sun.source.tree.Tree.Kind;
* </pre>
*
* @author Stefan Heule
- *
*/
-public class ConditionalOrNode extends Node {
-
- protected BinaryTree tree;
- protected Node lhs;
- protected Node rhs;
+public class ConditionalOrNode extends BinaryOperationNode {
- public ConditionalOrNode(BinaryTree tree, Node lhs, Node rhs) {
- super(InternalUtils.typeOf(tree));
+ public ConditionalOrNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind().equals(Kind.CONDITIONAL_OR);
- this.tree = tree;
- this.lhs = lhs;
- this.rhs = rhs;
- }
-
- public Node getLeftOperand() {
- return lhs;
- }
-
- public Node getRightOperand() {
- return rhs;
- }
-
- @Override
- public BinaryTree getTree() {
- return tree;
}
@Override
@@ -71,12 +44,4 @@ public class ConditionalOrNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/DoubleLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/DoubleLiteralNode.java
index 855a95a7b5..60c25749a4 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/DoubleLiteralNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/DoubleLiteralNode.java
@@ -1,10 +1,9 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.Collections;
-
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.Tree;
+import java.util.Collection;
+import java.util.Collections;
/**
* A node for a double literal. For example:
@@ -16,7 +15,6 @@ import com.sun.source.tree.Tree;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class DoubleLiteralNode extends ValueLiteralNode {
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/EqualToNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/EqualToNode.java
index ed56d4ab68..b1fb5d8f68 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/EqualToNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/EqualToNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for an equality check:
@@ -18,33 +12,12 @@ import com.sun.source.tree.Tree.Kind;
* </pre>
*
* @author Stefan Heule
- *
*/
-public class EqualToNode extends Node {
-
- protected BinaryTree tree;
- protected Node lhs;
- protected Node rhs;
+public class EqualToNode extends BinaryOperationNode {
- public EqualToNode(BinaryTree tree, Node lhs, Node rhs) {
- super(InternalUtils.typeOf(tree));
+ public EqualToNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind().equals(Kind.EQUAL_TO);
- this.tree = tree;
- this.lhs = lhs;
- this.rhs = rhs;
- }
-
- public Node getLeftOperand() {
- return lhs;
- }
-
- public Node getRightOperand() {
- return rhs;
- }
-
- @Override
- public BinaryTree getTree() {
- return tree;
}
@Override
@@ -71,12 +44,4 @@ public class EqualToNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ExplicitThisLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ExplicitThisLiteralNode.java
index 0c1069843c..abb3b5447e 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ExplicitThisLiteralNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ExplicitThisLiteralNode.java
@@ -1,9 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import org.checkerframework.javacutil.InternalUtils;
-
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.Tree;
+import org.checkerframework.javacutil.InternalUtils;
/**
* A node for a reference to 'this'.
@@ -14,7 +13,6 @@ import com.sun.source.tree.Tree;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class ExplicitThisLiteralNode extends ThisLiteralNode {
@@ -22,8 +20,7 @@ public class ExplicitThisLiteralNode extends ThisLiteralNode {
public ExplicitThisLiteralNode(Tree t) {
super(InternalUtils.typeOf(t));
- assert t instanceof IdentifierTree
- && ((IdentifierTree) t).getName().contentEquals("this");
+ assert t instanceof IdentifierTree && ((IdentifierTree) t).getName().contentEquals("this");
tree = t;
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FieldAccessNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FieldAccessNode.java
index db5bf51c5b..1b8e856a17 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FieldAccessNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FieldAccessNode.java
@@ -1,20 +1,16 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.IdentifierTree;
+import com.sun.source.tree.MemberSelectTree;
+import com.sun.source.tree.Tree;
import java.util.Collection;
import java.util.Collections;
-
import javax.lang.model.element.VariableElement;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-
import org.checkerframework.javacutil.ElementUtils;
import org.checkerframework.javacutil.InternalUtils;
import org.checkerframework.javacutil.TreeUtils;
-import com.sun.source.tree.IdentifierTree;
-import com.sun.source.tree.MemberSelectTree;
-import com.sun.source.tree.Tree;
-
/**
* A node for a field access, including a method accesses:
*
@@ -23,7 +19,6 @@ import com.sun.source.tree.Tree;
* </pre>
*
* @author Stefan Heule
- *
*/
public class FieldAccessNode extends Node {
@@ -45,7 +40,7 @@ public class FieldAccessNode extends Node {
this.element = (VariableElement) TreeUtils.elementFromUse((MemberSelectTree) tree);
} else {
assert tree instanceof IdentifierTree;
- this.element = (VariableElement) TreeUtils.elementFromUse((IdentifierTree) tree);
+ this.element = (VariableElement) TreeUtils.elementFromUse((IdentifierTree) tree);
}
}
@@ -84,9 +79,7 @@ public class FieldAccessNode extends Node {
return getReceiver() + "." + field;
}
- /**
- * Is this a static field?
- */
+ /** Is this a static field? */
public boolean isStatic() {
return ElementUtils.isStatic(getElement());
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatLiteralNode.java
index 518c974868..ee8b5103ed 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatLiteralNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatLiteralNode.java
@@ -1,10 +1,9 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.Collections;
-
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.Tree;
+import java.util.Collection;
+import java.util.Collections;
/**
* A node for a float literal. For example:
@@ -16,7 +15,6 @@ import com.sun.source.tree.Tree;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class FloatLiteralNode extends ValueLiteralNode {
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatingDivisionNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatingDivisionNode.java
index cd495b7b01..6eb6c41ac4 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatingDivisionNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatingDivisionNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for the floating-point division:
@@ -19,33 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class FloatingDivisionNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
+public class FloatingDivisionNode extends BinaryOperationNode {
- public FloatingDivisionNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
+ public FloatingDivisionNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind() == Kind.DIVIDE;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
-
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -72,12 +45,4 @@ public class FloatingDivisionNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatingRemainderNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatingRemainderNode.java
index d3b3caa0ab..d3a7918ff1 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatingRemainderNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FloatingRemainderNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for the floating-point remainder:
@@ -19,33 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class FloatingRemainderNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
+public class FloatingRemainderNode extends BinaryOperationNode {
- public FloatingRemainderNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
+ public FloatingRemainderNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind() == Kind.REMAINDER;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
-
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -72,12 +45,4 @@ public class FloatingRemainderNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FunctionalInterfaceNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FunctionalInterfaceNode.java
index 50c45daf2c..a0ddbaf10c 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FunctionalInterfaceNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/FunctionalInterfaceNode.java
@@ -3,24 +3,23 @@ package org.checkerframework.dataflow.cfg.node;
import com.sun.source.tree.LambdaExpressionTree;
import com.sun.source.tree.MemberReferenceTree;
import com.sun.source.tree.Tree;
-import org.checkerframework.javacutil.ErrorReporter;
-import org.checkerframework.javacutil.InternalUtils;
-
import java.util.Collection;
import java.util.LinkedList;
+import org.checkerframework.javacutil.ErrorReporter;
+import org.checkerframework.javacutil.InternalUtils;
/**
* A node for member references and lambdas.
*
- * The {@link Node#type} of a FunctionalInterfaceNode is determined by the
- * assignment context the member reference or lambda is used in.
+ * <p>The {@link Node#type} of a FunctionalInterfaceNode is determined by the assignment context the
+ * member reference or lambda is used in.
*
* <pre>
- * <em>FunctionalInterface func = param1, param2, ... -&gt; statement</em>
+ * <em>FunctionalInterface func = param1, param2, ... &rarr; statement</em>
* </pre>
*
* <pre>
- * <em>FunctionalInterface func = param1, param2, ... -&gt; { ... }</em>
+ * <em>FunctionalInterface func = param1, param2, ... &rarr; { ... }</em>
* </pre>
*
* <pre>
@@ -28,7 +27,6 @@ import java.util.LinkedList;
* </pre>
*
* @author David
- *
*/
public class FunctionalInterfaceNode extends Node {
@@ -56,7 +54,7 @@ public class FunctionalInterfaceNode extends Node {
@Override
public String toString() {
- if (tree instanceof LambdaExpressionTree){
+ if (tree instanceof LambdaExpressionTree) {
return "FunctionalInterfaceNode:" + ((LambdaExpressionTree) tree).getBodyKind();
} else if (tree instanceof MemberReferenceTree) {
return "FunctionalInterfaceNode:" + ((MemberReferenceTree) tree).getName();
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/GreaterThanNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/GreaterThanNode.java
index 7e51ccd115..f1713a9241 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/GreaterThanNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/GreaterThanNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for the greater than comparison:
@@ -19,33 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class GreaterThanNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
+public class GreaterThanNode extends BinaryOperationNode {
- public GreaterThanNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
+ public GreaterThanNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind() == Kind.GREATER_THAN;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
-
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -72,12 +45,4 @@ public class GreaterThanNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/GreaterThanOrEqualNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/GreaterThanOrEqualNode.java
index e23c824512..058ae7be84 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/GreaterThanOrEqualNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/GreaterThanOrEqualNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for the greater than or equal comparison:
@@ -19,33 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class GreaterThanOrEqualNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
+public class GreaterThanOrEqualNode extends BinaryOperationNode {
- public GreaterThanOrEqualNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
+ public GreaterThanOrEqualNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind() == Kind.GREATER_THAN_EQUAL;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
-
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -72,12 +45,4 @@ public class GreaterThanOrEqualNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ImplicitThisLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ImplicitThisLiteralNode.java
index 56bfa83e75..25a63617ad 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ImplicitThisLiteralNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ImplicitThisLiteralNode.java
@@ -1,14 +1,12 @@
package org.checkerframework.dataflow.cfg.node;
-import javax.lang.model.type.TypeMirror;
-
import com.sun.source.tree.Tree;
+import javax.lang.model.type.TypeMirror;
/**
- * A node to model the implicit <code>this</code>, e.g., in a field access.
+ * A node to model the implicit {@code this}, e.g., in a field access.
*
* @author Stefan Heule
- *
*/
public class ImplicitThisLiteralNode extends ThisLiteralNode {
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/InstanceOfNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/InstanceOfNode.java
index 2f49436da2..78b4e06916 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/InstanceOfNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/InstanceOfNode.java
@@ -1,25 +1,21 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.InstanceOfTree;
+import com.sun.source.tree.Tree;
import java.util.Collection;
import java.util.Collections;
-
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-import com.sun.source.tree.InstanceOfTree;
-import com.sun.source.tree.Tree;
-
/**
* A node for the instanceof operator:
*
- * <em>x</em> instanceof <em>Point</em>
+ * <p><em>x</em> instanceof <em>Point</em>
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class InstanceOfNode extends Node {
@@ -76,8 +72,7 @@ public class InstanceOfNode extends Node {
InstanceOfNode other = (InstanceOfNode) obj;
// TODO: TypeMirror.equals may be too restrictive.
// Check whether Types.isSameType is the better comparison.
- return getOperand().equals(other.getOperand())
- && getRefType().equals(other.getRefType());
+ return getOperand().equals(other.getOperand()) && getRefType().equals(other.getRefType());
}
@Override
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerDivisionNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerDivisionNode.java
index 0b5701413b..e69947bea5 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerDivisionNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerDivisionNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for the integer division:
@@ -19,33 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class IntegerDivisionNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
+public class IntegerDivisionNode extends BinaryOperationNode {
- public IntegerDivisionNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
+ public IntegerDivisionNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind() == Kind.DIVIDE;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
-
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -72,12 +45,4 @@ public class IntegerDivisionNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerLiteralNode.java
index b23a9cb512..5bea779369 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerLiteralNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerLiteralNode.java
@@ -1,10 +1,9 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.Collections;
-
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.Tree;
+import java.util.Collection;
+import java.util.Collections;
/**
* A node for an integer literal. For example:
@@ -14,7 +13,6 @@ import com.sun.source.tree.Tree;
* </pre>
*
* @author Stefan Heule
- *
*/
public class IntegerLiteralNode extends ValueLiteralNode {
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerRemainderNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerRemainderNode.java
index 39021cd2ab..d5399183a7 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerRemainderNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/IntegerRemainderNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for the integer remainder:
@@ -19,33 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class IntegerRemainderNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
+public class IntegerRemainderNode extends BinaryOperationNode {
- public IntegerRemainderNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
+ public IntegerRemainderNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind() == Kind.REMAINDER;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
-
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -72,12 +45,4 @@ public class IntegerRemainderNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LeftShiftNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LeftShiftNode.java
index 60652e6100..65a1e13d3c 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LeftShiftNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LeftShiftNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for bitwise left shift operations:
@@ -19,33 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class LeftShiftNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
+public class LeftShiftNode extends BinaryOperationNode {
- public LeftShiftNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
+ public LeftShiftNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind() == Kind.LEFT_SHIFT;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
-
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -72,12 +45,4 @@ public class LeftShiftNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LessThanNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LessThanNode.java
index a8dd5a18b4..fcc901150a 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LessThanNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LessThanNode.java
@@ -1,14 +1,9 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for the less than comparison:
@@ -21,33 +16,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class LessThanNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
+public class LessThanNode extends BinaryOperationNode {
- public LessThanNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
+ public LessThanNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind() == Kind.LESS_THAN;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
-
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -74,12 +48,4 @@ public class LessThanNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LessThanOrEqualNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LessThanOrEqualNode.java
index 4944ab66a0..0dfb65ec41 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LessThanOrEqualNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LessThanOrEqualNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for the less than or equal comparison:
@@ -19,33 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class LessThanOrEqualNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
+public class LessThanOrEqualNode extends BinaryOperationNode {
- public LessThanOrEqualNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
+ public LessThanOrEqualNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind() == Kind.LESS_THAN_EQUAL;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
-
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -72,12 +45,4 @@ public class LessThanOrEqualNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LocalVariableNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LocalVariableNode.java
index 5b18a71342..724d63a46b 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LocalVariableNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LocalVariableNode.java
@@ -1,19 +1,15 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.IdentifierTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.VariableTree;
import java.util.Collection;
import java.util.Collections;
-
import javax.lang.model.element.Element;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-
import org.checkerframework.javacutil.InternalUtils;
import org.checkerframework.javacutil.TreeUtils;
-import com.sun.source.tree.IdentifierTree;
-import com.sun.source.tree.Tree;
-import com.sun.source.tree.VariableTree;
-
/**
* A node for a local variable or a parameter:
*
@@ -21,11 +17,10 @@ import com.sun.source.tree.VariableTree;
* <em>identifier</em>
* </pre>
*
- * We allow local variable uses introduced by the {@link org.checkerframework.dataflow.cfg.CFGBuilder} without
- * corresponding AST {@link Tree}s.
+ * We allow local variable uses introduced by the {@link
+ * org.checkerframework.dataflow.cfg.CFGBuilder} without corresponding AST {@link Tree}s.
*
* @author Stefan Heule
- *
*/
// TODO: don't use for parameters, as they don't have a tree
public class LocalVariableNode extends Node {
@@ -58,11 +53,11 @@ public class LocalVariableNode extends Node {
}
return el;
}
-
+
public Node getReceiver() {
return receiver;
}
-
+
public String getName() {
if (tree instanceof IdentifierTree) {
return ((IdentifierTree) tree).getName().toString();
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LongLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LongLiteralNode.java
index 47f856a0d8..b92575ef90 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LongLiteralNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/LongLiteralNode.java
@@ -1,10 +1,9 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.Collections;
-
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.Tree;
+import java.util.Collection;
+import java.util.Collections;
/**
* A node for a long literal. For example:
@@ -16,7 +15,6 @@ import com.sun.source.tree.Tree;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class LongLiteralNode extends ValueLiteralNode {
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MarkerNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MarkerNode.java
index fa7238e1c6..a7a892f3be 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MarkerNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MarkerNode.java
@@ -4,27 +4,21 @@ package org.checkerframework.dataflow.cfg.node;
import org.checkerframework.checker.nullness.qual.Nullable;
*/
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
+import com.sun.source.tree.Tree;
import java.util.Collection;
import java.util.Collections;
-
import javax.lang.model.type.TypeKind;
import javax.lang.model.util.Types;
-
-import com.sun.source.tree.Tree;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
- * MarkerNodes are no-op Nodes used for debugging information.
- * They can hold a Tree and a message, which will be part of the
- * String representation of the MarkerNode.
+ * MarkerNodes are no-op Nodes used for debugging information. They can hold a Tree and a message,
+ * which will be part of the String representation of the MarkerNode.
*
- * An example use case for MarkerNodes is representing switch
- * statements.
+ * <p>An example use case for MarkerNodes is representing switch statements.
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class MarkerNode extends Node {
@@ -69,8 +63,7 @@ public class MarkerNode extends Node {
return false;
}
- return getTree().equals(other.getTree())
- && getMessage().equals(other.getMessage());
+ return getTree().equals(other.getTree()) && getMessage().equals(other.getMessage());
}
@Override
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MethodAccessNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MethodAccessNode.java
index 75a8d681d3..060f17b62d 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MethodAccessNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MethodAccessNode.java
@@ -1,18 +1,14 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.Tree;
import java.util.Collection;
import java.util.Collections;
-
import javax.lang.model.element.ExecutableElement;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-
import org.checkerframework.javacutil.InternalUtils;
import org.checkerframework.javacutil.TreeUtils;
-import com.sun.source.tree.ExpressionTree;
-import com.sun.source.tree.Tree;
-
/**
* A node for a method access, including a method accesses:
*
@@ -21,7 +17,6 @@ import com.sun.source.tree.Tree;
* </pre>
*
* @author Stefan Heule
- *
*/
public class MethodAccessNode extends Node {
@@ -68,8 +63,7 @@ public class MethodAccessNode extends Node {
return false;
}
MethodAccessNode other = (MethodAccessNode) obj;
- return getReceiver().equals(other.getReceiver())
- && getMethod().equals(other.getMethod());
+ return getReceiver().equals(other.getReceiver()) && getMethod().equals(other.getMethod());
}
@Override
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MethodInvocationNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MethodInvocationNode.java
index 797185a83b..9456f37808 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MethodInvocationNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/MethodInvocationNode.java
@@ -1,18 +1,15 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.MethodInvocationTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.TreePath;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
-
import org.checkerframework.dataflow.cfg.node.AssignmentContext.MethodParameterContext;
import org.checkerframework.dataflow.util.HashCodeUtils;
-
import org.checkerframework.javacutil.InternalUtils;
-import com.sun.source.tree.MethodInvocationTree;
-import com.sun.source.tree.Tree;
-import com.sun.source.util.TreePath;
-
/**
* A node for method invocation
*
@@ -20,12 +17,11 @@ import com.sun.source.util.TreePath;
* <em>target(arg1, arg2, ...)</em>
* </pre>
*
- * CFGs may contain {@link MethodInvocationNode}s that correspond to no AST
- * {@link Tree}, in which case, the tree field will be null.
+ * CFGs may contain {@link MethodInvocationNode}s that correspond to no AST {@link Tree}, in which
+ * case, the tree field will be null.
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class MethodInvocationNode extends Node {
@@ -34,8 +30,11 @@ public class MethodInvocationNode extends Node {
protected List<Node> arguments;
protected TreePath treePath;
- public MethodInvocationNode(MethodInvocationTree tree,
- MethodAccessNode target, List<Node> arguments, TreePath treePath) {
+ public MethodInvocationNode(
+ MethodInvocationTree tree,
+ MethodAccessNode target,
+ List<Node> arguments,
+ TreePath treePath) {
super(tree != null ? InternalUtils.typeOf(tree) : target.getMethod().getReturnType());
this.tree = tree;
this.target = target;
@@ -50,8 +49,7 @@ public class MethodInvocationNode extends Node {
}
}
- public MethodInvocationNode(MethodAccessNode target, List<Node> arguments,
- TreePath treePath) {
+ public MethodInvocationNode(MethodAccessNode target, List<Node> arguments, TreePath treePath) {
this(null, target, arguments, treePath);
}
@@ -105,8 +103,7 @@ public class MethodInvocationNode extends Node {
}
MethodInvocationNode other = (MethodInvocationNode) obj;
- return getTarget().equals(other.getTarget())
- && getArguments().equals(other.getArguments());
+ return getTarget().equals(other.getTarget()) && getArguments().equals(other.getArguments());
}
@Override
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NarrowingConversionNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NarrowingConversionNode.java
index f0165d9589..79a47283eb 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NarrowingConversionNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NarrowingConversionNode.java
@@ -1,27 +1,22 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.Tree;
import java.util.Collection;
import java.util.Collections;
-
import javax.lang.model.type.TypeMirror;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-
import org.checkerframework.javacutil.TypesUtils;
-import com.sun.source.tree.Tree;
-
/**
- * A node for the narrowing primitive conversion operation. See JLS 5.1.3 for
- * the definition of narrowing primitive conversion.
+ * A node for the narrowing primitive conversion operation. See JLS 5.1.3 for the definition of
+ * narrowing primitive conversion.
*
- * A {@link NarrowingConversionNode} does not correspond to any tree node in the
- * parsed AST. It is introduced when a value of some primitive type appears in a
- * context that requires a different primitive with more bits of precision.
+ * <p>A {@link NarrowingConversionNode} does not correspond to any tree node in the parsed AST. It
+ * is introduced when a value of some primitive type appears in a context that requires a different
+ * primitive with more bits of precision.
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class NarrowingConversionNode extends Node {
@@ -39,6 +34,7 @@ public class NarrowingConversionNode extends Node {
return operand;
}
+ @Override
public TypeMirror getType() {
return type;
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/Node.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/Node.java
index f59cc81bb8..fb5bf5335d 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/Node.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/Node.java
@@ -4,67 +4,52 @@ package org.checkerframework.dataflow.cfg.node;
import org.checkerframework.checker.nullness.qual.Nullable;
*/
-import org.checkerframework.dataflow.cfg.CFGBuilder;
-import org.checkerframework.dataflow.cfg.block.Block;
-
+import com.sun.source.tree.Tree;
import java.util.Collection;
import java.util.LinkedList;
-
import javax.lang.model.type.TypeMirror;
-
-import com.sun.source.tree.Tree;
+import org.checkerframework.dataflow.cfg.CFGBuilder;
+import org.checkerframework.dataflow.cfg.block.Block;
/**
- * A node in the abstract representation used for Java code inside a basic
- * block.
+ * A node in the abstract representation used for Java code inside a basic block.
*
- * <p>
- *
- * The following invariants hold:
+ * <p>The following invariants hold:
*
* <pre>
* block == null || block instanceof RegularBlock || block instanceof ExceptionBlock
- * block instanceof RegularBlock ==&gt; block.getContents().contains(this)
- * block instanceof ExceptionBlock ==&gt; block.getNode() == this
- * block == null &lt;==&gt; "This object represents a parameter of the method."
+ * block instanceof RegularBlock &rArr; block.getContents().contains(this)
+ * block instanceof ExceptionBlock &rArr; block.getNode() == this
+ * block == null &hArr; "This object represents a parameter of the method."
* </pre>
*
* <pre>
* type != null
- * tree != null ==&gt; node.getType() == InternalUtils.typeOf(node.getTree())
+ * tree != null &rArr; node.getType() == InternalUtils.typeOf(node.getTree())
* </pre>
*
* @author Stefan Heule
- *
*/
public abstract class Node {
- /**
- * The basic block this node belongs to (see invariant about this field
- * above).
- */
+ /** The basic block this node belongs to (see invariant about this field above). */
protected /*@Nullable*/ Block block;
- /**
- * Is this node an l-value?
- */
+ /** Is this node an l-value? */
protected boolean lvalue = false;
- /**
- * The assignment context of this node. See {@link AssignmentContext}.
- */
+ /** The assignment context of this node. See {@link AssignmentContext}. */
protected /*@Nullable*/ AssignmentContext assignmentContext;
/**
- * Does this node represent a tree that appears in the source code (true)
- * or one that the CFG builder added while desugaring (false).
+ * Does this node represent a tree that appears in the source code (true) or one that the CFG
+ * builder added while desugaring (false).
*/
protected boolean inSource = true;
/**
- * The type of this node. For {@link Node}s with {@link Tree}s, this type is
- * the type of the {@link Tree}. Otherwise, it is the type is set by the
- * {@link CFGBuilder}.
+ * The type of this node. For {@link Node}s with {@link Tree}s, this type is the type of the
+ * {@link Tree}. Otherwise, it is the type is set by the {@link CFGBuilder}.
*/
protected final TypeMirror type;
@@ -74,8 +59,8 @@ public abstract class Node {
}
/**
- * @return The basic block this node belongs to (or {@code null} if it
- * represents the parameter of a method).
+ * @return the basic block this node belongs to (or {@code null} if it represents the parameter
+ * of a method).
*/
public /*@Nullable*/ Block getBlock() {
return block;
@@ -87,19 +72,18 @@ public abstract class Node {
}
/**
- * Returns the {@link Tree} in the abstract syntax tree, or
- * <code>null</code> if no corresponding tree exists. For instance, this is
- * the case for an {@link ImplicitThisLiteralNode}.
+ * Returns the {@link Tree} in the abstract syntax tree, or {@code null} if no corresponding
+ * tree exists. For instance, this is the case for an {@link ImplicitThisLiteralNode}.
*
- * @return The corresponding {@link Tree} or <code>null</code>.
+ * @return the corresponding {@link Tree} or {@code null}.
*/
- abstract public /*@Nullable*/ Tree getTree();
+ public abstract /*@Nullable*/ Tree getTree();
/**
- * Returns a {@link TypeMirror} representing the type of a {@link Node} A
- * {@link Node} will always have a type even when it has no {@link Tree}.
+ * Returns a {@link TypeMirror} representing the type of a {@link Node} A {@link Node} will
+ * always have a type even when it has no {@link Tree}.
*
- * @return A {@link TypeMirror} representing the type of this {@link Node}.
+ * @return a {@link TypeMirror} representing the type of this {@link Node}
*/
public TypeMirror getType() {
return type;
@@ -108,14 +92,10 @@ public abstract class Node {
/**
* Accept method of the visitor pattern
*
- * @param <R>
- * Result type of the operation.
- * @param <P>
- * Parameter type.
- * @param visitor
- * The visitor to be applied to this node.
- * @param p
- * The parameter for this operation.
+ * @param <R> result type of the operation
+ * @param <P> parameter type
+ * @param visitor the visitor to be applied to this node
+ * @param p the parameter for this operation
*/
public abstract <R, P> R accept(NodeVisitor<R, P> visitor, P p);
@@ -123,9 +103,7 @@ public abstract class Node {
return lvalue;
}
- /**
- * Make this node an l-value.
- */
+ /** Make this node an l-value. */
public void setLValue() {
lvalue = true;
}
@@ -146,16 +124,12 @@ public abstract class Node {
this.assignmentContext = assignmentContext;
}
- /**
- * @return A collection containing all of the operand {@link Node}s of this
- * {@link Node}.
- */
+ /** @return a collection containing all of the operand {@link Node}s of this {@link Node}. */
public abstract Collection<Node> getOperands();
/**
- * @return A collection containing all of the operand {@link Node}s of this
- * {@link Node}, as well as (transitively) the operands of its
- * operands.
+ * @return a collection containing all of the operand {@link Node}s of this {@link Node}, as
+ * well as (transitively) the operands of its operands
*/
public Collection<Node> getTransitiveOperands() {
LinkedList<Node> operands = new LinkedList<>(getOperands());
@@ -167,5 +141,4 @@ public abstract class Node {
}
return transitiveOperands;
}
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NodeVisitor.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NodeVisitor.java
index fe751867a8..8a2f513924 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NodeVisitor.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NodeVisitor.java
@@ -4,13 +4,10 @@ package org.checkerframework.dataflow.cfg.node;
* A visitor for a {@link Node} tree.
*
* @author Stefan Heule
- *
- * @param <R>
- * Return type of the visitor. Use {@link Void} if the visitor does
- * not have a return value.
- * @param <P>
- * Parameter type of the visitor. Use {@link Void} if the visitor
- * does not have a parameter.
+ * @param <R> return type of the visitor. Use {@link Void} if the visitor does not have a return
+ * value.
+ * @param <P> parameter type of the visitor. Use {@link Void} if the visitor does not have a
+ * parameter.
*/
public interface NodeVisitor<R, P> {
// Literals
@@ -126,9 +123,9 @@ public interface NodeVisitor<R, P> {
R visitTypeCast(TypeCastNode n, P p);
// Blocks
-
+
R visitSynchronized(SynchronizedNode n, P p);
-
+
// Statements
R visitAssertionError(AssertionErrorNode n, P p);
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NotEqualNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NotEqualNode.java
index c043e20dee..debd7cbaf0 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NotEqualNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NotEqualNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for the not equal comparison:
@@ -19,33 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class NotEqualNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
+public class NotEqualNode extends BinaryOperationNode {
- public NotEqualNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
+ public NotEqualNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind() == Kind.NOT_EQUAL_TO;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
-
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -72,12 +45,4 @@ public class NotEqualNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullChkNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullChkNode.java
index 01ac008f40..6609a29b59 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullChkNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullChkNode.java
@@ -1,15 +1,12 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.Tree.Kind;
import java.util.Collection;
import java.util.Collections;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-
import org.checkerframework.javacutil.InternalUtils;
-import com.sun.source.tree.Tree;
-import com.sun.source.tree.Tree.Kind;
-
/**
* A node for the unary 'nullchk' operation (generated by the Java compiler):
*
@@ -22,51 +19,51 @@ import com.sun.source.tree.Tree.Kind;
*/
public class NullChkNode extends Node {
- protected Tree tree;
- protected Node operand;
+ protected Tree tree;
+ protected Node operand;
- public NullChkNode(Tree tree, Node operand) {
- super(InternalUtils.typeOf(tree));
- assert tree.getKind() == Kind.OTHER;
- this.tree = tree;
- this.operand = operand;
- }
+ public NullChkNode(Tree tree, Node operand) {
+ super(InternalUtils.typeOf(tree));
+ assert tree.getKind() == Kind.OTHER;
+ this.tree = tree;
+ this.operand = operand;
+ }
- public Node getOperand() {
- return operand;
- }
+ public Node getOperand() {
+ return operand;
+ }
- @Override
- public Tree getTree() {
- return tree;
- }
+ @Override
+ public Tree getTree() {
+ return tree;
+ }
- @Override
- public <R, P> R accept(NodeVisitor<R, P> visitor, P p) {
- return visitor.visitNullChk(this, p);
- }
+ @Override
+ public <R, P> R accept(NodeVisitor<R, P> visitor, P p) {
+ return visitor.visitNullChk(this, p);
+ }
- @Override
- public String toString() {
- return "(+ " + getOperand() + ")";
- }
+ @Override
+ public String toString() {
+ return "(+ " + getOperand() + ")";
+ }
- @Override
- public boolean equals(Object obj) {
- if (obj == null || !(obj instanceof NumericalPlusNode)) {
- return false;
- }
- NumericalPlusNode other = (NumericalPlusNode) obj;
- return getOperand().equals(other.getOperand());
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || !(obj instanceof NumericalPlusNode)) {
+ return false;
}
+ NumericalPlusNode other = (NumericalPlusNode) obj;
+ return getOperand().equals(other.getOperand());
+ }
- @Override
- public int hashCode() {
- return HashCodeUtils.hash(getOperand());
- }
+ @Override
+ public int hashCode() {
+ return HashCodeUtils.hash(getOperand());
+ }
- @Override
- public Collection<Node> getOperands() {
- return Collections.singletonList(getOperand());
- }
+ @Override
+ public Collection<Node> getOperands() {
+ return Collections.singletonList(getOperand());
}
+}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullLiteralNode.java
index 66e67152cd..1fcdeb4825 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullLiteralNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullLiteralNode.java
@@ -1,10 +1,9 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.Collections;
-
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.Tree;
+import java.util.Collection;
+import java.util.Collections;
/**
* A node for the null literal.
@@ -15,7 +14,6 @@ import com.sun.source.tree.Tree;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class NullLiteralNode extends ValueLiteralNode {
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalAdditionNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalAdditionNode.java
index d4192adf47..4692856dd8 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalAdditionNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalAdditionNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for the numerical addition:
@@ -18,34 +12,12 @@ import com.sun.source.tree.Tree.Kind;
* </pre>
*
* @author Stefan Heule
- *
*/
-public class NumericalAdditionNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
-
- public NumericalAdditionNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
- assert tree.getKind() == Kind.PLUS
- || tree.getKind() == Kind.PLUS_ASSIGNMENT;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
+public class NumericalAdditionNode extends BinaryOperationNode {
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
+ public NumericalAdditionNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
+ assert tree.getKind() == Kind.PLUS || tree.getKind() == Kind.PLUS_ASSIGNMENT;
}
@Override
@@ -72,12 +44,4 @@ public class NumericalAdditionNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalMinusNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalMinusNode.java
index 459f299262..141ab580e0 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalMinusNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalMinusNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.Collections;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
+import com.sun.source.tree.UnaryTree;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for the unary minus operation:
@@ -19,27 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class NumericalMinusNode extends Node {
+public class NumericalMinusNode extends UnaryOperationNode {
- protected Tree tree;
- protected Node operand;
-
- public NumericalMinusNode(Tree tree, Node operand) {
- super(InternalUtils.typeOf(tree));
+ public NumericalMinusNode(UnaryTree tree, Node operand) {
+ super(tree, operand);
assert tree.getKind() == Kind.UNARY_MINUS;
- this.tree = tree;
- this.operand = operand;
- }
-
- public Node getOperand() {
- return operand;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -65,9 +44,4 @@ public class NumericalMinusNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- return Collections.singletonList(getOperand());
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalMultiplicationNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalMultiplicationNode.java
index 947dc5dcde..85561a1a02 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalMultiplicationNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalMultiplicationNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for the numerical multiplication:
@@ -19,33 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class NumericalMultiplicationNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
+public class NumericalMultiplicationNode extends BinaryOperationNode {
- public NumericalMultiplicationNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
+ public NumericalMultiplicationNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind() == Kind.MULTIPLY;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
-
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -72,12 +45,4 @@ public class NumericalMultiplicationNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalPlusNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalPlusNode.java
index 3d19b278a7..21b5b584d2 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalPlusNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalPlusNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.Collections;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
+import com.sun.source.tree.UnaryTree;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for the unary plus operation:
@@ -19,27 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class NumericalPlusNode extends Node {
+public class NumericalPlusNode extends UnaryOperationNode {
- protected Tree tree;
- protected Node operand;
-
- public NumericalPlusNode(Tree tree, Node operand) {
- super(InternalUtils.typeOf(tree));
+ public NumericalPlusNode(UnaryTree tree, Node operand) {
+ super(tree, operand);
assert tree.getKind() == Kind.UNARY_PLUS;
- this.tree = tree;
- this.operand = operand;
- }
-
- public Node getOperand() {
- return operand;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -65,9 +44,4 @@ public class NumericalPlusNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- return Collections.singletonList(getOperand());
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalSubtractionNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalSubtractionNode.java
index 1526a18461..a962eadd78 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalSubtractionNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NumericalSubtractionNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for the numerical subtraction:
@@ -19,33 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class NumericalSubtractionNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
+public class NumericalSubtractionNode extends BinaryOperationNode {
- public NumericalSubtractionNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
+ public NumericalSubtractionNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind() == Kind.MINUS;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
-
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -72,12 +45,4 @@ public class NumericalSubtractionNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ObjectCreationNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ObjectCreationNode.java
index 67f2dee3bb..8ab862a2ef 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ObjectCreationNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ObjectCreationNode.java
@@ -1,16 +1,12 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.NewClassTree;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-
import org.checkerframework.javacutil.InternalUtils;
-import com.sun.source.tree.NewClassTree;
-import com.sun.source.tree.Tree;
-
/**
* A node for new object creation
*
@@ -20,7 +16,6 @@ import com.sun.source.tree.Tree;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class ObjectCreationNode extends Node {
@@ -28,9 +23,7 @@ public class ObjectCreationNode extends Node {
protected Node constructor;
protected List<Node> arguments;
- public ObjectCreationNode(NewClassTree tree,
- Node constructor,
- List<Node> arguments) {
+ public ObjectCreationNode(NewClassTree tree, Node constructor, List<Node> arguments) {
super(InternalUtils.typeOf(tree));
this.tree = tree;
this.constructor = constructor;
@@ -50,7 +43,7 @@ public class ObjectCreationNode extends Node {
}
@Override
- public Tree getTree() {
+ public NewClassTree getTree() {
return tree;
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/PackageNameNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/PackageNameNode.java
index 326ac5e43e..3c69b8252b 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/PackageNameNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/PackageNameNode.java
@@ -4,37 +4,30 @@ package org.checkerframework.dataflow.cfg.node;
import org.checkerframework.checker.nullness.qual.Nullable;
*/
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-import org.checkerframework.javacutil.TreeUtils;
-
-import java.util.Collection;
-import java.util.Collections;
-
-import javax.lang.model.element.Element;
-
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.Tree;
+import java.util.Collection;
+import java.util.Collections;
+import javax.lang.model.element.Element;
+import org.checkerframework.dataflow.util.HashCodeUtils;
+import org.checkerframework.javacutil.InternalUtils;
+import org.checkerframework.javacutil.TreeUtils;
/**
- * A node representing a package name used in an expression such as a
- * constructor invocation
+ * A node representing a package name used in an expression such as a constructor invocation
*
- * <p>
- * <em>package</em>.class.object(...)
- * <p>
- * parent.<em>package</em>.class.object(...)
+ * <p><em>package</em>.class.object(...)
+ *
+ * <p>parent.<em>package</em>.class.object(...)
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class PackageNameNode extends Node {
protected final Tree tree;
- // The package named by this node
+ /** The package named by this node */
protected final Element element;
/** The parent name, if any. */
@@ -84,11 +77,9 @@ public class PackageNameNode extends Node {
}
PackageNameNode other = (PackageNameNode) obj;
if (getParent() == null) {
- return other.getParent() == null
- && getElement().equals(other.getElement());
+ return other.getParent() == null && getElement().equals(other.getElement());
} else {
- return getParent().equals(other.getParent())
- && getElement().equals(other.getElement());
+ return getParent().equals(other.getParent()) && getElement().equals(other.getElement());
}
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ParameterizedTypeNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ParameterizedTypeNode.java
index 7939b41fa7..774ac8b7c5 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ParameterizedTypeNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ParameterizedTypeNode.java
@@ -1,15 +1,12 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.ParameterizedTypeTree;
+import com.sun.source.tree.Tree;
import java.util.Collection;
import java.util.Collections;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-
import org.checkerframework.javacutil.InternalUtils;
-import com.sun.source.tree.ParameterizedTypeTree;
-import com.sun.source.tree.Tree;
-
/**
* A node for a parameterized type occurring in an expression:
*
@@ -17,16 +14,13 @@ import com.sun.source.tree.Tree;
* <em>type&lt;arg1, arg2&gt;</em>
* </pre>
*
- * Parameterized types don't represent any computation to be done
- * at runtime, so we might choose to represent them differently by
- * modifying the {@link Node}s in which parameterized types can occur, such
- * as {@link ObjectCreationNode}s.
+ * Parameterized types don't represent any computation to be done at runtime, so we might choose to
+ * represent them differently by modifying the {@link Node}s in which parameterized types can occur,
+ * such as {@link ObjectCreationNode}s.
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-
public class ParameterizedTypeNode extends Node {
protected Tree tree;
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/PrimitiveTypeNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/PrimitiveTypeNode.java
index 69b185641d..379bb92024 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/PrimitiveTypeNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/PrimitiveTypeNode.java
@@ -1,24 +1,19 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.PrimitiveTypeTree;
+import com.sun.source.tree.Tree;
import java.util.Collection;
import java.util.Collections;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-
import org.checkerframework.javacutil.InternalUtils;
-import com.sun.source.tree.PrimitiveTypeTree;
-import com.sun.source.tree.Tree;
-
/**
- * A node representing a primitive type used in an expression
- * such as a field access
+ * A node representing a primitive type used in an expression such as a field access
*
- * <em>type</em> .class
+ * <p><em>type</em> .class
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class PrimitiveTypeNode extends Node {
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ReturnNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ReturnNode.java
index dbc74c83e3..b7222dfa18 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ReturnNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ReturnNode.java
@@ -5,19 +5,16 @@ import org.checkerframework.checker.nullness.qual.Nullable;
*/
import com.sun.source.tree.LambdaExpressionTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.ReturnTree;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
-import org.checkerframework.dataflow.cfg.node.AssignmentContext.LambdaReturnContext;
-import org.checkerframework.dataflow.cfg.node.AssignmentContext.MethodReturnContext;
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
import java.util.Collection;
import java.util.Collections;
-
import javax.lang.model.type.TypeKind;
import javax.lang.model.util.Types;
-
-import com.sun.source.tree.MethodTree;
-import com.sun.source.tree.ReturnTree;
+import org.checkerframework.dataflow.cfg.node.AssignmentContext.LambdaReturnContext;
+import org.checkerframework.dataflow.cfg.node.AssignmentContext.MethodReturnContext;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for a return statement:
@@ -28,7 +25,6 @@ import com.sun.source.tree.ReturnTree;
* </pre>
*
* @author Stefan Heule
- *
*/
public class ReturnNode extends Node {
@@ -42,14 +38,18 @@ public class ReturnNode extends Node {
result.setAssignmentContext(new MethodReturnContext(methodTree));
}
- public ReturnNode(ReturnTree t, /*@Nullable*/ Node result, Types types, LambdaExpressionTree lambda, MethodSymbol methodSymbol) {
+ public ReturnNode(
+ ReturnTree t,
+ /*@Nullable*/ Node result,
+ Types types,
+ LambdaExpressionTree lambda,
+ MethodSymbol methodSymbol) {
super(types.getNoType(TypeKind.NONE));
this.result = result;
tree = t;
result.setAssignmentContext(new LambdaReturnContext(methodSymbol));
}
-
public Node getResult() {
return result;
}
@@ -97,5 +97,4 @@ public class ReturnNode extends Node {
return Collections.singletonList(result);
}
}
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ShortLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ShortLiteralNode.java
index f61da82397..cd1db1e560 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ShortLiteralNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ShortLiteralNode.java
@@ -1,10 +1,9 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.Collections;
-
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.Tree;
+import java.util.Collection;
+import java.util.Collections;
/**
* A node for a short literal. For example:
@@ -14,14 +13,12 @@ import com.sun.source.tree.Tree;
* <em>0x8fff</em>
* </pre>
*
- * Java source and the AST representation do not have "short" literals. They
- * have integer literals that may be narrowed to shorts depending on context. If
- * we use explicit NarrowingConversionNodes, do we need ShortLiteralNodes too?
- * TODO: Decide this question.
+ * Java source and the AST representation do not have "short" literals. They have integer literals
+ * that may be narrowed to shorts depending on context. If we use explicit NarrowingConversionNodes,
+ * do we need ShortLiteralNodes too? TODO: Decide this question.
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class ShortLiteralNode extends ValueLiteralNode {
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SignedRightShiftNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SignedRightShiftNode.java
index 3683ab9a3c..ac4aa58783 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SignedRightShiftNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SignedRightShiftNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for bitwise right shift operations with sign extension:
@@ -19,33 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class SignedRightShiftNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
+public class SignedRightShiftNode extends BinaryOperationNode {
- public SignedRightShiftNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
+ public SignedRightShiftNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind() == Kind.RIGHT_SHIFT;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
-
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -72,12 +45,4 @@ public class SignedRightShiftNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConcatenateAssignmentNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConcatenateAssignmentNode.java
index d6c4c532b0..0e6f006d7e 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConcatenateAssignmentNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConcatenateAssignmentNode.java
@@ -1,13 +1,11 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.Tree.Kind;
import java.util.Collection;
import java.util.LinkedList;
-
import org.checkerframework.javacutil.InternalUtils;
-import com.sun.source.tree.Tree;
-import com.sun.source.tree.Tree.Kind;
-
/**
* A node for the string concatenation compound assignment:
*
@@ -17,7 +15,6 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class StringConcatenateAssignmentNode extends Node {
protected Tree tree;
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConcatenateNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConcatenateNode.java
index e42d6ac7db..c69beea694 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConcatenateNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConcatenateNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for string concatenation:
@@ -19,33 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class StringConcatenateNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
+public class StringConcatenateNode extends BinaryOperationNode {
- public StringConcatenateNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
+ public StringConcatenateNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind() == Kind.PLUS;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
-
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -72,12 +45,4 @@ public class StringConcatenateNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConversionNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConversionNode.java
index 2f62c8af9a..8ba8c6ff60 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConversionNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringConversionNode.java
@@ -1,31 +1,25 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.Tree;
import java.util.Collection;
import java.util.Collections;
-
import javax.lang.model.type.TypeMirror;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-import com.sun.source.tree.Tree;
-
/**
- * A node for the string conversion operation. See JLS 5.1.11 for the definition
- * of string conversion.
+ * A node for the string conversion operation. See JLS 5.1.11 for the definition of string
+ * conversion.
*
- * A {@link StringConversionNode} does not correspond to any tree node in the
- * parsed AST. It is introduced when a value of non-string type appears in a
- * context that requires a {@link String}, such as in a string concatenation. A
- * {@link StringConversionNode} should be treated as a potential call to the
- * toString method of its operand, but does not necessarily call any method
+ * <p>A {@link StringConversionNode} does not correspond to any tree node in the parsed AST. It is
+ * introduced when a value of non-string type appears in a context that requires a {@link String},
+ * such as in a string concatenation. A {@link StringConversionNode} should be treated as a
+ * potential call to the toString method of its operand, but does not necessarily call any method
* because null is converted to the string "null".
*
- * Conversion of primitive types to Strings requires first boxing and then
- * string conversion.
+ * <p>Conversion of primitive types to Strings requires first boxing and then string conversion.
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class StringConversionNode extends Node {
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringLiteralNode.java
index e8d9291c55..c6ec1c90b8 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringLiteralNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/StringLiteralNode.java
@@ -1,10 +1,9 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.Collections;
-
import com.sun.source.tree.LiteralTree;
import com.sun.source.tree.Tree;
+import java.util.Collection;
+import java.util.Collections;
/**
* A node for an string literal. For example:
@@ -14,7 +13,6 @@ import com.sun.source.tree.Tree;
* </pre>
*
* @author Stefan Heule
- *
*/
public class StringLiteralNode extends ValueLiteralNode {
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SuperNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SuperNode.java
index d6ce410285..797eae8e7a 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SuperNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SuperNode.java
@@ -1,15 +1,12 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.IdentifierTree;
+import com.sun.source.tree.Tree;
import java.util.Collection;
import java.util.Collections;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-
import org.checkerframework.javacutil.InternalUtils;
-import com.sun.source.tree.IdentifierTree;
-import com.sun.source.tree.Tree;
-
/**
* A node for a reference to 'super'.
*
@@ -19,7 +16,6 @@ import com.sun.source.tree.Tree;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class SuperNode extends Node {
@@ -27,8 +23,7 @@ public class SuperNode extends Node {
public SuperNode(Tree t) {
super(InternalUtils.typeOf(t));
- assert t instanceof IdentifierTree
- && ((IdentifierTree) t).getName().contentEquals("super");
+ assert t instanceof IdentifierTree && ((IdentifierTree) t).getName().contentEquals("super");
tree = t;
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SynchronizedNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SynchronizedNode.java
index 86d28bd87e..a17e2fa2e8 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SynchronizedNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/SynchronizedNode.java
@@ -10,15 +10,12 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* Otherwise it is the node immediately after a synchronized code block.
*/
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
+import com.sun.source.tree.Tree;
import java.util.Collection;
import java.util.Collections;
-
import javax.lang.model.type.TypeKind;
import javax.lang.model.util.Types;
-
-import com.sun.source.tree.Tree;
+import org.checkerframework.dataflow.util.HashCodeUtils;
public class SynchronizedNode extends Node {
@@ -26,7 +23,8 @@ public class SynchronizedNode extends Node {
protected Node expression;
protected boolean startOfBlock;
- public SynchronizedNode(/*@Nullable*/ Tree tree, Node expression, boolean startOfBlock, Types types) {
+ public SynchronizedNode(
+ /*@Nullable*/ Tree tree, Node expression, boolean startOfBlock, Types types) {
super(types.getNoType(TypeKind.NONE));
this.tree = tree;
this.expression = expression;
@@ -88,4 +86,4 @@ public class SynchronizedNode extends Node {
public Collection<Node> getOperands() {
return Collections.emptyList();
}
-} \ No newline at end of file
+}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/TernaryExpressionNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/TernaryExpressionNode.java
index 514f85944d..9a149a3325 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/TernaryExpressionNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/TernaryExpressionNode.java
@@ -1,15 +1,12 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.ConditionalExpressionTree;
+import com.sun.source.tree.Tree.Kind;
import java.util.Collection;
import java.util.LinkedList;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-
import org.checkerframework.javacutil.InternalUtils;
-import com.sun.source.tree.ConditionalExpressionTree;
-import com.sun.source.tree.Tree.Kind;
-
/**
* A node for a conditional expression:
*
@@ -19,7 +16,6 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class TernaryExpressionNode extends Node {
@@ -28,8 +24,8 @@ public class TernaryExpressionNode extends Node {
protected Node thenOperand;
protected Node elseOperand;
- public TernaryExpressionNode(ConditionalExpressionTree tree, Node condition,
- Node thenOperand, Node elseOperand) {
+ public TernaryExpressionNode(
+ ConditionalExpressionTree tree, Node condition, Node thenOperand, Node elseOperand) {
super(InternalUtils.typeOf(tree));
assert tree.getKind().equals(Kind.CONDITIONAL_EXPRESSION);
this.tree = tree;
@@ -62,8 +58,13 @@ public class TernaryExpressionNode extends Node {
@Override
public String toString() {
- return "(" + getConditionOperand() + " ? " + getThenOperand() + " : "
- + getElseOperand() + ")";
+ return "("
+ + getConditionOperand()
+ + " ? "
+ + getThenOperand()
+ + " : "
+ + getElseOperand()
+ + ")";
}
@Override
@@ -79,8 +80,7 @@ public class TernaryExpressionNode extends Node {
@Override
public int hashCode() {
- return HashCodeUtils.hash(getConditionOperand(), getThenOperand(),
- getElseOperand());
+ return HashCodeUtils.hash(getConditionOperand(), getThenOperand(), getElseOperand());
}
@Override
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ThisLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ThisLiteralNode.java
index f62d6ac675..3bb4c186e6 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ThisLiteralNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ThisLiteralNode.java
@@ -2,9 +2,7 @@ package org.checkerframework.dataflow.cfg.node;
import java.util.Collection;
import java.util.Collections;
-
import javax.lang.model.type.TypeMirror;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
/**
@@ -16,7 +14,6 @@ import org.checkerframework.dataflow.util.HashCodeUtils;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public abstract class ThisLiteralNode extends Node {
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ThrowNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ThrowNode.java
index f563cef96b..bb36e10a4a 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ThrowNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ThrowNode.java
@@ -1,16 +1,13 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.ThrowTree;
+import com.sun.source.tree.Tree;
import java.util.Collection;
import java.util.Collections;
-
import javax.lang.model.type.TypeKind;
import javax.lang.model.util.Types;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-import com.sun.source.tree.ThrowTree;
-import com.sun.source.tree.Tree;
-
/**
* A node for exception throws:
*
@@ -20,15 +17,13 @@ import com.sun.source.tree.Tree;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class ThrowNode extends Node {
protected ThrowTree tree;
protected Node expression;
- public ThrowNode(ThrowTree tree,
- Node expression, Types types) {
+ public ThrowNode(ThrowTree tree, Node expression, Types types) {
super(types.getNoType(TypeKind.NONE));
this.tree = tree;
this.expression = expression;
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/TypeCastNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/TypeCastNode.java
index ce287a5cb6..f6e71bf6aa 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/TypeCastNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/TypeCastNode.java
@@ -1,22 +1,18 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.Tree;
import java.util.Collection;
import java.util.Collections;
-
import javax.lang.model.type.TypeMirror;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-import com.sun.source.tree.Tree;
-
/**
* A node for the cast operator:
*
- * (<em>Point</em>) <em>x</em>
+ * <p>(<em>Point</em>) <em>x</em>
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class TypeCastNode extends Node {
@@ -33,6 +29,7 @@ public class TypeCastNode extends Node {
return operand;
}
+ @Override
public TypeMirror getType() {
return type;
}
@@ -60,8 +57,7 @@ public class TypeCastNode extends Node {
TypeCastNode other = (TypeCastNode) obj;
// TODO: TypeMirror.equals may be too restrictive.
// Check whether Types.isSameType is the better comparison.
- return getOperand().equals(other.getOperand())
- && getType().equals(other.getType());
+ return getOperand().equals(other.getOperand()) && getType().equals(other.getType());
}
@Override
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/UnaryOperationNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/UnaryOperationNode.java
new file mode 100644
index 0000000000..cb33e6a3f1
--- /dev/null
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/UnaryOperationNode.java
@@ -0,0 +1,45 @@
+package org.checkerframework.dataflow.cfg.node;
+
+import com.sun.source.tree.UnaryTree;
+import java.util.Collection;
+import java.util.Collections;
+import org.checkerframework.javacutil.InternalUtils;
+
+/**
+ * A node for a postfix or an unary expression.
+ *
+ * <p>For example:
+ *
+ * <pre>
+ * <em>operator</em> <em>expressionNode</em>
+ *
+ * <em>expressionNode</em> <em>operator</em>
+ * </pre>
+ *
+ * @author charleszhuochen
+ */
+public abstract class UnaryOperationNode extends Node {
+
+ protected final UnaryTree tree;
+ protected final Node operand;
+
+ public UnaryOperationNode(UnaryTree tree, Node operand) {
+ super(InternalUtils.typeOf(tree));
+ this.tree = tree;
+ this.operand = operand;
+ }
+
+ public Node getOperand() {
+ return this.operand;
+ }
+
+ @Override
+ public UnaryTree getTree() {
+ return tree;
+ }
+
+ @Override
+ public Collection<Node> getOperands() {
+ return Collections.singletonList(getOperand());
+ }
+}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/UnsignedRightShiftNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/UnsignedRightShiftNode.java
index 0ddea5b6c6..2609a7d7ae 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/UnsignedRightShiftNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/UnsignedRightShiftNode.java
@@ -1,14 +1,8 @@
package org.checkerframework.dataflow.cfg.node;
-import java.util.Collection;
-import java.util.LinkedList;
-
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
-import com.sun.source.tree.Tree;
+import com.sun.source.tree.BinaryTree;
import com.sun.source.tree.Tree.Kind;
+import org.checkerframework.dataflow.util.HashCodeUtils;
/**
* A node for bitwise right shift operations with zero extension:
@@ -19,33 +13,12 @@ import com.sun.source.tree.Tree.Kind;
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
-public class UnsignedRightShiftNode extends Node {
-
- protected Tree tree;
- protected Node left;
- protected Node right;
+public class UnsignedRightShiftNode extends BinaryOperationNode {
- public UnsignedRightShiftNode(Tree tree, Node left, Node right) {
- super(InternalUtils.typeOf(tree));
+ public UnsignedRightShiftNode(BinaryTree tree, Node left, Node right) {
+ super(tree, left, right);
assert tree.getKind() == Kind.UNSIGNED_RIGHT_SHIFT;
- this.tree = tree;
- this.left = left;
- this.right = right;
- }
-
- public Node getLeftOperand() {
- return left;
- }
-
- public Node getRightOperand() {
- return right;
- }
-
- @Override
- public Tree getTree() {
- return tree;
}
@Override
@@ -72,12 +45,4 @@ public class UnsignedRightShiftNode extends Node {
public int hashCode() {
return HashCodeUtils.hash(getLeftOperand(), getRightOperand());
}
-
- @Override
- public Collection<Node> getOperands() {
- LinkedList<Node> list = new LinkedList<Node>();
- list.add(getLeftOperand());
- list.add(getRightOperand());
- return list;
- }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ValueLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ValueLiteralNode.java
index 68058d3ccc..4c9c18f0af 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ValueLiteralNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/ValueLiteralNode.java
@@ -1,13 +1,10 @@
package org.checkerframework.dataflow.cfg.node;
-import org.checkerframework.dataflow.util.HashCodeUtils;
-
-import org.checkerframework.javacutil.InternalUtils;
-
+import com.sun.source.tree.LiteralTree;
import java.util.Collection;
import java.util.Collections;
-
-import com.sun.source.tree.LiteralTree;
+import org.checkerframework.dataflow.util.HashCodeUtils;
+import org.checkerframework.javacutil.InternalUtils;
/*>>>
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -15,28 +12,26 @@ import org.checkerframework.checker.nullness.qual.Nullable;
/**
* A node for a literals that have some form of value:
+ *
* <ul>
- * <li>integer literal</li>
- * <li>long literal</li>
- * <li>char literal</li>
- * <li>string literal</li>
- * <li>float literal</li>
- * <li>double literal</li>
- * <li>boolean literal</li>
- * <li>null literal</li>
+ * <li>integer literal
+ * <li>long literal
+ * <li>char literal
+ * <li>string literal
+ * <li>float literal
+ * <li>double literal
+ * <li>boolean literal
+ * <li>null literal
* </ul>
*
* @author Stefan Heule
- *
*/
public abstract class ValueLiteralNode extends Node {
protected final LiteralTree tree;
- /**
- * @return The value of the literal.
- */
- abstract public /*@Nullable*/ Object getValue();
+ /** @return the value of the literal */
+ public abstract /*@Nullable*/ Object getValue();
public ValueLiteralNode(LiteralTree tree) {
super(InternalUtils.typeOf(tree));
@@ -53,9 +48,7 @@ public abstract class ValueLiteralNode extends Node {
return String.valueOf(getValue());
}
- /**
- * Compare the value of this nodes.
- */
+ /** Compare the value of this nodes. */
@Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof ValueLiteralNode)) {
@@ -76,5 +69,4 @@ public abstract class ValueLiteralNode extends Node {
public Collection<Node> getOperands() {
return Collections.emptyList();
}
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/VariableDeclarationNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/VariableDeclarationNode.java
index 5841768e38..867cdf1ad9 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/VariableDeclarationNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/VariableDeclarationNode.java
@@ -1,14 +1,11 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.VariableTree;
import java.util.Collection;
import java.util.Collections;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-
import org.checkerframework.javacutil.InternalUtils;
-import com.sun.source.tree.VariableTree;
-
/**
* A node for a local variable declaration:
*
@@ -16,11 +13,10 @@ import com.sun.source.tree.VariableTree;
* <em>modifier</em> <em>type</em> <em>identifier</em>;
* </pre>
*
- * Note: Does not have an initializer block, as that will be translated to a
- * separate {@link AssignmentNode}.
+ * Note: Does not have an initializer block, as that will be translated to a separate {@link
+ * AssignmentNode}.
*
* @author Stefan Heule
- *
*/
public class VariableDeclarationNode extends Node {
@@ -72,5 +68,4 @@ public class VariableDeclarationNode extends Node {
public Collection<Node> getOperands() {
return Collections.emptyList();
}
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/WideningConversionNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/WideningConversionNode.java
index 4724ec1066..9b949ea546 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/WideningConversionNode.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/WideningConversionNode.java
@@ -1,27 +1,22 @@
package org.checkerframework.dataflow.cfg.node;
+import com.sun.source.tree.Tree;
import java.util.Collection;
import java.util.Collections;
-
import javax.lang.model.type.TypeMirror;
-
import org.checkerframework.dataflow.util.HashCodeUtils;
-
import org.checkerframework.javacutil.TypesUtils;
-import com.sun.source.tree.Tree;
-
/**
- * A node for the widening primitive conversion operation. See JLS 5.1.2 for the
- * definition of widening primitive conversion.
+ * A node for the widening primitive conversion operation. See JLS 5.1.2 for the definition of
+ * widening primitive conversion.
*
- * A {@link WideningConversionNode} does not correspond to any tree node in the
- * parsed AST. It is introduced when a value of some primitive type appears in a
- * context that requires a different primitive with more bits of precision.
+ * <p>A {@link WideningConversionNode} does not correspond to any tree node in the parsed AST. It is
+ * introduced when a value of some primitive type appears in a context that requires a different
+ * primitive with more bits of precision.
*
* @author Stefan Heule
* @author Charlie Garrett
- *
*/
public class WideningConversionNode extends Node {
@@ -39,6 +34,7 @@ public class WideningConversionNode extends Node {
return operand;
}
+ @Override
public TypeMirror getType() {
return type;
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/playground/ConstantPropagationPlayground.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/playground/ConstantPropagationPlayground.java
index 25cf73995a..79088386a9 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/playground/ConstantPropagationPlayground.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/playground/ConstantPropagationPlayground.java
@@ -8,26 +8,20 @@ import org.checkerframework.dataflow.constantpropagation.ConstantPropagationTran
public class ConstantPropagationPlayground {
- /**
- * Run constant propagation for a specific file and create a PDF of the CFG
- * in the end.
- */
+ /** Run constant propagation for a specific file and create a PDF of the CFG in the end. */
public static void main(String[] args) {
/* Configuration: change as appropriate */
String inputFile = "cfg-input.java"; // input file name and path
- String outputFileName = "cfg"; // output file name and path (without
- // extension)
+ String outputDir = "cfg"; // output directory
String method = "test"; // name of the method to analyze
String clazz = "Test"; // name of the class to consider
// run the analysis and create a PDF file
ConstantPropagationTransfer transfer = new ConstantPropagationTransfer();
// TODO: correct processing environment
- Analysis<Constant, ConstantPropagationStore, ConstantPropagationTransfer> analysis = new Analysis<>(
- null, transfer);
- JavaSource2CFGDOT.generateDOTofCFG(inputFile, outputFileName, method,
- clazz, true, analysis);
+ Analysis<Constant, ConstantPropagationStore, ConstantPropagationTransfer> analysis =
+ new Analysis<>(null, transfer);
+ JavaSource2CFGDOT.generateDOTofCFG(inputFile, outputDir, method, clazz, true, analysis);
}
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/Constant.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/Constant.java
index f63c23202e..a95af7fa43 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/Constant.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/Constant.java
@@ -5,7 +5,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
*/
import java.util.Objects;
-
import org.checkerframework.dataflow.analysis.AbstractValue;
public class Constant implements AbstractValue<Constant> {
@@ -17,7 +16,9 @@ public class Constant implements AbstractValue<Constant> {
protected /*@Nullable*/ Integer value;
public enum Type {
- CONSTANT, TOP, BOTTOM,
+ CONSTANT,
+ TOP,
+ BOTTOM,
}
public Constant(Type type) {
@@ -56,12 +57,15 @@ public class Constant implements AbstractValue<Constant> {
@Override
public Constant leastUpperBound(Constant other) {
- if (other.isBottom())
+ if (other.isBottom()) {
return this.copy();
- if (this.isBottom())
+ }
+ if (this.isBottom()) {
return other.copy();
- if (other.isTop() || this.isTop())
+ }
+ if (other.isTop() || this.isTop()) {
return new Constant(Type.TOP);
+ }
if (other.getValue().equals(getValue())) {
return this.copy();
}
@@ -70,8 +74,9 @@ public class Constant implements AbstractValue<Constant> {
@Override
public boolean equals(Object obj) {
- if (obj == null || !(obj instanceof Constant))
+ if (obj == null || !(obj instanceof Constant)) {
return false;
+ }
Constant other = (Constant) obj;
return type == other.type && Objects.equals(value, other.value);
}
@@ -84,12 +89,12 @@ public class Constant implements AbstractValue<Constant> {
@Override
public String toString() {
switch (type) {
- case TOP:
- return "T";
- case BOTTOM:
- return "-";
- case CONSTANT:
- return value.toString();
+ case TOP:
+ return "T";
+ case BOTTOM:
+ return "-";
+ case CONSTANT:
+ return value.toString();
}
assert false;
return "???";
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationStore.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationStore.java
index 3c96f8fd82..e7a718ee5b 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationStore.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationStore.java
@@ -3,16 +3,15 @@ package org.checkerframework.dataflow.constantpropagation;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
-
import org.checkerframework.dataflow.analysis.FlowExpressions;
import org.checkerframework.dataflow.analysis.Store;
+import org.checkerframework.dataflow.cfg.CFGVisualizer;
import org.checkerframework.dataflow.cfg.node.IntegerLiteralNode;
import org.checkerframework.dataflow.cfg.node.LocalVariableNode;
import org.checkerframework.dataflow.cfg.node.Node;
import org.checkerframework.dataflow.constantpropagation.Constant.Type;
-public class ConstantPropagationStore implements
- Store<ConstantPropagationStore> {
+public class ConstantPropagationStore implements Store<ConstantPropagationStore> {
/** Information about variables gathered so far. */
Map<Node, Constant> contents;
@@ -40,15 +39,13 @@ public class ConstantPropagationStore implements
value = val;
}
// TODO: remove (only two nodes supported atm)
- assert n instanceof IntegerLiteralNode
- || n instanceof LocalVariableNode;
+ assert n instanceof IntegerLiteralNode || n instanceof LocalVariableNode;
contents.put(n, value);
}
public void setInformation(Node n, Constant val) {
// TODO: remove (only two nodes supported atm)
- assert n instanceof IntegerLiteralNode
- || n instanceof LocalVariableNode;
+ assert n instanceof IntegerLiteralNode || n instanceof LocalVariableNode;
contents.put(n, val);
}
@@ -58,8 +55,7 @@ public class ConstantPropagationStore implements
}
@Override
- public ConstantPropagationStore leastUpperBound(
- ConstantPropagationStore other) {
+ public ConstantPropagationStore leastUpperBound(ConstantPropagationStore other) {
Map<Node, Constant> newContents = new HashMap<>();
// go through all of the information of the other class
@@ -88,18 +84,26 @@ public class ConstantPropagationStore implements
}
@Override
+ public ConstantPropagationStore widenedUpperBound(ConstantPropagationStore previous) {
+ return leastUpperBound(previous);
+ }
+
+ @Override
public boolean equals(Object o) {
- if (o == null)
+ if (o == null) {
return false;
- if (!(o instanceof ConstantPropagationStore))
+ }
+ if (!(o instanceof ConstantPropagationStore)) {
return false;
+ }
ConstantPropagationStore other = (ConstantPropagationStore) o;
// go through all of the information of the other object
for (Entry<Node, Constant> e : other.contents.entrySet()) {
Node n = e.getKey();
Constant otherVal = e.getValue();
- if (otherVal.isBottom())
+ if (otherVal.isBottom()) {
continue; // no information
+ }
if (contents.containsKey(n)) {
if (!otherVal.equals(contents.get(n))) {
return false;
@@ -112,8 +116,9 @@ public class ConstantPropagationStore implements
for (Entry<Node, Constant> e : contents.entrySet()) {
Node n = e.getKey();
Constant thisVal = e.getValue();
- if (thisVal.isBottom())
+ if (thisVal.isBottom()) {
continue; // no information
+ }
if (other.contents.containsKey(n)) {
continue;
} else {
@@ -147,19 +152,12 @@ public class ConstantPropagationStore implements
}
@Override
- public boolean canAlias(FlowExpressions.Receiver a,
- FlowExpressions.Receiver b) {
+ public boolean canAlias(FlowExpressions.Receiver a, FlowExpressions.Receiver b) {
return true;
}
@Override
- public boolean hasDOToutput() {
- return false;
- }
-
- @Override
- public String toDOToutput() {
- return "";
+ public void visualize(CFGVisualizer<?, ConstantPropagationStore, ?> viz) {
+ // Do nothing since ConstantPropagationStore doesn't support visualize
}
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationTransfer.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationTransfer.java
index 434bb96433..d5da13a518 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationTransfer.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationTransfer.java
@@ -1,7 +1,6 @@
package org.checkerframework.dataflow.constantpropagation;
import java.util.List;
-
import org.checkerframework.dataflow.analysis.ConditionalTransferResult;
import org.checkerframework.dataflow.analysis.RegularTransferResult;
import org.checkerframework.dataflow.analysis.TransferFunction;
@@ -15,39 +14,36 @@ import org.checkerframework.dataflow.cfg.node.IntegerLiteralNode;
import org.checkerframework.dataflow.cfg.node.LocalVariableNode;
import org.checkerframework.dataflow.cfg.node.Node;
-import com.sun.tools.javac.tree.JCTree.JCIdent;
-
-
public class ConstantPropagationTransfer
- extends
- AbstractNodeVisitor<TransferResult<Constant, ConstantPropagationStore>, TransferInput<Constant, ConstantPropagationStore>>
+ extends AbstractNodeVisitor<
+ TransferResult<Constant, ConstantPropagationStore>,
+ TransferInput<Constant, ConstantPropagationStore>>
implements TransferFunction<Constant, ConstantPropagationStore> {
@Override
- public ConstantPropagationStore initialStore(UnderlyingAST underlyingAST,
- List<LocalVariableNode> parameters) {
+ public ConstantPropagationStore initialStore(
+ UnderlyingAST underlyingAST, List<LocalVariableNode> parameters) {
ConstantPropagationStore store = new ConstantPropagationStore();
return store;
}
@Override
public TransferResult<Constant, ConstantPropagationStore> visitLocalVariable(
- LocalVariableNode node, TransferInput<Constant, ConstantPropagationStore> before) {
+ LocalVariableNode node, TransferInput<Constant, ConstantPropagationStore> before) {
ConstantPropagationStore store = before.getRegularStore();
Constant value = store.getInformation(node);
return new RegularTransferResult<>(value, store);
}
@Override
- public TransferResult<Constant, ConstantPropagationStore> visitNode(Node n,
- TransferInput<Constant, ConstantPropagationStore> p) {
+ public TransferResult<Constant, ConstantPropagationStore> visitNode(
+ Node n, TransferInput<Constant, ConstantPropagationStore> p) {
return new RegularTransferResult<>(null, p.getRegularStore());
}
@Override
public TransferResult<Constant, ConstantPropagationStore> visitAssignment(
- AssignmentNode n,
- TransferInput<Constant, ConstantPropagationStore> pi) {
+ AssignmentNode n, TransferInput<Constant, ConstantPropagationStore> pi) {
ConstantPropagationStore p = pi.getRegularStore();
Node target = n.getTarget();
Constant info = null;
@@ -61,8 +57,7 @@ public class ConstantPropagationTransfer
@Override
public TransferResult<Constant, ConstantPropagationStore> visitIntegerLiteral(
- IntegerLiteralNode n,
- TransferInput<Constant, ConstantPropagationStore> pi) {
+ IntegerLiteralNode n, TransferInput<Constant, ConstantPropagationStore> pi) {
ConstantPropagationStore p = pi.getRegularStore();
Constant c = new Constant(n.getValue());
p.setInformation(n, c);
@@ -87,5 +82,4 @@ public class ConstantPropagationTransfer
p.setInformation(b, val);
}
}
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/Deterministic.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/Deterministic.java
index e79543fbb1..7e7d8b9cdc 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/Deterministic.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/Deterministic.java
@@ -7,88 +7,81 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
- * A method is called <em>deterministic</em> if it returns the same value
- * (according to <tt>==</tt>) every time it is called with the same
- * parameters and in the same environment. The parameters include the
- * receiver, and the environment includes all of the Java heap (that is,
- * all fields of all objects and all static variables).
- * <p>
- * This annotation is important to pluggable type-checking because, after a
- * call to a <tt>@Deterministic</tt> method, flow-sensitive type refinement
- * can assume that anything learned about the first invocation is true
- * about subsequent invocations (so long as no non-<tt>@</tt>{@link
- * SideEffectFree} method call intervenes). For example,
- * the following code never suffers a null pointer
- * exception, so the Nullness Checker need not issue a warning:
- * <pre><code> if (x.myDeterministicMethod() != null) {
- x.myDeterministicMethod().hashCode();
- }</code></pre>
- * <p>
- * Note that <tt>@Deterministic</tt> guarantees that the result is
- * identical according to <tt>==</tt>, <b>not</b> equal according to
- * <tt>equals</tt>. This means that writing <tt>@Deterministic</tt> on a
- * method that returns a reference is often erroneous unless the
- * returned value is cached or interned.
- * <p>
- * Also see {@link Pure}, which means both deterministic and {@link
- * SideEffectFree}.
- * <p>
- * <b>Analysis:</b>
- * The Checker Framework performs a conservative analysis to verify a
- * <tt>@Deterministic</tt> annotation. The Checker Framework issues a
- * warning if the method uses any of the following Java constructs:
+ * A method is called <em>deterministic</em> if it returns the same value (according to {@code ==})
+ * every time it is called with the same parameters and in the same environment. The parameters
+ * include the receiver, and the environment includes all of the Java heap (that is, all fields of
+ * all objects and all static variables).
+ *
+ * <p>Determinism refers to the return value during a non-exceptional execution. If a method throws
+ * an exception, the Throwable does not have to be exactly the same object on each invocation (and
+ * generally should not be, to capture the correct stack trace).
+ *
+ * <p>This annotation is important to pluggable type-checking because, after a call to a
+ * {@code @Deterministic} method, flow-sensitive type refinement can assume that anything learned
+ * about the first invocation is true about subsequent invocations (so long as no
+ * non-{@code @}{@link SideEffectFree} method call intervenes). For example, the following code
+ * never suffers a null pointer exception, so the Nullness Checker need not issue a warning:
+ *
+ * <pre>{@code
+ * if (x.myDeterministicMethod() != null) {
+ * x.myDeterministicMethod().hashCode();
+ * }
+ * }</pre>
+ *
+ * <p>Note that {@code @Deterministic} guarantees that the result is identical according to {@code
+ * ==}, <b>not</b> just equal according to {@code equals()}. This means that writing <code>
+ * {@literal @}Deterministic</code> on a method that returns a reference (including a String) is
+ * often erroneous unless the returned value is cached or interned.
+ *
+ * <p>Also see {@link Pure}, which means both deterministic and {@link SideEffectFree}.
+ *
+ * <p><b>Analysis:</b> The Checker Framework performs a conservative analysis to verify a
+ * {@code @Deterministic} annotation. The Checker Framework issues a warning if the method uses any
+ * of the following Java constructs:
+ *
* <ol>
- * <li>Assignment to any expression, except for local variables (and method
- * parameters).
- * <li>A method invocation of a method that is not {@link Deterministic}.
- * <li>Construction of a new object.
- * <li>Catching any exceptions. This is to prevent a method to get a hold of
- * newly created objects and using these objects (or some property thereof)
- * to change their return value. For instance, the following method must be
- * forbidden.
- * <pre>
- <code>
- &#64;Deterministic
- int f() {
- try {
- int b = 0;
- int a = 1/b;
- } catch (Throwable t) {
- return t.hashCode();
- }
- return 0;
- }
- </code>
-</pre>
+ * <li>Assignment to any expression, except for local variables (and method parameters).
+ * <li>A method invocation of a method that is not {@link Deterministic}.
+ * <li>Construction of a new object.
+ * <li>Catching any exceptions. This is to prevent a method to get a hold of newly created objects
+ * and using these objects (or some property thereof) to change their return value. For
+ * instance, the following method must be forbidden.
+ * <pre>
+ * {@code @Deterministic
+ * int f() {
+ * try {
+ * int b = 0;
+ * int a = 1/b;
+ * } catch (Throwable t) {
+ * return t.hashCode();
+ * }
+ * return 0;
+ * }
+ * }</pre>
* </ol>
- * A constructor can be <tt>@Pure</tt>, but a constructor <em>invocation</em> is
- * not deterministic since it returns a different new object each time.
- * TODO: Side-effect-free constructors could be allowed to set their own fields.
- * <p>
*
- * Note that the rules for checking currently imply that every {@code
- * Deterministic} method is also {@link SideEffectFree}. This might change
- * in the future; in general, a deterministic method does not need to be
- * side-effect-free.
- * <p>
+ * A constructor can be {@code @Pure}, but a constructor <em>invocation</em> is not deterministic
+ * since it returns a different new object each time. TODO: Side-effect-free constructors could be
+ * allowed to set their own fields.
*
- * These rules are conservative: any code that passes the checks is
- * deterministic, but the Checker Framework may issue false positive
- * warnings, for code that uses one of the forbidden constructs but is
- * deterministic nonetheless.
- * <p>
+ * <p>Note that the rules for checking currently imply that every {@code Deterministic} method is
+ * also {@link SideEffectFree}. This might change in the future; in general, a deterministic method
+ * does not need to be side-effect-free.
*
- * In fact, the rules are so conservative that checking is currently
- * disabled by default, but can be enabled via the
- * <tt>-AcheckPurityAnnotations</tt> command-line option.
- * <p>
+ * <p>These rules are conservative: any code that passes the checks is deterministic, but the
+ * Checker Framework may issue false positive warnings, for code that uses one of the forbidden
+ * constructs but is deterministic nonetheless.
*
- * @checker_framework.manual #type-refinement-purity Side effects, determinism, purity, and flow-sensitive analysis
+ * <p>In fact, the rules are so conservative that checking is currently disabled by default, but can
+ * be enabled via the {@code -AcheckPurityAnnotations} command-line option.
+ *
+ * <p>
*
+ * @checker_framework.manual #type-refinement-purity Side effects, determinism, purity, and
+ * flow-sensitive analysis
* @author Stefan Heule
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
-@Target({ ElementType.METHOD, ElementType.CONSTRUCTOR })
-public @interface Deterministic {
-}
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface Deterministic {}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/LockingFree.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/LockingFree.java
deleted file mode 100644
index a210c1a857..0000000000
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/LockingFree.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.checkerframework.dataflow.qual;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Behaves identically to @SideEffectFree when running the Lock Checker.
- * Ignored by all other checkers.
- *
- * @see SideEffectFree
- */
-@Documented
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ ElementType.METHOD, ElementType.CONSTRUCTOR })
-public @interface LockingFree {
-}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/Pure.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/Pure.java
index a559c1db27..5a00db7a1b 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/Pure.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/Pure.java
@@ -7,31 +7,24 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
- * {@code Pure} is a method annotation that means both {@link
- * SideEffectFree} and {@link Deterministic}. The more important of these,
- * when performing pluggable type-checking, is usually {@link
- * SideEffectFree}.
- *
- * @checker_framework.manual #type-refinement-purity Side effects, determinism, purity, and flow-sensitive analysis
+ * {@code Pure} is a method annotation that means both {@link SideEffectFree} and {@link
+ * Deterministic}. The more important of these, when performing pluggable type-checking, is usually
+ * {@link SideEffectFree}.
*
+ * @checker_framework.manual #type-refinement-purity Side effects, determinism, purity, and
+ * flow-sensitive analysis
* @author Stefan Heule
- *
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
-@Target({ ElementType.METHOD, ElementType.CONSTRUCTOR })
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
public @interface Pure {
- /**
- * The type of purity.
- */
+ /** The type of purity. */
public static enum Kind {
/** The method has no visible side-effects. */
SIDE_EFFECT_FREE,
- /**
- * The method returns exactly the same value when called in the same
- * environment.
- */
+ /** The method returns exactly the same value when called in the same environment. */
DETERMINISTIC
}
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/SideEffectFree.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/SideEffectFree.java
index 0521113bab..6a969c4364 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/SideEffectFree.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/SideEffectFree.java
@@ -7,57 +7,48 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
- * A method is called <em>side-effect-free</em> if it has no visible
- * side-effects, such as setting a field of an object that existed before
- * the method was called.
- * <p>
- * Only the visible side-effects are important. The method is allowed to cache
- * the answer to a computationally expensive query, for instance. It is also
- * allowed to modify newly-created objects, and a constructor is
- * side-effect-free if it does not modify any objects that existed before
- * it was called.
- * <p>
- * This annotation is important to pluggable type-checking because if some
- * fact about an object is known before a call to such a method, then the
- * fact is still known afterwards, even if the fact is about some non-final
- * field. When any non-<tt>@SideEffectFree</tt> method is called, then a
- * pluggable type-checker must assume that any field of any accessible
- * object might have been modified, which annuls the effect of
- * flow-sensitive type refinement and prevents the pluggable type-checker
- * from making conclusions that are obvious to a programmer.
- * <p>
- * Also see {@link Pure}, which means both side-effect-free and {@link
- * Deterministic}.
- * <p>
- * <b>Analysis:</b>
- * The Checker Framework performs a conservative analysis to verify a
- * <tt>@SideEffectFree</tt> annotation.
- * The Checker Framework issues a warning
- * if the method uses any of the following Java constructs:
+ * A method is called <em>side-effect-free</em> if it has no visible side-effects, such as setting a
+ * field of an object that existed before the method was called.
+ *
+ * <p>Only the visible side-effects are important. The method is allowed to cache the answer to a
+ * computationally expensive query, for instance. It is also allowed to modify newly-created
+ * objects, and a constructor is side-effect-free if it does not modify any objects that existed
+ * before it was called.
+ *
+ * <p>This annotation is important to pluggable type-checking because if some fact about an object
+ * is known before a call to such a method, then the fact is still known afterwards, even if the
+ * fact is about some non-final field. When any non-{@code @SideEffectFree} method is called, then a
+ * pluggable type-checker must assume that any field of any accessible object might have been
+ * modified, which annuls the effect of flow-sensitive type refinement and prevents the pluggable
+ * type-checker from making conclusions that are obvious to a programmer.
+ *
+ * <p>Also see {@link Pure}, which means both side-effect-free and {@link Deterministic}.
+ *
+ * <p><b>Analysis:</b> The Checker Framework performs a conservative analysis to verify a
+ * {@code @SideEffectFree} annotation. The Checker Framework issues a warning if the method uses any
+ * of the following Java constructs:
+ *
* <ol>
- * <li>Assignment to any expression, except for local variables and method
- * parameters.
- * <li>A method invocation of a method that is not <tt>@SideEffectFree</tt>.
- * <li>Construction of a new object where the constructor is not <tt>@SideEffectFree</tt>.
+ * <li>Assignment to any expression, except for local variables and method parameters.
+ * <li>A method invocation of a method that is not {@code @SideEffectFree}.
+ * <li>Construction of a new object where the constructor is not {@code @SideEffectFree}.
* </ol>
- * These rules are conservative: any code that passes the checks is
- * side-effect-free, but the Checker Framework may issue false positive
- * warnings, for code that uses one of the forbidden constructs but is
- * side-effect-free nonetheless. In particular, a method that caches its
- * result will be rejected.
- * <p>
*
- * In fact, the rules are so conservative that checking is currently
- * disabled by default, but can be enabled via the
- * <tt>-AcheckPurityAnnotations</tt> command-line option.
- * <p>
+ * These rules are conservative: any code that passes the checks is side-effect-free, but the
+ * Checker Framework may issue false positive warnings, for code that uses one of the forbidden
+ * constructs but is side-effect-free nonetheless. In particular, a method that caches its result
+ * will be rejected.
+ *
+ * <p>In fact, the rules are so conservative that checking is currently disabled by default, but can
+ * be enabled via the {@code -AcheckPurityAnnotations} command-line option.
*
- * @checker_framework.manual #type-refinement-purity Side effects, determinism, purity, and flow-sensitive analysis
+ * <p>
*
+ * @checker_framework.manual #type-refinement-purity Side effects, determinism, purity, and
+ * flow-sensitive analysis
* @author Stefan Heule
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
-@Target({ ElementType.METHOD, ElementType.CONSTRUCTOR })
-public @interface SideEffectFree {
-}
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface SideEffectFree {}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/TerminatesExecution.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/TerminatesExecution.java
index 93ff95c546..4e83dcdb64 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/TerminatesExecution.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/qual/TerminatesExecution.java
@@ -7,32 +7,28 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
- * {@code TerminatesExecution} is a method annotation that indicates that a
- * method terminates the execution of the program. This can be used to
- * annotate methods such as {@code System.exit()}.
- * <p>
-
- * The annotation enables flow-sensitive type refinement to be more
- * precise. For example, after
+ * {@code TerminatesExecution} is a method annotation that indicates that a method terminates the
+ * execution of the program. This can be used to annotate methods such as {@code System.exit()}.
+ *
+ * <p>The annotation enables flow-sensitive type refinement to be more precise. For example, after
+ *
* <pre>
* if (x == null) {
* System.err.println("Bad value supplied");
* System.exit(1);
* }
* </pre>
- * the Nullness Checker can determine that <tt>x</tt> is non-null.
- *
- * <p>
- * The annotation is a <em>trusted</em> annotation, meaning that it is not
- * checked whether the annotated method really does terminate the program.
- *
- * @checker_framework.manual #type-refinement Automatic type refinement (flow-sensitive type qualifier inference)
*
+ * the Nullness Checker can determine that {@code x} is non-null.
+ *
+ * <p>The annotation is a <em>trusted</em> annotation, meaning that it is not checked whether the
+ * annotated method really does terminate the program.
+ *
+ * @checker_framework.manual #type-refinement Automatic type refinement (flow-sensitive type
+ * qualifier inference)
* @author Stefan Heule
- *
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
-@Target({ ElementType.METHOD, ElementType.CONSTRUCTOR })
-public @interface TerminatesExecution {
-}
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface TerminatesExecution {}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/HashCodeUtils.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/HashCodeUtils.java
index 200f96dfa9..f898e3c9b4 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/HashCodeUtils.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/HashCodeUtils.java
@@ -4,7 +4,6 @@ package org.checkerframework.dataflow.util;
* Utility class to implement the {@code hashCode} method.
*
* @author Stefan Heule
- *
*/
public class HashCodeUtils {
@@ -47,8 +46,9 @@ public class HashCodeUtils {
/** Add an object to a given hash. */
public static int hash(int hash, Object item) {
- if (item == null)
+ if (item == null) {
return hash * prime;
+ }
return hash * prime + item.hashCode();
}
@@ -85,8 +85,9 @@ public class HashCodeUtils {
/** Hash an object. */
public static int hash(Object item) {
- if (item == null)
+ if (item == null) {
return 0;
+ }
return item.hashCode();
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/MostlySingleton.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/MostlySingleton.java
index 44bdbd6f61..7e9172da91 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/MostlySingleton.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/MostlySingleton.java
@@ -8,13 +8,14 @@ import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
-/**
- * A set that is more efficient than HashSet for 0 and 1 elements.
- */
-final public class MostlySingleton<T> implements Set<T> {
+/** A set that is more efficient than HashSet for 0 and 1 elements. */
+public final class MostlySingleton<T> implements Set<T> {
private enum State {
- EMPTY, SINGLETON, ANY
+ EMPTY,
+ SINGLETON,
+ ANY
}
+
private State state = State.EMPTY;
private T value;
private HashSet<T> set;
@@ -22,14 +23,14 @@ final public class MostlySingleton<T> implements Set<T> {
@Override
public int size() {
switch (state) {
- case EMPTY:
- return 0;
- case SINGLETON:
- return 1;
- case ANY:
- return set.size();
- default:
- throw new AssertionError();
+ case EMPTY:
+ return 0;
+ case SINGLETON:
+ return 1;
+ case ANY:
+ return set.size();
+ default:
+ throw new AssertionError();
}
}
@@ -41,14 +42,14 @@ final public class MostlySingleton<T> implements Set<T> {
@Override
public boolean contains(Object o) {
switch (state) {
- case EMPTY:
- return false;
- case SINGLETON:
- return Objects.equals(o, value);
- case ANY:
- return set.contains(o);
- default:
- throw new AssertionError();
+ case EMPTY:
+ return false;
+ case SINGLETON:
+ return Objects.equals(o, value);
+ case ANY:
+ return set.contains(o);
+ default:
+ throw new AssertionError();
}
}
@@ -56,55 +57,55 @@ final public class MostlySingleton<T> implements Set<T> {
@SuppressWarnings("fallthrough")
public boolean add(T e) {
switch (state) {
- case EMPTY:
- state = State.SINGLETON;
- value = e;
- return true;
- case SINGLETON:
- state = State.ANY;
- set = new HashSet<T>();
- set.add(value);
- value = null;
- // fallthrough
- case ANY:
- return set.add(e);
- default:
- throw new AssertionError();
+ case EMPTY:
+ state = State.SINGLETON;
+ value = e;
+ return true;
+ case SINGLETON:
+ state = State.ANY;
+ set = new HashSet<T>();
+ set.add(value);
+ value = null;
+ // fallthrough
+ case ANY:
+ return set.add(e);
+ default:
+ throw new AssertionError();
}
}
@Override
public Iterator<T> iterator() {
switch (state) {
- case EMPTY:
- return Collections.emptyIterator();
- case SINGLETON:
- return new Iterator<T>() {
- private boolean hasNext = true;
-
- @Override
- public boolean hasNext() {
- return hasNext;
- }
-
- @Override
- public T next() {
- if (hasNext) {
- hasNext = false;
- return value;
+ case EMPTY:
+ return Collections.emptyIterator();
+ case SINGLETON:
+ return new Iterator<T>() {
+ private boolean hasNext = true;
+
+ @Override
+ public boolean hasNext() {
+ return hasNext;
+ }
+
+ @Override
+ public T next() {
+ if (hasNext) {
+ hasNext = false;
+ return value;
+ }
+ throw new NoSuchElementException();
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
}
- throw new NoSuchElementException();
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
- case ANY:
- return set.iterator();
- default:
- throw new AssertionError();
+ };
+ case ANY:
+ return set.iterator();
+ default:
+ throw new AssertionError();
}
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/NodeUtils.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/NodeUtils.java
index d429d238e9..cf7a090024 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/NodeUtils.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/NodeUtils.java
@@ -1,26 +1,24 @@
package org.checkerframework.dataflow.util;
-import org.checkerframework.javacutil.TypesUtils;
-
-import org.checkerframework.dataflow.cfg.node.ConditionalOrNode;
-import org.checkerframework.dataflow.cfg.node.Node;
-
import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.tree.JCTree;
+import javax.lang.model.type.TypeKind;
+import org.checkerframework.dataflow.cfg.node.ConditionalOrNode;
+import org.checkerframework.dataflow.cfg.node.FieldAccessNode;
+import org.checkerframework.dataflow.cfg.node.Node;
+import org.checkerframework.javacutil.TypesUtils;
/**
* A utility class to operate on a given {@link Node}.
*
* @author Stefan Heule
- *
*/
public class NodeUtils {
/**
- * @return true iff <code>node</code> corresponds to a boolean typed
- * expression (either the primitive type <code>boolean</code>, or
- * class type {@link java.lang.Boolean})
+ * @return true iff {@code node} corresponds to a boolean typed expression (either the primitive
+ * type {@code boolean}, or class type {@link java.lang.Boolean})
*/
public static boolean isBooleanTypeNode(Node node) {
@@ -42,4 +40,17 @@ public class NodeUtils {
return false;
}
+
+ /**
+ * @return true iff {@code node} is a {@link FieldAccessNode} that is an access to an array's
+ * length
+ */
+ public static boolean isArrayLengthFieldAccess(Node node) {
+ if (!(node instanceof FieldAccessNode)) {
+ return false;
+ }
+ FieldAccessNode fieldAccess = (FieldAccessNode) node;
+ return fieldAccess.getFieldName().equals("length")
+ && fieldAccess.getReceiver().getType().getKind() == TypeKind.ARRAY;
+ }
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/PurityChecker.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/PurityChecker.java
index 5fafb7a8a1..0b298f1955 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/PurityChecker.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/PurityChecker.java
@@ -5,23 +5,6 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.compilermsgs.qual.CompilerMessageKey;
*/
-import org.checkerframework.dataflow.qual.Deterministic;
-import org.checkerframework.dataflow.qual.Pure;
-import org.checkerframework.dataflow.qual.Pure.Kind;
-import org.checkerframework.dataflow.qual.SideEffectFree;
-
-import org.checkerframework.javacutil.AnnotationProvider;
-import org.checkerframework.javacutil.InternalUtils;
-import org.checkerframework.javacutil.Pair;
-import org.checkerframework.javacutil.TreeUtils;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.List;
-
-import javax.lang.model.element.Element;
-
import com.sun.source.tree.ArrayAccessTree;
import com.sun.source.tree.AssertTree;
import com.sun.source.tree.AssignmentTree;
@@ -64,39 +47,48 @@ import com.sun.source.tree.VariableTree;
import com.sun.source.tree.WhileLoopTree;
import com.sun.source.util.SimpleTreeVisitor;
import com.sun.tools.javac.tree.TreeScanner;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.List;
+import javax.lang.model.element.Element;
+import org.checkerframework.dataflow.qual.Deterministic;
+import org.checkerframework.dataflow.qual.Pure;
+import org.checkerframework.dataflow.qual.Pure.Kind;
+import org.checkerframework.dataflow.qual.SideEffectFree;
+import org.checkerframework.javacutil.AnnotationProvider;
+import org.checkerframework.javacutil.InternalUtils;
+import org.checkerframework.javacutil.Pair;
+import org.checkerframework.javacutil.TreeUtils;
/**
* A visitor that determines the purity (as defined by {@link
- * org.checkerframework.dataflow.qual.SideEffectFree}, {@link org.checkerframework.dataflow.qual.Deterministic},
- * and {@link org.checkerframework.dataflow.qual.Pure}) of a statement or expression. The
- * entry point is method {@link #checkPurity}.
+ * org.checkerframework.dataflow.qual.SideEffectFree}, {@link
+ * org.checkerframework.dataflow.qual.Deterministic}, and {@link
+ * org.checkerframework.dataflow.qual.Pure}) of a statement or expression. The entry point is method
+ * {@link #checkPurity}.
*
* @see SideEffectFree
* @see Deterministic
* @see Pure
- *
* @author Stefan Heule
- *
*/
public class PurityChecker {
/**
- * Compute whether the given statement is
- * side-effect-free, deterministic, or both.
- * Returns a result that can be queried.
+ * Compute whether the given statement is side-effect-free, deterministic, or both. Returns a
+ * result that can be queried.
*/
- public static PurityResult checkPurity(Tree statement,
- AnnotationProvider annoProvider, boolean assumeSideEffectFree) {
+ public static PurityResult checkPurity(
+ Tree statement, AnnotationProvider annoProvider, boolean assumeSideEffectFree) {
PurityCheckerHelper helper = new PurityCheckerHelper(annoProvider, assumeSideEffectFree);
PurityResult res = helper.scan(statement, new PurityResult());
return res;
}
/**
- * Result of the {@link PurityChecker}.
- * Can be queried queried regarding whether a given tree was
- * side-effect-free, deterministic, or both; also gives reasons if
- * the answer is "no".
+ * Result of the {@link PurityChecker}. Can be queried regarding whether a given tree was
+ * side-effect-free, deterministic, or both; also gives reasons if the answer is "no".
*/
public static class PurityResult {
@@ -121,48 +113,38 @@ public class PurityChecker {
return types.containsAll(kinds);
}
- /**
- * Get the {@code reason}s why the method is not side-effect-free.
- */
+ /** Get the {@code reason}s why the method is not side-effect-free. */
public List<Pair<Tree, String>> getNotSeFreeReasons() {
return notSeFreeReasons;
}
- /**
- * Add {@code reason} as a reason why the method is not side-effect
- * free.
- */
+ /** Add {@code reason} as a reason why the method is not side-effect free. */
public void addNotSeFreeReason(Tree t, String msgId) {
notSeFreeReasons.add(Pair.of(t, msgId));
types.remove(Kind.SIDE_EFFECT_FREE);
}
- /**
- * Get the {@code reason}s why the method is not deterministic.
- */
+ /** Get the {@code reason}s why the method is not deterministic. */
public List<Pair<Tree, String>> getNotDetReasons() {
return notDetReasons;
}
- /**
- * Add {@code reason} as a reason why the method is not deterministic.
- */
+ /** Add {@code reason} as a reason why the method is not deterministic. */
public void addNotDetReason(Tree t, String msgId) {
notDetReasons.add(Pair.of(t, msgId));
types.remove(Kind.DETERMINISTIC);
}
/**
- * Get the {@code reason}s why the method is not both side-effect-free
- * and deterministic.
+ * Get the {@code reason}s why the method is not both side-effect-free and deterministic.
*/
public List<Pair<Tree, String>> getNotBothReasons() {
return notBothReasons;
}
/**
- * Add {@code reason} as a reason why the method is not both side-effect
- * free and deterministic.
+ * Add {@code reason} as a reason why the method is not both side-effect free and
+ * deterministic.
*/
public void addNotBothReason(Tree t, String msgId) {
notBothReasons.add(Pair.of(t, msgId));
@@ -172,19 +154,21 @@ public class PurityChecker {
}
/**
- * Helper class to keep {@link PurityChecker}'s interface clean. The
- * implementation is heavily based on {@link TreeScanner}, but some parts of
- * the AST are skipped (such as types or modifiers). Furthermore, scanning
- * works differently in that the input parameter (usually named {@code p})
- * gets "threaded through", instead of using {@code reduce}.
+ * Helper class to keep {@link PurityChecker}'s interface clean. The implementation is heavily
+ * based on {@link TreeScanner}, but some parts of the AST are skipped (such as types or
+ * modifiers). Furthermore, scanning works differently in that the input parameter (usually
+ * named {@code p}) gets "threaded through", instead of using {@code reduce}.
*/
protected static class PurityCheckerHelper
extends SimpleTreeVisitor<PurityResult, PurityResult> {
protected final AnnotationProvider annoProvider;
- /** True if all methods should be assumed to be @SideEffectFree,
- * for the purposes of org.checkerframework.dataflow analysis. */
+ /**
+ * True if all methods should be assumed to be @SideEffectFree, for the purposes of
+ * org.checkerframework.dataflow analysis.
+ */
private final boolean assumeSideEffectFree;
+
protected /*@Nullable*/ List<Element> methodParameter;
public PurityCheckerHelper(AnnotationProvider annoProvider, boolean assumeSideEffectFree) {
@@ -192,16 +176,12 @@ public class PurityChecker {
this.assumeSideEffectFree = assumeSideEffectFree;
}
- /**
- * Scan a single node.
- */
+ /** Scan a single node. */
public PurityResult scan(Tree node, PurityResult p) {
return node == null ? p : node.accept(this, p);
}
- /**
- * Scan a list of nodes.
- */
+ /** Scan a list of nodes. */
public PurityResult scan(Iterable<? extends Tree> nodes, PurityResult p) {
PurityResult r = p;
if (nodes != null) {
@@ -229,8 +209,7 @@ public class PurityChecker {
}
@Override
- public PurityResult visitEmptyStatement(EmptyStatementTree node,
- PurityResult p) {
+ public PurityResult visitEmptyStatement(EmptyStatementTree node, PurityResult p) {
return p;
}
@@ -240,8 +219,7 @@ public class PurityChecker {
}
@Override
- public PurityResult visitDoWhileLoop(DoWhileLoopTree node,
- PurityResult p) {
+ public PurityResult visitDoWhileLoop(DoWhileLoopTree node, PurityResult p) {
PurityResult r = scan(node.getStatement(), p);
r = scan(node.getCondition(), r);
return r;
@@ -264,8 +242,7 @@ public class PurityChecker {
}
@Override
- public PurityResult visitEnhancedForLoop(EnhancedForLoopTree node,
- PurityResult p) {
+ public PurityResult visitEnhancedForLoop(EnhancedForLoopTree node, PurityResult p) {
PurityResult r = scan(node.getVariable(), p);
r = scan(node.getExpression(), r);
r = scan(node.getStatement(), r);
@@ -273,8 +250,7 @@ public class PurityChecker {
}
@Override
- public PurityResult visitLabeledStatement(LabeledStatementTree node,
- PurityResult p) {
+ public PurityResult visitLabeledStatement(LabeledStatementTree node, PurityResult p) {
return scan(node.getStatement(), p);
}
@@ -293,8 +269,7 @@ public class PurityChecker {
}
@Override
- public PurityResult visitSynchronized(SynchronizedTree node,
- PurityResult p) {
+ public PurityResult visitSynchronized(SynchronizedTree node, PurityResult p) {
PurityResult r = scan(node.getExpression(), p);
r = scan(node.getBlock(), r);
return r;
@@ -335,8 +310,7 @@ public class PurityChecker {
}
@Override
- public PurityResult visitExpressionStatement(
- ExpressionStatementTree node, PurityResult p) {
+ public PurityResult visitExpressionStatement(ExpressionStatementTree node, PurityResult p) {
return scan(node.getExpression(), p);
}
@@ -368,17 +342,15 @@ public class PurityChecker {
}
@Override
- public PurityResult visitMethodInvocation(MethodInvocationTree node,
- PurityResult p) {
+ public PurityResult visitMethodInvocation(MethodInvocationTree node, PurityResult p) {
Element elt = TreeUtils.elementFromUse(node);
String reason = "call";
if (!PurityUtils.hasPurityAnnotation(annoProvider, elt)) {
p.addNotBothReason(node, reason);
} else {
boolean det = PurityUtils.isDeterministic(annoProvider, elt);
- boolean seFree = (assumeSideEffectFree
- || PurityUtils.isSideEffectFree(annoProvider,
- elt));
+ boolean seFree =
+ (assumeSideEffectFree || PurityUtils.isSideEffectFree(annoProvider, elt));
if (!det && !seFree) {
p.addNotBothReason(node, reason);
} else if (!det) {
@@ -395,9 +367,9 @@ public class PurityChecker {
@Override
public PurityResult visitNewClass(NewClassTree node, PurityResult p) {
Element methodElement = InternalUtils.symbol(node);
- boolean sideEffectFree = (assumeSideEffectFree
- || PurityUtils.isSideEffectFree(annoProvider,
- methodElement));
+ boolean sideEffectFree =
+ (assumeSideEffectFree
+ || PurityUtils.isSideEffectFree(annoProvider, methodElement));
if (sideEffectFree) {
p.addNotDetReason(node, "object.creation");
} else {
@@ -417,16 +389,14 @@ public class PurityChecker {
}
@Override
- public PurityResult visitLambdaExpression(LambdaExpressionTree node,
- PurityResult p) {
+ public PurityResult visitLambdaExpression(LambdaExpressionTree node, PurityResult p) {
PurityResult r = scan(node.getParameters(), p);
r = scan(node.getBody(), r);
return r;
}
@Override
- public PurityResult visitParenthesized(ParenthesizedTree node,
- PurityResult p) {
+ public PurityResult visitParenthesized(ParenthesizedTree node, PurityResult p) {
return scan(node.getExpression(), p);
}
@@ -439,8 +409,7 @@ public class PurityChecker {
return r;
}
- protected PurityResult assignmentCheck(PurityResult p,
- ExpressionTree variable) {
+ protected PurityResult assignmentCheck(PurityResult p, ExpressionTree variable) {
if (TreeUtils.isFieldAccess(variable)) {
// rhs is a field access
p.addNotBothReason(variable, "assign.field");
@@ -455,13 +424,11 @@ public class PurityChecker {
}
protected boolean isLocalVariable(ExpressionTree variable) {
- return variable instanceof IdentifierTree
- && !TreeUtils.isFieldAccess(variable);
+ return variable instanceof IdentifierTree && !TreeUtils.isFieldAccess(variable);
}
@Override
- public PurityResult visitCompoundAssignment(
- CompoundAssignmentTree node, PurityResult p) {
+ public PurityResult visitCompoundAssignment(CompoundAssignmentTree node, PurityResult p) {
ExpressionTree variable = node.getVariable();
p = assignmentCheck(p, variable);
PurityResult r = scan(variable, p);
@@ -494,22 +461,19 @@ public class PurityChecker {
}
@Override
- public PurityResult visitArrayAccess(ArrayAccessTree node,
- PurityResult p) {
+ public PurityResult visitArrayAccess(ArrayAccessTree node, PurityResult p) {
PurityResult r = scan(node.getExpression(), p);
r = scan(node.getIndex(), r);
return r;
}
@Override
- public PurityResult visitMemberSelect(MemberSelectTree node,
- PurityResult p) {
+ public PurityResult visitMemberSelect(MemberSelectTree node, PurityResult p) {
return scan(node.getExpression(), p);
}
@Override
- public PurityResult visitMemberReference(MemberReferenceTree node,
- PurityResult p) {
+ public PurityResult visitMemberReference(MemberReferenceTree node, PurityResult p) {
assert false : "this type of tree is unexpected here";
return null;
}
@@ -524,5 +488,4 @@ public class PurityChecker {
return p;
}
}
-
}
diff --git a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/PurityUtils.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/PurityUtils.java
index 6b19543c91..c175877a24 100644
--- a/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/PurityUtils.java
+++ b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/util/PurityUtils.java
@@ -1,94 +1,79 @@
package org.checkerframework.dataflow.util;
+import com.sun.source.tree.MethodTree;
import java.util.ArrayList;
import java.util.List;
-
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
-
import org.checkerframework.dataflow.qual.Deterministic;
import org.checkerframework.dataflow.qual.Pure;
-import org.checkerframework.dataflow.qual.SideEffectFree;
import org.checkerframework.dataflow.qual.Pure.Kind;
-
+import org.checkerframework.dataflow.qual.SideEffectFree;
import org.checkerframework.javacutil.AnnotationProvider;
import org.checkerframework.javacutil.InternalUtils;
-import com.sun.source.tree.MethodTree;
-
/**
- * An utility class for working with the {@link SideEffectFree}, {@link
- * Deterministic}, and {@link Pure} annotations.
+ * An utility class for working with the {@link SideEffectFree}, {@link Deterministic}, and {@link
+ * Pure} annotations.
*
* @see SideEffectFree
* @see Deterministic
* @see Pure
- *
* @author Stefan Heule
- *
*/
public class PurityUtils {
/** Does the method {@code tree} have any purity annotation? */
- public static boolean hasPurityAnnotation(AnnotationProvider provider,
- MethodTree tree) {
+ public static boolean hasPurityAnnotation(AnnotationProvider provider, MethodTree tree) {
return !getPurityKinds(provider, tree).isEmpty();
}
/** Does the method {@code methodElement} have any purity annotation? */
- public static boolean hasPurityAnnotation(AnnotationProvider provider,
- Element methodElement) {
+ public static boolean hasPurityAnnotation(AnnotationProvider provider, Element methodElement) {
return !getPurityKinds(provider, methodElement).isEmpty();
}
/** Is the method {@code tree} deterministic? */
- public static boolean isDeterministic(AnnotationProvider provider,
- MethodTree tree) {
+ public static boolean isDeterministic(AnnotationProvider provider, MethodTree tree) {
Element methodElement = InternalUtils.symbol(tree);
return isDeterministic(provider, methodElement);
}
/** Is the method {@code methodElement} deterministic? */
- public static boolean isDeterministic(AnnotationProvider provider,
- Element methodElement) {
+ public static boolean isDeterministic(AnnotationProvider provider, Element methodElement) {
List<Kind> kinds = getPurityKinds(provider, methodElement);
return kinds.contains(Kind.DETERMINISTIC);
}
/** Is the method {@code tree} side-effect-free? */
- public static boolean isSideEffectFree(AnnotationProvider provider,
- MethodTree tree) {
+ public static boolean isSideEffectFree(AnnotationProvider provider, MethodTree tree) {
Element methodElement = InternalUtils.symbol(tree);
return isSideEffectFree(provider, methodElement);
}
/** Is the method {@code methodElement} side-effect-free? */
- public static boolean isSideEffectFree(AnnotationProvider provider,
- Element methodElement) {
+ public static boolean isSideEffectFree(AnnotationProvider provider, Element methodElement) {
List<Kind> kinds = getPurityKinds(provider, methodElement);
return kinds.contains(Kind.SIDE_EFFECT_FREE);
}
- /**
- * @return The types of purity of the method {@code tree}.
- */
- public static List<Pure.Kind> getPurityKinds(AnnotationProvider provider,
- MethodTree tree) {
+ /** @return the types of purity of the method {@code tree}. */
+ public static List<Pure.Kind> getPurityKinds(AnnotationProvider provider, MethodTree tree) {
Element methodElement = InternalUtils.symbol(tree);
return getPurityKinds(provider, methodElement);
}
/**
- * @return The types of purity of the method {@code methodElement}.
+ * @return the types of purity of the method {@code methodElement}. TODO: should the return type
+ * be an EnumSet?
*/
- public static List<Pure.Kind> getPurityKinds(AnnotationProvider provider,
- Element methodElement) {
- AnnotationMirror pureAnnotation = provider.getDeclAnnotation(
- methodElement, Pure.class);
- AnnotationMirror sefAnnotation = provider.getDeclAnnotation(
- methodElement, SideEffectFree.class);
- AnnotationMirror detAnnotation = provider.getDeclAnnotation(
- methodElement, Deterministic.class);
+ public static List<Pure.Kind> getPurityKinds(
+ AnnotationProvider provider, Element methodElement) {
+ AnnotationMirror pureAnnotation = provider.getDeclAnnotation(methodElement, Pure.class);
+ AnnotationMirror sefAnnotation =
+ provider.getDeclAnnotation(methodElement, SideEffectFree.class);
+ AnnotationMirror detAnnotation =
+ provider.getDeclAnnotation(methodElement, Deterministic.class);
List<Pure.Kind> kinds = new ArrayList<>();
if (pureAnnotation != null) {