From 085fbe769bc572f6a0160e79a1c216f784a87308 Mon Sep 17 00:00:00 2001
From: Johannes Mey <johannes.mey@tu-dresden.de>
Date: Wed, 11 Dec 2019 19:08:28 +0100
Subject: [PATCH] initial (broken) version of simplecfg

---
 settings.gradle                               |   1 +
 simplecfg/.gitignore                          |  20 +
 simplecfg/CONTRIBUTING.md                     |  24 +
 simplecfg/LICENSE                             | 202 +++++
 simplecfg/README.md                           |  70 ++
 simplecfg/build.gradle                        | 107 +++
 simplecfg/gentest.sh                          |  29 +
 simplecfg/gradle/wrapper/gradle-wrapper.jar   | Bin 0 -> 54459 bytes
 .../gradle/wrapper/gradle-wrapper.properties  |   5 +
 simplecfg/graph.sh                            |  36 +
 simplecfg/modules                             |  83 ++
 .../main/jastadd/AlreadyClosedAnalysis.jrag   |  90 ++
 simplecfg/src/main/jastadd/CFG.ast            |  36 +
 simplecfg/src/main/jastadd/CfgSearch.jrag     | 149 ++++
 .../src/main/jastadd/ClassPathFilter.ast      |  22 +
 .../src/main/jastadd/ClassPathFilter.jrag     | 235 ++++++
 simplecfg/src/main/jastadd/Findings.jrag      | 119 +++
 .../jastadd/NullableDereferenceAnalysis.jrag  | 504 +++++++++++
 simplecfg/src/main/jastadd/PrintCfg.jrag      | 145 ++++
 simplecfg/src/main/jastadd/PrintCfgTest.jrag  | 179 ++++
 simplecfg/src/main/jastadd/SimpleCFG.jrag     | 791 ++++++++++++++++++
 .../jastadd/VariableDeclarationScope.jrag     |  75 ++
 .../simplecfg/ExtendJAnalyzerFrontend.java    | 155 ++++
 .../google/simplecfg/ExtendJAnalyzerMain.java |  40 +
 .../java/com/google/simplecfg/PrintCfg.java   |  75 ++
 .../com/google/simplecfg/TestGenerator.java   |  66 ++
 .../google/simplecfg/AlreadyClosedTest.java   |  64 ++
 .../simplecfg/NullableDereferenceTest.java    | 145 ++++
 .../com/google/simplecfg/StmtCfgTest.java     | 658 +++++++++++++++
 .../org/extendj/ast/IdentityTupleSetTest.java |  58 ++
 .../testdata/AlreadyClosedControlFlow01.javax | 140 ++++
 .../AlreadyClosedNegativeFindings01.javax     |  87 ++
 .../testdata/AlreadyClosedWriter01.javax      |  29 +
 simplecfg/testdata/Close01.javax              |  25 +
 simplecfg/testdata/ConditionalExpr01.javax    |  25 +
 simplecfg/testdata/DoStmt01.javax             |  27 +
 simplecfg/testdata/DoStmt02.javax             |  28 +
 simplecfg/testdata/EnhancedFor01.javax        |  26 +
 simplecfg/testdata/Filtering01.javax          |  31 +
 simplecfg/testdata/ForStmt01.javax            |  25 +
 simplecfg/testdata/ForStmt02.javax            |  26 +
 simplecfg/testdata/ForStmt03.javax            |  25 +
 simplecfg/testdata/ForStmt04.javax            |  27 +
 simplecfg/testdata/ForStmt05.javax            |  28 +
 simplecfg/testdata/GenClassInstance01.javax   |  24 +
 simplecfg/testdata/GenClassInstance02.javax   |  28 +
 simplecfg/testdata/GenForStmt01.javax         |  33 +
 simplecfg/testdata/GenForStmt02.javax         |  33 +
 simplecfg/testdata/GenSwitchStmt01.javax      |  46 +
 simplecfg/testdata/GenTryStmt01.javax         |  34 +
 simplecfg/testdata/GenTryStmt02.javax         |  30 +
 simplecfg/testdata/GenTryStmt03.javax         |  33 +
 simplecfg/testdata/GenTryStmt04.javax         |  34 +
 simplecfg/testdata/GenTryStmt05.javax         |  35 +
 simplecfg/testdata/GenTryStmt06.javax         |  34 +
 simplecfg/testdata/GenTryStmt07.javax         |  35 +
 .../testdata/GenTryWithResources01.javax      |  30 +
 .../testdata/GenTryWithResources02.javax      |  31 +
 simplecfg/testdata/IfStmt01.javax             |  26 +
 simplecfg/testdata/IfStmt02.javax             |  28 +
 simplecfg/testdata/IfStmt03.javax             |  29 +
 simplecfg/testdata/IfStmt04.javax             |  29 +
 simplecfg/testdata/MethodAccess01.javax       |  25 +
 simplecfg/testdata/NullableDataflow01.javax   |  53 ++
 .../testdata/NullableDereference01.javax      |  37 +
 .../testdata/NullableDereferenceEqExpr.javax  | 200 +++++
 .../testdata/NullableDereferenceIssue10.javax |  36 +
 .../testdata/NullableDereferenceIssue11.javax |  46 +
 .../testdata/NullableDereferenceIssue12.javax |  45 +
 .../testdata/NullableDereferenceIssue13.javax |  40 +
 .../NullableDereferenceMethodCall.javax       |  55 ++
 .../testdata/NullableDereferenceNeExpr.javax  | 200 +++++
 simplecfg/testdata/NullableInstanceOf.javax   |  46 +
 .../testdata/NullableMethodNullGuard01.javax  |  66 ++
 simplecfg/testdata/NullableNullGuard01.javax  |  95 +++
 simplecfg/testdata/NullableNullGuard02.javax  |  74 ++
 simplecfg/testdata/NullableNullGuard03.javax  | 140 ++++
 .../testdata/NullableVariableArity.javax      |  35 +
 simplecfg/testdata/SwitchStmt01.javax         |  36 +
 simplecfg/testdata/SwitchStmt02.javax         |  34 +
 simplecfg/testdata/ThrowStmt01.javax          |  26 +
 simplecfg/testdata/TryStmt01.javax            |  32 +
 simplecfg/testdata/TryStmt02.javax            |  29 +
 simplecfg/testdata/TryStmt03.javax            |  33 +
 simplecfg/testdata/WhileStmt01.javax          |  26 +
 simplecfg/testdata/WhileStmt02.javax          |  25 +
 simplecfg/testdata/WhileStmt03.javax          |  30 +
 simplecfg/testdata/WhileStmt04.javax          |  32 +
 simplecfg/testdata/WhileStmt05.javax          |  28 +
 89 files changed, 6828 insertions(+)
 create mode 100644 simplecfg/.gitignore
 create mode 100644 simplecfg/CONTRIBUTING.md
 create mode 100644 simplecfg/LICENSE
 create mode 100644 simplecfg/README.md
 create mode 100644 simplecfg/build.gradle
 create mode 100755 simplecfg/gentest.sh
 create mode 100644 simplecfg/gradle/wrapper/gradle-wrapper.jar
 create mode 100644 simplecfg/gradle/wrapper/gradle-wrapper.properties
 create mode 100755 simplecfg/graph.sh
 create mode 100644 simplecfg/modules
 create mode 100644 simplecfg/src/main/jastadd/AlreadyClosedAnalysis.jrag
 create mode 100644 simplecfg/src/main/jastadd/CFG.ast
 create mode 100644 simplecfg/src/main/jastadd/CfgSearch.jrag
 create mode 100644 simplecfg/src/main/jastadd/ClassPathFilter.ast
 create mode 100644 simplecfg/src/main/jastadd/ClassPathFilter.jrag
 create mode 100644 simplecfg/src/main/jastadd/Findings.jrag
 create mode 100644 simplecfg/src/main/jastadd/NullableDereferenceAnalysis.jrag
 create mode 100644 simplecfg/src/main/jastadd/PrintCfg.jrag
 create mode 100644 simplecfg/src/main/jastadd/PrintCfgTest.jrag
 create mode 100644 simplecfg/src/main/jastadd/SimpleCFG.jrag
 create mode 100644 simplecfg/src/main/jastadd/VariableDeclarationScope.jrag
 create mode 100644 simplecfg/src/main/java/com/google/simplecfg/ExtendJAnalyzerFrontend.java
 create mode 100644 simplecfg/src/main/java/com/google/simplecfg/ExtendJAnalyzerMain.java
 create mode 100644 simplecfg/src/main/java/com/google/simplecfg/PrintCfg.java
 create mode 100644 simplecfg/src/main/java/com/google/simplecfg/TestGenerator.java
 create mode 100644 simplecfg/src/test/java/com/google/simplecfg/AlreadyClosedTest.java
 create mode 100644 simplecfg/src/test/java/com/google/simplecfg/NullableDereferenceTest.java
 create mode 100644 simplecfg/src/test/java/com/google/simplecfg/StmtCfgTest.java
 create mode 100644 simplecfg/src/test/java/org/extendj/ast/IdentityTupleSetTest.java
 create mode 100644 simplecfg/testdata/AlreadyClosedControlFlow01.javax
 create mode 100644 simplecfg/testdata/AlreadyClosedNegativeFindings01.javax
 create mode 100644 simplecfg/testdata/AlreadyClosedWriter01.javax
 create mode 100644 simplecfg/testdata/Close01.javax
 create mode 100644 simplecfg/testdata/ConditionalExpr01.javax
 create mode 100644 simplecfg/testdata/DoStmt01.javax
 create mode 100644 simplecfg/testdata/DoStmt02.javax
 create mode 100644 simplecfg/testdata/EnhancedFor01.javax
 create mode 100644 simplecfg/testdata/Filtering01.javax
 create mode 100644 simplecfg/testdata/ForStmt01.javax
 create mode 100644 simplecfg/testdata/ForStmt02.javax
 create mode 100644 simplecfg/testdata/ForStmt03.javax
 create mode 100644 simplecfg/testdata/ForStmt04.javax
 create mode 100644 simplecfg/testdata/ForStmt05.javax
 create mode 100644 simplecfg/testdata/GenClassInstance01.javax
 create mode 100644 simplecfg/testdata/GenClassInstance02.javax
 create mode 100644 simplecfg/testdata/GenForStmt01.javax
 create mode 100644 simplecfg/testdata/GenForStmt02.javax
 create mode 100644 simplecfg/testdata/GenSwitchStmt01.javax
 create mode 100644 simplecfg/testdata/GenTryStmt01.javax
 create mode 100644 simplecfg/testdata/GenTryStmt02.javax
 create mode 100644 simplecfg/testdata/GenTryStmt03.javax
 create mode 100644 simplecfg/testdata/GenTryStmt04.javax
 create mode 100644 simplecfg/testdata/GenTryStmt05.javax
 create mode 100644 simplecfg/testdata/GenTryStmt06.javax
 create mode 100644 simplecfg/testdata/GenTryStmt07.javax
 create mode 100644 simplecfg/testdata/GenTryWithResources01.javax
 create mode 100644 simplecfg/testdata/GenTryWithResources02.javax
 create mode 100644 simplecfg/testdata/IfStmt01.javax
 create mode 100644 simplecfg/testdata/IfStmt02.javax
 create mode 100644 simplecfg/testdata/IfStmt03.javax
 create mode 100644 simplecfg/testdata/IfStmt04.javax
 create mode 100644 simplecfg/testdata/MethodAccess01.javax
 create mode 100644 simplecfg/testdata/NullableDataflow01.javax
 create mode 100644 simplecfg/testdata/NullableDereference01.javax
 create mode 100644 simplecfg/testdata/NullableDereferenceEqExpr.javax
 create mode 100644 simplecfg/testdata/NullableDereferenceIssue10.javax
 create mode 100644 simplecfg/testdata/NullableDereferenceIssue11.javax
 create mode 100644 simplecfg/testdata/NullableDereferenceIssue12.javax
 create mode 100644 simplecfg/testdata/NullableDereferenceIssue13.javax
 create mode 100644 simplecfg/testdata/NullableDereferenceMethodCall.javax
 create mode 100644 simplecfg/testdata/NullableDereferenceNeExpr.javax
 create mode 100644 simplecfg/testdata/NullableInstanceOf.javax
 create mode 100644 simplecfg/testdata/NullableMethodNullGuard01.javax
 create mode 100644 simplecfg/testdata/NullableNullGuard01.javax
 create mode 100644 simplecfg/testdata/NullableNullGuard02.javax
 create mode 100644 simplecfg/testdata/NullableNullGuard03.javax
 create mode 100644 simplecfg/testdata/NullableVariableArity.javax
 create mode 100644 simplecfg/testdata/SwitchStmt01.javax
 create mode 100644 simplecfg/testdata/SwitchStmt02.javax
 create mode 100644 simplecfg/testdata/ThrowStmt01.javax
 create mode 100644 simplecfg/testdata/TryStmt01.javax
 create mode 100644 simplecfg/testdata/TryStmt02.javax
 create mode 100644 simplecfg/testdata/TryStmt03.javax
 create mode 100644 simplecfg/testdata/WhileStmt01.javax
 create mode 100644 simplecfg/testdata/WhileStmt02.javax
 create mode 100644 simplecfg/testdata/WhileStmt03.javax
 create mode 100644 simplecfg/testdata/WhileStmt04.javax
 create mode 100644 simplecfg/testdata/WhileStmt05.javax

diff --git a/settings.gradle b/settings.gradle
index afd285d..aba0955 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -11,6 +11,7 @@ rootProject.name = 'sle19-impl'
 
 include 'statemachine'
 include 'dg'
+include 'simplecfg'
 include 'extendj'
 include 'extendj:java4'
 include 'extendj:java5'
diff --git a/simplecfg/.gitignore b/simplecfg/.gitignore
new file mode 100644
index 0000000..e6c14cd
--- /dev/null
+++ b/simplecfg/.gitignore
@@ -0,0 +1,20 @@
+# gradle build
+/build/
+/.gradle/
+
+# generated files
+/*.jar
+/src/gen/
+
+# generated graphs
+/testdata/*.png
+
+# vim
+*.swp
+
+# eclipse
+/.project
+/.classpath
+/.settings/
+/bin/
+
diff --git a/simplecfg/CONTRIBUTING.md b/simplecfg/CONTRIBUTING.md
new file mode 100644
index 0000000..1ba8539
--- /dev/null
+++ b/simplecfg/CONTRIBUTING.md
@@ -0,0 +1,24 @@
+Want to contribute? Great! First, read this page (including the small print at the end).
+
+### Before you contribute
+Before we can use your code, you must sign the
+[Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual?csw=1)
+(CLA), which you can do online. The CLA is necessary mainly because you own the
+copyright to your changes, even after your contribution becomes part of our
+codebase, so we need your permission to use and distribute your code. We also
+need to be sure of various other things—for instance that you'll tell us if you
+know that your code infringes on other people's patents. You don't have to sign
+the CLA until after you've submitted your code for review and a member has
+approved it, but you must do it before we can put your code into our codebase.
+Before you start working on a larger contribution, you should get in touch with
+us first through the issue tracker with your idea so that we can help out and
+possibly guide you. Coordinating up front makes it much easier to avoid
+frustration later on.
+
+### Code reviews
+All submissions, including submissions by project members, require review. We
+use Github pull requests for this purpose.
+
+### The small print
+Contributions made by corporations are covered by a different agreement than
+the one above, the Software Grant and Corporate Contributor License Agreement.
diff --git a/simplecfg/LICENSE b/simplecfg/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/simplecfg/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/simplecfg/README.md b/simplecfg/README.md
new file mode 100644
index 0000000..bb0a66b
--- /dev/null
+++ b/simplecfg/README.md
@@ -0,0 +1,70 @@
+Simple CFG module for ExtendJ
+=============================
+
+This is a Control Flow Graph (CFG) module for the ExtendJ compiler for building
+simplified CFGs. This module builds CFGs for Java methods where only branches
+and method calls have are included.  These simple CFGs provide enough
+information to perform intraprocedural static analyses on Java code.
+
+This repository also includes two sample Java static analyzers based on the this
+CFG module.  One analyzer checks for additional calls to a
+java.io.Reader/java.io.Writer after `close()` was called on the same instance.
+The other analyzer checks for potential `null` dereferences on paramters
+annotated with javax.annotation.Nullable.
+
+Disclaimer
+----------
+
+This is not an official Google product (experimental or otherwise), it is just
+code that happens to be owned by Google.
+
+Shipshape Module
+----------------
+
+The demo analyzers can be plugged into the [Shipshape][1] pipeline. The
+Shipshape integration is currently experimental.
+
+Dependencies
+------------
+
+To build the Simplified CFG generator you need the following dependencies:
+
+* Git
+* Gradle 2.4
+* ExtendJ
+
+This repository has a submodule for the ExtendJ compiler. If you did not clone
+this repository with the `--recursive` flag you will have to run `git submodule
+init` followed by `git submodule update`, this will clone a specific commit from
+the ExtendJ repository into the `third_party/extendj/` directory.
+
+Building
+--------
+
+Note that you must have the Git submodule `third_party/extendj/git` in
+order to build SimpleCFG. To download the submodule, use the following commands:
+
+    git submodule init
+    git submodule update
+
+
+Build the Simplified CFG generator Jar file by running the following Gradle command:
+
+    gradle jar
+
+
+Testing
+-------
+
+The tests may be run by issuing the following command:
+
+    gradle test
+
+Most tests check that a well-formed SimpleCFG is built for each Java file in the
+testdata directory. The tests are structured so that they test the successors of
+each node in the resulting CFG for the single block/method in each of the Java files.
+
+You can generate images for the CFGs in each test file by running the `graph.sh`
+shell script.
+
+[1]: https://github.com/google/shipshape
diff --git a/simplecfg/build.gradle b/simplecfg/build.gradle
new file mode 100644
index 0000000..45deaad
--- /dev/null
+++ b/simplecfg/build.gradle
@@ -0,0 +1,107 @@
+buildscript {
+	repositories.mavenLocal()
+	repositories.mavenCentral()
+	dependencies {
+		classpath 'org.jastadd:jastaddgradle:1.13.3'
+	}
+}
+
+apply plugin: 'java'
+apply plugin: 'application'
+apply plugin: 'jastadd'
+apply plugin: 'idea'
+
+repositories {
+	mavenLocal()
+}
+
+idea {
+	module {
+		generatedSourceDirs += file('./src/gen/java')
+	}
+}
+
+//sourceSets {
+//	main {
+//		java.srcDirs "src/gen/java"
+//		java.srcDirs "../extendj/src/frontend"
+//	}
+//}
+sourceSets.main {
+	java {
+
+		srcDirs "src/gen/java"
+		srcDirs '../extendj/src/frontend'
+	}
+	resources {
+		srcDir '../extendj/src/res'
+		srcDir jastadd.buildInfoDir
+	}
+}
+
+dependencies {
+//	compile group: 'com.google.guava', name: 'guava', version: '18.0'
+	testCompile group: 'com.google.truth', name: 'truth', version: '0.27'
+}
+
+jastadd {
+	configureModuleBuild()
+	modules  {
+
+		include("../extendj/jastadd_modules")
+
+		module "simplecfg", {
+
+			imports "java8 frontend"
+
+			jastadd {
+				basedir "src/main/jastadd/"
+				include "**/*.ast"
+				include "**/*.jadd"
+				include "**/*.jrag"
+			}
+
+			java {
+				basedir "src/main/java/"
+				include "**/*.java"
+			}
+
+		}
+
+	}
+
+
+	// Target module to build:
+	module = 'simplecfg'
+
+	astPackage = 'org.extendj.ast'
+	parser.name = 'JavaParser'
+	scanner.name = 'OriginalScanner'
+//
+	genDir = 'src/gen/java'
+
+
+	parser.genDir = 'src/gen/java/org/extendj/parser'
+	scanner.genDir = 'src/gen/java/org/extendj/scanner'
+//
+//	if (project.hasProperty('extraJastAddOptions')) {
+//		extraJastAddOptions += project.extraJastAddOptions.split(',') as List
+//		print("options: ${extraJastAddOptions}")
+//	}
+
+}
+
+
+test {
+	inputs.dir file('testdata')
+}
+
+mainClassName = 'com.google.simplecfg.PrintCfg'
+jar.manifest.attributes 'Main-Class': mainClassName
+jar.destinationDir = projectDir
+
+sourceCompatibility = '1.8'
+targetCompatibility = '1.8'
+
+// fix broken scanner dependencies
+//scanner.outputs.upToDateWhen {false}
diff --git a/simplecfg/gentest.sh b/simplecfg/gentest.sh
new file mode 100755
index 0000000..388f72d
--- /dev/null
+++ b/simplecfg/gentest.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# Copyright 2014 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+if [ $# -lt "1" ]; then
+  echo "Error: no input program specified."
+  exit 1
+else
+  gradle jar
+  for src in "$@"; do
+    java -cp simplecfg.jar com.google.simplecfg.TestGenerator "$src"
+  done
+fi
+
+echo "done"
diff --git a/simplecfg/gradle/wrapper/gradle-wrapper.jar b/simplecfg/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000000000000000000000000000000000..3ebf88af3b642f4f202c85c16a3815fce3e9590d
GIT binary patch
literal 54459
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

literal 0
HcmV?d00001

