Update checker framework dataflow and javacutils to 2.1.14

Change-Id: I62ad827fc4bbd54d022097003af63e351e44b98c
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 4cbe8f1..0000000
--- 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 2dbcbd4..25b7807 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 @@
  * 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 fa07247..2e81b4a 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 @@
 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.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 @@
     /** 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).
-     */
+    /** Else stores before every basic block (assumed to be 'no information' if not present). */
     protected IdentityHashMap<Block, S> elseStores;
 
     /**
-     * The transfer inputs 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, Integer> blockCount;
+
+    /**
+     * Number of times a block can be analyzed before widening. -1 implies that widening shouldn't
+     * be used.
+     */
+    protected final int maxCountBeforeWidening;
+
+    /**
+     * 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.
-     */
+    /** 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 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 @@
 
     /**
      * 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 @@
      * 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 @@
     }
 
     /**
-     * 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 @@
             Block b = worklist.poll();
 
             switch (b.getType()) {
-            case REGULAR_BLOCK: {
-                RegularBlock rb = (RegularBlock) b;
+                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);
-                }
-
-                // 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);
+                        // 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;
                         }
-                    } else {
-                        for (Block exceptionSucc : e.getValue()) {
-                            addStoreBefore(exceptionSucc, node, inputBefore.copy().getRegularStore(),
-                                           Store.Kind.BOTH, addToWorklistAgain);
-                        }
+                        // 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;
                     }
-                }
-                break;
-            }
 
-            case CONDITIONAL_BLOCK: {
-                ConditionalBlock cb = (ConditionalBlock) b;
+                case EXCEPTION_BLOCK:
+                    {
+                        ExceptionBlock eb = (ExceptionBlock) b;
 
-                // get store before
-                TransferInput<A, S> inputBefore = getInputBefore(cb);
-                TransferInput<A, S> input = inputBefore.copy();
+                        // 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 thenSucc = cb.getThenSuccessor();
-                Block elseSucc = cb.getElseSuccessor();
+                        // 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);
+                        }
 
-                propagateStoresTo(thenSucc, null, input, cb.getThenFlowRule(), false);
-                propagateStoresTo(elseSucc, null, input, cb.getElseFlowRule(), false);
-                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);
+                                }
+                            } else {
+                                for (Block exceptionSucc : e.getValue()) {
+                                    addStoreBefore(
+                                            exceptionSucc,
+                                            node,
+                                            inputBefore.copy().getRegularStore(),
+                                            Store.Kind.BOTH,
+                                            addToWorklistAgain);
+                                }
+                            }
+                        }
+                        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 CONDITIONAL_BLOCK:
+                    {
+                        ConditionalBlock cb = (ConditionalBlock) b;
 
-            default:
-                assert false;
-                break;
+                        // 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();
+
+                        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;
+                    }
+
+                default:
+                    assert false;
+                    break;
             }
         }
 
@@ -291,78 +304,104 @@
     }
 
     /**
-     * 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 @@
         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 @@
     }
 
     /**
-     * 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 @@
     }
 
     /**
-     * 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);
+        boolean shouldWiden = false;
+        if (blockCount != null) {
+            Integer count = blockCount.get(b);
+            if (count == null) {
+                count = 0;
+            }
+            shouldWiden = count >= maxCountBeforeWidening;
+            if (shouldWiden) {
+                blockCount.put(b, 0);
+            } else {
+                blockCount.put(b, count + 1);
+            }
+        }
 
         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;
+            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;
                 }
-            }
-            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;
+            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;
                 }
-            }
-            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;
+            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 = (thenStore != null) ?
-                    thenStore.leastUpperBound(s) : s;
-                if (!newThenStore.equals(thenStore)) {
-                    thenStores.put(b, newThenStore);
-                    storeChanged = true;
-                }
+                    S newThenStore = mergeStores(s, thenStore, shouldWiden);
+                    if (!newThenStore.equals(thenStore)) {
+                        thenStores.put(b, newThenStore);
+                        storeChanged = true;
+                    }
 
-                S newElseStore = (elseStore != null) ?
-                    elseStore.leastUpperBound(s) : s;
-                if (!newElseStore.equals(elseStore)) {
-                    elseStores.put(b, newElseStore);
-                    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 @@
         }
     }
 
+    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 @@
         /** The backing priority queue. */
         protected PriorityQueue<Block> queue;
 
-
         public Worklist(ControlFlowGraph cfg) {
             depthFirstOrder = new IdentityHashMap<>();
             int count = 1;
@@ -569,43 +626,39 @@
     }
 
     /**
-     * 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 @@
     }
 
     /**
-     * @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 @@
     }
 
     /**
-     * @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 @@
         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 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 @@
     }
 
     /**
-     * @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 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 42b8d2f..48f376d 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 @@
 import org.checkerframework.checker.nullness.qual.Nullable;
 */
 
+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 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 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;
-
 /**
  * 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 @@
     /** 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 @@
         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 @@
         }
     }
 
-    /**
-     * @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 @@
     }
 
     /**
-     * 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 @@
         analysis.isRunning = true;
         try {
             switch (block.getType()) {
-            case REGULAR_BLOCK: {
-                RegularBlock rb = (RegularBlock) block;
+                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();
+                        // 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 c49357a..99a8a52 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 @@
     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.
+     * 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}.
+     * <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 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 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 @@
     }
 
     /**
-     * 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.
+     * 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><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 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 @@
         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 @@
         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 54828c7..85ad7b4 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.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 @@
     }
 
     /**
-     * @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 @@
     }
 
     /**
-     * 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 @@
                 // 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 @@
             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 @@
                 }
             }
 
-            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 @@
         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 @@
         }
 
         /**
-         * 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 @@
             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 @@
                 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 @@
 
         @Override
         public boolean containsSyntacticEqualReceiver(Receiver other) {
-            return syntacticEquals(other)
-                    || receiver.containsSyntacticEqualReceiver(other);
+            return syntacticEquals(other) || receiver.containsSyntacticEqualReceiver(other);
         }
 
         @Override
@@ -301,13 +508,17 @@
             }
             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 @@
     }
 
     /**
-     * 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 @@
 
         @Override
         public String toString() {
-            return getType().toString();
+            return getType().toString() + ".class";
         }
 
         @Override
@@ -447,7 +656,6 @@
         public boolean isUnmodifiableByOtherCode() {
             return false;
         }
-
     }
 
     public static class LocalVariable extends Receiver {
@@ -469,7 +677,17 @@
                 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 @@
 
         @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 @@
                 return false;
             }
             LocalVariable l = (LocalVariable) other;
-            return l.getElement().equals(getElement());
+            return l.equals(this);
         }
 
         @Override
@@ -542,11 +764,9 @@
             }
             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 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 @@
             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 @@
 
         @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 @@
 
         @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 @@
                 }
                 i++;
             }
-            return receiver.equals(other.receiver)
-                    && method.equals(other.method);
+            return receiver.equals(other.receiver) && method.equals(other.method);
         }
 
         @Override
@@ -695,7 +933,11 @@
         @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 @@
         }
     }
 
-    /**
-     * A deterministic method call.
-     */
+    /** A deterministic method call. */
     public static class ArrayAccess extends Receiver {
 
         protected final Receiver receiver;
@@ -753,7 +993,8 @@
 
         @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 @@
             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 8872e7f..b4044fa 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>
+     * <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>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 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 @@
     }
 
     /**
-     * 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 @@
         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 90c7f20..5d714da 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 @@
         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 e21ab56..a10a766 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 @@
 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 7314b35..f827ad3 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.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.
+     * Create a {@link TransferInput}, given a {@link TransferResult} and a node-value mapping.
      *
-     * <p>
+     * <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.
      *
-     * <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 @@
     /**
      * Create a {@link TransferInput}, given a store and a node-value mapping.
      *
-     * <p>
+     * <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.
      *
-     * <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 @@
     }
 
     /**
-     * Create a {@link TransferInput}, given two stores and a node-value
-     * mapping.
+     * Create a {@link TransferInput}, given two stores and a node-value mapping.
      *
-     * <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.
+     * <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 @@
         store = null;
     }
 
-    /**
-     * Copy constructor.
-     */
+    /** Copy constructor. */
     protected TransferInput(TransferInput<A, S> from) {
         this.node = from.node;
         this.analysis = from.analysis;
@@ -148,27 +123,24 @@
         }
     }
 
-    /**
-     * @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 @@
     }
 
     /**
-     * @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 @@
     }
 
     /**
-     * @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 @@
     }
 
     /**
-     * @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 @@
     /**
      * 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 @@
             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 @@
 
     @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 @@
             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 d083372..7c178a1 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 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}.
+ * {@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>
- *
- * 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 @@
         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 @@
     }
 
     /**
-     * @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 @@
     }
 
     /**
-     * @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 @@
     }
 
     /**
-     * @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 7b6804a..55daff2 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 @@
 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.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.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 @@
     }
 
     /**
-     * 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 @@
     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 @@
 
         /** 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 @@
         }
 
         /**
-         * @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 @@
         }
 
         /**
-         * @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 @@
         }
     }
 
-    /**
-     * 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 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 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 @@
 
         @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 @@
     }
 
     /**
-     * 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 @@
         }
 
         /**
-         * 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 @@
     }
 
     /**
-     * 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 @@
         }
 
         /**
-         * 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 @@
             // 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 @@
                 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 @@
                         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 @@
         }
     }
 
-    /**
-     * 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 @@
     }
 
     /**
-     * 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 @@
         }
 
         /**
-         * 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 @@
     /* --------------------------------------------------------- */
 
     /**
-     * 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 @@
         /**
          * 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 @@
                     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 @@
                     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 @@
         }
 
         /**
-         * 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 @@
             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 @@
         }
 
         /**
-         * 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);
-                        }
+                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;
+                            }
+                        };
+                    } 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 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;
-                                }
-                            };
+                                    @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 @@
         }
     }
 
-    /**
-     * 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 @@
             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 @@
             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);
-                        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));
+                    case NODE:
+                        if (leaders.contains(i)) {
+                            RegularBlockImpl b = new RegularBlockImpl();
+                            block.setSuccessor(b);
+                            block = b;
                         }
-                    }
-                    break;
+                        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 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;
                 }
                 i++;
             }
@@ -1293,8 +1259,14 @@
                 }
             }
 
-            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 @@
     /* --------------------------------------------------------- */
 
     /**
-     * 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 @@
         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 @@
             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 @@
             }
             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>
+     * <p>The return type of this scanner is {@link Node}. For expressions, the corresponding node
+     * is returned to allow linking between different nodes.
      *
-     * The return type of this scanner is {@link Node}. For expressions, the
-     * corresponding node is returned to allow linking between different nodes.
+     * <p>However, for statements there is usually no single {@link Node} that is created, and thus
+     * no node is returned (rather, null is returned).
      *
-     * 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).
-     *
+     * <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 @@
         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 @@
         /** 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 @@
             // 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 @@
         /**
          * 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 @@
         }
 
         /**
-         * 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 @@
         }
 
         /**
-         * 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 @@
         /**
          * 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 @@
         }
 
         /**
-         * 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 @@
         }
 
         /**
-         * 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 @@
         /**
          * 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 @@
             }
             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 @@
         /* --------------------------------------------------------- */
 
         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 @@
                 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 @@
         }
 
         /**
-         * 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 @@
             };
         }
 
-        /**
-         * @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 @@
         /**
          * 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 @@
         /**
          * 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 @@
         }
 
         /**
-         * 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 @@
         }
 
         /**
-         * 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 @@
         }
 
         /**
-         * 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 @@
         }
 
         /**
-         * 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 @@
         }
 
         /**
-         * 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 @@
             }
         }
 
-
         /**
-         * 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 @@
                 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 @@
         }
 
         /**
-         * 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 @@
                     // 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 @@
             } 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 @@
         }
 
         /**
-         * 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 @@
 
             // 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 @@
                 // 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 @@
             }
 
             // 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 @@
         }
 
         /**
-         * 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 @@
             // 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 @@
 
             // 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 @@
 
             // 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 @@
                 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 @@
             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 @@
         }
 
         /**
-         * 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 @@
                     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 @@
             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 @@
             // 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 @@
                 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 @@
                 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.
          *
-         * @param tree
-         *            the field access tree containing the receiver
-         * @param classTree
-         *            the ClassTree enclosing the field access
-         * @return The receiver of the field access.
+         * <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
          */
-        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 @@
 
             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);
+                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);
+                        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);
+                        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);
+
+                        AssignmentNode assignNode = new AssignmentNode(tree, targetLHS, castNode);
+                        extendWithNode(assignNode);
+                        return assignNode;
                     }
-                } else {
-                    assert kind == Kind.REMAINDER_ASSIGNMENT;
-                    if (TypesUtils.isIntegral(exprType)) {
-                        operNode = new IntegerRemainderNode(operTree, targetRHS, value);
-                    } else {
-                        operNode = new FloatingRemainderNode(operTree, targetRHS, value);
+
+                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;
+                        }
                     }
-                }
-                extendWithNode(operNode);
 
-                TypeCastTree castTree = treeBuilder.buildTypeCast(leftType, operTree);
-                handleArtificialTree(castTree);
-                TypeCastNode castNode = new TypeCastNode(castTree, operNode, leftType);
-                castNode.setInSource(false);
-                extendWithNode(castNode);
+                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);
 
-                AssignmentNode assignNode = new AssignmentNode(tree, targetLHS, castNode);
-                extendWithNode(assignNode);
-                return assignNode;
-            }
+                        TypeMirror leftType = InternalUtils.typeOf(tree.getVariable());
 
-            case MINUS_ASSIGNMENT:
-            case PLUS_ASSIGNMENT: {
-                // see JLS 15.18 and 15.26.2
+                        Node targetRHS = unaryNumericPromotion(targetLHS);
+                        value = unaryNumericPromotion(value);
 
-                Node targetLHS = scan(tree.getVariable(), p);
-                Node value = scan(tree.getExpression(), p);
+                        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 @@
                     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 @@
 
             Tree.Kind kind = tree.getKind();
             switch (kind) {
-            case DIVIDE:
-            case MULTIPLY:
-            case REMAINDER: {
-                // see JLS 15.17
+                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);
+                        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);
+                        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);
+                        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;
                     }
-                } else {
-                    assert kind == Kind.REMAINDER;
-                    if (TypesUtils.isIntegral(exprType)) {
-                        r = new IntegerRemainderNode(tree, left, right);
-                    } else {
-                        r = new FloatingRemainderNode(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 MINUS:
-            case PLUS: {
-                // see JLS 15.18
+                case LEFT_SHIFT:
+                case RIGHT_SHIFT:
+                case UNSIGNED_RIGHT_SHIFT:
+                    {
+                        // see JLS 15.19
 
-                // TypeMirror exprType = InternalUtils.typeOf(tree);
-                TypeMirror leftType = InternalUtils.typeOf(leftTree);
-                TypeMirror rightType = InternalUtils.typeOf(rightTree);
+                        Node left = unaryNumericPromotion(scan(leftTree, p));
+                        Node right = unaryNumericPromotion(scan(rightTree, p));
 
-                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);
+                        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;
                     }
-                }
-                break;
-            }
 
-            case LEFT_SHIFT:
-            case RIGHT_SHIFT:
-            case UNSIGNED_RIGHT_SHIFT: {
-                // see JLS 15.19
+                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 left = unaryNumericPromotion(scan(leftTree, p));
-                Node right = unaryNumericPromotion(scan(rightTree, p));
+                        TypeMirror rightType = InternalUtils.typeOf(rightTree);
+                        if (TypesUtils.isBoxedPrimitive(rightType)) {
+                            rightType = types.unboxedType(rightType);
+                        }
 
-                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;
-            }
+                        TypeMirror promotedType = binaryPromotedType(leftType, rightType);
+                        Node left = binaryNumericPromotion(scan(leftTree, p), promotedType);
+                        Node right = binaryNumericPromotion(scan(rightTree, p), promotedType);
 
-            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.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);
+                        }
 
-                TypeMirror rightType = InternalUtils.typeOf(rightTree);
-                if (TypesUtils.isBoxedPrimitive(rightType)) {
-                    rightType = types.unboxedType(rightType);
-                }
+                        extendWithNode(node);
 
-                TypeMirror promotedType = binaryPromotedType(leftType, rightType);
-                Node left = binaryNumericPromotion(scan(leftTree, p), promotedType);
-                Node right = binaryNumericPromotion(scan(rightTree, p), promotedType);
+                        return node;
+                    }
 
-                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 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);
 
-                extendWithNode(node);
+                        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 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);
+                        return node;
+                    }
 
-                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 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 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);
+                        Node left;
+                        Node right;
 
-                return node;
-            }
+                        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));
+                        }
 
-            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 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);
+                        }
 
-                Node left;
-                Node right;
+                        extendWithNode(node);
 
-                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));
-                }
+                        return 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);
-                }
+                case CONDITIONAL_AND:
+                case CONDITIONAL_OR:
+                    {
+                        // see JLS 15.23 and 15.24
 
-                extendWithNode(node);
+                        // all necessary labels
+                        Label rightStartL = new Label();
+                        Label shortCircuitL = new Label();
 
-                return node;
-            }
+                        // left-hand side
+                        Node left = scan(leftTree, p);
 
-            case CONDITIONAL_AND:
-            case CONDITIONAL_OR: {
-                // see JLS 15.23 and 15.24
+                        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);
 
-                // all necessary labels
-                Label rightStartL = new Label();
-                Label shortCircuitL = new Label();
+                        // right-hand side
+                        addLabelForNextNode(rightStartL);
+                        Node right = scan(rightTree, p);
 
-                // 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;
+                        // 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 @@
             } else {
                 assert breakLabels.containsKey(label);
 
-                extendWithExtendedNode(new UnconditionalJump(
-                        breakLabels.get(label)));
+                extendWithExtendedNode(new UnconditionalJump(breakLabels.get(label)));
             }
 
             return null;
@@ -3205,9 +3126,9 @@
         }
 
         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 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 @@
 
             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 @@
         }
 
         @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 @@
             } else {
                 assert continueLabels.containsKey(label);
 
-                extendWithExtendedNode(new UnconditionalJump(
-                        continueLabels.get(label)));
+                extendWithExtendedNode(new UnconditionalJump(continueLabels.get(label)));
             }
 
             return null;
@@ -3387,329 +3308,322 @@
         }
 
         @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());
+            // see JLS 14.14.2
+            Name parentLabel = getLabel(getCurrentPath());
 
-          Label conditionStart = new Label();
-          Label loopEntry = new Label();
-          Label loopExit = new Label();
+            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();
-          }
+            // 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 oldBreakTargetL = breakTargetL;
+            breakTargetL = loopExit;
 
-          Label oldContinueTargetL = continueTargetL;
-          continueTargetL = updateStart;
+            Label oldContinueTargetL = continueTargetL;
+            continueTargetL = updateStart;
 
-          // Distinguish loops over Iterables from loops over arrays.
+            // Distinguish loops over Iterables from loops over arrays.
 
-          TypeElement iterableElement = elements.getTypeElement("java.lang.Iterable");
-          TypeMirror iterableType = types.erasure(iterableElement.asType());
+            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();
+            VariableTree variable = tree.getVariable();
+            VariableElement variableElement = TreeUtils.elementFromDeclaration(variable);
+            ExpressionTree expression = tree.getExpression();
+            StatementTree statement = tree.getStatement();
 
-          TypeMirror exprType = InternalUtils.typeOf(expression);
+            TypeMirror exprType = InternalUtils.typeOf(expression);
 
-          if (types.isSubtype(exprType, iterableType)) {
-              // Take the upper bound of a type variable or wildcard
-              exprType = TypesUtils.upperBound(exprType);
+            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();
+                assert (exprType instanceof DeclaredType) : "an Iterable must be a DeclaredType";
+                DeclaredType declaredExprType = (DeclaredType) exprType;
+                declaredExprType.getTypeArguments();
 
-              MemberSelectTree iteratorSelect =
-                  treeBuilder.buildIteratorMethodAccess(expression);
-              handleArtificialTree(iteratorSelect);
+                MemberSelectTree iteratorSelect = treeBuilder.buildIteratorMethodAccess(expression);
+                handleArtificialTree(iteratorSelect);
 
-              MethodInvocationTree iteratorCall =
-                  treeBuilder.buildMethodInvocation(iteratorSelect);
-              handleArtificialTree(iteratorCall);
+                MethodInvocationTree iteratorCall =
+                        treeBuilder.buildMethodInvocation(iteratorSelect);
+                handleArtificialTree(iteratorCall);
 
-              TypeMirror iteratorType = InternalUtils.typeOf(iteratorCall);
+                VariableTree iteratorVariable =
+                        createEnhancedForLoopIteratorVariable(iteratorCall, variableElement);
+                handleArtificialTree(iteratorVariable);
 
-              // 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);
 
-              VariableDeclarationNode iteratorVariableDecl =
-                  new VariableDeclarationNode(iteratorVariable);
-              iteratorVariableDecl.setInSource(false);
+                extendWithNode(iteratorVariableDecl);
 
-              extendWithNode(iteratorVariableDecl);
+                Node expressionNode = scan(expression, p);
 
-              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);
 
-              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);
 
-              translateAssignment(iteratorVariable,
-                                  new LocalVariableNode(iteratorVariable),
-                                  iteratorCallNode);
+                // Test the loop ending condition
+                addLabelForNextNode(conditionStart);
+                IdentifierTree iteratorUse1 = treeBuilder.buildVariableUse(iteratorVariable);
+                handleArtificialTree(iteratorUse1);
 
-              // Test the loop ending condition
-              addLabelForNextNode(conditionStart);
-              IdentifierTree iteratorUse1 =
-                  treeBuilder.buildVariableUse(iteratorVariable);
-              handleArtificialTree(iteratorUse1);
+                LocalVariableNode iteratorReceiverNode = new LocalVariableNode(iteratorUse1);
+                iteratorReceiverNode.setInSource(false);
+                extendWithNode(iteratorReceiverNode);
 
-              LocalVariableNode iteratorReceiverNode =
-                  new LocalVariableNode(iteratorUse1);
-              iteratorReceiverNode.setInSource(false);
-              extendWithNode(iteratorReceiverNode);
+                MemberSelectTree hasNextSelect = treeBuilder.buildHasNextMethodAccess(iteratorUse1);
+                handleArtificialTree(hasNextSelect);
 
-              MemberSelectTree hasNextSelect =
-                  treeBuilder.buildHasNextMethodAccess(iteratorUse1);
-              handleArtificialTree(hasNextSelect);
+                MethodAccessNode hasNextAccessNode =
+                        new MethodAccessNode(hasNextSelect, iteratorReceiverNode);
+                hasNextAccessNode.setInSource(false);
+                extendWithNode(hasNextAccessNode);
 
-              MethodAccessNode hasNextAccessNode =
-                  new MethodAccessNode(hasNextSelect, iteratorReceiverNode);
-              hasNextAccessNode.setInSource(false);
-              extendWithNode(hasNextAccessNode);
+                MethodInvocationTree hasNextCall = treeBuilder.buildMethodInvocation(hasNextSelect);
+                handleArtificialTree(hasNextCall);
 
-              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));
 
-              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));
 
-              // Loop body, starting with declaration of the loop iteration variable
-              addLabelForNextNode(loopEntry);
-              extendWithNode(new VariableDeclarationNode(variable));
+                IdentifierTree iteratorUse2 = treeBuilder.buildVariableUse(iteratorVariable);
+                handleArtificialTree(iteratorUse2);
 
-              IdentifierTree iteratorUse2 =
-                  treeBuilder.buildVariableUse(iteratorVariable);
-              handleArtificialTree(iteratorUse2);
+                LocalVariableNode iteratorReceiverNode2 = new LocalVariableNode(iteratorUse2);
+                iteratorReceiverNode2.setInSource(false);
+                extendWithNode(iteratorReceiverNode2);
 
-              LocalVariableNode iteratorReceiverNode2 =
-                  new LocalVariableNode(iteratorUse2);
-              iteratorReceiverNode2.setInSource(false);
-              extendWithNode(iteratorReceiverNode2);
+                MemberSelectTree nextSelect = treeBuilder.buildNextMethodAccess(iteratorUse2);
+                handleArtificialTree(nextSelect);
 
-              MemberSelectTree nextSelect =
-                  treeBuilder.buildNextMethodAccess(iteratorUse2);
-              handleArtificialTree(nextSelect);
+                MethodAccessNode nextAccessNode =
+                        new MethodAccessNode(nextSelect, iteratorReceiverNode2);
+                nextAccessNode.setInSource(false);
+                extendWithNode(nextAccessNode);
 
-              MethodAccessNode nextAccessNode =
-                  new MethodAccessNode(nextSelect, iteratorReceiverNode2);
-              nextAccessNode.setInSource(false);
-              extendWithNode(nextAccessNode);
+                MethodInvocationTree nextCall = treeBuilder.buildMethodInvocation(nextSelect);
+                handleArtificialTree(nextCall);
 
-              MethodInvocationTree nextCall =
-                  treeBuilder.buildMethodInvocation(nextSelect);
-              handleArtificialTree(nextCall);
+                MethodInvocationNode nextCallNode =
+                        new MethodInvocationNode(
+                                nextCall,
+                                nextAccessNode,
+                                Collections.<Node>emptyList(),
+                                getCurrentPath());
+                nextCallNode.setInSource(false);
+                extendWithNode(nextCallNode);
 
-              MethodInvocationNode nextCallNode =
-                  new MethodInvocationNode(nextCall, nextAccessNode,
-                                           Collections.<Node>emptyList(), getCurrentPath());
-              nextCallNode.setInSource(false);
-              extendWithNode(nextCallNode);
+                translateAssignment(variable, new LocalVariableNode(variable), nextCall);
 
-              translateAssignment(variable,
-                                  new LocalVariableNode(variable),
-                                  nextCall);
+                if (statement != null) {
+                    scan(statement, p);
+                }
 
-              if (statement != null) {
-                  scan(statement, p);
-              }
+                // Loop back edge
+                addLabelForNextNode(updateStart);
+                extendWithExtendedNode(new UnconditionalJump(conditionStart));
 
-              // Loop back edge
-              addLabelForNextNode(updateStart);
-              extendWithExtendedNode(new UnconditionalJump(conditionStart));
+            } else {
+                // TODO: Shift any labels after the initialization of the
+                // temporary array variable.
 
-          } else {
-              // TODO: Shift any labels after the initialization of the
-              // temporary array variable.
+                VariableTree arrayVariable =
+                        createEnhancedForLoopArrayVariable(expression, variableElement);
+                handleArtificialTree(arrayVariable);
 
-              TypeMirror arrayType = InternalUtils.typeOf(expression);
+                VariableDeclarationNode arrayVariableNode =
+                        new VariableDeclarationNode(arrayVariable);
+                arrayVariableNode.setInSource(false);
+                extendWithNode(arrayVariableNode);
+                Node expressionNode = scan(expression, p);
 
-              // Declare and initialize a temporary array variable
-              VariableTree arrayVariable =
-                  treeBuilder.buildVariableDecl(arrayType,
-                                                uniqueName("array"),
-                                                variableElement.getEnclosingElement(),
-                                                expression);
-              handleArtificialTree(arrayVariable);
+                translateAssignment(
+                        arrayVariable, new LocalVariableNode(arrayVariable), expressionNode);
 
-              VariableDeclarationNode arrayVariableNode =
-                  new VariableDeclarationNode(arrayVariable);
-              arrayVariableNode.setInSource(false);
-              extendWithNode(arrayVariableNode);
-              Node expressionNode = scan(expression, p);
+                // Declare and initialize the loop index variable
+                TypeMirror intType = types.getPrimitiveType(TypeKind.INT);
 
-              translateAssignment(arrayVariable,
-                                  new LocalVariableNode(arrayVariable),
-                                  expressionNode);
+                LiteralTree zero = treeBuilder.buildLiteral(Integer.valueOf(0));
+                handleArtificialTree(zero);
 
-              // Declare and initialize the loop index variable
-              TypeMirror intType = types.getPrimitiveType(TypeKind.INT);
+                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));
 
-              LiteralTree zero =
-                  treeBuilder.buildLiteral(new Integer(0));
-              handleArtificialTree(zero);
+                translateAssignment(indexVariable, new LocalVariableNode(indexVariable), zeroNode);
 
-              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));
+                // Compare index to array length
+                addLabelForNextNode(conditionStart);
+                IdentifierTree indexUse1 = treeBuilder.buildVariableUse(indexVariable);
+                handleArtificialTree(indexUse1);
+                LocalVariableNode indexNode1 = new LocalVariableNode(indexUse1);
+                indexNode1.setInSource(false);
+                extendWithNode(indexNode1);
 
-              translateAssignment(indexVariable,
-                                  new LocalVariableNode(indexVariable),
-                                  zeroNode);
+                IdentifierTree arrayUse1 = treeBuilder.buildVariableUse(arrayVariable);
+                handleArtificialTree(arrayUse1);
+                LocalVariableNode arrayNode1 = extendWithNode(new LocalVariableNode(arrayUse1));
 
-              // Compare index to array length
-              addLabelForNextNode(conditionStart);
-              IdentifierTree indexUse1 =
-                  treeBuilder.buildVariableUse(indexVariable);
-              handleArtificialTree(indexUse1);
-              LocalVariableNode indexNode1 =
-                  new LocalVariableNode(indexUse1);
-              indexNode1.setInSource(false);
-              extendWithNode(indexNode1);
+                MemberSelectTree lengthSelect = treeBuilder.buildArrayLengthAccess(arrayUse1);
+                handleArtificialTree(lengthSelect);
+                FieldAccessNode lengthAccessNode = new FieldAccessNode(lengthSelect, arrayNode1);
+                lengthAccessNode.setInSource(false);
+                extendWithNode(lengthAccessNode);
 
-              IdentifierTree arrayUse1 =
-                  treeBuilder.buildVariableUse(arrayVariable);
-              handleArtificialTree(arrayUse1);
-              LocalVariableNode arrayNode1 =
-                  extendWithNode(new LocalVariableNode(arrayUse1));
+                BinaryTree lessThan = treeBuilder.buildLessThan(indexUse1, lengthSelect);
+                handleArtificialTree(lessThan);
 
-              MemberSelectTree lengthSelect =
-                  treeBuilder.buildArrayLengthAccess(arrayUse1);
-              handleArtificialTree(lengthSelect);
-              FieldAccessNode lengthAccessNode =
-                  new FieldAccessNode(lengthSelect, arrayNode1);
-              lengthAccessNode.setInSource(false);
-              extendWithNode(lengthAccessNode);
+                LessThanNode lessThanNode =
+                        new LessThanNode(lessThan, indexNode1, lengthAccessNode);
+                lessThanNode.setInSource(false);
+                extendWithNode(lessThanNode);
+                extendWithExtendedNode(new ConditionalJump(loopEntry, loopExit));
 
-              BinaryTree lessThan =
-                  treeBuilder.buildLessThan(indexUse1, lengthSelect);
-              handleArtificialTree(lessThan);
+                // Loop body, starting with declaration of the loop iteration variable
+                addLabelForNextNode(loopEntry);
+                extendWithNode(new VariableDeclarationNode(variable));
 
-              LessThanNode lessThanNode =
-                  new LessThanNode(lessThan, indexNode1, lengthAccessNode);
-              lessThanNode.setInSource(false);
-              extendWithNode(lessThanNode);
-              extendWithExtendedNode(new ConditionalJump(loopEntry, loopExit));
+                IdentifierTree arrayUse2 = treeBuilder.buildVariableUse(arrayVariable);
+                handleArtificialTree(arrayUse2);
+                LocalVariableNode arrayNode2 = new LocalVariableNode(arrayUse2);
+                arrayNode2.setInSource(false);
+                extendWithNode(arrayNode2);
 
-              // Loop body, starting with declaration of the loop iteration variable
-              addLabelForNextNode(loopEntry);
-              extendWithNode(new VariableDeclarationNode(variable));
+                IdentifierTree indexUse2 = treeBuilder.buildVariableUse(indexVariable);
+                handleArtificialTree(indexUse2);
+                LocalVariableNode indexNode2 = new LocalVariableNode(indexUse2);
+                indexNode2.setInSource(false);
+                extendWithNode(indexNode2);
 
-              IdentifierTree arrayUse2 =
-                  treeBuilder.buildVariableUse(arrayVariable);
-              handleArtificialTree(arrayUse2);
-              LocalVariableNode arrayNode2 =
-                  new LocalVariableNode(arrayUse2);
-              arrayNode2.setInSource(false);
-              extendWithNode(arrayNode2);
+                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);
 
-              IdentifierTree indexUse2 =
-                  treeBuilder.buildVariableUse(indexVariable);
-              handleArtificialTree(indexUse2);
-              LocalVariableNode indexNode2 =
-                  new LocalVariableNode(indexUse2);
-              indexNode2.setInSource(false);
-              extendWithNode(indexNode2);
+                if (statement != null) {
+                    scan(statement, p);
+                }
 
-              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);
+                // Loop back edge
+                addLabelForNextNode(updateStart);
 
-              if (statement != null) {
-                  scan(statement, p);
-              }
+                IdentifierTree indexUse3 = treeBuilder.buildVariableUse(indexVariable);
+                handleArtificialTree(indexUse3);
+                LocalVariableNode indexNode3 = new LocalVariableNode(indexUse3);
+                indexNode3.setInSource(false);
+                extendWithNode(indexNode3);
 
-              // Loop back edge
-              addLabelForNextNode(updateStart);
+                LiteralTree oneTree = treeBuilder.buildLiteral(Integer.valueOf(1));
+                handleArtificialTree(oneTree);
+                Node one = new IntegerLiteralNode(oneTree);
+                one.setInSource(false);
+                extendWithNode(one);
 
-              IdentifierTree indexUse3 =
-                  treeBuilder.buildVariableUse(indexVariable);
-              handleArtificialTree(indexUse3);
-              LocalVariableNode indexNode3 =
-                  new LocalVariableNode(indexUse3);
-              indexNode3.setInSource(false);
-              extendWithNode(indexNode3);
+                BinaryTree addOneTree =
+                        treeBuilder.buildBinary(intType, Tree.Kind.PLUS, indexUse3, oneTree);
+                handleArtificialTree(addOneTree);
+                Node addOneNode = new NumericalAdditionNode(addOneTree, indexNode3, one);
+                addOneNode.setInSource(false);
+                extendWithNode(addOneNode);
 
-              LiteralTree oneTree = treeBuilder.buildLiteral(Integer.valueOf(1));
-              handleArtificialTree(oneTree);
-              Node one = new IntegerLiteralNode(oneTree);
-              one.setInSource(false);
-              extendWithNode(one);
+                AssignmentTree assignTree = treeBuilder.buildAssignment(indexUse3, addOneTree);
+                handleArtificialTree(assignTree);
+                Node assignNode = new AssignmentNode(assignTree, indexNode3, addOneNode);
+                assignNode.setInSource(false);
+                extendWithNode(assignNode);
 
-              BinaryTree addOneTree = treeBuilder.buildBinary(intType, Tree.Kind.PLUS,
-                      indexUse3, oneTree);
-              handleArtificialTree(addOneTree);
-              Node addOneNode = new NumericalAdditionNode(addOneTree, indexNode3, one);
-              addOneNode.setInSource(false);
-              extendWithNode(addOneNode);
+                extendWithExtendedNode(new UnconditionalJump(conditionStart));
+            }
 
-              AssignmentTree assignTree = treeBuilder.buildAssignment(indexUse3, addOneTree);
-              handleArtificialTree(assignTree);
-              Node assignNode = new AssignmentNode(assignTree, indexNode3, addOneNode);
-              assignNode.setInSource(false);
-              extendWithNode(assignNode);
+            // Loop exit
+            addLabelForNextNode(loopExit);
 
-              extendWithExtendedNode(new UnconditionalJump(conditionStart));
-          }
+            breakTargetL = oldBreakTargetL;
+            continueTargetL = oldContinueTargetL;
 
-          // Loop exit
-          addLabelForNextNode(loopExit);
+            return null;
+        }
 
-          breakTargetL = oldBreakTargetL;
-          continueTargetL = oldContinueTargetL;
+        protected VariableTree createEnhancedForLoopIteratorVariable(
+                MethodInvocationTree iteratorCall, VariableElement variableElement) {
+            TypeMirror iteratorType = InternalUtils.typeOf(iteratorCall);
 
-          return null;
+            // 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 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 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 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 @@
                 }
             }
 
-            Node node = new ArrayCreationNode(tree, type, dimensionNodes,
-                    initializerNodes);
+            Node node = new ArrayCreationNode(tree, type, dimensionNodes, initializerNodes);
             return extendWithNode(node);
         }
 