diff --git a/simplecfg/gradle/wrapper/gradle-wrapper.properties b/simplecfg/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..019065d
--- /dev/null
+++ b/simplecfg/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
diff --git a/simplecfg/graph.sh b/simplecfg/graph.sh
new file mode 100755
index 0000000..c15fd3c
--- /dev/null
+++ b/simplecfg/graph.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+# Copyright 2015 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+gradle jar
+
+gengraph()
+{
+    OUT="${1%%\.javax}.png"
+    echo "$1 -> $OUT"
+    java -jar simplecfg.jar "$1" | dot -Tpng > "$OUT"
+}
+
+if [ $# -lt "1" ]; then
+  for f in testdata/*.javax; do
+    gengraph $f
+  done
+else
+  gengraph $1
+fi
+
+echo "done"
diff --git a/simplecfg/modules b/simplecfg/modules
new file mode 100644
index 0000000..52ac3fc
--- /dev/null
+++ b/simplecfg/modules
@@ -0,0 +1,83 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+// // Custom version of the Java 8 frontend without JavaScanner (compile error due to moved class).
+// module("java8 frontend mod") {
+// 	moduleName "Java SE 8"
+// 	moduleVariant "frontend"
+//
+// 	def java8 = "../extendj/java8"
+//
+// 	imports "java7 frontend"
+//
+// 	jastadd {
+// 		basedir java8
+// 		include "grammar/*.ast"
+// 		include "frontend/*.jadd"
+// 		include "frontend/*.jrag"
+//
+// 		excludeFrom "java7 frontend", "frontend/JavaVersion.jrag"
+//
+// 		exclude "frontend/FrontendMain.jrag"
+// 		excludeFrom "java5 frontend", "frontend/BytecodeReader.jrag"
+// 		excludeFrom "java7 frontend", "frontend/Variable.jadd"
+//
+// 	}
+//
+// 	scanner {
+// 		basedir java8
+// 		include "scanner/Separators.flex"
+// 		include "scanner/Operators.flex"
+//
+// 		excludeFrom "java4 frontend", "scanner/Preamble.flex"
+// 	}
+//
+// 	parser {
+// 	    basedir java8
+// 		include "parser/*"
+// 	}
+// }
+
+module("simplecfg") {
+
+	imports "java8 frontend"
+
+	jastadd {
+		basedir "src/main/jastadd/"
+		include "**/*.ast"
+		include "**/*.jadd"
+		include "**/*.jrag"
+	}
+
+	java {
+		basedir "src/main/java/"
+		include "**/*.java"
+	}
+
+	scanner {
+		include "src/main/scanner/Header.flex", [-4]
+		excludeFrom "java4 frontend", "scanner/Header.flex"
+	}
+
+	parser {
+		// Replace parser package declaration.
+		include "src/main/parser/Header.parser", [-2]
+		excludeFrom "java4 frontend", "parser/Header.parser"
+	}
+}
+
diff --git a/simplecfg/src/main/jastadd/AlreadyClosedAnalysis.jrag b/simplecfg/src/main/jastadd/AlreadyClosedAnalysis.jrag
new file mode 100644
index 0000000..47d4988
--- /dev/null
+++ b/simplecfg/src/main/jastadd/AlreadyClosedAnalysis.jrag
@@ -0,0 +1,90 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Adds an analysis checking for calls to an instance of java.io.Writer or java.io.Reader after
+ * {@code close()} has been called on the same instance.
+ *
+ * <p>For each method call to an effectively final variable of type java.io.Closeable,
+ * we do a breadth-first search on the reverse CFG from the location of that call to see if a
+ * call to {@code close()} was made on the same instance previously.
+ */
+aspect AlreadyClosedAnalysis {
+
+  MethodAccess contributes alreadyClosedFinding()
+      when alreadyClosedStream()
+      to CompilationUnit.findings()
+      for compilationUnit();
+
+  /** Allow MethodAccess to lookup the enclosing compilation unit.  */
+  inh CompilationUnit MethodAccess.compilationUnit();
+
+  /** Generate a finding for method call after close() call.  */
+  syn lazy ExtendJFinding MethodAccess.alreadyClosedFinding() =
+      finding("AlreadyClosed", String.format(
+          "close() may have already been called on %s at this point",
+          prevExpr().prettyPrint()));
+
+  /** Check if the reciever of this method access was already closed. */
+  syn boolean MethodAccess.alreadyClosedStream() {
+    // The receiver must be an effectively final local variable (or parameter).
+    if (name().equals("close") // Don't check for repeated close() calls.
+        || name().equals("toString") || name().equals("toByteArray")
+        || !hasPrevExpr() // Does not have a variable or parameter receiver.
+        || prevExpr().varDecl() == null // Receiver is not a variable/parameter.
+        || !(prevExpr().varDecl().isFinal()
+            || prevExpr().varDecl().isEffectivelyFinal()) // Receiver might have changed.
+        || !prevExpr().type().isCloseable()) { // Receiver is not instance of java.io.Closeable.
+      return false;
+    }
+    final Variable receiver = prevExpr().varDecl();
+    return null != call().reverseBfs(new CfgVisitor() {
+      @Override
+      public SearchAction processEdge(CfgNode pred, CfgNode succ) {
+        if (succ.isCloseCall(receiver)) {
+          if (pred.isException()) {
+            // This call is interrupted by an exception. Don't continue the search from this node.
+            return SearchAction.SKIP;
+          } else {
+            return SearchAction.SUCCESSOR_MATCH;
+          }
+        }
+        if (succ.isCall(receiver)) {
+          // Already analyzed from this point.
+          return SearchAction.SKIP;
+        }
+        if (succ.isDeclarationOf(receiver)) {
+          // Skip this node and don't reconsider any other path that encounters the node.
+          return SearchAction.IGNORE;
+        }
+        return SearchAction.CONTINUE;
+      }
+    });
+  }
+
+  /** Test if the CFG node is a call node with the given variable as receiver. */
+  syn boolean CfgNode.isCall(Variable receiver) = false;
+  eq CfgMethodCall.isCall(Variable receiver) = methodAccess().hasReceiver(receiver);
+
+  /** Test if the CFG node is a call node for receiver.close(). */
+  syn boolean CfgNode.isCloseCall(Variable receiver) = false;
+  eq CfgMethodCall.isCloseCall(Variable receiver) =
+      methodAccess().hasReceiver(receiver) && methodAccess().getID().equals("close");
+
+  /** Check if this is a Reader or Writer.  */
+  syn boolean TypeDecl.isCloseable() =
+      !isUnknown() && instanceOf(lookupType("java.io", "Closeable"));
+}
diff --git a/simplecfg/src/main/jastadd/CFG.ast b/simplecfg/src/main/jastadd/CFG.ast
new file mode 100644
index 0000000..b1e7cbe
--- /dev/null
+++ b/simplecfg/src/main/jastadd/CFG.ast
@@ -0,0 +1,36 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** A node in a Control Flow Graph (CFG). */
+abstract CfgNode;
+
+/** The CFG entry node. */
+CfgEntry : CfgNode ::= <Succ:CfgNode>;
+
+/** The CFG exit node. */
+CfgExit : CfgNode;
+
+/** A method call in the CFG. */
+CfgMethodCall : CfgNode;
+
+/** A conditional branch in the CFG.  */
+CfgBranch : CfgNode;
+
+/** A branch in the CFG caused by potential thrown exceptions.  */
+CfgException : CfgNode;
+
+/** A marker node used to mark try block entry points or the end of if-statement branches.  */
+CfgMarker : CfgNode;
diff --git a/simplecfg/src/main/jastadd/CfgSearch.jrag b/simplecfg/src/main/jastadd/CfgSearch.jrag
new file mode 100644
index 0000000..e950ffe
--- /dev/null
+++ b/simplecfg/src/main/jastadd/CfgSearch.jrag
@@ -0,0 +1,149 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This aspect adds an API for searching for nodes matching some property in a Control Flow Graph.
+ */
+aspect CfgSearch {
+  enum SearchAction {
+    /**
+     * The search is complete because the currently processed edge successor matches the search.
+     */
+    SUCCESSOR_MATCH,
+    /**
+     * The search is complete because the currently processed edge predecessor matches the search.
+     */
+    PREDECESSOR_MATCH,
+    /**
+     * The search should skip adding the successors from the successor of the current edge.
+     */
+    SKIP,
+    /**
+     * The search continues as normal, adding successors from the target of the current edge.
+     */
+    CONTINUE,
+    /**
+     * The search does not process additional edges to the target of the current edge, and the
+     * successors of the target node are not added to the work queue.
+     */
+    IGNORE
+  }
+
+  /** A CFG visitor decides which nodes to process based on the current edge (pred, succ). */
+  interface CfgVisitor {
+    /**
+     * Returns the action a Breadth-First search should take for this edge.
+     * @param pred Edge source.
+     * @param succ Edge destination.
+     */
+    public SearchAction processEdge(CfgNode pred, CfgNode succ);
+  }
+
+  /**
+   * Performs a Breadth-First Search over the CFG successors starting from this node.
+   * @param visitor a visitor that decides when the search is terminated and which
+   * successors to process
+   * @return {@code null} if no match was found
+   */
+  public CfgNode CfgNode.bfs(CfgVisitor visitor) {
+    Set<CfgNode> visited = Collections.newSetFromMap(
+        new IdentityHashMap<CfgNode, Boolean>());
+    Queue<CfgNode> work = new LinkedList<CfgNode>();
+    work.add(this);
+    while (!work.isEmpty()) {
+      CfgNode node = work.poll();
+      for (CfgNode succ : node.successors()) {
+        if (!visited.contains(succ)) {
+          switch (visitor.processEdge(node, succ)) {
+            case SUCCESSOR_MATCH:
+              return succ;
+            case PREDECESSOR_MATCH:
+              return node;
+            case SKIP:
+              continue;
+            case CONTINUE:
+              work.add(succ);
+              visited.add(succ);
+              break;
+            case IGNORE:
+              visited.add(succ);
+              break;
+          }
+        }
+      }
+    }
+    // The search matched nothing and we exhausted all successors.
+    return null;
+  }
+
+  inh lazy CfgEntry CfgNode.cfg();
+
+  /**
+   * Performs a Breadth-First Search over the CFG predecessors starting from this node.
+   * @param visitor a visitor that decides when the search is terminated and which
+   * predecessors to process
+   * @return {@code null} if no match was found
+   */
+  public CfgNode CfgNode.reverseBfs(CfgVisitor visitor) {
+    Set<CfgNode> visited = Collections.newSetFromMap(
+        new IdentityHashMap<CfgNode, Boolean>());
+    cfg().initPredecessors();
+    Queue<CfgNode> work = new LinkedList<CfgNode>();
+    work.add(this);
+    while (!work.isEmpty()) {
+      CfgNode node = work.poll();
+      for (CfgNode pred : node.predecessors) {
+        if (!visited.contains(pred)) {
+          switch (visitor.processEdge(node, pred)) {
+            case SUCCESSOR_MATCH:
+              return pred;
+            case PREDECESSOR_MATCH:
+              return node;
+            case SKIP:
+              continue;
+            case CONTINUE:
+              work.add(pred);
+              visited.add(pred);
+              break;
+            case IGNORE:
+              visited.add(pred);
+              break;
+          }
+        }
+      }
+    }
+    // The search matched nothing and we exhausted all predecessors.
+    return null;
+  }
+
+  /** A matcher used to search for particular nodes in a CFG. */
+  interface CfgMatcher {
+    public boolean match(CfgNode node);
+  }
+
+  /** Search for a previous node matching the matcher, starting from the current CFG node. */
+  public CfgNode CfgNode.findPreviousNode(final CfgMatcher matcher) {
+    return reverseBfs(new CfgVisitor() {
+      @Override
+      public SearchAction processEdge(CfgNode pred, CfgNode succ) {
+        return matcher.match(succ) ? SearchAction.SUCCESSOR_MATCH : SearchAction.CONTINUE;
+      }
+    });
+  }
+
+  /** Check if there is a previous node matching the matcher, starting from the current CFG node. */
+  syn boolean CfgNode.hasPreviousNode(CfgMatcher matcher) = null != findPreviousNode(matcher);
+}
diff --git a/simplecfg/src/main/jastadd/ClassPathFilter.ast b/simplecfg/src/main/jastadd/ClassPathFilter.ast
new file mode 100644
index 0000000..0acfbec
--- /dev/null
+++ b/simplecfg/src/main/jastadd/ClassPathFilter.ast
@@ -0,0 +1,22 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * PlaceholderTypeDecl is used to avoid locating and parsing source or class files when
+ * analyzing a single file.
+ * Represents a type that is known to exist but which we don't know anything else about.
+ */
+PlaceholderTypeDecl : ClassDecl;
diff --git a/simplecfg/src/main/jastadd/ClassPathFilter.jrag b/simplecfg/src/main/jastadd/ClassPathFilter.jrag
new file mode 100644
index 0000000..33e9b33
--- /dev/null
+++ b/simplecfg/src/main/jastadd/ClassPathFilter.jrag
@@ -0,0 +1,235 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Replace type lookup to avoid parsing extra sources.
+ * All sources other than the one that is being analyzed is replaced
+ * by the Unknown type, or a placeholder type - a TypeDecl with just
+ * a name and package.
+ */
+aspect ClassPathFilter {
+
+  /** The type lookup filter to use during type lookups.  */
+  private TypeLookupFilter Program.typeLookupFilter = NO_TYPE_FILTER;
+
+  /** Changes the type lookup filter.  */
+  public void Program.setTypeLookupFilter(TypeLookupFilter filter) {
+    typeLookupFilter = filter;
+  }
+
+  public interface TypeLookupFilter {
+    /**
+     * This allows extra source type map initialization. It is run after the default source type map
+     * initialization code.
+     */
+    void initializeSourceTypeMap(Program program);
+    /**
+     * This allows extra library type map initialization. It is run after the default library type
+     * map initialization code.
+     */
+    void initializeLibraryTypeMap(Program program);
+
+    /**
+     * Returns the TypeDecl for the requested type. Returns UnknownType if the type was not
+     * found, or if the type was filtered out by this filter.
+     */
+    TypeDecl lookupSourceType(Program program, String packageName, String typeName);
+
+    /**
+     * Returns the TypeDecl for the requested type. Returns UnknownType if the type was not
+     * found, or if the type was filtered out by this filter.
+     */
+    TypeDecl lookupLibraryType(Program program, String packageName, String typeName);
+  }
+
+  /** This type filter does not perform any filtering. */
+  public static final TypeLookupFilter Program.NO_TYPE_FILTER = new TypeLookupFilter() {
+    @Override
+    public void initializeSourceTypeMap(Program program) {
+    }
+
+    @Override
+    public void initializeLibraryTypeMap(Program program) {
+    }
+
+    @Override
+    public TypeDecl lookupSourceType(Program program, String packageName, String typeName) {
+      return program.lookupSourceType(packageName, typeName);
+    }
+
+    @Override
+    public TypeDecl lookupLibraryType(Program program, String packageName, String typeName) {
+      return program.lookupLibraryType(packageName, typeName);
+    }
+  };
+
+  /** This type filter filters out library types. */
+  public static final TypeLookupFilter Program.BASE_LIBRARY_FILTER = new TypeLookupFilter() {
+    @Override
+    public void initializeSourceTypeMap(Program program) {
+    }
+
+    @Override
+    public void initializeLibraryTypeMap(Program program) {
+      // All types that need to be distinguishable in the code being analyzed
+      // should be added as placeholders here.
+      // This list contains all types which are looked up explicitly in the
+      // ExtendJ frontend code with lookupType(pkg, name) All type lookups that
+      // don't match a placeholder type get mapped to the Unknown type.
+      program.addPlaceholderType("java.lang", "Object");
+      program.addPlaceholderType("java.lang", "AutoCloseable");
+      program.addPlaceholderType("java.lang", "Class");
+      program.addPlaceholderType("java.lang", "Cloneable");
+      program.addPlaceholderType("java.lang", "Error");
+      program.addPlaceholderType("java.lang", "Exception");
+      program.addPlaceholderType("java.lang", "FunctionalInterface");
+      program.addPlaceholderType("java.lang", "NullPointerException");
+      program.addPlaceholderType("java.lang", "Throwable");
+      program.addPlaceholderType("java.lang", "Enum");
+      program.addPlaceholderType("java.lang", "Iterable");
+      program.addPlaceholderType("java.lang", "Iterator");
+      program.addPlaceholderType("java.lang", "RuntimeException");
+
+      // Annotations and boxed primitive types are required
+      // to do some simple type analysis.
+
+      // Add annotation types.
+      program.addPlaceholderType("java.lang.annotation", "Target");
+      program.addPlaceholderType("java.lang.annotation", "Retention");
+      program.addPlaceholderType("java.lang.annotation", "Inherited");
+      program.addPlaceholderType("java.lang", "SuppressWarnings");
+      program.addPlaceholderType("java.lang", "Override");
+      program.addPlaceholderType("java.lang", "Serializable");
+
+      // Boxed primitive types.
+      program.addPlaceholderType("java.lang", "Integer");
+      program.addPlaceholderType("java.lang", "Float");
+      program.addPlaceholderType("java.lang", "Short");
+      program.addPlaceholderType("java.lang", "Byte");
+      program.addPlaceholderType("java.lang", "Character");
+      program.addPlaceholderType("java.lang", "Long");
+      program.addPlaceholderType("java.lang", "Double");
+      program.addPlaceholderType("java.lang", "String");
+      program.addPlaceholderType("java.lang", "Boolean");
+      program.addPlaceholderType("java.lang", "Void");
+    }
+
+    @Override
+    public TypeDecl lookupSourceType(Program program, String packageName, String typeName) {
+      return program.lookupSourceType(packageName, typeName);
+    }
+
+    @Override
+    public TypeDecl lookupLibraryType(Program program, String packageName, String typeName) {
+      String fullName = packageName.isEmpty() ? typeName : packageName + "." + typeName;
+      if (program.libraryTypeMap.containsKey(fullName)) {
+        return program.libraryTypeMap.get(fullName);
+      } else {
+        program.libraryTypeMap.put(fullName, program.unknownType());
+        return program.unknownType();
+      }
+    }
+  };
+
+  public static final TypeLookupFilter Program.ANALYZER_TYPE_FILTER = new TypeLookupFilter() {
+    @Override
+    public void initializeSourceTypeMap(Program program) {
+      BASE_LIBRARY_FILTER.initializeSourceTypeMap(program);
+    }
+
+    @Override
+    public void initializeLibraryTypeMap(Program program) {
+      BASE_LIBRARY_FILTER.initializeLibraryTypeMap(program);
+
+      // Types needed for read/write after close analysis.
+      program.addPlaceholderType("java.io", "Writer");
+      program.addPlaceholderType("java.io", "Reader");
+
+      // Types needed for Nullable Dereference analysis.
+      program.addPlaceholderType("javax.annotation", "Nullable");
+    }
+
+    @Override
+    public TypeDecl lookupSourceType(Program program, String packageName, String typeName) {
+      return BASE_LIBRARY_FILTER.lookupSourceType(program, packageName, typeName);
+    }
+
+    @Override
+    public TypeDecl lookupLibraryType(Program program, String packageName, String typeName) {
+      return BASE_LIBRARY_FILTER.lookupLibraryType(program, packageName, typeName);
+    }
+  };
+
+  refine LookupFullyQualifiedTypes
+  protected void Program.initializeSourceTypeMap() {
+    refined();
+    typeLookupFilter.initializeSourceTypeMap(this);
+  }
+
+  refine LookupFullyQualifiedTypes
+  protected void Program.initializeLibraryTypeMap() {
+    refined();
+    typeLookupFilter.initializeLibraryTypeMap(this);
+  }
+
+  refine LookupFullyQualifiedTypes
+  eq Program.lookupType(String packageName, String typeName) {
+    TypeDecl sourceType = typeLookupFilter.lookupSourceType(this, packageName, typeName);
+    if (!sourceType.isUnknown()) {
+      return sourceType;
+    }
+    if (!libraryTypeMapInitialized) {
+      initializeLibraryTypeMap();
+      libraryTypeMapInitialized = true;
+    }
+    return typeLookupFilter.lookupLibraryType(this, packageName, typeName);
+  }
+
+  /**
+   * Add a placeholder type declaration to the library type map.
+   * This triggers evaluation of a placeholder type NTA and a placeholder
+   * compilation unit NTA.
+   */
+  public void Program.addPlaceholderType(String packageName, String typeName) {
+    String fullName = packageName.equals("") ? typeName : packageName + "." + typeName;
+    CompilationUnit cu = placeholderCompilationUnit(packageName);
+    cu.setFromSource(false);
+    cu.setClassSource(ClassSource.NONE);
+    TypeDecl placeholder = cu.placeholderTypeDecl(typeName);
+    libraryTypeMap.put(fullName, placeholder);
+  }
+
+  /**
+   * Build a placeholder compilation unit for types in a package.
+   */
+  syn nta CompilationUnit Program.placeholderCompilationUnit(String packageName) {
+    CompilationUnit u = new CompilationUnit();
+    u.setPackageDecl(packageName);
+    return u;
+  }
+
+  /**
+   * Build placeholder type declaration.
+   */
+  syn nta TypeDecl CompilationUnit.placeholderTypeDecl(String typeName) {
+    PlaceholderTypeDecl decl = new PlaceholderTypeDecl();
+    decl.setModifiers(new Modifiers(new List().add(new Modifier("public"))));
+    decl.setID(typeName);
+    return decl;
+  }
+
+}
+
diff --git a/simplecfg/src/main/jastadd/Findings.jrag b/simplecfg/src/main/jastadd/Findings.jrag
new file mode 100644
index 0000000..104905b
--- /dev/null
+++ b/simplecfg/src/main/jastadd/Findings.jrag
@@ -0,0 +1,119 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+/**
+ * This aspect provides the general attributes to collect findings for the
+ * available analyses.
+ */
+aspect Findings {
+  /** Collection of API usage findings.  */
+  coll Collection<ExtendJFinding> CompilationUnit.findings()
+      [new LinkedList<ExtendJFinding>()]
+      with add
+      root CompilationUnit;
+
+  /** Build a new finding with the given subcategory and message.  */
+  syn ExtendJFinding ASTNode.finding(String subcategory, String message) {
+    ASTNode location = locationNode();
+    return new ExtendJFinding(sourceFile(), subcategory, message,
+        getLine(location.getStart()), getColumn(location.getStart()),
+        getLine(location.getEnd()), getColumn(location.getEnd()));
+  }
+
+  /** Find the closest AST node with source location information.  */
+  syn ASTNode ASTNode.locationNode() {
+    ASTNode node = this;
+    while (node.getParent() != null && node.getStart() == 0) {
+      node = node.getParent();
+    }
+    return node;
+  }
+
+  /** Find the indentation for the current statement.  */
+  inh String Stmt.indentation();
+
+  /** Find the indentation for the current expression.  */
+  inh String Expr.indentation();
+
+  /** Find the indentation for the current type declaration.  */
+  inh String TypeDecl.indentation();
+
+  eq Block.getChild().indentation() = indentation() + "  ";
+  eq TypeDecl.getChild().indentation() = indentation() + "  ";
+
+  eq CompilationUnit.getChild().indentation() = "";
+  eq Program.getChild().indentation() = "";
+
+  /** A finding produced by an ExtendJ analyzer.  */
+  public class ExtendJFinding {
+
+    public final String sourcePath;
+    public final String subcategory;
+    public final String message;
+    public final int startLine;
+    public final int startColumn;
+    public final int endLine;
+    public final int endColumn;
+    public final Collection<ExtendJFix> fixes = new ArrayList<>();
+
+    /**
+     * Describes a suggested fix. The suggested fix has a description which does not seem to
+     * show up in Critique. The new text should end with a newline.
+     */
+    public static class ExtendJFix {
+      public final String description;
+      public final int startLine;
+      public final int endLine;
+      public final String newText;
+
+      ExtendJFix(String description, int startLine, int endLine, String newText) {
+        this.description = description;
+        this.startLine = startLine;
+        this.endLine = endLine;
+        this.newText = newText;
+      }
+    }
+
+    public ExtendJFinding(String sourcePath, String subcategory, String message,
+        int startLine, int startColumn, int endLine, int endColumn) {
+      this.sourcePath = sourcePath;
+      this.subcategory = subcategory;
+      this.message = message;
+      this.startLine = startLine;
+      this.startColumn = startColumn;
+      this.endLine = endLine;
+      this.endColumn = endColumn;
+    }
+
+    /**
+     * Set a new suggested fix for this finding.
+     */
+    public ExtendJFinding addFix(String description, int startLine, int endLine, String newText) {
+      fixes.add(new ExtendJFix(description, startLine, endLine, newText));
+      return this;
+    }
+
+    @Override
+    public String toString() {
+      // This message is printed for each finding when running the CLI.
+      return String.format("%s:%d:%d: %s", sourcePath, startLine, startColumn, message);
+    }
+  }
+}
diff --git a/simplecfg/src/main/jastadd/NullableDereferenceAnalysis.jrag b/simplecfg/src/main/jastadd/NullableDereferenceAnalysis.jrag
new file mode 100644
index 0000000..db9afd1
--- /dev/null
+++ b/simplecfg/src/main/jastadd/NullableDereferenceAnalysis.jrag
@@ -0,0 +1,504 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Adds an analysis that checks for dereferences of a parameter declared nullable.
+ *
+ * <p>When a method or constructor parameter is annotated with javax.annotation.Nullable,
+ * we check that all dereferences of that parameter are guarded by a null-check. The
+ * analysis is control-flow sensitive in that it will recognize if all control flow paths
+ * to the dereference are effectively guarded by a null check, for example: {@code
+ * if (p == null) return;
+ * p.x(); // Guarded by null check above.
+ * }
+ *
+ * <p>The analysis is not intraprocedural, so in order to avoid false positives
+ * where a method call guards against nullness the analyzer assumes that
+ * calling a method with an argument x results in an exception if x is null and
+ * thus works like an effective null guard for x.
+ *
+ * <p>To find potential null dereferences on nullable parameters, the analysis does a forward CFG
+ * traversal from the entry-point of the method. Note that this is only done whenever a
+ * {@code @Nullable} parameter has been encountered in the method. The traversal explores all paths
+ * from the method entry until it finds null guard statements such as {@code if (p != null)}. The
+ * branches that are protected from nullness get pruned in the search and the search continues on
+ * other branches. The search is performed by a {@code NullDereferenceLocator}, which implements the
+ * {@code CfgSearch} interface. This visitor is invoked for each node in the CFG search, and it
+ * decides if the search will continue from that node, or if the current edge should be skipped
+ * (i.e., pruned).
+ *
+ * <p>In order to find the position in the CFG where a potential null dereference occurs, CFG marker
+ * nodes are inserted. This is done by adding a synthesized non-terminal attribute (NTA) for
+ * a CfgMarker on Dot (which represents Java dot expressions). This marker node appears
+ * in the CFG as "nullable access" because it is inserted whenever a nullable variable is
+ * dereferenced.
+ *
+ * <p>Dataflow analysis is not used, so in order to analyze a parameter it is required to be
+ * effectively final, i.e. it is not assigned anywhere in side the body of the method/constructor.
+ */
+aspect NullableDereferenceAnalysis {
+
+  // Give ParameterDeclaration access to the inherited compilationUnit attribute.
+  inh CompilationUnit ParameterDeclaration.compilationUnit();
+
+  ParameterDeclaration contributes nullableDereferenceFinding()
+      when nullableDereferenceFinding() != null
+      to CompilationUnit.findings()
+      for compilationUnit();
+
+  /**
+   * Generate a NullableDereference finding for this dot expression,
+   * if no finding should be reported this attribute returns {@code null}.
+   */
+  syn lazy ExtendJFinding ParameterDeclaration.nullableDereferenceFinding() {
+    if (!getModifiers().hasNullableAnnotation()) {
+      return null;
+    }
+    if (!isFinal() && !isEffectivelyFinal()) {
+      // Do not analyze non-effectively final parameters.
+      return null;
+    }
+    Expr location = findNullableDereference(this);
+    if (location == null) {
+      return null;
+    }
+    ExtendJFinding finding = location.finding("NullableDereference", String.format(
+        "Dereferencing %s, which was declared @Nullable.", name()));
+    if (compilationUnit().fromSource()) {
+      ASTNode modifierLocation = nullableModifierLocation();
+      int line = getLine(modifierLocation.getStart());
+      int startCol = getColumn(modifierLocation.getStart());
+      int endCol = getColumn(modifierLocation.getEnd());
+      if (startCol < endCol && line == getLine(modifierLocation.getEnd())) {
+        try {
+          InputStream data = compilationUnit().getClassSource().openInputStream();
+          java.util.Scanner scanner = new java.util.Scanner(data);
+          for (int i = 1; i < line && scanner.hasNextLine(); ++i) {
+            scanner.nextLine();
+          }
+          if (scanner.hasNextLine()) {
+            String text = scanner.nextLine();
+            finding.addFix("Remove the @Nullable annotation.",
+                line, line,
+                text.substring(0,startCol-1) + text.substring(endCol+1) + "\n");
+          }
+        } catch (IOException e) {
+          // Failed to unparse the current line.
+          // This is not a serious problem; we just don't give a fix suggestion.
+        }
+      }
+    }
+    return finding;
+  }
+
+  // Exclude variable arity parameters from Nullable dereference analysis.
+  // When a variable arity parameter is annotated @Nullable, that will most likely be intended as a
+  // @Nullable annotation for the individual parameters, not the containing argument array.
+  eq VariableArityParameterDeclaration.nullableDereferenceFinding() = null;
+
+  /**
+   * Find the location node for the javax.annotation.Nullable annotation in the modifier list.
+   * Returns {@code null} if the location of the modifier was not found.
+   */
+  syn ASTNode ParameterDeclaration.nullableModifierLocation() =
+      getModifiers().nullableModifierLocation();
+
+  syn ASTNode Modifiers.nullableModifierLocation() {
+    for (Modifier modifier : getModifierList()) {
+      if (modifier.isAnnotation("javax.annotation", "Nullable")) {
+        return modifier.locationNode();
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Find a location, not necessarily the first location, in the host method/constructor where the
+   * parameter is accessed without a null guard.
+   */
+  inh Expr ParameterDeclaration.findNullableDereference(Variable var);
+
+  eq Program.getChild().findNullableDereference(Variable var) = null;
+  eq BodyDecl.getChild().findNullableDereference(Variable var) = null;
+
+  eq MethodDecl.getParameter().findNullableDereference(Variable var) {
+    if (!hasBlock()) {
+      return null;
+    }
+    CfgNode cfgNode = entry().bfs(new NullDereferenceLocator(var));
+    return cfgNode == null ? null : cfgNode.receiverExpr();
+  }
+
+  eq ConstructorDecl.getParameter().findNullableDereference(Variable var) {
+    CfgNode cfgNode = entry().bfs(new NullDereferenceLocator(var));
+    return cfgNode == null ? null : cfgNode.receiverExpr();
+  }
+
+  /**
+   * A CFG visitor that searches in the forward CFG for a nullable dereference.
+   *
+   * <p>The search stops at parts of the search tree guarded by a null check
+   * on the receiver variable.
+   */
+  class NullDereferenceLocator implements CfgVisitor {
+    private final Variable var;
+
+    public NullDereferenceLocator(Variable var) {
+      this.var = var;
+    }
+
+    @Override public SearchAction processEdge(CfgNode pred, CfgNode succ) {
+      if (pred.isNullGuard(var, succ)) {
+        return SearchAction.SKIP;
+      }
+      Expr receiver = succ.receiverExpr();
+      if (receiver != null && receiver.isVariable(var) && !receiver.hasNullGuard(var)) {
+        return SearchAction.SUCCESSOR_MATCH;
+      }
+      return SearchAction.CONTINUE;
+    }
+  }
+
+  /**
+   * Returns the receiver expression if the CFG node is the child of a dereference expression.
+   * Returns {@code null} otherwise.
+   */
+  inh Expr CfgNode.receiverExpr();
+  eq Program.getChild().receiverExpr() = null;
+  eq BodyDecl.getChild().receiverExpr() = null;
+  eq BodyDecl.exit().receiverExpr() = null;
+  eq TryStmt.tryEntryMarker().receiverExpr() = null;
+  eq BreakStmt.marker().receiverExpr() = null;
+  eq ContinueStmt.marker().receiverExpr() = null;
+  eq ReturnStmt.marker().receiverExpr() = null;
+  eq MethodAccess.exceptionNode().receiverExpr() = null;
+  eq MethodAccess.call().receiverExpr() =
+      hasPrevExpr()
+      ? prevExpr()
+      : null;
+  eq ThrowStmt.exceptionNode().receiverExpr() = null;
+  eq TryStmt.exceptionNode().receiverExpr() = null;
+  eq ConditionalExpr.branch().receiverExpr() = null;
+  eq ConditionalExpr.thenEndMarker().receiverExpr() = null;
+  eq ConditionalExpr.elseEndMarker().receiverExpr() = null;
+  eq IfStmt.branch().receiverExpr() = null;
+  eq IfStmt.thenEndMarker().receiverExpr() = null;
+  eq IfStmt.elseEndMarker().receiverExpr() = null;
+  eq ForStmt.branch().receiverExpr() = null;
+  eq EnhancedForStmt.branch().receiverExpr() = null;
+  eq WhileStmt.branch().receiverExpr() = null;
+  eq DoStmt.branch().receiverExpr() = null;
+  eq SwitchStmt.branch().receiverExpr() = null;
+  eq LambdaBody.exit().receiverExpr() = null;
+  eq Dot.nullableDereferenceMarker().receiverExpr() = getLeft();
+
+  /** Marker node used to find location of a nullable dereference in the CFG.  */
+  syn nta CfgMarker Dot.nullableDereferenceMarker() = new CfgMarker();
+
+  /** Insert nullable dereference marker in the CFG.  */
+  refine SimpleCFG
+  eq Dot.getLeft().follow() =
+      getRight().isMethodAccess()
+      ? refined()
+      : nullableDereferenceMarker();
+
+  eq Dot.nullableDereferenceMarker().succ() = Collections.singleton(getRight().entry());
+
+  syn boolean CfgNode.isNullGuard(Variable var, CfgNode succ) = false;
+
+  /**
+   * We assume that calling a method with the variable var as an argument
+   * results in an exception thrown by the method call if var is null. This is
+   * not true for many methods, but it should reduce the false positive rate
+   * for the NullableDereference analyzer.
+   */
+  eq CfgMethodCall.isNullGuard(Variable var, CfgNode succ) {
+    if (succ instanceof CfgException) {
+      return false;
+    }
+    MethodAccess access = methodAccess();
+    for (Expr arg : access.getArgList()) {
+      if (arg.isVariable(var)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /** Check if this branch has a null-guarding condition.  */
+  eq CfgBranch.isNullGuard(Variable var, CfgNode succ) = inNullGuard(var, succ);
+
+  inh boolean CfgBranch.inNullGuard(Variable var, CfgNode succ);
+
+  eq IfStmt.branch().inNullGuard(Variable var, CfgNode succ) =
+      succ == getThen().entry()
+      ? getCondition().isNonNullWhenTrue(var)
+      : getCondition().isNonNullWhenFalse(var);
+
+  eq ConditionalExpr.branch().inNullGuard(Variable var, CfgNode succ) =
+      succ == getTrueExpr().entry()
+      ? getCondition().isNonNullWhenTrue(var)
+      : getCondition().isNonNullWhenFalse(var);
+
+  eq ForStmt.branch().inNullGuard(Variable var, CfgNode succ) =
+      succ == getStmt().entry()
+      ? getCondition().isNonNullWhenTrue(var)
+      : getCondition().isNonNullWhenFalse(var);
+
+  eq WhileStmt.branch().inNullGuard(Variable var, CfgNode succ) =
+      succ == getStmt().entry()
+      ? getCondition().isNonNullWhenTrue(var)
+      : getCondition().isNonNullWhenFalse(var);
+
+  eq EnhancedForStmt.branch().inNullGuard(Variable var, CfgNode succ) = false;
+  eq DoStmt.branch().inNullGuard(Variable var, CfgNode succ) = false;
+  eq SwitchStmt.branch().inNullGuard(Variable var, CfgNode succ) = false;
+
+  /** Returns {@code true} if this set of modifiers includes {@code javax.annotation.Nullable}.  */
+  syn boolean Modifiers.hasNullableAnnotation() = hasAnnotation("javax.annotation", "Nullable");
+
+  /** Return {@code true} if this expression is guarded by a != null check for var.  */
+  inh boolean Expr.hasNullGuard(Variable var);
+  eq Program.getChild().hasNullGuard(Variable var) = false;
+  eq IfStmt.getThen().hasNullGuard(Variable var) = getCondition().isNonNullWhenTrue(var);
+  eq IfStmt.getElse().hasNullGuard(Variable var) = getCondition().isNonNullWhenFalse(var);
+  eq WhileStmt.getStmt().hasNullGuard(Variable var) = getCondition().isNonNullWhenTrue(var);
+  eq ForStmt.getStmt().hasNullGuard(Variable var) = getCondition().isNonNullWhenTrue(var);
+  eq ConditionalExpr.getTrueExpr().hasNullGuard(Variable var) =
+      getCondition().isNonNullWhenTrue(var) || hasNullGuard(var);
+  eq ConditionalExpr.getFalseExpr().hasNullGuard(Variable var) =
+      getCondition().isNonNullWhenFalse(var) || hasNullGuard(var);
+  eq AndLogicalExpr.getRightOperand().hasNullGuard(Variable var) =
+      getLeftOperand().isNonNullWhenTrue(var) || hasNullGuard(var);
+  eq AndBitwiseExpr.getRightOperand().hasNullGuard(Variable var) =
+      getLeftOperand().isNonNullWhenTrue(var) || hasNullGuard(var);
+  eq OrLogicalExpr.getRightOperand().hasNullGuard(Variable var) =
+      getLeftOperand().isNonNullWhenFalse(var) || hasNullGuard(var);
+
+  /** @return {@code true} if the variable var is null when this expression is true. */
+  syn boolean Expr.isNullWhenTrue(Variable var) = false;
+
+  eq NEExpr.isNullWhenTrue(Variable var) =
+      getLeftOperand().isTrue() && getRightOperand().isNullWhenFalse(var)
+      || getRightOperand().isTrue() && getLeftOperand().isNullWhenFalse(var)
+      || getLeftOperand().isFalse() && getRightOperand().isNullWhenTrue(var)
+      || getRightOperand().isFalse() && getLeftOperand().isNullWhenTrue(var);
+
+  eq EQExpr.isNullWhenTrue(Variable var) =
+      getLeftOperand().isNull() && getRightOperand().varDecl() == var
+      || getRightOperand().isNull() && getLeftOperand().varDecl() == var
+      || getLeftOperand().isTrue() && getRightOperand().isNullWhenTrue(var)
+      || getRightOperand().isTrue() && getLeftOperand().isNullWhenTrue(var)
+      || getLeftOperand().isFalse() && getRightOperand().isNullWhenFalse(var)
+      || getRightOperand().isFalse() && getLeftOperand().isNullWhenFalse(var);
+
+  eq LogNotExpr.isNullWhenTrue(Variable var) = getOperand().isNullWhenFalse(var);
+
+  eq ParExpr.isNullWhenTrue(Variable var) = getExpr().isNullWhenTrue(var);
+
+  eq AndLogicalExpr.isNullWhenTrue(Variable var) =
+      getLeftOperand().isNullWhenTrue(var) || getRightOperand().isNullWhenTrue(var);
+
+  eq AndBitwiseExpr.isNullWhenTrue(Variable var) =
+      getLeftOperand().isNullWhenTrue(var) || getRightOperand().isNullWhenTrue(var);
+
+  eq OrLogicalExpr.isNullWhenTrue(Variable var) =
+      getLeftOperand().isFalse() && getRightOperand().isNullWhenTrue(var)
+      || getRightOperand().isFalse() && getLeftOperand().isNullWhenTrue(var);
+
+  eq Dot.isNullWhenTrue(Variable var) =
+      !getLeft().isVariable(var) && getRight().isNullWhenTrue(var);
+
+  // Assume that a method call to X.isNull_(var) is equivalent to a null test on var.
+  eq MethodAccess.isNullWhenTrue(Variable var) =
+      name().startsWith("isNull") && getNumArg() == 1 && getArg(0).isVariable(var);
+
+  eq VarAccess.isNullWhenTrue(Variable var) = decl().isNullWhenTrue(var);
+
+  syn boolean Variable.isNullWhenTrue(Variable var);
+  eq EnumConstant.isNullWhenTrue(Variable var) = false;
+  eq ParameterDeclaration.isNullWhenTrue(Variable var) = false;
+  eq FieldDeclarator.isNullWhenTrue(Variable var) = false;
+  eq CatchParameterDeclaration.isNullWhenTrue(Variable var) = false;
+  eq InferredParameterDeclaration.isNullWhenTrue(Variable var) = false;
+  eq VariableDeclarator.isNullWhenTrue(Variable var) =
+      type().isBoolean() && hasInit() && isEffectivelyFinal()
+      ? getInit().isNullWhenTrue(var)
+      : false;
+
+  /** @return {@code true} if the variable var is null when this expression is false. */
+  syn boolean Expr.isNullWhenFalse(Variable var) = false;
+
+  eq NEExpr.isNullWhenFalse(Variable var) =
+      getLeftOperand().isNull() && getRightOperand().varDecl() == var
+      || getRightOperand().isNull() && getLeftOperand().varDecl() == var
+      || getLeftOperand().isTrue() && getRightOperand().isNullWhenTrue(var)
+      || getRightOperand().isTrue() && getLeftOperand().isNullWhenTrue(var)
+      || getLeftOperand().isFalse() && getRightOperand().isNullWhenFalse(var)
+      || getRightOperand().isFalse() && getLeftOperand().isNullWhenFalse(var);
+
+  eq EQExpr.isNullWhenFalse(Variable var) =
+      getLeftOperand().isTrue() && getRightOperand().isNullWhenFalse(var)
+      || getRightOperand().isTrue() && getLeftOperand().isNullWhenFalse(var)
+      || getLeftOperand().isFalse() && getRightOperand().isNullWhenTrue(var)
+      || getRightOperand().isFalse() && getLeftOperand().isNullWhenTrue(var);
+
+  eq LogNotExpr.isNullWhenFalse(Variable var) = getOperand().isNullWhenTrue(var);
+
+  eq ParExpr.isNullWhenFalse(Variable var) = getExpr().isNullWhenFalse(var);
+
+  eq AndLogicalExpr.isNullWhenFalse(Variable var) =
+      getLeftOperand().isTrue() && getRightOperand().isNullWhenFalse(var)
+      || getRightOperand().isTrue() && getLeftOperand().isNullWhenFalse(var);
+
+  eq AndBitwiseExpr.isNullWhenFalse(Variable var) =
+      getLeftOperand().isTrue() && getRightOperand().isNullWhenFalse(var)
+      || getRightOperand().isTrue() && getLeftOperand().isNullWhenFalse(var);
+
+  eq OrLogicalExpr.isNullWhenFalse(Variable var) =
+      getLeftOperand().isNullWhenFalse(var) && getRightOperand().isNullWhenFalse(var);
+
+  eq Dot.isNullWhenFalse(Variable var) =
+      !getLeft().isVariable(var) && getRight().isNullWhenFalse(var);
+
+  // Assume that a method call to X.isNo{t,n}Null_(var) is equivalent to a non-null test on var.
+  eq MethodAccess.isNullWhenFalse(Variable var) =
+      (name().startsWith("isNotNull") || name().startsWith("isNonNull"))
+      && getNumArg() == 1 && getArg(0).isVariable(var);
+
+  eq VarAccess.isNullWhenFalse(Variable var) = decl().isNullWhenFalse(var);
+
+  syn boolean Variable.isNullWhenFalse(Variable var);
+  eq EnumConstant.isNullWhenFalse(Variable var) = false;
+  eq ParameterDeclaration.isNullWhenFalse(Variable var) = false;
+  eq FieldDeclarator.isNullWhenFalse(Variable var) = false;
+  eq CatchParameterDeclaration.isNullWhenFalse(Variable var) = false;
+  eq InferredParameterDeclaration.isNullWhenFalse(Variable var) = false;
+  eq VariableDeclarator.isNullWhenFalse(Variable var) =
+      type().isBoolean() && hasInit() && isEffectivelyFinal()
+      ? getInit().isNullWhenFalse(var)
+      : false;
+
+  /** @return {@code true} if the variable var is non-null when this expression is true. */
+  syn boolean Expr.isNonNullWhenTrue(Variable var) = false;
+
+  eq NEExpr.isNonNullWhenTrue(Variable var) =
+      getLeftOperand().isNull() && getRightOperand().varDecl() == var
+      || getRightOperand().isNull() && getLeftOperand().varDecl() == var
+      || getLeftOperand().isTrue() && getRightOperand().isNonNullWhenFalse(var)
+      || getRightOperand().isTrue() && getLeftOperand().isNonNullWhenFalse(var)
+      || getLeftOperand().isFalse() && getRightOperand().isNonNullWhenTrue(var)
+      || getRightOperand().isFalse() && getLeftOperand().isNonNullWhenTrue(var);
+
+  eq EQExpr.isNonNullWhenTrue(Variable var) =
+      getLeftOperand().isTrue() && getRightOperand().isNonNullWhenTrue(var)
+      || getRightOperand().isTrue() && getLeftOperand().isNonNullWhenTrue(var)
+      || getLeftOperand().isFalse() && getRightOperand().isNonNullWhenFalse(var)
+      || getRightOperand().isFalse() && getLeftOperand().isNonNullWhenFalse(var);
+
+  eq LogNotExpr.isNonNullWhenTrue(Variable var) = getOperand().isNullWhenTrue(var);
+
+  eq ParExpr.isNonNullWhenTrue(Variable var) = getExpr().isNonNullWhenTrue(var);
+
+  eq AndLogicalExpr.isNonNullWhenTrue(Variable var) =
+      getLeftOperand().isNonNullWhenTrue(var) || getRightOperand().isNonNullWhenTrue(var);
+
+  eq AndBitwiseExpr.isNonNullWhenTrue(Variable var) =
+      getLeftOperand().isNonNullWhenTrue(var) || getRightOperand().isNonNullWhenTrue(var);
+
+  eq OrLogicalExpr.isNonNullWhenTrue(Variable var) =
+      getLeftOperand().isFalse() && getRightOperand().isNonNullWhenTrue(var)
+      || getRightOperand().isFalse() && getLeftOperand().isNonNullWhenTrue(var);
+
+  eq Dot.isNonNullWhenTrue(Variable var) =
+      !getLeft().isVariable(var) && getRight().isNonNullWhenTrue(var);
+
+  // Assume that a method call to X.isNo{t,n}Null_(var) is equivalent to a non-null test on var.
+  eq MethodAccess.isNonNullWhenTrue(Variable var) =
+      (name().startsWith("isNotNull") || name().startsWith("isNonNull"))
+      && getNumArg() == 1 && getArg(0).isVariable(var);
+
+  eq VarAccess.isNonNullWhenTrue(Variable var) = decl().isNonNullWhenTrue(var);
+
+  syn boolean Variable.isNonNullWhenTrue(Variable var);
+  eq EnumConstant.isNonNullWhenTrue(Variable var) = false;
+  eq ParameterDeclaration.isNonNullWhenTrue(Variable var) = false;
+  eq FieldDeclarator.isNonNullWhenTrue(Variable var) = false;
+  eq CatchParameterDeclaration.isNonNullWhenTrue(Variable var) = false;
+  eq InferredParameterDeclaration.isNonNullWhenTrue(Variable var) = false;
+  eq VariableDeclarator.isNonNullWhenTrue(Variable var) =
+      type().isBoolean() && hasInit() && isEffectivelyFinal()
+      ? getInit().isNonNullWhenTrue(var)
+      : false;
+
+  // An instanceof check guards against the variable being null.
+  eq InstanceOfExpr.isNonNullWhenTrue(Variable var) = getExpr().isVariable(var);
+
+  /** @return {@code true} if the variable var is non-null when this expression is false. */
+  syn boolean Expr.isNonNullWhenFalse(Variable var) = false;
+
+  eq NEExpr.isNonNullWhenFalse(Variable var) =
+      getLeftOperand().isTrue() && getRightOperand().isNonNullWhenTrue(var)
+      || getRightOperand().isTrue() && getLeftOperand().isNonNullWhenTrue(var)
+      || getLeftOperand().isFalse() && getRightOperand().isNonNullWhenFalse(var)
+      || getRightOperand().isFalse() && getLeftOperand().isNonNullWhenFalse(var);
+
+  eq EQExpr.isNonNullWhenFalse(Variable var) =
+      getLeftOperand().isNull() && getRightOperand().varDecl() == var
+      || getRightOperand().isNull() && getLeftOperand().varDecl() == var
+      || getLeftOperand().isTrue() && getRightOperand().isNonNullWhenFalse(var)
+      || getRightOperand().isTrue() && getLeftOperand().isNonNullWhenFalse(var)
+      || getLeftOperand().isFalse() && getRightOperand().isNonNullWhenTrue(var)
+      || getRightOperand().isFalse() && getLeftOperand().isNonNullWhenTrue(var);
+
+  eq LogNotExpr.isNonNullWhenFalse(Variable var) = getOperand().isNonNullWhenTrue(var);
+
+  eq ParExpr.isNonNullWhenFalse(Variable var) = getExpr().isNonNullWhenFalse(var);
+
+  eq AndLogicalExpr.isNonNullWhenFalse(Variable var) =
+      getLeftOperand().isTrue() && getRightOperand().isNonNullWhenFalse(var)
+      || getRightOperand().isTrue() && getLeftOperand().isNonNullWhenFalse(var);
+
+  eq AndBitwiseExpr.isNonNullWhenFalse(Variable var) =
+      getLeftOperand().isTrue() && getRightOperand().isNonNullWhenFalse(var)
+      || getRightOperand().isTrue() && getLeftOperand().isNonNullWhenFalse(var);
+
+  eq OrLogicalExpr.isNonNullWhenFalse(Variable var) =
+      getLeftOperand().isNonNullWhenFalse(var) || getRightOperand().isNonNullWhenFalse(var);
+
+  eq Dot.isNonNullWhenFalse(Variable var) =
+      !getLeft().isVariable(var) && getRight().isNonNullWhenFalse(var);
+
+  // Assume that a method call to X.isNull_(var) is equivalent to a null test on var.
+  eq MethodAccess.isNonNullWhenFalse(Variable var) =
+      name().startsWith("isNull") && getNumArg() == 1 && getArg(0).isVariable(var);
+
+  eq VarAccess.isNonNullWhenFalse(Variable var) = decl().isNonNullWhenFalse(var);
+
+  syn boolean Variable.isNonNullWhenFalse(Variable var);
+  eq EnumConstant.isNonNullWhenFalse(Variable var) = false;
+  eq ParameterDeclaration.isNonNullWhenFalse(Variable var) = false;
+  eq FieldDeclarator.isNonNullWhenFalse(Variable var) = false;
+  eq CatchParameterDeclaration.isNonNullWhenFalse(Variable var) = false;
+  eq InferredParameterDeclaration.isNonNullWhenFalse(Variable var) = false;
+  eq VariableDeclarator.isNonNullWhenFalse(Variable var) =
+      type().isBoolean() && hasInit() && isEffectivelyFinal()
+      ? getInit().isNonNullWhenFalse(var)
+      : false;
+
+  syn boolean Expr.isNull() = type().isNull();
+  eq NullLiteral.isNull() = true;
+}
diff --git a/simplecfg/src/main/jastadd/PrintCfg.jrag b/simplecfg/src/main/jastadd/PrintCfg.jrag
new file mode 100644
index 0000000..35b7f87
--- /dev/null
+++ b/simplecfg/src/main/jastadd/PrintCfg.jrag
@@ -0,0 +1,145 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.LinkedList;
+import java.util.Set;
+import java.util.Queue;
+
+/** Helper attributes used to print a CFG in dot graph format. */
+aspect PrintCfg {
+
+  @Override
+  public String CfgNode.toString() {
+    return name();
+  }
+
+  public void BodyDecl.printReverseCfg() {
+    entry().initPredecessors();
+    System.out.println("digraph " + graphName() + " {");
+    exit().printReverseCfg();
+    System.out.println("}");
+  }
+
+  public void CfgNode.printReverseCfg() {
+    Set<CfgNode> visited = Collections.newSetFromMap(new IdentityHashMap<CfgNode, Boolean>());
+    Queue<CfgNode> queue = new LinkedList<CfgNode>();
+
+    // Enqueue this node.
+    visited.add(this);
+    queue.add(this);
+
+    while (!queue.isEmpty()) {
+      CfgNode work = queue.poll();
+
+      System.out.format("  %s%s;\n", work.dotId(), work.dotAttributes());
+
+      // Add all out-edges for this node.
+      for (CfgNode succ : work.predecessors) {
+        System.out.format("  %s -> %s;\n", work.dotId(), succ.dotId());
+        if (!visited.contains(succ)) {
+          visited.add(succ);
+          queue.add(succ);
+        }
+      }
+    }
+  }
+
+  public void BodyDecl.printCfg() {
+    System.out.println("digraph " + graphName() + " {");
+    entry().printCfg();
+    System.out.println("}");
+  }
+
+  public void CfgNode.printCfg() {
+    Set<CfgNode> visited = Collections.newSetFromMap(new IdentityHashMap<CfgNode, Boolean>());
+    Queue<CfgNode> queue = new LinkedList<CfgNode>();
+
+    // Enqueue this node.
+    visited.add(this);
+    queue.add(this);
+
+    while (!queue.isEmpty()) {
+      CfgNode work = queue.poll();
+
+      System.out.format("  %s%s;\n", work.dotId(), work.dotAttributes());
+
+      // Add all out-edges for this node.
+      for (CfgNode succ : work.successors()) {
+        System.out.format("  %s -> %s;\n", work.dotId(), succ.dotId());
+        if (!visited.contains(succ)) {
+          visited.add(succ);
+          queue.add(succ);
+        }
+      }
+    }
+  }
+
+  syn String BodyDecl.graphName() = "";
+  eq MethodDecl.graphName() = name();
+
+  /**
+   * The ID for this node in a dot graph.
+   */
+  syn String CfgNode.dotId() = String.format("n%08X", hashCode());
+
+  // TODO(joqvist): escape string literals in generated labels.
+  syn String CfgNode.dotAttributes() = " [label=\"" + name() + "\"]";
+  eq CfgBranch.dotAttributes() = " [label=\"" + name() + "\",shape=diamond]";
+  eq CfgException.dotAttributes() = " [label=\"" + name() + "\",shape=box]";
+  eq CfgMarker.dotAttributes() = " [label=\"" + name() + "\",shape=box]";
+
+  syn String CfgNode.name();
+  eq CfgBranch.name() = branchLabel();
+  eq CfgEntry.name() = "entry";
+  eq CfgExit.name() = "exit";
+  eq CfgException.name() = "exception";
+  eq CfgMarker.name() = markerName();
+  eq CfgMethodCall.name() = callLabel();
+
+  inh String CfgMethodCall.callLabel();
+  eq MethodAccess.call().callLabel() = name() + "()";
+
+  inh String CfgBranch.branchLabel();
+  eq IfStmt.branch().branchLabel() = "if (" + getCondition().prettyPrint() + ")";
+  eq ConditionalExpr.branch().branchLabel() = "if (" + getCondition().prettyPrint() + ")";
+  eq ForStmt.branch().branchLabel() = "for (" + getCondition().prettyPrint() + ")";
+  eq WhileStmt.branch().branchLabel() = "while (" + getCondition().prettyPrint() + ")";
+  eq DoStmt.branch().branchLabel() = "do_while (" + getCondition().prettyPrint() + ")";
+  eq EnhancedForStmt.branch().branchLabel() = String.format("for (%s %s : %s)",
+      getVariableDecl().getTypeAccess().prettyPrint(),
+      getVariableDecl().getID(),
+      getExpr().prettyPrint());
+  eq SwitchStmt.branch().branchLabel() = "switch (" + getExpr().prettyPrint() + ")";
+
+  inh String CfgMarker.markerName();
+  eq BreakStmt.marker().markerName() = "break";
+  eq ContinueStmt.marker().markerName() = "continue";
+  eq ConditionalExpr.thenEndMarker().markerName() = "then-end";
+  eq ConditionalExpr.elseEndMarker().markerName() = "else-end";
+  eq IfStmt.thenEndMarker().markerName() = "then-end";
+  eq IfStmt.elseEndMarker().markerName() = "else-end";
+  eq ReturnStmt.marker().markerName() = "return";
+  eq TryStmt.tryEntryMarker().markerName() = "try";
+  eq Program.getChild().markerName() = "marker";
+  eq Dot.nullableDereferenceMarker().markerName() = "nullable access";
+  eq ForStmt.loopEndMarker().markerName() = "for-end";
+  eq EnhancedForStmt.loopEndMarker().markerName() = "for-end";
+  eq WhileStmt.loopEndMarker().markerName() = "while-end";
+  eq DoStmt.doEntryMarker().markerName() = "do-entry";
+}
diff --git a/simplecfg/src/main/jastadd/PrintCfgTest.jrag b/simplecfg/src/main/jastadd/PrintCfgTest.jrag
new file mode 100644
index 0000000..cc881f8
--- /dev/null
+++ b/simplecfg/src/main/jastadd/PrintCfgTest.jrag
@@ -0,0 +1,179 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.Set;
+
+import java.util.Collections;
+import java.util.Queue;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.Queue;
+import java.util.LinkedList;
+
+/** Attributes useful for generating a test case from a CFG. */
+aspect PrintCfgTest {
+
+  /** Generate a test case from the CFG of this body decl. */
+  public void BodyDecl.printCfgTest() {
+    CfgNode entry = entry();
+    String className = hostType().name();
+    String testName = className.substring(0, 1).toLowerCase()
+        + className.substring(1);
+    System.out.println("  @Test public void " + testName + "() {");
+    System.out.println("    CfgNode entry = parseCfg(\"" + className + "\");");
+    Queue<CfgNode> work = new LinkedList<CfgNode>();
+    Set<CfgNode> visited = Collections.newSetFromMap(
+        new IdentityHashMap<CfgNode, Boolean>());
+    visited.add(entry);
+    Map<CfgNode, String> vars = new HashMap<CfgNode, String>();
+    vars.put(entry, entry.toString());
+    Map<String, Integer> nextIds = new HashMap<String, Integer>();
+    nextIds.put("entry", 2);
+    work.add(entry);
+    while (!work.isEmpty()) {
+      CfgNode node = work.poll();
+      boolean testSuccs = node.printAssert(visited, vars, nextIds);
+      if (testSuccs) {
+        for (CfgNode succ : node.successors()) {
+          if (!visited.contains(succ)) {
+            visited.add(succ);
+            work.add(succ);
+          }
+        }
+      }
+    }
+    System.out.println("  }");
+  }
+
+  /**
+   * @return {@code true} if successors should be tested.
+   */
+  protected boolean CfgNode.printAssert(
+      Set<CfgNode> visited,
+      Map<CfgNode, String> vars,
+      Map<String, Integer> nextIds) {
+    Set<? extends CfgNode> successors = successors();
+    if (successors.size() == 1) {
+      CfgNode succ = successors.iterator().next();
+      String nodeName = nextVarName(succ.varName(), nextIds);
+      if (!visited.contains(succ)) {
+        vars.put(succ, nodeName);
+        System.out.println(String.format(
+            "    CfgNode %s = succ(%s, \"%s\");",
+            nodeName, vars.get(this), succ.name()));
+      } else {
+        System.out.println(String.format(
+            "    assertThat(succ(%s, \"%s\")).isSameAs(%s);",
+            vars.get(this), succ.name(), vars.get(succ)));
+      }
+    } else if (successors.size() > 1) {
+      boolean duplicates = false;
+      Set<String> dups = new HashSet<String>();
+      for (CfgNode succ : successors) {
+        if (dups.contains(succ.name())) {
+          duplicates = true;
+          break;
+        }
+        dups.add(succ.name());
+      }
+      if (duplicates) {
+        System.out.print(String.format(
+            "    assertThat(%s.successors()).containsExactly(\"",
+            vars.get(this)));
+        boolean first = true;
+        for (CfgNode succ : successors) {
+          if (!first) {
+            System.out.print("\", \"");
+          }
+          first = false;
+          System.out.print(succ.name());
+        }
+        System.out.println("\");");
+        System.out.println(String.format(
+            "    // NOTE Code to test the successors of %s was not "
+            + "auto-generated\n    // due to identical successor names.",
+            vars.get(this)));
+        return false;
+      } else {
+        String arrayName = nextVarName(this.varName() + "Succ", nextIds);
+        System.out.print(String.format(
+            "    CfgNode[] %s = succ(%s",
+            arrayName, vars.get(this)));
+        int index = 0;
+        Map<String, CfgNode> succMap = new HashMap<String, CfgNode>();
+        for (CfgNode succ : successors) {
+          System.out.format(", \"%s\"", succ.name());
+          succMap.put(arrayName + "[" + index + "]", succ);
+          index += 1;
+        }
+        System.out.println(");");
+        for (Map.Entry<String, CfgNode> succ : succMap.entrySet()) {
+          if (!visited.contains(succ.getValue())) {
+            vars.put(succ.getValue(), succ.getKey());
+          } else {
+            System.out.println(String.format(
+                "    assertThat(%s).isSameAs(%s);",
+                succ.getKey(), vars.get(succ.getValue())));
+          }
+        }
+      }
+    }
+    return true;
+  }
+
+  protected static String CfgNode.nextVarName(String name,
+      Map<String, Integer> nextIds) {
+    if (nextIds.containsKey(name)) {
+      int id = nextIds.get(name);
+      nextIds.put(name, id+1);
+      return name + id;
+    } else {
+      nextIds.put(name, 2);
+      return name;
+    }
+  }
+
+  syn String CfgNode.varName() = name();
+  eq CfgBranch.varName() = branchKind() + "Branch";
+  eq CfgException.varName() = "exception";
+  eq CfgMarker.varName() = markerVarName();
+  eq CfgMethodCall.varName() = methodAccess().getID();
+
+  inh String CfgBranch.branchKind();
+  eq IfStmt.branch().branchKind() = "if";
+  eq ConditionalExpr.branch().branchKind() = "if";
+  eq ForStmt.branch().branchKind() = "for";
+  eq WhileStmt.branch().branchKind() = "while";
+  eq DoStmt.branch().branchKind() = "doWhile";
+  eq EnhancedForStmt.branch().branchKind() = "for";
+  eq SwitchStmt.branch().branchKind() = "switch";
+
+  inh String CfgMarker.markerVarName();
+  eq BreakStmt.marker().markerVarName() = "breakMarker";
+  eq ContinueStmt.marker().markerVarName() = "continueMarker";
+  eq ConditionalExpr.thenEndMarker().markerVarName() = "thenEnd";
+  eq ConditionalExpr.elseEndMarker().markerVarName() = "elseEnd";
+  eq IfStmt.thenEndMarker().markerVarName() = "thenEnd";
+  eq IfStmt.elseEndMarker().markerVarName() = "elseEnd";
+  eq ReturnStmt.marker().markerVarName() = "returnMarker";
+  eq TryStmt.tryEntryMarker().markerVarName() = "tryEntry";
+  eq Program.getChild().markerVarName() = "marker";
+  eq Dot.nullableDereferenceMarker().markerVarName() = "nullable";
+  eq ForStmt.loopEndMarker().markerVarName() = "forEnd";
+  eq EnhancedForStmt.loopEndMarker().markerVarName() = "forEnd";
+  eq WhileStmt.loopEndMarker().markerVarName() = "whileEnd";
+  eq DoStmt.doEntryMarker().markerVarName() = "doEntry";
+}
diff --git a/simplecfg/src/main/jastadd/SimpleCFG.jrag b/simplecfg/src/main/jastadd/SimpleCFG.jrag
new file mode 100644
index 0000000..162622b
--- /dev/null
+++ b/simplecfg/src/main/jastadd/SimpleCFG.jrag
@@ -0,0 +1,791 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Attributes to build a simplified Control Flow Graph (CFG) for a methods,
+ * constructors, and initializers.
+ *
+ * <p>The simple CFG contains only method calls and branches. The simple CFG has
+ * a naive exception model - any exception is assumed to be throwable by any
+ * statement.
+ */
+aspect SimpleCFG {
+
+  /** @return {@code true} if this node corresponds to a method call. */
+  syn boolean CfgNode.isCall() = false;
+  eq CfgMethodCall.isCall() = true;
+
+  /** @return {@code true} if this node corresponds to an exception branch. */
+  syn boolean CfgNode.isException() = false;
+  eq CfgException.isException() = true;
+
+  /** @return {@code true} if this node corresponds to a branch. */
+  syn boolean CfgNode.isBranch() = false;
+  eq CfgBranch.isBranch() = true;
+
+  /**
+   * Successor nodes in the CFG.
+   */
+  syn lazy Set<? extends CfgNode> CfgNode.successors();
+
+  eq CfgEntry.successors() = Collections.singleton(getSucc());
+
+  eq CfgExit.successors() = Collections.emptySet();
+
+  eq CfgMethodCall.successors() = succ();
+
+  eq CfgBranch.successors() = succ();
+
+  eq CfgException.successors() = succ();
+
+  eq CfgMarker.successors() = succ();
+
+  /**
+   * Set that contains either one or two unique objects. The objects are
+   * compared with reference equality.
+   */
+  class IdentityTupleSet<E> implements Set<E> {
+    final E a, b;
+
+    public IdentityTupleSet(E a, E b) {
+      this.a = a;
+      this.b = b;
+    }
+
+    @Override
+    public boolean add(E e) {
+      throw new UnsupportedOperationException();
+    }
+    @Override
+    public boolean addAll(Collection<? extends E> e) {
+      throw new UnsupportedOperationException();
+    }
+    @Override
+    public void clear() {
+      throw new UnsupportedOperationException();
+    }
+    @Override
+    public boolean contains(Object o) {
+      return o == a || o == b;
+    }
+    @Override
+    public boolean containsAll(Collection<?> c) {
+      for (Object o : c) {
+        if (!contains(o)) {
+          return false;
+        }
+      }
+      return true;
+    }
+    @Override
+    public int hashCode() {
+      return a.hashCode() + b.hashCode();
+    }
+    @Override
+    public boolean isEmpty() {
+      return false;
+    }
+    @Override
+    public Iterator<E> iterator() {
+      return new Iterator<E>() {
+        int index = 0;
+        @Override
+        public boolean hasNext() {
+          return (a == b && index < 1)
+              || (a != b && index < 2);
+        }
+        @Override
+        public E next() {
+          return ++index == 1 ? a : b;
+        }
+        @Override
+        public void remove() {
+          throw new UnsupportedOperationException();
+        }
+      };
+    }
+    @Override
+    public boolean remove(Object o) {
+      throw new UnsupportedOperationException();
+    }
+    @Override
+    public boolean removeAll(Collection<?> c) {
+      throw new UnsupportedOperationException();
+    }
+    @Override
+    public boolean retainAll(Collection<?> c) {
+      throw new UnsupportedOperationException();
+    }
+    @Override
+    public int size() {
+      return a == b ? 1 : 2;
+    }
+    @Override
+    public Object[] toArray() {
+      return new Object[] { a, b };
+    }
+    @Override
+    public <T> T[] toArray(T[] array) {
+      array[0] = (T) a;
+      array[1] = (T) b;
+      return array;
+    }
+    @Override
+    public String toString() {
+      if (a == b) {
+        return "[" + a + "]";
+      } else {
+        return "[" + a + ", " + b + "]";
+      }
+    }
+  }
+
+  /** Successors to this branch node. */
+  inh Set<? extends CfgNode> CfgBranch.succ();
+
+  /** Successors to this method call node. */
+  inh Set<? extends CfgNode> CfgMethodCall.succ();
+
+  inh Set<? extends CfgNode> CfgException.succ();
+
+  inh Set<? extends CfgNode> CfgMarker.succ();
+
+  /** Build a small set with two elements. */
+  public <T> Set<T> ASTNode.smallSet(T a, T b) {
+    return new IdentityTupleSet<T>(a, b);
+  }
+
+  /**
+   * The entry CFG node of this statement. This is the next method call,
+   * branch, or exit node of the simplified CFG following the entry of
+   * this statement.
+   */
+  syn CfgNode Stmt.entry() = follow();
+
+  /**
+   * Find the next CFG node representing the next branch, or the next
+   * method access following this statement.
+   */
+  inh CfgNode Stmt.follow();
+
+  inh CfgNode Expr.follow();
+
+  // Needed for completeness, but never used by anything relevant.
+  eq Program.getChild().follow() = new CfgExit();
+
+  /**
+   * The entry node in a filtered CFG.
+   */
+  syn lazy CfgEntry BodyDecl.entry() = new CfgEntry(exit());
+
+  eq MethodDecl.entry() =
+      hasBlock()
+      ?  new CfgEntry(getBlock().entry())
+      : new CfgEntry(exit());
+
+  eq ConstructorDecl.entry() = new CfgEntry(getBlock().entry());
+
+  eq InstanceInitializer.entry() = new CfgEntry(getBlock().entry());
+
+  eq StaticInitializer.entry() = new CfgEntry(getBlock().entry());
+
+  /**
+   * The exit node in a filtered CFG.
+   */
+  syn nta CfgExit BodyDecl.exit() = new CfgExit();
+
+  eq Block.entry() {
+    if (getNumStmt() > 0) {
+      return getStmt(0).entry();
+    } else {
+      return follow();
+    }
+  }
+
+  eq LabeledStmt.entry() = getStmt().entry();
+
+  eq VarDeclStmt.entry() =
+      getNumDeclarator() > 0
+      ? getDeclarator(0).entry()
+      : follow();
+
+  eq VarDeclStmt.getDeclarator(int index).follow() =
+      index + 1 < getNumDeclarator()
+      ? getDeclarator(index + 1).entry()
+      : follow();
+
+  inh CfgNode VariableDeclarator.follow();
+
+  syn CfgNode VariableDeclarator.entry() =
+      hasInit()
+      ? getInit().entry()
+      : follow();
+
+  eq SynchronizedStmt.entry() = getExpr().entry();
+
+  eq SynchronizedStmt.getExpr().follow() = getBlock().entry();
+
+  // Note: catch-all clauses get special treatment!
+
+  eq TryStmt.entry() = tryEntryMarker();
+
+  eq TryWithResources.entry() =
+      getNumResource() > 0
+      ? getResource(0).entry()
+      : super.entry();
+
+  eq TryWithResources.getResource(int index).follow() =
+      index+1 < getNumResource()
+      ? getResource(index+1).entry()
+      : super.entry();
+
+  /**
+   * The entry of a try statement has a branch to the block and to each
+   * catch clause or finally block.
+   */
+  syn nta CfgMarker TryStmt.tryEntryMarker() = new CfgMarker();
+
+  eq TryStmt.tryEntryMarker().succ() =
+      joinSets(Collections.singleton(getBlock().entry()), catchBranches());
+
+  eq MethodAccess.exceptionNode().succ() = exceptionBranches();
+
+  eq ThrowStmt.exceptionNode().succ() = exceptionBranches();
+
+  /**
+   * Gives the set of CFG nodes targeted by an exception thrown at this
+   * statement. This includes the catch blocks of the enclosing try statement as
+   * well as the finally block. Does not include any targets following a
+   * catch of Throwable.
+   */
+  inh Set<? extends CfgNode> MethodAccess.exceptionBranches();
+  inh Set<? extends CfgNode> TryStmt.exceptionBranches();
+  inh Set<? extends CfgNode> ThrowStmt.exceptionBranches();
+
+  inh TypeDecl TryStmt.typeThrowable();
+
+  eq TryStmt.getBlock().exceptionBranches() = catchBranches();
+
+  eq TryWithResources.getResource().exceptionBranches() = catchBranches();
+
+  /**
+   * Gives the set of CFG nodes targeted by an exception thrown inside this try
+   * statement. This includes the catch blocks of this try statements as
+   * well as the finally block. Does not include any targets following a
+   * catch of Throwable.
+   */
+  syn Set<? extends CfgNode> TryStmt.catchBranches() {
+    // Check for catch-all clauses (catching java.lang.Throwable).
+    Set<CfgNode> set = Collections.newSetFromMap(new IdentityHashMap<CfgNode, Boolean>());
+    for (CatchClause clause : getCatchClauseList()) {
+      set.add(clause.getBlock().entry());
+      if (clause instanceof BasicCatch
+          && ((BasicCatch) clause).getParameter().type() == typeThrowable()) {
+        // This is a catch-all clause: no other clauses after this can catch an
+        // exception.
+        return set;
+      }
+    }
+    if (hasNonEmptyFinally()) {
+      set.add(getExceptionHandler().entry());
+    }
+    return set;
+  }
+
+  eq TryStmt.getExceptionHandler().follow() = exceptionNode();
+  eq TryStmt.exceptionNode().succ() = exceptionBranches();
+
+  eq BodyDecl.getChild().exceptionBranches() = Collections.singleton(exit());
+
+  eq CompilationUnit.getChild().exceptionBranches() = Collections.emptySet();
+  eq TypeDecl.getChild().exceptionBranches() = Collections.emptySet();
+
+  public <U, V extends U> Set<U> Stmt.joinSets(Set<U> a, Set<V> b) {
+    Set<U> set = Collections.newSetFromMap(
+        new IdentityHashMap<U, Boolean>());
+    set.addAll(a);
+    set.addAll(b);
+    return set;
+  }
+
+  eq TryStmt.getBlock().follow() =
+      hasNonEmptyFinally()
+      ? getFinally().entry()
+      : follow();
+
+  eq TryStmt.getCatchClause(int index).follow() =
+      hasNonEmptyFinally()
+      ? getFinally().entry()
+      : follow();
+
+  /** The CFG marker for this break statement.  */
+  syn nta CfgMarker BreakStmt.marker() = new CfgMarker();
+
+  eq BreakStmt.entry() = marker();
+  eq BreakStmt.marker().succ() =
+      hasFinally()
+      ? Collections.singleton(getFinally().entry())
+      : Collections.singleton(targetStmt().follow());
+  eq BreakStmt.marker().follow() =
+      hasFinally()
+      ? getFinally().entry()
+      : targetStmt().follow();
+
+  eq BreakStmt.getFinally().follow() = targetStmt().follow();
+
+  /** The CFG marker for this continue statement.  */
+  syn nta CfgMarker ContinueStmt.marker() = new CfgMarker();
+
+  eq ContinueStmt.entry() = marker();
+  eq ContinueStmt.marker().succ() =
+      hasFinally()
+      ? Collections.singleton(getFinally().entry())
+      : Collections.singleton(targetStmt().entry());
+  eq ContinueStmt.marker().follow() =
+      hasFinally()
+      ? getFinally().entry()
+      : targetStmt().entry();
+
+  eq ContinueStmt.getFinally().follow() = targetStmt().follow();
+
+  /** The CFG marker for this continue statement.  */
+  syn nta CfgMarker ReturnStmt.marker() = new CfgMarker();
+
+  eq ReturnStmt.entry() = marker();
+  eq ReturnStmt.marker().succ() =
+      hasResult()
+      ? Collections.singleton(getResult().entry())
+      : Collections.singleton(returnTarget());
+  eq ReturnStmt.marker().follow() =
+      hasResult()
+      ? getResult().entry()
+      : returnTarget();
+
+  eq ReturnStmt.getResult().follow() = returnTarget();
+
+  inh CompilationUnit ReturnStmt.compilationUnit();
+
+  syn CfgNode ReturnStmt.returnTarget() =
+      hasFinally()
+      ? getFinally().entry()
+      : methodExit();
+
+  eq ReturnStmt.getFinally().follow() = methodExit();
+
+  /**
+   * Finds the CFG exit node for the enclosing method, constructor, or
+   * initializer.
+   */
+  inh CfgNode ReturnStmt.methodExit();
+
+  eq BodyDecl.getChild().methodExit() = exit();
+
+  eq LambdaBody.getChild().methodExit() = exit();
+
+  eq ThrowStmt.entry() = getExpr().entry();
+
+  // Since we not have precise type lookups we need to approximate the possible
+  // exception branches.
+  eq ThrowStmt.getExpr().follow() = exceptionNode();
+
+  /**
+   * This node represents the control flow path taken when an exception
+   * interrupts the call.
+   */
+  syn nta CfgException MethodAccess.exceptionNode() = new CfgException();
+
+  /** This node represents the control flow following the exception.  */
+  syn nta CfgException ThrowStmt.exceptionNode() = new CfgException();
+
+  /**
+   * This node represents the control flow path taken if an exception
+   * is thrown in the start of a try statement.
+   */
+  syn nta CfgException TryStmt.exceptionNode() = new CfgException();
+
+  eq ExprStmt.entry() = getExpr().entry();
+
+  syn CfgNode Expr.entry();
+
+  eq ArrayAccess.entry() = getExpr().entry();
+
+  // All of these nodes are uninteresting for the simple CFG.
+  // Setting entry() = follow() makes sure the node is not included in the CFG.
+  eq AbstractWildcard.entry() = follow();
+  eq ClassAccess.entry() = follow();
+  eq DiamondAccess.entry() = follow();
+  eq PackageAccess.entry() = follow();
+  eq ParseName.entry() = follow(); // Always rewritten.
+  eq ParTypeAccess.entry() = follow();
+  eq SuperAccess.entry() = follow();
+  eq ThisAccess.entry() = follow();
+  eq VarAccess.entry() = follow();
+  eq TypeAccess.entry() = follow();
+  eq SyntheticTypeAccess.entry() = follow();
+  eq ClassReference.entry() = follow();
+  eq ArrayReference.entry() = follow();
+  eq LambdaExpr.entry() = follow();
+  eq TypeMethodReference.entry() = follow();
+  eq AmbiguousMethodReference.entry() = follow();
+
+  eq ParExpr.entry() = getExpr().entry();
+  eq CastExpr.entry() = getExpr().entry();
+  eq IntersectionCastExpr.entry() = getExpr().entry();
+  eq Unary.entry() = getOperand().entry();
+
+  eq ExprMethodReference.entry() = getExpr().entry();
+
+  /** The method call node for this method access. */
+  syn nta CfgMethodCall MethodAccess.call() = new CfgMethodCall();
+
+  eq MethodAccess.call().succ() =
+      isInsideTryBlockOrResource()
+      ? smallSet(exceptionNode(), follow())
+      : Collections.singleton(follow());
+
+  // If there are arguments control flow passes to the arguments first.
+  eq MethodAccess.entry() =
+      getNumArg() > 0
+      ? getArg(0).entry()
+      : call();
+
+  // If we have arguments the CfgMethodCall is placed after the last argument.
+  eq MethodAccess.getArg(int index).follow() =
+      index+1 < getNumArg()
+      ? getArg(index+1).entry()
+      : call();
+
+  // If there are arguments control flow passes to the arguments first.
+  eq ConstructorAccess.entry() =
+      getNumArg() > 0
+      ? getArg(0).entry()
+      : follow();
+
+  // If we have arguments the CfgMethodCall is placed after the last argument.
+  eq ConstructorAccess.getArg(int index).follow() =
+      index+1 < getNumArg()
+      ? getArg(index+1).entry()
+      : follow();
+
+  eq ClassInstanceExpr.entry() =
+      getNumArg() > 0
+      ? getArg(0).entry()
+      : getAccess().entry();
+
+  eq ClassInstanceExpr.getArg(int index).follow() =
+      index+1 < getNumArg()
+      ? getArg(index+1).entry()
+      : getAccess().entry();
+
+  eq ArrayInit.entry() =
+      getNumInit() > 0
+      ? getInit(0).entry()
+      : follow();
+
+  eq ArrayInit.getInit(int index).follow() =
+      index+1 < getNumInit()
+      ? getInit(index+1).entry()
+      : follow();
+
+  /** @return {@code true} if this statement is inside a try block. */
+  inh boolean MethodAccess.isInsideTryBlockOrResource();
+  inh boolean Stmt.isInsideTryBlockOrResource();
+
+  eq CompilationUnit.getChild().isInsideTryBlockOrResource() = false;
+  eq TypeDecl.getChild().isInsideTryBlockOrResource() = false;
+  eq BodyDecl.getChild().isInsideTryBlockOrResource() = false;
+  eq LambdaBody.getChild().isInsideTryBlockOrResource() = false;
+  eq TryStmt.getBlock().isInsideTryBlockOrResource() = true;
+  eq TryWithResources.getResource().isInsideTryBlockOrResource() = true;
+  eq NTAFinallyBlock.getChild().isInsideTryBlockOrResource() =
+      origin.getFinallyBlock().isInsideTryBlockOrResource();
+  eq Program.getChild().isInsideTryBlockOrResource() = false;
+
+  eq InstanceOfExpr.entry() = getExpr().entry();
+
+  eq AssignExpr.entry() = getSource().entry();
+
+  eq AssignExpr.getSource().follow() = getDest().entry();
+
+  eq Literal.entry() = follow();
+
+  eq ArrayCreationExpr.entry() =
+      hasArrayInit()
+      ? getArrayInit().entry()
+      : follow();
+
+  eq Binary.entry() = getLeftOperand().entry();
+  eq Binary.getLeftOperand().follow() = getRightOperand().entry();
+
+  eq Dot.entry() = getLeft().entry();
+  eq Dot.getLeft().follow() = getRight().entry();
+
+  /** The branch node for this conditional expression. */
+  syn nta CfgBranch ConditionalExpr.branch() = new CfgBranch();
+
+  /**
+   * The then-end node is a marker node marking the end of a then-branch in a conditional
+   * expression.
+   */
+  syn nta CfgMarker ConditionalExpr.thenEndMarker() = new CfgMarker();
+
+  /**
+   * The else-end node is a marker node marking the end of a else-branch in a conditional
+   * expression.
+   */
+  syn nta CfgMarker ConditionalExpr.elseEndMarker() = new CfgMarker();
+
+  eq ConditionalExpr.entry() = getCondition().entry();
+  eq ConditionalExpr.getCondition().follow() = branch();
+  eq ConditionalExpr.getTrueExpr().follow() = thenEndMarker();
+  eq ConditionalExpr.getFalseExpr().follow() = elseEndMarker();
+  eq ConditionalExpr.thenEndMarker().follow() = follow();
+  eq ConditionalExpr.elseEndMarker().follow() = follow();
+  eq ConditionalExpr.thenEndMarker().succ() = Collections.singleton(follow());
+  eq ConditionalExpr.elseEndMarker().succ() = Collections.singleton(follow());
+
+  eq ConditionalExpr.branch().succ() =
+      smallSet(getTrueExpr().entry(), getFalseExpr().entry());
+
+  /** The branch node for this statement. */
+  syn nta CfgBranch IfStmt.branch() = new CfgBranch();
+
+  /** The then-end node is a marker node marking the end of a then-branch in an if statement.  */
+  syn nta CfgMarker IfStmt.thenEndMarker() = new CfgMarker();
+
+  /** The else-end node is a marker node marking the end of a else-branch in an if statement.  */
+  syn nta CfgMarker IfStmt.elseEndMarker() = new CfgMarker();
+
+  eq IfStmt.entry() = getCondition().entry();
+
+  eq IfStmt.getCondition().follow() = branch();
+  eq IfStmt.getThen().follow() = thenEndMarker();
+  eq IfStmt.getElse().follow() = elseEndMarker();
+  eq IfStmt.thenEndMarker().follow() = follow();
+  eq IfStmt.elseEndMarker().follow() = follow();
+  eq IfStmt.thenEndMarker().succ() = Collections.singleton(follow());
+  eq IfStmt.elseEndMarker().succ() = Collections.singleton(follow());
+
+  eq IfStmt.branch().succ() =
+      hasElse()
+      ? smallSet(getThen().entry(), getElse().entry())
+      : smallSet(getThen().entry(), follow());
+
+  /** The branch node for this statement. */
+  syn nta CfgBranch ForStmt.branch() = new CfgBranch();
+
+  /** The CFG end marker for this loop. */
+  syn nta CfgMarker ForStmt.loopEndMarker() = new CfgMarker();
+
+  eq ForStmt.entry() =
+      getNumInitStmt() > 0
+      ? getInitStmt(0).entry()
+      : getCondition().entry();
+
+  eq ForStmt.getInitStmt(int index).follow() =
+      index+1 < getNumInitStmt()
+      ? getInitStmt(index+1).entry()
+      : getCondition().entry();
+
+  eq ForStmt.getCondition().follow() = branch();
+
+  eq ForStmt.getUpdateStmt(int index).follow() =
+      index+1 < getNumUpdateStmt()
+      ? getUpdateStmt(index+1).entry()
+      : getCondition().entry();
+
+  eq ForStmt.getStmt().follow() = loopEndMarker();
+
+  eq ForStmt.loopEndMarker().follow() =
+      getNumUpdateStmt() > 0
+      ? getUpdateStmt(0).entry()
+      : getCondition().entry();
+
+  eq ForStmt.loopEndMarker().succ() =
+      getNumUpdateStmt() > 0
+      ? Collections.singleton(getUpdateStmt(0).entry())
+      : Collections.singleton(getCondition().entry());
+
+  eq ForStmt.branch().succ() {
+    if (getCondition().isTrue()) {
+      return Collections.singleton(getStmt().entry());
+    } else if (getCondition().isFalse()) {
+      return Collections.singleton(follow());
+    } else {
+      return smallSet(getStmt().entry(), follow());
+    }
+  }
+
+  /** The branch node for this statement. */
+  syn nta CfgBranch EnhancedForStmt.branch() = new CfgBranch();
+
+  /** The CFG end marker for this loop. */
+  syn nta CfgMarker EnhancedForStmt.loopEndMarker() = new CfgMarker();
+
+  eq EnhancedForStmt.branch().succ() =
+      smallSet(getStmt().entry(), follow());
+
+  eq EnhancedForStmt.entry() = getExpr().entry();
+
+  eq EnhancedForStmt.getExpr().follow() = branch();
+
+  eq EnhancedForStmt.getStmt().follow() = loopEndMarker();
+
+  eq EnhancedForStmt.loopEndMarker().follow() = entry(); // Loop back.
+
+  eq EnhancedForStmt.loopEndMarker().succ() = Collections.singleton(entry());
+
+  /** The branch node for this statement. */
+  syn nta CfgBranch WhileStmt.branch() = new CfgBranch();
+
+  /** The CFG end marker for this loop. */
+  syn nta CfgMarker WhileStmt.loopEndMarker() = new CfgMarker();
+
+  eq WhileStmt.entry() = getCondition().entry();
+
+  eq WhileStmt.getCondition().follow() = branch();
+
+  eq WhileStmt.getStmt().follow() = loopEndMarker();
+
+  eq WhileStmt.loopEndMarker().follow() = entry(); // Loop back.
+
+  eq WhileStmt.loopEndMarker().succ() = Collections.singleton(entry());
+
+  eq WhileStmt.branch().succ() {
+    if (getCondition().isTrue()) {
+      return Collections.singleton(getStmt().entry());
+    } else if (getCondition().isFalse()) {
+      return Collections.singleton(follow());
+    } else {
+      return smallSet(getStmt().entry(), follow());
+    }
+  }
+
+  /** The branch node for this statement. */
+  syn nta CfgBranch DoStmt.branch() = new CfgBranch();
+
+  /** The CFG entry marker for this loop. */
+  syn nta CfgMarker DoStmt.doEntryMarker() = new CfgMarker();
+
+  eq DoStmt.entry() = doEntryMarker();
+
+  eq DoStmt.doEntryMarker().follow() = getStmt().entry();
+
+  eq DoStmt.doEntryMarker().succ() = Collections.singleton(getStmt().entry());
+
+  eq DoStmt.getStmt().follow() = getCondition().entry();
+
+  eq DoStmt.getCondition().follow() = branch();
+
+  // Loop back.
+  eq DoStmt.branch().succ() {
+    if (getCondition().isTrue()) {
+      return Collections.singleton(entry());
+    } else if (getCondition().isFalse()) {
+      return Collections.singleton(follow());
+    } else {
+      return smallSet(entry(), follow());
+    }
+  }
+
+  syn nta CfgBranch SwitchStmt.branch() = new CfgBranch();
+
+  eq SwitchStmt.entry() = getExpr().entry();
+
+  eq SwitchStmt.getExpr().follow() = branch();
+
+  eq SwitchStmt.branch().succ() {
+    Set<CfgNode> set = Collections.newSetFromMap(
+        new IdentityHashMap<CfgNode, Boolean>());
+    boolean hasDefault = false;
+    for (Stmt stmt : getBlock().getStmtList()) {
+      if (stmt instanceof Case) {
+        set.add(stmt.entry());
+        if (stmt instanceof DefaultCase) {
+          hasDefault = true;
+        }
+      }
+    }
+    if (!hasDefault) {
+      set.add(follow());
+    }
+    return set;
+  }
+
+  eq BodyDecl.getChild().follow() = exit();
+
+  eq Block.getStmt(int index).follow() =
+      index+1 < getNumStmt()
+      ? getStmt(index+1).entry()
+      : follow();
+
+  syn lazy CfgEntry LambdaBody.entry();
+  eq BlockLambdaBody.entry() = new CfgEntry(getBlock().entry());
+  eq ExprLambdaBody.entry() = new CfgEntry(getExpr().entry());
+
+  syn nta CfgExit LambdaBody.exit() = new CfgExit();
+
+  eq BlockLambdaBody.getBlock().follow() = exit();
+  eq ExprLambdaBody.getExpr().follow() = exit();
+
+  /** Find the method access which this call node is associated with. */
+  inh MethodAccess CfgMethodCall.methodAccess();
+  eq MethodAccess.call().methodAccess() = this;
+
+  /** Find the entry node to the CFG this statement belongs to.  */
+  inh lazy CfgEntry Stmt.cfg();
+  inh lazy CfgEntry Expr.cfg();
+
+  eq BodyDecl.getChild().cfg() = entry();
+  eq LambdaBody.getChild().cfg() = entry();
+
+  eq CompilationUnit.getChild().cfg() {
+    throw new Error("Not in a CFG.");
+  }
+
+  /**
+   * Predecessors of this node in the CFG.  Predecessors are filled in when
+   * accessing the CFG through the cfg() attribute.
+   */
+  protected Collection<CfgNode> CfgNode.predecessors =
+      new LinkedList<CfgNode>();
+
+  private boolean CfgEntry.initializedPredecessors = false;
+
+  /** Initializes the predecessor sets for each node in a CFG. */
+  protected void CfgEntry.initPredecessors() {
+    if (!initializedPredecessors) {
+      initializedPredecessors = true;
+      Queue<CfgNode> queue = new LinkedList<CfgNode>();
+      queue.add(this);
+      while (!queue.isEmpty()) {
+        CfgNode node = queue.poll();
+        for (CfgNode succ : node.successors()) {
+          if (succ.predecessors.isEmpty()) {
+            queue.add(succ);
+          }
+          succ.predecessors.add(node);
+        }
+      }
+    }
+  }
+}
diff --git a/simplecfg/src/main/jastadd/VariableDeclarationScope.jrag b/simplecfg/src/main/jastadd/VariableDeclarationScope.jrag
new file mode 100644
index 0000000..653d511
--- /dev/null
+++ b/simplecfg/src/main/jastadd/VariableDeclarationScope.jrag
@@ -0,0 +1,75 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This aspect adds attributes to check if a variable was declared inside an a statement represented
+ * by a particular CFG node.
+ */
+aspect VariableDeclarationScope {
+
+  /** @return {@code true} if this method access has the given variable as receiver. */
+  syn boolean MethodAccess.hasReceiver(Variable receiver) =
+      hasPrevExpr() && prevExpr().isVariable(receiver);
+
+  /**
+   * Test if the CFG node is tied to a statement that declares the variable,
+   * or if the declaration of the variable is somewhere inside the statement this
+   * branch represents.
+   */
+  syn boolean CfgNode.isDeclarationOf(Variable var) = false;
+
+  eq CfgBranch.isDeclarationOf(Variable var) =
+      branchDeclaresVariable(var)
+      || variableDeclaredInsideStatement(var);
+
+  syn boolean CfgBranch.variableDeclaredInsideStatement(Variable var) {
+    Stmt stmt = hostStatement();
+    ASTNode node = (ASTNode) var;
+    while (node != stmt && node != null) {
+      node = node.getParent();
+    }
+    return node == stmt;
+  }
+
+  /** The statement this branch represents.  */
+  inh Stmt CfgBranch.hostStatement();
+
+  /** The statement this expression is part of.  */
+  inh Stmt Expr.hostStatement();
+  eq Stmt.getChild().hostStatement() = this;
+  eq Program.getChild().hostStatement() = null;
+
+  eq IfStmt.branch().hostStatement() = this;
+  eq ConditionalExpr.branch().hostStatement() = hostStatement();
+  eq ForStmt.branch().hostStatement() = this;
+  eq WhileStmt.branch().hostStatement() = this;
+  eq DoStmt.branch().hostStatement() = this;
+  eq EnhancedForStmt.branch().hostStatement() = this;
+  eq SwitchStmt.branch().hostStatement() = this;
+
+  /** Test if the CFG node is tied to a statement that declares the variable. */
+  inh boolean CfgBranch.branchDeclaresVariable(Variable var);
+
+  eq EnhancedForStmt.branch().branchDeclaresVariable(Variable var) =
+      getVariableDecl() == var;
+  eq IfStmt.branch().branchDeclaresVariable(Variable var) = false;
+  eq ConditionalExpr.branch().branchDeclaresVariable(Variable var) = false;
+  eq ForStmt.branch().branchDeclaresVariable(Variable var) = false;
+  eq WhileStmt.branch().branchDeclaresVariable(Variable var) = false;
+  eq DoStmt.branch().branchDeclaresVariable(Variable var) = false;
+  eq SwitchStmt.branch().branchDeclaresVariable(Variable var) = false;
+
+}
diff --git a/simplecfg/src/main/java/com/google/simplecfg/ExtendJAnalyzerFrontend.java b/simplecfg/src/main/java/com/google/simplecfg/ExtendJAnalyzerFrontend.java
new file mode 100644
index 0000000..fb9ad9d
--- /dev/null
+++ b/simplecfg/src/main/java/com/google/simplecfg/ExtendJAnalyzerFrontend.java
@@ -0,0 +1,155 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.simplecfg;
+
+import org.extendj.ast.*;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * Produces findings using analyzers implemented in the ExtendJ compiler.
+ */
+public class ExtendJAnalyzerFrontend extends Frontend {
+
+  private final JavaParser javaParser;
+  private final BytecodeReader bytecodeReader;
+  private final Collection<ExtendJFinding> findings = new ArrayList<ExtendJFinding>();
+
+  /** Create new analyzer instance.  */
+  public ExtendJAnalyzerFrontend() {
+    super("ExtendJ Analyzer", "v1.0");
+    javaParser = new JavaParser() {
+      @Override
+      public CompilationUnit parse(InputStream is, String fileName)
+          throws IOException, beaver.Parser.Exception {
+        return new org.extendj.parser.JavaParser().parse(is, fileName);
+      }
+    };
+    bytecodeReader = new BytecodeReader() {
+      @Override
+      public CompilationUnit read(InputStream is, String fullName, Program p)
+          throws FileNotFoundException, IOException {
+        return new BytecodeParser(is, fullName).parse(null, null, p);
+      }
+    };
+  }
+
+  /**
+   * Analyze a single file for findings and return the findings in a collection.
+   */
+  public static Collection<ExtendJFinding> analyzeFile(final String path) throws Error {
+    ExtendJAnalyzerFrontend checker = new ExtendJAnalyzerFrontend();
+    int result = checker.run(new String[]{path});
+    if (result != EXIT_SUCCESS) {
+      throw new Error("exit code: " + result);
+    }
+    return checker.findings;
+  }
+
+  /**
+   * Returns the list of findings from the analyzed source files.
+   *
+   * <p>Used by ExtendJAnalyzerMain to print the generated findings on stdout.
+   */
+  Collection<ExtendJFinding> getFindings() {
+    return findings;
+  }
+
+  /**
+   * Run the Java checker.
+   * @param args command-line arguments
+   * @return 0 on success, 1 on error, 2 on configuration error, 3 on system
+   */
+  public int run(String args[]) {
+    return run(args, bytecodeReader, javaParser);
+  }
+
+  @Override
+  protected int processCompilationUnit(CompilationUnit unit) {
+    if (unit.fromSource()) {
+      findings.addAll(unit.findings());
+    }
+    return EXIT_SUCCESS;
+  }
+
+  @Override
+  public int run(String[] args, BytecodeReader reader, JavaParser parser) {
+    program.resetStatistics();
+    program.setTypeLookupFilter(Program.ANALYZER_TYPE_FILTER);
+    program.initBytecodeReader(bytecodeReader);
+    program.initJavaParser(javaParser);
+
+    initOptions();
+    int argResult = processArgs(args);
+    if (argResult != 0) {
+      return argResult;
+    }
+
+    if (program.options().hasOption("-version")) {
+      printVersion();
+      return EXIT_SUCCESS;
+    }
+
+    Collection<String> files = program.options().files();
+    if (program.options().hasOption("-help") || files.isEmpty()) {
+      printUsage();
+      return EXIT_SUCCESS;
+    }
+
+    return run(files);
+  }
+
+  private int run(Collection<String> files) {
+    try {
+      for (String file : files) {
+        // Calling addSourceFile will parse the file and add it to the program AST.
+        program.addSourceFile(file);
+      }
+
+      // Process source compilation units.
+      int compileResult = EXIT_SUCCESS;
+
+      Iterator<CompilationUnit> iter = program.compilationUnitIterator();
+      while (iter.hasNext()) {
+        CompilationUnit unit = iter.next();
+        int result = processCompilationUnit(unit);
+        if (result != EXIT_SUCCESS) {
+          compileResult = result;
+          if (compileResult == EXIT_UNHANDLED_ERROR) {
+            // Stop immediately when an unhandled error is encountered.
+            return compileResult;
+          }
+        }
+      }
+
+      if (compileResult != EXIT_SUCCESS) {
+        return compileResult;
+      }
+    } catch (IOException e) {
+      throw new Error(e);
+    } finally {
+      if (program.options().hasOption("-profile")) {
+        program.printStatistics(System.out);
+      }
+    }
+    return EXIT_SUCCESS;
+  }
+}
diff --git a/simplecfg/src/main/java/com/google/simplecfg/ExtendJAnalyzerMain.java b/simplecfg/src/main/java/com/google/simplecfg/ExtendJAnalyzerMain.java
new file mode 100644
index 0000000..78c7422
--- /dev/null
+++ b/simplecfg/src/main/java/com/google/simplecfg/ExtendJAnalyzerMain.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.simplecfg;
+
+import org.extendj.ast.ExtendJFinding;
+
+/**
+ * Produces findings using analyzers implemented in the ExtendJ compiler.
+ */
+public class ExtendJAnalyzerMain {
+
+  /**
+   * Run the ExtendJ analyzer on the files supplied on the command line.
+   * @param args command-line arguments
+   */
+  public static void main(String[] args) {
+    ExtendJAnalyzerFrontend checker = new ExtendJAnalyzerFrontend();
+    int result = checker.run(args);
+    if (result != 0) {
+      System.exit(result);
+    }
+    System.out.println("Found " + checker.getFindings().size() + " findings.");
+    for (ExtendJFinding finding : checker.getFindings()) {
+      System.out.println(finding);
+    }
+  }
+}
diff --git a/simplecfg/src/main/java/com/google/simplecfg/PrintCfg.java b/simplecfg/src/main/java/com/google/simplecfg/PrintCfg.java
new file mode 100644
index 0000000..31c69ff
--- /dev/null
+++ b/simplecfg/src/main/java/com/google/simplecfg/PrintCfg.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.simplecfg;
+
+import org.extendj.ast.BodyDecl;
+import org.extendj.ast.CompilationUnit;
+import org.extendj.ast.Program;
+import org.extendj.ast.TypeDecl;
+import org.extendj.parser.JavaParser;
+
+import java.io.FileInputStream;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Prints a Simplified Control Flow Graph for the first method in a Java program.
+ */
+public class PrintCfg {
+
+  public static void main(String args[]) {
+    int exitCode = new PrintCfg().run(args);
+    if (exitCode != 0) {
+      System.exit(exitCode);
+    }
+  }
+
+  private int run(String args[]) {
+    Set<String> argSet = new HashSet<>();
+    for (String arg : args) {
+      argSet.add(arg);
+    }
+    boolean reverse = argSet.contains("-reverse");
+    for (String path : args) {
+      if (!path.equals("-reverse")) {
+        try {
+          Program program = new Program();
+          program.setTypeLookupFilter(Program.BASE_LIBRARY_FILTER);
+          CompilationUnit unit = new JavaParser().parse(new FileInputStream(path), path);
+          // Attach the parsed unit to a program node so we have a healthy AST.
+          program.addCompilationUnit(unit);
+          // Ensure compilation unit is set to final. This is important to get
+          // caching to work right in the AST.
+          unit = program.getCompilationUnit(0);
+          for (TypeDecl type : unit.getTypeDeclList()) {
+            for (BodyDecl bd : type.getBodyDeclList()) {
+              if (reverse) {
+                bd.printReverseCfg();
+              } else {
+                bd.printCfg();
+              }
+            }
+          }
+        } catch (Exception e) {
+          System.err.println("Failed to parse input file: " + path);
+          e.printStackTrace();
+          return 1;
+        }
+      }
+    }
+    return 0;
+  }
+}
diff --git a/simplecfg/src/main/java/com/google/simplecfg/TestGenerator.java b/simplecfg/src/main/java/com/google/simplecfg/TestGenerator.java
new file mode 100644
index 0000000..83172ea
--- /dev/null
+++ b/simplecfg/src/main/java/com/google/simplecfg/TestGenerator.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.simplecfg;
+
+import org.extendj.ast.BodyDecl;
+import org.extendj.ast.CompilationUnit;
+import org.extendj.ast.Program;
+import org.extendj.ast.TypeDecl;
+import org.extendj.parser.JavaParser;
+
+import java.io.FileInputStream;
+
+/** Generate test cases for the first CFG of each input class. */
+class TestGenerator {
+
+  public static void main(String args[]) {
+    int exitCode = new TestGenerator().run(args);
+    if (exitCode != 0) {
+      System.exit(exitCode);
+    }
+  }
+
+  private int run(String args[]) {
+    for (String path : args) {
+      try {
+        Program program = new Program();
+        program.setTypeLookupFilter(Program.BASE_LIBRARY_FILTER);
+        CompilationUnit unit = new JavaParser().parse(new FileInputStream(path), path);
+        // Attach the parsed unit to a program node so we have a healthy AST.
+        program.addCompilationUnit(unit);
+        // Ensure compilation unit is set to final. This is important to get
+        // caching to work right in the AST.
+        unit = program.getCompilationUnit(0);
+        if (unit.getNumTypeDecl() < 1) {
+          System.err.println("Error: no classes declared in file " + path);
+          return 1;
+        }
+        TypeDecl type = unit.getTypeDecl(0);
+        if (type.getNumBodyDecl() < 1) {
+          System.err.println("Error: first class has no body decls in file " + path);
+          return 1;
+        }
+        BodyDecl bd = type.getBodyDecl(0);
+        bd.printCfgTest();
+      } catch (Exception e) {
+        System.err.println("Failed to parse input file: " + path);
+        e.printStackTrace();
+        return 1;
+      }
+    }
+    return 0;
+  }
+}
diff --git a/simplecfg/src/test/java/com/google/simplecfg/AlreadyClosedTest.java b/simplecfg/src/test/java/com/google/simplecfg/AlreadyClosedTest.java
new file mode 100644
index 0000000..687f228
--- /dev/null
+++ b/simplecfg/src/test/java/com/google/simplecfg/AlreadyClosedTest.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.simplecfg;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.extendj.ast.Program;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Collection;
+
+/** Integration tests for the already-closed checker. */
+@RunWith(JUnit4.class)
+public class AlreadyClosedTest {
+
+  @Test public void test01() {
+    Collection<String> findings = StmtCfgTest.findings("Close01", Program.NO_TYPE_FILTER);
+    assertThat(findings).containsExactly(
+        "testdata/Close01.javax:23:5: close() may have already been called on writer at this point");
+  }
+
+  /**
+   * Test that an already-closed finding was generated on the correct line for a simple positive
+   * test case.
+   *
+   * <p>This test case effectively checks that the type analysis works because the type used is
+   * java.io.Writer, and the analyzer will check if that type is a subtype of java.io.Closeable.
+   */
+  @Test public void writer01() {
+    Collection<String> findings = StmtCfgTest.findings("AlreadyClosedWriter01",
+        Program.NO_TYPE_FILTER);
+    assertThat(findings).hasSize(1);
+    assertThat(findings).containsExactly(
+        "testdata/AlreadyClosedWriter01.javax:27:5: close() may have already been called on writer at this point");
+  }
+
+  @Test public void controlFlow01() {
+    Collection<Integer> lines = StmtCfgTest.findingLines("AlreadyClosedControlFlow01",
+        Program.NO_TYPE_FILTER);
+    assertThat(lines).containsExactly(34, 60, 68, 79, 84, 103, 118);
+  }
+
+  @Test public void negativeFindings01() {
+    Collection<String> findings = StmtCfgTest.findings("AlreadyClosedNegativeFindings01",
+        Program.NO_TYPE_FILTER);
+    assertThat(findings).isEmpty();
+  }
+}
diff --git a/simplecfg/src/test/java/com/google/simplecfg/NullableDereferenceTest.java b/simplecfg/src/test/java/com/google/simplecfg/NullableDereferenceTest.java
new file mode 100644
index 0000000..5d49861
--- /dev/null
+++ b/simplecfg/src/test/java/com/google/simplecfg/NullableDereferenceTest.java
@@ -0,0 +1,145 @@
+/**
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.simplecfg;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.extendj.ast.CompilationUnit;
+import org.extendj.ast.ExtendJFinding;
+import org.extendj.ast.Program;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Collection;
+
+/**
+ * Integration tests for the nullable dereference checker.
+ *
+ * <p>Tests are grouped by the type of null guard used, and then split arbitrarily into separate
+ * tests/files in order to not have too many positive/negative finding tests in a single test file.
+ */
+@RunWith(JUnit4.class)
+public class NullableDereferenceTest {
+
+  @Test public void suggestedFixEndsWithNewline() {
+    CompilationUnit unit = StmtCfgTest.parseFile("NullableNullGuard01",
+        Program.ANALYZER_TYPE_FILTER);
+    Collection<ExtendJFinding> findings = unit.findings();
+    assertThat(findings).isNotEmpty();
+    ExtendJFinding finding = findings.iterator().next();
+    assertThat(finding.fixes).hasSize(1);
+    assertThat(finding.fixes.iterator().next().newText).endsWith("\n");
+  }
+
+  @Test public void nullGuards01() {
+    Collection<String> findings = StmtCfgTest.findings("NullableNullGuard01");
+    assertThat(findings).containsExactly(
+        "testdata/NullableNullGuard01.javax:42:25: Dereferencing p, which was declared @Nullable.",
+        "testdata/NullableNullGuard01.javax:49:12: Dereferencing p, which was declared @Nullable.",
+        "testdata/NullableNullGuard01.javax:62:12: Dereferencing p, which was declared @Nullable.",
+        "testdata/NullableNullGuard01.javax:93:12: Dereferencing q, which was declared @Nullable."
+        );
+  }
+
+  @Test public void nullGuards02() {
+    Collection<String> findings = StmtCfgTest.findings("NullableNullGuard02");
+    assertThat(findings).containsExactly(
+        "testdata/NullableNullGuard02.javax:49:7: Dereferencing p, which was declared @Nullable.",
+        "testdata/NullableNullGuard02.javax:54:7: Dereferencing p, which was declared @Nullable."
+        );
+  }
+
+  @Test public void nullGuards03() {
+    Collection<Integer> lines = StmtCfgTest.findingLines("NullableNullGuard03",
+        Program.ANALYZER_TYPE_FILTER);
+    assertThat(lines).containsExactly(28, 34, 41, 48, 113, 119);
+  }
+
+  @Test public void methodNullGuard01() {
+    Collection<String> findings = StmtCfgTest.findings("NullableMethodNullGuard01");
+    assertThat(findings).isEmpty();
+  }
+
+  @Test public void dataflow01() {
+    Collection<String> findings = StmtCfgTest.findings("NullableDataflow01");
+    assertThat(findings).containsExactly(
+        "testdata/NullableDataflow01.javax:27:7: Dereferencing p, which was declared @Nullable.",
+        "testdata/NullableDataflow01.javax:35:7: Dereferencing p, which was declared @Nullable."
+        );
+  }
+
+  @Test public void instanceOf() {
+    Collection<String> findings = StmtCfgTest.findings("NullableInstanceOf");
+    assertThat(findings).isEmpty();
+  }
+
+  @Test public void variableArity() {
+    Collection<String> findings = StmtCfgTest.findings("NullableVariableArity");
+    assertThat(findings).isEmpty();
+  }
+
+  @Test public void nullableDereference01() {
+    Collection<String> findings = StmtCfgTest.findings("NullableDereference01");
+    assertThat(findings).containsExactly(
+        "testdata/NullableDereference01.javax:27:12: Dereferencing p, which was declared @Nullable.",
+        "testdata/NullableDereference01.javax:31:12: Dereferencing p, which was declared @Nullable."
+        );
+  }
+
+  /** Test false positive for GitHub issue #10. */
+  @Test public void issue10() {
+    Collection<String> findings = StmtCfgTest.findings("NullableDereferenceIssue10");
+    assertThat(findings).containsExactly(
+        "testdata/NullableDereferenceIssue10.javax:34:31: Dereferencing y, which was declared @Nullable."
+        );
+  }
+
+  @Test public void issue11() {
+    Collection<String> findings = StmtCfgTest.findings("NullableDereferenceIssue11");
+    assertThat(findings).isEmpty();
+  }
+
+  @Test public void issue12() {
+    Collection<String> findings = StmtCfgTest.findings("NullableDereferenceIssue12");
+    assertThat(findings).isEmpty();
+  }
+
+  @Test public void eqExpr() {
+    Collection<String> findings = StmtCfgTest.findings("NullableDereferenceEqExpr");
+    assertThat(findings).isEmpty();
+  }
+
+  @Test public void neExpr() {
+    Collection<String> findings = StmtCfgTest.findings("NullableDereferenceNeExpr");
+    assertThat(findings).isEmpty();
+  }
+
+  @Test public void methodCall() {
+    Collection<String> findings = StmtCfgTest.findings("NullableDereferenceMethodCall");
+    assertThat(findings).containsExactly(
+        "testdata/NullableDereferenceMethodCall.javax:41:16: "
+        + "Dereferencing p, which was declared @Nullable.");
+  }
+
+  @Test public void issue13() {
+    Collection<String> findings = StmtCfgTest.findings("NullableDereferenceIssue13");
+    assertThat(findings).containsExactly(
+        "testdata/NullableDereferenceIssue13.javax:33:7: "
+        + "Dereferencing obj, which was declared @Nullable.");
+  }
+}
diff --git a/simplecfg/src/test/java/com/google/simplecfg/StmtCfgTest.java b/simplecfg/src/test/java/com/google/simplecfg/StmtCfgTest.java
new file mode 100644
index 0000000..974b174
--- /dev/null
+++ b/simplecfg/src/test/java/com/google/simplecfg/StmtCfgTest.java
@@ -0,0 +1,658 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.simplecfg;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+import org.extendj.ast.BytecodeParser;
+import org.extendj.ast.BytecodeReader;
+import org.extendj.ast.CfgNode;
+import org.extendj.ast.CompilationUnit;
+import org.extendj.ast.ExtendJFinding;
+import org.extendj.ast.FileClassSource;
+import org.extendj.ast.JavaParser;
+import org.extendj.ast.Program;
+import org.extendj.ast.SourceFolderPath;
+import org.extendj.ast.TypeLookupFilter;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+
+/** Tests for simplified Control Flow Graphs built for methods/constructors/initializers.  */
+@RunWith(JUnit4.class)
+public class StmtCfgTest {
+
+  /** Helper method to parse an ExtendJ compilation unit from a file.  */
+  protected static CompilationUnit parseFile(String filename, TypeLookupFilter typeFilter) {
+    String path = "testdata/" + filename + ".javax";
+    try {
+      JavaParser javaParser = new JavaParser() {
+        @Override
+        public CompilationUnit parse(java.io.InputStream is, String fileName)
+            throws IOException, beaver.Parser.Exception {
+          return new org.extendj.parser.JavaParser().parse(is, fileName);
+        }
+      };
+      BytecodeReader bytecodeReader = new BytecodeReader() {
+        @Override
+        public CompilationUnit read(InputStream is, String fullName, Program p)
+        throws FileNotFoundException, IOException {
+          return new BytecodeParser(is, fullName).parse(null, null, p);
+        }
+      };
+      Program program = new Program();
+      program.initBytecodeReader(bytecodeReader);
+      program.initJavaParser(javaParser);
+      program.setTypeLookupFilter(typeFilter);
+      CompilationUnit unit = javaParser.parse(new FileInputStream(path), path);
+      // Attach the parsed unit to a program node so we have a healthy AST.
+      program.addCompilationUnit(unit);
+      // Ensure compilation unit is set to final. This is important to get
+      // caching to work right in the AST.
+      unit = program.getCompilationUnit(0);
+      unit.setClassSource(new FileClassSource(new SourceFolderPath("testdata"), path));
+      unit.setFromSource(true);
+      return unit;
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail("failed to parse test input file: " + path);
+    }
+    // Failed.
+    return null;
+  }
+
+  /** Helper to get the findings for a given file. */
+  protected static Collection<String> findings(String filename) {
+    return findings(filename, Program.ANALYZER_TYPE_FILTER);
+  }
+
+  /** Helper to get the findings for a given file. */
+  protected static Collection<String> findings(String filename, TypeLookupFilter typeFilter) {
+    CompilationUnit unit = StmtCfgTest.parseFile(filename, typeFilter);
+    Collection<String> findings = new HashSet<String>();
+    for (ExtendJFinding finding : unit.findings()) {
+      findings.add(finding.toString());
+    }
+    return findings;
+  }
+
+  /** Helper to get the line numbers where findings were reported for a given file. */
+  protected static Collection<Integer> findingLines(String filename, TypeLookupFilter typeFilter) {
+    CompilationUnit unit = StmtCfgTest.parseFile(filename, typeFilter);
+    Collection<Integer> lines = new LinkedList<>();
+    for (ExtendJFinding finding : unit.findings()) {
+      lines.add(finding.startLine);
+    }
+    return lines;
+  }
+
+  private static CfgNode parseCfg(String filename) {
+    CompilationUnit unit = parseFile(filename, Program.BASE_LIBRARY_FILTER);
+    assertThat(unit.getTypeDeclList()).isNotEmpty();
+    assertThat(unit.getTypeDecl(0).getBodyDeclList()).isNotEmpty();
+    return unit.getTypeDecl(0).getBodyDecl(0).entry();
+  }
+
+  /**
+   * Assert and return a single successor of the node.
+   */
+  private static CfgNode succ(CfgNode node, String successor) {
+    assertThat(cfgNames(node.successors())).containsExactly(successor);
+    return node.successors().iterator().next();
+  }
+
+  /**
+   * Assert the successors of the node and return them in an array
+   * using the same ordering as the input array.
+   */
+  private static CfgNode[] succ(CfgNode node, String... successors) {
+    assertThat(cfgNames(node.successors())).containsExactly((Object[]) successors);
+
+    // Ensure no duplicate successor names.
+    Set<String> dups = new HashSet<String>();
+    for (String succ : successors) {
+      if (dups.contains(succ)) {
+        fail("can not assert successors with duplicate names");
+      }
+      dups.add(succ);
+    }
+
+    Map<String, CfgNode> successorMap = new HashMap<>();
+    for (CfgNode successor : node.successors()) {
+      successorMap.put(successor.toString(), successor);
+    }
+
+    CfgNode[] result = new CfgNode[successors.length];
+    for (int i = 0; i < successors.length; ++i) {
+      result[i] = successorMap.get(successors[i]);
+    }
+    return result;
+  }
+
+  /** Convert a collection of CfgNodes to a collection of of the node names.  */
+  private static Collection<String> cfgNames(Iterable<? extends CfgNode> cfgs) {
+    // Use a linked list because we need to preserve duplicate names.
+    // TODO(joqvist): Use Java 8 stream api to map CfgNode -> String.
+    Collection<String> names = new LinkedList<>();
+    for (CfgNode cfg : cfgs) {
+      names.add(cfg.toString());
+    }
+    return names;
+  }
+
+  @Test public void ifStmt01() {
+    CfgNode entry = parseCfg("IfStmt01");
+    CfgNode call1 = succ(entry, "call1()");
+    CfgNode branch = succ(call1, "if (call1())");
+    CfgNode[] targets = succ(branch, "onTrue()", "exit");
+    CfgNode thenEnd = succ(targets[0], "then-end");
+    assertThat(succ(thenEnd, "exit")).isSameAs(targets[1]);
+  }
+
+  @Test public void ifStmt02() {
+    CfgNode entry = parseCfg("IfStmt02");
+    CfgNode call1 = succ(entry, "call1()");
+    CfgNode branch = succ(call1, "if (call1())");
+    CfgNode[] targets = succ(branch, "onTrue()", "onFalse()");
+    CfgNode thenEnd = succ(targets[0], "then-end");
+    CfgNode elseEnd = succ(targets[1], "else-end");
+    assertThat(succ(thenEnd, "exit")).isSameAs(succ(elseEnd, "exit"));
+  }
+
+  @Test public void ifStmt03() {
+    CfgNode entry = parseCfg("IfStmt03");
+    CfgNode call1 = succ(entry, "call1()");
+    CfgNode branch = succ(call1, "if (call1())");
+    CfgNode[] targets = succ(branch, "onTrue()", "onFalse()");
+    succ(succ(targets[0], "then-end"), "exit");
+    succ(targets[1], "call2()");
+  }
+
+  @Test public void ifStmt04() {
+    CfgNode entry = parseCfg("IfStmt04");
+    CfgNode call1 = succ(entry, "call1()");
+    CfgNode branch = succ(call1, "if (call1())");
+    CfgNode[] targets = succ(branch, "onTrue()", "onFalse()");
+    succ(targets[0], "call2()");
+    succ(succ(targets[1], "else-end"), "exit");
+  }
+
+  @Test public void forStmt01() {
+    CfgNode entry = parseCfg("ForStmt01");
+    CfgNode call1 = succ(entry, "call1()");
+    CfgNode branch = succ(call1, "for (call1())");
+    CfgNode[] targets = succ(branch, "for-end", "exit");
+    assertThat(succ(targets[0], "call1()")).isSameAs(call1);
+  }
+
+  @Test public void forStmt02() {
+    CfgNode entry = parseCfg("ForStmt02");
+    CfgNode call1 = succ(entry, "call1()");
+    CfgNode branch = succ(call1, "for (call1())");
+    CfgNode[] targets = succ(branch, "call2()", "exit");
+    CfgNode forEnd = succ(targets[0], "for-end");
+    assertThat(succ(forEnd, "call1()")).isSameAs(call1);
+  }
+
+  @Test public void forStmt03() {
+    CfgNode entry = parseCfg("ForStmt03");
+    CfgNode init = succ(entry, "init()");
+    CfgNode cond = succ(init, "cond()");
+    CfgNode branch = succ(cond, "for (cond())");
+    CfgNode[] targets = succ(branch, "stmt()", "exit");
+    CfgNode stmt = targets[0];
+    CfgNode forEnd = succ(stmt, "for-end");
+    CfgNode update = succ(forEnd, "update()");
+    assertThat(succ(update, "cond()")).isSameAs(cond);
+  }
+
+  @Test public void forStmt04() {
+    CfgNode entry = parseCfg("ForStmt04");
+    CfgNode i = succ(entry, "i()");
+    CfgNode j = succ(i, "j()");
+    CfgNode cond = succ(j, "cond()");
+    CfgNode branch = succ(cond, "for (cond())");
+    CfgNode[] targets = succ(branch, "stmt()", "exit");
+    CfgNode stmt = targets[0];
+    CfgNode forEnd = succ(stmt, "for-end");
+    CfgNode u1 = succ(forEnd, "u1()");
+    CfgNode u2 = succ(u1, "u2()");
+    CfgNode u3 = succ(u2, "u3()");
+    assertThat(succ(u3, "cond()")).isSameAs(cond);
+  }
+
+  @Test public void forStmt05() {
+    CfgNode entry = parseCfg("ForStmt05");
+    CfgNode i = succ(entry, "i()");
+    CfgNode branch = succ(i, "for (false)");
+    CfgNode y = succ(branch, "y()");
+    succ(y, "exit");
+  }
+
+  @Test public void whileStmt01() {
+    CfgNode entry = parseCfg("WhileStmt01");
+    CfgNode branch = succ(entry, "while (true)");
+    CfgNode whileEnd = succ(branch, "while-end");
+    assertThat(succ(whileEnd, "while (true)")).isSameAs(branch);
+  }
+
+  @Test public void whileStmt02() {
+    CfgNode entry = parseCfg("WhileStmt02");
+    CfgNode cond = succ(entry, "cond()");
+    CfgNode branch = succ(cond, "while (cond())");
+    CfgNode[] targets = succ(branch, "while-end", "exit");
+    assertThat(succ(targets[0], "cond()")).isSameAs(cond);
+  }
+
+  @Test public void whileStmt03() {
+    CfgNode entry = parseCfg("WhileStmt03");
+    CfgNode whileBranch = succ(entry, "while (true)");
+    CfgNode cond = succ(whileBranch, "cond()");
+    CfgNode ifBranch = succ(cond, "if (cond())");
+    CfgNode[] whileSucc = succ(ifBranch, "while-end", "break");
+    assertThat(succ(whileSucc[0], "while (true)")).isSameAs(whileBranch);
+    succ(succ(whileSucc[1], "tail()"), "exit");
+  }
+
+  @Test public void whileStmt04() {
+    CfgNode entry = parseCfg("WhileStmt04");
+    CfgNode whileBranch = succ(entry, "while (true)");
+    CfgNode cond = succ(whileBranch, "cond()");
+    CfgNode ifBranch = succ(cond, "if (cond())");
+    CfgNode[] ifSucc = succ(ifBranch, "continue", "x()");
+    assertThat(succ(ifSucc[0], "while (true)")).isSameAs(whileBranch);
+    CfgNode y = succ(succ(ifSucc[1], "break"), "y()");
+    succ(y, "exit");
+  }
+
+  @Test public void whileStmt05() {
+    CfgNode entry = parseCfg("WhileStmt05");
+    CfgNode branch = succ(entry, "while (false)");
+    CfgNode y = succ(branch, "y()");
+    succ(y, "exit");
+  }
+
+  @Test public void doStmt01() {
+    CfgNode entry = parseCfg("DoStmt01");
+    CfgNode doEntry = succ(entry, "do-entry");
+    CfgNode x = succ(doEntry, "x()");
+    CfgNode y = succ(x, "y()");
+    CfgNode branch = succ(y, "do_while (y())");
+    CfgNode[] targets = succ(branch, "z()", "do-entry");
+    succ(targets[0], "exit");
+    assertThat(succ(targets[1], "x()")).isSameAs(x);
+  }
+
+  @Test public void doStmt02() {
+    CfgNode entry = parseCfg("DoStmt02");
+    CfgNode doEntry = succ(entry, "do-entry");
+    CfgNode x = succ(doEntry, "x()");
+    CfgNode branch = succ(x, "do_while (false)");
+    CfgNode y = succ(branch, "y()");
+    succ(y, "exit");
+  }
+
+  @Test public void enhancedFor01() {
+    CfgNode entry = parseCfg("EnhancedFor01");
+    CfgNode aList = succ(entry, "aList()");
+    CfgNode branch = succ(aList, "for (int a : aList())");
+    CfgNode[] targets = succ(branch, "x()", "exit");
+    CfgNode forEnd = succ(targets[0], "for-end");
+    assertThat(succ(forEnd, "aList()")).isSameAs(aList);
+  }
+
+  @Test public void methodAccess01() {
+    CfgNode entry = parseCfg("MethodAccess01");
+    CfgNode p1 = succ(entry, "p1()");
+    CfgNode p2 = succ(p1, "p2()");
+    CfgNode p3 = succ(p2, "p3()");
+    CfgNode x = succ(p3, "x()");
+    succ(x, "exit");
+  }
+
+  @Test public void conditionalExpr01() {
+    CfgNode entry = parseCfg("ConditionalExpr01");
+    CfgNode x = succ(entry, "x()");
+    CfgNode branch = succ(x, "if (x())");
+    CfgNode[] targets = succ(branch, "y()", "z()");
+    CfgNode thenEnd = succ(targets[0], "then-end");
+    CfgNode elseEnd = succ(targets[1], "else-end");
+    // Assert that the branches converge on exit.
+    assertThat(succ(thenEnd, "exit")).isSameAs(succ(elseEnd, "exit"));
+  }
+
+  @Test public void switchStmt01() {
+    CfgNode entry = parseCfg("SwitchStmt01");
+    CfgNode expr = succ(entry, "expr()");
+    CfgNode branch = succ(expr, "switch (expr())");
+    CfgNode[] targets = succ(branch, "x()", "y()", "z()", "d()");
+    assertThat(succ(targets[0], "y()")).isSameAs(targets[1]);
+    CfgNode exit = succ(succ(targets[1], "break"), "exit");
+    assertThat(succ(targets[2], "d()")).isSameAs(targets[3]);
+    assertThat(succ(targets[3], "exit")).isSameAs(exit);
+  }
+
+  @Test public void switchStmt02() {
+    CfgNode entry = parseCfg("SwitchStmt02");
+    CfgNode expr = succ(entry, "expr()");
+    CfgNode branch = succ(expr, "switch (expr())");
+    CfgNode[] targets = succ(branch, "x()", "y()", "z()", "exit");
+    assertThat(succ(targets[0], "y()")).isSameAs(targets[1]);
+    assertThat(succ(succ(targets[1], "break"), "exit")).isSameAs(targets[3]);
+    assertThat(succ(targets[2], "exit")).isSameAs(targets[3]);
+  }
+
+  @Test public void tryStmt01() {
+    CfgNode entry = parseCfg("TryStmt01");
+    CfgNode tryBranch = succ(entry, "try");
+    CfgNode[] trySucc = succ(tryBranch, "cond()", "x()");
+    CfgNode[] condSucc = succ(trySucc[0], "exception", "if (cond())");
+    CfgNode x = succ(condSucc[0], "x()");
+    assertThat(x).isSameAs(trySucc[1]);
+    CfgNode exit = succ(succ(x, "exception"), "exit");
+    CfgNode[] ifSucc = succ(condSucc[1], "a()", "return");
+    CfgNode[] aSucc = succ(ifSucc[0], "exception", "x()");
+    assertThat(succ(aSucc[0], "x()")).isSameAs(x);
+    assertThat(aSucc[1]).isNotSameAs(x);
+    assertThat(succ(succ(aSucc[1], "y()"), "exit")).isSameAs(exit);
+    CfgNode x2 = succ(ifSucc[1], "x()");
+    assertThat(x2).isNotSameAs(x);
+    assertThat(succ(x2, "exit")).isSameAs(exit);
+  }
+
+  @Test public void tryStmt02() {
+    CfgNode entry = parseCfg("TryStmt02");
+    CfgNode tryBranch = succ(entry, "try");
+    CfgNode[] tryTargets = succ(tryBranch, "c1()", "c2()", "exit");
+    assertThat(succ(tryTargets[0], "exit")).isSameAs(tryTargets[2]);
+    assertThat(succ(tryTargets[1], "exit")).isSameAs(tryTargets[2]);
+  }
+
+  @Test public void tryStmt03() {
+    CfgNode entry = parseCfg("TryStmt03");
+    CfgNode tryEntry = succ(entry, "try");
+    CfgNode[] targets = succ(tryEntry, "if (condition)", "x()");
+
+    CfgNode exception = succ(targets[1], "exception");
+    CfgNode exit = succ(exception, "exit");
+
+    CfgNode[] ifSucc = succ(targets[0], "return", "x()");
+    assertThat(succ(succ(ifSucc[0], "x()"), "exit")).isSameAs(exit);
+    assertThat(succ(succ(ifSucc[1], "y()"), "exit")).isSameAs(exit);
+  }
+
+  @Test public void filtering01() {
+    CfgNode entry = parseCfg("Filtering01");
+    CfgNode i = succ(entry, "i()");
+    CfgNode j = succ(i, "j()");
+    CfgNode cond = succ(j, "cond()");
+    CfgNode forBranch = succ(cond, "for (cond() && c == 3)");
+    CfgNode[] forSucc = succ(forBranch, "stmt()", "return");
+    CfgNode stmt = forSucc[0];
+    CfgNode u1 = succ(succ(stmt, "for-end"), "u1()");
+    CfgNode u2 = succ(u1, "u2()");
+    CfgNode u3 = succ(u2, "u3()");
+    assertThat(succ(u3, "cond()")).isSameAs(cond);
+  }
+
+  @Test public void throwStmt01() {
+    CfgNode entry = parseCfg("ThrowStmt01");
+    CfgNode x = succ(entry, "x()");
+    CfgNode exception = succ(x, "exception");
+    succ(exception, "exit");
+  }
+
+  // Note: tests should be designed so that there is no need to test duplicate
+  // successors. Simply insert an extra call at the start of one of the
+  // branches.
+
+  // Generated tests below here.
+  // Be extra careful when generating a test: you must manually verify that
+  // it tests the graph correctly and that the generated graph matches your
+  // expectations. Watch out for nodes that should be identical but appear to
+  // be separate: in some cases this is okay but it could also indicate faulty
+  // caching for NTAs.
+
+  @Test public void genTryStmt01() {
+    CfgNode entry = parseCfg("GenTryStmt01");
+    CfgNode tryEntry = succ(entry, "try");
+    CfgNode[] targets = succ(tryEntry, "cond()", "c1()", "c2()");
+    CfgNode[] targets2 = succ(targets[0], "exception", "if (cond())");
+    CfgNode exit = succ(targets[1], "exit");
+    assertThat(succ(targets[2], "exit")).isSameAs(exit);
+    CfgNode[] targets3 = succ(targets2[0], "c1()", "c2()");
+    assertThat(targets3[0]).isSameAs(targets[1]);
+    assertThat(targets3[1]).isSameAs(targets[2]);
+    CfgNode[] targets4 = succ(targets2[1], "exception", "x()");
+    CfgNode[] targets5 = succ(targets4[0], "c1()", "c2()");
+    assertThat(targets5[1]).isSameAs(targets[2]);
+    assertThat(targets5[0]).isSameAs(targets[1]);
+    CfgNode[] targets6 = succ(targets4[1], "exception", "exit");
+    assertThat(targets6[1]).isSameAs(exit);
+    CfgNode[] targets7 = succ(targets6[0], "c1()", "c2()");
+    assertThat(targets7[0]).isSameAs(targets[1]);
+    assertThat(targets7[1]).isSameAs(targets[2]);
+  }
+
+  @Test public void genTryStmt02() {
+    CfgNode entry = parseCfg("GenTryStmt02");
+    CfgNode tryEntry = succ(entry, "try");
+    CfgNode[] targets = succ(tryEntry, "tryBlock()", "c2()", "c1()");
+    CfgNode[] targets2 = succ(targets[0], "exception", "exit");
+    assertThat(succ(targets[1], "exit")).isSameAs(targets2[1]);
+    assertThat(succ(targets[2], "exit")).isSameAs(targets2[1]);
+    CfgNode[] targets3 = succ(targets2[0], "c2()", "c1()");
+    assertThat(targets3[0]).isSameAs(targets[1]);
+    assertThat(targets3[1]).isSameAs(targets[2]);
+  }
+
+  @Test public void genTryStmt03() {
+    CfgNode entry = parseCfg("GenTryStmt03");
+    CfgNode tryEntry = succ(entry, "try");
+    CfgNode[] targets = succ(tryEntry, "c1()", "x()");
+    CfgNode f = succ(targets[0], "f()");
+    CfgNode[] targets2 = succ(targets[1], "exception", "f()");
+    assertThat(targets2[1]).isSameAs(f);
+    CfgNode exit = succ(f, "exit");
+    assertThat(succ(targets2[0], "c1()")).isSameAs(targets[0]);
+  }
+
+
+  @Test public void genTryStmt04() {
+    CfgNode entry = parseCfg("GenTryStmt04");
+    CfgNode tryEntry = succ(entry, "try");
+    CfgNode[] tryEntrySucc = succ(tryEntry, "if (condition)", "x()");
+    CfgNode[] ifBranchSucc = succ(tryEntrySucc[0], "a()", "x()");
+    CfgNode exception = succ(tryEntrySucc[1], "exception");
+    CfgNode[] aSucc = succ(ifBranchSucc[0], "exception", "return");
+    CfgNode y = succ(ifBranchSucc[1], "y()");
+    CfgNode exit = succ(exception, "exit");
+    assertThat(succ(aSucc[0], "x()")).isSameAs(tryEntrySucc[1]);
+    CfgNode x2 = succ(aSucc[1], "x()");
+    assertThat(succ(y, "exit")).isSameAs(exit);
+    assertThat(succ(x2, "exit")).isSameAs(exit);
+  }
+
+  @Test public void genTryStmt05() {
+    CfgNode entry = parseCfg("GenTryStmt05");
+    CfgNode tryEntry = succ(entry, "try");
+    CfgNode[] tryEntrySucc = succ(tryEntry, "f2()", "try");
+    CfgNode exception = succ(tryEntrySucc[0], "exception");
+    CfgNode[] tryEntrySucc2 = succ(tryEntrySucc[1], "if (condition)", "f1()");
+    CfgNode exit = succ(exception, "exit");
+    CfgNode[] ifBranchSucc = succ(tryEntrySucc2[0], "exception", "f1()");
+    CfgNode[] f1Succ = succ(tryEntrySucc2[1], "exception", "return");
+    assertThat(succ(ifBranchSucc[0], "f1()")).isSameAs(tryEntrySucc2[1]);
+    CfgNode[] f1Succ2 = succ(ifBranchSucc[1], "exception", "return");
+    assertThat(succ(f1Succ[0], "f2()")).isSameAs(tryEntrySucc[0]);
+    CfgNode f22 = succ(f1Succ[1], "f2()");
+    assertThat(succ(f1Succ2[0], "f2()")).isSameAs(tryEntrySucc[0]);
+    CfgNode f24 = succ(f1Succ2[1], "f2()");
+    assertThat(succ(f22, "exit")).isSameAs(exit);
+    assertThat(succ(f24, "exit")).isSameAs(exit);
+  }
+
+  @Test public void genTryStmt06() {
+    CfgNode entry = parseCfg("GenTryStmt06");
+    CfgNode tryEntry = succ(entry, "try");
+    CfgNode[] tryEntrySucc = succ(tryEntry, "f2()", "try");
+    CfgNode exception = succ(tryEntrySucc[0], "exception");
+    CfgNode[] tryEntrySucc2 = succ(tryEntrySucc[1], "s()", "f1()");
+    CfgNode exit = succ(exception, "exit");
+    CfgNode[] sSucc = succ(tryEntrySucc2[0], "exception", "f1()");
+    CfgNode[] f1Succ = succ(tryEntrySucc2[1], "exception", "return");
+    assertThat(succ(sSucc[0], "f1()")).isSameAs(tryEntrySucc2[1]);
+    CfgNode[] f1Succ2 = succ(sSucc[1], "exception", "return");
+    assertThat(succ(f1Succ[0], "f2()")).isSameAs(tryEntrySucc[0]);
+    CfgNode f22 = succ(f1Succ[1], "f2()");
+    assertThat(succ(f1Succ2[0], "f2()")).isSameAs(tryEntrySucc[0]);
+    CfgNode f24 = succ(f1Succ2[1], "f2()");
+    assertThat(succ(f22, "exit")).isSameAs(exit);
+    assertThat(succ(f24, "exit")).isSameAs(exit);
+  }
+
+  @Test public void genTryStmt07() {
+    CfgNode entry = parseCfg("GenTryStmt07");
+    CfgNode tryEntry = succ(entry, "try");
+    CfgNode[] tryEntrySucc = succ(tryEntry, "c1()", "x()");
+    CfgNode returnMarker = succ(tryEntrySucc[0], "return");
+    CfgNode[] xSucc = succ(tryEntrySucc[1], "exception", "f()");
+    CfgNode f = succ(returnMarker, "f()");
+    assertThat(succ(xSucc[0], "c1()")).isSameAs(tryEntrySucc[0]);
+    CfgNode y = succ(xSucc[1], "y()");
+    CfgNode exit = succ(f, "exit");
+    assertThat(succ(y, "exit")).isSameAs(exit);
+  }
+
+  @Test public void genForStmt01() {
+    CfgNode entry = parseCfg("GenForStmt01");
+    CfgNode forBranch = succ(entry, "for (i < 100)");
+    CfgNode[] forBranchSucc = succ(forBranch, "c()", "fin()");
+    CfgNode whileBranch = succ(forBranchSucc[0], "while (c())");
+    CfgNode exit = succ(forBranchSucc[1], "exit");
+    CfgNode[] whileBranchSucc = succ(whileBranch, "if (i >= 40)", "for-end");
+    CfgNode[] ifBranchSucc = succ(whileBranchSucc[0], "break", "while-end");
+    CfgNode u = succ(whileBranchSucc[1], "u()");
+    assertThat(succ(ifBranchSucc[0], "fin()")).isSameAs(forBranchSucc[1]);
+    assertThat(succ(ifBranchSucc[1], "c()")).isSameAs(forBranchSucc[0]);
+    assertThat(succ(u, "for (i < 100)")).isSameAs(forBranch);
+  }
+
+  @Test public void genForStmt02() {
+    CfgNode entry = parseCfg("GenForStmt02");
+    CfgNode forBranch = succ(entry, "for (i < 100)");
+    CfgNode[] forBranchSucc = succ(forBranch, "c()", "fin()");
+    CfgNode whileBranch = succ(forBranchSucc[0], "while (c())");
+    CfgNode exit = succ(forBranchSucc[1], "exit");
+    CfgNode[] whileBranchSucc = succ(whileBranch, "if (i >= 40)", "for-end");
+    CfgNode[] ifBranchSucc = succ(whileBranchSucc[0], "continue", "while-end");
+    CfgNode u = succ(whileBranchSucc[1], "u()");
+    assertThat(succ(ifBranchSucc[0], "for (i < 100)")).isSameAs(forBranch);
+    assertThat(succ(ifBranchSucc[1], "c()")).isSameAs(forBranchSucc[0]);
+    assertThat(succ(u, "for (i < 100)")).isSameAs(forBranch);
+  }
+
+  @Test public void genClassInstance01() {
+    CfgNode entry = parseCfg("GenClassInstance01");
+    CfgNode p1 = succ(entry, "p1()");
+    CfgNode p2 = succ(p1, "p2()");
+    CfgNode p3 = succ(p2, "p3()");
+    CfgNode p4 = succ(p3, "p4()");
+    CfgNode exit = succ(p4, "exit");
+  }
+
+  @Test public void genSwitchStmt01() {
+    CfgNode entry = parseCfg("GenSwitchStmt01");
+    CfgNode whileBranch = succ(entry, "while (x + y == 400 - z)");
+    CfgNode[] whileBranchSucc = succ(whileBranch, "switch (x)", "exit");
+    CfgNode[] switchBranchSucc = succ(whileBranchSucc[0], "c6()", "c3()", "break", "c5()", "c1()", "c4()", "while-end", "c2()");
+    CfgNode breakMarker = succ(switchBranchSucc[0], "break");
+    assertThat(succ(switchBranchSucc[1], "c2()")).isSameAs(switchBranchSucc[7]);
+    assertThat(succ(switchBranchSucc[2], "while-end")).isSameAs(switchBranchSucc[6]);
+    CfgNode returnMarker = succ(switchBranchSucc[3], "return");
+    CfgNode breakMarker2 = succ(switchBranchSucc[4], "break");
+    CfgNode breakMarker3 = succ(switchBranchSucc[5], "break");
+    assertThat(succ(switchBranchSucc[6], "while (x + y == 400 - z)")).isSameAs(whileBranch);
+    CfgNode continueMarker = succ(switchBranchSucc[7], "continue");
+    assertThat(succ(breakMarker, "while-end")).isSameAs(switchBranchSucc[6]);
+    assertThat(succ(returnMarker, "exit")).isSameAs(whileBranchSucc[1]);
+    assertThat(succ(breakMarker2, "while-end")).isSameAs(switchBranchSucc[6]);
+    assertThat(succ(breakMarker3, "while-end")).isSameAs(switchBranchSucc[6]);
+    assertThat(succ(continueMarker, "while (x + y == 400 - z)")).isSameAs(whileBranch);
+  }
+
+  @Test public void genClassInstance02() {
+    CfgNode entry = parseCfg("GenClassInstance02");
+    CfgNode toString = succ(entry, "toString()");
+    CfgNode exit = succ(toString, "exit");
+  }
+
+  @Test public void genTryWithResources01() {
+    CfgNode entry = parseCfg("GenTryWithResources01");
+    CfgNode openStream = succ(entry, "openStream()");
+    CfgNode[] openStreamSucc = succ(openStream, "exception", "try");
+    CfgNode[] exceptionSucc = succ(openStreamSucc[0], "c()", "f()");
+    CfgNode[] tryEntrySucc = succ(openStreamSucc[1], "c()", "stmt()", "f()");
+    assertThat(tryEntrySucc[2]).isSameAs(exceptionSucc[1]);
+    assertThat(tryEntrySucc[0]).isSameAs(exceptionSucc[0]);
+    CfgNode f = succ(exceptionSucc[0], "f()");
+    CfgNode exception = succ(exceptionSucc[1], "exception");
+    CfgNode[] stmtSucc = succ(tryEntrySucc[1], "exception", "f()");
+    assertThat(stmtSucc[1]).isSameAs(f);
+    CfgNode exit = succ(f, "exit");
+    assertThat(succ(exception, "exit")).isSameAs(exit);
+    CfgNode[] exceptionSucc2 = succ(stmtSucc[0], "c()", "f()");
+    assertThat(exceptionSucc2[0]).isSameAs(exceptionSucc[0]);
+    assertThat(exceptionSucc2[1]).isSameAs(exceptionSucc[1]);
+  }
+
+  @Test public void genTryWithResources02() {
+    CfgNode entry = parseCfg("GenTryWithResources02");
+    CfgNode o1 = succ(entry, "o1()");
+    CfgNode[] o1Succ = succ(o1, "exception", "o2()");
+    CfgNode[] exceptionSucc = succ(o1Succ[0], "c()", "f()");
+    CfgNode[] o2Succ = succ(o1Succ[1], "exception", "try");
+    CfgNode f = succ(exceptionSucc[0], "f()");
+    CfgNode exception = succ(exceptionSucc[1], "exception");
+    CfgNode[] exceptionSucc2 = succ(o2Succ[0], "c()", "f()");
+    assertThat(exceptionSucc2[0]).isSameAs(exceptionSucc[0]);
+    assertThat(exceptionSucc2[1]).isSameAs(exceptionSucc[1]);
+    CfgNode[] tryEntrySucc = succ(o2Succ[1], "c()", "stmt()", "f()");
+    assertThat(tryEntrySucc[2]).isSameAs(exceptionSucc[1]);
+    assertThat(tryEntrySucc[0]).isSameAs(exceptionSucc[0]);
+    CfgNode exit = succ(f, "exit");
+    assertThat(succ(exception, "exit")).isSameAs(exit);
+    CfgNode[] stmtSucc = succ(tryEntrySucc[1], "exception", "f()");
+    assertThat(stmtSucc[1]).isSameAs(f);
+    CfgNode[] exceptionSucc3 = succ(stmtSucc[0], "c()", "f()");
+    assertThat(exceptionSucc3[1]).isSameAs(exceptionSucc[1]);
+    assertThat(exceptionSucc3[0]).isSameAs(exceptionSucc[0]);
+  }
+
+}
diff --git a/simplecfg/src/test/java/org/extendj/ast/IdentityTupleSetTest.java b/simplecfg/src/test/java/org/extendj/ast/IdentityTupleSetTest.java
new file mode 100644
index 0000000..417eeb8
--- /dev/null
+++ b/simplecfg/src/test/java/org/extendj/ast/IdentityTupleSetTest.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.extendj.ast;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import java.util.Set;
+
+import org.extendj.ast.IdentityTupleSet;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link IdentityTupleSet}. */
+@RunWith(JUnit4.class)
+public class IdentityTupleSetTest {
+
+  // Two unique objects used for testing.
+  private Object a = new Object();
+  private Object b = new Object();
+
+  @Test public void testSize() {
+    assertThat(new IdentityTupleSet<>(null, null)).hasSize(1);
+    assertThat(new IdentityTupleSet<>(a, a)).hasSize(1);
+    assertThat(new IdentityTupleSet<>(a, b)).hasSize(2);
+    assertThat(new IdentityTupleSet<>(null, b)).hasSize(2);
+  }
+
+  @Test public void testIsEmpty() {
+    assertThat(new IdentityTupleSet<>(null, null)).isNotEmpty();
+    assertThat(new IdentityTupleSet<>(a, a)).isNotEmpty();
+    assertThat(new IdentityTupleSet<>(a, b)).isNotEmpty();
+    assertThat(new IdentityTupleSet<>(null, b)).isNotEmpty();
+  }
+
+  @Test public void testDuplicateContains() {
+    assertThat(new IdentityTupleSet<>(null, null)).containsExactly((Object) null);
+    assertThat(new IdentityTupleSet<>(a, a)).containsExactly(a);
+  }
+
+  @Test public void testContains() {
+    assertThat(new IdentityTupleSet<>(a, b)).containsExactly(a, b);
+  }
+}
diff --git a/simplecfg/testdata/AlreadyClosedControlFlow01.javax b/simplecfg/testdata/AlreadyClosedControlFlow01.javax
new file mode 100644
index 0000000..2463b37
--- /dev/null
+++ b/simplecfg/testdata/AlreadyClosedControlFlow01.javax
@@ -0,0 +1,140 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real code! This file is parsed by the Java API analyzer tests
+ * to check that the expected findings are reported for this file.
+ */
+import java.io.BufferedInputStream;
+import java.io.Closeable;
+import java.io.FileInputStream;
+
+/* This code is used to check that the already-closed analysis handles different control flow
+ * structures appropriately.
+ */
+class AlreadyClosedControlFlow01 {
+  void for01(FileInputStream in) {
+    for (int i = 0; i < 10; ++i) {
+      in.close();
+    }
+    // The analyzer does not know how many loop iterations are executed, assumes 0+
+    // iterations are possible.
+    in.skip(0); // Positive finding.
+  }
+
+  void for02() {
+    for (int i = 0; i < 10; ++i) {
+      FileInputStream in = new FileInputStream("somefile");
+      in.skip(0);
+      in.close(); // Negative finding: new instance each iteration.
+    }
+  }
+
+  void if01() {
+    Closeable in = new FileInputStream("somefile");
+    if (System.currentTimeMillis() & 1 == 0) {
+      in.read();
+      in.close();
+    } else {
+      in.read();
+      in.close();
+    }
+  }
+
+  void if02() {
+    Closeable in = new FileInputStream("somefile");
+    in.close();
+    if (System.currentTimeMillis() & 1 == 0) {
+      in.read(); // Positive finding.
+    }
+  }
+
+  void if03() {
+    Closeable in = new FileInputStream("foo");
+    in.close();
+    // Check that the if condition is analyzed.
+    if (in.read() == -1) { // Positive finding.
+    }
+  }
+
+  void while01() {
+    Closeable in = new FileInputStream("bar");
+    while (true) {
+      in.read();
+      in.close();
+      break;
+    }
+    in.read(); // Positive finding.
+  }
+
+  void while02() {
+    Closeable in = new FileInputStream("bar");
+    while (in.read() != -1) { // Positive finding.
+      in.close();
+    }
+  }
+
+  void try01(BufferedInputStream in) {
+    try {
+      in.close();
+    } catch (Throwable t) {
+      in.read(); // Negative finding: preceding close call interrupted by exception.
+    }
+  }
+
+  void try02(BufferedInputStream in) {
+    try {
+      in.close();
+    } catch (Throwable t) {
+      in.read();
+    } finally {
+      in.read(); // Positive finding: can be reached after an uninterrupted close call.
+    }
+  }
+
+  void switch01(BufferedInputStream in, int i) {
+    switch (i) {
+      case 1:
+        in.close();
+        break;
+      case 2:
+        in.read();
+        break;
+      case 3:
+        in.close();
+      case 4:
+        in.read(); // Positive finding.
+        break;
+    }
+  }
+
+  void switch02(BufferedInputStream in, int i) {
+    switch (i) {
+      case 1:
+        in.close();
+        break;
+      case 2:
+        in.read();
+        break;
+      case 3:
+        in.close();
+        return;
+      case 4:
+        in.read();
+      default:
+        in.close();
+    }
+  }
+}
diff --git a/simplecfg/testdata/AlreadyClosedNegativeFindings01.javax b/simplecfg/testdata/AlreadyClosedNegativeFindings01.javax
new file mode 100644
index 0000000..f59ecd1
--- /dev/null
+++ b/simplecfg/testdata/AlreadyClosedNegativeFindings01.javax
@@ -0,0 +1,87 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real code! This file is parsed by the Java API analyzer tests
+ * to check that no findings are reported for this file.
+ */
+import java.io.Closeable;
+import java.io.FileInputStream;
+
+/* Negative findings for the already-closed analyzer. */
+class AlreadyClosedNegativeFindings01 {
+
+  static class MyCloseable {
+    public void close() {
+    }
+    public void write() {
+    }
+  }
+
+  void f1() {
+    // MyCloseable does not implement java.io.Closeable, so it should not cause findings.
+    MyCloseable closeable = new MyCloseable();
+    closeable.close();
+    closeable.write();
+  }
+
+  void f2() {
+    while (true) {
+      // This is a new instance each iteration, so close is only called once per instance.
+      Closeable in = new FileInputStream("x");
+      in.read();
+      in.close();
+      if (System.currentTimeMillis() % 2 == 1) {
+        break;
+      }
+  }
+
+  void f3() {
+    // This local variable is not effectively final, so it should not be analyzed.
+    Closeable in = new FileInputStream("x");
+    in.read();
+    in.close();
+    in = new FileInputStream("y");
+    in.read();
+  }
+
+  void f4() {
+    // This local variable is not effectively final, so it should not be analyzed.
+    Closeable in = new FileInputStream("x");
+    in.read();
+    in.close();
+    in = new FileInputStream("y");
+    in.read();
+  }
+
+  void f5(Closeable in) {
+    // Repeated calls to close() are allowed and do not produce findings.
+    in.close();
+    in.close();
+    in.close();
+    in.close();
+    in.close();
+  }
+
+  String f6(ByteArrayOutputStream out) {
+    out.close();
+    return out.toString(); // Negative finding: calling toString() after close() is okay.
+  }
+
+  byte[] f7(ByteArrayOutputStream out) {
+    out.close();
+    return out.toByteArray(); // Negative finding: calling toByteArray() after close() is okay.
+  }
+}
diff --git a/simplecfg/testdata/AlreadyClosedWriter01.javax b/simplecfg/testdata/AlreadyClosedWriter01.javax
new file mode 100644
index 0000000..2b7769c
--- /dev/null
+++ b/simplecfg/testdata/AlreadyClosedWriter01.javax
@@ -0,0 +1,29 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real code! This file is parsed by the Java API analyzer tests
+ * to check that the expected findings are reported for this file.
+ */
+
+/* This code is used to check that the already-closed analyzer can identify java.io.Writer
+ * as a subtype of java.io.Closeable and report a finding for a simple call after close.
+ */
+class AlreadyClosedWriter01 {
+  void f(java.io.Writer writer) {
+    writer.close();
+    writer.flush(); // Finding: Calling flush() after close().
+  }
+}
diff --git a/simplecfg/testdata/Close01.javax b/simplecfg/testdata/Close01.javax
new file mode 100644
index 0000000..025fc45
--- /dev/null
+++ b/simplecfg/testdata/Close01.javax
@@ -0,0 +1,25 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+public class Close01 {
+  void f(java.io.Writer writer) {
+    writer.close();
+    writer.write(new byte[10]);
+  }
+}
diff --git a/simplecfg/testdata/ConditionalExpr01.javax b/simplecfg/testdata/ConditionalExpr01.javax
new file mode 100644
index 0000000..de8385b
--- /dev/null
+++ b/simplecfg/testdata/ConditionalExpr01.javax
@@ -0,0 +1,25 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class ConditionalExpr01 {
+  static {
+    // Conditional expressions work like if statements.
+    int unused = x() ? y() : z();
+  }
+}
diff --git a/simplecfg/testdata/DoStmt01.javax b/simplecfg/testdata/DoStmt01.javax
new file mode 100644
index 0000000..d2a6d83
--- /dev/null
+++ b/simplecfg/testdata/DoStmt01.javax
@@ -0,0 +1,27 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class DoStmt01 {
+  {
+    do {
+      x();
+    } while (y());
+    z();
+  }
+}
diff --git a/simplecfg/testdata/DoStmt02.javax b/simplecfg/testdata/DoStmt02.javax
new file mode 100644
index 0000000..2e1fb9e
--- /dev/null
+++ b/simplecfg/testdata/DoStmt02.javax
@@ -0,0 +1,28 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class DoStmt02 {
+  {
+    // Test do statement with constant false condition.
+    do {
+      x();
+    } while (false);
+    y();
+  }
+}
diff --git a/simplecfg/testdata/EnhancedFor01.javax b/simplecfg/testdata/EnhancedFor01.javax
new file mode 100644
index 0000000..f1532b2
--- /dev/null
+++ b/simplecfg/testdata/EnhancedFor01.javax
@@ -0,0 +1,26 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class EnhancedFor01 {
+  {
+    for (int a : aList()) {
+      x();
+    }
+  }
+}
diff --git a/simplecfg/testdata/Filtering01.javax b/simplecfg/testdata/Filtering01.javax
new file mode 100644
index 0000000..8f83cee
--- /dev/null
+++ b/simplecfg/testdata/Filtering01.javax
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class Filtering01 {
+  int x(int c) {
+    // Test that uninteresting expressions are not included in the CFG.
+    int a = 4;
+    int b = 3;
+    for (int i = i(1, 4 * 5), j = j(); cond() && c == 3; u1(), j += c / 2, u2(), u3(), i++) {
+      stmt();
+      a += (--b) * c;
+    }
+    return a + b;
+  }
+}
diff --git a/simplecfg/testdata/ForStmt01.javax b/simplecfg/testdata/ForStmt01.javax
new file mode 100644
index 0000000..ce58d63
--- /dev/null
+++ b/simplecfg/testdata/ForStmt01.javax
@@ -0,0 +1,25 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class ForStmt01 {
+  void x() {
+    for (; call1(); ) {
+    }
+  }
+}
diff --git a/simplecfg/testdata/ForStmt02.javax b/simplecfg/testdata/ForStmt02.javax
new file mode 100644
index 0000000..f204489
--- /dev/null
+++ b/simplecfg/testdata/ForStmt02.javax
@@ -0,0 +1,26 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class ForStmt02 {
+  void x() {
+    for (; call1(); ) {
+      call2();
+    }
+  }
+}
diff --git a/simplecfg/testdata/ForStmt03.javax b/simplecfg/testdata/ForStmt03.javax
new file mode 100644
index 0000000..720fefd
--- /dev/null
+++ b/simplecfg/testdata/ForStmt03.javax
@@ -0,0 +1,25 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class ForStmt03 {
+  void x() {
+    for (int i = init(); cond(); update())
+      stmt();
+  }
+}
diff --git a/simplecfg/testdata/ForStmt04.javax b/simplecfg/testdata/ForStmt04.javax
new file mode 100644
index 0000000..29b0363
--- /dev/null
+++ b/simplecfg/testdata/ForStmt04.javax
@@ -0,0 +1,27 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class ForStmt04 {
+  {
+    // Initializer expressions and update statements are evaluated in the order they are listed.
+    for (int i = i(), j = j(); cond(); u1(), u2(), u3()) {
+      stmt();
+    }
+  }
+}
diff --git a/simplecfg/testdata/ForStmt05.javax b/simplecfg/testdata/ForStmt05.javax
new file mode 100644
index 0000000..7cea144
--- /dev/null
+++ b/simplecfg/testdata/ForStmt05.javax
@@ -0,0 +1,28 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class ForStmt05 {
+  {
+    // Test for statement with constant false condition.
+    for (Object o = i(); false; u()) {
+      x();
+    }
+    y();
+  }
+}
diff --git a/simplecfg/testdata/GenClassInstance01.javax b/simplecfg/testdata/GenClassInstance01.javax
new file mode 100644
index 0000000..26e7bae
--- /dev/null
+++ b/simplecfg/testdata/GenClassInstance01.javax
@@ -0,0 +1,24 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class GenClassInstance01 {
+  GenClassInstance01() {
+    new C(p1(), p2(), new D(p3() + p4()));
+  }
+}
diff --git a/simplecfg/testdata/GenClassInstance02.javax b/simplecfg/testdata/GenClassInstance02.javax
new file mode 100644
index 0000000..a73a972
--- /dev/null
+++ b/simplecfg/testdata/GenClassInstance02.javax
@@ -0,0 +1,28 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class GenClassInstance02 {
+  {
+    new Object() {
+      void f() {
+        notInParentCfg();
+      }
+    }.toString();
+  }
+}
diff --git a/simplecfg/testdata/GenForStmt01.javax b/simplecfg/testdata/GenForStmt01.javax
new file mode 100644
index 0000000..a1dab9a
--- /dev/null
+++ b/simplecfg/testdata/GenForStmt01.javax
@@ -0,0 +1,33 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class GenForStmt01 {
+  {
+    // Test a labeled break.
+    loop1:
+    for (int i = 3 * x; i < 100; ++i, u()) {
+      while (c()) {
+        if (i >= 40) {
+          break loop1;
+        }
+      }
+    }
+    fin();
+  }
+}
diff --git a/simplecfg/testdata/GenForStmt02.javax b/simplecfg/testdata/GenForStmt02.javax
new file mode 100644
index 0000000..23535ba
--- /dev/null
+++ b/simplecfg/testdata/GenForStmt02.javax
@@ -0,0 +1,33 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class GenForStmt02 {
+  {
+    // Test a labeled continue.
+    loop1:
+    for (int i = 3 * x; i < 100; ++i, u()) {
+      while (c()) {
+        if (i >= 40) {
+          continue loop1;
+        }
+      }
+    }
+    fin();
+  }
+}
diff --git a/simplecfg/testdata/GenSwitchStmt01.javax b/simplecfg/testdata/GenSwitchStmt01.javax
new file mode 100644
index 0000000..1ef81a6
--- /dev/null
+++ b/simplecfg/testdata/GenSwitchStmt01.javax
@@ -0,0 +1,46 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class GenSwitchStmt01 {
+  GenSwitchStmt01() {
+    while (x + y == 400 - z) {
+      switch (x) {
+        case -1:
+          c1();
+          break;
+        case 1:
+          break;
+        case 3:
+          c3();
+        case 2:
+          c2();
+          continue;
+        case 4:
+          c4();
+          break;
+        case 5:
+          c5();
+          return;
+        case 6:
+          c6();
+          break;
+      }
+    }
+  }
+}
diff --git a/simplecfg/testdata/GenTryStmt01.javax b/simplecfg/testdata/GenTryStmt01.javax
new file mode 100644
index 0000000..63975d3
--- /dev/null
+++ b/simplecfg/testdata/GenTryStmt01.javax
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class GenTryStmt01 {
+  void f(Exception exception) {
+    // Test that branches from throw statement go to both all catch clauses.
+    try {
+      if (cond()) {
+        throw exception;
+      }
+      x();
+    } catch (Exception1 e) {
+      c1();
+    } catch (Exception2 e) {
+      c2();
+    }
+  }
+}
diff --git a/simplecfg/testdata/GenTryStmt02.javax b/simplecfg/testdata/GenTryStmt02.javax
new file mode 100644
index 0000000..3fb2f47
--- /dev/null
+++ b/simplecfg/testdata/GenTryStmt02.javax
@@ -0,0 +1,30 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class GenTryStmt02 {
+  {
+    try {
+      tryBlock();
+    } catch (Exception unused) {
+      c1();
+    } catch (Throwable unused) {
+      c2();
+    }
+  }
+}
diff --git a/simplecfg/testdata/GenTryStmt03.javax b/simplecfg/testdata/GenTryStmt03.javax
new file mode 100644
index 0000000..3d0cf1f
--- /dev/null
+++ b/simplecfg/testdata/GenTryStmt03.javax
@@ -0,0 +1,33 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class GenTryStmt03 {
+  {
+    try {
+      x();
+    } catch (Throwable unused) {
+      c1();
+    } catch (Exception unused) {
+      // Never reached.
+      c2();
+    } finally {
+      f();
+    }
+  }
+}
diff --git a/simplecfg/testdata/GenTryStmt04.javax b/simplecfg/testdata/GenTryStmt04.javax
new file mode 100644
index 0000000..66f3e7d
--- /dev/null
+++ b/simplecfg/testdata/GenTryStmt04.javax
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class GenTryStmt04 {
+  void m() {
+    // Test that finally handlers are generated in separate CFG branches.
+    // Non-identical CFG nodes with the same name are expected in this graph.
+    try {
+      if (condition) {
+        a();
+        return;
+      }
+    } finally {
+      x();
+    }
+    y();
+  }
+}
diff --git a/simplecfg/testdata/GenTryStmt05.javax b/simplecfg/testdata/GenTryStmt05.javax
new file mode 100644
index 0000000..2d4d554
--- /dev/null
+++ b/simplecfg/testdata/GenTryStmt05.javax
@@ -0,0 +1,35 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class GenTryStmt05 {
+  void z() {
+    try {
+      try {
+        if (condition) throw exception;
+      } finally {
+        f1();
+        return;
+      }
+      a();
+    } finally {
+      f2();
+    }
+    b();
+  }
+}
diff --git a/simplecfg/testdata/GenTryStmt06.javax b/simplecfg/testdata/GenTryStmt06.javax
new file mode 100644
index 0000000..8af1b83
--- /dev/null
+++ b/simplecfg/testdata/GenTryStmt06.javax
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class GenTryStmt06 {
+  {
+    // Abrupt exit from nested finally block.
+    try {
+      try {
+        s();
+      } finally {
+        f1();
+        return;
+      }
+    } finally {
+      f2();
+    }
+  }
+}
diff --git a/simplecfg/testdata/GenTryStmt07.javax b/simplecfg/testdata/GenTryStmt07.javax
new file mode 100644
index 0000000..02a27a9
--- /dev/null
+++ b/simplecfg/testdata/GenTryStmt07.javax
@@ -0,0 +1,35 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class GenTryStmt07 {
+  {
+    try {
+      x();
+    } catch (Throwable unused) {
+      c1();
+      return;
+    } catch (Exception unused) {
+      // Never reached.
+      c2();
+    } finally {
+      f();
+    }
+    y();
+  }
+}
diff --git a/simplecfg/testdata/GenTryWithResources01.javax b/simplecfg/testdata/GenTryWithResources01.javax
new file mode 100644
index 0000000..c0c5c43
--- /dev/null
+++ b/simplecfg/testdata/GenTryWithResources01.javax
@@ -0,0 +1,30 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class GenTryWithResources01 {
+  {
+    try (AutoCloseable stream = openStream()) {
+      stmt();
+    } catch (IOException e) {
+      c();
+    } finally {
+      f();
+    }
+  }
+}
diff --git a/simplecfg/testdata/GenTryWithResources02.javax b/simplecfg/testdata/GenTryWithResources02.javax
new file mode 100644
index 0000000..d814c24
--- /dev/null
+++ b/simplecfg/testdata/GenTryWithResources02.javax
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class GenTryWithResources02 {
+  {
+    try (AutoCloseable s1 = o1();
+        AutoCloseable s2 = o2()) {
+      stmt();
+    } catch (IOException e) {
+      c();
+    } finally {
+      f();
+    }
+  }
+}
diff --git a/simplecfg/testdata/IfStmt01.javax b/simplecfg/testdata/IfStmt01.javax
new file mode 100644
index 0000000..ef8dd0b
--- /dev/null
+++ b/simplecfg/testdata/IfStmt01.javax
@@ -0,0 +1,26 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class IfStmt01 {
+  void f() {
+    if (call1()) {
+      onTrue();
+    }
+  }
+}
diff --git a/simplecfg/testdata/IfStmt02.javax b/simplecfg/testdata/IfStmt02.javax
new file mode 100644
index 0000000..0271e68
--- /dev/null
+++ b/simplecfg/testdata/IfStmt02.javax
@@ -0,0 +1,28 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class IfStmt02 {
+  void f() {
+    if (call1()) {
+      onTrue();
+    } else {
+      onFalse();
+    }
+  }
+}
diff --git a/simplecfg/testdata/IfStmt03.javax b/simplecfg/testdata/IfStmt03.javax
new file mode 100644
index 0000000..e515c9c
--- /dev/null
+++ b/simplecfg/testdata/IfStmt03.javax
@@ -0,0 +1,29 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class IfStmt03 {
+  void f() {
+    if (call1()) {
+      onTrue();
+    } else {
+      onFalse();
+      call2();
+    }
+  }
+}
diff --git a/simplecfg/testdata/IfStmt04.javax b/simplecfg/testdata/IfStmt04.javax
new file mode 100644
index 0000000..19c6c45
--- /dev/null
+++ b/simplecfg/testdata/IfStmt04.javax
@@ -0,0 +1,29 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class IfStmt04 {
+  void f() {
+    if (call1()) {
+      onTrue();
+      call2();
+    } else {
+      onFalse();
+    }
+  }
+}
diff --git a/simplecfg/testdata/MethodAccess01.javax b/simplecfg/testdata/MethodAccess01.javax
new file mode 100644
index 0000000..dad7cc7
--- /dev/null
+++ b/simplecfg/testdata/MethodAccess01.javax
@@ -0,0 +1,25 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class MethodAccess01 {
+  void f() {
+    // Parameters are evaluated before the outer method call.
+    x(p1(), p2(), p3());
+  }
+}
diff --git a/simplecfg/testdata/NullableDataflow01.javax b/simplecfg/testdata/NullableDataflow01.javax
new file mode 100644
index 0000000..41013ed
--- /dev/null
+++ b/simplecfg/testdata/NullableDataflow01.javax
@@ -0,0 +1,53 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ */
+import javax.annotation.Nullable;
+
+public class NullableDataflow01 {
+  boolean x = false;
+
+  void fp1(@Nullable String p) {
+    boolean var = p == null;
+    if (!var) {
+      p.hashCode(); // False positive: condition variable not effectively final.
+    }
+    var = false;
+  }
+
+  void fp2(@Nullable String p) {
+    boolean var = p != null;
+    if (var) {
+      p.hashCode(); // False positive: condition variable not effectively final.
+    }
+    var = false;
+  }
+
+  void n1(@Nullable String p) {
+    boolean var = p == null;
+    if (!var) {
+      p.hashCode(); // Negative.
+    }
+  }
+
+  void n2(@Nullable String p) {
+    boolean var = p != null;
+    if (var) {
+      p.hashCode(); // Negative.
+    }
+  }
+}
diff --git a/simplecfg/testdata/NullableDereference01.javax b/simplecfg/testdata/NullableDereference01.javax
new file mode 100644
index 0000000..e9b01b9
--- /dev/null
+++ b/simplecfg/testdata/NullableDereference01.javax
@@ -0,0 +1,37 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+import javax.annotation.Nullable;
+
+/**
+ * Test some simple positive findings for the Nullable Dereference analyzer.
+ */
+class NullableDereference01 {
+  int p1(@Nullable String[] p) {
+    return p.length;
+  }
+
+  String p2(@Nullable String[] p) {
+    return p[0];
+  }
+
+  int fn3(@Nullable String[] p) {
+    return p[0].size(); // False negative.
+  }
+}
diff --git a/simplecfg/testdata/NullableDereferenceEqExpr.javax b/simplecfg/testdata/NullableDereferenceEqExpr.javax
new file mode 100644
index 0000000..95adffa
--- /dev/null
+++ b/simplecfg/testdata/NullableDereferenceEqExpr.javax
@@ -0,0 +1,200 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import javax.annotation.Nullable;
+
+/**
+ * This is test data, not real source code!
+ * This contains tests for EQExpr null guards. Each test method contains
+ * one false positive dereference of the parameter p. The parameter is
+ * guarded by a null check in an equality expression.
+ */
+public class NullableDereferenceEqExpr {
+  /**
+   * Non-null when true condition.
+   * Null test in left hand side, comparing to false.
+   */
+  int nntLhsFalse(@Nullable String p) {
+    if (false == (p == null)) {
+      return p.size();
+    }
+    return 0;
+  }
+
+  /**
+   * Non-null when true condition.
+   * Null test in right hand side, comparing to false.
+   */
+  int nntRhsFalse(@Nullable String p) {
+    if ((p == null) == false) {
+      return p.size();
+    }
+    return 0;
+  }
+
+  /**
+   * Non-null when true condition.
+   * Null test in left hand side, comparing to true.
+   */
+  int nntLhsTrue(@Nullable String p) {
+    if (true == (p != null)) {
+      return p.size();
+    }
+    return 0;
+  }
+
+  /**
+   * Non-null when true condition.
+   * Null test in right hand side, comparing to true.
+   */
+  int nntRhsTrue(@Nullable String p) {
+    if ((p != null) == true) {
+      return p.size();
+    }
+    return 0;
+  }
+
+  /**
+   * Non-null when false condition.
+   * Null test in left hand side, comparing to false.
+   */
+  int nnfLhsFalse(@Nullable String p) {
+    if (false == (p != null)) {
+      return 0;
+    }
+    return p.size();
+  }
+
+  /**
+   * Non-null when false condition.
+   * Null test in right hand side, comparing to false.
+   */
+  int nnfRhsFalse(@Nullable String p) {
+    if ((p != null) == false) {
+      return 0;
+    }
+    return p.size();
+  }
+
+  /**
+   * Non-null when false condition.
+   * Null test in left hand side, comparing to true.
+   */
+  int nnfLhsTrue(@Nullable String p) {
+    if (true == (p == null)) {
+      return 0;
+    }
+    return p.size();
+  }
+
+  /**
+   * Non-null when false condition.
+   * Null test in right hand side, comparing to true.
+   */
+  int nnfRhsTrue(@Nullable String p) {
+    if ((p == null) == true) {
+      return 0;
+    }
+    return p.size();
+  }
+
+  /**
+   * Null when true condition (negated).
+   * Null test in left hand side, comparing to false.
+   */
+  int ntLhsFalse(@Nullable String p) {
+    if (!(false == (p != null))) {
+      return p.size();
+    }
+    return 0;
+  }
+
+  /**
+   * Null when true condition (negated).
+   * Null test in right hand side, comparing to false.
+   */
+  int ntRhsFalse(@Nullable String p) {
+    if (!((p != null) == false)) {
+      return p.size();
+    }
+    return 0;
+  }
+
+  /**
+   * Null when true condition (negated).
+   * Null test in left hand side, comparing to true.
+   */
+  int ntLhsTrue(@Nullable String p) {
+    if (!(true == (p == null))) {
+      return p.size();
+    }
+    return 0;
+  }
+
+  /**
+   * Null when true condition (negated).
+   * Null test in right hand side, comparing to true.
+   */
+  int ntRhsTrue(@Nullable String p) {
+    if (!((p == null) == true)) {
+      return p.size();
+    }
+    return 0;
+  }
+
+  /**
+   * Null when false condition (negated).
+   * Null test in left hand side, comparing to false.
+   */
+  int nfLhsFalse(@Nullable String p) {
+    if (!(false == (p == null))) {
+      return 0;
+    }
+    return p.size();
+  }
+
+  /**
+   * Null when false condition (negated).
+   * Null test in right hand side, comparing to false.
+   */
+  int nfRhsFalse(@Nullable String p) {
+    if (!((p == null) == false)) {
+      return 0;
+    }
+    return p.size();
+  }
+
+  /**
+   * Null when false condition (negated).
+   * Null test in left hand side, comparing to true.
+   */
+  int nfLhsTrue(@Nullable String p) {
+    if (!(true == (p != null))) {
+      return 0;
+    }
+    return p.size();
+  }
+
+  /**
+   * Null when false condition (negated).
+   * Null test in right hand side, comparing to true.
+   */
+  int nfRhsTrue(@Nullable String p) {
+    if (!((p != null) == true)) {
+      return 0;
+    }
+    return p.size();
+  }
+}
diff --git a/simplecfg/testdata/NullableDereferenceIssue10.javax b/simplecfg/testdata/NullableDereferenceIssue10.javax
new file mode 100644
index 0000000..cd5e584
--- /dev/null
+++ b/simplecfg/testdata/NullableDereferenceIssue10.javax
@@ -0,0 +1,36 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* This is test data, not real source code! */
+import javax.annotation.Nullable;
+
+/**
+ * Test a false positive finding from GitHub issue #10
+ * (https://github.com/google/simplecfg/issues/10).
+ */
+class NullableDereferenceIssue10 {
+  static class A {
+    public void m() {
+    }
+  }
+
+  void fp1(@Nullable A x, @Nullable A y) {
+    if (x == null && y == null) {
+      return;
+    }
+    // If x is null then y is not null.
+    z = (x != null) ? x.m() : y.m(); // False positive for y.m().
+  }
+}
diff --git a/simplecfg/testdata/NullableDereferenceIssue11.javax b/simplecfg/testdata/NullableDereferenceIssue11.javax
new file mode 100644
index 0000000..fb1fdaa
--- /dev/null
+++ b/simplecfg/testdata/NullableDereferenceIssue11.javax
@@ -0,0 +1,46 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import javax.annotation.Nullable;
+
+/**
+ * This is test data, not real source code!
+ * Test for GitHub issue #11 (https://github.com/google/simplecfg/issues/11).
+ */
+public class Issue11 {
+  /** Test nullable deref in true-part of conditional expression. */
+  int test(@Nullable String p, boolean maybe) {
+    if (p == null || (maybe ? p.size() != 1 : false)) { // Negative finding.
+      return 1;
+    }
+    return 2;
+  }
+
+  /** Test nullable deref in false-part of conditional expression. */
+  int test2(@Nullable String p, boolean maybe) {
+    if (p == null || (maybe ? false : p.size() != 1)) { // Negative finding.
+      return 1;
+    }
+    return 2;
+  }
+
+  /** Test that the same null-guard used above works outside of conditional expression. */
+  int test3(@Nullable String p) {
+    if (p == null || p.size() != 1) { // Negative finding.
+      return 1;
+    }
+    return 2;
+  }
+}
diff --git a/simplecfg/testdata/NullableDereferenceIssue12.javax b/simplecfg/testdata/NullableDereferenceIssue12.javax
new file mode 100644
index 0000000..95ca235
--- /dev/null
+++ b/simplecfg/testdata/NullableDereferenceIssue12.javax
@@ -0,0 +1,45 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import javax.annotation.Nullable;
+
+/**
+ * This is test data, not real source code!
+ * Test for GitHub issue #12 (https://github.com/google/simplecfg/issues/12).
+ */
+public class NullableDereferenceIssue12 {
+  /**
+   * The condition (false == x) is equivalent to (!x), however this test
+   * shows a bug causing a null guard check to fail for (false == x)
+   * expressions.
+   */
+  int test(@Nullable String p) {
+    if (false == (p != null)) {
+      return 0;
+    }
+    return p.size(); // Negative finding: not reachable if p == null.
+  }
+
+  /**
+   * The condition in this if-statement and the one in the first test are
+   * equivalent but this version does not give a false positive.
+   */
+  int test2(@Nullable String p) {
+    if (!(p != null)) {
+      return 0;
+    }
+    return p.size(); // Negative finding.
+  }
+}
diff --git a/simplecfg/testdata/NullableDereferenceIssue13.javax b/simplecfg/testdata/NullableDereferenceIssue13.javax
new file mode 100644
index 0000000..27a28b9
--- /dev/null
+++ b/simplecfg/testdata/NullableDereferenceIssue13.javax
@@ -0,0 +1,40 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import javax.annotation.Nullable;
+
+/**
+ * This is test data, not real source code!
+ * Test for GitHub issue #13 (https://github.com/google/simplecfg/issues/13).
+ */
+public class NullableDereferenceIssue13 {
+  protected final Object obj;
+
+  public NullableDereferenceIssue13(@Nullable Object obj) {
+    this.obj = obj;
+
+    // Calling test() is equivalent to checking obj != null,
+    // however, the current NullableDereference implementation
+    // can not handle this case, even though test() is declared
+    // inside the same class.
+    if (test()) {
+      obj.hashCode(); // False positive finding generated here.
+    }
+  }
+
+  private boolean test() {
+    return obj != null;
+  }
+}
diff --git a/simplecfg/testdata/NullableDereferenceMethodCall.javax b/simplecfg/testdata/NullableDereferenceMethodCall.javax
new file mode 100644
index 0000000..c2bcf20
--- /dev/null
+++ b/simplecfg/testdata/NullableDereferenceMethodCall.javax
@@ -0,0 +1,55 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import javax.annotation.Nullable;
+
+/**
+ * This is test data, not real source code!
+ *
+ * <p>This class contains tests checking that a null dereference
+ * finding is not reported for a parameter p after p has been used
+ * as an argument in a method call. The NullableDereference
+ * analyzer is not an interprocedural analysis, so we can not know
+ * if the method called will perform a null check and ensure
+ * non-nullness of the argument after the call completes. Instead
+ * we should just stop analyzing a parameter after it has been
+ * passed to another method.
+ */
+public class NullableDereferenceMethodCall {
+  public interface SomeApi {
+    public void doSomething(String str);
+  }
+
+  int interfaceMethodCall(@Nullable String p, SomeApi s) {
+    s.doSomething(p);
+    return p.size(); // No finding here, since doSomething might have done a null check.
+  }
+
+  int interfaceMethodCall2(@Nullable String p, SomeApi s) {
+    int size = p.size(); // Finding here: no call yet.
+    s.doSomething(p);
+    return size;
+  }
+
+  int methodCall(@Nullable String p, String q) {
+    q.equals(p);
+    return p.size();
+  }
+
+  int localMethodCall(@Nullable String p) {
+    localMethod(p);
+    return p.size(); // No finding here, we don't analyze even local methods.
+  }
+}
diff --git a/simplecfg/testdata/NullableDereferenceNeExpr.javax b/simplecfg/testdata/NullableDereferenceNeExpr.javax
new file mode 100644
index 0000000..f70f138
--- /dev/null
+++ b/simplecfg/testdata/NullableDereferenceNeExpr.javax
@@ -0,0 +1,200 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import javax.annotation.Nullable;
+
+/**
+ * This is test data, not real source code!
+ * This contains tests for NEExpr null guards. Each test method contains
+ * one false positive dereference of the parameter p. The parameter is
+ * guarded by a null check in an inequality expression.
+ */
+public class NullableDereferenceNeExpr {
+  /**
+   * Non-null when true condition.
+   * Null test in left hand side, comparing to false.
+   */
+  int nntLhsFalse(@Nullable String p) {
+    if (false != (p != null)) {
+      return p.size();
+    }
+    return 0;
+  }
+
+  /**
+   * Non-null when true condition.
+   * Null test in right hand side, comparing to false.
+   */
+  int nntRhsFalse(@Nullable String p) {
+    if ((p != null) != false) {
+      return p.size();
+    }
+    return 0;
+  }
+
+  /**
+   * Non-null when true condition.
+   * Null test in left hand side, comparing to true.
+   */
+  int nntLhsTrue(@Nullable String p) {
+    if (true != (p == null)) {
+      return p.size();
+    }
+    return 0;
+  }
+
+  /**
+   * Non-null when true condition.
+   * Null test in right hand side, comparing to true.
+   */
+  int nntRhsTrue(@Nullable String p) {
+    if ((p == null) != true) {
+      return p.size();
+    }
+    return 0;
+  }
+
+  /**
+   * Non-null when false condition.
+   * Null test in left hand side, comparing to false.
+   */
+  int nnfLhsFalse(@Nullable String p) {
+    if (false != (p == null)) {
+      return 0;
+    }
+    return p.size();
+  }
+
+  /**
+   * Non-null when false condition.
+   * Null test in right hand side, comparing to false.
+   */
+  int nnfRhsFalse(@Nullable String p) {
+    if ((p == null) != false) {
+      return 0;
+    }
+    return p.size();
+  }
+
+  /**
+   * Non-null when false condition.
+   * Null test in left hand side, comparing to true.
+   */
+  int nnfLhsTrue(@Nullable String p) {
+    if (true != (p != null)) {
+      return 0;
+    }
+    return p.size();
+  }
+
+  /**
+   * Non-null when false condition.
+   * Null test in right hand side, comparing to true.
+   */
+  int nnfRhsTrue(@Nullable String p) {
+    if ((p != null) != true) {
+      return 0;
+    }
+    return p.size();
+  }
+
+  /**
+   * Null when true condition (negated).
+   * Null test in left hand side, comparing to false.
+   */
+  int ntLhsFalse(@Nullable String p) {
+    if (!(false != (p == null))) {
+      return p.size();
+    }
+    return 0;
+  }
+
+  /**
+   * Null when true condition (negated).
+   * Null test in right hand side, comparing to false.
+   */
+  int ntRhsFalse(@Nullable String p) {
+    if (!((p == null) != false)) {
+      return p.size();
+    }
+    return 0;
+  }
+
+  /**
+   * Null when true condition (negated).
+   * Null test in left hand side, comparing to true.
+   */
+  int ntLhsTrue(@Nullable String p) {
+    if (!(true != (p != null))) {
+      return p.size();
+    }
+    return 0;
+  }
+
+  /**
+   * Null when true condition (negated).
+   * Null test in right hand side, comparing to true.
+   */
+  int ntRhsTrue(@Nullable String p) {
+    if (!((p != null) != true)) {
+      return p.size();
+    }
+    return 0;
+  }
+
+  /**
+   * Null when false condition (negated).
+   * Null test in left hand side, comparing to false.
+   */
+  int nfLhsFalse(@Nullable String p) {
+    if (!(false != (p != null))) {
+      return 0;
+    }
+    return p.size();
+  }
+
+  /**
+   * Null when false condition (negated).
+   * Null test in right hand side, comparing to false.
+   */
+  int nfRhsFalse(@Nullable String p) {
+    if (!((p != null) != false)) {
+      return 0;
+    }
+    return p.size();
+  }
+
+  /**
+   * Null when false condition (negated).
+   * Null test in left hand side, comparing to true.
+   */
+  int nfLhsTrue(@Nullable String p) {
+    if (!(true != (p == null))) {
+      return 0;
+    }
+    return p.size();
+  }
+
+  /**
+   * Null when false condition (negated).
+   * Null test in right hand side, comparing to true.
+   */
+  int nfRhsTrue(@Nullable String p) {
+    if (!((p == null) != true)) {
+      return 0;
+    }
+    return p.size();
+  }
+}
diff --git a/simplecfg/testdata/NullableInstanceOf.javax b/simplecfg/testdata/NullableInstanceOf.javax
new file mode 100644
index 0000000..de6c069
--- /dev/null
+++ b/simplecfg/testdata/NullableInstanceOf.javax
@@ -0,0 +1,46 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+import javax.annotation.Nullable;
+
+/**
+ * Using instanceof to test for null.
+ */
+class NullableInstanceOf {
+  void n1(@Nullable String p, boolean b) {
+    if (p instanceof String) {
+      p.size();
+    }
+  }
+
+  void n2(@Nullable String p, boolean b) {
+    if (!(p instanceof String)) {
+      return;
+    }
+    p.size();
+  }
+
+  int n2(@Nullable String p, boolean b) {
+    return (p instanceof String) ? p.size() : 0;
+  }
+
+  void n2(@Nullable String p, boolean b) {
+    return !(p instanceof String) ? 0 : p.size();
+  }
+}
diff --git a/simplecfg/testdata/NullableMethodNullGuard01.javax b/simplecfg/testdata/NullableMethodNullGuard01.javax
new file mode 100644
index 0000000..0ec5ab6
--- /dev/null
+++ b/simplecfg/testdata/NullableMethodNullGuard01.javax
@@ -0,0 +1,66 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+import javax.annotation.Nullable;
+import com.google.common.base.Strings;
+
+/**
+ * Test using methods for null guards.
+ */
+class NullableMethodNullGuard01 {
+  int f1(@Nullable String p) {
+    if (Stings.isNullOrEmpty(p)) return 0;
+    return p.hashCode(); // negative
+  }
+
+  int f2(@Nullable String p) {
+    if (isNotNull(p)) {
+      return p.hashCode(); // negative
+    }
+    return 0;
+  }
+
+  int f3(@Nullable String p) {
+    if (!isNonNull(p)) return 0;
+    return p.hashCode(); // negative
+  }
+
+  int f4(@Nullable String p) {
+    checkNotNull(p);
+    return p.hashCode(); // negative
+  }
+
+  int f5(@Nullable String p) {
+    checkNonNull(p);
+    return p.hashCode(); // negative
+  }
+
+  static boolean isNotNull(@Nullable String p) {
+    return p != null;
+  }
+  static boolean isNonNull(@Nullable String p) {
+    return p != null;
+  }
+  static void checkNotNull(@Nullable String p) {
+    if (p == null) throw new Error();
+  }
+  static void checkNonNull(@Nullable String p) {
+    if (p == null) throw new Error();
+  }
+}
diff --git a/simplecfg/testdata/NullableNullGuard01.javax b/simplecfg/testdata/NullableNullGuard01.javax
new file mode 100644
index 0000000..cb9b423
--- /dev/null
+++ b/simplecfg/testdata/NullableNullGuard01.javax
@@ -0,0 +1,95 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+import javax.annotation.Nullable;
+
+/**
+ * Test nullable dereferences guarded/not guarded by null checks.
+ */
+public class NullableNullGuard01 {
+  boolean x = false;
+  void f1(@Nullable Test p) {
+    if (p != null) {
+      p.f1(p); // negative
+    }
+  }
+  boolean f2(@Nullable Test p) {
+    return p == null || p.f1(p); // negative
+  }
+  boolean f3(@Nullable Test p) {
+    return p == null ? false : p.f1(p); // negative
+  }
+  boolean f4(@Nullable Test p) {
+    return p != null ? p.f1(p) : false; // negative
+  }
+  boolean f5(@Nullable Test p) {
+    return p != null || p.f1(p); // positive
+  }
+  boolean f5(@Nullable Test p) {
+    p = null;
+    return p.x; // negative
+  }
+  boolean f5(@Nullable Test p) {
+    return p.x; // positive
+  }
+  void f6(@Nullable Test p) {
+    if (p == null) return;
+    p.x = true; // negative
+  }
+  void f6(@Nullable Test p) {
+    while (true) {
+      if (p == null) break;
+      p.x = true; // negative
+    }
+  }
+  void f6(@Nullable Test p) {
+    while (p.x) { // positive
+      if (p == null) continue;
+      p.x = false; // negative
+    }
+  }
+  void f7(@Nullable Test p) {
+    while (p == null) {
+    }
+    p.x = false; // Negative: not reachable.
+  }
+
+  void f8(@Nullable Test p) {
+    while (p == null) {
+      if (System.currentTimeMillis() & 1 == 0) {
+        return;
+      }
+    }
+    p.x = false; // Negative.
+  }
+
+  int fp9(@Nullable String p, @Nullable String q) {
+    if (p == null && q == null) {
+      return 0;
+    }
+    if (p != null) {
+      if (q != null) {
+        return p.size() + q.size();
+      } else {
+        return p.size();
+      }
+    }
+    return q.size(); // False positive.
+  }
+}
diff --git a/simplecfg/testdata/NullableNullGuard02.javax b/simplecfg/testdata/NullableNullGuard02.javax
new file mode 100644
index 0000000..4221cf6
--- /dev/null
+++ b/simplecfg/testdata/NullableNullGuard02.javax
@@ -0,0 +1,74 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+import javax.annotation.Nullable;
+
+/**
+ * More complex conditional null guards.
+ */
+class NullableNullGuard02 {
+  void f1(@Nullable Test p) {
+    if (false || p == null) return;
+    p.x = true; // negative
+  }
+  void f2(@Nullable Test p, String n) {
+    while (p != null && n == null) {
+      p.x = true; // negative
+    }
+  }
+  void f3(@Nullable Test p, String n) {
+    if (p == null || false) return;
+    p.x = true; // negative
+  }
+  void f4(@Nullable Test p, String n) {
+    if (p == null || n == null) return;
+    p.x = true; // negative
+  }
+  void f4(@Nullable Test p, String n) {
+    for (; p == null || n == null; ) return;
+    p.x = true; // negative
+  }
+  void f5(@Nullable Test p, String n) {
+    if (p != null || n == null) {
+      p.x = true; // positive
+    }
+  }
+  void f6(@Nullable Test p, String n) {
+    if (p != null || n == null) {
+      p.x = true; // positive
+    }
+  }
+  void f7(@Nullable Test p, String n) {
+    if (p != null || false) {
+      p.x = true; // negative
+    }
+  }
+
+  boolean f8(@Nullable Test p, String n) {
+    return p != null && p.x; // Negative.
+  }
+
+  boolean f9(@Nullable Test p, String n) {
+    return p != null && (n == null || p.x); // Negative.
+  }
+
+  boolean f10(@Nullable Test p, String n) {
+    return p == null || (n == null || p.x); // Negative.
+  }
+}
diff --git a/simplecfg/testdata/NullableNullGuard03.javax b/simplecfg/testdata/NullableNullGuard03.javax
new file mode 100644
index 0000000..4e9d137
--- /dev/null
+++ b/simplecfg/testdata/NullableNullGuard03.javax
@@ -0,0 +1,140 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+import javax.annotation.Nullable;
+
+/**
+ * More complex conditional null guards.
+ */
+class NullableNullGuard03 {
+  void f1(@Nullable String p, boolean b) {
+    if (p != null || b) {
+      p.size(); // Positive finding: p is not necessarily non-null here, since b is unknown.
+    }
+  }
+
+  void f2(@Nullable String p, boolean b) {
+    if (b || p != null) {
+      p.size(); // Positive finding.
+    }
+  }
+
+  void f3(@Nullable String p, boolean b) {
+    if (p == null && b) {
+    } else {
+      p.size(); // Positive finding.
+    }
+  }
+
+  void f4(@Nullable String p, boolean b) {
+    if (b && p == null) {
+    } else {
+      p.size(); // Positive finding.
+    }
+  }
+
+  void f5(@Nullable String p, boolean b) {
+    if (p == null || b) {
+    } else {
+      p.size(); // Negative finding.
+    }
+  }
+
+  void f6(@Nullable String p, boolean b) {
+    if (b || p == null) {
+    } else {
+      p.size(); // Negative finding.
+    }
+  }
+
+  void f7(@Nullable String p, boolean b) {
+    while (b && p != null) {
+      p.size(); // Negative finding.
+    }
+  }
+
+  void f8(@Nullable String p) {
+    while (p != null) {
+      p.size(); // Negative finding.
+    }
+  }
+
+  void f9(@Nullable String p, boolean b) {
+    while (b && p != null) {
+      p.size(); // Negative finding.
+    }
+  }
+
+  void f10(@Nullable String p, boolean b) {
+    while (p != null && b) {
+      p.size(); // Negative finding.
+    }
+  }
+
+  void f11(@Nullable String p) {
+    while (p == null) {
+      return;
+    }
+    p.size(); // Negative finding.
+  }
+
+  void f12(@Nullable String p, boolean b) {
+    while (b || p == null) {
+      return;
+    }
+    p.size(); // Negative finding.
+  }
+
+  void f13(@Nullable String p, boolean b) {
+    while (p == null || b) {
+      return;
+    }
+    p.size(); // Negative finding.
+  }
+
+  void f14(@Nullable String p, boolean b) {
+    while (b || p != null) {
+      p.size(); // Positive finding.
+    }
+  }
+
+  void f15(@Nullable String p, boolean b) {
+    while (p == null || b) {
+      p.size(); // Positive finding.
+    }
+  }
+
+  void f16(@Nullable String p, boolean b) {
+    while (b || p == null) {
+    }
+    p.size(); // Positive finding.
+  }
+
+  void f17(@Nullable String p, boolean b) {
+    while (p == null || b) {
+    }
+    p.size(); // Positive finding.
+  }
+
+  void f18(@Nullable String p, boolean b) {
+    if (p != null & b) {
+      p.size(); // Negative finding.
+    }
+  }
+}
diff --git a/simplecfg/testdata/NullableVariableArity.javax b/simplecfg/testdata/NullableVariableArity.javax
new file mode 100644
index 0000000..8690959
--- /dev/null
+++ b/simplecfg/testdata/NullableVariableArity.javax
@@ -0,0 +1,35 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+import javax.annotation.Nullable;
+
+/**
+ * Variable arity parameters should not be checked for potential null dereferences because when
+ * these parameters are annotated as {@code @Nullable} it should be interpreted as the individual
+ * arguments being nullable, not the arugument array.
+ */
+class NullableVariableArity {
+  int n1(@Nullable String... p) {
+    return p.length;
+  }
+
+  int n2(@Nullable String... p) {
+    return p[0].size();
+  }
+}
diff --git a/simplecfg/testdata/SwitchStmt01.javax b/simplecfg/testdata/SwitchStmt01.javax
new file mode 100644
index 0000000..5441285
--- /dev/null
+++ b/simplecfg/testdata/SwitchStmt01.javax
@@ -0,0 +1,36 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class SwitchStmt01 {
+  {
+    // Test switch with default label.
+    switch (expr()) {
+      case 1:
+        x();
+      case 2:
+        // Fallthrough.
+        y();
+        break;
+      case 3:
+        z();
+      default:
+        d();
+    }
+  }
+}
diff --git a/simplecfg/testdata/SwitchStmt02.javax b/simplecfg/testdata/SwitchStmt02.javax
new file mode 100644
index 0000000..a86c3da
--- /dev/null
+++ b/simplecfg/testdata/SwitchStmt02.javax
@@ -0,0 +1,34 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class SwitchStmt02 {
+  {
+    // Test switch without default label.
+    switch (expr()) {
+      case 1:
+        x();
+      case 2:
+        // Fallthrough.
+        y();
+        break;
+      case 3:
+        z();
+    }
+  }
+}
diff --git a/simplecfg/testdata/ThrowStmt01.javax b/simplecfg/testdata/ThrowStmt01.javax
new file mode 100644
index 0000000..b9a5b3c
--- /dev/null
+++ b/simplecfg/testdata/ThrowStmt01.javax
@@ -0,0 +1,26 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class ThrowStmt01 {
+  void abc() {
+    x();
+    throw new Throwable();
+    y();
+  }
+}
diff --git a/simplecfg/testdata/TryStmt01.javax b/simplecfg/testdata/TryStmt01.javax
new file mode 100644
index 0000000..bd81d04
--- /dev/null
+++ b/simplecfg/testdata/TryStmt01.javax
@@ -0,0 +1,32 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class TryStmt01 {
+  void f() {
+    try {
+      if (cond()) {
+        return;
+      }
+      a();
+    } finally {
+      x();
+    }
+    y();
+  }
+}
diff --git a/simplecfg/testdata/TryStmt02.javax b/simplecfg/testdata/TryStmt02.javax
new file mode 100644
index 0000000..2ce30a1
--- /dev/null
+++ b/simplecfg/testdata/TryStmt02.javax
@@ -0,0 +1,29 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class TryStmt02 {
+  {
+    try {
+    } catch (java.io.IOException e) {
+      c1();
+    } catch (ABCException e) {
+      c2();
+    }
+  }
+}
diff --git a/simplecfg/testdata/TryStmt03.javax b/simplecfg/testdata/TryStmt03.javax
new file mode 100644
index 0000000..ea202aa
--- /dev/null
+++ b/simplecfg/testdata/TryStmt03.javax
@@ -0,0 +1,33 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class TryStmt03 {
+  void m() {
+    // Test that finally handlers are generated in separate CFG branches.
+    // Non-identical CFG nodes with the same name are expected in this graph.
+    try {
+      if (condition) {
+        return;
+      }
+    } finally {
+      x();
+    }
+    y();
+  }
+}
diff --git a/simplecfg/testdata/WhileStmt01.javax b/simplecfg/testdata/WhileStmt01.javax
new file mode 100644
index 0000000..e52225d
--- /dev/null
+++ b/simplecfg/testdata/WhileStmt01.javax
@@ -0,0 +1,26 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class WhileStmt01 {
+  {
+    // Test that infinite while loop never terminates.
+    while (true) {
+    }
+  }
+}
diff --git a/simplecfg/testdata/WhileStmt02.javax b/simplecfg/testdata/WhileStmt02.javax
new file mode 100644
index 0000000..a38bcd3
--- /dev/null
+++ b/simplecfg/testdata/WhileStmt02.javax
@@ -0,0 +1,25 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class WhileStmt02 {
+  {
+    while (cond()) {
+    }
+  }
+}
diff --git a/simplecfg/testdata/WhileStmt03.javax b/simplecfg/testdata/WhileStmt03.javax
new file mode 100644
index 0000000..9d9bf61
--- /dev/null
+++ b/simplecfg/testdata/WhileStmt03.javax
@@ -0,0 +1,30 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class WhileStmt03 {
+  {
+    // A while statement with a conditional break.
+    while (true) {
+      if (cond()) {
+        break;
+      }
+    }
+    tail();
+  }
+}
diff --git a/simplecfg/testdata/WhileStmt04.javax b/simplecfg/testdata/WhileStmt04.javax
new file mode 100644
index 0000000..6010cb1
--- /dev/null
+++ b/simplecfg/testdata/WhileStmt04.javax
@@ -0,0 +1,32 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class WhileStmt04 {
+  {
+    // A while loop with conditional continue and break.
+    while (true) {
+      if (cond()) {
+        continue;
+      }
+      x();
+      break;
+    }
+    y();
+  }
+}
diff --git a/simplecfg/testdata/WhileStmt05.javax b/simplecfg/testdata/WhileStmt05.javax
new file mode 100644
index 0000000..34928a4
--- /dev/null
+++ b/simplecfg/testdata/WhileStmt05.javax
@@ -0,0 +1,28 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * This is test data, not real source code!
+ * StmtCfgTest builds and tests the CFG for the first block/method in this class.
+ */
+class WhileStmt05 {
+  {
+    // Test while loop with constant false condition.
+    while (false) {
+      x();
+    }
+    y();
+  }
+}
-- 
GitLab