@@ -3973,15 +3885,19 @@
 
             // 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 @@
             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 @@
         }
 
         /**
-         * 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 @@
             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);
+                    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);
+                    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 @@
                 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 @@
             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 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 @@
             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 @@
                 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 @@
                 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 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 @@
             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;
+                    {
+                        // 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);
+
+                        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;
+                    }
+
+                case OTHER:
                 default:
-                    assert false;
-                    break;
-                }
-                break;
-            }
+                    // special node NLLCHK
+                    if (tree.toString().startsWith("<*nullchk*>")) {
+                        Node expr = scan(tree.getExpression(), p);
+                        result = extendWithNode(new NullChkNode(tree, expr));
+                        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);
-
-                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;
-            }
-
-            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 @@
 
             // 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 @@
 
                 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 @@
         }
     }
 
-    /**
-     * 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 @@
     /* --------------------------------------------------------- */
 
     /**
-     * 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 abd4821..0000000
--- 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 0000000..9378d83
--- /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 759d261..0a2687a 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 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.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 @@
     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 @@
     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 @@
         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 @@
         }
     }
 
-    /** @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 @@
         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 @@
 
         // 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 @@
     }
 
     /**
-     * @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 @@
 
     /**
      * 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 @@
         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 @@
     }
 
     /**
-     * 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 0000000..1eb1cb8
--- /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 8d5ee1c..fa6ff55 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,27 +4,6 @@
 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 java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintStream;
-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;
@@ -32,10 +11,27 @@
 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.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 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 @@
                 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 @@
 
     /** 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 @@
         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 @@
     }
 
     /**
-     * @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 @@
             }
         };
     }
-
 }
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 5f61468..dd646f1 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.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 @@
         /** 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 @@
         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 @@
         }
     }
 
-    /**
-     * 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 @@
         }
     }
 
-    /**
-     * 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 @@
             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 81edef6..2d58550 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 @@
  * Represents a basic block in a control flow graph.
  *
  * @author Stefan Heule
- *
  */
 public interface Block {
 
@@ -24,14 +23,9 @@
         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 c3df418..0421a1e 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 @@
 
 /**
  * Base class of the {@link Block} implementation hierarchy.
- * 
+ *
  * @author Stefan Heule
- * 
  */
 public abstract class BlockImpl implements Block {
 
@@ -24,9 +23,7 @@
     /** 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 @@
         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 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 d267c99..dce04ab 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.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 629bb81..bd12522 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 @@
  * Implementation of a conditional basic block.
  *
  * @author Stefan Heule
- *
  */
 public class ConditionalBlockImpl extends BlockImpl implements ConditionalBlock {
 
@@ -17,34 +16,29 @@
     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 c00a7e1..a549c5f 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 @@
 
 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.
+ * 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>
- *
- * 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 2148e06..2a6c3b4 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.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 @@
     /** 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 @@
         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 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 dd6502f..5664492 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 853f2c9..b302710 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 @@
 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 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 4d56291..038a69d 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 @@
  * 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 7e5988e..9e8872e 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 @@
  * 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 @@
         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 89154bf..dac9b4b 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 @@
 
 /**
  * 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 @@
         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 9b3f8fb..e6f25e8 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 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 0f8a998..39f1f84 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}.
+ * 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>
- *
- * 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 @@
 
     // 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 c51d7c1..24ef689 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 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;
+import java.util.Collection;
+import java.util.LinkedList;
+import org.checkerframework.dataflow.util.HashCodeUtils;
+import org.checkerframework.javacutil.InternalUtils;
 
 /**
  * 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 @@
             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 4af6907..5f277f2 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 @@
 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 @@
  *
  * @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 d7e0cd7..dfde575 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 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;
+import java.util.Collection;
+import java.util.Collections;
+import org.checkerframework.dataflow.util.HashCodeUtils;
+import org.checkerframework.javacutil.InternalUtils;
 
 /**
- * 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 efc066a..0b4d747 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,14 +1,11 @@
 package org.checkerframework.dataflow.cfg.node;
 
-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;
+import java.util.Collection;
+import java.util.LinkedList;
+import javax.lang.model.type.TypeMirror;
+import org.checkerframework.dataflow.util.HashCodeUtils;
 
 /**
  * A node for the {@link AssertionError} when an assertion fails.
@@ -19,7 +16,6 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
 public class AssertionErrorNode extends Node {
 
@@ -66,8 +62,7 @@
             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 85d17e7..5e6a160 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 @@
         }
     }
 
-    /**
-     * 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 @@
         }
     }
 
-    /**
-     * 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 @@
         }
     }
 
-    /**
-     * 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 @@
         }
     }
 
-    /**
-     * 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 d48666a..32723dd 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 @@
  * We allow assignments without corresponding AST {@link Tree}s.
  *
  * @author Stefan Heule
- *
  */
 public class AssignmentNode extends Node {
 
@@ -36,8 +32,10 @@
 
     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 0000000..424747b
--- /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 82c5f5d..18d7163 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class BitwiseAndNode extends Node {
+public class BitwiseAndNode extends BinaryOperationNode {
 
-    protected Tree tree;
-    protected Node left;
-    protected Node right;
-
-    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 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 1b8ad73..a1c2111 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 @@
  *
  * @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 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 f9763c9..6608913 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class BitwiseOrNode extends Node {
+public class BitwiseOrNode extends BinaryOperationNode {
 
-    protected Tree tree;
-    protected Node left;
-    protected Node right;
-
-    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 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 848b2f1..cdbe0ed 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class BitwiseXorNode extends Node {
+public class BitwiseXorNode extends BinaryOperationNode {
 
-    protected Tree tree;
-    protected Node left;
-    protected Node right;
-
-    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 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 8368c87..7f5a7a1 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 @@
  * </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 f5a3d46..a694dfb 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 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;
+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;
 
 /**
- * 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 @@
  *
  * @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 979a417..c1d51c7 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 @@
  *
  * @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 b74965d..c3e2471 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 @@
 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 @@
         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 @@
         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 @@
         }
         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 dfa9f99..fb5145a 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class ConditionalAndNode extends Node {
+public class ConditionalAndNode extends BinaryOperationNode {
 
-    protected BinaryTree tree;
-    protected Node lhs;
-    protected Node rhs;
-
-    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 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 5143c69..6a28c67 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 @@
  *
  * @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 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 2da33fa..e5cb0bf 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 @@
  * </pre>
  *
  * @author Stefan Heule
- *
  */
-public class ConditionalOrNode extends Node {
+public class ConditionalOrNode extends BinaryOperationNode {
 
-    protected BinaryTree tree;
-    protected Node lhs;
-    protected Node rhs;
-
-    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 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 855a95a..60c2574 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 @@
  *
  * @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 ed56d4a..b1fb5d8 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 @@
  * </pre>
  *
  * @author Stefan Heule
- *
  */
-public class EqualToNode extends Node {
+public class EqualToNode extends BinaryOperationNode {
 
-    protected BinaryTree tree;
-    protected Node lhs;
-    protected Node rhs;
-
-    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 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 0c10698..abb3b54 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
 public class ExplicitThisLiteralNode extends ThisLiteralNode {
 
@@ -22,8 +20,7 @@
 
     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 db5bf51..1b8e856 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,19 +1,15 @@
 package org.checkerframework.dataflow.cfg.node;
 
-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;
+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;
 
 /**
  * A node for a field access, including a method accesses:
@@ -23,7 +19,6 @@
  * </pre>
  *
  * @author Stefan Heule
- *
  */
 public class FieldAccessNode extends Node {
 
@@ -45,7 +40,7 @@
             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 @@
         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 518c974..ee8b510 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 @@
  *
  * @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 cd495b7..6eb6c41 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class FloatingDivisionNode extends Node {
+public class FloatingDivisionNode extends BinaryOperationNode {
 
-    protected Tree tree;
-    protected Node left;
-    protected Node right;
-
-    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 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 d3b3caa..d3a7918 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class FloatingRemainderNode extends Node {
+public class FloatingRemainderNode extends BinaryOperationNode {
 
-    protected Tree tree;
-    protected Node left;
-    protected Node right;
-
-    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 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 50c45da..a0ddbaf 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 @@
 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 @@
  * </pre>
  *
  * @author David
- *
  */
 public class FunctionalInterfaceNode extends Node {
 
@@ -56,7 +54,7 @@
 
     @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 7e51ccd..f1713a9 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class GreaterThanNode extends Node {
+public class GreaterThanNode extends BinaryOperationNode {
 
-    protected Tree tree;
-    protected Node left;
-    protected Node right;
-
-    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 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 e23c824..058ae7b 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class GreaterThanOrEqualNode extends Node {
+public class GreaterThanOrEqualNode extends BinaryOperationNode {
 
-    protected Tree tree;
-    protected Node left;
-    protected Node right;
-
-    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 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 56bfa83..25a6361 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 com.sun.source.tree.Tree;
 import javax.lang.model.type.TypeMirror;
 
-import com.sun.source.tree.Tree;
-
 /**
- * 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 2f49436..78b4e06 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 @@
         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 0b57014..e69947b 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class IntegerDivisionNode extends Node {
+public class IntegerDivisionNode extends BinaryOperationNode {
 
-    protected Tree tree;
-    protected Node left;
-    protected Node right;
-
-    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 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 b23a9cb..5bea779 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 @@
  * </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 39021cd..d539918 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class IntegerRemainderNode extends Node {
+public class IntegerRemainderNode extends BinaryOperationNode {
 
-    protected Tree tree;
-    protected Node left;
-    protected Node right;
-
-    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 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 60652e6..65a1e13 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class LeftShiftNode extends Node {
+public class LeftShiftNode extends BinaryOperationNode {
 
-    protected Tree tree;
-    protected Node left;
-    protected Node right;
-
-    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 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 a8dd5a1..fcc9011 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class LessThanNode extends Node {
+public class LessThanNode extends BinaryOperationNode {
 
-    protected Tree tree;
-    protected Node left;
-    protected Node right;
-
-    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 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 4944ab6..0dfb65e 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class LessThanOrEqualNode extends Node {
+public class LessThanOrEqualNode extends BinaryOperationNode {
 
-    protected Tree tree;
-    protected Node left;
-    protected Node right;
-
-    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 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 5b18a71..724d63a 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,18 +1,14 @@
 package org.checkerframework.dataflow.cfg.node;
 
-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;
+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 for a local variable or a parameter:
@@ -21,11 +17,10 @@
  *   <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 @@
         }
         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 47f856a..b92575e 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 @@
  *
  * @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 fa7238e..a7a892f 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 @@
 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 @@
             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 75a8d68..060f17b 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,17 +1,13 @@
 package org.checkerframework.dataflow.cfg.node;
 
-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;
+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;
 
 /**
  * A node for a method access, including a method accesses:
@@ -21,7 +17,6 @@
  * </pre>
  *
  * @author Stefan Heule
- *
  */
 public class MethodAccessNode extends Node {
 
@@ -68,8 +63,7 @@
             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 797185a..9456f37 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,17 +1,14 @@
 package org.checkerframework.dataflow.cfg.node;
 
-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;
+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;
 
 /**
  * A node for method invocation
@@ -20,12 +17,11 @@
  *   <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 @@
     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 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 @@
         }
         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 f0165d9..79a4728 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 @@
         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 f59cc81..fb5bf53 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 @@
 import org.checkerframework.checker.nullness.qual.Nullable;
 */
 
+import com.sun.source.tree.Tree;
+import java.util.Collection;
+import java.util.LinkedList;
+import javax.lang.model.type.TypeMirror;
 import org.checkerframework.dataflow.cfg.CFGBuilder;
 import org.checkerframework.dataflow.cfg.block.Block;
 
-import java.util.Collection;
-import java.util.LinkedList;
-
-import javax.lang.model.type.TypeMirror;
-
-import com.sun.source.tree.Tree;
-
 /**
- * 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 @@
     }
 
     /**
-     * @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 @@
     }
 
     /**
-     * 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 @@
     /**
      * 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 @@
         return lvalue;
     }
 
-    /**
-     * Make this node an l-value.
-     */
+    /** Make this node an l-value. */
     public void setLValue() {
         lvalue = true;
     }
@@ -146,16 +124,12 @@
         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 @@
         }
         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 fe75186..8a2f513 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 @@
  * 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 @@
     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 c043e20..debd7cb 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class NotEqualNode extends Node {
+public class NotEqualNode extends BinaryOperationNode {
 
-    protected Tree tree;
-    protected Node left;
-    protected Node right;
-
-    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 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 01ac008..6609a29 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,14 +1,11 @@
 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 java.util.Collection;
+import java.util.Collections;
+import org.checkerframework.dataflow.util.HashCodeUtils;
+import org.checkerframework.javacutil.InternalUtils;
 
 /**
  * A node for the unary 'nullchk' operation (generated by the Java compiler):
@@ -22,51 +19,51 @@
  */
 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 Node getOperand() {
-            return operand;
-        }
-
-        @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 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 int hashCode() {
-            return HashCodeUtils.hash(getOperand());
-        }
-
-        @Override
-        public Collection<Node> getOperands() {
-            return Collections.singletonList(getOperand());
-        }
+    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;
+    }
+
+    @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 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 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/NullLiteralNode.java b/third_party/checker_framework_dataflow/java/org/checkerframework/dataflow/cfg/node/NullLiteralNode.java
index 66e6715..1fcdeb4 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 @@
  *
  * @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 d4192ad..4692856 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 @@
  * </pre>
  *
  * @author Stefan Heule
- *
  */
-public class NumericalAdditionNode extends Node {
+public class NumericalAdditionNode extends BinaryOperationNode {
 
-    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 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 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 459f299..141ab58 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 @@
  *
  * @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 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 947dc5d..85561a1 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class NumericalMultiplicationNode extends Node {
+public class NumericalMultiplicationNode extends BinaryOperationNode {
 
-    protected Tree tree;
-    protected Node left;
-    protected Node right;
-
-    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 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 3d19b27..21b5b58 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 @@
  *
  * @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 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 1526a18..a962ead 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class NumericalSubtractionNode extends Node {
+public class NumericalSubtractionNode extends BinaryOperationNode {
 
-    protected Tree tree;
-    protected Node left;
-    protected Node right;
-
-    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 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 67f2dee..8ab862a 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
 public class ObjectCreationNode extends Node {
 
@@ -28,9 +23,7 @@
     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 @@
     }
 
     @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 326ac5e..3c69b82 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 @@
 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 @@
         }
         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 7939b41..774ac8b 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,14 +1,11 @@
 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.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;
 
 /**
  * A node for a parameterized type occurring in an expression:
@@ -17,16 +14,13 @@
  *   <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 69b1856..379bb92 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 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;
+import java.util.Collection;
+import java.util.Collections;
+import org.checkerframework.dataflow.util.HashCodeUtils;
+import org.checkerframework.javacutil.InternalUtils;
 
 /**
- * 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 dbc74c8..b7222df 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,20 +5,17 @@
 */
 
 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 java.util.Collection;
+import java.util.Collections;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.util.Types;
 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;
-
 /**
  * A node for a return statement:
  *
@@ -28,7 +25,6 @@
  * </pre>
  *
  * @author Stefan Heule
- *
  */
 public class ReturnNode extends Node {
 
@@ -42,14 +38,18 @@
         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 @@
             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 f61da82..cd1db1e 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 @@
  *   <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 3683ab9..ac4aa58 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class SignedRightShiftNode extends Node {
+public class SignedRightShiftNode extends BinaryOperationNode {
 
-    protected Tree tree;
-    protected Node left;
-    protected Node right;
-
-    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 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 d6c4c53..0e6f006 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,12 +1,10 @@
 package org.checkerframework.dataflow.cfg.node;
 
-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;
+import java.util.Collection;
+import java.util.LinkedList;
+import org.checkerframework.javacutil.InternalUtils;
 
 /**
  * A node for the string concatenation compound assignment:
@@ -17,7 +15,6 @@
  *
  * @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 e42d6ac..c69beea 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class StringConcatenateNode extends Node {
+public class StringConcatenateNode extends BinaryOperationNode {
 
-    protected Tree tree;
-    protected Node left;
-    protected Node right;
-
-    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 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 2f62c8a..8ba8c6f 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 e8d9291..c6ec1c9 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 @@
  * </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 d6ce410..797eae8 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,14 +1,11 @@
 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.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;
 
 /**
  * A node for a reference to 'super'.
@@ -19,7 +16,6 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
 public class SuperNode extends Node {
 
@@ -27,8 +23,7 @@
 
     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 86d28bd..a17e2fa 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 @@
  * 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 @@
     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 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 514f859..9a149a3 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,14 +1,11 @@
 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.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;
 
 /**
  * A node for a conditional expression:
@@ -19,7 +16,6 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
 public class TernaryExpressionNode extends Node {
 
@@ -28,8 +24,8 @@
     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 @@
 
     @Override
     public String toString() {
-        return "(" + getConditionOperand() + " ? " + getThenOperand() + " : "
-                + getElseOperand() + ")";
+        return "("
+                + getConditionOperand()
+                + " ? "
+                + getThenOperand()
+                + " : "
+                + getElseOperand()
+                + ")";
     }
 
     @Override
@@ -79,8 +80,7 @@
 
     @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 f62d6ac..3bb4c18 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 @@
 
 import java.util.Collection;
 import java.util.Collections;
-
 import javax.lang.model.type.TypeMirror;
-
 import org.checkerframework.dataflow.util.HashCodeUtils;
 
 /**
@@ -16,7 +14,6 @@
  *
  * @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 f563cef..bb36e10 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,15 +1,12 @@
 package org.checkerframework.dataflow.cfg.node;
 
-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;
+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;
 
 /**
  * A node for exception throws:
@@ -20,15 +17,13 @@
  *
  * @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 ce287a5..f6e71bf 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 @@
         return operand;
     }
 
+    @Override
     public TypeMirror getType() {
         return type;
     }
@@ -60,8 +57,7 @@
         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 0000000..cb33e6a
--- /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 0ddea5b..2609a7d 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 @@
  *
  * @author Stefan Heule
  * @author Charlie Garrett
- *
  */
-public class UnsignedRightShiftNode extends Node {
+public class UnsignedRightShiftNode extends BinaryOperationNode {
 
-    protected Tree tree;
-    protected Node left;
-    protected Node right;
-
-    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 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 68058d3..4c9c18f 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 @@
 
 /**
  * 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 @@
         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 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 5841768..867cdf1 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 @@
  *   <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 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 4724ec1..9b949ea 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 @@
         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 25cf739..7908838 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 @@
 
 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 f63c232..a95af7f 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 java.util.Objects;
-
 import org.checkerframework.dataflow.analysis.AbstractValue;
 
 public class Constant implements AbstractValue<Constant> {
@@ -17,7 +16,9 @@
     protected /*@Nullable*/ Integer value;
 
     public enum Type {
-        CONSTANT, TOP, BOTTOM,
+        CONSTANT,
+        TOP,
+        BOTTOM,
     }
 
     public Constant(Type type) {
@@ -56,12 +57,15 @@
 
     @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 @@
 
     @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 @@
     @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 3c96f8f..e7a718e 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 @@
 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 @@
             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 @@
     }
 
     @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 @@
     }
 
     @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 @@
         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 @@
     }
 
     @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;
+    public void visualize(CFGVisualizer<?, ConstantPropagationStore, ?> viz) {
+        // Do nothing since ConstantPropagationStore doesn't support visualize
     }
-
-    @Override
-    public String toDOToutput() {
-        return "";
-    }
-
 }
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 434bb96..d5da13a 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.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 @@
 
     @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 @@
             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 e79543f..7e7d8b9 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.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.
+ *
+ * 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.
+ *
+ * <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>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>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>
  *
- * 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>
- *
- * 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>
- *
- * 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>
- *
- * @checker_framework.manual #type-refinement-purity Side effects, determinism, purity, and flow-sensitive analysis
- *
+ * @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 a210c1a..0000000
--- 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 a559c1d..5a00db7 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.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}.
+ * {@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
- *
+ * @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 0521113..6a969c4 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.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.
+ *
+ * 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.
+ *
  * <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>
- *
- * @checker_framework.manual #type-refinement-purity Side effects, determinism, purity, and flow-sensitive analysis
- *
+ * @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 93ff95c..4e83dcd 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.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 200f96d..f898e3c 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 @@
  * Utility class to implement the {@code hashCode} method.
  *
  * @author Stefan Heule
- *
  */
 public class HashCodeUtils {
 
@@ -47,8 +46,9 @@
 
     /** 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 @@
 
     /** 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 44bdbd6..7e9172d 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.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 @@
     @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 @@
     @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 @@
     @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;
+            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;
+                    @Override
+                    public boolean hasNext() {
+                        return hasNext;
                     }
-                    throw new NoSuchElementException();
-                }
 
-                @Override
-                public void remove() {
-                    throw new UnsupportedOperationException();
-                }
-            };
-        case ANY:
-            return set.iterator();
-        default:
-            throw new AssertionError();
+                    @Override
+                    public T next() {
+                        if (hasNext) {
+                            hasNext = false;
+                            return value;
+                        }
+                        throw new NoSuchElementException();
+                    }
+
+                    @Override
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+                };
+            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 d429d23..cf7a090 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 @@
 
         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 5fafb7a..0b298f1 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.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.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 @@
             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 @@
     }
 
     /**
-     * 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 @@
             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 @@
         }
 
         @Override
-        public PurityResult visitEmptyStatement(EmptyStatementTree node,
-                PurityResult p) {
+        public PurityResult visitEmptyStatement(EmptyStatementTree node, PurityResult p) {
             return p;
         }
 
@@ -240,8 +219,7 @@
         }
 
         @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 @@
         }
 
         @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 @@
         }
 
         @Override
-        public PurityResult visitLabeledStatement(LabeledStatementTree node,
-                PurityResult p) {
+        public PurityResult visitLabeledStatement(LabeledStatementTree node, PurityResult p) {
             return scan(node.getStatement(), p);
         }
 
@@ -293,8 +269,7 @@
         }
 
         @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 @@
         }
 
         @Override
-        public PurityResult visitExpressionStatement(
-                ExpressionStatementTree node, PurityResult p) {
+        public PurityResult visitExpressionStatement(ExpressionStatementTree node, PurityResult p) {
             return scan(node.getExpression(), p);
         }
 
@@ -368,17 +342,15 @@
         }
 
         @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 @@
         @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 @@
         }
 
         @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 @@
             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 @@
         }
 
         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 @@
         }
 
         @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 @@
             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 6b19543..c175877 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) {
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AbstractTypeProcessor.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AbstractTypeProcessor.java
index 0438903..114ce6d 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AbstractTypeProcessor.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AbstractTypeProcessor.java
@@ -1,136 +1,117 @@
 package org.checkerframework.javacutil;
 
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.annotation.processing.*;
-import javax.lang.model.element.Name;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.ElementFilter;
-
-import com.sun.tools.javac.main.JavaCompiler;
-import com.sun.tools.javac.comp.CompileStates.CompileState;
-import com.sun.tools.javac.processing.JavacProcessingEnvironment;
-import com.sun.tools.javac.util.Context;
-import com.sun.tools.javac.util.Log;
-
 import com.sun.source.tree.ClassTree;
 import com.sun.source.util.JavacTask;
 import com.sun.source.util.TaskEvent;
 import com.sun.source.util.TaskListener;
 import com.sun.source.util.TreePath;
 import com.sun.source.util.Trees;
+import com.sun.tools.javac.comp.CompileStates.CompileState;
+import com.sun.tools.javac.main.JavaCompiler;
+import com.sun.tools.javac.processing.JavacProcessingEnvironment;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Log;
+import java.util.HashSet;
+import java.util.Set;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.Processor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.ElementFilter;
 
 /**
- * This class is an abstract annotation processor designed to be a
- * convenient superclass for concrete "type processors", processors that
- * require the type information in the processed source.
+ * This class is an abstract annotation processor designed to be a convenient superclass for
+ * concrete "type processors", processors that require the type information in the processed source.
  *
- * <p>Type processing occurs in one round after the tool (e.g. Java compiler)
- * analyzes the source (all sources taken as input to the tool and sources
- * generated by other annotation processors).
+ * <p>Type processing occurs in one round after the tool (e.g. Java compiler) analyzes the source
+ * (all sources taken as input to the tool and sources generated by other annotation processors).
  *
- * <p>The tool infrastructure will interact with classes extending this abstract
- * class as follows.
+ * <p>The tool infrastructure will interact with classes extending this abstract class as follows.
  *
- * <p>
- *  1-3 are Identical to the {@link Processor} life cycle.
- *  4-5 are unique to {@code AbstractTypeProcessor} subclasses.
+ * <p>1-3 are identical to the {@link Processor} life cycle. 4-5 are unique to {@code
+ * AbstractTypeProcessor} subclasses.
  *
  * <ol>
- *
- * <li>If an existing {@code Processor} object is not being used, to
- * create an instance of a processor the tool calls the no-arg
- * constructor of the processor class.
- *
- * <li>Next, the tool calls the {@link #init init} method with
- * an appropriate {@code ProcessingEnvironment}.
- *
- * <li>Afterwards, the tool calls {@link #getSupportedAnnotationTypes
- * getSupportedAnnotationTypes}, {@link #getSupportedOptions
- * getSupportedOptions}, and {@link #getSupportedSourceVersion
- * getSupportedSourceVersion}.  These methods are only called once per
- * run, not on each round.
- *
- *
- * <li>For each class containing a supported annotation, the tool calls
- * {@link #typeProcess(TypeElement, TreePath) typeProcess} method on the
- * {@code Processor}.  The class is guaranteed to be type-checked Java code
- * and all the tree type and symbol information is resolved.
- *
- * <li>Finally, the tools calls the
- * {@link #typeProcessingOver() typeProcessingOver} method
- * on the {@code Processor}.
- *
+ *   <li>If an existing {@code Processor} object is not being used, to create an instance of a
+ *       processor the tool calls the no-arg constructor of the processor class.
+ *   <li>Next, the tool calls the {@link #init init} method with an appropriate {@code
+ *       ProcessingEnvironment}.
+ *   <li>Afterwards, the tool calls {@link #getSupportedAnnotationTypes
+ *       getSupportedAnnotationTypes}, {@link #getSupportedOptions getSupportedOptions}, and {@link
+ *       #getSupportedSourceVersion getSupportedSourceVersion}. These methods are only called once
+ *       per run, not on each round.
+ *   <li>For each class containing a supported annotation, the tool calls {@link
+ *       #typeProcess(TypeElement, TreePath) typeProcess} method on the {@code Processor}. The class
+ *       is guaranteed to be type-checked Java code and all the tree type and symbol information is
+ *       resolved.
+ *   <li>Finally, the tools calls the {@link #typeProcessingOver() typeProcessingOver} method on the
+ *       {@code Processor}.
  * </ol>
  *
- * <p>The tool is permitted to ask type processors to process a class once
- * it is analyzed before the rest of classes are analyzed.  The tool is also
- * permitted to stop type processing immediately if any errors are raised,
- * without invoking {@code typeProcessingOver}
+ * <p>The tool is permitted to ask type processors to process a class once it is analyzed before the
+ * rest of classes are analyzed. The tool is also permitted to stop type processing immediately if
+ * any errors are raised, without invoking {@code typeProcessingOver}
  *
- * <p>A subclass may override any of the methods in this class, as long as the
- * general {@link javax.annotation.processing.Processor Processor}
- * contract is obeyed, with one notable exception.
- * {@link #process(Set, RoundEnvironment)} may not be overridden, as it
- * is called during the declaration annotation phase before classes are analyzed.
+ * <p>A subclass may override any of the methods in this class, as long as the general {@link
+ * javax.annotation.processing.Processor Processor} contract is obeyed, with one notable exception.
+ * {@link #process(Set, RoundEnvironment)} may not be overridden, as it is called during the
+ * declaration annotation phase before classes are analyzed.
  *
  * @author Mahmood Ali
  * @author Werner Dietl
  */
 public abstract class AbstractTypeProcessor extends AbstractProcessor {
     /**
-     * The set of fully-qualified element names that should be type-checked.
-     * We store the names of the elements, in order to prevent
-     * possible confusion between different Element instantiations.
+     * The set of fully-qualified element names that should be type-checked. We store the names of
+     * the elements, in order to prevent possible confusion between different Element
+     * instantiations.
      */
     private final Set<Name> elements = new HashSet<Name>();
 
     /**
-     * Method {@link #typeProcessingStart()} must be invoked exactly once,
-     * before any invocation of {@link #typeProcess(TypeElement, TreePath)}.
+     * Method {@link #typeProcessingStart()} must be invoked exactly once, before any invocation of
+     * {@link #typeProcess(TypeElement, TreePath)}.
      */
     private boolean hasInvokedTypeProcessingStart = false;
 
     /**
-     * Method {@link #typeProcessingOver()} must be invoked exactly once,
-     * after the last invocation of {@link #typeProcess(TypeElement, TreePath)}.
+     * Method {@link #typeProcessingOver()} must be invoked exactly once, after the last invocation
+     * of {@link #typeProcess(TypeElement, TreePath)}.
      */
     private static boolean hasInvokedTypeProcessingOver = false;
 
-    /**
-     * The TaskListener registered for completion of attribution.
-     */
+    /** The TaskListener registered for completion of attribution. */
     private final AttributionTaskListener listener = new AttributionTaskListener();
 
-    /**
-     * Constructor for subclasses to call.
-     */
-    protected AbstractTypeProcessor() { }
+    /** Constructor for subclasses to call. */
+    protected AbstractTypeProcessor() {}
 
     /**
      * {@inheritDoc}
      *
-     * Register a TaskListener that will get called after FLOW.
+     * <p>Register a TaskListener that will get called after FLOW.
      */
     @Override
-    public void init(ProcessingEnvironment env) {
+    public synchronized void init(ProcessingEnvironment env) {
         super.init(env);
         JavacTask.instance(env).addTaskListener(listener);
         Context ctx = ((JavacProcessingEnvironment) processingEnv).getContext();
         JavaCompiler compiler = JavaCompiler.instance(ctx);
-        compiler.shouldStopPolicyIfNoError = CompileState.max(compiler.shouldStopPolicyIfNoError,
-                                                           CompileState.FLOW);
+        compiler.shouldStopPolicyIfNoError =
+                CompileState.max(compiler.shouldStopPolicyIfNoError, CompileState.FLOW);
+        compiler.shouldStopPolicyIfError =
+                CompileState.max(compiler.shouldStopPolicyIfError, CompileState.FLOW);
     }
 
     /**
-     * The use of this method is obsolete in type processors.  The method is
-     * called during declaration annotation processing phase only.
-     * It registers the names of elements to process.
+     * The use of this method is obsolete in type processors. The method is called during
+     * declaration annotation processing phase only. It registers the names of elements to process.
      */
     @Override
-    public final boolean process(Set<? extends TypeElement> annotations,
-            RoundEnvironment roundEnv) {
+    public final boolean process(
+            Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
         for (TypeElement elem : ElementFilter.typesIn(roundEnv.getRootElements())) {
             elements.add(elem.getQualifiedName());
         }
@@ -145,39 +126,35 @@
     public void typeProcessingStart() {}
 
     /**
-     * Processes a fully analyzed class that contains a supported annotation
-     * (look {@link #getSupportedAnnotationTypes()}).
+     * Processes a fully-analyzed class that contains a supported annotation (see {@link
+     * #getSupportedAnnotationTypes()}).
      *
      * <p>The passed class is always valid type-checked Java code.
      *
-     * @param element       element of the analyzed class
-     * @param tree  the tree path to the element, with the leaf being a
-     *              {@link ClassTree}
+     * @param element element of the analyzed class
+     * @param tree the tree path to the element, with the leaf being a {@link ClassTree}
      */
     public abstract void typeProcess(TypeElement element, TreePath tree);
 
     /**
-     * A method to be called once all the classes are processed and no error
-     * is reported.
+     * A method to be called once all the classes are processed and no error is reported.
      *
-     * <p>Subclasses may override this method to do any aggregate analysis
-     * (e.g. generate report, persistence) or resource deallocation.
+     * <p>Subclasses may override this method to do any aggregate analysis (e.g. generate report,
+     * persistence) or resource deallocation.
      *
-     * <p>If an error (a Java error or a processor error) is reported, this
-     * method is not guaranteed to be invoked.
+     * <p>If an error (a Java error or a processor error) is reported, this method is not guaranteed
+     * to be invoked.
      */
-    public void typeProcessingOver() { }
+    public void typeProcessingOver() {}
 
-    /**
-     * A task listener that invokes the processor whenever a class is fully
-     * analyzed.
-     */
+    /** A task listener that invokes the processor whenever a class is fully analyzed. */
     private final class AttributionTaskListener implements TaskListener {
 
         @Override
         public void finished(TaskEvent e) {
-            if (e.getKind() != TaskEvent.Kind.ANALYZE)
+            if (e.getKind() != TaskEvent.Kind.ANALYZE) {
                 return;
+            }
 
             if (!hasInvokedTypeProcessingStart) {
                 typeProcessingStart();
@@ -191,13 +168,16 @@
                 hasInvokedTypeProcessingOver = true;
             }
 
-            if (e.getTypeElement() == null)
+            if (e.getTypeElement() == null) {
                 throw new AssertionError("event task without a type element");
-            if (e.getCompilationUnit() == null)
+            }
+            if (e.getCompilationUnit() == null) {
                 throw new AssertionError("event task without compilation unit");
+            }
 
-            if (!elements.remove(e.getTypeElement().getQualifiedName()))
+            if (!elements.remove(e.getTypeElement().getQualifiedName())) {
                 return;
+            }
 
             TypeElement elem = e.getTypeElement();
             TreePath p = Trees.instance(processingEnv).getPath(elem);
@@ -211,6 +191,6 @@
         }
 
         @Override
-        public void started(TaskEvent e) { }
+        public void started(TaskEvent e) {}
     }
 }
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AnnotationProvider.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AnnotationProvider.java
index 8ed857a..1245960 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AnnotationProvider.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AnnotationProvider.java
@@ -1,38 +1,28 @@
 package org.checkerframework.javacutil;
 
+import com.sun.source.tree.Tree;
 import java.lang.annotation.Annotation;
-
 import javax.lang.model.element.AnnotationMirror;
 import javax.lang.model.element.Element;
 
-import com.sun.source.tree.Tree;
-
-/**
- * An implementation of AnnotationProvider returns annotations on
- * Java AST elements.
- */
+/** An implementation of AnnotationProvider returns annotations on Java AST elements. */
 public interface AnnotationProvider {
 
     /**
-     * Returns the actual annotation mirror used to annotate this type,
-     * whose name equals the passed annotationName if one exists, null otherwise.
+     * Returns the actual annotation mirror used to annotate this type, whose name equals the passed
+     * annotationName if one exists, null otherwise.
      *
      * @param anno annotation class
      * @return the annotation mirror for anno
      */
-    public AnnotationMirror getDeclAnnotation(Element elt,
-            Class<? extends Annotation> anno);
-    
+    public AnnotationMirror getDeclAnnotation(Element elt, Class<? extends Annotation> anno);
+
     /**
-     * Return the annotation on <code>tree</code> that has the class
-     * <code>target</code>. If no annotation for the given target class exists,
-     * the result is <code>null</code>
-     * 
-     * @param tree
-     *            The tree of which the annotation is returned
-     * @param target
-     *            The class of the annotation
+     * Return the annotation on {@code tree} that has the class {@code target}. If no annotation for
+     * the given target class exists, the result is {@code null}
+     *
+     * @param tree the tree of which the annotation is returned
+     * @param target the class of the annotation
      */
-    public AnnotationMirror getAnnotationMirror(Tree tree,
-            Class<? extends Annotation> target);
+    public AnnotationMirror getAnnotationMirror(Tree tree, Class<? extends Annotation> target);
 }
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AnnotationUtils.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AnnotationUtils.java
index 54eb54d..c80f57c 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AnnotationUtils.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/AnnotationUtils.java
@@ -7,7 +7,12 @@
 import org.checkerframework.checker.interning.qual.*;
 */
 
-
+import com.sun.source.tree.AnnotationTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.ModifiersTree;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.model.JavacElements;
 import java.lang.annotation.Annotation;
 import java.lang.annotation.Inherited;
 import java.util.ArrayList;
@@ -21,7 +26,6 @@
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.TreeSet;
-
 import javax.lang.model.element.AnnotationMirror;
 import javax.lang.model.element.AnnotationValue;
 import javax.lang.model.element.ElementKind;
@@ -33,23 +37,19 @@
 import javax.lang.model.util.ElementFilter;
 import javax.lang.model.util.Elements;
 
-import com.sun.tools.javac.code.Symbol.VarSymbol;
-import com.sun.tools.javac.code.Type;
-import com.sun.tools.javac.model.JavacElements;
-/**
- * A utility class for working with annotations.
- */
+/** A utility class for working with annotations. */
 public class AnnotationUtils {
 
     // Class cannot be instantiated.
-    private AnnotationUtils() { throw new AssertionError("Class AnnotationUtils cannot be instantiated."); }
+    private AnnotationUtils() {
+        throw new AssertionError("Class AnnotationUtils cannot be instantiated.");
+    }
 
     // TODO: hack to clear out static state.
-    // {@link org.checkerframework.qualframework.util.QualifierContext} should
-    // handle instantiation of utility classes.
     public static void clear() {
         annotationsFromNames.clear();
         annotationMirrorNames.clear();
+        annotationMirrorSimpleNames.clear();
         annotationClassNames.clear();
     }
 
@@ -58,68 +58,85 @@
     // **********************************************************************
 
     /** Caching for annotation creation. */
-    private static final Map<CharSequence, AnnotationMirror> annotationsFromNames
-        = new HashMap<CharSequence, AnnotationMirror>();
+    private static final Map<CharSequence, AnnotationMirror> annotationsFromNames =
+            Collections.synchronizedMap(new HashMap<CharSequence, AnnotationMirror>());
+
+    private static final int ANNOTATION_CACHE_SIZE = 500;
 
     /**
-     * Cache names of AnnotationMirrors for faster access.  Values in
-     * the map are interned Strings, so they can be compared with ==.
+     * Cache names of AnnotationMirrors for faster access. Values in the map are interned Strings,
+     * so they can be compared with ==.
      */
-    private static final Map<AnnotationMirror, /*@Interned*/ String> annotationMirrorNames
-        = new HashMap<AnnotationMirror, /*@Interned*/ String>();
+    private static final Map<AnnotationMirror, /*@Interned*/ String> annotationMirrorNames =
+            Collections.synchronizedMap(
+                    CollectionUtils.<AnnotationMirror, /*@Interned*/ String>createLRUCache(
+                            ANNOTATION_CACHE_SIZE));
 
     /**
-     * Cache names of classes representing AnnotationMirrors for
-     * faster access.  Values in the map are interned Strings, so they
-     * can be compared with ==.
+     * Cache simple names of AnnotationMirrors for faster access. Values in the map are interned
+     * Strings, so they can be compared with ==.
      */
-    private static final Map<Class<? extends Annotation>, /*@Interned*/ String> annotationClassNames
-        = new HashMap<Class<? extends Annotation>, /*@Interned*/ String>();
+    private static final Map<AnnotationMirror, /*@Interned*/ String> annotationMirrorSimpleNames =
+            Collections.synchronizedMap(
+                    CollectionUtils.<AnnotationMirror, /*@Interned*/ String>createLRUCache(
+                            ANNOTATION_CACHE_SIZE));
 
     /**
-     * Creates an {@link AnnotationMirror} given by a particular
-     * fully-qualified name.  getElementValues on the result returns an
-     * empty map.
+     * Cache names of classes representing AnnotationMirrors for faster access. Values in the map
+     * are interned Strings, so they can be compared with ==.
+     */
+    private static final Map<Class<? extends Annotation>, /*@Interned*/ String>
+            annotationClassNames =
+                    Collections.synchronizedMap(
+                            new HashMap<Class<? extends Annotation>, /*@Interned*/ String>());
+
+    /**
+     * Creates an {@link AnnotationMirror} given by a particular fully-qualified name.
+     * getElementValues on the result returns an empty map.
      *
      * @param elements the element utilities to use
      * @param name the name of the annotation to create
      * @return an {@link AnnotationMirror} of type {@code} name
      */
     public static AnnotationMirror fromName(Elements elements, CharSequence name) {
-        if (annotationsFromNames.containsKey(name))
-            return annotationsFromNames.get(name);
+        AnnotationMirror res = annotationsFromNames.get(name);
+        if (res != null) {
+            return res;
+        }
         final DeclaredType annoType = typeFromName(elements, name);
-        if (annoType == null)
+        if (annoType == null) {
             return null;
+        }
         if (annoType.asElement().getKind() != ElementKind.ANNOTATION_TYPE) {
             ErrorReporter.errorAbort(annoType + " is not an annotation");
             return null; // dead code
         }
-        AnnotationMirror result = new AnnotationMirror() {
-            String toString = "@" + annoType;
+        AnnotationMirror result =
+                new AnnotationMirror() {
+                    String toString = "@" + annoType;
 
-            @Override
-            public DeclaredType getAnnotationType() {
-                return annoType;
-            }
-            @Override
-            public Map<? extends ExecutableElement, ? extends AnnotationValue>
-                getElementValues() {
-                return Collections.emptyMap();
-            }
-            /*@SideEffectFree*/
-            @Override
-            public String toString() {
-                return toString;
-            }
-        };
+                    @Override
+                    public DeclaredType getAnnotationType() {
+                        return annoType;
+                    }
+
+                    @Override
+                    public Map<? extends ExecutableElement, ? extends AnnotationValue>
+                            getElementValues() {
+                        return Collections.emptyMap();
+                    }
+                    /*@SideEffectFree*/
+                    @Override
+                    public String toString() {
+                        return toString;
+                    }
+                };
         annotationsFromNames.put(name, result);
         return result;
     }
 
     /**
-     * Creates an {@link AnnotationMirror} given by a particular annotation
-     * class.
+     * Creates an {@link AnnotationMirror} given by a particular annotation class.
      *
      * @param elements the element utilities to use
      * @param clazz the annotation class
@@ -130,8 +147,8 @@
     }
 
     /**
-     * A utility method that converts a {@link CharSequence} (usually a {@link
-     * String}) into a {@link TypeMirror} named thereby.
+     * A utility method that converts a {@link CharSequence} (usually a {@link String}) into a
+     * {@link TypeMirror} named thereby.
      *
      * @param elements the element utilities to use
      * @param name the name of a type
@@ -139,26 +156,25 @@
      */
     private static DeclaredType typeFromName(Elements elements, CharSequence name) {
         /*@Nullable*/ TypeElement typeElt = elements.getTypeElement(name);
-        if (typeElt == null)
+        if (typeElt == null) {
             return null;
+        }
 
         return (DeclaredType) typeElt.asType();
     }
 
-
     // **********************************************************************
     // Helper methods to handle annotations.  mainly workaround
     // AnnotationMirror.equals undesired property
     // (I think the undesired property is that it's reference equality.)
     // **********************************************************************
 
-    /**
-     * @return the fully-qualified name of an annotation as a Name
-     */
+    /** @return the fully-qualified name of an annotation as a String */
     public static final /*@Interned*/ String annotationName(AnnotationMirror annotation) {
-        if (annotationMirrorNames.containsKey(annotation))
-            return annotationMirrorNames.get(annotation);
-
+        String res = annotationMirrorNames.get(annotation);
+        if (res != null) {
+            return res;
+        }
         final DeclaredType annoType = annotation.getAnnotationType();
         final TypeElement elm = (TypeElement) annoType.asElement();
         /*@Interned*/ String name = elm.getQualifiedName().toString().intern();
@@ -166,25 +182,40 @@
         return name;
     }
 
+    /** @return the simple name of an annotation as a String */
+    public static String annotationSimpleName(AnnotationMirror annotation) {
+        String res = annotationMirrorSimpleNames.get(annotation);
+        if (res != null) {
+            return res;
+        }
+        final DeclaredType annoType = annotation.getAnnotationType();
+        final TypeElement elm = (TypeElement) annoType.asElement();
+        /*@Interned*/ String name = elm.getSimpleName().toString().intern();
+        annotationMirrorSimpleNames.put(annotation, name);
+        return name;
+    }
+
     /**
      * Checks if both annotations are the same.
      *
-     * Returns true iff both annotations are of the same type and have the
-     * same annotation values.  This behavior differs from
-     * {@code AnnotationMirror.equals(Object)}.  The equals method returns
-     * true iff both annotations are the same and annotate the same annotation
-     * target (e.g. field, variable, etc).
+     * <p>Returns true iff both annotations are of the same type and have the same annotation
+     * values. This behavior differs from {@code AnnotationMirror.equals(Object)}. The equals method
+     * returns true iff both annotations are the same and annotate the same annotation target (e.g.
+     * field, variable, etc).
      *
      * @return true iff a1 and a2 are the same annotation
      */
-    public static boolean areSame(/*@Nullable*/ AnnotationMirror a1, /*@Nullable*/ AnnotationMirror a2) {
+    public static boolean areSame(
+            /*@Nullable*/ AnnotationMirror a1, /*@Nullable*/ AnnotationMirror a2) {
         if (a1 != null && a2 != null) {
             if (annotationName(a1) != annotationName(a2)) {
                 return false;
             }
 
-            Map<? extends ExecutableElement, ? extends AnnotationValue> elval1 = getElementValuesWithDefaults(a1);
-            Map<? extends ExecutableElement, ? extends AnnotationValue> elval2 = getElementValuesWithDefaults(a2);
+            Map<? extends ExecutableElement, ? extends AnnotationValue> elval1 =
+                    getElementValuesWithDefaults(a1);
+            Map<? extends ExecutableElement, ? extends AnnotationValue> elval2 =
+                    getElementValuesWithDefaults(a2);
 
             return elval1.toString().equals(elval2.toString());
         }
@@ -198,30 +229,22 @@
      * @return true iff a1 and a2 have the same annotation type
      */
     public static boolean areSameIgnoringValues(AnnotationMirror a1, AnnotationMirror a2) {
-        if (a1 != null && a2 != null)
+        if (a1 != null && a2 != null) {
             return annotationName(a1) == annotationName(a2);
+        }
         return a1 == a2;
     }
 
-    /**
-     * Checks that the annotation {@code am} has the name {@code aname}. Values
-     * are ignored.
-     */
+    /** Checks that the annotation {@code am} has the name {@code aname}. Values are ignored. */
     public static boolean areSameByName(AnnotationMirror am, /*@Interned*/ String aname) {
         // Both strings are interned.
         return annotationName(am) == aname;
     }
 
-    /**
-     * Checks that the annotation {@code am} has the name of {@code anno}.
-     * Values are ignored.
-     */
-    public static boolean areSameByClass(AnnotationMirror am,
-            Class<? extends Annotation> anno) {
-        /*@Interned*/ String canonicalName;
-        if (annotationClassNames.containsKey(anno)) {
-            canonicalName = annotationClassNames.get(anno).intern();
-        } else {
+    /** Checks that the annotation {@code am} has the name of {@code anno}. Values are ignored. */
+    public static boolean areSameByClass(AnnotationMirror am, Class<? extends Annotation> anno) {
+        /*@Interned*/ String canonicalName = annotationClassNames.get(anno);
+        if (canonicalName == null) {
             canonicalName = anno.getCanonicalName().intern();
             annotationClassNames.put(anno, canonicalName);
         }
@@ -233,11 +256,14 @@
      *
      * @return true iff c1 and c2 contain the same annotations
      */
-    public static boolean areSame(Collection<? extends AnnotationMirror> c1, Collection<? extends AnnotationMirror> c2) {
-        if (c1.size() != c2.size())
+    public static boolean areSame(
+            Collection<? extends AnnotationMirror> c1, Collection<? extends AnnotationMirror> c2) {
+        if (c1.size() != c2.size()) {
             return false;
-        if (c1.size() == 1)
+        }
+        if (c1.size() == 1) {
             return areSame(c1.iterator().next(), c2.iterator().next());
+        }
 
         Set<AnnotationMirror> s1 = createAnnotationSet();
         Set<AnnotationMirror> s2 = createAnnotationSet();
@@ -251,78 +277,122 @@
         while (iter1.hasNext()) {
             AnnotationMirror anno1 = iter1.next();
             AnnotationMirror anno2 = iter2.next();
-            if (!areSame(anno1, anno2))
+            if (!areSame(anno1, anno2)) {
                 return false;
+            }
         }
         return true;
     }
 
     /**
-     * Checks that the collection contains the annotation.
-     * Using Collection.contains does not always work, because it
-     * does not use areSame for comparison.
+     * Checks that the collection contains the annotation. Using Collection.contains does not always
+     * work, because it does not use areSame for comparison.
      *
-     * @return true iff c contains anno, according to areSame.
+     * @return true iff c contains anno, according to areSame
      */
-    public static boolean containsSame(Collection<? extends AnnotationMirror> c, AnnotationMirror anno) {
-        for(AnnotationMirror an : c) {
-            if(AnnotationUtils.areSame(an, anno)) {
-                return true;
-            }
-        }
-        return false;
+    public static boolean containsSame(
+            Collection<? extends AnnotationMirror> c, AnnotationMirror anno) {
+        return getSame(c, anno) != null;
     }
 
     /**
-     * Checks that the collection contains the annotation.
-     * Using Collection.contains does not always work, because it
-     * does not use areSame for comparison.
+     * Returns the AnnotationMirror in {@code c} that is the same annotation as {@code anno}.
      *
-     * @return true iff c contains anno, according to areSameByClass.
+     * @return AnnotationMirror with the same class as {@code anno} iff c contains anno, according
+     *     to areSame; otherwise, {@code null}
      */
-    public static boolean containsSameByClass(Collection<? extends AnnotationMirror> c, Class<? extends Annotation> anno) {
-        for(AnnotationMirror an : c) {
-            if(AnnotationUtils.areSameByClass(an, anno)) {
-                return true;
+    public static AnnotationMirror getSame(
+            Collection<? extends AnnotationMirror> c, AnnotationMirror anno) {
+        for (AnnotationMirror an : c) {
+            if (AnnotationUtils.areSame(an, anno)) {
+                return an;
             }
         }
-        return false;
+        return null;
     }
 
     /**
-     * Checks that the collection contains the annotation ignoring values.
-     * Using Collection.contains does not always work, because it
-     * does not use areSameIgnoringValues for comparison.
+     * Checks that the collection contains the annotation. Using Collection.contains does not always
+     * work, because it does not use areSame for comparison.
      *
-     * @return true iff c contains anno, according to areSameIgnoringValues.
+     * @return true iff c contains anno, according to areSameByClass
      */
-    public static boolean containsSameIgnoringValues(Collection<? extends AnnotationMirror> c, AnnotationMirror anno) {
-        for(AnnotationMirror an : c) {
-            if(AnnotationUtils.areSameIgnoringValues(an, anno)) {
-                return true;
-            }
-        }
-        return false;
+    public static boolean containsSameByClass(
+            Collection<? extends AnnotationMirror> c, Class<? extends Annotation> anno) {
+        return getAnnotationByClass(c, anno) != null;
     }
 
-    private static final Comparator<AnnotationMirror> ANNOTATION_ORDERING
-    = new Comparator<AnnotationMirror>() {
-        @Override
-        public int compare(AnnotationMirror a1, AnnotationMirror a2) {
-            String n1 = a1.toString();
-            String n2 = a2.toString();
-
-            return n1.compareTo(n2);
+    /**
+     * Returns the AnnotationMirror in {@code c} that has the same class as {@code anno}.
+     *
+     * @return AnnotationMirror with the same class as {@code anno} iff c contains anno, according
+     *     to areSameByClass; otherwise, {@code null}
+     */
+    public static AnnotationMirror getAnnotationByClass(
+            Collection<? extends AnnotationMirror> c, Class<? extends Annotation> anno) {
+        for (AnnotationMirror an : c) {
+            if (AnnotationUtils.areSameByClass(an, anno)) {
+                return an;
+            }
         }
-    };
+        return null;
+    }
 
     /**
-     * provide ordering for {@link AnnotationMirror} based on their fully
-     * qualified name.  The ordering ignores annotation values when ordering.
+     * Checks that the collection contains the annotation ignoring values. Using Collection.contains
+     * does not always work, because it does not use areSameIgnoringValues for comparison.
      *
-     * The ordering is meant to be used as {@link TreeSet} or {@link TreeMap}
-     * ordering.  A {@link Set} should not contain two annotations that only
-     * differ in values.
+     * @return true iff c contains anno, according to areSameIgnoringValues
+     */
+    public static boolean containsSameIgnoringValues(
+            Collection<? extends AnnotationMirror> c, AnnotationMirror anno) {
+        return getSameIgnoringValues(c, anno) != null;
+    }
+
+    /**
+     * Returns the AnnotationMirror in {@code c} that is the same annotation as {@code anno}
+     * ignoring values.
+     *
+     * @return AnnotationMirror with the same class as {@code anno} iff c contains anno, according
+     *     to areSameIgnoringValues; otherwise, {@code null}
+     */
+    public static AnnotationMirror getSameIgnoringValues(
+            Collection<? extends AnnotationMirror> c, AnnotationMirror anno) {
+        for (AnnotationMirror an : c) {
+            if (AnnotationUtils.areSameIgnoringValues(an, anno)) {
+                return an;
+            }
+        }
+        return null;
+    }
+
+    private static final Comparator<AnnotationMirror> ANNOTATION_ORDERING =
+            new Comparator<AnnotationMirror>() {
+                @Override
+                public int compare(AnnotationMirror a1, AnnotationMirror a2) {
+                    // AnnotationMirror.toString() prints the elements of an annotation in the
+                    // order in which they were written. So, use areSame to check for equality.
+                    if (AnnotationUtils.areSame(a1, a2)) {
+                        return 0;
+                    }
+
+                    String n1 = a1.toString();
+                    String n2 = a2.toString();
+
+                    // Because the AnnotationMirror.toString prints the annotation as it appears
+                    // in source code, the order in which annotations of the same class are
+                    // sorted may be confusing.  For example, it might order
+                    // @IntRange(from=1, to=MAX) before @IntRange(to=MAX,from=0).
+                    return n1.compareTo(n2);
+                }
+            };
+
+    /**
+     * provide ordering for {@link AnnotationMirror} based on their fully qualified name. The
+     * ordering ignores annotation values when ordering.
+     *
+     * <p>The ordering is meant to be used as {@link TreeSet} or {@link TreeMap} ordering. A {@link
+     * Set} should not contain two annotations that only differ in values.
      */
     public static Comparator<AnnotationMirror> annotationOrdering() {
         return ANNOTATION_ORDERING;
@@ -331,8 +401,8 @@
     /**
      * Create a map suitable for storing {@link AnnotationMirror} as keys.
      *
-     * It can store one instance of {@link AnnotationMirror} of a given
-     * declared type, regardless of the annotation element values.
+     * <p>It can store one instance of {@link AnnotationMirror} of a given declared type, regardless
+     * of the annotation element values.
      *
      * @param <V> the value of the map
      * @return a new map with {@link AnnotationMirror} as key
@@ -344,8 +414,8 @@
     /**
      * Constructs a {@link Set} suitable for storing {@link AnnotationMirror}s.
      *
-     * It stores at most once instance of {@link AnnotationMirror} of a given
-     * type, regardless of the annotation element values.
+     * <p>It stores at most once instance of {@link AnnotationMirror} of a given type, regardless of
+     * the annotation element values.
      *
      * @return a new set to store {@link AnnotationMirror} as element
      */
@@ -358,62 +428,75 @@
         return anno.getAnnotationType().asElement().getAnnotation(Inherited.class) != null;
     }
 
-
     // **********************************************************************
     // Extractors for annotation values
     // **********************************************************************
 
     /**
-     * Returns the values of an annotation's attributes, including defaults.
-     * The method with the same name in JavacElements cannot be used directly,
-     * because it includes a cast to Attribute.Compound, which doesn't hold
-     * for annotations generated by the Checker Framework.
+     * Returns the values of an annotation's attributes, including defaults. The method with the
+     * same name in JavacElements cannot be used directly, because it includes a cast to
+     * Attribute.Compound, which doesn't hold for annotations generated by the Checker Framework.
      *
      * @see AnnotationMirror#getElementValues()
      * @see JavacElements#getElementValuesWithDefaults(AnnotationMirror)
-     *
-     * @param ad  annotation to examine
+     * @param ad annotation to examine
      * @return the values of the annotation's elements, including defaults
      */
     public static Map<? extends ExecutableElement, ? extends AnnotationValue>
-    getElementValuesWithDefaults(AnnotationMirror ad) {
-        Map<ExecutableElement, AnnotationValue> valMap
-            = new HashMap<ExecutableElement, AnnotationValue>();
+            getElementValuesWithDefaults(AnnotationMirror ad) {
+        Map<ExecutableElement, AnnotationValue> valMap =
+                new HashMap<ExecutableElement, AnnotationValue>();
         if (ad.getElementValues() != null) {
             valMap.putAll(ad.getElementValues());
         }
         for (ExecutableElement meth :
-            ElementFilter.methodsIn(ad.getAnnotationType().asElement().getEnclosedElements())) {
+                ElementFilter.methodsIn(ad.getAnnotationType().asElement().getEnclosedElements())) {
             AnnotationValue defaultValue = meth.getDefaultValue();
-            if (defaultValue != null && !valMap.containsKey(meth))
+            if (defaultValue != null && !valMap.containsKey(meth)) {
                 valMap.put(meth, defaultValue);
+            }
         }
         return valMap;
     }
 
     /**
-     * Get the attribute with the name {@code name} of the annotation
-     * {@code anno}. The result is expected to have type {@code expectedType}.
+     * Verify whether the attribute with the name {@code name} exists in the annotation {@code
+     * anno}.
      *
-     * <p>
-     * <em>Note 1</em>: The method does not work well for attributes of an array
-     * type (as it would return a list of {@link AnnotationValue}s). Use
-     * {@code getElementValueArray} instead.
+     * @param anno the annotation to examine
+     * @param name the name of the attribute
+     * @return whether the attribute exists in anno
+     */
+    public static <T> boolean hasElementValue(AnnotationMirror anno, CharSequence name) {
+        Map<? extends ExecutableElement, ? extends AnnotationValue> valmap =
+                anno.getElementValues();
+        for (ExecutableElement elem : valmap.keySet()) {
+            if (elem.getSimpleName().contentEquals(name)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Get the attribute with the name {@code name} of the annotation {@code anno}. The result is
+     * expected to have type {@code expectedType}.
      *
-     * <p>
-     * <em>Note 2</em>: The method does not work for attributes of an enum type,
-     * as the AnnotationValue is a VarSymbol and would be cast to the enum type,
-     * which doesn't work. Use {@code getElementValueEnum} instead.
+     * <p><em>Note 1</em>: The method does not work well for attributes of an array type (as it
+     * would return a list of {@link AnnotationValue}s). Use {@code getElementValueArray} instead.
      *
+     * <p><em>Note 2</em>: The method does not work for attributes of an enum type, as the
+     * AnnotationValue is a VarSymbol and would be cast to the enum type, which doesn't work. Use
+     * {@code getElementValueEnum} instead.
      *
      * @param anno the annotation to disassemble
      * @param name the name of the attribute to access
      * @param expectedType the expected type used to cast the return type
-     * @param useDefaults whether to apply default values to the attribute.
+     * @param useDefaults whether to apply default values to the attribute
      * @return the value of the attribute with the given name
      */
-    public static <T> T getElementValue(AnnotationMirror anno, CharSequence name,
-            Class<T> expectedType, boolean useDefaults) {
+    public static <T> T getElementValue(
+            AnnotationMirror anno, CharSequence name, Class<T> expectedType, boolean useDefaults) {
         Map<? extends ExecutableElement, ? extends AnnotationValue> valmap;
         if (useDefaults) {
             valmap = getElementValuesWithDefaults(anno);
@@ -430,34 +513,31 @@
         return null; // dead code
     }
 
-    /**
-     * Version that is suitable for Enum elements.
-     */
+    /** Version that is suitable for Enum elements. */
     public static <T extends Enum<T>> T getElementValueEnum(
-            AnnotationMirror anno, CharSequence name, Class<T> t,
-            boolean useDefaults) {
+            AnnotationMirror anno, CharSequence name, Class<T> t, boolean useDefaults) {
         VarSymbol vs = getElementValue(anno, name, VarSymbol.class, useDefaults);
         T value = Enum.valueOf(t, vs.getSimpleName().toString());
         return value;
     }
 
     /**
-     * Get the attribute with the name {@code name} of the annotation
-     * {@code anno}, where the attribute has an array type. One element of the
-     * result is expected to have type {@code expectedType}.
+     * Get the attribute with the name {@code name} of the annotation {@code anno}, where the
+     * attribute has an array type. One element of the result is expected to have type {@code
+     * expectedType}.
      *
-     * Parameter useDefaults is used to determine whether default values
-     * should be used for annotation values. Finding defaults requires
-     * more computation, so should be false when no defaulting is needed.
+     * <p>Parameter useDefaults is used to determine whether default values should be used for
+     * annotation values. Finding defaults requires more computation, so should be false when no
+     * defaulting is needed.
      *
      * @param anno the annotation to disassemble
      * @param name the name of the attribute to access
      * @param expectedType the expected type used to cast the return type
-     * @param useDefaults whether to apply default values to the attribute.
+     * @param useDefaults whether to apply default values to the attribute
      * @return the value of the attribute with the given name
      */
-    public static <T> List<T> getElementValueArray(AnnotationMirror anno,
-            CharSequence name, Class<T> expectedType, boolean useDefaults) {
+    public static <T> List<T> getElementValueArray(
+            AnnotationMirror anno, CharSequence name, Class<T> expectedType, boolean useDefaults) {
         @SuppressWarnings("unchecked")
         List<AnnotationValue> la = getElementValue(anno, name, List.class, useDefaults);
         List<T> result = new ArrayList<T>(la.size());
@@ -468,14 +548,13 @@
     }
 
     /**
-     * Get the attribute with the name {@code name} of the annotation
-     * {@code anno}, or the default value if no attribute is present explicitly,
-     * where the attribute has an array type and the elements are {@code Enum}s.
-     * One element of the result is expected to have type {@code expectedType}.
+     * Get the attribute with the name {@code name} of the annotation {@code anno}, or the default
+     * value if no attribute is present explicitly, where the attribute has an array type and the
+     * elements are {@code Enum}s. One element of the result is expected to have type {@code
+     * expectedType}.
      */
     public static <T extends Enum<T>> List<T> getElementValueEnumArray(
-            AnnotationMirror anno, CharSequence name, Class<T> t,
-            boolean useDefaults) {
+            AnnotationMirror anno, CharSequence name, Class<T> t, boolean useDefaults) {
         @SuppressWarnings("unchecked")
         List<AnnotationValue> la = getElementValue(anno, name, List.class, useDefaults);
         List<T> result = new ArrayList<T>(la.size());
@@ -487,42 +566,58 @@
     }
 
     /**
-     * Get the Name of the class that is referenced by attribute 'name'.
-     * This is a convenience method for the most common use-case.
-     * Like getElementValue(anno, name, ClassType.class).getQualifiedName(), but
-     * this method ensures consistent use of the qualified name.
+     * Get the Name of the class that is referenced by attribute {@code name}.
+     *
+     * <p>This is a convenience method for the most common use-case. Like getElementValue(anno,
+     * name, ClassType.class).getQualifiedName(), but this method ensures consistent use of the
+     * qualified name.
      */
-    public static Name getElementValueClassName(AnnotationMirror anno, CharSequence name,
-            boolean useDefaults) {
+    public static Name getElementValueClassName(
+            AnnotationMirror anno, CharSequence name, boolean useDefaults) {
         Type.ClassType ct = getElementValue(anno, name, Type.ClassType.class, useDefaults);
         // TODO:  Is it a problem that this returns the type parameters too?  Should I cut them off?
         return ct.asElement().getQualifiedName();
     }
 
+    /** Get the list of Names of the classes that are referenced by attribute {@code name}. */
+    public static List<Name> getElementValueClassNames(
+            AnnotationMirror anno, CharSequence name, boolean useDefaults) {
+        List<Type.ClassType> la =
+                getElementValueArray(anno, name, Type.ClassType.class, useDefaults);
+        List<Name> names = new ArrayList<>();
+        for (Type.ClassType classType : la) {
+            names.add(classType.asElement().getQualifiedName());
+        }
+        return names;
+    }
+
     /**
-     * Get the Class that is referenced by attribute 'name'.
-     * This method uses Class.forName to load the class. It returns
-     * null if the class wasn't found.
+     * Get the Class that is referenced by attribute {@code name}. This method uses Class.forName to
+     * load the class. It returns null if the class wasn't found.
      */
-    public static Class<?> getElementValueClass(AnnotationMirror anno, CharSequence name,
-            boolean useDefaults) {
+    public static Class<?> getElementValueClass(
+            AnnotationMirror anno, CharSequence name, boolean useDefaults) {
         Name cn = getElementValueClassName(anno, name, useDefaults);
         try {
-            Class<?> cls =  Class.forName(cn.toString());
+            ClassLoader classLoader = InternalUtils.getClassLoaderForClass(AnnotationUtils.class);
+            Class<?> cls = Class.forName(cn.toString(), true, classLoader);
             return cls;
         } catch (ClassNotFoundException e) {
-            ErrorReporter.errorAbort("Could not load class '" + cn + "' for field '" + name +
-                    "' in annotation " + anno, e);
+            String msg =
+                    String.format(
+                            "Could not load class '%s' for field '%s' in annotation %s",
+                            cn, name, anno);
+            ErrorReporter.errorAbort(msg, e);
             return null; // dead code
         }
     }
 
     /**
-     * See checkers.types.QualifierHierarchy#updateMappingToMutableSet(QualifierHierarchy, Map, Object, AnnotationMirror)
-     * (Not linked because it is in an independent project.
+     * See checkers.types.QualifierHierarchy#updateMappingToMutableSet(QualifierHierarchy, Map,
+     * Object, AnnotationMirror) (Not linked because it is in an independent project.
      */
-    public static <T> void updateMappingToImmutableSet(Map<T, Set<AnnotationMirror>> map,
-            T key, Set<AnnotationMirror> newQual) {
+    public static <T> void updateMappingToImmutableSet(
+            Map<T, Set<AnnotationMirror>> map, T key, Set<AnnotationMirror> newQual) {
 
         Set<AnnotationMirror> result = AnnotationUtils.createAnnotationSet();
         // TODO: if T is also an AnnotationMirror, should we use areSame?
@@ -534,4 +629,22 @@
         }
         map.put(key, Collections.unmodifiableSet(result));
     }
+
+    /**
+     * Returns the annotations explicitly written on a constructor result. Callers should check that
+     * {@code constructorDeclaration} is in fact a declaration of a constructor.
+     *
+     * @param constructorDeclaration declaration tree of constructor
+     * @return set of annotations explicit on the resulting type of the constructor
+     */
+    public static Set<AnnotationMirror> getExplicitAnnotationsOnConstructorResult(
+            MethodTree constructorDeclaration) {
+        Set<AnnotationMirror> annotationSet = AnnotationUtils.createAnnotationSet();
+        ModifiersTree modifiersTree = constructorDeclaration.getModifiers();
+        if (modifiersTree != null) {
+            List<? extends AnnotationTree> annotationTrees = modifiersTree.getAnnotations();
+            annotationSet.addAll(InternalUtils.annotationsFromTypeAnnotationTrees(annotationTrees));
+        }
+        return annotationSet;
+    }
 }
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/BasicAnnotationProvider.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/BasicAnnotationProvider.java
index b885b5c..6cf40e7 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/BasicAnnotationProvider.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/BasicAnnotationProvider.java
@@ -1,21 +1,16 @@
 package org.checkerframework.javacutil;
 
+import com.sun.source.tree.Tree;
 import java.lang.annotation.Annotation;
-
 import java.util.List;
-
 import javax.lang.model.element.AnnotationMirror;
 import javax.lang.model.element.Element;
 
-import com.sun.source.tree.Tree;
-
 public class BasicAnnotationProvider implements AnnotationProvider {
 
     @Override
-    public AnnotationMirror getDeclAnnotation(Element elt,
-            Class<? extends Annotation> anno) {
-        List<? extends AnnotationMirror> annotationMirrors = elt
-                .getAnnotationMirrors();
+    public AnnotationMirror getDeclAnnotation(Element elt, Class<? extends Annotation> anno) {
+        List<? extends AnnotationMirror> annotationMirrors = elt.getAnnotationMirrors();
 
         // Then look at the real annotations.
         for (AnnotationMirror am : annotationMirrors) {
@@ -28,8 +23,7 @@
     }
 
     @Override
-    public AnnotationMirror getAnnotationMirror(Tree tree,
-            Class<? extends Annotation> target) {
+    public AnnotationMirror getAnnotationMirror(Tree tree, Class<? extends Annotation> target) {
         return null;
     }
 }
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/BasicTypeProcessor.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/BasicTypeProcessor.java
index c83a000..6b68fa4 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/BasicTypeProcessor.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/BasicTypeProcessor.java
@@ -1,28 +1,22 @@
 package org.checkerframework.javacutil;
 
-import javax.lang.model.element.TypeElement;
-
 import com.sun.source.tree.CompilationUnitTree;
-
 import com.sun.source.util.TreePath;
 import com.sun.source.util.TreePathScanner;
+import javax.lang.model.element.TypeElement;
 
 /**
- * Process the types in an AST in a trivial manner, with hooks for derived classes
- * to actually do something.
+ * Process the types in an AST in a trivial manner, with hooks for derived classes to actually do
+ * something.
  */
 public abstract class BasicTypeProcessor extends AbstractTypeProcessor {
     /** The source tree that's being scanned. */
     protected CompilationUnitTree currentRoot;
 
-    /**
-     * Create a TreePathScanner at the given root.
-     */
+    /** Create a TreePathScanner at the given root. */
     protected abstract TreePathScanner<?, ?> createTreePathScanner(CompilationUnitTree root);
 
-    /**
-     * Visit the tree path for the type element.
-     */
+    /** Visit the tree path for the type element. */
     @Override
     public void typeProcess(TypeElement e, TreePath p) {
         currentRoot = p.getCompilationUnit();
@@ -32,12 +26,12 @@
             scanner = createTreePathScanner(currentRoot);
             scanner.scan(p, null);
         } catch (Throwable t) {
-            System.err.println("BasicTypeProcessor.typeProcess: unexpected Throwable (" +
-                    t.getClass().getSimpleName() + ")  when processing "
-                    + currentRoot.getSourceFile().getName() +
-                    (t.getMessage()!=null ? "; message: " + t.getMessage() : ""));
+            System.err.println(
+                    "BasicTypeProcessor.typeProcess: unexpected Throwable ("
+                            + t.getClass().getSimpleName()
+                            + ")  when processing "
+                            + currentRoot.getSourceFile().getName()
+                            + (t.getMessage() != null ? "; message: " + t.getMessage() : ""));
         }
     }
-
 }
-
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/CollectionUtils.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/CollectionUtils.java
new file mode 100644
index 0000000..a6a5825
--- /dev/null
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/CollectionUtils.java
@@ -0,0 +1,26 @@
+package org.checkerframework.javacutil;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/** Utility methods related to Java Collections */
+public class CollectionUtils {
+
+    /**
+     * A Utility method for creating LRU cache
+     *
+     * @param size size of the cache
+     * @return a new cache with the provided size
+     */
+    public static <K, V> Map<K, V> createLRUCache(final int size) {
+        return new LinkedHashMap<K, V>() {
+
+            private static final long serialVersionUID = 5261489276168775084L;
+
+            @Override
+            protected boolean removeEldestEntry(Map.Entry<K, V> entry) {
+                return size() > size;
+            }
+        };
+    }
+}
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ElementUtils.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ElementUtils.java
index 160a9c2..4abfa86 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ElementUtils.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ElementUtils.java
@@ -8,6 +8,7 @@
 import static com.sun.tools.javac.code.Flags.EFFECTIVELY_FINAL;
 import static com.sun.tools.javac.code.Flags.FINAL;
 
+import com.sun.tools.javac.code.Symbol;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -16,7 +17,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-
+import javax.annotation.processing.ProcessingEnvironment;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
@@ -31,26 +32,23 @@
 import javax.lang.model.util.ElementFilter;
 import javax.lang.model.util.Elements;
 
-import com.sun.tools.javac.code.Symbol;
-
-/**
- * A Utility class for analyzing {@code Element}s.
- */
+/** A Utility class for analyzing {@code Element}s. */
 public class ElementUtils {
 
     // Class cannot be instantiated.
-    private ElementUtils() { throw new AssertionError("Class ElementUtils cannot be instantiated."); }
+    private ElementUtils() {
+        throw new AssertionError("Class ElementUtils cannot be instantiated.");
+    }
 
     /**
      * Returns the innermost type element enclosing the given element
      *
      * @param elem the enclosed element of a class
-     * @return  the innermost type element
+     * @return the innermost type element
      */
     public static TypeElement enclosingClass(final Element elem) {
         Element result = elem;
-        while (result != null && !result.getKind().isClass()
-                && !result.getKind().isInterface()) {
+        while (result != null && !result.getKind().isClass() && !result.getKind().isInterface()) {
             /*@Nullable*/ Element encl = result.getEnclosingElement();
             result = encl;
         }
@@ -58,13 +56,12 @@
     }
 
     /**
-     * Returns the innermost package element enclosing the given element.
-     * The same effect as {@link javax.lang.model.util.Elements#getPackageOf(Element)}.
-     * Returns the element itself if it is a package.
+     * Returns the innermost package element enclosing the given element. The same effect as {@link
+     * javax.lang.model.util.Elements#getPackageOf(Element)}. Returns the element itself if it is a
+     * package.
      *
      * @param elem the enclosed element of a package
      * @return the innermost package element
-     *
      */
     public static PackageElement enclosingPackage(final Element elem) {
         Element result = elem;
@@ -76,20 +73,21 @@
     }
 
     /**
-     * Returns the "parent" package element for the given package element.
-     * For package "A.B" it gives "A".
-     * For package "A" it gives the default package.
-     * For the default package it returns null;
+     * Returns the "parent" package element for the given package element. For package "A.B" it
+     * gives "A". For package "A" it gives the default package. For the default package it returns
+     * null;
      *
-     * Note that packages are not enclosed within each other, we have to manually climb
-     * the namespaces. Calling "enclosingPackage" on a package element returns the
-     * package element itself again.
+     * <p>Note that packages are not enclosed within each other, we have to manually climb the
+     * namespaces. Calling "enclosingPackage" on a package element returns the package element
+     * itself again.
      *
      * @param elem the package to start from
      * @return the parent package element
-     *
      */
     public static PackageElement parentPackage(final Elements e, final PackageElement elem) {
+        // The following might do the same thing:
+        //   ((Symbol) elt).owner;
+        // TODO: verify and see whether the change is worth it.
         String fqnstart = elem.getQualifiedName().toString();
         String fqn = fqnstart;
         if (fqn != null && !fqn.isEmpty() && fqn.contains(".")) {
@@ -100,10 +98,9 @@
     }
 
     /**
-     * Returns true if the element is a static element: whether it is a static
-     * field, static method, or static class
+     * Returns true if the element is a static element: whether it is a static field, static method,
+     * or static class
      *
-     * @param element
      * @return true if element is static
      */
     public static boolean isStatic(Element element) {
@@ -111,10 +108,8 @@
     }
 
     /**
-     * Returns true if the element is a final element: a final field, final
-     * method, or final class
+     * Returns true if the element is a final element: a final field, final method, or final class
      *
-     * @param element
      * @return true if the element is final
      */
     public static boolean isFinal(Element element) {
@@ -124,44 +119,39 @@
     /**
      * Returns true if the element is a effectively final element.
      *
-     * @param element
      * @return true if the element is effectively final
      */
     public static boolean isEffectivelyFinal(Element element) {
         Symbol sym = (Symbol) element;
-        if (sym.getEnclosingElement().getKind() == ElementKind.METHOD &&
-                (sym.getEnclosingElement().flags() & ABSTRACT) != 0) {
+        if (sym.getEnclosingElement().getKind() == ElementKind.METHOD
+                && (sym.getEnclosingElement().flags() & ABSTRACT) != 0) {
             return true;
         }
         return (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0;
     }
 
     /**
-     * Returns the {@code TypeMirror} for usage of Element as a value. It
-     * returns the return type of a method element, the class type of a
-     * constructor, or simply the type mirror of the element itself.
+     * Returns the {@code TypeMirror} for usage of Element as a value. It returns the return type of
+     * a method element, the class type of a constructor, or simply the type mirror of the element
+     * itself.
      *
-     * @param element
-     * @return  the type for the element used as a value
+     * @return the type for the element used as a value
      */
     public static TypeMirror getType(Element element) {
-        if (element.getKind() == ElementKind.METHOD)
-            return ((ExecutableElement)element).getReturnType();
-        else if (element.getKind() == ElementKind.CONSTRUCTOR)
+        if (element.getKind() == ElementKind.METHOD) {
+            return ((ExecutableElement) element).getReturnType();
+        } else if (element.getKind() == ElementKind.CONSTRUCTOR) {
             return enclosingClass(element).asType();
-        else
+        } else {
             return element.asType();
+        }
     }
 
     /**
-     * Returns the qualified name of the inner most class enclosing
-     * the provided {@code Element}
+     * Returns the qualified name of the inner most class enclosing the provided {@code Element}
      *
-     * @param element
-     *            an element enclosed by a class, or a
-     *            {@code TypeElement}
-     * @return The qualified {@code Name} of the innermost class
-     *         enclosing the element
+     * @param element an element enclosed by a class, or a {@code TypeElement}
+     * @return the qualified {@code Name} of the innermost class enclosing the element
      */
     public static /*@Nullable*/ Name getQualifiedClassName(Element element) {
         if (element.getKind() == ElementKind.PACKAGE) {
@@ -170,18 +160,18 @@
         }
 
         TypeElement elem = enclosingClass(element);
-        if (elem == null)
+        if (elem == null) {
             return null;
+        }
 
         return elem.getQualifiedName();
     }
 
-    /**
-     * Returns a verbose name that identifies the element.
-     */
+    /** Returns a verbose name that identifies the element. */
     public static String getVerboseName(Element elt) {
-        if (elt.getKind() == ElementKind.PACKAGE ||
-                elt.getKind().isClass()) {
+        if (elt.getKind() == ElementKind.PACKAGE
+                || elt.getKind().isClass()
+                || elt.getKind().isInterface()) {
             return getQualifiedClassName(elt).toString();
         } else {
             return getQualifiedClassName(elt) + "." + elt.toString();
@@ -191,34 +181,33 @@
     /**
      * Check if the element is an element for 'java.lang.Object'
      *
-     * @param element   the type element
+     * @param element the type element
      * @return true iff the element is java.lang.Object element
      */
     public static boolean isObject(TypeElement element) {
         return element.getQualifiedName().contentEquals("java.lang.Object");
     }
 
-    /**
-     * Returns true if the element is a constant time reference
-     */
+    /** Returns true if the element is a constant time reference */
     public static boolean isCompileTimeConstant(Element elt) {
         return elt != null
-            && elt.getKind() == ElementKind.FIELD
-            && ((VariableElement)elt).getConstantValue() != null;
+                && (elt.getKind() == ElementKind.FIELD
+                        || elt.getKind() == ElementKind.LOCAL_VARIABLE)
+                && ((VariableElement) elt).getConstantValue() != null;
     }
 
     /**
-     * Returns true if the element is declared in ByteCode.
-     * Always return false if elt is a package.
+     * Returns true if the element is declared in ByteCode. Always return false if elt is a package.
      */
-    public static boolean isElementFromByteCode(Element elt){
-        if (elt == null)
+    public static boolean isElementFromByteCode(Element elt) {
+        if (elt == null) {
             return false;
+        }
 
-        if (elt instanceof Symbol.ClassSymbol){
+        if (elt instanceof Symbol.ClassSymbol) {
             Symbol.ClassSymbol clss = (Symbol.ClassSymbol) elt;
-            if (null != clss.classfile){
-                //The class file could be a .java file
+            if (null != clss.classfile) {
+                // The class file could be a .java file
                 return clss.classfile.getName().endsWith(".class");
             } else {
                 return false;
@@ -228,19 +217,19 @@
     }
 
     /**
-     * Returns true if the element is declared in ByteCode.
-     * Always return false if elt is a package.
+     * Returns true if the element is declared in ByteCode. Always return false if elt is a package.
      */
-    private static boolean isElementFromByteCode(Element elt, Element orig){
-        if (elt == null)
+    private static boolean isElementFromByteCode(Element elt, Element orig) {
+        if (elt == null) {
             return false;
-        if (elt instanceof Symbol.ClassSymbol){
+        }
+        if (elt instanceof Symbol.ClassSymbol) {
             Symbol.ClassSymbol clss = (Symbol.ClassSymbol) elt;
-            if (null != clss.classfile){
+            if (null != clss.classfile) {
                 // The class file could be a .java file
-                return (clss.classfile.getName().endsWith(".class") ||
-                        clss.classfile.getName().endsWith(".class)") ||
-                        clss.classfile.getName().endsWith(".class)]"));
+                return (clss.classfile.getName().endsWith(".class")
+                        || clss.classfile.getName().endsWith(".class)")
+                        || clss.classfile.getName().endsWith(".class)]"));
             } else {
                 return false;
             }
@@ -248,11 +237,9 @@
         return isElementFromByteCode(elt.getEnclosingElement(), elt);
     }
 
-    /**
-     * Returns the field of the class
-     */
+    /** Returns the field of the class */
     public static VariableElement findFieldInType(TypeElement type, String name) {
-        for (VariableElement field: ElementFilter.fieldsIn(type.getEnclosedElements())) {
+        for (VariableElement field : ElementFilter.fieldsIn(type.getEnclosedElements())) {
             if (field.getSimpleName().toString().equals(name)) {
                 return field;
             }
@@ -260,9 +247,22 @@
         return null;
     }
 
-    public static Set<VariableElement> findFieldsInType(TypeElement type, Collection<String> names) {
+    /**
+     * Returns the elements of the fields whose simple names are {@code names} and are declared in
+     * {@code type}.
+     *
+     * <p>If a field isn't declared in {@code type}, its element isn't included in the returned set.
+     * If none of the fields is declared in {@code type}, the empty set is returned.
+     *
+     * @param type where to look for fields
+     * @param names simple names of fields that might be declared in {@code type}
+     * @return the elements of the fields whose simple names are {@code names} and are declared in
+     *     {@code type}
+     */
+    public static Set<VariableElement> findFieldsInType(
+            TypeElement type, Collection<String> names) {
         Set<VariableElement> results = new HashSet<VariableElement>();
-        for (VariableElement field: ElementFilter.fieldsIn(type.getEnclosedElements())) {
+        for (VariableElement field : ElementFilter.fieldsIn(type.getEnclosedElements())) {
             if (names.contains(field.getSimpleName().toString())) {
                 results.add(field);
             }
@@ -270,35 +270,87 @@
         return results;
     }
 
-    public static boolean isError(Element element) {
-        return element.getClass().getName().equals("com.sun.tools.javac.comp.Resolve$SymbolNotFoundError");
+    /**
+     * Returns non-private field elements, and side-effects {@code names} to remove them. For every
+     * field name in {@code names} that is declared in {@code type} or a supertype, add its element
+     * to the returned set and remove it from {@code names}.
+     *
+     * <p>When this routine returns, the combination of the return value and {@code names} has the
+     * same cardinality, and represents the same fields, as {@code names} did when the method was
+     * called.
+     *
+     * @param type where to look for fields
+     * @param names simple names of fields that might be declared in {@code type} or a supertype.
+     *     (Names that are found are removed from this list.)
+     * @return the {@code VariableElement}s for non-private fields that are declared in {@code type}
+     *     whose simple names were in {@code names} when the method was called.
+     */
+    public static Set<VariableElement> findFieldsInTypeOrSuperType(
+            TypeMirror type, Collection<String> names) {
+        Set<VariableElement> elements = new HashSet<>();
+        findFieldsInTypeOrSuperType(type, names, elements);
+        return elements;
     }
 
     /**
-     * Does the given element need a receiver for accesses?
-     * For example, an access to a local variable does not require a receiver.
+     * Side-effects both {@code foundFields} (which starts empty) and {@code notFound}, conceptually
+     * moving elements from {@code notFound} to {@code foundFields}.
+     */
+    private static void findFieldsInTypeOrSuperType(
+            TypeMirror type, Collection<String> notFound, Set<VariableElement> foundFields) {
+        if (TypesUtils.isObject(type)) {
+            return;
+        }
+        TypeElement elt = InternalUtils.getTypeElement(type);
+
+        Set<VariableElement> fieldElts = findFieldsInType(elt, notFound);
+        for (VariableElement field : new HashSet<>(fieldElts)) {
+            if (!field.getModifiers().contains(Modifier.PRIVATE)) {
+                notFound.remove(field.getSimpleName().toString());
+            } else {
+                fieldElts.remove(field);
+            }
+        }
+        foundFields.addAll(fieldElts);
+
+        if (!notFound.isEmpty()) {
+            findFieldsInTypeOrSuperType(elt.getSuperclass(), notFound, foundFields);
+        }
+    }
+
+    public static boolean isError(Element element) {
+        return element.getClass()
+                .getName()
+                .equals("com.sun.tools.javac.comp.Resolve$SymbolNotFoundError");
+    }
+
+    /**
+     * Does the given element need a receiver for accesses? For example, an access to a local
+     * variable does not require a receiver.
      *
-     * @param element The element to test.
-     * @return whether the element requires a receiver for accesses.
+     * @param element the element to test
+     * @return whether the element requires a receiver for accesses
      */
     public static boolean hasReceiver(Element element) {
-        return element.getKind() != ElementKind.LOCAL_VARIABLE
-                && element.getKind() != ElementKind.PARAMETER
-                && element.getKind() != ElementKind.PACKAGE
+        return (element.getKind().isField()
+                        || element.getKind() == ElementKind.METHOD
+                        || element.getKind() == ElementKind.CONSTRUCTOR)
                 && !ElementUtils.isStatic(element);
     }
 
     /**
-     * Determine all type elements for the classes and interfaces referenced
-     * in the extends/implements clauses of the given type element.
-     * TODO: can we learn from the implementation of
+     * Determine all type elements for the classes and interfaces referenced (directly or
+     * indirectly) in the extends/implements clauses of the given type element.
+     *
+     * <p>TODO: can we learn from the implementation of
      * com.sun.tools.javac.model.JavacElements.getAllMembers(TypeElement)?
      */
-    public static List<TypeElement> getSuperTypes(TypeElement type) {
+    public static List<TypeElement> getSuperTypes(Elements elements, TypeElement type) {
 
         List<TypeElement> superelems = new ArrayList<TypeElement>();
-        if (type == null)
+        if (type == null) {
             return superelems;
+        }
 
         // Set up a stack containing type, which is our starting point.
         Deque<TypeElement> stack = new ArrayDeque<TypeElement>();
@@ -310,16 +362,27 @@
             // For each direct supertype of the current type element, if it
             // hasn't already been visited, push it onto the stack and
             // add it to our superelems set.
-            TypeMirror supertypecls = current.getSuperclass();
-            if (supertypecls.getKind() != TypeKind.NONE) {
-                TypeElement supercls = (TypeElement) ((DeclaredType)supertypecls).asElement();
+            TypeMirror supertypecls;
+            try {
+                supertypecls = current.getSuperclass();
+            } catch (com.sun.tools.javac.code.Symbol.CompletionFailure cf) {
+                // Looking up a supertype failed. This sometimes happens
+                // when transitive dependencies are not on the classpath.
+                // As javac didn't complain, let's also not complain.
+                // TODO: Use an expanded ErrorReporter to output a message.
+                supertypecls = null;
+            }
+
+            if (supertypecls != null && supertypecls.getKind() != TypeKind.NONE) {
+                TypeElement supercls = (TypeElement) ((DeclaredType) supertypecls).asElement();
                 if (!superelems.contains(supercls)) {
                     stack.push(supercls);
                     superelems.add(supercls);
                 }
             }
+
             for (TypeMirror supertypeitf : current.getInterfaces()) {
-                TypeElement superitf = (TypeElement) ((DeclaredType)supertypeitf).asElement();
+                TypeElement superitf = (TypeElement) ((DeclaredType) supertypeitf).asElement();
                 if (!superelems.contains(superitf)) {
                     stack.push(superitf);
                     superelems.add(superitf);
@@ -327,18 +390,24 @@
             }
         }
 
+        // Include java.lang.Object as implicit superclass for all classes and interfaces.
+        TypeElement jlobject = elements.getTypeElement("java.lang.Object");
+        if (!superelems.contains(jlobject)) {
+            superelems.add(jlobject);
+        }
+
         return Collections.<TypeElement>unmodifiableList(superelems);
     }
 
     /**
-     * Return all fields declared in the given type or any superclass/interface.
-     * TODO: should this use javax.lang.model.util.Elements.getAllMembers(TypeElement)
-     * instead of our own getSuperTypes?
+     * Return all fields declared in the given type or any superclass/interface. TODO: should this
+     * use javax.lang.model.util.Elements.getAllMembers(TypeElement) instead of our own
+     * getSuperTypes?
      */
-    public static List<VariableElement> getAllFieldsIn(TypeElement type) {
+    public static List<VariableElement> getAllFieldsIn(Elements elements, TypeElement type) {
         List<VariableElement> fields = new ArrayList<VariableElement>();
         fields.addAll(ElementFilter.fieldsIn(type.getEnclosedElements()));
-        List<TypeElement> alltypes = getSuperTypes(type);
+        List<TypeElement> alltypes = getSuperTypes(elements, type);
         for (TypeElement atype : alltypes) {
             fields.addAll(ElementFilter.fieldsIn(atype.getEnclosedElements()));
         }
@@ -346,16 +415,15 @@
     }
 
     /**
-     * Return all methods declared in the given type or any superclass/interface.
-     * Note that no constructors will be returned.
-     * TODO: should this use javax.lang.model.util.Elements.getAllMembers(TypeElement)
-     * instead of our own getSuperTypes?
+     * Return all methods declared in the given type or any superclass/interface. Note that no
+     * constructors will be returned. TODO: should this use
+     * javax.lang.model.util.Elements.getAllMembers(TypeElement) instead of our own getSuperTypes?
      */
-    public static List<ExecutableElement> getAllMethodsIn(TypeElement type) {
+    public static List<ExecutableElement> getAllMethodsIn(Elements elements, TypeElement type) {
         List<ExecutableElement> meths = new ArrayList<ExecutableElement>();
         meths.addAll(ElementFilter.methodsIn(type.getEnclosedElements()));
 
-        List<TypeElement> alltypes = getSuperTypes(type);
+        List<TypeElement> alltypes = getSuperTypes(elements, type);
         for (TypeElement atype : alltypes) {
             meths.addAll(ElementFilter.methodsIn(atype.getEnclosedElements()));
         }
@@ -364,8 +432,8 @@
 
     public static boolean isTypeDeclaration(Element elt) {
         switch (elt.getKind()) {
-            // These tree kinds are always declarations.  Uses of the declared
-            // types have tree kind IDENTIFIER.
+                // These tree kinds are always declarations.  Uses of the declared
+                // types have tree kind IDENTIFIER.
             case ANNOTATION_TYPE:
             case CLASS:
             case ENUM:
@@ -381,17 +449,16 @@
     /**
      * Check that a method Element matches a signature.
      *
-     * Note: Matching the receiver type must be done elsewhere as
-     * the Element receiver type is only populated when annotated.
+     * <p>Note: Matching the receiver type must be done elsewhere as the Element receiver type is
+     * only populated when annotated.
      *
      * @param method the method Element
      * @param methodName the name of the method
      * @param parameters the formal parameters' Classes
      * @return true if the method matches
      */
-    public static boolean matchesElement(ExecutableElement method,
-            String methodName,
-            Class<?> ... parameters) {
+    public static boolean matchesElement(
+            ExecutableElement method, String methodName, Class<?>... parameters) {
 
         if (!method.getSimpleName().toString().equals(methodName)) {
             return false;
@@ -401,8 +468,11 @@
             return false;
         } else {
             for (int i = 0; i < method.getParameters().size(); i++) {
-                if (!method.getParameters().get(i).asType().toString().equals(
-                        parameters[i].getName())) {
+                if (!method.getParameters()
+                        .get(i)
+                        .asType()
+                        .toString()
+                        .equals(parameters[i].getName())) {
 
                     return false;
                 }
@@ -411,4 +481,12 @@
 
         return true;
     }
+
+    /** Returns true if the given element is, or overrides, method. */
+    public static boolean isMethod(
+            ExecutableElement questioned, ExecutableElement method, ProcessingEnvironment env) {
+        TypeElement enclosing = (TypeElement) questioned.getEnclosingElement();
+        return questioned.equals(method)
+                || env.getElementUtils().overrides(questioned, method, enclosing);
+    }
 }
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ErrorHandler.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ErrorHandler.java
index 3fd0faa..76ee74e 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ErrorHandler.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ErrorHandler.java
@@ -1,16 +1,15 @@
 package org.checkerframework.javacutil;
 
 /**
- * An implementation of the ErrorHandler interface can be registered
- * with the ErrorReporter class to change the default behavior on
- * errors.
+ * An implementation of the ErrorHandler interface can be registered with the ErrorReporter class to
+ * change the default behavior on errors.
  */
 public interface ErrorHandler {
 
     /**
      * Log an error message and abort processing.
      *
-     * @param msg The error message to log.
+     * @param msg the error message to log
      */
     public void errorAbort(String msg);
 
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ErrorReporter.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ErrorReporter.java
index 072e1a1..4ff62e0 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ErrorReporter.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/ErrorReporter.java
@@ -1,27 +1,24 @@
 package org.checkerframework.javacutil;
 
 /**
- * Handle errors detected in utility classes.  By default, the error reporter
- * throws a RuntimeException, but clients of the utility library may register
- * a handler to change the behavior.  For example, type checkers can direct
- * errors to the org.checkerframework.framework.source.SourceChecker class.
+ * Handle errors detected in utility classes. By default, the error reporter throws a
+ * RuntimeException, but clients of the utility library may register a handler to change the
+ * behavior. For example, type checkers can direct errors to the
+ * org.checkerframework.framework.source.SourceChecker class.
  */
 public class ErrorReporter {
 
     protected static ErrorHandler handler = null;
 
-    /**
-     * Register a handler to customize error reporting.
-     */
+    /** Register a handler to customize error reporting. */
     public static void setHandler(ErrorHandler h) {
         handler = h;
     }
 
     /**
-     * Log an error message and abort processing.
-     * Call this method instead of raising an exception.
+     * Log an error message and abort processing. Call this method instead of raising an exception.
      *
-     * @param msg The error message to log.
+     * @param msg the error message to log
      */
     public static void errorAbort(String msg) {
         if (handler != null) {
@@ -31,6 +28,22 @@
         }
     }
 
+    /**
+     * Log an error message use {@link String#format(String, Object...)}} and abort processing. Call
+     * this method instead of raising an exception.
+     *
+     * @param format a format string
+     * @param args arguments to the format string
+     */
+    public static void errorAbort(String format, Object... args) {
+        String formattedMsg = String.format(format, args);
+        if (handler != null) {
+            handler.errorAbort(formattedMsg);
+        } else {
+            throw new RuntimeException(formattedMsg, new Throwable());
+        }
+    }
+
     public static void errorAbort(String msg, Throwable cause) {
         if (handler != null) {
             handler.errorAbort(msg, cause);
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/InternalUtils.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/InternalUtils.java
index 40cb474..10a48cd 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/InternalUtils.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/InternalUtils.java
@@ -1,19 +1,5 @@
 package org.checkerframework.javacutil;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.TypeVariable;
-import javax.lang.model.type.WildcardType;
-import javax.lang.model.util.Elements;
-
 import com.sun.source.tree.AnnotatedTypeTree;
 import com.sun.source.tree.AnnotationTree;
 import com.sun.source.tree.ArrayAccessTree;
@@ -29,6 +15,7 @@
 import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.code.Symbol.TypeSymbol;
 import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Type.CapturedType;
 import com.sun.tools.javac.code.Types;
 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
 import com.sun.tools.javac.tree.JCTree;
@@ -43,15 +30,29 @@
 import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
 import com.sun.tools.javac.tree.TreeInfo;
 import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.WildcardType;
+import javax.lang.model.util.Elements;
 
 /*>>>
- import org.checkerframework.checker.nullness.qual.*;
- */
+import org.checkerframework.checker.nullness.qual.*;
+*/
 
 /**
- * Static utility methods used by annotation abstractions in this package. Some
- * methods in this class depend on the use of Sun javac internals; any procedure
- * in the Checker Framework that uses a non-public API should be placed here.
+ * Static utility methods used by annotation abstractions in this package. Some methods in this
+ * class depend on the use of Sun javac internals; any procedure in the Checker Framework that uses
+ * a non-public API should be placed here.
  */
 public class InternalUtils {
 
@@ -64,11 +65,9 @@
      * Gets the {@link Element} ("symbol") for the given Tree API node.
      *
      * @param tree the {@link Tree} node to get the symbol for
-     * @throws IllegalArgumentException
-     *         if {@code tree} is null or is not a valid javac-internal tree
-     *         (JCTree)
-     * @return the {@code {@link Symbol}} for the given tree, or null if one
-     *         could not be found
+     * @throws IllegalArgumentException if {@code tree} is null or is not a valid javac-internal
+     *     tree (JCTree)
+     * @return the {@link Symbol} for the given tree, or null if one could not be found
      */
     public static /*@Nullable*/ Element symbol(Tree tree) {
         if (tree == null) {
@@ -95,19 +94,19 @@
             case TYPE_PARAMETER:
                 return TreeInfo.symbolFor((JCTree) tree);
 
-            // symbol() only works on MethodSelects, so we need to get it manually
-            // for method invocations.
+                // symbol() only works on MethodSelects, so we need to get it manually
+                // for method invocations.
             case METHOD_INVOCATION:
                 return TreeInfo.symbol(((JCMethodInvocation) tree).getMethodSelect());
 
             case ASSIGNMENT:
-                return TreeInfo.symbol((JCTree)((AssignmentTree)tree).getVariable());
+                return TreeInfo.symbol((JCTree) ((AssignmentTree) tree).getVariable());
 
             case ARRAY_ACCESS:
-                return symbol(((ArrayAccessTree)tree).getExpression());
+                return symbol(((ArrayAccessTree) tree).getExpression());
 
             case NEW_CLASS:
-                return ((JCNewClass)tree).constructor;
+                return ((JCNewClass) tree).constructor;
 
             case MEMBER_REFERENCE:
                 // TreeInfo.symbol, which is used in the default case, didn't handle
@@ -120,43 +119,40 @@
     }
 
     /**
-     * Determines whether or not the node referred to by the given
-     * {@link TreePath} is an anonymous constructor (the constructor for an
-     * anonymous class.
+     * Determines whether or not the node referred to by the given {@link TreePath} is an anonymous
+     * constructor (the constructor for an anonymous class.
      *
-     * @param method the {@link TreePath} for a node that may be an anonymous
-     *        constructor
-     * @return true if the given path points to an anonymous constructor, false
-     *         if it does not
+     * @param method the {@link TreePath} for a node that may be an anonymous constructor
+     * @return true if the given path points to an anonymous constructor, false if it does not
      */
     public static boolean isAnonymousConstructor(final MethodTree method) {
         /*@Nullable*/ Element e = InternalUtils.symbol(method);
-        if (e == null || !(e instanceof Symbol))
+        if (e == null || !(e instanceof Symbol)) {
             return false;
+        }
 
-        if ((((/*@NonNull*/ Symbol)e).flags() & Flags.ANONCONSTR) != 0)
+        if ((((/*@NonNull*/ Symbol) e).flags() & Flags.ANONCONSTR) != 0) {
             return true;
+        }
 
         return false;
     }
 
     /**
-     * indicates whether it should return the constructor that gets invoked
-     * in cases of anonymous classes
+     * indicates whether it should return the constructor that gets invoked in cases of anonymous
+     * classes
      */
     private static final boolean RETURN_INVOKE_CONSTRUCTOR = true;
 
     /**
-     * Determines the symbol for a constructor given an invocation via
-     * {@code new}.
+     * Determines the symbol for a constructor given an invocation via {@code new}.
      *
-     * If the tree is a declaration of an anonymous class, then method returns
-     * constructor that gets invoked in the extended class, rather than the
-     * anonymous constructor implicitly added by the constructor (JLS 15.9.5.1)
+     * <p>If the tree is a declaration of an anonymous class, then method returns constructor that
+     * gets invoked in the extended class, rather than the anonymous constructor implicitly added by
+     * the constructor (JLS 15.9.5.1)
      *
      * @param tree the constructor invocation
-     * @return the {@link ExecutableElement} corresponding to the constructor
-     *         call in {@code tree}
+     * @return the {@link ExecutableElement} corresponding to the constructor call in {@code tree}
      */
     public static ExecutableElement constructor(NewClassTree tree) {
 
@@ -178,7 +174,7 @@
 
             // the method call is guaranteed to return nonnull
             JCMethodDecl anonConstructor =
-                (JCMethodDecl) TreeInfo.declarationFor(newClassTree.constructor, newClassTree);
+                    (JCMethodDecl) TreeInfo.declarationFor(newClassTree.constructor, newClassTree);
             assert anonConstructor != null;
             assert anonConstructor.body.stats.size() == 1;
             JCExpressionStatement stmt = (JCExpressionStatement) anonConstructor.body.stats.head;
@@ -193,22 +189,31 @@
         return (ExecutableElement) e;
     }
 
-    public final static List<AnnotationMirror> annotationsFromTypeAnnotationTrees(List<? extends AnnotationTree> annos) {
+    public static final List<AnnotationMirror> annotationsFromTypeAnnotationTrees(
+            List<? extends AnnotationTree> annos) {
         List<AnnotationMirror> annotations = new ArrayList<AnnotationMirror>(annos.size());
-        for (AnnotationTree anno : annos)
-            annotations.add(((JCAnnotation)anno).attribute);
+        for (AnnotationTree anno : annos) {
+            annotations.add(annotationFromAnnotationTree(anno));
+        }
         return annotations;
     }
 
-    public final static List<? extends AnnotationMirror> annotationsFromTree(AnnotatedTypeTree node) {
-        return annotationsFromTypeAnnotationTrees(((JCAnnotatedType)node).annotations);
+    public static AnnotationMirror annotationFromAnnotationTree(AnnotationTree tree) {
+        return ((JCAnnotation) tree).attribute;
     }
 
-    public final static List<? extends AnnotationMirror> annotationsFromTree(TypeParameterTree node) {
-        return annotationsFromTypeAnnotationTrees(((JCTypeParameter)node).annotations);
+    public static final List<? extends AnnotationMirror> annotationsFromTree(
+            AnnotatedTypeTree node) {
+        return annotationsFromTypeAnnotationTrees(((JCAnnotatedType) node).annotations);
     }
 
-    public final static List<? extends AnnotationMirror> annotationsFromArrayCreation(NewArrayTree node, int level) {
+    public static final List<? extends AnnotationMirror> annotationsFromTree(
+            TypeParameterTree node) {
+        return annotationsFromTypeAnnotationTrees(((JCTypeParameter) node).annotations);
+    }
+
+    public static final List<? extends AnnotationMirror> annotationsFromArrayCreation(
+            NewArrayTree node, int level) {
 
         assert node instanceof JCNewArray;
         final JCNewArray newArray = ((JCNewArray) node);
@@ -229,32 +234,40 @@
         return ((JCTree) tree).type;
     }
 
-    /**
-     * Returns whether a TypeVariable represents a captured type.
-     */
+    /** Returns whether a TypeVariable represents a captured type. */
     public static boolean isCaptured(TypeVariable typeVar) {
-        return ((Type.TypeVar) typeVar).isCaptured();
+        return ((Type.TypeVar) TypeAnnotationUtils.unannotatedType(typeVar)).isCaptured();
     }
 
-    /**
-     * Returns whether a TypeMirror represents a class type.
-     */
+    /** If typeVar is a captured wildcard, returns that wildcard; otherwise returns null. */
+    public static WildcardType getCapturedWildcard(TypeVariable typeVar) {
+        if (isCaptured(typeVar)) {
+            return ((CapturedType) TypeAnnotationUtils.unannotatedType(typeVar)).wildcard;
+        }
+        return null;
+    }
+
+    /** Returns whether a TypeMirror represents a class type. */
     public static boolean isClassType(TypeMirror type) {
         return (type instanceof Type.ClassType);
     }
 
     /**
-     * Returns the least upper bound of two {@link TypeMirror}s.
+     * Returns the least upper bound of two {@link TypeMirror}s, ignoring any annotations on the
+     * types.
      *
-     * @param processingEnv The {@link ProcessingEnvironment} to use.
-     * @param tm1 A {@link TypeMirror}.
-     * @param tm2 A {@link TypeMirror}.
-     * @return The least upper bound of {@code tm1} and {@code tm2}.
+     * <p>Wrapper around Types.lub to add special handling for null types, primitives, and
+     * wildcards.
+     *
+     * @param processingEnv the {@link ProcessingEnvironment} to use
+     * @param tm1 a {@link TypeMirror}
+     * @param tm2 a {@link TypeMirror}
+     * @return the least upper bound of {@code tm1} and {@code tm2}.
      */
     public static TypeMirror leastUpperBound(
             ProcessingEnvironment processingEnv, TypeMirror tm1, TypeMirror tm2) {
-        Type t1 = (Type) tm1;
-        Type t2 = (Type) tm2;
+        Type t1 = TypeAnnotationUtils.unannotatedType(tm1);
+        Type t2 = TypeAnnotationUtils.unannotatedType(tm2);
         JavacProcessingEnvironment javacEnv = (JavacProcessingEnvironment) processingEnv;
         Types types = Types.instance(javacEnv.getContext());
         if (types.isSameType(t1, t2)) {
@@ -268,16 +281,6 @@
         if (t2.getKind() == TypeKind.NULL) {
             return t1;
         }
-        // Special case for primitives.
-        if (TypesUtils.isPrimitive(t1) || TypesUtils.isPrimitive(t2)) {
-            if (types.isAssignable(t1, t2)) {
-                return t2;
-            } else if (types.isAssignable(t2, t1)) {
-                return t1;
-            } else {
-                return processingEnv.getTypeUtils().getNoType(TypeKind.NONE);
-            }
-        }
         if (t1.getKind() == TypeKind.WILDCARD) {
             WildcardType wc1 = (WildcardType) t1;
             Type bound = (Type) wc1.getExtendsBound();
@@ -298,21 +301,36 @@
             }
             t2 = bound;
         }
+        // Special case for primitives.
+        if (TypesUtils.isPrimitive(t1) || TypesUtils.isPrimitive(t2)) {
+            if (types.isAssignable(t1, t2)) {
+                return t2;
+            } else if (types.isAssignable(t2, t1)) {
+                return t1;
+            } else {
+                Elements elements = processingEnv.getElementUtils();
+                return elements.getTypeElement("java.lang.Object").asType();
+            }
+        }
         return types.lub(t1, t2);
     }
 
     /**
-     * Returns the greatest lower bound of two {@link TypeMirror}s.
+     * Returns the greatest lower bound of two {@link TypeMirror}s, ignoring any annotations on the
+     * types.
      *
-     * @param processingEnv The {@link ProcessingEnvironment} to use.
-     * @param tm1 A {@link TypeMirror}.
-     * @param tm2 A {@link TypeMirror}.
-     * @return The greatest lower bound of {@code tm1} and {@code tm2}.
+     * <p>Wrapper around Types.glb to add special handling for null types, primitives, and
+     * wildcards.
+     *
+     * @param processingEnv the {@link ProcessingEnvironment} to use
+     * @param tm1 a {@link TypeMirror}
+     * @param tm2 a {@link TypeMirror}
+     * @return the greatest lower bound of {@code tm1} and {@code tm2}.
      */
     public static TypeMirror greatestLowerBound(
             ProcessingEnvironment processingEnv, TypeMirror tm1, TypeMirror tm2) {
-        Type t1 = (Type) tm1;
-        Type t2 = (Type) tm2;
+        Type t1 = TypeAnnotationUtils.unannotatedType(tm1);
+        Type t2 = TypeAnnotationUtils.unannotatedType(tm2);
         JavacProcessingEnvironment javacEnv = (JavacProcessingEnvironment) processingEnv;
         Types types = Types.instance(javacEnv.getContext());
         if (types.isSameType(t1, t2)) {
@@ -345,21 +363,24 @@
         if (t2.getKind() == TypeKind.WILDCARD) {
             return t1;
         }
+
+        // If neither type is a primitive type, null type, or wildcard
+        // and if the types are not the same, use javac types.glb
         return types.glb(t1, t2);
     }
 
     /**
-     * Returns the return type of a method, where the "raw" return type of that
-     * method is given (i.e., the return type might still contain unsubstituted
-     * type variables), given the receiver of the method call.
+     * Returns the return type of a method, where the "raw" return type of that method is given
+     * (i.e., the return type might still contain unsubstituted type variables), given the receiver
+     * of the method call.
      */
-    public static TypeMirror substituteMethodReturnType(TypeMirror methodType,
-            TypeMirror substitutedReceiverType) {
+    public static TypeMirror substituteMethodReturnType(
+            TypeMirror methodType, TypeMirror substitutedReceiverType) {
         if (methodType.getKind() != TypeKind.TYPEVAR) {
             return methodType;
         }
         // TODO: find a nicer way to substitute type variables
-        String t = methodType.toString();
+        String t = TypeAnnotationUtils.unannotatedType(methodType).toString();
         Type finalReceiverType = (Type) substitutedReceiverType;
         int i = 0;
         for (TypeSymbol typeParam : finalReceiverType.tsym.getTypeParameters()) {
@@ -372,13 +393,91 @@
         return null;
     }
 
-    /** Helper function to extract the javac Context from the
-     * javac processing environment.
+    /**
+     * Helper function to extract the javac Context from the javac processing environment.
      *
      * @param env the processing environment
      * @return the javac Context
      */
     public static Context getJavacContext(ProcessingEnvironment env) {
-        return ((JavacProcessingEnvironment)env).getContext();
+        return ((JavacProcessingEnvironment) env).getContext();
+    }
+
+    /**
+     * Returns the type element for {@code type} if {@code type} is a class, interface, annotation
+     * type, or enum. Otherwise, returns null.
+     *
+     * @param type whose element is returned
+     * @return the type element for {@code type} if {@code type} is a class, interface, annotation
+     *     type, or enum; otherwise, returns null
+     */
+    public static TypeElement getTypeElement(TypeMirror type) {
+        Element element = ((Type) type).asElement();
+        switch (element.getKind()) {
+            case ANNOTATION_TYPE:
+            case CLASS:
+            case ENUM:
+            case INTERFACE:
+                return (TypeElement) element;
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * Obtain the class loader for {@code clazz}. If that is not available, return the system class
+     * loader.
+     *
+     * @param clazz the class whose class loader to find
+     * @return the class loader used to {@code clazz}, or the system class loader, or null if both
+     *     are unavailable
+     */
+    public static ClassLoader getClassLoaderForClass(Class<? extends Object> clazz) {
+        ClassLoader classLoader = clazz.getClassLoader();
+        return classLoader == null ? ClassLoader.getSystemClassLoader() : classLoader;
+    }
+
+    /**
+     * Compares tree1 to tree2 by the position at which a diagnostic (e.g., an error message) for
+     * the tree should be printed.
+     */
+    public static int compareDiagnosticPosition(Tree tree1, Tree tree2) {
+        DiagnosticPosition pos1 = (DiagnosticPosition) tree1;
+        DiagnosticPosition pos2 = (DiagnosticPosition) tree2;
+
+        int preferred = Integer.compare(pos1.getPreferredPosition(), pos2.getPreferredPosition());
+        if (preferred != 0) {
+            return preferred;
+        }
+
+        return Integer.compare(pos1.getStartPosition(), pos2.getStartPosition());
+    }
+
+    /**
+     * Returns whether or not {@code type} is a functional interface type (as defined in JLS 9.8).
+     *
+     * @param type possible functional interface type
+     * @param env ProcessingEnvironment
+     * @return whether or not {@code type} is a functional interface type (as defined in JLS 9.8)
+     */
+    public static boolean isFunctionalInterface(TypeMirror type, ProcessingEnvironment env) {
+        Context ctx = ((JavacProcessingEnvironment) env).getContext();
+        com.sun.tools.javac.code.Types javacTypes = com.sun.tools.javac.code.Types.instance(ctx);
+        return javacTypes.isFunctionalInterface((Type) type);
+    }
+
+    /**
+     * The type of the lambda or method reference tree is a functional interface type. This method
+     * returns the single abstract method declared by that functional interface. (The type of this
+     * method is referred to as the function type.)
+     *
+     * @param tree lambda or member reference tree
+     * @param env ProcessingEnvironment
+     * @return the single abstract method declared by the type of the tree
+     */
+    public static Symbol findFunction(Tree tree, ProcessingEnvironment env) {
+        Context ctx = ((JavacProcessingEnvironment) env).getContext();
+        com.sun.tools.javac.code.Types javacTypes = com.sun.tools.javac.code.Types.instance(ctx);
+        return javacTypes.findDescriptorSymbol(((Type) typeOf(tree)).asElement());
     }
 }
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/Pair.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/Pair.java
index 779c9b3..161af82 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/Pair.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/Pair.java
@@ -8,7 +8,7 @@
 /**
  * Simple pair class for multiple returns.
  *
- * TODO: as class is immutable, use @Covariant annotation.
+ * <p>TODO: as class is immutable, use @Covariant annotation.
  */
 public class Pair<V1, V2> {
     public final V1 first;
@@ -36,18 +36,21 @@
     public int hashCode() {
         if (hashCode == -1) {
             hashCode = 31;
-            if (first != null)
+            if (first != null) {
                 hashCode += 17 * first.hashCode();
-            if (second != null)
+            }
+            if (second != null) {
                 hashCode += 17 * second.hashCode();
+            }
         }
         return hashCode;
     }
 
     @Override
     public boolean equals(Object o) {
-        if (!(o instanceof Pair))
+        if (!(o instanceof Pair)) {
             return false;
+        }
         @SuppressWarnings("unchecked")
         Pair<V1, V2> other = (Pair<V1, V2>) o;
         if (this.first == null) {
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/Resolver.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/Resolver.java
index c47566b..361c6ae 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/Resolver.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/Resolver.java
@@ -1,22 +1,15 @@
 package org.checkerframework.javacutil;
 
+import static com.sun.tools.javac.code.Kinds.PCK;
+import static com.sun.tools.javac.code.Kinds.TYP;
 import static com.sun.tools.javac.code.Kinds.VAR;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeMirror;
-
 import com.sun.source.util.TreePath;
 import com.sun.source.util.Trees;
 import com.sun.tools.javac.api.JavacScope;
 import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.PackageSymbol;
 import com.sun.tools.javac.code.Symbol.TypeSymbol;
 import com.sun.tools.javac.code.Type;
 import com.sun.tools.javac.comp.AttrContext;
@@ -29,20 +22,97 @@
 import com.sun.tools.javac.util.Log;
 import com.sun.tools.javac.util.Name;
 import com.sun.tools.javac.util.Names;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
 
-/**
- * A Utility class to find symbols corresponding to string references.
- */
+/** A Utility class to find symbols corresponding to string references. */
 public class Resolver {
     private final Resolve resolve;
     private final Names names;
     private final Trees trees;
     private final Log log;
 
-    private final Method FIND_METHOD;
-    private final Method FIND_IDENT_IN_TYPE;
-    private final Method FIND_IDENT_IN_PACKAGE;
-    private final Method FIND_TYPE;
+    private static final Method FIND_METHOD;
+    private static final Method FIND_VAR;
+    private static final Method FIND_IDENT;
+    private static final Method FIND_IDENT_IN_TYPE;
+    private static final Method FIND_IDENT_IN_PACKAGE;
+    private static final Method FIND_TYPE;
+
+    private static final Class<?> ACCESSERROR;
+    // Note that currently access(...) is defined in InvalidSymbolError, a superclass of AccessError
+    private static final Method ACCESSERROR_ACCESS;
+
+    static {
+        try {
+            FIND_METHOD =
+                    Resolve.class.getDeclaredMethod(
+                            "findMethod",
+                            Env.class,
+                            Type.class,
+                            Name.class,
+                            List.class,
+                            List.class,
+                            boolean.class,
+                            boolean.class,
+                            boolean.class);
+            FIND_METHOD.setAccessible(true);
+
+            FIND_VAR = Resolve.class.getDeclaredMethod("findVar", Env.class, Name.class);
+            FIND_VAR.setAccessible(true);
+
+            FIND_IDENT =
+                    Resolve.class.getDeclaredMethod("findIdent", Env.class, Name.class, int.class);
+            FIND_IDENT.setAccessible(true);
+
+            FIND_IDENT_IN_TYPE =
+                    Resolve.class.getDeclaredMethod(
+                            "findIdentInType", Env.class, Type.class, Name.class, int.class);
+            FIND_IDENT_IN_TYPE.setAccessible(true);
+
+            FIND_IDENT_IN_PACKAGE =
+                    Resolve.class.getDeclaredMethod(
+                            "findIdentInPackage",
+                            Env.class,
+                            TypeSymbol.class,
+                            Name.class,
+                            int.class);
+            FIND_IDENT_IN_PACKAGE.setAccessible(true);
+
+            FIND_TYPE = Resolve.class.getDeclaredMethod("findType", Env.class, Name.class);
+            FIND_TYPE.setAccessible(true);
+        } catch (Exception e) {
+            Error err =
+                    new AssertionError(
+                            "Compiler 'Resolve' class doesn't contain required 'find' method");
+            err.initCause(e);
+            throw err;
+        }
+
+        try {
+            ACCESSERROR = Class.forName("com.sun.tools.javac.comp.Resolve$AccessError");
+            ACCESSERROR_ACCESS = ACCESSERROR.getMethod("access", Name.class, TypeSymbol.class);
+            ACCESSERROR_ACCESS.setAccessible(true);
+        } catch (ClassNotFoundException e) {
+            ErrorReporter.errorAbort(
+                    "Compiler 'Resolve$AccessError' class could not be retrieved.", e);
+            // Unreachable code - needed so the compiler does not warn about a possibly uninitialized final field.
+            throw new AssertionError();
+        } catch (NoSuchMethodException e) {
+            ErrorReporter.errorAbort(
+                    "Compiler 'Resolve$AccessError' class doesn't contain required 'access' method",
+                    e);
+            // Unreachable code - needed so the compiler does not warn about a possibly uninitialized final field.
+            throw new AssertionError();
+        }
+    }
 
     public Resolver(ProcessingEnvironment env) {
         Context context = ((JavacProcessingEnvironment) env).getContext();
@@ -50,60 +120,86 @@
         this.names = Names.instance(context);
         this.trees = Trees.instance(env);
         this.log = Log.instance(context);
+    }
 
+    /**
+     * Determine the environment for the given path.
+     *
+     * @param path the tree path to the local scope
+     * @return the corresponding attribution environment
+     */
+    public Env<AttrContext> getEnvForPath(TreePath path) {
+        TreePath iter = path;
+        JavacScope scope = null;
+        while (scope == null && iter != null) {
+            try {
+                scope = (JavacScope) trees.getScope(iter);
+            } catch (Throwable t) {
+                // Work around Issue #1059 by skipping through the TreePath until something
+                // doesn't crash. This probably returns the class scope, so users might not
+                // get the variables they expect. But that is better than crashing.
+                iter = iter.getParentPath();
+            }
+        }
+        if (scope != null) {
+            return scope.getEnv();
+        } else {
+            ErrorReporter.errorAbort(
+                    "Could not determine any possible scope for path: " + path.getLeaf());
+            return null;
+        }
+    }
+
+    /**
+     * Finds the package with name {@code name}.
+     *
+     * @param name the name of the package
+     * @param path the tree path to the local scope
+     * @return the {@code PackageSymbol} for the package if it is found, {@code null} otherwise
+     */
+    public PackageSymbol findPackage(String name, TreePath path) {
+        Log.DiagnosticHandler discardDiagnosticHandler = new Log.DiscardDiagnosticHandler(log);
         try {
-            FIND_METHOD = Resolve.class.getDeclaredMethod("findMethod",
-                    Env.class, Type.class, Name.class, List.class, List.class,
-                    boolean.class, boolean.class, boolean.class);
-            FIND_METHOD.setAccessible(true);
-
-            FIND_IDENT_IN_TYPE = Resolve.class.getDeclaredMethod(
-                    "findIdentInType", Env.class, Type.class, Name.class,
-                    int.class);
-            FIND_IDENT_IN_TYPE.setAccessible(true);
-
-            FIND_IDENT_IN_PACKAGE = Resolve.class.getDeclaredMethod(
-                    "findIdentInPackage", Env.class, TypeSymbol.class, Name.class,
-                    int.class);
-            FIND_IDENT_IN_PACKAGE.setAccessible(true);
-
-            FIND_TYPE = Resolve.class.getDeclaredMethod(
-                    "findType", Env.class, Name.class);
-            FIND_TYPE.setAccessible(true);
-        } catch (Exception e) {
-            Error err = new AssertionError(
-                    "Compiler 'Resolve' class doesn't contain required 'find' method");
-            err.initCause(e);
-            throw err;
+            Env<AttrContext> env = getEnvForPath(path);
+            Element res =
+                    wrapInvocationOnResolveInstance(FIND_IDENT, env, names.fromString(name), PCK);
+            // findIdent will return a PackageSymbol even for a symbol that is not a package,
+            // such as a.b.c.MyClass.myStaticField. "exists()" must be called on it to ensure
+            // that it exists.
+            if (res.getKind() == ElementKind.PACKAGE) {
+                PackageSymbol ps = (PackageSymbol) res;
+                return ps.exists() ? ps : null;
+            } else {
+                return null;
+            }
+        } finally {
+            log.popDiagnosticHandler(discardDiagnosticHandler);
         }
     }
 
     /**
      * Finds the field with name {@code name} in a given type.
      *
-     * <p>
-     * The method adheres to all the rules of Java's scoping (while also
-     * considering the imports) for name resolution.
+     * <p>The method adheres to all the rules of Java's scoping (while also considering the imports)
+     * for name resolution.
      *
-     * @param name
-     *            The name of the field.
-     * @param type
-     *            The type of the receiver (i.e., the type in which to look for
-     *            the field).
-     * @param path
-     *            The tree path to the local scope.
-     * @return The element for the field.
+     * @param name the name of the field
+     * @param type the type of the receiver (i.e., the type in which to look for the field).
+     * @param path the tree path to the local scope
+     * @return the element for the field
      */
     public VariableElement findField(String name, TypeMirror type, TreePath path) {
-        Log.DiagnosticHandler discardDiagnosticHandler =
-            new Log.DiscardDiagnosticHandler(log);
+        Log.DiagnosticHandler discardDiagnosticHandler = new Log.DiscardDiagnosticHandler(log);
         try {
-            JavacScope scope = (JavacScope) trees.getScope(path);
-            Env<AttrContext> env = scope.getEnv();
-            Element res = wrapInvocation(FIND_IDENT_IN_TYPE, env, type,
-                    names.fromString(name), VAR);
+            Env<AttrContext> env = getEnvForPath(path);
+            Element res =
+                    wrapInvocationOnResolveInstance(
+                            FIND_IDENT_IN_TYPE, env, type, names.fromString(name), VAR);
             if (res.getKind() == ElementKind.FIELD) {
                 return (VariableElement) res;
+            } else if (res.getKind() == ElementKind.OTHER && ACCESSERROR.isInstance(res)) {
+                // Return the inaccessible field that was found
+                return (VariableElement) wrapInvocation(res, ACCESSERROR_ACCESS, null, null);
             } else {
                 // Most likely didn't find the field and the Element is a SymbolNotFoundError
                 return null;
@@ -114,53 +210,94 @@
     }
 
     /**
-     * Finds the class literal with name {@code name}.
+     * Finds the local variable with name {@code name} in the given scope.
      *
-     * <p>
-     * The method adheres to all the rules of Java's scoping (while also
-     * considering the imports) for name resolution.
-     *
-     * @param name
-     *            The name of the class.
-     * @param path
-     *            The tree path to the local scope.
-     * @return The element for the class.
+     * @param name the name of the local variable
+     * @param path the tree path to the local scope
+     * @return the element for the local variable
      */
-    public Element findClass(String name, TreePath path) {
-        Log.DiagnosticHandler discardDiagnosticHandler =
-            new Log.DiscardDiagnosticHandler(log);
+    public VariableElement findLocalVariableOrParameterOrField(String name, TreePath path) {
+        Log.DiagnosticHandler discardDiagnosticHandler = new Log.DiscardDiagnosticHandler(log);
         try {
-            JavacScope scope = (JavacScope) trees.getScope(path);
-            Env<AttrContext> env = scope.getEnv();
-            return wrapInvocation(FIND_TYPE, env, names.fromString(name));
+            Env<AttrContext> env = getEnvForPath(path);
+            Element res = wrapInvocationOnResolveInstance(FIND_VAR, env, names.fromString(name));
+            if (res.getKind() == ElementKind.LOCAL_VARIABLE
+                    || res.getKind() == ElementKind.PARAMETER
+                    || res.getKind() == ElementKind.FIELD) {
+                return (VariableElement) res;
+            } else {
+                // Most likely didn't find the variable and the Element is a SymbolNotFoundError
+                return null;
+            }
         } finally {
             log.popDiagnosticHandler(discardDiagnosticHandler);
         }
     }
 
     /**
-     * Finds the method element for a given name and list of expected parameter
-     * types.
+     * Finds the class literal with name {@code name}.
      *
-     * <p>
-     * The method adheres to all the rules of Java's scoping (while also
-     * considering the imports) for name resolution.
+     * <p>The method adheres to all the rules of Java's scoping (while also considering the imports)
+     * for name resolution.
      *
-     * @param methodName
-     *            Name of the method to find.
-     * @param receiverType
-     *            Type of the receiver of the method
-     * @param path
-     *            Tree path.
-     * @return The method element (if found).
+     * @param name the name of the class
+     * @param path the tree path to the local scope
+     * @return the element for the class
      */
-    public Element findMethod(String methodName, TypeMirror receiverType,
-            TreePath path, java.util.List<TypeMirror> argumentTypes) {
-        Log.DiagnosticHandler discardDiagnosticHandler =
-            new Log.DiscardDiagnosticHandler(log);
+    public Element findClass(String name, TreePath path) {
+        Log.DiagnosticHandler discardDiagnosticHandler = new Log.DiscardDiagnosticHandler(log);
         try {
-            JavacScope scope = (JavacScope) trees.getScope(path);
-            Env<AttrContext> env = scope.getEnv();
+            Env<AttrContext> env = getEnvForPath(path);
+            return wrapInvocationOnResolveInstance(FIND_TYPE, env, names.fromString(name));
+        } finally {
+            log.popDiagnosticHandler(discardDiagnosticHandler);
+        }
+    }
+
+    /**
+     * Finds the class with name {@code name} in a given package.
+     *
+     * @param name the name of the class
+     * @param pck the PackageSymbol for the package
+     * @param path the tree path to the local scope
+     * @return the {@code ClassSymbol} for the class if it is found, {@code null} otherwise
+     */
+    public ClassSymbol findClassInPackage(String name, PackageSymbol pck, TreePath path) {
+        Log.DiagnosticHandler discardDiagnosticHandler = new Log.DiscardDiagnosticHandler(log);
+        try {
+            Env<AttrContext> env = getEnvForPath(path);
+            Element res =
+                    wrapInvocationOnResolveInstance(
+                            FIND_IDENT_IN_PACKAGE, env, pck, names.fromString(name), TYP);
+            if (res.getKind() == ElementKind.CLASS) {
+                return (ClassSymbol) res;
+            } else {
+                return null;
+            }
+        } finally {
+            log.popDiagnosticHandler(discardDiagnosticHandler);
+        }
+    }
+
+    /**
+     * Finds the method element for a given name and list of expected parameter types.
+     *
+     * <p>The method adheres to all the rules of Java's scoping (while also considering the imports)
+     * for name resolution.
+     *
+     * @param methodName name of the method to find
+     * @param receiverType type of the receiver of the method
+     * @param path tree path
+     * @return the method element (if found)
+     */
+    public Element findMethod(
+            String methodName,
+            TypeMirror receiverType,
+            TreePath path,
+            java.util.List<TypeMirror> argumentTypes) {
+        Log.DiagnosticHandler discardDiagnosticHandler = new Log.DiscardDiagnosticHandler(log);
+        try {
+            Env<AttrContext> env = getEnvForPath(path);
 
             Type site = (Type) receiverType;
             Name name = names.fromString(methodName);
@@ -179,8 +316,17 @@
                 Object methodContext = buildMethodContext();
                 Object oldContext = getField(resolve, "currentResolutionContext");
                 setField(resolve, "currentResolutionContext", methodContext);
-                Element result = wrapInvocation(FIND_METHOD, env, site, name, argtypes,
-                    typeargtypes, allowBoxing, useVarargs, operator);
+                Element result =
+                        wrapInvocationOnResolveInstance(
+                                FIND_METHOD,
+                                env,
+                                site,
+                                name,
+                                argtypes,
+                                typeargtypes,
+                                allowBoxing,
+                                useVarargs,
+                                operator);
                 setField(resolve, "currentResolutionContext", oldContext);
                 return result;
             } catch (Throwable t) {
@@ -193,14 +339,13 @@
         }
     }
 
-    /**
-     * Build an instance of {@code Resolve$MethodResolutionContext}.
-     */
-    protected Object buildMethodContext() throws ClassNotFoundException,
-            InstantiationException, IllegalAccessException,
-            InvocationTargetException, NoSuchFieldException {
+    /** Build an instance of {@code Resolve$MethodResolutionContext}. */
+    protected Object buildMethodContext()
+            throws ClassNotFoundException, InstantiationException, IllegalAccessException,
+                    InvocationTargetException, NoSuchFieldException {
         // Class is not accessible, instantiate reflectively.
-        Class<?> methCtxClss = Class.forName("com.sun.tools.javac.comp.Resolve$MethodResolutionContext");
+        Class<?> methCtxClss =
+                Class.forName("com.sun.tools.javac.comp.Resolve$MethodResolutionContext");
         Constructor<?> constructor = methCtxClss.getDeclaredConstructors()[0];
         constructor.setAccessible(true);
         Object methodContext = constructor.newInstance(resolve);
@@ -213,25 +358,28 @@
     }
 
     /** Reflectively set a field. */
-    private void setField(Object receiver, String fieldName,
-            Object value) throws NoSuchFieldException,
-            IllegalAccessException {
+    private void setField(Object receiver, String fieldName, Object value)
+            throws NoSuchFieldException, IllegalAccessException {
         Field f = receiver.getClass().getDeclaredField(fieldName);
         f.setAccessible(true);
         f.set(receiver, value);
     }
 
     /** Reflectively get the value of a field. */
-    private Object getField(Object receiver, String fieldName) throws NoSuchFieldException,
-            IllegalAccessException {
+    private Object getField(Object receiver, String fieldName)
+            throws NoSuchFieldException, IllegalAccessException {
         Field f = receiver.getClass().getDeclaredField(fieldName);
         f.setAccessible(true);
         return f.get(receiver);
     }
 
-    private Symbol wrapInvocation(Method method, Object... args) {
+    private Symbol wrapInvocationOnResolveInstance(Method method, Object... args) {
+        return wrapInvocation(resolve, method, args);
+    }
+
+    private Symbol wrapInvocation(Object receiver, Method method, Object... args) {
         try {
-            return (Symbol) method.invoke(resolve, args);
+            return (Symbol) method.invoke(receiver, args);
         } catch (IllegalAccessException e) {
             Error err = new AssertionError("Unexpected Reflection error");
             err.initCause(e);
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TreeUtils.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TreeUtils.java
index a3ae88f..4da97b4 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TreeUtils.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TreeUtils.java
@@ -4,25 +4,13 @@
 import org.checkerframework.checker.nullness.qual.*;
 */
 
-import java.util.EnumSet;
-import java.util.Set;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-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.util.ElementFilter;
-
 import com.sun.source.tree.AnnotatedTypeTree;
 import com.sun.source.tree.ArrayAccessTree;
-import com.sun.source.tree.AssignmentTree;
 import com.sun.source.tree.BinaryTree;
 import com.sun.source.tree.BlockTree;
 import com.sun.source.tree.ClassTree;
 import com.sun.source.tree.CompoundAssignmentTree;
+import com.sun.source.tree.ConditionalExpressionTree;
 import com.sun.source.tree.ExpressionStatementTree;
 import com.sun.source.tree.ExpressionTree;
 import com.sun.source.tree.IdentifierTree;
@@ -30,14 +18,13 @@
 import com.sun.source.tree.MemberSelectTree;
 import com.sun.source.tree.MethodInvocationTree;
 import com.sun.source.tree.MethodTree;
-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.Tree;
+import com.sun.source.tree.Tree.Kind;
 import com.sun.source.tree.TypeCastTree;
 import com.sun.source.tree.VariableTree;
 import com.sun.source.util.TreePath;
@@ -45,21 +32,34 @@
 import com.sun.tools.javac.code.Flags;
 import com.sun.tools.javac.code.Symbol.MethodSymbol;
 import com.sun.tools.javac.tree.JCTree;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.util.ElementFilter;
 
-/**
- * A utility class made for helping to analyze a given {@code Tree}.
- */
+/** A utility class made for helping to analyze a given {@code Tree}. */
 // TODO: This class needs significant restructuring
 public final class TreeUtils {
 
     // Class cannot be instantiated.
-    private TreeUtils() { throw new AssertionError("Class TreeUtils cannot be instantiated."); }
+    private TreeUtils() {
+        throw new AssertionError("Class TreeUtils cannot be instantiated.");
+    }
 
     /**
      * Checks if the provided method is a constructor method or no.
      *
-     * @param tree
-     *            a tree defining the method
+     * @param tree a tree defining the method
      * @return true iff tree describes a constructor
      */
     public static boolean isConstructor(final MethodTree tree) {
@@ -69,39 +69,50 @@
     /**
      * Checks if the method invocation is a call to super.
      *
-     * @param tree
-     *            a tree defining a method invocation
-     *
+     * @param tree a tree defining a method invocation
      * @return true iff tree describes a call to super
      */
     public static boolean isSuperCall(MethodInvocationTree tree) {
+        return isNamedMethodCall("super", tree);
+    }
+
+    /**
+     * Checks if the method invocation is a call to this.
+     *
+     * @param tree a tree defining a method invocation
+     * @return true iff tree describes a call to this
+     */
+    public static boolean isThisCall(MethodInvocationTree tree) {
+        return isNamedMethodCall("this", tree);
+    }
+
+    protected static boolean isNamedMethodCall(String name, MethodInvocationTree tree) {
         /*@Nullable*/ ExpressionTree mst = tree.getMethodSelect();
         assert mst != null; /*nninvariant*/
 
-        if (mst.getKind() == Tree.Kind.IDENTIFIER ) {
-            return ((IdentifierTree)mst).getName().contentEquals("super");
+        if (mst.getKind() == Tree.Kind.IDENTIFIER) {
+            return ((IdentifierTree) mst).getName().contentEquals(name);
         }
 
         if (mst.getKind() == Tree.Kind.MEMBER_SELECT) {
-            MemberSelectTree selectTree = (MemberSelectTree)mst;
+            MemberSelectTree selectTree = (MemberSelectTree) mst;
 
             if (selectTree.getExpression().getKind() != Tree.Kind.IDENTIFIER) {
                 return false;
             }
 
-            return ((IdentifierTree) selectTree.getExpression()).getName()
-                .contentEquals("super");
+            return ((IdentifierTree) selectTree.getExpression()).getName().contentEquals(name);
         }
 
         return false;
     }
 
     /**
-     * Returns true if the tree is a tree that 'looks like' either an access
-     * of a field or an invocation of a method that are owned by the same
-     * accessing instance.
+     * Returns true if the tree is a tree that 'looks like' either an access of a field or an
+     * invocation of a method that are owned by the same accessing instance.
      *
-     * It would only return true if the access tree is of the form:
+     * <p>It would only return true if the access tree is of the form:
+     *
      * <pre>
      *   field
      *   this.field
@@ -110,35 +121,37 @@
      *   this.method()
      * </pre>
      *
-     * It does not perform any semantical check to differentiate between
-     * fields and local variables; local methods or imported static methods.
+     * It does not perform any semantical check to differentiate between fields and local variables;
+     * local methods or imported static methods.
      *
-     * @param tree  expression tree representing an access to object member
+     * @param tree expression tree representing an access to object member
      * @return {@code true} iff the member is a member of {@code this} instance
      */
     public static boolean isSelfAccess(final ExpressionTree tree) {
         ExpressionTree tr = TreeUtils.skipParens(tree);
         // If method invocation check the method select
-        if (tr.getKind() == Tree.Kind.ARRAY_ACCESS)
+        if (tr.getKind() == Tree.Kind.ARRAY_ACCESS) {
             return false;
+        }
 
         if (tree.getKind() == Tree.Kind.METHOD_INVOCATION) {
-            tr = ((MethodInvocationTree)tree).getMethodSelect();
+            tr = ((MethodInvocationTree) tree).getMethodSelect();
         }
         tr = TreeUtils.skipParens(tr);
-        if (tr.getKind() == Tree.Kind.TYPE_CAST)
-            tr = ((TypeCastTree)tr).getExpression();
+        if (tr.getKind() == Tree.Kind.TYPE_CAST) {
+            tr = ((TypeCastTree) tr).getExpression();
+        }
         tr = TreeUtils.skipParens(tr);
 
-        if (tr.getKind() == Tree.Kind.IDENTIFIER)
+        if (tr.getKind() == Tree.Kind.IDENTIFIER) {
             return true;
+        }
 
         if (tr.getKind() == Tree.Kind.MEMBER_SELECT) {
-            tr = ((MemberSelectTree)tr).getExpression();
+            tr = ((MemberSelectTree) tr).getExpression();
             if (tr.getKind() == Tree.Kind.IDENTIFIER) {
-                Name ident = ((IdentifierTree)tr).getName();
-                return ident.contentEquals("this") ||
-                        ident.contentEquals("super");
+                Name ident = ((IdentifierTree) tr).getName();
+                return ident.contentEquals("this") || ident.contentEquals("super");
             }
         }
 
@@ -148,8 +161,8 @@
     /**
      * Gets the first enclosing tree in path, of the specified kind.
      *
-     * @param path  the path defining the tree node
-     * @param kind  the kind of the desired tree
+     * @param path the path defining the tree node
+     * @param kind the kind of the desired tree
      * @return the enclosing tree of the given type as given by the path
      */
     public static Tree enclosingOfKind(final TreePath path, final Tree.Kind kind) {
@@ -159,8 +172,8 @@
     /**
      * Gets the first enclosing tree in path, with any one of the specified kinds.
      *
-     * @param path  the path defining the tree node
-     * @param kinds  the set of kinds of the desired tree
+     * @param path the path defining the tree node
+     * @param kinds the set of kinds of the desired tree
      * @return the enclosing tree of the given type as given by the path
      */
     public static Tree enclosingOfKind(final TreePath path, final Set<Tree.Kind> kinds) {
@@ -169,8 +182,9 @@
         while (p != null) {
             Tree leaf = p.getLeaf();
             assert leaf != null; /*nninvariant*/
-            if (kinds.contains(leaf.getKind()))
+            if (kinds.contains(leaf.getKind())) {
                 return leaf;
+            }
             p = p.getParentPath();
         }
 
@@ -178,10 +192,10 @@
     }
 
     /**
-     * Gets path to the the first enclosing class tree, where class is
-     * defined by the classTreeKinds method.
+     * Gets path to the first enclosing class tree, where class is defined by the classTreeKinds
+     * method.
      *
-     * @param path  the path defining the tree node
+     * @param path the path defining the tree node
      * @return the path to the enclosing class tree
      */
     public static TreePath pathTillClass(final TreePath path) {
@@ -189,10 +203,10 @@
     }
 
     /**
-     * Gets path to the the first enclosing tree of the specified kind.
+     * Gets path to the first enclosing tree of the specified kind.
      *
-     * @param path  the path defining the tree node
-     * @param kind  the kind of the desired tree
+     * @param path the path defining the tree node
+     * @param kind the kind of the desired tree
      * @return the path to the enclosing tree of the given type
      */
     public static TreePath pathTillOfKind(final TreePath path, final Tree.Kind kind) {
@@ -200,10 +214,10 @@
     }
 
     /**
-     * Gets path to the the first enclosing tree with any one of the specified kinds.
+     * Gets path to the first enclosing tree with any one of the specified kinds.
      *
-     * @param path  the path defining the tree node
-     * @param kinds  the set of kinds of the desired tree
+     * @param path the path defining the tree node
+     * @param kinds the set of kinds of the desired tree
      * @return the path to the enclosing tree of the given type
      */
     public static TreePath pathTillOfKind(final TreePath path, final Set<Tree.Kind> kinds) {
@@ -212,8 +226,9 @@
         while (p != null) {
             Tree leaf = p.getLeaf();
             assert leaf != null; /*nninvariant*/
-            if (kinds.contains(leaf.getKind()))
+            if (kinds.contains(leaf.getKind())) {
                 return p;
+            }
             p = p.getParentPath();
         }
 
@@ -223,17 +238,19 @@
     /**
      * Gets the first enclosing tree in path, of the specified class
      *
-     * @param path  the path defining the tree node
+     * @param path the path defining the tree node
      * @param treeClass the class of the desired tree
      * @return the enclosing tree of the given type as given by the path
      */
-    public static <T extends Tree> T enclosingOfClass(final TreePath path, final Class<T> treeClass) {
+    public static <T extends Tree> T enclosingOfClass(
+            final TreePath path, final Class<T> treeClass) {
         TreePath p = path;
 
         while (p != null) {
             Tree leaf = p.getLeaf();
-            if (treeClass.isInstance(leaf))
+            if (treeClass.isInstance(leaf)) {
                 return treeClass.cast(leaf);
+            }
             p = p.getParentPath();
         }
 
@@ -241,22 +258,20 @@
     }
 
     /**
-     * Gets the enclosing class of the tree node defined by the given
-     * {@code {@link TreePath}}. It returns a {@link Tree}, from which
-     * {@code checkers.types.AnnotatedTypeMirror} or {@link Element} can be
+     * Gets the enclosing class of the tree node defined by the given {@link TreePath}. It returns a
+     * {@link Tree}, from which {@code checkers.types.AnnotatedTypeMirror} or {@link Element} can be
      * obtained.
      *
      * @param path the path defining the tree node
-     * @return the enclosing class (or interface) as given by the path, or null
-     *         if one does not exist.
+     * @return the enclosing class (or interface) as given by the path, or null if one does not
+     *     exist
      */
     public static /*@Nullable*/ ClassTree enclosingClass(final /*@Nullable*/ TreePath path) {
         return (ClassTree) enclosingOfKind(path, classTreeKinds());
     }
 
     /**
-     * Gets the enclosing variable of a tree node defined by the given
-     * {@link TreePath}.
+     * Gets the enclosing variable of a tree node defined by the given {@link TreePath}.
      *
      * @param path the path defining the tree node
      * @return the enclosing variable as given by the path, or null if one does not exist
@@ -266,14 +281,12 @@
     }
 
     /**
-     * Gets the enclosing method of the tree node defined by the given
-     * {@code {@link TreePath}}. It returns a {@link Tree}, from which an
-     * {@code checkers.types.AnnotatedTypeMirror} or {@link Element} can be
-     * obtained.
+     * Gets the enclosing method of the tree node defined by the given {@link TreePath}. It returns
+     * a {@link Tree}, from which an {@code checkers.types.AnnotatedTypeMirror} or {@link Element}
+     * can be obtained.
      *
      * @param path the path defining the tree node
-     * @return the enclosing method as given by the path, or null if one does
-     *         not exist
+     * @return the enclosing method as given by the path, or null if one does not exist
      */
     public static /*@Nullable*/ MethodTree enclosingMethod(final /*@Nullable*/ TreePath path) {
         return (MethodTree) enclosingOfKind(path, Tree.Kind.METHOD);
@@ -281,7 +294,7 @@
 
     public static /*@Nullable*/ BlockTree enclosingTopLevelBlock(TreePath path) {
         TreePath parpath = path.getParentPath();
-        while (parpath!=null && parpath.getLeaf().getKind() != Tree.Kind.CLASS) {
+        while (parpath != null && !classTreeKinds.contains(parpath.getLeaf().getKind())) {
             path = parpath;
             parpath = parpath.getParentPath();
         }
@@ -291,61 +304,89 @@
         return null;
     }
 
-
     /**
-     * If the given tree is a parenthesized tree, it returns the enclosed
-     * non-parenthesized tree. Otherwise, it returns the same tree.
+     * If the given tree is a parenthesized tree, it returns the enclosed non-parenthesized tree.
+     * Otherwise, it returns the same tree.
      *
-     * @param tree  an expression tree
-     * @return  the outermost non-parenthesized tree enclosed by the given tree
+     * @param tree an expression tree
+     * @return the outermost non-parenthesized tree enclosed by the given tree
      */
     public static ExpressionTree skipParens(final ExpressionTree tree) {
         ExpressionTree t = tree;
-        while (t.getKind() == Tree.Kind.PARENTHESIZED)
-            t = ((ParenthesizedTree)t).getExpression();
+        while (t.getKind() == Tree.Kind.PARENTHESIZED) {
+            t = ((ParenthesizedTree) t).getExpression();
+        }
         return t;
     }
 
     /**
-     * Returns the tree with the assignment context for the treePath
-     * leaf node.
+     * Returns the tree with the assignment context for the treePath leaf node. (Does not handle
+     * pseudo-assignment of an argument to a parameter or a receiver expression to a receiver.)
      *
-     * The assignment context for the treepath is the most enclosing
-     * tree of type:
+     * <p>The assignment context for the {@code treePath} is the leaf of its parent, if the parent
+     * is one of the following trees:
+     *
      * <ul>
-     *   <li>AssignmentTree </li>
-     *   <li>CompoundAssignmentTree </li>
-     *   <li>MethodInvocationTree</li>
-     *   <li>NewArrayTree</li>
-     *   <li>NewClassTree</li>
-     *   <li>ReturnTree</li>
-     *   <li>VariableTree</li>
+     *   <li>AssignmentTree
+     *   <li>CompoundAssignmentTree
+     *   <li>MethodInvocationTree
+     *   <li>NewArrayTree
+     *   <li>NewClassTree
+     *   <li>ReturnTree
+     *   <li>VariableTree
      * </ul>
      *
-     * @param treePath
-     * @return  the assignment context as described.
+     * If the parent is a ConditionalExpressionTree we need to distinguish two cases: If the leaf is
+     * either the then or else branch of the ConditionalExpressionTree, then recurse on the parent.
+     * If the leaf is the condition of the ConditionalExpressionTree, then return null to not
+     * consider this assignment context.
+     *
+     * <p>If the leaf is a ParenthesizedTree, then recurse on the parent.
+     *
+     * <p>Otherwise, null is returned.
+     *
+     * @return the assignment context as described
      */
     public static Tree getAssignmentContext(final TreePath treePath) {
-        TreePath path = treePath.getParentPath();
+        TreePath parentPath = treePath.getParentPath();
 
-        if (path == null)
+        if (parentPath == null) {
             return null;
-        Tree node = path.getLeaf();
-        if ((node instanceof AssignmentTree) ||
-                (node instanceof CompoundAssignmentTree) ||
-                (node instanceof MethodInvocationTree) ||
-                (node instanceof NewArrayTree) ||
-                (node instanceof NewClassTree) ||
-                (node instanceof ReturnTree) ||
-                (node instanceof VariableTree))
-            return node;
-        return null;
+        }
+
+        Tree parent = parentPath.getLeaf();
+        switch (parent.getKind()) {
+            case PARENTHESIZED:
+                return getAssignmentContext(parentPath);
+            case CONDITIONAL_EXPRESSION:
+                ConditionalExpressionTree cet = (ConditionalExpressionTree) parent;
+                if (cet.getCondition() == treePath.getLeaf()) {
+                    // The assignment context for the condition is simply boolean.
+                    // No point in going on.
+                    return null;
+                }
+                // Otherwise use the context of the ConditionalExpressionTree.
+                return getAssignmentContext(parentPath);
+            case ASSIGNMENT:
+            case METHOD_INVOCATION:
+            case NEW_ARRAY:
+            case NEW_CLASS:
+            case RETURN:
+            case VARIABLE:
+                return parent;
+            default:
+                // 11 Tree.Kinds are CompoundAssignmentTrees,
+                // so use instanceof rather than listing all 11.
+                if (parent instanceof CompoundAssignmentTree) {
+                    return parent;
+                }
+                return null;
+        }
     }
 
     /**
      * Gets the element for a class corresponding to a declaration.
      *
-     * @param node
      * @return the element for the given class
      */
     public static final TypeElement elementFromDeclaration(ClassTree node) {
@@ -356,7 +397,6 @@
     /**
      * Gets the element for a method corresponding to a declaration.
      *
-     * @param node
      * @return the element for the given method
      */
     public static final ExecutableElement elementFromDeclaration(MethodTree node) {
@@ -367,7 +407,6 @@
     /**
      * Gets the element for a variable corresponding to its declaration.
      *
-     * @param node
      * @return the element for the given variable
      */
     public static final VariableElement elementFromDeclaration(VariableTree node) {
@@ -376,11 +415,10 @@
     }
 
     /**
-     * Gets the element for the declaration corresponding to this use of an element.
-     * To get the element for a declaration, use {@link
-     * Trees#getElement(TreePath)} instead.
+     * Gets the element for the declaration corresponding to this use of an element. To get the
+     * element for a declaration, use {@link Trees#getElement(TreePath)} instead.
      *
-     * TODO: remove this method, as it really doesn't do anything.
+     * <p>TODO: remove this method, as it really doesn't do anything.
      *
      * @param node the tree corresponding to a use of an element
      * @return the element for the corresponding declaration
@@ -390,8 +428,14 @@
     }
 
     // Specialization for return type.
+    // Might return null if element wasn't found.
     public static final ExecutableElement elementFromUse(MethodInvocationTree node) {
-        return (ExecutableElement) elementFromUse((ExpressionTree) node);
+        Element el = elementFromUse((ExpressionTree) node);
+        if (el instanceof ExecutableElement) {
+            return (ExecutableElement) el;
+        } else {
+            return null;
+        }
     }
 
     // Specialization for return type.
@@ -399,12 +443,11 @@
         return (ExecutableElement) elementFromUse((ExpressionTree) node);
     }
 
-
     /**
      * Determine whether the given ExpressionTree has an underlying element.
      *
      * @param node the ExpressionTree to test
-     * @return whether the tree refers to an identifier, member select, or method invocation.
+     * @return whether the tree refers to an identifier, member select, or method invocation
      */
     public static final boolean isUseOfElement(ExpressionTree node) {
         node = TreeUtils.skipParens(node);
@@ -419,35 +462,35 @@
         }
     }
 
-    /**
-     * @return the name of the invoked method
-     */
+    /** @return the name of the invoked method */
     public static final Name methodName(MethodInvocationTree node) {
         ExpressionTree expr = node.getMethodSelect();
-        if (expr.getKind() == Tree.Kind.IDENTIFIER)
-            return ((IdentifierTree)expr).getName();
-        else if (expr.getKind() == Tree.Kind.MEMBER_SELECT)
-            return ((MemberSelectTree)expr).getIdentifier();
+        if (expr.getKind() == Tree.Kind.IDENTIFIER) {
+            return ((IdentifierTree) expr).getName();
+        } else if (expr.getKind() == Tree.Kind.MEMBER_SELECT) {
+            return ((MemberSelectTree) expr).getIdentifier();
+        }
         ErrorReporter.errorAbort("TreeUtils.methodName: cannot be here: " + node);
         return null; // dead code
     }
 
     /**
-     * @return true if the first statement in the body is a self constructor
-     *  invocation within a constructor
+     * @return true if the first statement in the body is a self constructor invocation within a
+     *     constructor
      */
     public static final boolean containsThisConstructorInvocation(MethodTree node) {
-        if (!TreeUtils.isConstructor(node)
-                || node.getBody().getStatements().isEmpty())
+        if (!TreeUtils.isConstructor(node) || node.getBody().getStatements().isEmpty())
             return false;
 
         StatementTree st = node.getBody().getStatements().get(0);
         if (!(st instanceof ExpressionStatementTree)
-                || !(((ExpressionStatementTree)st).getExpression() instanceof MethodInvocationTree))
+                || !(((ExpressionStatementTree) st).getExpression()
+                        instanceof MethodInvocationTree)) {
             return false;
+        }
 
-        MethodInvocationTree invocation = (MethodInvocationTree)
-            ((ExpressionStatementTree)st).getExpression();
+        MethodInvocationTree invocation =
+                (MethodInvocationTree) ((ExpressionStatementTree) st).getExpression();
 
         return "this".contentEquals(TreeUtils.methodName(invocation));
     }
@@ -455,11 +498,12 @@
     public static final Tree firstStatement(Tree tree) {
         Tree first;
         if (tree.getKind() == Tree.Kind.BLOCK) {
-            BlockTree block = (BlockTree)tree;
-            if (block.getStatements().isEmpty())
+            BlockTree block = (BlockTree) tree;
+            if (block.getStatements().isEmpty()) {
                 first = block;
-            else
+            } else {
                 first = block.getStatements().iterator().next();
+            }
         } else {
             first = tree;
         }
@@ -469,13 +513,13 @@
     /**
      * Determine whether the given class contains an explicit constructor.
      *
-     * @param node A class tree.
-     * @return True, iff there is an explicit constructor.
+     * @param node a class tree
+     * @return true, iff there is an explicit constructor
      */
     public static boolean hasExplicitConstructor(ClassTree node) {
         TypeElement elem = TreeUtils.elementFromDeclaration(node);
 
-        for ( ExecutableElement ee : ElementFilter.constructorsIn(elem.getEnclosedElements())) {
+        for (ExecutableElement ee : ElementFilter.constructorsIn(elem.getEnclosedElements())) {
             MethodSymbol ms = (MethodSymbol) ee;
             long mod = ms.flags();
 
@@ -487,33 +531,31 @@
     }
 
     /**
-     * Returns true if the tree is of a diamond type.
-     * In contrast to the implementation in TreeInfo, this version
-     * works on Trees.
+     * Returns true if the tree is of a diamond type. In contrast to the implementation in TreeInfo,
+     * this version works on Trees.
      *
      * @see com.sun.tools.javac.tree.TreeInfo#isDiamond(JCTree)
      */
     public static final boolean isDiamondTree(Tree tree) {
         switch (tree.getKind()) {
-        case ANNOTATED_TYPE: return isDiamondTree(((AnnotatedTypeTree)tree).getUnderlyingType());
-        case PARAMETERIZED_TYPE: return ((ParameterizedTypeTree)tree).getTypeArguments().isEmpty();
-        case NEW_CLASS: return isDiamondTree(((NewClassTree)tree).getIdentifier());
-        default: return false;
+            case ANNOTATED_TYPE:
+                return isDiamondTree(((AnnotatedTypeTree) tree).getUnderlyingType());
+            case PARAMETERIZED_TYPE:
+                return ((ParameterizedTypeTree) tree).getTypeArguments().isEmpty();
+            case NEW_CLASS:
+                return isDiamondTree(((NewClassTree) tree).getIdentifier());
+            default:
+                return false;
         }
     }
 
-    /**
-     * Returns true if the tree represents a {@code String} concatenation
-     * operation
-     */
+    /** Returns true if the tree represents a {@code String} concatenation operation */
     public static final boolean isStringConcatenation(Tree tree) {
         return (tree.getKind() == Tree.Kind.PLUS
                 && TypesUtils.isString(InternalUtils.typeOf(tree)));
     }
 
-    /**
-     * Returns true if the compound assignment tree is a string concatenation
-     */
+    /** Returns true if the compound assignment tree is a string concatenation */
     public static final boolean isStringCompoundConcatenation(CompoundAssignmentTree tree) {
         return (tree.getKind() == Tree.Kind.PLUS_ASSIGNMENT
                 && TypesUtils.isString(InternalUtils.typeOf(tree)));
@@ -522,18 +564,19 @@
     /**
      * Returns true if the node is a constant-time expression.
      *
-     * A tree is a constant-time expression if it is:
+     * <p>A tree is a constant-time expression if it is:
+     *
      * <ol>
-     * <li>a literal tree
-     * <li>a reference to a final variable initialized with a compile time
-     *  constant
-     * <li>a String concatenation of two compile time constants
+     *   <li>a literal tree
+     *   <li>a reference to a final variable initialized with a compile time constant
+     *   <li>a String concatenation of two compile time constants
      * </ol>
      */
     public static boolean isCompileTimeString(ExpressionTree node) {
         ExpressionTree tree = TreeUtils.skipParens(node);
-        if (tree instanceof LiteralTree)
+        if (tree instanceof LiteralTree) {
             return true;
+        }
 
         if (TreeUtils.isUseOfElement(tree)) {
             Element elt = TreeUtils.elementFromUse(tree);
@@ -541,15 +584,13 @@
         } else if (TreeUtils.isStringConcatenation(tree)) {
             BinaryTree binOp = (BinaryTree) tree;
             return isCompileTimeString(binOp.getLeftOperand())
-                && isCompileTimeString(binOp.getRightOperand());
+                    && isCompileTimeString(binOp.getRightOperand());
         } else {
             return false;
         }
     }
 
-    /**
-     * Returns the receiver tree of a field access or a method invocation
-     */
+    /** Returns the receiver tree of a field access or a method invocation */
     public static ExpressionTree getReceiverTree(ExpressionTree expression) {
         ExpressionTree receiver = TreeUtils.skipParens(expression);
 
@@ -565,13 +606,13 @@
             // Trying to handle receiver calls to trees of the form
             //     ((m).getArray())
             // returns the type of 'm' in this case
-            receiver = ((MethodInvocationTree)receiver).getMethodSelect();
+            receiver = ((MethodInvocationTree) receiver).getMethodSelect();
 
             if (receiver.getKind() == Tree.Kind.IDENTIFIER) {
                 // It's a method call "m(foo)" without an explicit receiver
                 return null;
             } else if (receiver.getKind() == Tree.Kind.MEMBER_SELECT) {
-                receiver = ((MemberSelectTree)receiver).getExpression();
+                receiver = ((MemberSelectTree) receiver).getExpression();
             } else {
                 // Otherwise, e.g. a NEW_CLASS: nothing to do.
             }
@@ -579,9 +620,9 @@
             // It's a field access on implicit this or a local variable/parameter.
             return null;
         } else if (receiver.getKind() == Tree.Kind.ARRAY_ACCESS) {
-            return TreeUtils.skipParens(((ArrayAccessTree)receiver).getExpression());
+            return TreeUtils.skipParens(((ArrayAccessTree) receiver).getExpression());
         } else if (receiver.getKind() == Tree.Kind.MEMBER_SELECT) {
-            receiver = ((MemberSelectTree)receiver).getExpression();
+            receiver = ((MemberSelectTree) receiver).getExpression();
             // Avoid int.class
             if (receiver instanceof PrimitiveTypeTree) {
                 return null;
@@ -596,20 +637,19 @@
     // Adding Tree.Kind.NEW_CLASS here doesn't work, because then a
     // tree gets cast to ClassTree when it is actually a NewClassTree,
     // for example in enclosingClass above.
-    private final static Set<Tree.Kind> classTreeKinds = EnumSet.of(
-            Tree.Kind.CLASS,
-            Tree.Kind.ENUM,
-            Tree.Kind.INTERFACE,
-            Tree.Kind.ANNOTATION_TYPE
-    );
+    private static final Set<Tree.Kind> classTreeKinds =
+            EnumSet.of(
+                    Tree.Kind.CLASS,
+                    Tree.Kind.ENUM,
+                    Tree.Kind.INTERFACE,
+                    Tree.Kind.ANNOTATION_TYPE);
 
     public static Set<Tree.Kind> classTreeKinds() {
         return classTreeKinds;
     }
 
     /**
-     * Is the given tree kind a class, i.e. a class, enum,
-     * interface, or annotation type.
+     * Is the given tree kind a class, i.e. a class, enum, interface, or annotation type.
      *
      * @param tree the tree to test
      * @return true, iff the given kind is a class kind
@@ -618,16 +658,16 @@
         return classTreeKinds().contains(tree.getKind());
     }
 
-    private final static Set<Tree.Kind> typeTreeKinds = EnumSet.of(
-            Tree.Kind.PRIMITIVE_TYPE,
-            Tree.Kind.PARAMETERIZED_TYPE,
-            Tree.Kind.TYPE_PARAMETER,
-            Tree.Kind.ARRAY_TYPE,
-            Tree.Kind.UNBOUNDED_WILDCARD,
-            Tree.Kind.EXTENDS_WILDCARD,
-            Tree.Kind.SUPER_WILDCARD,
-            Tree.Kind.ANNOTATED_TYPE
-    );
+    private static final Set<Tree.Kind> typeTreeKinds =
+            EnumSet.of(
+                    Tree.Kind.PRIMITIVE_TYPE,
+                    Tree.Kind.PARAMETERIZED_TYPE,
+                    Tree.Kind.TYPE_PARAMETER,
+                    Tree.Kind.ARRAY_TYPE,
+                    Tree.Kind.UNBOUNDED_WILDCARD,
+                    Tree.Kind.EXTENDS_WILDCARD,
+                    Tree.Kind.SUPER_WILDCARD,
+                    Tree.Kind.ANNOTATED_TYPE);
 
     public static Set<Tree.Kind> typeTreeKinds() {
         return typeTreeKinds;
@@ -636,8 +676,8 @@
     /**
      * Is the given tree a type instantiation?
      *
-     * TODO: this is an under-approximation: e.g. an identifier could
-     * be either a type use or an expression. How can we distinguish.
+     * <p>TODO: this is an under-approximation: e.g. an identifier could be either a type use or an
+     * expression. How can we distinguish.
      *
      * @param tree the tree to test
      * @return true, iff the given tree is a type
@@ -647,54 +687,60 @@
     }
 
     /**
-     * Returns true if the given element is an invocation of the method, or
-     * of any method that overrides that one.
+     * Returns true if the given element is an invocation of the method, or of any method that
+     * overrides that one.
      */
-    public static boolean isMethodInvocation(Tree tree, ExecutableElement method, ProcessingEnvironment env) {
-        if (!(tree instanceof MethodInvocationTree))
+    public static boolean isMethodInvocation(
+            Tree tree, ExecutableElement method, ProcessingEnvironment env) {
+        if (!(tree instanceof MethodInvocationTree)) {
             return false;
-        MethodInvocationTree methInvok = (MethodInvocationTree)tree;
+        }
+        MethodInvocationTree methInvok = (MethodInvocationTree) tree;
         ExecutableElement invoked = TreeUtils.elementFromUse(methInvok);
-        return isMethod(invoked, method, env);
-    }
-
-    /** Returns true if the given element is, or overrides, method. */
-    private static boolean isMethod(ExecutableElement questioned, ExecutableElement method, ProcessingEnvironment env) {
-        return (questioned.equals(method)
-                || env.getElementUtils().overrides(questioned, method,
-                        (TypeElement)questioned.getEnclosingElement()));
+        return ElementUtils.isMethod(invoked, method, env);
     }
 
     /**
-     * Returns the ExecutableElement for a method declaration of
-     * methodName, in class typeName, with params parameters.
+     * Returns the ExecutableElement for a method declaration of methodName, in class typeName, with
+     * params parameters.
      *
-     * TODO: to precisely resolve method overloading, we should use parameter types and not just
+     * <p>TODO: to precisely resolve method overloading, we should use parameter types and not just
      * the number of parameters!
      */
-    public static ExecutableElement getMethod(String typeName, String methodName, int params, ProcessingEnvironment env) {
-        TypeElement mapElt = env.getElementUtils().getTypeElement(typeName);
-        for (ExecutableElement exec : ElementFilter.methodsIn(mapElt.getEnclosedElements())) {
+    public static ExecutableElement getMethod(
+            String typeName, String methodName, int params, ProcessingEnvironment env) {
+        TypeElement typeElt = env.getElementUtils().getTypeElement(typeName);
+        for (ExecutableElement exec : ElementFilter.methodsIn(typeElt.getEnclosedElements())) {
             if (exec.getSimpleName().contentEquals(methodName)
-                    && exec.getParameters().size() == params)
+                    && exec.getParameters().size() == params) {
                 return exec;
+            }
         }
         ErrorReporter.errorAbort("TreeUtils.getMethod: shouldn't be here!");
         return null; // dead code
     }
 
+    public static List<ExecutableElement> getMethodList(
+            String typeName, String methodName, int params, ProcessingEnvironment env) {
+        List<ExecutableElement> methods = new ArrayList<>();
+        TypeElement typeElement = env.getElementUtils().getTypeElement(typeName);
+        for (ExecutableElement exec : ElementFilter.methodsIn(typeElement.getEnclosedElements())) {
+            if (exec.getSimpleName().contentEquals(methodName)
+                    && exec.getParameters().size() == params) {
+                methods.add(exec);
+            }
+        }
+        return methods;
+    }
+
     /**
-     * Determine whether the given expression is either "this" or an outer
-     * "C.this".
+     * Determine whether the given expression is either "this" or an outer "C.this".
      *
-     * TODO: Should this also handle "super"?
-     *
-     * @param tree
-     * @return
+     * <p>TODO: Should this also handle "super"?
      */
     public static final boolean isExplicitThisDereference(ExpressionTree tree) {
         if (tree.getKind() == Tree.Kind.IDENTIFIER
-                && ((IdentifierTree)tree).getName().contentEquals("this")) {
+                && ((IdentifierTree) tree).getName().contentEquals("this")) {
             // Explicit this reference "this"
             return true;
         }
@@ -712,16 +758,30 @@
     }
 
     /**
-     * Determine whether <code>tree</code> is a field access expressions, such
-     * as
+     * Determine whether {@code tree} is a class literal, such as
+     *
+     * <pre>
+     *   <em>Object</em> . <em>class</em>
+     * </pre>
+     *
+     * @return true iff if tree is a class literal
+     */
+    public static boolean isClassLiteral(Tree tree) {
+        if (tree.getKind() != Tree.Kind.MEMBER_SELECT) {
+            return false;
+        }
+        return "class".equals(((MemberSelectTree) tree).getIdentifier().toString());
+    }
+
+    /**
+     * Determine whether {@code tree} is a field access expressions, such as
      *
      * <pre>
      *   <em>f</em>
      *   <em>obj</em> . <em>f</em>
      * </pre>
      *
-     * @return true iff if tree is a field access expression (implicit or
-     *         explicit).
+     * @return true iff if tree is a field access expression (implicit or explicit)
      */
     public static boolean isFieldAccess(Tree tree) {
         if (tree.getKind().equals(Tree.Kind.MEMBER_SELECT)) {
@@ -734,17 +794,17 @@
             IdentifierTree ident = (IdentifierTree) tree;
             Element el = TreeUtils.elementFromUse(ident);
             return el.getKind().isField()
-                    && !ident.getName().contentEquals("this") && !ident.getName().contentEquals("super");
+                    && !ident.getName().contentEquals("this")
+                    && !ident.getName().contentEquals("super");
         }
         return false;
     }
 
     /**
-     * Compute the name of the field that the field access <code>tree</code>
-     * accesses. Requires <code>tree</code> to be a field access, as determined
-     * by <code>isFieldAccess</code>.
+     * Compute the name of the field that the field access {@code tree} accesses. Requires {@code
+     * tree} to be a field access, as determined by {@code isFieldAccess}.
      *
-     * @return The name of the field accessed by <code>tree</code>.
+     * @return the name of the field accessed by {@code tree}.
      */
     public static String getFieldName(Tree tree) {
         assert isFieldAccess(tree);
@@ -758,45 +818,39 @@
     }
 
     /**
-     * Determine whether <code>tree</code> refers to a method element, such
-     * as
+     * Determine whether {@code tree} refers to a method element, such as
      *
      * <pre>
      *   <em>m</em>(...)
      *   <em>obj</em> . <em>m</em>(...)
      * </pre>
      *
-     * @return true iff if tree is a method access expression (implicit or
-     *         explicit).
+     * @return true iff if tree is a method access expression (implicit or explicit)
      */
     public static boolean isMethodAccess(Tree tree) {
         if (tree.getKind().equals(Tree.Kind.MEMBER_SELECT)) {
             // explicit method access
             MemberSelectTree memberSelect = (MemberSelectTree) tree;
             Element el = TreeUtils.elementFromUse(memberSelect);
-            return el.getKind() == ElementKind.METHOD
-                    || el.getKind() == ElementKind.CONSTRUCTOR;
+            return el.getKind() == ElementKind.METHOD || el.getKind() == ElementKind.CONSTRUCTOR;
         } else if (tree.getKind().equals(Tree.Kind.IDENTIFIER)) {
             // implicit method access
             IdentifierTree ident = (IdentifierTree) tree;
             // The field "super" and "this" are also legal methods
-            if (ident.getName().contentEquals("super")
-                    || ident.getName().contentEquals("this")) {
+            if (ident.getName().contentEquals("super") || ident.getName().contentEquals("this")) {
                 return true;
             }
             Element el = TreeUtils.elementFromUse(ident);
-            return el.getKind() == ElementKind.METHOD
-                    || el.getKind() == ElementKind.CONSTRUCTOR;
+            return el.getKind() == ElementKind.METHOD || el.getKind() == ElementKind.CONSTRUCTOR;
         }
         return false;
     }
 
     /**
-     * Compute the name of the method that the method access <code>tree</code>
-     * accesses. Requires <code>tree</code> to be a method access, as determined
-     * by <code>isMethodAccess</code>.
+     * Compute the name of the method that the method access {@code tree} accesses. Requires {@code
+     * tree} to be a method access, as determined by {@code isMethodAccess}.
      *
-     * @return The name of the method accessed by <code>tree</code>.
+     * @return the name of the method accessed by {@code tree}.
      */
     public static String getMethodName(Tree tree) {
         assert isMethodAccess(tree);
@@ -810,19 +864,17 @@
     }
 
     /**
-     * @return {@code true} if and only if {@code tree} can have a type
-     *         annotation.
-     *
-     * TODO: is this implementation precise enough? E.g. does
-     * a .class literal work correctly?
+     * @return {@code true} if and only if {@code tree} can have a type annotation.
+     *     <p>TODO: is this implementation precise enough? E.g. does a .class literal work
+     *     correctly?
      */
     public static boolean canHaveTypeAnnotation(Tree tree) {
         return ((JCTree) tree).type != null;
     }
 
     /**
-     * Returns true if and only if the given {@code tree} represents a field
-     * access of the given {@link VariableElement}.
+     * Returns true if and only if the given {@code tree} represents a field access of the given
+     * {@link VariableElement}.
      */
     public static boolean isSpecificFieldAccess(Tree tree, VariableElement var) {
         if (tree instanceof MemberSelectTree) {
@@ -841,12 +893,13 @@
     /**
      * Returns the VariableElement for a field declaration.
      *
-     * @param typeName the class where the field is declared.
-     * @param fieldName the name of the field.
-     * @param env the processing environment.
+     * @param typeName the class where the field is declared
+     * @param fieldName the name of the field
+     * @param env the processing environment
      * @return the VariableElement for typeName.fieldName
      */
-    public static VariableElement getField(String typeName, String fieldName, ProcessingEnvironment env) {
+    public static VariableElement getField(
+            String typeName, String fieldName, ProcessingEnvironment env) {
         TypeElement mapElt = env.getElementUtils().getTypeElement(typeName);
         for (VariableElement var : ElementFilter.fieldsIn(mapElt.getEnclosedElements())) {
             if (var.getSimpleName().contentEquals(fieldName)) {
@@ -857,11 +910,12 @@
         return null; // dead code
     }
 
-    /** Determine whether the given tree represents an ExpressionTree.
+    /**
+     * Determine whether the given tree represents an ExpressionTree.
      *
-     * TODO: is there a nicer way than an instanceof?
+     * <p>TODO: is there a nicer way than an instanceof?
      *
-     * @param tree the Tree to test.
+     * @param tree the Tree to test
      * @return whether the tree is an ExpressionTree
      */
     public static boolean isExpressionTree(Tree tree) {
@@ -880,16 +934,17 @@
         return correctClass && correctMethod;
     }
 
-    /** Determine whether the given tree represents a declaration of a type
-     * (including type parameters).
+    /**
+     * Determine whether the given tree represents a declaration of a type (including type
+     * parameters).
      *
-     * @param node  the Tree to test
+     * @param node the Tree to test
      * @return true if the tree is a type declaration
      */
     public static boolean isTypeDeclaration(Tree node) {
         switch (node.getKind()) {
-            // These tree kinds are always declarations.  Uses of the declared
-            // types have tree kind IDENTIFIER.
+                // These tree kinds are always declarations.  Uses of the declared
+                // types have tree kind IDENTIFIER.
             case ANNOTATION_TYPE:
             case CLASS:
             case ENUM:
@@ -901,4 +956,65 @@
                 return false;
         }
     }
+
+    /**
+     * @see Object#getClass()
+     * @return true iff invocationTree is an instance of getClass()
+     */
+    public static boolean isGetClassInvocation(MethodInvocationTree invocationTree) {
+        final Element declarationElement = elementFromUse(invocationTree);
+        String ownerName =
+                ElementUtils.getQualifiedClassName(declarationElement.getEnclosingElement())
+                        .toString();
+        return ownerName.equals("java.lang.Object")
+                && declarationElement.getSimpleName().toString().equals("getClass");
+    }
+
+    /**
+     * Returns whether or not the leaf of the tree path is in a static scope.
+     *
+     * @param path TreePath whose leaf may or may not be in static scope
+     * @return returns whether or not the leaf of the tree path is in a static scope
+     */
+    public static boolean isTreeInStaticScope(TreePath path) {
+        MethodTree enclosingMethod = TreeUtils.enclosingMethod(path);
+
+        if (enclosingMethod != null) {
+            return enclosingMethod.getModifiers().getFlags().contains(Modifier.STATIC);
+        }
+        // no enclosing method, check for static or initializer block
+        BlockTree block = enclosingTopLevelBlock(path);
+        if (block != null) {
+            return block.isStatic();
+        }
+
+        // check if its in a variable initializer
+        Tree t = enclosingVariable(path);
+        if (t != null) {
+            return ((VariableTree) t).getModifiers().getFlags().contains((Modifier.STATIC));
+        }
+        ClassTree classTree = enclosingClass(path);
+        if (classTree != null) {
+            return classTree.getModifiers().getFlags().contains((Modifier.STATIC));
+        }
+        return false;
+    }
+
+    /**
+     * Returns whether or not tree is an access of array length.
+     *
+     * @param tree tree to check
+     * @return true if tree is an access of array length
+     */
+    public static boolean isArrayLengthAccess(Tree tree) {
+        if (tree.getKind() == Kind.MEMBER_SELECT
+                && isFieldAccess(tree)
+                && getFieldName(tree).equals("length")) {
+            ExpressionTree expressionTree = ((MemberSelectTree) tree).getExpression();
+            if (InternalUtils.typeOf(expressionTree).getKind() == TypeKind.ARRAY) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypeAnnotationUtils.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypeAnnotationUtils.java
index c166e43..b925f91 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypeAnnotationUtils.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypeAnnotationUtils.java
@@ -1,11 +1,20 @@
 package org.checkerframework.javacutil;
 
-import java.lang.reflect.InvocationTargetException;
+import com.sun.tools.javac.code.Attribute;
+import com.sun.tools.javac.code.Attribute.TypeCompound;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.TargetType;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.TypeAnnotationPosition;
+import com.sun.tools.javac.processing.JavacProcessingEnvironment;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Name;
+import com.sun.tools.javac.util.Pair;
+import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Map;
-
 import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.SourceVersion;
 import javax.lang.model.element.AnnotationMirror;
 import javax.lang.model.element.AnnotationValue;
 import javax.lang.model.element.AnnotationValueVisitor;
@@ -18,18 +27,6 @@
 import javax.lang.model.util.Elements;
 import javax.lang.model.util.Types;
 
-import com.sun.tools.javac.code.Attribute;
-import com.sun.tools.javac.code.Attribute.TypeCompound;
-import com.sun.tools.javac.code.Symbol;
-import com.sun.tools.javac.code.TargetType;
-import com.sun.tools.javac.code.Type;
-import com.sun.tools.javac.code.TypeAnnotationPosition;
-import com.sun.tools.javac.processing.JavacProcessingEnvironment;
-import com.sun.tools.javac.tree.JCTree.JCLambda;
-import com.sun.tools.javac.util.Context;
-import com.sun.tools.javac.util.List;
-import com.sun.tools.javac.util.Pair;
-
 /**
  * A collection of helper methods related to type annotation handling.
  *
@@ -38,111 +35,117 @@
 public class TypeAnnotationUtils {
 
     // Class cannot be instantiated.
-    private TypeAnnotationUtils() { throw new AssertionError("Class TypeAnnotationUtils cannot be instantiated."); }
+    private TypeAnnotationUtils() {
+        throw new AssertionError("Class TypeAnnotationUtils cannot be instantiated.");
+    }
 
     /**
      * Check whether a TypeCompound is contained in a list of TypeCompounds.
      *
-     * @param list The input list of TypeCompounds.
-     * @param tc The TypeCompound to find.
-     * @return true, iff a TypeCompound equal to tc is contained in list.
+     * @param list the input list of TypeCompounds
+     * @param tc the TypeCompound to find
+     * @return true, iff a TypeCompound equal to tc is contained in list
      */
-    public static boolean isTypeCompoundContained(Types types, List<TypeCompound> list, TypeCompound tc) {
+    public static boolean isTypeCompoundContained(
+            Types types, List<TypeCompound> list, TypeCompound tc) {
         for (Attribute.TypeCompound rawat : list) {
-            if (rawat.type.tsym.name.contentEquals(tc.type.tsym.name) &&
+            if (contentEquals(rawat.type.tsym.name, tc.type.tsym.name)
                     // TODO: in previous line, it would be nicer to use reference equality:
                     //   rawat.type == tc.type &&
                     // or at least "isSameType":
                     //   types.isSameType(rawat.type, tc.type) &&
                     // but each fails in some cases.
-                    rawat.values.equals(tc.values) &&
-                    isSameTAPosition(rawat.position, tc.position)) {
+                    && rawat.values.equals(tc.values)
+                    && isSameTAPositionExceptTreePos(rawat.position, tc.position)) {
                 return true;
             }
         }
         return false;
     }
 
+    private static boolean contentEquals(Name n1, Name n2) {
+        // Views of underlying bytes, not copies as with Name#contentEquals
+        ByteBuffer b1 = ByteBuffer.wrap(n1.getByteArray(), n1.getByteOffset(), n1.getByteLength());
+        ByteBuffer b2 = ByteBuffer.wrap(n2.getByteArray(), n2.getByteOffset(), n2.getByteLength());
+
+        return b1.equals(b2);
+    }
+
     /**
      * Compare two TypeAnnotationPositions for equality.
      *
-     * @param p1 The first position.
-     * @param p2 The second position.
-     * @return true, iff the two positions are equal.
+     * @param p1 the first position
+     * @param p2 the second position
+     * @return true, iff the two positions are equal
      */
-    public static boolean isSameTAPosition(TypeAnnotationPosition p1,
-            TypeAnnotationPosition p2) {
-        if (p1.isValidOffset == p2.isValidOffset &&
-                p1.bound_index == p2.bound_index &&
-                p1.exception_index == p2.exception_index &&
-                p1.location.equals(p2.location) &&
-                Arrays.equals(p1.lvarIndex, p2.lvarIndex) &&
-                Arrays.equals(p1.lvarLength, p2.lvarLength) &&
-                Arrays.equals(p1.lvarOffset, p2.lvarOffset) &&
-                p1.offset == p2.offset &&
-                p1.onLambda == p2.onLambda &&
-                p1.parameter_index == p2.parameter_index &&
-                p1.pos == p2.pos &&
-                p1.type == p2.type &&
-                p1.type_index == p2.type_index) {
-            return true;
-        }
-        return false;
+    public static boolean isSameTAPosition(TypeAnnotationPosition p1, TypeAnnotationPosition p2) {
+        return isSameTAPositionExceptTreePos(p1, p2) && p1.pos == p2.pos;
+    }
+
+    public static boolean isSameTAPositionExceptTreePos(
+            TypeAnnotationPosition p1, TypeAnnotationPosition p2) {
+        return p1.isValidOffset == p2.isValidOffset
+                && p1.bound_index == p2.bound_index
+                && p1.exception_index == p2.exception_index
+                && p1.location.equals(p2.location)
+                && Arrays.equals(p1.lvarIndex, p2.lvarIndex)
+                && Arrays.equals(p1.lvarLength, p2.lvarLength)
+                && Arrays.equals(p1.lvarOffset, p2.lvarOffset)
+                && p1.offset == p2.offset
+                && p1.onLambda == p2.onLambda
+                && p1.parameter_index == p2.parameter_index
+                && p1.type == p2.type
+                && p1.type_index == p2.type_index;
     }
 
     /**
-     * Returns a newly created Attribute.Compound corresponding to an
-     * argument AnnotationMirror.
+     * Returns a newly created Attribute.Compound corresponding to an argument AnnotationMirror.
      *
-     * @param am  an AnnotationMirror, which may be part of an AST or an internally
-     *            created subclass.
-     * @return  a new Attribute.Compound corresponding to the AnnotationMirror
+     * @param am an AnnotationMirror, which may be part of an AST or an internally created subclass
+     * @return a new Attribute.Compound corresponding to the AnnotationMirror
      */
-    public static Attribute.Compound createCompoundFromAnnotationMirror(ProcessingEnvironment env,
-            AnnotationMirror am) {
+    public static Attribute.Compound createCompoundFromAnnotationMirror(
+            ProcessingEnvironment env, AnnotationMirror am) {
         // Create a new Attribute to match the AnnotationMirror.
         List<Pair<Symbol.MethodSymbol, Attribute>> values = List.nil();
         for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry :
-                 am.getElementValues().entrySet()) {
-            Attribute attribute = attributeFromAnnotationValue(env, entry.getKey(), entry.getValue());
-            values = values.append(new Pair<>((Symbol.MethodSymbol)entry.getKey(),
-                                              attribute));
+                am.getElementValues().entrySet()) {
+            Attribute attribute =
+                    attributeFromAnnotationValue(env, entry.getKey(), entry.getValue());
+            values = values.append(new Pair<>((Symbol.MethodSymbol) entry.getKey(), attribute));
         }
-        return new Attribute.Compound((Type.ClassType)am.getAnnotationType(), values);
+        return new Attribute.Compound((Type.ClassType) am.getAnnotationType(), values);
     }
 
     /**
-     * Returns a newly created Attribute.TypeCompound corresponding to an
-     * argument AnnotationMirror.
+     * Returns a newly created Attribute.TypeCompound corresponding to an argument AnnotationMirror.
      *
-     * @param am  an AnnotationMirror, which may be part of an AST or an internally
-     *            created subclass.
-     * @param tapos  the type annotation position to use.
-     * @return  a new Attribute.TypeCompound corresponding to the AnnotationMirror
+     * @param am an AnnotationMirror, which may be part of an AST or an internally created subclass
+     * @param tapos the type annotation position to use
+     * @return a new Attribute.TypeCompound corresponding to the AnnotationMirror
      */
-    public static Attribute.TypeCompound createTypeCompoundFromAnnotationMirror(ProcessingEnvironment env,
-            AnnotationMirror am, TypeAnnotationPosition tapos) {
+    public static Attribute.TypeCompound createTypeCompoundFromAnnotationMirror(
+            ProcessingEnvironment env, AnnotationMirror am, TypeAnnotationPosition tapos) {
         // Create a new Attribute to match the AnnotationMirror.
         List<Pair<Symbol.MethodSymbol, Attribute>> values = List.nil();
         for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry :
-                 am.getElementValues().entrySet()) {
-            Attribute attribute = attributeFromAnnotationValue(env, entry.getKey(), entry.getValue());
-            values = values.append(new Pair<>((Symbol.MethodSymbol)entry.getKey(),
-                                              attribute));
+                am.getElementValues().entrySet()) {
+            Attribute attribute =
+                    attributeFromAnnotationValue(env, entry.getKey(), entry.getValue());
+            values = values.append(new Pair<>((Symbol.MethodSymbol) entry.getKey(), attribute));
         }
-        return new Attribute.TypeCompound((Type.ClassType)am.getAnnotationType(), values, tapos);
+        return new Attribute.TypeCompound((Type.ClassType) am.getAnnotationType(), values, tapos);
     }
 
     /**
-     * Returns a newly created Attribute corresponding to an argument
-     * AnnotationValue.
+     * Returns a newly created Attribute corresponding to an argument AnnotationValue.
      *
-     * @param meth the ExecutableElement that is assigned the value, needed for empty arrays.
-     * @param av  an AnnotationValue, which may be part of an AST or an internally
-     *            created subclass.
-     * @return  a new Attribute corresponding to the AnnotationValue
+     * @param meth the ExecutableElement that is assigned the value, needed for empty arrays
+     * @param av an AnnotationValue, which may be part of an AST or an internally created subclass
+     * @return a new Attribute corresponding to the AnnotationValue
      */
-    public static Attribute attributeFromAnnotationValue(ProcessingEnvironment env, ExecutableElement meth, AnnotationValue av) {
+    public static Attribute attributeFromAnnotationValue(
+            ProcessingEnvironment env, ExecutableElement meth, AnnotationValue av) {
         return av.accept(new AttributeCreator(env, meth), null);
     }
 
@@ -156,7 +159,7 @@
 
         public AttributeCreator(ProcessingEnvironment env, ExecutableElement meth) {
             this.processingEnv = env;
-            Context context = ((JavacProcessingEnvironment)env).getContext();
+            Context context = ((JavacProcessingEnvironment) env).getContext();
             this.elements = env.getElementUtils();
             this.modelTypes = env.getTypeUtils();
             this.javacTypes = com.sun.tools.javac.code.Types.instance(context);
@@ -183,55 +186,55 @@
         @Override
         public Attribute visitByte(byte b, Void p) {
             TypeMirror byteType = modelTypes.getPrimitiveType(TypeKind.BYTE);
-            return new Attribute.Constant((Type)byteType, b);
+            return new Attribute.Constant((Type) byteType, b);
         }
 
         @Override
         public Attribute visitChar(char c, Void p) {
             TypeMirror charType = modelTypes.getPrimitiveType(TypeKind.CHAR);
-            return new Attribute.Constant((Type)charType, c);
+            return new Attribute.Constant((Type) charType, c);
         }
 
         @Override
         public Attribute visitDouble(double d, Void p) {
             TypeMirror doubleType = modelTypes.getPrimitiveType(TypeKind.DOUBLE);
-            return new Attribute.Constant((Type)doubleType, d);
+            return new Attribute.Constant((Type) doubleType, d);
         }
 
         @Override
         public Attribute visitFloat(float f, Void p) {
             TypeMirror floatType = modelTypes.getPrimitiveType(TypeKind.FLOAT);
-            return new Attribute.Constant((Type)floatType, f);
+            return new Attribute.Constant((Type) floatType, f);
         }
 
         @Override
         public Attribute visitInt(int i, Void p) {
             TypeMirror intType = modelTypes.getPrimitiveType(TypeKind.INT);
-            return new Attribute.Constant((Type)intType, i);
+            return new Attribute.Constant((Type) intType, i);
         }
 
         @Override
         public Attribute visitLong(long i, Void p) {
             TypeMirror longType = modelTypes.getPrimitiveType(TypeKind.LONG);
-            return new Attribute.Constant((Type)longType, i);
+            return new Attribute.Constant((Type) longType, i);
         }
 
         @Override
         public Attribute visitShort(short s, Void p) {
             TypeMirror shortType = modelTypes.getPrimitiveType(TypeKind.SHORT);
-            return new Attribute.Constant((Type)shortType, s);
+            return new Attribute.Constant((Type) shortType, s);
         }
 
         @Override
         public Attribute visitString(String s, Void p) {
             TypeMirror stringType = elements.getTypeElement("java.lang.String").asType();
-            return new Attribute.Constant((Type)stringType, s);
+            return new Attribute.Constant((Type) stringType, s);
         }
 
         @Override
         public Attribute visitType(TypeMirror t, Void p) {
             if (t instanceof Type) {
-                return new Attribute.Class(javacTypes, (Type)t);
+                return new Attribute.Class(javacTypes, (Type) t);
             }
 
             assert false : "Unexpected type of TypeMirror: " + t.getClass();
@@ -264,7 +267,7 @@
                     valAttrs = valAttrs.append(av.accept(this, p));
                 }
                 ArrayType arrayType = modelTypes.getArrayType(valAttrs.get(0).type);
-                return new Attribute.Array((Type)arrayType, valAttrs);
+                return new Attribute.Array((Type) arrayType, valAttrs);
             } else {
                 return new Attribute.Array((Type) meth.getReturnType(), List.<Attribute>nil());
             }
@@ -277,338 +280,118 @@
         }
     }
 
-    /**
-     * An interface to abstract a Java 8 and a Java 9 version of how
-     * to get a RET reference.
-     * These methods must then be implemented using reflection in order to
-     * compile in either setting.
-     * Note that we cannot use lambda for this as long as we want to
-     * support Java 7.
-     */
-    interface Call8or9<RET> {
-        RET call8() throws Throwable;
-        RET call9() throws Throwable;
-    }
-
-    /**
-     * Use the SourceVersion to decide whether to call the Java 8 or Java 9 version.
-     * Catch all exceptions and abort if one occurs - the reflection code should
-     * never break once fully debugged.
-     *
-     * @param ver The SourceVersion to decide what API to use.
-     * @param tc The TAPCall abstraction to encapsulate two methods.
-     * @return The created TypeAnnotationPosition.
-     */
-    private static <RET> RET call8or9(Call8or9<RET> tc) {
-        try {
-            boolean hasNine;
-            try {
-                hasNine = SourceVersion.valueOf("RELEASE_9") != null;
-            } catch(IllegalArgumentException iae) {
-                hasNine = false;
-            }
-            if (hasNine) {
-                return tc.call9();
-            } else {
-                boolean hasEight;
-                try {
-                    hasEight = SourceVersion.valueOf("RELEASE_8") != null;
-                } catch(IllegalArgumentException iae) {
-                    hasEight = false;
-                }
-                if (hasEight) {
-                    return tc.call8();
-                } else {
-                    assert false : "Checker Framework needs a Java 8 or 9 javac.";
-                    return null;
-                }
-            }
-        } catch (Throwable t) {
-            assert false : "Checker Framework internal error: " + t;
-            t.printStackTrace();
-            return null;
-        }
-    }
-
     public static TypeAnnotationPosition unknownTAPosition() {
-        return call8or9(
-                new Call8or9<TypeAnnotationPosition>() {
-                    @Override
-                    public TypeAnnotationPosition call8() throws InstantiationException, IllegalAccessException {
-                        return TypeAnnotationPosition.class.newInstance();
-                    }
-                    @Override
-                    public TypeAnnotationPosition call9() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
-                        return (TypeAnnotationPosition) TypeAnnotationPosition.class
-                                .getField("unknown")
-                                .get(null);
-                    }
-                }
-            );
+        return new TypeAnnotationPosition();
     }
 
     public static TypeAnnotationPosition methodReturnTAPosition(final int pos) {
-        return call8or9(
-                new Call8or9<TypeAnnotationPosition>() {
-                    @Override
-                    public TypeAnnotationPosition call8() throws InstantiationException, IllegalAccessException, IllegalArgumentException, NoSuchFieldException, SecurityException {
-                        TypeAnnotationPosition tapos = TypeAnnotationPosition.class.newInstance();
-                        TypeAnnotationPosition.class.getField("type").set(tapos, TargetType.METHOD_RETURN);
-                        TypeAnnotationPosition.class.getField("pos").set(tapos, pos);
-                        return tapos;
-                    }
-                    @Override
-                    public TypeAnnotationPosition call9() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
-                        return (TypeAnnotationPosition) TypeAnnotationPosition.class
-                                .getMethod("methodReturn", int.class)
-                                .invoke(null, pos);
-                    }
-                }
-            );
+        TypeAnnotationPosition tapos = new TypeAnnotationPosition();
+        tapos.type = TargetType.METHOD_RETURN;
+        tapos.pos = pos;
+        return tapos;
     }
 
     public static TypeAnnotationPosition methodReceiverTAPosition(final int pos) {
-        return call8or9(
-                new Call8or9<TypeAnnotationPosition>() {
-                    @Override
-                    public TypeAnnotationPosition call8() throws InstantiationException, IllegalAccessException, IllegalArgumentException, NoSuchFieldException, SecurityException {
-                        TypeAnnotationPosition tapos = TypeAnnotationPosition.class.newInstance();
-                        TypeAnnotationPosition.class.getField("type").set(tapos, TargetType.METHOD_RECEIVER);
-                        TypeAnnotationPosition.class.getField("pos").set(tapos, pos);
-                        return tapos;
-                    }
-                    @Override
-                    public TypeAnnotationPosition call9() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
-                        return (TypeAnnotationPosition) TypeAnnotationPosition.class
-                                .getMethod("methodReceiver", int.class)
-                                .invoke(null, pos);
-                    }
-                }
-            );
+        TypeAnnotationPosition tapos = new TypeAnnotationPosition();
+        tapos.type = TargetType.METHOD_RECEIVER;
+        tapos.pos = pos;
+        return tapos;
     }
 
     public static TypeAnnotationPosition methodParameterTAPosition(final int pidx, final int pos) {
-        return call8or9(
-                new Call8or9<TypeAnnotationPosition>() {
-                    @Override
-                    public TypeAnnotationPosition call8() throws InstantiationException, IllegalAccessException, IllegalArgumentException, NoSuchFieldException, SecurityException {
-                        TypeAnnotationPosition tapos = TypeAnnotationPosition.class.newInstance();
-                        TypeAnnotationPosition.class.getField("type").set(tapos, TargetType.METHOD_FORMAL_PARAMETER);
-                        TypeAnnotationPosition.class.getField("parameter_index").set(tapos, pidx);
-                        TypeAnnotationPosition.class.getField("pos").set(tapos, pos);
-                        return tapos;
-                    }
-                    @Override
-                    public TypeAnnotationPosition call9() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
-                        return (TypeAnnotationPosition) TypeAnnotationPosition.class
-                                .getMethod("methodParameter", int.class, int.class)
-                                .invoke(null, pidx, pos);
-                    }
-                }
-            );
+        TypeAnnotationPosition tapos = new TypeAnnotationPosition();
+        tapos.type = TargetType.METHOD_FORMAL_PARAMETER;
+        tapos.parameter_index = pidx;
+        tapos.pos = pos;
+        return tapos;
     }
 
     public static TypeAnnotationPosition methodThrowsTAPosition(final int tidx, final int pos) {
-        return call8or9(
-                new Call8or9<TypeAnnotationPosition>() {
-                    @Override
-                    public TypeAnnotationPosition call8() throws InstantiationException, IllegalAccessException, IllegalArgumentException, NoSuchFieldException, SecurityException {
-                        TypeAnnotationPosition tapos = TypeAnnotationPosition.class.newInstance();
-                        TypeAnnotationPosition.class.getField("type").set(tapos, TargetType.THROWS);
-                        TypeAnnotationPosition.class.getField("type_index").set(tapos, tidx);
-                        TypeAnnotationPosition.class.getField("pos").set(tapos, pos);
-                        return tapos;
-                    }
-                    @Override
-                    public TypeAnnotationPosition call9() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, NoSuchFieldException {
-                        return (TypeAnnotationPosition) TypeAnnotationPosition.class
-                                .getMethod("methodThrows", List.class, JCLambda.class, int.class, int.class)
-                                .invoke(null, TypeAnnotationPosition.class.getField("emptyPath").get(null), null, tidx, pos);
-                    }
-                }
-            );
+        TypeAnnotationPosition tapos = new TypeAnnotationPosition();
+        tapos.type = TargetType.THROWS;
+        tapos.type_index = tidx;
+        tapos.pos = pos;
+        return tapos;
     }
 
     public static TypeAnnotationPosition fieldTAPosition(final int pos) {
-        return call8or9(
-                new Call8or9<TypeAnnotationPosition>() {
-                    @Override
-                    public TypeAnnotationPosition call8() throws InstantiationException, IllegalAccessException, IllegalArgumentException, NoSuchFieldException, SecurityException {
-                        TypeAnnotationPosition tapos = TypeAnnotationPosition.class.newInstance();
-                        TypeAnnotationPosition.class.getField("type").set(tapos, TargetType.FIELD);
-                        TypeAnnotationPosition.class.getField("pos").set(tapos, pos);
-                        return tapos;
-                    }
-                    @Override
-                    public TypeAnnotationPosition call9() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
-                        return (TypeAnnotationPosition) TypeAnnotationPosition.class
-                                .getMethod("field", int.class)
-                                .invoke(null, pos);
-                    }
-                }
-            );
+        TypeAnnotationPosition tapos = new TypeAnnotationPosition();
+        tapos.type = TargetType.FIELD;
+        tapos.pos = pos;
+        return tapos;
     }
 
     public static TypeAnnotationPosition classExtendsTAPosition(final int implidx, final int pos) {
-        return call8or9(
-                new Call8or9<TypeAnnotationPosition>() {
-                    @Override
-                    public TypeAnnotationPosition call8() throws InstantiationException, IllegalAccessException, IllegalArgumentException, NoSuchFieldException, SecurityException {
-                        TypeAnnotationPosition tapos = TypeAnnotationPosition.class.newInstance();
-                        TypeAnnotationPosition.class.getField("type").set(tapos, TargetType.CLASS_EXTENDS);
-                        TypeAnnotationPosition.class.getField("type_index").set(tapos, implidx);
-                        TypeAnnotationPosition.class.getField("pos").set(tapos, pos);
-                        return tapos;
-                    }
-                    @Override
-                    public TypeAnnotationPosition call9() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
-                        return (TypeAnnotationPosition) TypeAnnotationPosition.class
-                                .getMethod("classExtends", int.class, int.class)
-                                .invoke(null, implidx, pos);
-                    }
-                }
-            );
+        TypeAnnotationPosition tapos = new TypeAnnotationPosition();
+        tapos.type = TargetType.CLASS_EXTENDS;
+        tapos.type_index = implidx;
+        tapos.pos = pos;
+        return tapos;
     }
 
     public static TypeAnnotationPosition typeParameterTAPosition(final int tpidx, final int pos) {
-        return call8or9(
-                new Call8or9<TypeAnnotationPosition>() {
-                    @Override
-                    public TypeAnnotationPosition call8() throws InstantiationException, IllegalAccessException, IllegalArgumentException, NoSuchFieldException, SecurityException {
-                        TypeAnnotationPosition tapos = TypeAnnotationPosition.class.newInstance();
-                        TypeAnnotationPosition.class.getField("type").set(tapos, TargetType.CLASS_TYPE_PARAMETER);
-                        TypeAnnotationPosition.class.getField("parameter_index").set(tapos, tpidx);
-                        TypeAnnotationPosition.class.getField("pos").set(tapos, pos);
-                        return tapos;
-                    }
-                    @Override
-                    public TypeAnnotationPosition call9() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, NoSuchFieldException {
-                        return (TypeAnnotationPosition) TypeAnnotationPosition.class
-                                .getMethod("typeParameter", List.class, JCLambda.class, int.class, int.class)
-                                .invoke(null, TypeAnnotationPosition.class.getField("emptyPath").get(null), null, tpidx, pos);
-                    }
-                }
-            );
+        TypeAnnotationPosition tapos = new TypeAnnotationPosition();
+        tapos.type = TargetType.CLASS_TYPE_PARAMETER;
+        tapos.parameter_index = tpidx;
+        tapos.pos = pos;
+        return tapos;
     }
 
-    public static TypeAnnotationPosition methodTypeParameterTAPosition(final int tpidx, final int pos) {
-        return call8or9(
-                new Call8or9<TypeAnnotationPosition>() {
-                    @Override
-                    public TypeAnnotationPosition call8() throws InstantiationException, IllegalAccessException, IllegalArgumentException, NoSuchFieldException, SecurityException {
-                        TypeAnnotationPosition tapos = TypeAnnotationPosition.class.newInstance();
-                        TypeAnnotationPosition.class.getField("type").set(tapos, TargetType.METHOD_TYPE_PARAMETER);
-                        TypeAnnotationPosition.class.getField("parameter_index").set(tapos, tpidx);
-                        TypeAnnotationPosition.class.getField("pos").set(tapos, pos);
-                        return tapos;
-                    }
-                    @Override
-                    public TypeAnnotationPosition call9() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, NoSuchFieldException {
-                        return (TypeAnnotationPosition) TypeAnnotationPosition.class
-                                .getMethod("methodTypeParameter", List.class, JCLambda.class, int.class, int.class)
-                                .invoke(null, TypeAnnotationPosition.class.getField("emptyPath").get(null), null, tpidx, pos);
-                    }
-                }
-            );
+    public static TypeAnnotationPosition methodTypeParameterTAPosition(
+            final int tpidx, final int pos) {
+        TypeAnnotationPosition tapos = new TypeAnnotationPosition();
+        tapos.type = TargetType.METHOD_TYPE_PARAMETER;
+        tapos.parameter_index = tpidx;
+        tapos.pos = pos;
+        return tapos;
     }
 
-    public static TypeAnnotationPosition typeParameterBoundTAPosition(final int tpidx, final int bndidx, final int pos) {
-        return call8or9(
-                new Call8or9<TypeAnnotationPosition>() {
-                    @Override
-                    public TypeAnnotationPosition call8() throws InstantiationException, IllegalAccessException, IllegalArgumentException, NoSuchFieldException, SecurityException {
-                        TypeAnnotationPosition tapos = TypeAnnotationPosition.class.newInstance();
-                        TypeAnnotationPosition.class.getField("type").set(tapos, TargetType.CLASS_TYPE_PARAMETER_BOUND);
-                        TypeAnnotationPosition.class.getField("parameter_index").set(tapos, tpidx);
-                        TypeAnnotationPosition.class.getField("bound_index").set(tapos, bndidx);
-                        TypeAnnotationPosition.class.getField("pos").set(tapos, pos);
-                        return tapos;
-                    }
-                    @Override
-                    public TypeAnnotationPosition call9() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, NoSuchFieldException {
-                        return (TypeAnnotationPosition) TypeAnnotationPosition.class
-                                .getMethod("typeParameterBound", List.class, JCLambda.class, int.class, int.class, int.class)
-                                .invoke(null, TypeAnnotationPosition.class.getField("emptyPath").get(null), null, tpidx, bndidx, pos);
-                    }
-                }
-            );
+    public static TypeAnnotationPosition typeParameterBoundTAPosition(
+            final int tpidx, final int bndidx, final int pos) {
+        TypeAnnotationPosition tapos = new TypeAnnotationPosition();
+        tapos.type = TargetType.CLASS_TYPE_PARAMETER_BOUND;
+        tapos.parameter_index = tpidx;
+        tapos.bound_index = bndidx;
+        tapos.pos = pos;
+        return tapos;
     }
 
-    public static TypeAnnotationPosition methodTypeParameterBoundTAPosition(final int tpidx, final int bndidx, final int pos) {
-        return call8or9(
-                new Call8or9<TypeAnnotationPosition>() {
-                    @Override
-                    public TypeAnnotationPosition call8() throws InstantiationException, IllegalAccessException, IllegalArgumentException, NoSuchFieldException, SecurityException {
-                        TypeAnnotationPosition tapos = TypeAnnotationPosition.class.newInstance();
-                        TypeAnnotationPosition.class.getField("type").set(tapos, TargetType.METHOD_TYPE_PARAMETER_BOUND);
-                        TypeAnnotationPosition.class.getField("parameter_index").set(tapos, tpidx);
-                        TypeAnnotationPosition.class.getField("bound_index").set(tapos, bndidx);
-                        TypeAnnotationPosition.class.getField("pos").set(tapos, pos);
-                        return tapos;
-                    }
-                    @Override
-                    public TypeAnnotationPosition call9() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, NoSuchFieldException {
-                        return (TypeAnnotationPosition) TypeAnnotationPosition.class
-                                .getMethod("methodTypeParameterBound", List.class, JCLambda.class, int.class, int.class, int.class)
-                                .invoke(null, TypeAnnotationPosition.class.getField("emptyPath").get(null), null, tpidx, bndidx, pos);
-                    }
-                }
-            );
+    public static TypeAnnotationPosition methodTypeParameterBoundTAPosition(
+            final int tpidx, final int bndidx, final int pos) {
+        TypeAnnotationPosition tapos = new TypeAnnotationPosition();
+        tapos.type = TargetType.METHOD_TYPE_PARAMETER_BOUND;
+        tapos.parameter_index = tpidx;
+        tapos.bound_index = bndidx;
+        tapos.pos = pos;
+        return tapos;
     }
 
     public static TypeAnnotationPosition copyTAPosition(final TypeAnnotationPosition tapos) {
-        return call8or9(
-                new Call8or9<TypeAnnotationPosition>() {
-                    @Override
-                    public TypeAnnotationPosition call8() throws InstantiationException, IllegalAccessException, IllegalArgumentException, NoSuchFieldException, SecurityException {
-                        return copyTAPosition8(tapos);
-                    }
-                    @Override
-                    public TypeAnnotationPosition call9() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException, InvocationTargetException, NoSuchMethodException {
-                        return (TypeAnnotationPosition) TypeAnnotationPosition.class
-                                .getMethod("copy", TypeAnnotationPosition.class)
-                                .invoke(null, tapos);
-                    }
-                }
-            );
-    }
-
-    private static TypeAnnotationPosition copyTAPosition8(TypeAnnotationPosition tapos) throws InstantiationException, IllegalAccessException, IllegalArgumentException, NoSuchFieldException, SecurityException {
-        TypeAnnotationPosition res = TypeAnnotationPosition.class.newInstance();
+        TypeAnnotationPosition res = new TypeAnnotationPosition();
         res.isValidOffset = tapos.isValidOffset;
-        TypeAnnotationPosition.class.getField("bound_index").set(res, tapos.bound_index);
+        res.bound_index = tapos.bound_index;
         res.exception_index = tapos.exception_index;
         res.location = List.from(tapos.location);
-        if (tapos.lvarIndex != null)
+        if (tapos.lvarIndex != null) {
             res.lvarIndex = Arrays.copyOf(tapos.lvarIndex, tapos.lvarIndex.length);
-        if (tapos.lvarLength != null)
+        }
+        if (tapos.lvarLength != null) {
             res.lvarLength = Arrays.copyOf(tapos.lvarLength, tapos.lvarLength.length);
-        if (tapos.lvarOffset != null)
+        }
+        if (tapos.lvarOffset != null) {
             res.lvarOffset = Arrays.copyOf(tapos.lvarOffset, tapos.lvarOffset.length);
+        }
         res.offset = tapos.offset;
-        TypeAnnotationPosition.class.getField("onLambda").set(res, tapos.onLambda);
-        TypeAnnotationPosition.class.getField("parameter_index").set(res, tapos.parameter_index);
-        TypeAnnotationPosition.class.getField("pos").set(res, tapos.pos);
-        TypeAnnotationPosition.class.getField("type").set(res, tapos.type);
-        TypeAnnotationPosition.class.getField("type_index").set(res, tapos.type_index);
+        res.onLambda = tapos.onLambda;
+        res.parameter_index = tapos.parameter_index;
+        res.pos = tapos.pos;
+        res.type = tapos.type;
+        res.type_index = tapos.type_index;
         return res;
     }
 
-    public static Type unannotatedType(final Type in) {
-    	return call8or9(
-                new Call8or9<Type>() {
-                    @Override
-                    public Type call8() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
-                        return (Type) Type.class
-                                .getMethod("unannotatedType")
-                                .invoke(in);
-                    }
-                    @Override
-                    public Type call9() {
-                        return in;
-                    }
-                }
-            );
+    public static Type unannotatedType(final TypeMirror in) {
+        final Type impl = (Type) in;
+        return impl.unannotatedType();
     }
-
-}
\ No newline at end of file
+}
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypesUtils.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypesUtils.java
index f024a60..fe7456f 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypesUtils.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/TypesUtils.java
@@ -1,8 +1,19 @@
 package org.checkerframework.javacutil;
 
+import static com.sun.tools.javac.code.TypeTag.WILDCARD;
+
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.TypeTag;
+import com.sun.tools.javac.model.JavacTypes;
+import com.sun.tools.javac.processing.JavacProcessingEnvironment;
+import com.sun.tools.javac.util.Context;
 import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
 import javax.lang.model.element.Name;
+import javax.lang.model.element.NestingKind;
 import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.TypeParameterElement;
 import javax.lang.model.type.ArrayType;
 import javax.lang.model.type.DeclaredType;
 import javax.lang.model.type.TypeKind;
@@ -12,26 +23,18 @@
 import javax.lang.model.util.Elements;
 import javax.lang.model.util.Types;
 
-import com.sun.tools.javac.code.Symtab;
-import com.sun.tools.javac.code.Type;
-import com.sun.tools.javac.code.TypeTag;
-import com.sun.tools.javac.model.JavacTypes;
-import com.sun.tools.javac.processing.JavacProcessingEnvironment;
-import com.sun.tools.javac.util.Context;
-
-/**
- * A utility class that helps with {@link TypeMirror}s.
- *
- */
+/** A utility class that helps with {@link TypeMirror}s. */
 // TODO: This class needs significant restructuring
 public final class TypesUtils {
 
     // Class cannot be instantiated
-    private TypesUtils() { throw new AssertionError("Class TypesUtils cannot be instantiated."); }
+    private TypesUtils() {
+        throw new AssertionError("Class TypesUtils cannot be instantiated.");
+    }
 
     /**
-     * Gets the fully qualified name for a provided type.  It returns an empty
-     * name if type is an anonymous type.
+     * Gets the fully qualified name for a provided type. It returns an empty name if type is an
+     * anonymous type.
      *
      * @param type the declared type
      * @return the name corresponding to that type
@@ -44,7 +47,7 @@
     /**
      * Checks if the type represents a java.lang.Object declared type.
      *
-     * @param type  the type
+     * @param type the type
      * @return true iff type represents java.lang.Object
      */
     public static boolean isObject(TypeMirror type) {
@@ -54,7 +57,7 @@
     /**
      * Checks if the type represents a java.lang.Class declared type.
      *
-     * @param type  the type
+     * @param type the type
      * @return true iff type represents java.lang.Class
      */
     public static boolean isClass(TypeMirror type) {
@@ -62,11 +65,11 @@
     }
 
     /**
-     * Checks if the type represents a java.lang.String declared type.
-     * TODO: it would be cleaner to use String.class.getCanonicalName(), but
-     *   the two existing methods above don't do that, I guess for performance reasons.
+     * Checks if the type represents a java.lang.String declared type. TODO: it would be cleaner to
+     * use String.class.getCanonicalName(), but the two existing methods above don't do that, I
+     * guess for performance reasons.
      *
-     * @param type  the type
+     * @param type the type
      * @return true iff type represents java.lang.String
      */
     public static boolean isString(TypeMirror type) {
@@ -74,8 +77,8 @@
     }
 
     /**
-     * Checks if the type represents a boolean type, that is either boolean
-     * (primitive type) or java.lang.Boolean.
+     * Checks if the type represents a boolean type, that is either boolean (primitive type) or
+     * java.lang.Boolean.
      *
      * @param type the type to test
      * @return true iff type represents a boolean type
@@ -93,14 +96,15 @@
      */
     public static boolean isDeclaredOfName(TypeMirror type, CharSequence qualifiedName) {
         return type.getKind() == TypeKind.DECLARED
-            && getQualifiedName((DeclaredType)type).contentEquals(qualifiedName);
+                && getQualifiedName((DeclaredType) type).contentEquals(qualifiedName);
     }
 
     public static boolean isBoxedPrimitive(TypeMirror type) {
-        if (type.getKind() != TypeKind.DECLARED)
+        if (type.getKind() != TypeKind.DECLARED) {
             return false;
+        }
 
-        String qualifiedName = getQualifiedName((DeclaredType)type).toString();
+        String qualifiedName = getQualifiedName((DeclaredType) type).toString();
 
         return (qualifiedName.equals("java.lang.Boolean")
                 || qualifiedName.equals("java.lang.Byte")
@@ -112,44 +116,57 @@
                 || qualifiedName.equals("java.lang.Float"));
     }
 
-    /** @return type represents a Throwable type (e.g. Exception, Error) **/
+    /** @return type represents a Throwable type (e.g. Exception, Error) */
     public static boolean isThrowable(TypeMirror type) {
         while (type != null && type.getKind() == TypeKind.DECLARED) {
             DeclaredType dt = (DeclaredType) type;
             TypeElement elem = (TypeElement) dt.asElement();
             Name name = elem.getQualifiedName();
-            if ("java.lang.Throwable".contentEquals(name))
+            if ("java.lang.Throwable".contentEquals(name)) {
                 return true;
+            }
             type = elem.getSuperclass();
         }
         return false;
     }
 
     /**
+     * Returns true iff the argument is an anonymous type.
+     *
+     * @return whether the argument is an anonymous type
+     */
+    public static boolean isAnonymous(TypeMirror type) {
+        return (type instanceof DeclaredType)
+                && (((TypeElement) ((DeclaredType) type).asElement())
+                        .getNestingKind()
+                        .equals(NestingKind.ANONYMOUS));
+    }
+
+    /**
      * Returns true iff the argument is a primitive type.
      *
-     * @return  whether the argument is a primitive type
+     * @return whether the argument is a primitive type
      */
     public static boolean isPrimitive(TypeMirror type) {
         switch (type.getKind()) {
-        case BOOLEAN:
-        case BYTE:
-        case CHAR:
-        case DOUBLE:
-        case FLOAT:
-        case INT:
-        case LONG:
-        case SHORT:
-            return true;
-        default:
-            return false;
+            case BOOLEAN:
+            case BYTE:
+            case CHAR:
+            case DOUBLE:
+            case FLOAT:
+            case INT:
+            case LONG:
+            case SHORT:
+                return true;
+            default:
+                return false;
         }
     }
 
     /**
      * Returns true iff the arguments are both the same primitive types.
      *
-     * @return  whether the arguments are the same primitive types
+     * @return whether the arguments are the same primitive types
      */
     public static boolean areSamePrimitiveTypes(TypeMirror left, TypeMirror right) {
         if (!isPrimitive(left) || !isPrimitive(right)) {
@@ -162,65 +179,64 @@
     /**
      * Returns true iff the argument is a primitive numeric type.
      *
-     * @return  whether the argument is a primitive numeric type
+     * @return whether the argument is a primitive numeric type
      */
     public static boolean isNumeric(TypeMirror type) {
         switch (type.getKind()) {
-        case BYTE:
-        case CHAR:
-        case DOUBLE:
-        case FLOAT:
-        case INT:
-        case LONG:
-        case SHORT:
-            return true;
-        default:
-            return false;
+            case BYTE:
+            case CHAR:
+            case DOUBLE:
+            case FLOAT:
+            case INT:
+            case LONG:
+            case SHORT:
+                return true;
+            default:
+                return false;
         }
     }
 
     /**
      * Returns true iff the argument is an integral type.
      *
-     * @return  whether the argument is an integral type
+     * @return whether the argument is an integral type
      */
     public static boolean isIntegral(TypeMirror type) {
         switch (type.getKind()) {
-        case BYTE:
-        case CHAR:
-        case INT:
-        case LONG:
-        case SHORT:
-            return true;
-        default:
-            return false;
+            case BYTE:
+            case CHAR:
+            case INT:
+            case LONG:
+            case SHORT:
+                return true;
+            default:
+                return false;
         }
     }
 
     /**
      * Returns true iff the argument is a floating point type.
      *
-     * @return  whether the argument is a floating point type
+     * @return whether the argument is a floating point type
      */
     public static boolean isFloating(TypeMirror type) {
         switch (type.getKind()) {
-        case DOUBLE:
-        case FLOAT:
-            return true;
-        default:
-            return false;
+            case DOUBLE:
+            case FLOAT:
+                return true;
+            default:
+                return false;
         }
     }
 
     /**
-     * Returns the widened numeric type for an arithmetic operation
-     * performed on a value of the left type and the right type.
-     * Defined in JLS 5.6.2.  We return a {@link TypeKind} because
-     * creating a {@link TypeMirror} requires a {@link Types} object
-     * from the {@link javax.annotation.processing.ProcessingEnvironment}.
+     * Returns the widened numeric type for an arithmetic operation performed on a value of the left
+     * type and the right type. Defined in JLS 5.6.2. We return a {@link TypeKind} because creating
+     * a {@link TypeMirror} requires a {@link Types} object from the {@link
+     * javax.annotation.processing.ProcessingEnvironment}.
      *
-     * @return  the result of widening numeric conversion, or NONE when
-     *          the conversion cannot be performed
+     * @return the result of widening numeric conversion, or NONE when the conversion cannot be
+     *     performed
      */
     public static TypeKind widenedNumericType(TypeMirror left, TypeMirror right) {
         if (!isNumeric(left) || !isNumeric(right)) {
@@ -246,13 +262,12 @@
     }
 
     /**
-     * If the argument is a bounded TypeVariable or WildcardType,
-     * return its non-variable, non-wildcard upper bound.  Otherwise,
-     * return the type itself.
+     * If the argument is a bounded TypeVariable or WildcardType, return its non-variable,
+     * non-wildcard upper bound. Otherwise, return the type itself.
      *
-     * @param type  a type
-     * @return  the non-variable, non-wildcard upper bound of a type,
-     *    if it has one, or itself if it has no bounds
+     * @param type a type
+     * @return the non-variable, non-wildcard upper bound of a type, if it has one, or itself if it
+     *     has no bounds
      */
     public static TypeMirror upperBound(TypeMirror type) {
         do {
@@ -277,8 +292,28 @@
         return type;
     }
 
-    // Version of com.sun.tools.javac.code.Types.wildUpperBound(Type)
-    // that works with both jdk8 (called upperBound there) and jdk8u.
+    /**
+     * Get the type parameter for this wildcard from the underlying type's bound field This field is
+     * sometimes null, in that case this method will return null
+     *
+     * @return the TypeParameterElement the wildcard is an argument to
+     */
+    public static TypeParameterElement wildcardToTypeParam(final Type.WildcardType wildcard) {
+
+        final Element typeParamElement;
+        if (wildcard.bound != null) {
+            typeParamElement = wildcard.bound.asElement();
+        } else {
+            typeParamElement = null;
+        }
+
+        return (TypeParameterElement) typeParamElement;
+    }
+
+    /**
+     * Version of com.sun.tools.javac.code.Types.wildUpperBound(Type) that works with both jdk8
+     * (called upperBound there) and jdk8u.
+     */
     // TODO: contrast to upperBound.
     public static Type wildUpperBound(ProcessingEnvironment env, TypeMirror tm) {
         Type t = (Type) tm;
@@ -291,15 +326,27 @@
             } else {
                 return wildUpperBound(env, w.type);
             }
-        }
-        else {
+        } else {
             return TypeAnnotationUtils.unannotatedType(t);
         }
     }
 
     /**
-     * Returns the {@link TypeMirror} for a given {@link Class}.
+     * Version of com.sun.tools.javac.code.Types.wildLowerBound(Type) that works with both jdk8
+     * (called upperBound there) and jdk8u.
      */
+    public static Type wildLowerBound(ProcessingEnvironment env, TypeMirror tm) {
+        Type t = (Type) tm;
+        if (t.hasTag(WILDCARD)) {
+            Context context = ((JavacProcessingEnvironment) env).getContext();
+            Symtab syms = Symtab.instance(context);
+            Type.WildcardType w = (Type.WildcardType) TypeAnnotationUtils.unannotatedType(t);
+            return w.isExtendsBound() ? syms.botType : wildLowerBound(env, w.type);
+        } else {
+            return TypeAnnotationUtils.unannotatedType(t);
+        }
+    }
+    /** Returns the {@link TypeMirror} for a given {@link Class}. */
     public static TypeMirror typeFromClass(Types types, Elements elements, Class<?> clazz) {
         if (clazz == void.class) {
             return types.getNoType(TypeKind.VOID);
@@ -320,11 +367,86 @@
         }
     }
 
-    /**
-     * Returns an {@link ArrayType} with elements of type {@code componentType}.
-     */
+    /** Returns an {@link ArrayType} with elements of type {@code componentType}. */
     public static ArrayType createArrayType(Types types, TypeMirror componentType) {
         JavacTypes t = (JavacTypes) types;
         return t.getArrayType(componentType);
     }
+
+    /**
+     * Returns true if declaredType is a Class that is used to box primitive type (e.g.
+     * declaredType=java.lang.Double and primitiveType=22.5d )
+     */
+    public static boolean isBoxOf(TypeMirror declaredType, TypeMirror primitiveType) {
+        if (declaredType.getKind() != TypeKind.DECLARED) {
+            return false;
+        }
+
+        final String qualifiedName = getQualifiedName((DeclaredType) declaredType).toString();
+        switch (primitiveType.getKind()) {
+            case BOOLEAN:
+                return qualifiedName.equals("java.lang.Boolean");
+            case BYTE:
+                return qualifiedName.equals("java.lang.Byte");
+            case CHAR:
+                return qualifiedName.equals("java.lang.Character");
+            case DOUBLE:
+                return qualifiedName.equals("java.lang.Double");
+            case FLOAT:
+                return qualifiedName.equals("java.lang.Float");
+            case INT:
+                return qualifiedName.equals("java.lang.Integer");
+            case LONG:
+                return qualifiedName.equals("java.lang.Long");
+            case SHORT:
+                return qualifiedName.equals("java.lang.Short");
+
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Given a bounded type (wildcard or typevar) get the concrete type of its upper bound. If the
+     * bounded type extends other bounded types, this method will iterate through their bounds until
+     * a class, interface, or intersection is found.
+     *
+     * @return a type that is not a wildcard or typevar, or null if this type is an unbounded
+     *     wildcard
+     */
+    public static TypeMirror findConcreteUpperBound(final TypeMirror boundedType) {
+        TypeMirror effectiveUpper = boundedType;
+        outerLoop:
+        while (true) {
+            switch (effectiveUpper.getKind()) {
+                case WILDCARD:
+                    effectiveUpper =
+                            ((javax.lang.model.type.WildcardType) effectiveUpper).getExtendsBound();
+                    if (effectiveUpper == null) {
+                        return null;
+                    }
+                    break;
+
+                case TYPEVAR:
+                    effectiveUpper = ((TypeVariable) effectiveUpper).getUpperBound();
+                    break;
+
+                default:
+                    break outerLoop;
+            }
+        }
+        return effectiveUpper;
+    }
+
+    /**
+     * Returns true if the erased type of subtype is a subtype of the erased type of supertype.
+     *
+     * @param types Types
+     * @param subtype possible subtype
+     * @param supertype possible supertype
+     * @return true if the erased type of subtype is a subtype of the erased type of supertype
+     */
+    public static boolean isErasedSubtype(Types types, TypeMirror subtype, TypeMirror supertype) {
+        return types.isSubtype(types.erasure(subtype), types.erasure(supertype));
+    }
 }
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/dist/ManualTaglet.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/dist/ManualTaglet.java
index ade653e..01f3548 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/dist/ManualTaglet.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/dist/ManualTaglet.java
@@ -1,22 +1,20 @@
 package org.checkerframework.javacutil.dist;
 
-import java.util.Map;
-
 import com.sun.javadoc.Tag;
 import com.sun.tools.doclets.Taglet;
+import java.util.Map;
 
 /**
  * A taglet for processing the {@code @checker_framework.manual} javadoc block tag, which inserts
  * references to the Checker Framework manual into javadoc.
  *
- * <p>
- *
- * The {@code @checker_framework.manual} tag is used as follows:
+ * <p>The {@code @checker_framework.manual} tag is used as follows:
  *
  * <ul>
- * <li>{@code @checker_framework.manual #} expands to a top-level link to the Checker Framework manual
- * <li>{@code @checker_framework.manual #anchor text} expands to a link with some text to a
- * particular part of the manual
+ *   <li>{@code @checker_framework.manual #} expands to a top-level link to the Checker Framework
+ *       manual
+ *   <li>{@code @checker_framework.manual #anchor text} expands to a link with some text to a
+ *       particular part of the manual
  * </ul>
  */
 public class ManualTaglet implements Taglet {
@@ -65,8 +63,8 @@
      * Formats a link, given an array of tokens.
      *
      * @param parts the array of tokens
-     * @return a link to the manual top-level if the array size is one, or a
-     *         link to a part of the manual if it's larger than one
+     * @return a link to the manual top-level if the array size is one, or a link to a part of the
+     *     manual if it's larger than one
      */
     private String formatLink(String[] parts) {
         String anchor, text;
@@ -78,21 +76,18 @@
             text = parts[1];
         }
         return String.format(
-                "<A HREF=\"http://types.cs.washington.edu/checker-framework/current/checker-framework-manual.html%s\">%s</A>",
-                anchor, text);
+                "<A HREF=\"https://checkerframework.org/manual/%s\">%s</A>", anchor, text);
     }
 
     /**
-     * Formats the {@code @checker_framework.manual} tag, prepending the tag header to the
-     * tag content.
+     * Formats the {@code @checker_framework.manual} tag, prepending the tag header to the tag
+     * content.
      *
      * @param text the tag content
      * @return the formatted tag
      */
     private String formatHeader(String text) {
-        return String.format(
-                "<DT><B>See the Checker Framework Manual:</B><DD>%s<BR>",
-                text);
+        return String.format("<DT><B>See the Checker Framework Manual:</B><DD>%s<BR>", text);
     }
 
     @Override
@@ -103,19 +98,21 @@
 
     @Override
     public String toString(Tag[] tags) {
-        if (tags.length == 0)
+        if (tags.length == 0) {
             return "";
+        }
         StringBuilder sb = new StringBuilder();
         for (Tag t : tags) {
             String[] split = t.text().split(" ", 2);
-            if (t != tags[0])
+            if (t != tags[0]) {
                 sb.append(", ");
+            }
             sb.append(formatLink(split));
         }
         return formatHeader(sb.toString());
     }
 
-    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @SuppressWarnings({"unchecked", "rawtypes"})
     public static void register(Map tagletMap) {
         ManualTaglet tag = new ManualTaglet();
         Taglet t = (Taglet) tagletMap.get(tag.getName());
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/DetachedVarSymbol.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/DetachedVarSymbol.java
index 0edf394..43d79cc 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/DetachedVarSymbol.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/DetachedVarSymbol.java
@@ -10,35 +10,26 @@
 */
 
 /**
- * A DetachedVarSymbol represents a variable that is not part of any
- * AST Tree.  DetachedVarSymbols are created when desugaring source
- * code constructs and they carry important type information, but some
- * methods such as TreeInfo.declarationFor do not work on them.
+ * A DetachedVarSymbol represents a variable that is not part of any AST Tree. DetachedVarSymbols
+ * are created when desugaring source code constructs and they carry important type information, but
+ * some methods such as TreeInfo.declarationFor do not work on them.
  */
-
 public class DetachedVarSymbol extends Symbol.VarSymbol {
 
     protected /*@Nullable*/ VariableTree decl;
 
-    /**
-     * Construct a detached variable symbol, given its flags, name,
-     * type and owner.
-     */
+    /** Construct a detached variable symbol, given its flags, name, type and owner. */
     public DetachedVarSymbol(long flags, Name name, Type type, Symbol owner) {
         super(flags, name, type, owner);
         this.decl = null;
     }
 
-    /**
-     * Set the declaration tree for the variable.
-     */
+    /** Set the declaration tree for the variable. */
     public void setDeclaration(VariableTree decl) {
         this.decl = decl;
     }
 
-    /**
-     * Get the declaration tree for the variable.
-     */
+    /** Get the declaration tree for the variable. */
     public /*@Nullable*/ VariableTree getDeclaration() {
         return decl;
     }
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/TreeBuilder.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/TreeBuilder.java
index 2623f2f..eab005d 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/TreeBuilder.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/TreeBuilder.java
@@ -1,24 +1,5 @@
 package org.checkerframework.javacutil.trees;
 
-import java.util.List;
-
-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.TypeKind;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.ElementFilter;
-import javax.lang.model.util.Elements;
-import javax.lang.model.util.Types;
-
-import org.checkerframework.javacutil.InternalUtils;
-import org.checkerframework.javacutil.TypesUtils;
-
 import com.sun.source.tree.ArrayAccessTree;
 import com.sun.source.tree.AssignmentTree;
 import com.sun.source.tree.BinaryTree;
@@ -40,12 +21,27 @@
 import com.sun.tools.javac.tree.TreeMaker;
 import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.Names;
+import java.util.List;
+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.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import org.checkerframework.javacutil.InternalUtils;
+import org.checkerframework.javacutil.TypesUtils;
 
 /**
- * The TreeBuilder permits the creation of new AST Trees using the
- * non-public Java compiler API TreeMaker.
+ * The TreeBuilder permits the creation of new AST Trees using the non-public Java compiler API
+ * TreeMaker.
  */
-
 public class TreeBuilder {
     protected final Elements elements;
     protected final Types modelTypes;
@@ -57,7 +53,7 @@
 
     public TreeBuilder(ProcessingEnvironment env) {
         this.env = env;
-        Context context = ((JavacProcessingEnvironment)env).getContext();
+        Context context = ((JavacProcessingEnvironment) env).getContext();
         elements = env.getElementUtils();
         modelTypes = env.getTypeUtils();
         javacTypes = com.sun.tools.javac.code.Types.instance(context);
@@ -67,66 +63,63 @@
     }
 
     /**
-     * Builds an AST Tree to access the iterator() method of some iterable
-     * expression.
+     * Builds an AST Tree to access the iterator() method of some iterable expression.
      *
-     * @param iterableExpr  an expression whose type is a subtype of Iterable
-     * @return  a MemberSelectTree that accesses the iterator() method of
-     *    the expression
+     * @param iterableExpr an expression whose type is a subtype of Iterable
+     * @return a MemberSelectTree that accesses the iterator() method of the expression
      */
     public MemberSelectTree buildIteratorMethodAccess(ExpressionTree iterableExpr) {
         DeclaredType exprType =
-            (DeclaredType)TypesUtils.upperBound(InternalUtils.typeOf(iterableExpr));
+                (DeclaredType) TypesUtils.upperBound(InternalUtils.typeOf(iterableExpr));
         assert exprType != null : "expression must be of declared type Iterable<>";
 
-        TypeElement exprElement = (TypeElement)exprType.asElement();
+        TypeElement exprElement = (TypeElement) exprType.asElement();
 
         // Find the iterator() method of the iterable type
         Symbol.MethodSymbol iteratorMethod = null;
 
         for (ExecutableElement method :
-                 ElementFilter.methodsIn(elements.getAllMembers(exprElement))) {
+                ElementFilter.methodsIn(elements.getAllMembers(exprElement))) {
             Name methodName = method.getSimpleName();
 
             if (method.getParameters().size() == 0) {
                 if (methodName.contentEquals("iterator")) {
-                    iteratorMethod = (Symbol.MethodSymbol)method;
+                    iteratorMethod = (Symbol.MethodSymbol) method;
                 }
             }
         }
 
         assert iteratorMethod != null : "no iterator method declared for expression type";
 
-        Type.MethodType methodType = (Type.MethodType)iteratorMethod.asType();
+        Type.MethodType methodType = (Type.MethodType) iteratorMethod.asType();
         Symbol.TypeSymbol methodClass = methodType.asElement();
-        DeclaredType iteratorType = (DeclaredType)methodType.getReturnType();
+        DeclaredType iteratorType = (DeclaredType) methodType.getReturnType();
         TypeMirror elementType;
 
         if (iteratorType.getTypeArguments().size() > 0) {
             elementType = iteratorType.getTypeArguments().get(0);
             // Remove captured type from a wildcard.
             if (elementType instanceof Type.CapturedType) {
-                elementType = ((Type.CapturedType)elementType).wildcard;
+                elementType = ((Type.CapturedType) elementType).wildcard;
             }
 
             iteratorType =
-                modelTypes.getDeclaredType((TypeElement)modelTypes.asElement(iteratorType),
-                                      elementType);
+                    modelTypes.getDeclaredType(
+                            (TypeElement) modelTypes.asElement(iteratorType), elementType);
         }
 
-
         // Replace the iterator method's generic return type with
         // the actual element type of the expression.
         Type.MethodType updatedMethodType =
-            new Type.MethodType(com.sun.tools.javac.util.List.<Type>nil(),
-                                (Type)iteratorType,
-                                com.sun.tools.javac.util.List.<Type>nil(),
-                                methodClass);
+                new Type.MethodType(
+                        com.sun.tools.javac.util.List.<Type>nil(),
+                        (Type) iteratorType,
+                        com.sun.tools.javac.util.List.<Type>nil(),
+                        methodClass);
 
         JCTree.JCFieldAccess iteratorAccess =
-            (JCTree.JCFieldAccess)
-            maker.Select((JCTree.JCExpression)iterableExpr,
-                         iteratorMethod);
+                (JCTree.JCFieldAccess)
+                        maker.Select((JCTree.JCExpression) iterableExpr, iteratorMethod);
         iteratorAccess.setType(updatedMethodType);
 
         return iteratorAccess;
@@ -135,26 +128,25 @@
     /**
      * Builds an AST Tree to access the hasNext() method of an iterator.
      *
-     * @param iteratorExpr  an expression whose type is a subtype of Iterator
-     * @return  a MemberSelectTree that accesses the hasNext() method of
-     *    the expression
+     * @param iteratorExpr an expression whose type is a subtype of Iterator
+     * @return a MemberSelectTree that accesses the hasNext() method of the expression
      */
     public MemberSelectTree buildHasNextMethodAccess(ExpressionTree iteratorExpr) {
-        DeclaredType exprType = (DeclaredType)InternalUtils.typeOf(iteratorExpr);
+        DeclaredType exprType = (DeclaredType) InternalUtils.typeOf(iteratorExpr);
         assert exprType != null : "expression must be of declared type Iterator<>";
 
-        TypeElement exprElement = (TypeElement)exprType.asElement();
+        TypeElement exprElement = (TypeElement) exprType.asElement();
 
         // Find the hasNext() method of the iterator type
         Symbol.MethodSymbol hasNextMethod = null;
 
         for (ExecutableElement method :
-                 ElementFilter.methodsIn(elements.getAllMembers(exprElement))) {
+                ElementFilter.methodsIn(elements.getAllMembers(exprElement))) {
             Name methodName = method.getSimpleName();
 
             if (method.getParameters().size() == 0) {
                 if (methodName.contentEquals("hasNext")) {
-                    hasNextMethod = (Symbol.MethodSymbol)method;
+                    hasNextMethod = (Symbol.MethodSymbol) method;
                 }
             }
         }
@@ -162,9 +154,8 @@
         assert hasNextMethod != null : "no hasNext method declared for expression type";
 
         JCTree.JCFieldAccess hasNextAccess =
-            (JCTree.JCFieldAccess)
-            maker.Select((JCTree.JCExpression)iteratorExpr,
-                         hasNextMethod);
+                (JCTree.JCFieldAccess)
+                        maker.Select((JCTree.JCExpression) iteratorExpr, hasNextMethod);
         hasNextAccess.setType(hasNextMethod.asType());
 
         return hasNextAccess;
@@ -173,38 +164,37 @@
     /**
      * Builds an AST Tree to access the next() method of an iterator.
      *
-     * @param iteratorExpr  an expression whose type is a subtype of Iterator
-     * @return  a MemberSelectTree that accesses the next() method of
-     *    the expression
+     * @param iteratorExpr an expression whose type is a subtype of Iterator
+     * @return a MemberSelectTree that accesses the next() method of the expression
      */
     public MemberSelectTree buildNextMethodAccess(ExpressionTree iteratorExpr) {
-        DeclaredType exprType = (DeclaredType)InternalUtils.typeOf(iteratorExpr);
+        DeclaredType exprType = (DeclaredType) InternalUtils.typeOf(iteratorExpr);
         assert exprType != null : "expression must be of declared type Iterator<>";
 
-        TypeElement exprElement = (TypeElement)exprType.asElement();
+        TypeElement exprElement = (TypeElement) exprType.asElement();
 
         // Find the next() method of the iterator type
         Symbol.MethodSymbol nextMethod = null;
 
         for (ExecutableElement method :
-                 ElementFilter.methodsIn(elements.getAllMembers(exprElement))) {
+                ElementFilter.methodsIn(elements.getAllMembers(exprElement))) {
             Name methodName = method.getSimpleName();
 
             if (method.getParameters().size() == 0) {
                 if (methodName.contentEquals("next")) {
-                    nextMethod = (Symbol.MethodSymbol)method;
+                    nextMethod = (Symbol.MethodSymbol) method;
                 }
             }
         }
 
         assert nextMethod != null : "no next method declared for expression type";
 
-        Type.MethodType methodType = (Type.MethodType)nextMethod.asType();
+        Type.MethodType methodType = (Type.MethodType) nextMethod.asType();
         Symbol.TypeSymbol methodClass = methodType.asElement();
         Type elementType;
 
         if (exprType.getTypeArguments().size() > 0) {
-            elementType = (Type)exprType.getTypeArguments().get(0);
+            elementType = (Type) exprType.getTypeArguments().get(0);
         } else {
             elementType = symtab.objectType;
         }
@@ -212,15 +202,14 @@
         // Replace the next method's generic return type with
         // the actual element type of the expression.
         Type.MethodType updatedMethodType =
-            new Type.MethodType(com.sun.tools.javac.util.List.<Type>nil(),
-                                elementType,
-                                com.sun.tools.javac.util.List.<Type>nil(),
-                                methodClass);
+                new Type.MethodType(
+                        com.sun.tools.javac.util.List.<Type>nil(),
+                        elementType,
+                        com.sun.tools.javac.util.List.<Type>nil(),
+                        methodClass);
 
         JCTree.JCFieldAccess nextAccess =
-            (JCTree.JCFieldAccess)
-            maker.Select((JCTree.JCExpression)iteratorExpr,
-                         nextMethod);
+                (JCTree.JCFieldAccess) maker.Select((JCTree.JCExpression) iteratorExpr, nextMethod);
         nextAccess.setType(updatedMethodType);
 
         return nextAccess;
@@ -229,82 +218,80 @@
     /**
      * Builds an AST Tree to dereference the length field of an array
      *
-     * @param expression  the array expression whose length is being accessed
-     * @return  a MemberSelectTree to dereference the length of the array
+     * @param expression the array expression whose length is being accessed
+     * @return a MemberSelectTree to dereference the length of the array
      */
     public MemberSelectTree buildArrayLengthAccess(ExpressionTree expression) {
 
         return (JCTree.JCFieldAccess)
-            maker.Select((JCTree.JCExpression)expression, symtab.lengthVar);
+                maker.Select((JCTree.JCExpression) expression, symtab.lengthVar);
     }
 
     /**
      * Builds an AST Tree to call a method designated by the argument expression.
      *
-     * @param methodExpr  an expression denoting a method with no arguments
-     * @return  a MethodInvocationTree to call the argument method
+     * @param methodExpr an expression denoting a method with no arguments
+     * @return a MethodInvocationTree to call the argument method
      */
     public MethodInvocationTree buildMethodInvocation(ExpressionTree methodExpr) {
-        return maker.App((JCTree.JCExpression)methodExpr);
+        return maker.App((JCTree.JCExpression) methodExpr);
     }
 
     /**
-     * Builds an AST Tree to call a method designated by methodExpr,
-     * with one argument designated by argExpr.
+     * Builds an AST Tree to call a method designated by methodExpr, with one argument designated by
+     * argExpr.
      *
-     * @param methodExpr  an expression denoting a method with one argument
-     * @param argExpr  an expression denoting an argument to the method
-     * @return  a MethodInvocationTree to call the argument method
+     * @param methodExpr an expression denoting a method with one argument
+     * @param argExpr an expression denoting an argument to the method
+     * @return a MethodInvocationTree to call the argument method
      */
-    public MethodInvocationTree buildMethodInvocation(ExpressionTree methodExpr,
-            ExpressionTree argExpr) {
-        return maker.App((JCTree.JCExpression)methodExpr,
-                com.sun.tools.javac.util.List.of((JCTree.JCExpression)argExpr));
+    public MethodInvocationTree buildMethodInvocation(
+            ExpressionTree methodExpr, ExpressionTree argExpr) {
+        return maker.App(
+                (JCTree.JCExpression) methodExpr,
+                com.sun.tools.javac.util.List.of((JCTree.JCExpression) argExpr));
     }
 
     /**
      * Builds an AST Tree to declare and initialize a variable, with no modifiers.
      *
-     * @param type  the type of the variable
-     * @param name  the name of the variable
-     * @param owner  the element containing the new symbol
-     * @param initializer  the initializer expression
-     * @return  a VariableDeclTree declaring the new variable
+     * @param type the type of the variable
+     * @param name the name of the variable
+     * @param owner the element containing the new symbol
+     * @param initializer the initializer expression
+     * @return a VariableDeclTree declaring the new variable
      */
-    public VariableTree buildVariableDecl(TypeMirror type,
-                                          String name,
-                                          Element owner,
-                                          ExpressionTree initializer) {
+    public VariableTree buildVariableDecl(
+            TypeMirror type, String name, Element owner, ExpressionTree initializer) {
         DetachedVarSymbol sym =
-            new DetachedVarSymbol(0, names.fromString(name),
-                                  (Type)type, (Symbol)owner);
-        VariableTree tree = maker.VarDef(sym, (JCTree.JCExpression)initializer);
+                new DetachedVarSymbol(0, names.fromString(name), (Type) type, (Symbol) owner);
+        VariableTree tree = maker.VarDef(sym, (JCTree.JCExpression) initializer);
         sym.setDeclaration(tree);
         return tree;
     }
 
     /**
-     * Builds an AST Tree to declare and initialize a variable.  The
-     * type of the variable is specified by a Tree.
+     * Builds an AST Tree to declare and initialize a variable. The type of the variable is
+     * specified by a Tree.
      *
-     * @param type  the type of the variable, as a Tree
-     * @param name  the name of the variable
-     * @param owner  the element containing the new symbol
-     * @param initializer  the initializer expression
-     * @return  a VariableDeclTree declaring the new variable
+     * @param type the type of the variable, as a Tree
+     * @param name the name of the variable
+     * @param owner the element containing the new symbol
+     * @param initializer the initializer expression
+     * @return a VariableDeclTree declaring the new variable
      */
-    public VariableTree buildVariableDecl(Tree type,
-                                          String name,
-                                          Element owner,
-                                          ExpressionTree initializer) {
-        Type typeMirror = (Type)InternalUtils.typeOf(type);
+    public VariableTree buildVariableDecl(
+            Tree type, String name, Element owner, ExpressionTree initializer) {
+        Type typeMirror = (Type) InternalUtils.typeOf(type);
         DetachedVarSymbol sym =
-            new DetachedVarSymbol(0, names.fromString(name),
-                                  typeMirror, (Symbol)owner);
+                new DetachedVarSymbol(0, names.fromString(name), typeMirror, (Symbol) owner);
         JCTree.JCModifiers mods = maker.Modifiers(0);
-        JCTree.JCVariableDecl decl = maker.VarDef(mods, sym.name,
-                                                  (JCTree.JCExpression)type,
-                                                  (JCTree.JCExpression)initializer);
+        JCTree.JCVariableDecl decl =
+                maker.VarDef(
+                        mods,
+                        sym.name,
+                        (JCTree.JCExpression) type,
+                        (JCTree.JCExpression) initializer);
         decl.setType(typeMirror);
         decl.sym = sym;
         sym.setDeclaration(decl);
@@ -314,57 +301,49 @@
     /**
      * Builds an AST Tree to refer to a variable.
      *
-     * @param decl  the declaration of the variable
-     * @return  an IdentifierTree to refer to the variable
+     * @param decl the declaration of the variable
+     * @return an IdentifierTree to refer to the variable
      */
     public IdentifierTree buildVariableUse(VariableTree decl) {
-        return (IdentifierTree)maker.Ident((JCTree.JCVariableDecl)decl);
+        return (IdentifierTree) maker.Ident((JCTree.JCVariableDecl) decl);
     }
 
     /**
      * Builds an AST Tree to cast the type of an expression.
      *
-     * @param type  the type to cast to
-     * @param expr  the expression to be cast
-     * @return  a cast of the expression to the type
+     * @param type the type to cast to
+     * @param expr the expression to be cast
+     * @return a cast of the expression to the type
      */
-    public TypeCastTree buildTypeCast(TypeMirror type,
-                                      ExpressionTree expr) {
-        return maker.TypeCast((Type)type, (JCTree.JCExpression)expr);
+    public TypeCastTree buildTypeCast(TypeMirror type, ExpressionTree expr) {
+        return maker.TypeCast((Type) type, (JCTree.JCExpression) expr);
     }
 
     /**
      * Builds an AST Tree to assign an expression to a variable.
      *
-     * @param variable  the declaration of the variable to assign to
-     * @param expr      the expression to be assigned
-     * @return  a statement assigning the expression to the variable
+     * @param variable the declaration of the variable to assign to
+     * @param expr the expression to be assigned
+     * @return a statement assigning the expression to the variable
      */
-    public StatementTree buildAssignment(VariableTree variable,
-                                         ExpressionTree expr) {
-        return maker.Assignment(TreeInfo.symbolFor((JCTree)variable),
-                                (JCTree.JCExpression)expr);
+    public StatementTree buildAssignment(VariableTree variable, ExpressionTree expr) {
+        return maker.Assignment(TreeInfo.symbolFor((JCTree) variable), (JCTree.JCExpression) expr);
     }
 
     /**
      * Builds an AST Tree to assign an RHS expression to an LHS expression.
      *
-     * @param lhs  the expression to be assigned to
-     * @param rhs  the expression to be assigned
-     * @return  a statement assigning the expression to the variable
+     * @param lhs the expression to be assigned to
+     * @param rhs the expression to be assigned
+     * @return a statement assigning the expression to the variable
      */
-    public AssignmentTree buildAssignment(ExpressionTree lhs,
-                                          ExpressionTree rhs) {
-        JCTree.JCAssign assign =
-            maker.Assign((JCTree.JCExpression)lhs, (JCTree.JCExpression)rhs);
-        assign.setType((Type)InternalUtils.typeOf(lhs));
+    public AssignmentTree buildAssignment(ExpressionTree lhs, ExpressionTree rhs) {
+        JCTree.JCAssign assign = maker.Assign((JCTree.JCExpression) lhs, (JCTree.JCExpression) rhs);
+        assign.setType((Type) InternalUtils.typeOf(lhs));
         return assign;
     }
 
-    /**
-     * Builds an AST Tree representing a literal value of primitive
-     * or String type.
-     */
+    /** Builds an AST Tree representing a literal value of primitive or String type. */
     public LiteralTree buildLiteral(Object value) {
         return maker.Literal(value);
     }
@@ -372,51 +351,48 @@
     /**
      * Builds an AST Tree to compare two operands with less than.
      *
-     * @param left  the left operand tree
-     * @param right  the right operand tree
-     * @return  a Tree representing "left &lt; right"
+     * @param left the left operand tree
+     * @param right the right operand tree
+     * @return a Tree representing "left &lt; right"
      */
     public BinaryTree buildLessThan(ExpressionTree left, ExpressionTree right) {
         JCTree.JCBinary binary =
-            maker.Binary(JCTree.Tag.LT, (JCTree.JCExpression)left,
-                         (JCTree.JCExpression)right);
-        binary.setType((Type)modelTypes.getPrimitiveType(TypeKind.BOOLEAN));
+                maker.Binary(
+                        JCTree.Tag.LT, (JCTree.JCExpression) left, (JCTree.JCExpression) right);
+        binary.setType((Type) modelTypes.getPrimitiveType(TypeKind.BOOLEAN));
         return binary;
     }
 
     /**
      * Builds an AST Tree to dereference an array.
      *
-     * @param array  the array to dereference
-     * @param index  the index at which to dereference
-     * @return  a Tree representing the dereference
+     * @param array the array to dereference
+     * @param index the index at which to dereference
+     * @return a Tree representing the dereference
      */
-    public ArrayAccessTree buildArrayAccess(ExpressionTree array,
-                                            ExpressionTree index) {
-        ArrayType arrayType = (ArrayType)InternalUtils.typeOf(array);
+    public ArrayAccessTree buildArrayAccess(ExpressionTree array, ExpressionTree index) {
+        ArrayType arrayType = (ArrayType) InternalUtils.typeOf(array);
         JCTree.JCArrayAccess access =
-            maker.Indexed((JCTree.JCExpression)array, (JCTree.JCExpression)index);
-        access.setType((Type)arrayType.getComponentType());
+                maker.Indexed((JCTree.JCExpression) array, (JCTree.JCExpression) index);
+        access.setType((Type) arrayType.getComponentType());
         return access;
     }
 
     /**
      * Builds an AST Tree to refer to a class name.
      *
-     * @param elt  an element representing the class
-     * @return  an IdentifierTree referring to the class
+     * @param elt an element representing the class
+     * @return an IdentifierTree referring to the class
      */
     public IdentifierTree buildClassUse(Element elt) {
-        return maker.Ident((Symbol)elt);
+        return maker.Ident((Symbol) elt);
     }
 
     /**
-     * Builds an AST Tree to access the valueOf() method of boxed type
-     * such as Short or Float.
+     * Builds an AST Tree to access the valueOf() method of boxed type such as Short or Float.
      *
-     * @param expr  an expression whose type is a boxed type
-     * @return  a MemberSelectTree that accesses the valueOf() method of
-     *    the expression
+     * @param expr an expression whose type is a boxed type
+     * @return a MemberSelectTree that accesses the valueOf() method of the expression
      */
     public MemberSelectTree buildValueOfMethodAccess(Tree expr) {
         TypeMirror boxedType = InternalUtils.typeOf(expr);
@@ -426,32 +402,31 @@
         // Find the valueOf(unboxedType) method of the boxed type
         Symbol.MethodSymbol valueOfMethod = getValueOfMethod(env, boxedType);
 
-        Type.MethodType methodType = (Type.MethodType)valueOfMethod.asType();
+        Type.MethodType methodType = (Type.MethodType) valueOfMethod.asType();
 
         JCTree.JCFieldAccess valueOfAccess =
-            (JCTree.JCFieldAccess)
-            maker.Select((JCTree.JCExpression)expr, valueOfMethod);
+                (JCTree.JCFieldAccess) maker.Select((JCTree.JCExpression) expr, valueOfMethod);
         valueOfAccess.setType(methodType);
 
         return valueOfAccess;
     }
 
-    /**
-     * Returns the valueOf method of a boxed type such as Short or Float.
-     */
-    public static Symbol.MethodSymbol getValueOfMethod(ProcessingEnvironment env, TypeMirror boxedType) {
+    /** Returns the valueOf method of a boxed type such as Short or Float. */
+    public static Symbol.MethodSymbol getValueOfMethod(
+            ProcessingEnvironment env, TypeMirror boxedType) {
         Symbol.MethodSymbol valueOfMethod = null;
 
         TypeMirror unboxedType = env.getTypeUtils().unboxedType(boxedType);
-        TypeElement boxedElement = (TypeElement)((DeclaredType)boxedType).asElement();
+        TypeElement boxedElement = (TypeElement) ((DeclaredType) boxedType).asElement();
         for (ExecutableElement method :
-                 ElementFilter.methodsIn(env.getElementUtils().getAllMembers(boxedElement))) {
+                ElementFilter.methodsIn(env.getElementUtils().getAllMembers(boxedElement))) {
             Name methodName = method.getSimpleName();
 
             if (methodName.contentEquals("valueOf")) {
                 List<? extends VariableElement> params = method.getParameters();
-                if (params.size() == 1 && env.getTypeUtils().isSameType(params.get(0).asType(), unboxedType)) {
-                    valueOfMethod = (Symbol.MethodSymbol)method;
+                if (params.size() == 1
+                        && env.getTypeUtils().isSameType(params.get(0).asType(), unboxedType)) {
+                    valueOfMethod = (Symbol.MethodSymbol) method;
                 }
             }
         }
@@ -461,17 +436,15 @@
     }
 
     /**
-     * Builds an AST Tree to access the *Value() method of a
-     * boxed type such as Short or Float, where * is the corresponding
-     * primitive type (i.e. shortValue or floatValue).
+     * Builds an AST Tree to access the *Value() method of a boxed type such as Short or Float,
+     * where * is the corresponding primitive type (i.e. shortValue or floatValue).
      *
-     * @param expr  an expression whose type is a boxed type
-     * @return  a MemberSelectTree that accesses the *Value() method of
-     *    the expression
+     * @param expr an expression whose type is a boxed type
+     * @return a MemberSelectTree that accesses the *Value() method of the expression
      */
     public MemberSelectTree buildPrimValueMethodAccess(Tree expr) {
         TypeMirror boxedType = InternalUtils.typeOf(expr);
-        TypeElement boxedElement = (TypeElement)((DeclaredType)boxedType).asElement();
+        TypeElement boxedElement = (TypeElement) ((DeclaredType) boxedType).asElement();
 
         assert TypesUtils.isBoxedPrimitive(boxedType);
         TypeMirror unboxedType = modelTypes.unboxedType(boxedType);
@@ -481,207 +454,202 @@
         Symbol.MethodSymbol primValueMethod = null;
 
         for (ExecutableElement method :
-                 ElementFilter.methodsIn(elements.getAllMembers(boxedElement))) {
+                ElementFilter.methodsIn(elements.getAllMembers(boxedElement))) {
             Name methodName = method.getSimpleName();
 
-            if (methodName.contentEquals(primValueName) &&
-                method.getParameters().size() == 0) {
-                primValueMethod = (Symbol.MethodSymbol)method;
+            if (methodName.contentEquals(primValueName) && method.getParameters().size() == 0) {
+                primValueMethod = (Symbol.MethodSymbol) method;
             }
         }
 
         assert primValueMethod != null : "no *Value method declared for boxed type";
 
-        Type.MethodType methodType = (Type.MethodType)primValueMethod.asType();
+        Type.MethodType methodType = (Type.MethodType) primValueMethod.asType();
 
         JCTree.JCFieldAccess primValueAccess =
-            (JCTree.JCFieldAccess)
-            maker.Select((JCTree.JCExpression)expr, primValueMethod);
+                (JCTree.JCFieldAccess) maker.Select((JCTree.JCExpression) expr, primValueMethod);
         primValueAccess.setType(methodType);
 
         return primValueAccess;
     }
 
-    /**
-     * Map public AST Tree.Kinds to internal javac JCTree.Tags.
-     */
+    /** Map public AST Tree.Kinds to internal javac JCTree.Tags. */
     public JCTree.Tag kindToTag(Tree.Kind kind) {
         switch (kind) {
-        case AND:
-            return JCTree.Tag.BITAND;
-        case AND_ASSIGNMENT:
-            return JCTree.Tag.BITAND_ASG;
-        case ANNOTATION:
-            return JCTree.Tag.ANNOTATION;
-        case ANNOTATION_TYPE:
-            return JCTree.Tag.TYPE_ANNOTATION;
-        case ARRAY_ACCESS:
-            return JCTree.Tag.INDEXED;
-        case ARRAY_TYPE:
-            return JCTree.Tag.TYPEARRAY;
-        case ASSERT:
-            return JCTree.Tag.ASSERT;
-        case ASSIGNMENT:
-            return JCTree.Tag.ASSIGN;
-        case BITWISE_COMPLEMENT:
-            return JCTree.Tag.COMPL;
-        case BLOCK:
-            return JCTree.Tag.BLOCK;
-        case BREAK:
-            return JCTree.Tag.BREAK;
-        case CASE:
-            return JCTree.Tag.CASE;
-        case CATCH:
-            return JCTree.Tag.CATCH;
-        case CLASS:
-            return JCTree.Tag.CLASSDEF;
-        case CONDITIONAL_AND:
-            return JCTree.Tag.AND;
-        case CONDITIONAL_EXPRESSION:
-            return JCTree.Tag.CONDEXPR;
-        case CONDITIONAL_OR:
-            return JCTree.Tag.OR;
-        case CONTINUE:
-            return JCTree.Tag.CONTINUE;
-        case DIVIDE:
-            return JCTree.Tag.DIV;
-        case DIVIDE_ASSIGNMENT:
-            return JCTree.Tag.DIV_ASG;
-        case DO_WHILE_LOOP:
-            return JCTree.Tag.DOLOOP;
-        case ENHANCED_FOR_LOOP:
-            return JCTree.Tag.FOREACHLOOP;
-        case EQUAL_TO:
-            return JCTree.Tag.EQ;
-        case EXPRESSION_STATEMENT:
-            return JCTree.Tag.EXEC;
-        case FOR_LOOP:
-            return JCTree.Tag.FORLOOP;
-        case GREATER_THAN:
-            return JCTree.Tag.GT;
-        case GREATER_THAN_EQUAL:
-            return JCTree.Tag.GE;
-        case IDENTIFIER:
-            return JCTree.Tag.IDENT;
-        case IF:
-            return JCTree.Tag.IF;
-        case IMPORT:
-            return JCTree.Tag.IMPORT;
-        case INSTANCE_OF:
-            return JCTree.Tag.TYPETEST;
-        case LABELED_STATEMENT:
-            return JCTree.Tag.LABELLED;
-        case LEFT_SHIFT:
-            return JCTree.Tag.SL;
-        case LEFT_SHIFT_ASSIGNMENT:
-            return JCTree.Tag.SL_ASG;
-        case LESS_THAN:
-            return JCTree.Tag.LT;
-        case LESS_THAN_EQUAL:
-            return JCTree.Tag.LE;
-        case LOGICAL_COMPLEMENT:
-            return JCTree.Tag.NOT;
-        case MEMBER_SELECT:
-            return JCTree.Tag.SELECT;
-        case METHOD:
-            return JCTree.Tag.METHODDEF;
-        case METHOD_INVOCATION:
-            return JCTree.Tag.APPLY;
-        case MINUS:
-            return JCTree.Tag.MINUS;
-        case MINUS_ASSIGNMENT:
-            return JCTree.Tag.MINUS_ASG;
-        case MODIFIERS:
-            return JCTree.Tag.MODIFIERS;
-        case MULTIPLY:
-            return JCTree.Tag.MUL;
-        case MULTIPLY_ASSIGNMENT:
-            return JCTree.Tag.MUL_ASG;
-        case NEW_ARRAY:
-            return JCTree.Tag.NEWARRAY;
-        case NEW_CLASS:
-            return JCTree.Tag.NEWCLASS;
-        case NOT_EQUAL_TO:
-            return JCTree.Tag.NE;
-        case OR:
-            return JCTree.Tag.BITOR;
-        case OR_ASSIGNMENT:
-            return JCTree.Tag.BITOR_ASG;
-        case PARENTHESIZED:
-            return JCTree.Tag.PARENS;
-        case PLUS:
-            return JCTree.Tag.PLUS;
-        case PLUS_ASSIGNMENT:
-            return JCTree.Tag.PLUS_ASG;
-        case POSTFIX_DECREMENT:
-            return JCTree.Tag.POSTDEC;
-        case POSTFIX_INCREMENT:
-            return JCTree.Tag.POSTINC;
-        case PREFIX_DECREMENT:
-            return JCTree.Tag.PREDEC;
-        case PREFIX_INCREMENT:
-            return JCTree.Tag.PREINC;
-        case REMAINDER:
-            return JCTree.Tag.MOD;
-        case REMAINDER_ASSIGNMENT:
-            return JCTree.Tag.MOD_ASG;
-        case RETURN:
-            return JCTree.Tag.RETURN;
-        case RIGHT_SHIFT:
-            return JCTree.Tag.SR;
-        case RIGHT_SHIFT_ASSIGNMENT:
-            return JCTree.Tag.SR_ASG;
-        case SWITCH:
-            return JCTree.Tag.SWITCH;
-        case SYNCHRONIZED:
-            return JCTree.Tag.SYNCHRONIZED;
-        case THROW:
-            return JCTree.Tag.THROW;
-        case TRY:
-            return JCTree.Tag.TRY;
-        case TYPE_CAST:
-            return JCTree.Tag.TYPECAST;
-        case TYPE_PARAMETER:
-            return JCTree.Tag.TYPEPARAMETER;
-        case UNARY_MINUS:
-            return JCTree.Tag.NEG;
-        case UNARY_PLUS:
-            return JCTree.Tag.POS;
-        case UNION_TYPE:
-            return JCTree.Tag.TYPEUNION;
-        case UNSIGNED_RIGHT_SHIFT:
-            return JCTree.Tag.USR;
-        case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT:
-            return JCTree.Tag.USR_ASG;
-        case VARIABLE:
-            return JCTree.Tag.VARDEF;
-        case WHILE_LOOP:
-            return JCTree.Tag.WHILELOOP;
-        case XOR:
-            return JCTree.Tag.BITXOR;
-        case XOR_ASSIGNMENT:
-            return JCTree.Tag.BITXOR_ASG;
-        default:
-            return JCTree.Tag.NO_TAG;
+            case AND:
+                return JCTree.Tag.BITAND;
+            case AND_ASSIGNMENT:
+                return JCTree.Tag.BITAND_ASG;
+            case ANNOTATION:
+                return JCTree.Tag.ANNOTATION;
+            case ANNOTATION_TYPE:
+                return JCTree.Tag.TYPE_ANNOTATION;
+            case ARRAY_ACCESS:
+                return JCTree.Tag.INDEXED;
+            case ARRAY_TYPE:
+                return JCTree.Tag.TYPEARRAY;
+            case ASSERT:
+                return JCTree.Tag.ASSERT;
+            case ASSIGNMENT:
+                return JCTree.Tag.ASSIGN;
+            case BITWISE_COMPLEMENT:
+                return JCTree.Tag.COMPL;
+            case BLOCK:
+                return JCTree.Tag.BLOCK;
+            case BREAK:
+                return JCTree.Tag.BREAK;
+            case CASE:
+                return JCTree.Tag.CASE;
+            case CATCH:
+                return JCTree.Tag.CATCH;
+            case CLASS:
+                return JCTree.Tag.CLASSDEF;
+            case CONDITIONAL_AND:
+                return JCTree.Tag.AND;
+            case CONDITIONAL_EXPRESSION:
+                return JCTree.Tag.CONDEXPR;
+            case CONDITIONAL_OR:
+                return JCTree.Tag.OR;
+            case CONTINUE:
+                return JCTree.Tag.CONTINUE;
+            case DIVIDE:
+                return JCTree.Tag.DIV;
+            case DIVIDE_ASSIGNMENT:
+                return JCTree.Tag.DIV_ASG;
+            case DO_WHILE_LOOP:
+                return JCTree.Tag.DOLOOP;
+            case ENHANCED_FOR_LOOP:
+                return JCTree.Tag.FOREACHLOOP;
+            case EQUAL_TO:
+                return JCTree.Tag.EQ;
+            case EXPRESSION_STATEMENT:
+                return JCTree.Tag.EXEC;
+            case FOR_LOOP:
+                return JCTree.Tag.FORLOOP;
+            case GREATER_THAN:
+                return JCTree.Tag.GT;
+            case GREATER_THAN_EQUAL:
+                return JCTree.Tag.GE;
+            case IDENTIFIER:
+                return JCTree.Tag.IDENT;
+            case IF:
+                return JCTree.Tag.IF;
+            case IMPORT:
+                return JCTree.Tag.IMPORT;
+            case INSTANCE_OF:
+                return JCTree.Tag.TYPETEST;
+            case LABELED_STATEMENT:
+                return JCTree.Tag.LABELLED;
+            case LEFT_SHIFT:
+                return JCTree.Tag.SL;
+            case LEFT_SHIFT_ASSIGNMENT:
+                return JCTree.Tag.SL_ASG;
+            case LESS_THAN:
+                return JCTree.Tag.LT;
+            case LESS_THAN_EQUAL:
+                return JCTree.Tag.LE;
+            case LOGICAL_COMPLEMENT:
+                return JCTree.Tag.NOT;
+            case MEMBER_SELECT:
+                return JCTree.Tag.SELECT;
+            case METHOD:
+                return JCTree.Tag.METHODDEF;
+            case METHOD_INVOCATION:
+                return JCTree.Tag.APPLY;
+            case MINUS:
+                return JCTree.Tag.MINUS;
+            case MINUS_ASSIGNMENT:
+                return JCTree.Tag.MINUS_ASG;
+            case MODIFIERS:
+                return JCTree.Tag.MODIFIERS;
+            case MULTIPLY:
+                return JCTree.Tag.MUL;
+            case MULTIPLY_ASSIGNMENT:
+                return JCTree.Tag.MUL_ASG;
+            case NEW_ARRAY:
+                return JCTree.Tag.NEWARRAY;
+            case NEW_CLASS:
+                return JCTree.Tag.NEWCLASS;
+            case NOT_EQUAL_TO:
+                return JCTree.Tag.NE;
+            case OR:
+                return JCTree.Tag.BITOR;
+            case OR_ASSIGNMENT:
+                return JCTree.Tag.BITOR_ASG;
+            case PARENTHESIZED:
+                return JCTree.Tag.PARENS;
+            case PLUS:
+                return JCTree.Tag.PLUS;
+            case PLUS_ASSIGNMENT:
+                return JCTree.Tag.PLUS_ASG;
+            case POSTFIX_DECREMENT:
+                return JCTree.Tag.POSTDEC;
+            case POSTFIX_INCREMENT:
+                return JCTree.Tag.POSTINC;
+            case PREFIX_DECREMENT:
+                return JCTree.Tag.PREDEC;
+            case PREFIX_INCREMENT:
+                return JCTree.Tag.PREINC;
+            case REMAINDER:
+                return JCTree.Tag.MOD;
+            case REMAINDER_ASSIGNMENT:
+                return JCTree.Tag.MOD_ASG;
+            case RETURN:
+                return JCTree.Tag.RETURN;
+            case RIGHT_SHIFT:
+                return JCTree.Tag.SR;
+            case RIGHT_SHIFT_ASSIGNMENT:
+                return JCTree.Tag.SR_ASG;
+            case SWITCH:
+                return JCTree.Tag.SWITCH;
+            case SYNCHRONIZED:
+                return JCTree.Tag.SYNCHRONIZED;
+            case THROW:
+                return JCTree.Tag.THROW;
+            case TRY:
+                return JCTree.Tag.TRY;
+            case TYPE_CAST:
+                return JCTree.Tag.TYPECAST;
+            case TYPE_PARAMETER:
+                return JCTree.Tag.TYPEPARAMETER;
+            case UNARY_MINUS:
+                return JCTree.Tag.NEG;
+            case UNARY_PLUS:
+                return JCTree.Tag.POS;
+            case UNION_TYPE:
+                return JCTree.Tag.TYPEUNION;
+            case UNSIGNED_RIGHT_SHIFT:
+                return JCTree.Tag.USR;
+            case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT:
+                return JCTree.Tag.USR_ASG;
+            case VARIABLE:
+                return JCTree.Tag.VARDEF;
+            case WHILE_LOOP:
+                return JCTree.Tag.WHILELOOP;
+            case XOR:
+                return JCTree.Tag.BITXOR;
+            case XOR_ASSIGNMENT:
+                return JCTree.Tag.BITXOR_ASG;
+            default:
+                return JCTree.Tag.NO_TAG;
         }
     }
 
     /**
      * Builds an AST Tree to perform a binary operation.
      *
-     * @param type  result type of the operation
-     * @param op    AST Tree operator
-     * @param left  the left operand tree
-     * @param right  the right operand tree
-     * @return  a Tree representing "left &lt; right"
+     * @param type result type of the operation
+     * @param op AST Tree operator
+     * @param left the left operand tree
+     * @param right the right operand tree
+     * @return a Tree representing "left &lt; right"
      */
-    public BinaryTree buildBinary(TypeMirror type, Tree.Kind op, ExpressionTree left, ExpressionTree right) {
+    public BinaryTree buildBinary(
+            TypeMirror type, Tree.Kind op, ExpressionTree left, ExpressionTree right) {
         JCTree.Tag jcOp = kindToTag(op);
         JCTree.JCBinary binary =
-            maker.Binary(jcOp, (JCTree.JCExpression)left,
-                         (JCTree.JCExpression)right);
-        binary.setType((Type)type);
+                maker.Binary(jcOp, (JCTree.JCExpression) left, (JCTree.JCExpression) right);
+        binary.setType((Type) type);
         return binary;
     }
-
 }
diff --git a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/TreeParser.java b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/TreeParser.java
index ea7f67f..9ea545e 100644
--- a/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/TreeParser.java
+++ b/third_party/checker_framework_javacutil/java/org/checkerframework/javacutil/trees/TreeParser.java
@@ -1,9 +1,5 @@
 package org.checkerframework.javacutil.trees;
 
-import java.util.StringTokenizer;
-
-import javax.annotation.processing.ProcessingEnvironment;
-
 import com.sun.source.tree.ExpressionTree;
 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
 import com.sun.tools.javac.tree.JCTree.JCExpression;
@@ -12,27 +8,28 @@
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.util.ListBuffer;
 import com.sun.tools.javac.util.Names;
+import java.util.StringTokenizer;
+import javax.annotation.processing.ProcessingEnvironment;
 
 /**
- * A Utility class for parsing Java expression snippets, and converting them
- * to proper Javac AST nodes.
+ * A Utility class for parsing Java expression snippets, and converting them to proper Javac AST
+ * nodes.
  *
- * This is useful for parsing {@code EnsuresNonNull*},
- * and {@code KeyFor} values.
+ * <p>This is useful for parsing {@code EnsuresNonNull*}, and {@code KeyFor} values.
  *
- * Currently, it handles four tree types only:
+ * <p>Currently, it handles four tree types only:
+ *
  * <ul>
- *  <li>Identifier tree (e.g. {@code id})</li>
- *  <li>Literal tree (e.g. 2, 3)</li>
- *  <li>Method invocation tree (e.g. {@code method(2, 3)})</li>
- *  <li>Member select tree (e.g. {@code Class.field}, {@code instance.method()})
- *  <li>Array access tree (e.g. {@code array[id]})</li>
+ *   <li>Identifier tree (e.g. {@code id})
+ *   <li>Literal tree (e.g. 2, 3)
+ *   <li>Method invocation tree (e.g. {@code method(2, 3)})
+ *   <li>Member select tree (e.g. {@code Class.field}, {@code instance.method()})
+ *   <li>Array access tree (e.g. {@code array[id]})
  * </ul>
  *
- * Notable limitation: Doesn't handle spaces, or non-method-argument
- * parenthesis.
+ * Notable limitation: Doesn't handle spaces, or non-method-argument parenthesis.
  *
- * It's implemented via a Recursive-Descend parser.
+ * <p>It's implemented via a Recursive-Descend parser.
  */
 public class TreeParser {
     private static final String DELIMS = ".[](),";
@@ -42,17 +39,16 @@
     private final Names names;
 
     public TreeParser(ProcessingEnvironment env) {
-        Context context = ((JavacProcessingEnvironment)env).getContext();
+        Context context = ((JavacProcessingEnvironment) env).getContext();
         maker = TreeMaker.instance(context);
         names = Names.instance(context);
     }
 
     /**
-     * Parses the snippet in the string as an internal Javac AST expression
-     * node
+     * Parses the snippet in the string as an internal Javac AST expression node
      *
      * @param s the java snippet
-     * @return  the AST corresponding to the snippet
+     * @return the AST corresponding to the snippet
      */
     public ExpressionTree parseTree(String s) {
         tokenizer = new StringTokenizer(s, DELIMS, true);
@@ -84,15 +80,19 @@
             return maker.Literal(false);
         }
 
-        if (Character.isLetter(token.charAt(0)))
+        if (Character.isLetter(token.charAt(0))) {
             return maker.Ident(names.fromString(token));
+        }
 
         Object value = null;
         try {
             value = Integer.valueOf(token);
-        } catch (Exception e2) { try {
-            value = Double.valueOf(token);
-        } catch (Exception ef) {}}
+        } catch (Exception e2) {
+            try {
+                value = Double.valueOf(token);
+            } catch (Exception ef) {
+            }
+        }
         assert value != null;
         return maker.Literal(value);
     }
@@ -104,21 +104,20 @@
             String delim = nextToken();
             if (".".equals(delim)) {
                 nextToken();
-                tree = maker.Select(tree,
-                        names.fromString(token));
+                tree = maker.Select(tree, names.fromString(token));
             } else if ("(".equals(delim)) {
                 nextToken();
                 ListBuffer<JCExpression> args = new ListBuffer<>();
                 while (!")".equals(token)) {
                     JCExpression arg = parseExpression();
                     args.append(arg);
-                    if (",".equals(token))
+                    if (",".equals(token)) {
                         nextToken();
+                    }
                 }
                 // For now, handle empty args only
                 assert ")".equals(token);
-                tree = maker.Apply(List.<JCExpression>nil(),
-                        tree, args.toList());
+                tree = maker.Apply(List.<JCExpression>nil(), tree, args.toList());
             } else if ("[".equals(token)) {
                 nextToken();
                 JCExpression index = parseExpression();
@@ -132,7 +131,7 @@
         return tree;
     }
 
-    class ParseError extends RuntimeException {
+    private static class ParseError extends RuntimeException {
         private static final long serialVersionUID = 1887754619522101929L;
 
         ParseError(Throwable cause) {