Initial commit of respository.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..cfe6248
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,48 @@
+# Contributing to the Checker Framework
+
+Thank you for contributing to the Checker Framework!  This project is a
+community effort of [more than 110
+developers](https://checkerframework.org/manual/#credits), plus countless
+more people who have contributed bug reports and feature suggestions.  We
+couldn't do it without your help.
+
+
+## Reporting bugs
+
+Please see the [bug
+reporting](https://checkerframework.org/manual/#reporting-bugs) section of
+the Checker Framework manual.
+
+If the documentation is incorrect, incomplete, or confusing, that is a
+bug, and we want to fix it.  Please report it.
+
+
+## Submitting changes
+
+Please see the [pull
+requests](https://rawgit.com/typetools/checker-framework/master/docs/developer/developer-manual.html#pull-requests)
+section of the Developer Manual.
+
+Submit changes to the annotated JDK at https://github.com/typetools/jdk/pulls .
+Annotations for other libraries can be contributed as stub files in this
+repository, in a fork of the library in https://github.com/typetools/, or
+in the library's own repository.
+
+Do you want to contribute to the project, but you are not sure what issue
+to fix or what feature to add?  Use the tool in your daily work, and when
+you encounter a limitation that bothers you, fix that one.  The ["help
+wanted"](https://github.com/typetools/checker-framework/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22)
+label marks issues that require less deep knowledge and may be appropriate
+for a newcomer to the codebase.
+
+
+## License
+
+By contributing, you agree that your contributions will be licensed under the
+existing [license](LICENSE.txt), usually GPL2 or MIT License.
+
+
+## Code of conduct
+
+When interacting with other people, please abide by the [Contributor
+Covenant](https://www.contributor-covenant.org/version/2/0/code_of_conduct).
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..827585f
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,413 @@
+The Checker Framework
+Copyright 2004-present by the Checker Framework developers
+
+
+Most of the Checker Framework is licensed under the GNU General Public
+License, version 2 (GPL2), with the classpath exception.  The text of this
+license appears below.  This is the same license used for OpenJDK.
+
+A few parts of the Checker Framework have more permissive licenses, notably
+the parts that you might want to include with your own program.
+
+ * The annotations and utility files are licensed under the MIT License.
+   (The text of this license also appears below.)  This applies to
+   checker-qual*.jar and checker-util.jar and all the files that appear in
+   them, which is all files in checker-qual and checker-util directories.
+   It also applies to the cleanroom implementations of
+   third-party annotations (in checker/src/testannotations/,
+   framework/src/main/java/org/jmlspecs/, and
+   framework/src/main/java/com/google/).
+
+The Checker Framework includes annotations for some libraries.  Those in
+.astub files use the MIT License.  Those in https://github.com/typetools/jdk
+(which appears in the annotated-jdk directory of file checker.jar) use the
+GPL2 license.
+
+Some external libraries that are included with the Checker Framework
+distribution have different licenses.  Here are some examples.
+
+ * JavaParser is dual licensed under the LGPL or the Apache license -- you
+   may use it under whichever one you want.  (The JavaParser source code
+   contains a file with the text of the GPL, but it is not clear why, since
+   JavaParser does not use the GPL.)  See
+   https://github.com/typetools/stubparser .
+
+ * Annotation Tools (https://github.com/typetools/annotation-tools) uses
+   the MIT license.
+
+ * Libraries in plume-lib (https://github.com/plume-lib/) are licensed
+   under the MIT License.
+
+===========================================================================
+
+The GNU General Public License (GPL)
+
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to share
+and change it.  By contrast, the GNU General Public License is intended to
+guarantee your freedom to share and change free software--to make sure the
+software is free for all its users.  This General Public License applies to
+most of the Free Software Foundation's software and to any other program whose
+authors commit to using it.  (Some other Free Software Foundation software is
+covered by the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+When we speak of free software, we are referring to freedom, not price.  Our
+General Public Licenses are designed to make sure that you have the freedom to
+distribute copies of free software (and charge for this service if you wish),
+that you receive source code or can get it if you want it, that you can change
+the software or use pieces of it in new free programs; and that you know you
+can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to deny
+you these rights or to ask you to surrender the rights.  These restrictions
+translate to certain responsibilities for you if you distribute copies of the
+software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or for
+a fee, you must give the recipients all the rights that you have.  You must
+make sure that they, too, receive or can get the source code.  And you must
+show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2)
+offer you this license which gives you legal permission to copy, distribute
+and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that
+everyone understands that there is no warranty for this free software.  If the
+software is modified by someone else and passed on, we want its recipients to
+know that what they have is not the original, so that any problems introduced
+by others will not reflect on the original authors' reputations.
+
+Finally, any free program is threatened constantly by software patents.  We
+wish to avoid the danger that redistributors of a free program will
+individually obtain patent licenses, in effect making the program proprietary.
+To prevent this, we have made it clear that any patent must be licensed for
+everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification
+follow.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice
+placed by the copyright holder saying it may be distributed under the terms of
+this General Public License.  The "Program", below, refers to any such program
+or work, and a "work based on the Program" means either the Program or any
+derivative work under copyright law: that is to say, a work containing the
+Program or a portion of it, either verbatim or with modifications and/or
+translated into another language.  (Hereinafter, translation is included
+without limitation in the term "modification".) Each licensee is addressed as
+"you".
+
+Activities other than copying, distribution and modification are not covered by
+this License; they are outside its scope.  The act of running the Program is
+not restricted, and the output from the Program is covered only if its contents
+constitute a work based on the Program (independent of having been made by
+running the Program).  Whether that is true depends on what the Program does.
+
+1. You may copy and distribute verbatim copies of the Program's source code as
+you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this License
+and to the absence of any warranty; and give any other recipients of the
+Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you may
+at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of it, thus
+forming a work based on the Program, and copy and distribute such modifications
+or work under the terms of Section 1 above, provided that you also meet all of
+these conditions:
+
+    a) You must cause the modified files to carry prominent notices stating
+    that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in whole or
+    in part contains or is derived from the Program or any part thereof, to be
+    licensed as a whole at no charge to all third parties under the terms of
+    this License.
+
+    c) If the modified program normally reads commands interactively when run,
+    you must cause it, when started running for such interactive use in the
+    most ordinary way, to print or display an announcement including an
+    appropriate copyright notice and a notice that there is no warranty (or
+    else, saying that you provide a warranty) and that users may redistribute
+    the program under these conditions, and telling the user how to view a copy
+    of this License.  (Exception: if the Program itself is interactive but does
+    not normally print such an announcement, your work based on the Program is
+    not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If identifiable
+sections of that work are not derived from the Program, and can be reasonably
+considered independent and separate works in themselves, then this License, and
+its terms, do not apply to those sections when you distribute them as separate
+works.  But when you distribute the same sections as part of a whole which is a
+work based on the Program, the distribution of the whole must be on the terms
+of this License, whose permissions for other licensees extend to the entire
+whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your
+rights to work written entirely by you; rather, the intent is to exercise the
+right to control the distribution of derivative or collective works based on
+the Program.
+
+In addition, mere aggregation of another work not based on the Program with the
+Program (or with a work based on the Program) on a volume of a storage or
+distribution medium does not bring the other work under the scope of this
+License.
+
+3. You may copy and distribute the Program (or a work based on it, under
+Section 2) in object code or executable form under the terms of Sections 1 and
+2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable source
+    code, which must be distributed under the terms of Sections 1 and 2 above
+    on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three years, to
+    give any third party, for a charge no more than your cost of physically
+    performing source distribution, a complete machine-readable copy of the
+    corresponding source code, to be distributed under the terms of Sections 1
+    and 2 above on a medium customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer to
+    distribute corresponding source code.  (This alternative is allowed only
+    for noncommercial distribution and only if you received the program in
+    object code or executable form with such an offer, in accord with
+    Subsection b above.)
+
+The source code for a work means the preferred form of the work for making
+modifications to it.  For an executable work, complete source code means all
+the source code for all modules it contains, plus any associated interface
+definition files, plus the scripts used to control compilation and installation
+of the executable.  However, as a special exception, the source code
+distributed need not include anything that is normally distributed (in either
+source or binary form) with the major components (compiler, kernel, and so on)
+of the operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the source
+code from the same place counts as distribution of the source code, even though
+third parties are not compelled to copy the source along with the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program except as
+expressly provided under this License.  Any attempt otherwise to copy, modify,
+sublicense or distribute the Program is void, and will automatically terminate
+your rights under this License.  However, parties who have received copies, or
+rights, from you under this License will not have their licenses terminated so
+long as such parties remain in full compliance.
+
+5. You are not required to accept this License, since you have not signed it.
+However, nothing else grants you permission to modify or distribute the Program
+or its derivative works.  These actions are prohibited by law if you do not
+accept this License.  Therefore, by modifying or distributing the Program (or
+any work based on the Program), you indicate your acceptance of this License to
+do so, and all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the Program),
+the recipient automatically receives a license from the original licensor to
+copy, distribute or modify the Program subject to these terms and conditions.
+You may not impose any further restrictions on the recipients' exercise of the
+rights granted herein.  You are not responsible for enforcing compliance by
+third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues), conditions
+are imposed on you (whether by court order, agreement or otherwise) that
+contradict the conditions of this License, they do not excuse you from the
+conditions of this License.  If you cannot distribute so as to satisfy
+simultaneously your obligations under this License and any other pertinent
+obligations, then as a consequence you may not distribute the Program at all.
+For example, if a patent license would not permit royalty-free redistribution
+of the Program by all those who receive copies directly or indirectly through
+you, then the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply and
+the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or
+other property right claims or to contest validity of any such claims; this
+section has the sole purpose of protecting the integrity of the free software
+distribution system, which is implemented by public license practices.  Many
+people have made generous contributions to the wide range of software
+distributed through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing to
+distribute software through any other system and a licensee cannot impose that
+choice.
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in certain
+countries either by patents or by copyrighted interfaces, the original
+copyright holder who places the Program under this License may add an explicit
+geographical distribution limitation excluding those countries, so that
+distribution is permitted only in or among countries not thus excluded.  In
+such case, this License incorporates the limitation as if written in the body
+of this License.
+
+9. The Free Software Foundation may publish revised and/or new versions of the
+General Public License from time to time.  Such new versions will be similar in
+spirit to the present version, but may differ in detail to address new problems
+or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any later
+version", you have the option of following the terms and conditions either of
+that version or of any later version published by the Free Software Foundation.
+If the Program does not specify a version number of this License, you may
+choose any version ever published by the Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free programs
+whose distribution conditions are different, write to the author to ask for
+permission.  For software which is copyrighted by the Free Software Foundation,
+write to the Free Software Foundation; we sometimes make exceptions for this.
+Our decision will be guided by the two goals of preserving the free status of
+all derivatives of our free software and of promoting the sharing and reuse of
+software generally.
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
+THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN OTHERWISE
+STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE
+PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE,
+YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL
+ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE
+PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
+INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
+BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER
+OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible
+use to the public, the best way to achieve this is to make it free software
+which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program.  It is safest to attach
+them to the start of each source file to most effectively convey the exclusion
+of warranty; and each file should have at least the "copyright" line and a
+pointer to where the full notice is found.
+
+    One line to give the program's name and a brief idea of what it does.
+
+    Copyright (C) <year> <name of author>
+
+    This program is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by the Free
+    Software Foundation; either version 2 of the License, or (at your option)
+    any later version.
+
+    This program is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+    more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc., 59
+    Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this when it
+starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author Gnomovision comes
+    with ABSOLUTELY NO WARRANTY; for details type 'show w'.  This is free
+    software, and you are welcome to redistribute it under certain conditions;
+    type 'show c' for details.
+
+The hypothetical commands 'show w' and 'show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may be
+called something other than 'show w' and 'show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.  Here
+is a sample; alter the names:
+
+    Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+    'Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+    signature of Ty Coon, 1 April 1989
+
+    Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General Public
+License instead of this License.
+
+
+"CLASSPATH" EXCEPTION TO THE GPL
+
+Certain source files distributed by Oracle America and/or its affiliates are
+subject to the following clarification and special exception to the GPL, but
+only where Oracle has expressly included in the particular source file's header
+the words "Oracle designates this particular file as subject to the "Classpath"
+exception as provided by Oracle in the LICENSE file that accompanied this code."
+
+    Linking this library statically or dynamically with other modules is making
+    a combined work based on this library.  Thus, the terms and conditions of
+    the GNU General Public License cover the whole combination.
+
+    As a special exception, the copyright holders of this library give you
+    permission to link this library with independent modules to produce an
+    executable, regardless of the license terms of these independent modules,
+    and to copy and distribute the resulting executable under terms of your
+    choice, provided that you also meet, for each linked independent module,
+    the terms and conditions of the license of that module.  An independent
+    module is a module which is not derived from or based on this library.  If
+    you modify this library, you may extend this exception to your version of
+    the library, but you are not obligated to do so.  If you do not wish to do
+    so, delete this exception statement from your version.
+
+===========================================================================
+
+MIT License:
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+===========================================================================
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a2197d7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+Please see the Checker Framework manual
+([HTML](https://checkerframework.org/manual/),
+[PDF](https://checkerframework.org/manual/checker-framework-manual.pdf)).
+
+The history of releases and changes is in file
+[docs/CHANGELOG.md](docs/CHANGELOG.md).
+
+Documentation for Checker Framework developers
+is in directory `docs/developer/`.
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
new file mode 100644
index 0000000..371b4ed
--- /dev/null
+++ b/azure-pipelines.yml
@@ -0,0 +1,228 @@
+# Workaround for https://status.dev.azure.com/_event/179641421
+trigger:
+  branches:
+    include:
+    - '*'
+pr:
+  branches:
+    include:
+    - '*'
+
+
+jobs:
+- job: junit_tests_jdk8
+  dependsOn:
+   - junit_tests_jdk11
+   - nonjunit_tests_jdk11
+   - misc_jdk11
+   - typecheck_jdk11
+  pool:
+    vmImage: 'ubuntu-latest'
+  container: mdernst/cf-ubuntu-jdk8:latest
+  timeoutInMinutes: 70
+  steps:
+  - checkout: self
+    fetchDepth: 25
+  - bash: ./checker/bin-devel/test-cftests-junit.sh
+    displayName: test-cftests-junit.sh
+- job: junit_tests_jdk11
+  pool:
+    vmImage: 'ubuntu-latest'
+  container: mdernst/cf-ubuntu-jdk11:latest
+  steps:
+  - checkout: self
+    fetchDepth: 25
+  - bash: ./checker/bin-devel/test-cftests-junit.sh
+    displayName: test-cftests-junit.sh
+- job: nonjunit_tests_jdk8
+  dependsOn:
+   - junit_tests_jdk11
+   - nonjunit_tests_jdk11
+   - misc_jdk11
+   - typecheck_jdk11
+  pool:
+    vmImage: 'ubuntu-latest'
+  container: mdernst/cf-ubuntu-jdk8:latest
+  steps:
+  - checkout: self
+    fetchDepth: 25
+  - bash: ./checker/bin-devel/test-cftests-nonjunit.sh
+    displayName: test-cftests-nonjunit.sh
+- job: nonjunit_tests_jdk11
+  pool:
+    vmImage: 'ubuntu-latest'
+  container: mdernst/cf-ubuntu-jdk11:latest
+  steps:
+  - checkout: self
+    fetchDepth: 25
+  - bash: ./checker/bin-devel/test-cftests-nonjunit.sh
+    displayName: test-cftests-nonjunit.sh
+- job: inference_tests_jdk8
+  dependsOn:
+   - junit_tests_jdk11
+   - inference_tests_jdk11
+   - misc_jdk11
+   - typecheck_jdk11
+  pool:
+    vmImage: 'ubuntu-latest'
+  container: mdernst/cf-ubuntu-jdk8:latest
+  steps:
+  - checkout: self
+    fetchDepth: 25
+  - bash: ./checker/bin-devel/test-cftests-inference.sh
+    displayName: test-cftests-inference.sh
+- job: inference_tests_jdk11
+  pool:
+    vmImage: 'ubuntu-latest'
+  container: mdernst/cf-ubuntu-jdk11:latest
+  steps:
+  - checkout: self
+    fetchDepth: 25
+  - bash: ./checker/bin-devel/test-cftests-inference.sh
+    displayName: test-cftests-inference.sh
+- job: misc_jdk8
+  ## The dependsOn is commented out because misc_jdk8 sometimes fails when misc_jdk11 does not.
+  # dependsOn:
+  #  - junit_tests_jdk11
+  #  - nonjunit_tests_jdk11
+  #  - misc_jdk11
+  #  - typecheck_jdk11
+  pool:
+    vmImage: 'ubuntu-latest'
+  container: mdernst/cf-ubuntu-jdk8-plus:latest
+  steps:
+  - checkout: self
+    fetchDepth: 1000
+  - bash: ./checker/bin-devel/test-misc.sh
+    displayName: test-misc.sh
+- job: misc_jdk11
+  pool:
+    vmImage: 'ubuntu-latest'
+  container: mdernst/cf-ubuntu-jdk11-plus:latest
+  steps:
+  - checkout: self
+    fetchDepth: 1000
+  - bash: ./checker/bin-devel/test-misc.sh
+    displayName: test-misc.sh
+- job: typecheck_jdk8
+  dependsOn:
+   - junit_tests_jdk11
+   - nonjunit_tests_jdk11
+   - misc_jdk11
+   - typecheck_jdk11
+  pool:
+    vmImage: 'ubuntu-latest'
+  container: mdernst/cf-ubuntu-jdk8-plus:latest
+  steps:
+  - checkout: self
+    fetchDepth: 1000
+  - bash: ./checker/bin-devel/test-typecheck.sh
+    displayName: test-typecheck.sh
+- job: typecheck_jdk11
+  pool:
+    vmImage: 'ubuntu-latest'
+  container: mdernst/cf-ubuntu-jdk11-plus:latest
+  steps:
+  - checkout: self
+    fetchDepth: 1000
+  - bash: ./checker/bin-devel/test-typecheck.sh
+    displayName: test-typecheck.sh
+- job: daikon_jdk8
+  dependsOn:
+   - junit_tests_jdk11
+   - nonjunit_tests_jdk11
+   - misc_jdk11
+   - typecheck_jdk11
+   ## Commented to reduce latency and eliminate the "daikon_jdk11 -> daikon_jdk8" critical path.
+   # - daikon_jdk11
+  pool:
+    vmImage: 'ubuntu-latest'
+  container: mdernst/cf-ubuntu-jdk8:latest
+  timeoutInMinutes: 70
+  steps:
+  - checkout: self
+    fetchDepth: 25
+  - bash: ./checker/bin-devel/test-daikon.sh
+    displayName: test-daikon.sh
+- job: daikon_jdk11
+  pool:
+    vmImage: 'ubuntu-latest'
+  container: mdernst/cf-ubuntu-jdk11:latest
+  timeoutInMinutes: 80
+  steps:
+  - checkout: self
+    fetchDepth: 25
+  - bash: ./checker/bin-devel/test-daikon.sh
+    displayName: test-daikon.sh
+- job: guava_jdk8
+  dependsOn:
+   - junit_tests_jdk11
+   - nonjunit_tests_jdk11
+   - misc_jdk11
+   - typecheck_jdk11
+   - guava_jdk11
+  pool:
+    vmImage: 'ubuntu-latest'
+  container: mdernst/cf-ubuntu-jdk8:latest
+  steps:
+  - checkout: self
+    fetchDepth: 25
+  - bash: ./checker/bin-devel/test-guava.sh
+    displayName: test-guava.sh
+- job: guava_jdk11
+  pool:
+    vmImage: 'ubuntu-latest'
+  container: mdernst/cf-ubuntu-jdk11:latest
+  steps:
+  - checkout: self
+    fetchDepth: 25
+  - bash: ./checker/bin-devel/test-guava.sh
+    displayName: test-guava.sh
+- job: plume_lib_jdk8
+  dependsOn:
+   - junit_tests_jdk11
+   - nonjunit_tests_jdk11
+   - misc_jdk11
+   - typecheck_jdk11
+   - plume_lib_jdk11
+  pool:
+    vmImage: 'ubuntu-latest'
+  container: mdernst/cf-ubuntu-jdk8:latest
+  steps:
+  - checkout: self
+    fetchDepth: 25
+  - bash: ./checker/bin-devel/test-plume-lib.sh
+    displayName: test-plume-lib.sh
+- job: plume_lib_jdk11
+  pool:
+    vmImage: 'ubuntu-latest'
+  container: mdernst/cf-ubuntu-jdk11:latest
+  steps:
+  - checkout: self
+    fetchDepth: 25
+  - bash: ./checker/bin-devel/test-plume-lib.sh
+    displayName: test-plume-lib.sh
+# - job: downstream_jdk8
+#   dependsOn:
+#    - junit_tests_jdk11
+#    - nonjunit_tests_jdk11
+#    - misc_jdk11
+#    - typecheck_jdk11
+#    - downstream_jdk11
+#   pool:
+#     vmImage: 'ubuntu-latest'
+#   container: mdernst/cf-ubuntu-jdk8:latest
+#   steps:
+#   - checkout: self
+#     fetchDepth: 25
+#   - bash: ./checker/bin-devel/test-downstream.sh
+#     displayName: test-downstream.sh
+# - job: downstream_jdk11
+#   pool:
+#     vmImage: 'ubuntu-latest'
+#   container: mdernst/cf-ubuntu-jdk11:latest
+#   steps:
+#   - checkout: self
+#     fetchDepth: 25
+#   - bash: ./checker/bin-devel/test-downstream.sh
+#     displayName: test-downstream.sh
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..844686d
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,1131 @@
+import de.undercouch.gradle.tasks.download.Download
+
+plugins {
+    // https://plugins.gradle.org/plugin/com.github.johnrengelman.shadow (v5 requires Gradle 5)
+    id 'com.github.johnrengelman.shadow' version '6.1.0'
+    // https://plugins.gradle.org/plugin/de.undercouch.download
+    id "de.undercouch.download" version "4.1.1"
+    id 'java'
+    // https://github.com/tbroyer/gradle-errorprone-plugin
+    id "net.ltgt.errorprone" version "2.0.1"
+    // https://plugins.gradle.org/plugin/org.ajoberstar.grgit
+    id 'org.ajoberstar.grgit' version '4.1.0' apply false
+    // https://github.com/n0mer/gradle-git-properties ; target is: generateGitProperties
+    id "com.gorylenko.gradle-git-properties" version "2.3.1"
+}
+apply plugin: "de.undercouch.download"
+
+import org.ajoberstar.grgit.Grgit
+
+repositories {
+    jcenter()
+    mavenCentral()
+}
+
+gitProperties {
+    // logically belongs in framework, but only checker resources are copied to .jar file
+    gitPropertiesResourceDir = file("${project.rootDir}/checker/src/main/resources")
+}
+
+ext {
+    release = false
+
+    // On a Java 8 JVM, use error-prone javac and source/target 8.
+    // On a Java 9+ JVM, use the host javac, default source/target, and required module flags.
+    isJava8 = JavaVersion.current() == JavaVersion.VERSION_1_8
+
+    errorproneJavacVersion = '9+181-r4173-1'
+
+    parentDir = file("${rootDir}/../").absolutePath
+
+    annotationTools = "${parentDir}/annotation-tools"
+    afu = "${annotationTools}/annotation-file-utilities"
+
+    stubparser = "${parentDir}/stubparser"
+    stubparserJar = "${stubparser}/javaparser-core/target/stubparser-3.20.2.1.jar"
+
+    jtregHome = "${parentDir}/jtreg"
+    formatScriptsHome = "${project(':checker').projectDir}/bin-devel/.run-google-java-format"
+    plumeScriptsHome = "${project(':checker').projectDir}/bin-devel/.plume-scripts"
+    htmlToolsHome = "${project(':checker').projectDir}/bin-devel/.html-tools"
+
+    javadocMemberLevel = JavadocMemberLevel.PROTECTED
+
+    // The local git repository, typically in the .git directory, but not for worktrees.
+    // This value is always overwritten, but Gradle needs the variable to be initialized.
+    localRepo = ".git"
+}
+// Keep in sync with check in org.checkerframework.framework.source.SourceChecker.init
+// and with text in #installation
+switch (JavaVersion.current()) {
+    case JavaVersion.VERSION_1_9:
+    case JavaVersion.VERSION_1_10:
+    case JavaVersion.VERSION_12:
+        logger.warn("The Checker Framework has only been tested with JDK 8 and 11." +
+                " Found version " + JavaVersion.current().majorVersion);
+        break;
+    case JavaVersion.VERSION_1_8:
+    case JavaVersion.VERSION_11:
+        break; // Supported versions
+    default:
+        throw new GradleException("Build the Checker Framework with JDK 8 or JDK 11." +
+                " Found version " + JavaVersion.current().majorVersion);
+}
+
+task setLocalRepo(type:Exec) {
+    commandLine 'git', 'worktree', 'list'
+    standardOutput = new ByteArrayOutputStream()
+    doLast {
+       String worktreeList = standardOutput.toString()
+       localRepo = worktreeList.substring(0, worktreeList.indexOf(" ")) + "/.git"
+    }
+}
+
+// No group so it does not show up in the output of `gradlew tasks`
+task installGitHooks(type: Copy, dependsOn: 'setLocalRepo') {
+    description 'Copies git hooks to .git directory'
+    from files("checker/bin-devel/git.post-merge", "checker/bin-devel/git.pre-commit")
+    rename('git\\.(.*)', '$1')
+    into localRepo + "/hooks"
+}
+
+allprojects {
+    apply plugin: 'java'
+    apply plugin: 'com.github.johnrengelman.shadow'
+    apply plugin: "de.undercouch.download"
+    apply plugin: 'net.ltgt.errorprone'
+
+    group 'org.checkerframework'
+    // Increment the minor version (second number) rather than just the patch
+    // level (third number) if:
+    //   * any new checkers have been added, or
+    //   * backward-incompatible changes have been made to APIs or elsewhere.
+    version '3.13.1-SNAPSHOT'
+
+    repositories {
+        mavenCentral()
+    }
+
+    configurations {
+        javacJar
+
+        // Holds the combined classpath of all subprojects including the subprojects themselves.
+        allProjects
+
+        // Exclude checker-qual dependency added by Error Prone to avoid a circular dependency.
+        annotationProcessor.exclude group:'org.checkerframework', module:'checker-qual'
+    }
+
+    configurations {
+        checkerFatJar
+    }
+    dependencies {
+        if (isJava8) {
+            javacJar group: 'com.google.errorprone', name: 'javac', version: "$errorproneJavacVersion"
+        }
+
+        errorproneJavac("com.google.errorprone:javac:$errorproneJavacVersion")
+
+        allProjects subprojects
+        checkerFatJar project(path: ':checker', configuration: 'shadow')
+    }
+
+
+    // After all the tasks have been created, modify some of them.
+    afterEvaluate {
+        // Add the fat checker.jar to the classpath of every Javadoc task. This allows Javadoc in
+        // any module to reference classes in any other module.
+        // Also, build and use ManualTaglet as a taglet.
+        tasks.withType(Javadoc) {
+            def tagletVersion = isJava8 ? 'taglet' : 'tagletJdk11'
+
+            dependsOn(':checker:shadowJar')
+            dependsOn(":framework-test:${tagletVersion}Classes")
+            doFirst {
+                options.encoding = 'UTF-8'
+                if (!name.equals("javadocDoclintAll")) {
+                    options.memberLevel = javadocMemberLevel
+                }
+                classpath += rootProject.configurations.getByName('checkerFatJar').asFileTree
+                if (isJava8) {
+                    classpath += configurations.javacJar
+                }
+                options.taglets 'org.checkerframework.taglet.ManualTaglet'
+                options.tagletPath(project(':framework-test').sourceSets."${tagletVersion}".output.classesDirs.getFiles() as File[])
+
+                // We want to link to Java 9 documentation of the compiler classes since we use Java 9
+                // versions of those classes and Java 8 for everything else.  Because the compiler classes are not
+                // a part of the main documentation of Java 8, javadoc links to the Java 9 versions.
+                // TODO, this creates broken links to the com.sun.tools.javac package.
+                options.links = ['https://docs.oracle.com/javase/8/docs/api/', 'https://docs.oracle.com/javase/9/docs/api/']
+                // This file is looked for by Javadoc.
+                file("${destinationDir}/resources/fonts/").mkdirs()
+                ant.touch(file: "${destinationDir}/resources/fonts/dejavu.css")
+                options.addStringOption('source', '8')
+                // "-Xwerror" requires Javadoc everywhere.  Currently, CI jobs require Javadoc only
+                // on changed lines.  Enable -Xwerror in the future when all Javadoc exists.
+                // options.addBooleanOption('Xwerror', true)
+                options.addStringOption('Xmaxwarns', '99999')
+            }
+        }
+
+        // Add standard javac options
+        tasks.withType(JavaCompile) { compilationTask ->
+            dependsOn(':installGitHooks')
+            // Put source files in deterministic order, for debugging.
+            compilationTask.source = compilationTask.source.sort()
+            sourceCompatibility = 8
+            targetCompatibility = 8
+            // Because the target is 8, all of the public compiler classes are accessible, so
+            // --add-exports are not required, (nor are they allowed with target 8). See
+            // https://openjdk.java.net/jeps/247 for details on compiling for older versions.
+
+            // When sourceCompatibilty is changed to 11, then the following will be required.
+            // options.compilerArgs += [
+            // "--add-exports", "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
+            // "--add-exports", "jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
+            // "--add-exports", "jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED",
+            // "--add-exports", "jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",
+            // "--add-exports", "jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
+            // "--add-exports", "jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED",
+            // "--add-exports", "jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED",
+            // "--add-exports", "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
+            // "--add-exports", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
+            // ]
+            // This is equivalent to writing "exports jdk.compiler/... to ALL-UNNAMED" in the
+            // module-info.java of jdk.compiler, so corresponding --add-opens are only required for
+            // reflective access to private members.
+            //
+            // From https://openjdk.java.net/jeps/261, Section titled: "Breaking encapsulation"
+            // "The effect of each instance [of --add-exports] is to add a qualified export of the
+            // named package from the source module to the target module. This is, essentially, a
+            // command-line form of an exports clause in a module declaration[...].
+            // [...]
+            // The --add-exports option enables access to the public types of a specified package.
+            // It is sometimes necessary to go further and enable access to all non-public elements
+            // via the setAccessible method of the core reflection API. The --add-opens option can
+            // be used, at run time, to do this."
+
+            options.failOnError = true
+            options.deprecation = true
+            options.compilerArgs += [
+                    '-g',
+                    '-Werror',
+                    // -options: To not get a warning about missing bootstrap classpath for Java 8 (once we use Java 9).
+                    // -fallthrough: Don't check fallthroughs.  Instead, use Error Prone.  Its
+                    // warnings are suppressible with a "// fall through" comment.
+                    "-Xlint:-options,-fallthrough",
+                    "-Xlint",
+            ]
+
+            options.encoding = 'UTF-8'
+            options.fork = true
+            if (isJava8) {
+                options.forkOptions.jvmArgs += ["-Xbootclasspath/p:${configurations.javacJar.asPath}".toString()]
+            }
+
+            // Error prone depends on checker-qual.jar, so don't run it on that project to avoid a circular dependency.
+            // TODO: enable Error Prone on test classes.
+            if (compilationTask.name.equals('compileJava') && !project.name.startsWith('checker-qual')) {
+                // Error Prone must be available in the annotation processor path
+                options.annotationProcessorPath = configurations.errorprone
+                // Enable Error Prone
+                options.errorprone.enabled = true
+                options.errorprone.disableWarningsInGeneratedCode = true
+                options.errorprone.errorproneArgs = [
+                        // Many compiler classes are interned.
+                        '-Xep:ReferenceEquality:OFF',
+                        // These might be worth fixing.
+                        '-Xep:DefaultCharset:OFF',
+                        // Not useful to suggest Splitter; maybe clean up.
+                        '-Xep:StringSplitter:OFF',
+                        // Too broad, rejects seemingly-correct code.
+                        '-Xep:EqualsGetClass:OFF',
+                        // Not a real problem
+                        '-Xep:MixedMutabilityReturnType:OFF',
+                        // Don't want to add a dependency to ErrorProne.
+                        '-Xep:AnnotateFormatMethod:OFF',
+                        // Warns for every use of "@checker_framework.manual"
+                        '-Xep:InvalidBlockTag:OFF',
+                        // Recommends writing @InlineMe which is an Error-Prone-specific annotation
+                        '-Xep:InlineMeSuggester:OFF',
+                        // -Werror halts the build if Error Prone issues a warning, which ensures that
+                        // the errors get fixed.  On the downside, Error Prone (or maybe the compiler?)
+                        // stops as soon as it issues one warning, rather than outputting them all.
+                        // https://github.com/google/error-prone/issues/436
+                        '-Werror',
+                ]
+            } else {
+                options.errorprone.enabled = false
+            }
+        }
+    }
+}
+
+task cloneAndBuildDependencies(type: Exec, group: 'Build') {
+    description 'Clones (or updates) and builds all dependencies'
+    executable 'checker/bin-devel/build.sh'
+}
+
+task maybeCloneAndBuildDependencies() {
+    // No group so it does not show up in the output of `gradlew tasks`
+    description 'Clones (or updates) and builds all dependencies if they are not present.'
+    onlyIf {
+        !file(stubparserJar).exists()
+        // The jdk repository is cloned via the copyAndMinimizeAnnotatedJdkFiles task that is run if
+        // the repository does not exist when building checker.jar.
+    }
+
+    doFirst {
+        if (file(stubparser).exists()) {
+            exec {
+                workingDir stubparser
+                executable 'git'
+                args = ['pull', '-q']
+                ignoreExitValue = true
+            }
+            exec {
+                workingDir stubparser
+                executable "${stubparser}/.travis-build-without-test.sh"
+            }
+        } else {
+            executable 'checker/bin-devel/build.sh'
+        }
+    }
+    doLast {
+        if (!file(stubparserJar).exists()) {
+            exec {
+                workingDir ${stubparser}/javaparser-core/target
+                executable 'ls'
+                ignoreExitValue = true
+            }
+            throw new RuntimeException("Can't find stubparser jar: " + stubparserJar)
+        }
+    }
+}
+
+task version(group: 'Documentation') {
+    description 'Print Checker Framework version'
+    doLast {
+        println version
+    }
+}
+
+/**
+ * Creates a task that runs the checker on the main source set of each subproject. The task is named
+ * "check${taskName}", for example "checkPurity" or "checkNullness".
+ *
+ * @param projectName name of the project
+ * @param taskName short name (often the checker name) to use as part of the task name
+ * @param checker fully qualified name of the checker to run
+ * @param args list of arguments to pass to the checker
+ */
+def createCheckTypeTask(projectName, taskName, checker, args = []) {
+    project("${projectName}").tasks.create(name: "check${taskName}", type: JavaCompile, dependsOn: ':checker:shadowJar') {
+        description "Run the ${taskName} Checker on the main sources."
+        group 'Verification'
+        // Always run the task.
+        outputs.upToDateWhen { false }
+        source = project("${projectName}").sourceSets.main.java
+        classpath = files(project("${projectName}").compileJava.classpath,project(':checker-qual').sourceSets.main.output)
+        destinationDir = file("${buildDir}")
+
+        options.annotationProcessorPath = files(project(':checker').tasks.shadowJar.archivePath)
+        options.compilerArgs += [
+                '-processor', "${checker}",
+                '-proc:only',
+                '-Xlint:-processing',
+                '-Xmaxerrs', '10000',
+                '-Xmaxwarns', '10000',
+                '-ArequirePrefixInWarningSuppressions',
+                '-AwarnUnneededSuppressions',
+        ]
+        options.compilerArgs += args
+        options.forkOptions.jvmArgs += ["-Xmx2g"]
+
+        if (isJava8) {
+            options.compilerArgs += [
+                "-source",
+                "8",
+                "-target",
+                "8"
+                ]
+        } else {
+            options.fork = true
+            options.forkOptions.jvmArgs += [
+                "--add-opens", "jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED",
+                ]
+       }
+    }
+}
+
+/**
+ * Returns a list of all the Java files that should be formatted for the given project. These are:
+ *
+ * All java files in the main sourceSet.
+ * All java files in the tests directory that compile.
+ *
+ * @param projectName name of the project to format
+ * @return a list of all Java files that should be formatted for projectName
+ */
+List<String> getJavaFilesToFormat(projectName) {
+    List<File> javaFiles = new ArrayList<>();
+    project(':' + projectName).sourceSets.forEach { set ->
+        javaFiles.addAll(set.java.files)
+    }
+
+    // Collect all java files in tests directory
+    fileTree("${project(projectName).projectDir}/tests").visit { details ->
+        // If you change this, also change checker/bin-devel/git.pre-commit
+        if (!details.path.contains("nullness-javac-errors")
+                && !details.path.contains("returnsreceiverdelomboked")
+                && !details.path.contains("build")
+                && details.name.endsWith('.java')) {
+            javaFiles.add(details.file)
+        }
+    }
+
+    // Collect all java files in jtreg directory
+    fileTree("${project(projectName).projectDir}/jtreg").visit { details ->
+        if (!details.path.contains("nullness-javac-errors") && details.name.endsWith('.java')) {
+            javaFiles.add(details.file)
+        }
+    }
+
+    // Collect all java files in jtregJdk11 directory
+    fileTree("${project(projectName).projectDir}/jtregJdk11").visit { details ->
+        if (!details.path.contains("nullness-javac-errors") && details.name.endsWith('.java')) {
+            javaFiles.add(details.file)
+        }
+    }
+
+    List<String> args = new ArrayList<>(javaFiles.size());
+    for (File f : javaFiles) {
+        args += project(projectName).relativePath(f)
+    }
+    return args
+}
+
+task htmlValidate(type: Exec, group: 'Format') {
+    description 'Validate that HTML files are well-formed'
+    executable 'html5validator'
+    args = [
+            "--ignore",
+            "/api/",
+            "/build/",
+            "/docs/manual/manual.html",
+            "/checker/jdk/nullness/src/java/lang/ref/package.html"
+    ]
+}
+
+
+// `gradle allJavadoc` builds the Javadoc for all modules in `docs/api`.
+//   This is what is published to checkerframework.org.
+// `gradle javadoc` builds the Javadoc for each sub-project in <subproject>/build/docs/javadoc/ .
+//   It's needed to create the Javadoc jars that we release in Maven Central.
+// To make javadoc for only one subproject, run `./gradlew javadoc`
+//   in the subproject or `./gradlew :checker:javadoc` at the top level.
+task allJavadoc(type: Javadoc, group: 'Documentation') {
+    description = 'Generates API documentation that includes all the modules.'
+    dependsOn(':checker:shadowJar', 'getPlumeScripts', 'getHtmlTools')
+    destinationDir = file("${rootDir}/docs/api")
+    source(project(':checker-util').sourceSets.main.allJava, project(':checker-qual').sourceSets.main.allJava, project(':checker').sourceSets.main.allJava, project(':framework').sourceSets.main.allJava,
+            project(':dataflow').sourceSets.main.allJava, project(':javacutil').sourceSets.main.allJava)
+
+    classpath = configurations.allProjects
+    if (isJava8) {
+        classpath += configurations.javacJar
+    }
+    doLast {
+        exec {
+            // Javadoc for to com.sun.tools.java.* is not publicly available, so these links are broken.
+            // This command removes those links.
+            workingDir "${rootDir}/docs/api"
+            executable "${plumeScriptsHome}/preplace"
+            args += ['<a href="https://docs.oracle.com/javase/9/docs/api/com/sun/tools/javac/.*?>(.*?)</a>', '\\1']
+        }
+        copy {
+            from 'docs/logo/Checkmark/CFCheckmark_favicon.png'
+            rename('CFCheckmark_favicon.png', 'favicon-checkerframework.png')
+            into "${rootDir}/docs/api"
+        }
+        exec {
+            workingDir "${rootDir}/docs/api"
+            executable "${htmlToolsHome}/html-add-favicon"
+            args += ['.', 'favicon-checkerframework.png']
+        }
+    }
+}
+
+// See documentation for allJavadoc task.
+javadoc.dependsOn(allJavadoc)
+
+configurations {
+    requireJavadoc
+}
+dependencies {
+    requireJavadoc "org.plumelib:require-javadoc:1.0.2"
+}
+task requireJavadoc(type: JavaExec, group: 'Documentation') {
+    description = 'Ensures that Javadoc documentation exists in source code.'
+    main = "org.plumelib.javadoc.RequireJavadoc"
+    classpath = configurations.requireJavadoc
+    args "checker/src/main/java", "dataflow/src/main/java", "framework-test/src/main/java", "framework/src/main/java", "javacutil/src/main/java"
+}
+
+
+/**
+ * Creates a task named taskName that runs javadoc with the -Xdoclint:all option.
+ *
+ * @param taskName the name of the task to create
+ * @param taskDescription description of the task
+ * @param memberLevel the JavadocMemberLevel to use
+ * @return the new task
+ */
+def createJavadocTask(taskName, taskDescription, memberLevel) {
+    tasks.create(name: taskName, type: Javadoc) {
+        description = taskDescription
+        destinationDir = file("${rootDir}/docs/tmpapi")
+        destinationDir.mkdirs()
+        subprojects.forEach {
+            if (!it.name.startsWith("checker-qual-android")) {
+                source += it.sourceSets.main.allJava
+            }
+        }
+
+        classpath = configurations.allProjects
+
+        destinationDir.deleteDir()
+        options.memberLevel = memberLevel
+        options.addBooleanOption('Xdoclint:all', true)
+        options.addStringOption('Xmaxwarns', '99999')
+
+        // options.addStringOption('skip', 'ClassNotToCheck|OtherClass')
+    }
+}
+
+createJavadocTask('javadocDoclintAll', 'Runs javadoc with -Xdoclint:all option.', JavadocMemberLevel.PRIVATE)
+
+task manual(group: 'Documentation') {
+    description 'Build the manual'
+    doLast {
+        exec {
+            commandLine "make", "-C", "docs/manual", "all"
+        }
+    }
+}
+
+// No group so it does not show up in the output of `gradlew tasks`
+task downloadJtreg(type: Download) {
+    description "Downloads and unpacks jtreg."
+    onlyIf { !(new File("${jtregHome}/lib/jtreg.jar").exists()) }
+    // src 'https://ci.adoptopenjdk.net/view/Dependencies/job/jtreg/lastSuccessfulBuild/artifact/jtreg-4.2.0-tip.tar.gz'
+    // If ci.adoptopenjdk.net is down, use this copy.
+    src 'https://checkerframework.org/jtreg-4.2.0-tip.tar.gz'
+    dest new File(buildDir, 'jtreg-4.2.0-tip.tar.gz')
+    overwrite true
+    retries 3
+    doLast {
+        copy {
+            from tarTree(dest)
+            into "${jtregHome}/.."
+        }
+        exec {
+            commandLine('chmod',  '+x', "${jtregHome}/bin/jtdiff", "${jtregHome}/bin/jtreg")
+        }
+    }
+}
+
+// See alternate implementation getCodeFormatScriptsInGradle below.
+// No group so it does not show up in the output of `gradlew tasks`
+task getCodeFormatScripts() {
+    description 'Obtain or update the run-google-java-format scripts'
+    if (file(formatScriptsHome).exists()) {
+        exec {
+            workingDir formatScriptsHome
+            executable 'git'
+            args = ['pull', '-q']
+            ignoreExitValue = true
+        }
+    } else {
+        exec {
+            workingDir "${formatScriptsHome}/../"
+            executable 'git'
+            args = ['clone', '-q', '--depth', '1', 'https://github.com/plume-lib/run-google-java-format.git', '.run-google-java-format']
+        }
+    }
+}
+
+// This implementation is preferable to the above because it does work in Gradle rather than in bash.
+// However, it fails in the presence of worktrees: https://github.com/ajoberstar/grgit/issues/97 .
+// No group so it does not show up in the output of `gradlew tasks`
+task getCodeFormatScriptsInGradle {
+  description "Obtain the run-google-java-format scripts"
+  doLast {
+    if (! new File(formatScriptsHome).exists()) {
+      // There is no support for the --depth argument:
+      // https://github.com/ajoberstar/grgit/issues/155   https://bugs.eclipse.org/bugs/show_bug.cgi?id=475615
+      def rgjfGit = Grgit.clone(dir: formatScriptsHome, uri: 'https://github.com/plume-lib/run-google-java-format.git')
+    } else {
+      def rgjfGit = Grgit.open(dir: formatScriptsHome)
+      rgjfGit.pull()
+    }
+  }
+}
+
+// No group so it does not show up in the output of `gradlew tasks`
+task getPlumeScripts() {
+    description 'Obtain or update plume-scripts'
+    if (file(plumeScriptsHome).exists()) {
+        exec {
+            workingDir plumeScriptsHome
+            executable 'git'
+            args = ['pull', '-q']
+            ignoreExitValue = true
+        }
+    } else {
+        exec {
+            workingDir "${plumeScriptsHome}/../"
+            executable 'git'
+            args = ['clone', '-q', '--depth', '1', 'https://github.com/plume-lib/plume-scripts.git', '.plume-scripts']
+        }
+    }
+}
+
+// No group so it does not show up in the output of `gradlew tasks`
+task getHtmlTools() {
+    description 'Obtain or update html-tools'
+    if (file(htmlToolsHome).exists()) {
+        exec {
+            workingDir htmlToolsHome
+            executable 'git'
+            args = ['pull', '-q']
+            ignoreExitValue = true
+        }
+    } else {
+        exec {
+            workingDir "${htmlToolsHome}/../"
+            executable 'git'
+            args = ['clone', '-q', '--depth', '1', 'https://github.com/plume-lib/html-tools.git', '.html-tools']
+        }
+    }
+}
+
+// No group so it does not show up in the output of `gradlew tasks`
+task pythonIsInstalled(type: Exec) {
+  description "Check that the python3 executable is installed."
+  executable = "python3"
+  args "--version"
+}
+
+task tags {
+    group 'Emacs'
+    description 'Create Emacs TAGS table'
+    doLast {
+        exec {
+            commandLine "etags", "-i", "checker/TAGS", "-i", "checker-qual/TAGS", "-i", "checker-util/TAGS", "-i", "dataflow/TAGS", "-i", "framework/TAGS", "-i", "framework-test/TAGS", "-i", "javacutil/TAGS", "-i", "docs/manual/TAGS"
+        }
+        exec {
+            commandLine "make", "-C", "docs/manual", "tags"
+        }
+    }
+}
+
+subprojects {
+    configurations {
+        errorprone
+    }
+
+    dependencies {
+        // https://mvnrepository.com/artifact/com.google.errorprone/error_prone_core
+        // If you update this:
+        //  * Temporarily comment out "-Werror" elsewhere in this file
+        //  * Repeatedly run `./gradlew clean compileJava` and fix all errors
+        //  * Uncomment "-Werror"
+        //  * Don't edit framework/build.gradle to use the same version number
+        //    (it is updated when the annotated version of Guava is updated).
+        errorprone group: 'com.google.errorprone', name: 'error_prone_core', version: '2.7.1'
+    }
+
+    task checkFormat(type: Exec, dependsOn: [getCodeFormatScripts, pythonIsInstalled], group: 'Format') {
+        description 'Check whether the source code is properly formatted'
+        // checker-qual-android project has no source, so skip
+        onlyIf {!project.name.startsWith('checker-qual-android') }
+        executable 'python3'
+
+        doFirst {
+            args += "${formatScriptsHome}/check-google-java-format.py"
+            args += getJavaFilesToFormat(project.name)
+        }
+        ignoreExitValue = true
+        doLast {
+            if (execResult.exitValue != 0) {
+                throw new RuntimeException('Found improper formatting, try running:  ./gradlew reformat"')
+            }
+        }
+    }
+
+    task reformat(type: Exec, dependsOn: [getCodeFormatScripts, pythonIsInstalled], group: 'Format') {
+        description 'Format the Java source code'
+        // checker-qual-android project has no source, so skip
+        onlyIf {!project.name.startsWith('checker-qual-android') }
+        executable 'python3'
+        doFirst {
+            args += "${formatScriptsHome}/run-google-java-format.py"
+            args += getJavaFilesToFormat(project.name)
+        }
+    }
+
+    shadowJar {
+        // If you add an external dependency, then do the following:
+        // 1. Before adding the dependency, run ./gradlew copyJarsToDist.
+        // 2. Copy checker/dist/checker.jar elsewhere.
+        // 3. Add the dependency, then run ./gradlew clean copyJarsToDist.
+        // 4. Unzip both jars and compare the contents.
+        // 5. Add relocate lines below for the packages.
+        // 6. Do steps 3-5 until all new classes are in org/checkerframework/.
+
+        // Relocate packages that might conflict with user's classpath.
+        relocate 'org.apache', 'org.checkerframework.org.apache'
+        relocate 'org.relaxng', 'org.checkerframework.org.relaxng'
+        relocate 'org.plumelib', 'org.checkerframework.org.plumelib'
+        relocate 'org.codehaus', 'org.checkerframework.org.codehaus'
+        relocate 'org.objectweb.asm', 'org.checkerframework.org.objectweb.asm'
+        relocate 'io.github.classgraph', 'org.checkerframework.io.github.classgraph'
+        relocate 'nonapi.io.github.classgraph', 'org.checkerframework.nonapi.io.github.classgraph'
+        // relocate 'sun', 'org.checkerframework.sun'
+        relocate 'com.google', 'org.checkerframework.com.google'
+        relocate 'plume', 'org.checkerframework.plume'
+        exclude '**/module-info.class'
+
+        doFirst {
+            if (release) {
+                // Only relocate JavaParser during a release:
+                relocate 'com.github.javaparser', 'org.checkerframework.com.github.javaparser'
+            }
+        }
+    }
+
+    if (!project.name.startsWith('checker-qual-android')) {
+        task tags(type: Exec) {
+            description 'Create Emacs TAGS table'
+            commandLine "bash", "-c", "find . \\( -name build \\) -prune -o -name '*.java' -print | sort-directory-order | xargs ctags -e -f TAGS"
+        }
+    }
+
+    java {
+        withJavadocJar()
+        withSourcesJar()
+    }
+
+    // Things in this block reference definitions in the subproject that do not exist,
+    // until the project is evaluated.
+    afterEvaluate {
+        // Adds manifest to all Jar files
+        tasks.withType(Jar) {
+            includeEmptyDirs = false
+            if (archiveFileName.get().startsWith("checker-qual") || archiveFileName.get().startsWith("checker-util")) {
+                metaInf {
+                    from './LICENSE.txt'
+                }
+            } else {
+                metaInf {
+                    from "${rootDir}/LICENSE.txt"
+                }
+            }
+            manifest {
+                attributes("Implementation-Version": "${project.version}")
+                attributes("Implementation-URL": "https://checkerframework.org")
+                if (! archiveFileName.get().endsWith("source.jar")) {
+                    attributes('Automatic-Module-Name': "org.checkerframework." + project.name.replaceAll('-', '.'))
+                }
+                if (archiveFileName.get().startsWith("checker-qual") || archiveFileName.get().startsWith("checker-util")) {
+                    attributes("Bundle-License": "MIT")
+                } else {
+                    attributes("Bundle-License": "(GPL-2.0-only WITH Classpath-exception-2.0)")
+                }
+            }
+        }
+
+        // Add tasks to run various checkers on all the main source sets.
+        // These pass and are run by typecheckTests.
+        createCheckTypeTask(project.name, 'Formatter',
+            'org.checkerframework.checker.formatter.FormatterChecker')
+        createCheckTypeTask(project.name, 'Interning',
+            'org.checkerframework.checker.interning.InterningChecker',
+            ['-Astubs=javax-lang-model-element-name.astub'])
+        createCheckTypeTask(project.name, 'NullnessOnlyAnnotatedFor',
+            'org.checkerframework.checker.nullness.NullnessChecker',
+            ['-AskipUses=com.sun.*', '-AuseConservativeDefaultsForUncheckedCode=source'])
+        createCheckTypeTask(project.name, 'Purity',
+            'org.checkerframework.framework.util.PurityChecker')
+        createCheckTypeTask(project.name, 'Signature',
+            'org.checkerframework.checker.signature.SignatureChecker')
+        // These pass on some subprojects, which the `typecheck` task runs.
+        // TODO: Incrementally add @AnnotatedFor on more classes.
+        createCheckTypeTask(project.name, 'Nullness',
+            'org.checkerframework.checker.nullness.NullnessChecker',
+            ['-AskipUses=com.sun.*'])
+
+
+        // Add jtregTests to framework and checker modules
+        if (project.name.is('framework') || project.name.is('checker')) {
+            tasks.create(name: 'jtregTests', dependsOn: ':downloadJtreg', group: 'Verification') {
+                description 'Run the jtreg tests.'
+                dependsOn('compileJava')
+                dependsOn('compileTestJava')
+                dependsOn('shadowJar')
+
+                String jtregOutput = "${buildDir}/jtreg"
+                String name = 'all'
+                String tests = '.'
+                doLast {
+                    exec {
+                        executable "${jtregHome}/bin/jtreg"
+                        args = [
+                                "-dir:${projectDir}/jtreg",
+                                "-workDir:${jtregOutput}/${name}/work",
+                                "-reportDir:${jtregOutput}/${name}/report",
+                                "-verbose:error,fail",
+                                // Don't add debugging information
+                                //  "-javacoptions:-g",
+                                "-keywords:!ignore",
+                                "-samevm",
+                                "-javacoptions:-classpath ${tasks.shadowJar.archiveFile.get()}:${sourceSets.test.output.asPath}",
+                                // Required for checker/jtreg/nullness/PersistUtil.java and other tests
+                                "-vmoptions:-classpath ${tasks.shadowJar.archiveFile.get()}:${sourceSets.test.output.asPath}",
+                        ]
+                        if (isJava8) {
+                            // Use Error Prone javac and source/target 8
+                            args += [
+                                "-vmoptions:-Xbootclasspath/p:${configurations.javacJar.asPath}",
+                                "-javacoptions:-Xbootclasspath/p:${configurations.javacJar.asPath}",
+                                "-javacoptions:-source 8",
+                                "-javacoptions:-target 8"
+                                ]
+                        } else {
+                            args += [
+                                    // checker/jtreg/nullness/defaultsPersist/ReferenceInfoUtil.java
+                                    // uses the jdk.jdeps module.
+                                    "-javacoptions:--add-modules jdk.jdeps",
+                                    "-javacoptions:--add-exports=jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED",
+                                    "-vmoptions:--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED",
+                            ]
+                        }
+                        if (project.name.is('framework')) {
+                            // Do not check for the annotated JDK
+                            args += [
+                                    "-javacoptions:-ApermitMissingJdk"
+                            ]
+                        } else if (project.name.is('checker')) {
+                            args += [
+                                    "-javacoptions:-classpath ${sourceSets.testannotations.output.asPath}",
+                            ]
+                        }
+
+                        // Location of jtreg tests
+                        args += "${tests}"
+                    }
+                }
+            }
+        }
+
+        // Create a task for each JUnit test class whose name is the same as the JUnit class name.
+        sourceSets.test.allJava.filter { it.path.contains('test/junit') }.forEach { file ->
+            String junitClassName = file.name.replaceAll(".java", "")
+            tasks.create(name: "${junitClassName}", type: Test) {
+                description "Run ${junitClassName} tests."
+                include "**/${name}.class"
+            }
+        }
+
+        // Configure JUnit tests
+        tasks.withType(Test) {
+            if (isJava8) {
+                jvmArgs "-Xbootclasspath/p:${configurations.javacJar.asPath}".toString()
+            } else {
+                jvmArgs += [
+                        "--illegal-access=warn",
+                        "--add-opens", "jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED",
+                ]
+            }
+
+            maxParallelForks = Integer.MAX_VALUE
+
+            if (project.name.is('checker')) {
+                dependsOn('copyJarsToDist')
+            }
+
+            if (project.hasProperty('emit.test.debug')) {
+                systemProperties += ["emit.test.debug": 'true']
+            }
+
+            testLogging {
+                showStandardStreams = true
+                // Always run the tests
+                outputs.upToDateWhen { false }
+
+                // Show the found unexpected diagnostics and expected diagnostics not found.
+                exceptionFormat "full"
+                events "failed"
+            }
+
+            // After each test, print a summary.
+            afterSuite { desc, result ->
+                if (desc.getClassName() != null) {
+                    long mils = result.getEndTime() - result.getStartTime()
+                    double seconds = mils / 1000.0
+
+                    println "Testsuite: ${desc.getClassName()}\n" +
+                            "Tests run: ${result.testCount}, " +
+                            "Failures: ${result.failedTestCount}, " +
+                            "Skipped: ${result.skippedTestCount}, " +
+                            "Time elapsed: ${seconds} sec\n"
+                }
+
+            }
+        }
+
+        // Create a nonJunitTests task per project
+        tasks.create(name: 'nonJunitTests', group: 'Verification') {
+            description 'Run all Checker Framework tests except for the Junit tests and inference tests.'
+            if (project.name.is('framework') || project.name.is('checker')) {
+                dependsOn('jtregTests')
+            }
+            if (project.name.is('framework')) {
+                dependsOn('loaderTests')
+            }
+
+            if (project.name.is('checker')) {
+                if (!isJava8) {
+                    dependsOn('jtregJdk11Tests')
+                }
+                dependsOn('nullnessExtraTests', 'commandLineTests', 'tutorialTests')
+            }
+
+            if (project.name.is('dataflow')) {
+                dependsOn('liveVariableTest')
+                dependsOn('issue3447Test')
+            }
+        }
+
+        // Create an inferenceTests task per project
+        tasks.create(name: 'inferenceTests', group: 'Verification') {
+            description 'Run inference tests.'
+            if (project.name.is('checker')) {
+                dependsOn('wholeProgramInferenceTests', 'wpiManyTests', 'wpiPlumeLibTests')
+            }
+        }
+
+        // Create a typecheck task per project (dogfooding the Checker Framework on itself).
+        // This isn't a test of the Checker Framework as the test and nonJunitTests tasks are.
+        // Tasks such as 'checkInterning' are constructed by createCheckTypeTask.
+        tasks.create(name: 'typecheck', group: 'Verification') {
+            description 'Run the Checker Framework on itself'
+            dependsOn('checkFormatter', 'checkInterning', 'checkPurity', 'checkSignature')
+            if (project.name.is('framework') || project.name.is('checker')) {
+                dependsOn('checkNullnessOnlyAnnotatedFor', 'checkCompilerMessages')
+            } else {
+                dependsOn('checkNullness')
+            }
+        }
+
+        // Create an allTests task per project.
+        // allTests = test + nonJunitTests + inferenceTests + typecheck
+        tasks.create(name: 'allTests', group: 'Verification') {
+            description 'Run all Checker Framework tests'
+            // The 'test' target is just the JUnit tests.
+            dependsOn('test', 'nonJunitTests', 'inferenceTests', 'typecheck')
+        }
+
+        task javadocPrivate(dependsOn: javadoc) {
+            doFirst {
+                javadocMemberLevel = JavadocMemberLevel.PRIVATE
+            }
+            doLast {
+                javadocMemberLevel = JavadocMemberLevel.PROTECTED
+            }
+        }
+    }
+}
+
+assemble.dependsOn(':checker:copyJarsToDist')
+
+task checkBasicStyle(group: 'Format') {
+    description 'Check basic style guidelines, mostly whitespace.  Not related to Checkstyle tool.'
+    String[] ignoreDirectories = ['.git',
+                                  '.gradle',
+                                  '.html-tools',
+                                  '.idea',
+                                  '.plume-scripts',
+                                  '.run-google-java-format',
+                                  'annotated',
+                                  'api',
+                                  'plume-bib',
+                                  'bootstrap',
+                                  'build',
+                                  'jdk']
+
+    String[] ignoreFilePatterns = [
+            '*.aux',
+            '*.bib',
+            '*.class',
+            '*.dvi',
+            '*.expected',
+            '*.gif',
+            '*.jar',
+            '*.jtr',
+            '*.log',
+            '*.out',
+            '*.patch',
+            '*.pdf',
+            '*.png',
+            '*.sty',
+            '*.toc',
+            '*.xcf',
+            '*~',
+            '#*#',
+            'CFLogo.ai',
+            'logfile.log.rec.index',
+            'manual.html',
+            'manual.html-e',
+            'junit.*.properties',
+            'securerandom.*',
+            'checker/dist/META-INF/maven/org.apache.bcel/bcel/pom.xml',
+            'checker/dist/META-INF/maven/org.apache.commons/commons-text/pom.xml',
+            'framework/src/main/resources/git.properties']
+    doLast {
+        FileTree tree = fileTree(dir: projectDir)
+        for (String dir : ignoreDirectories) {
+            tree.exclude "**/${dir}/**"
+        }
+        for (String file : ignoreFilePatterns) {
+            tree.exclude "**/${file}"
+        }
+        boolean failed = false
+        tree.visit {
+            if (!it.file.isDirectory()) {
+                boolean blankLineAtEnd = false
+                String fileName = it.file.getName()
+                boolean checkTabs = !fileName.equals("Makefile")
+                it.file.eachLine { line ->
+                    if (line.endsWith(' ')) {
+                        println("Trailing whitespace: ${it.file.absolutePath}")
+                        failed = true
+                    }
+                    if (checkTabs && line.contains('\t')) {
+                        println("Contains tab (use spaces): ${it.file.absolutePath}")
+                        failed = true
+                        checkTabs = false
+                    }
+                    if (!line.startsWith('\\') &&
+                            (line.matches('^.* (else|finally|try)\\{}.*$')
+                                    || line.matches('^.*}(catch|else|finally) .*$')
+                                    || line.matches('^.* (catch|for|if|while)\\('))) {
+                        // This runs on non-java files, too.
+                        println("Missing space: ${it.file.absolutePath}")
+                        failed = true
+                    }
+                    if (line.isEmpty()) {
+                        blankLineAtEnd = true;
+                    } else {
+                        blankLineAtEnd = false;
+                    }
+                }
+
+                if (blankLineAtEnd) {
+                    println("Blank line at end of file: ${it.file.absolutePath}")
+                    failed = true
+                }
+
+                RandomAccessFile file
+                try {
+                    file = new RandomAccessFile(it.file, 'r')
+                    int end = file.length() - 1;
+                    if (end > 0) {
+                        file.seek(end)
+                        byte last = file.readByte()
+                        if (last != '\n') {
+                            println("Missing newline at end of file: ${it.file.absolutePath}")
+                            failed = true
+                        }
+                    }
+                } finally {
+                    if (file != null) {
+                        file.close()
+                    }
+                }
+            }
+        }
+        if (failed) {
+            throw new GradleException("Files do not meet basic style guidelines.")
+        }
+    }
+}
+assemble.mustRunAfter(clean)
+task buildAll(group: 'Build') {
+    description 'Build all jar files, including source and javadoc jars'
+    dependsOn(allJavadoc)
+    subprojects { Project subproject ->
+        dependsOn("${subproject.name}:assemble")
+        dependsOn("${subproject.name}:javadocJar")
+        dependsOn("${subproject.name}:sourcesJar")
+    }
+    dependsOn('framework:allJavadocJar', 'framework:allSourcesJar', 'checker:allJavadocJar', 'checker:allSourcesJar')
+}
+
+task releaseBuild(group: 'Build') {
+    description 'Build everything required for a release'
+    dependsOn(clean)
+    doFirst {
+        release = true
+    }
+    // Use finalizedBy rather than dependsOn so that release is set to true before any of the tasks are run.
+    finalizedBy(buildAll)
+}
+
+// No group so it does not show up in the output of `gradlew tasks`
+task releaseAndTest {
+    description 'Build everything required for a release and run allTests'
+    dependsOn(releaseBuild)
+    subprojects { Project subproject ->
+        dependsOn("${subproject.name}:allTests")
+    }
+}
+
+// Don't create an empty checker-framework-VERSION.jar
+jar.onlyIf {false}
+
+/**
+ * Adds the shared pom information to the given publication.
+ * @param publication MavenPublication
+ */
+final sharedPublicationConfiguration(publication) {
+    publication.pom {
+        url = 'https://checkerframework.org'
+        developers {
+            // These are the lead developers/maintainers, not all the developers or contributors.
+            developer {
+                id = 'mernst'
+                name = 'Michael Ernst'
+                email = 'mernst@cs.washington.edu'
+                url = 'https://homes.cs.washington.edu/~mernst/'
+                organization = 'University of Washington'
+                organizationUrl = 'https://www.cs.washington.edu/'
+            }
+            developer {
+                id = 'smillst'
+                name = 'Suzanne Millstein'
+                email = 'smillst@cs.washington.edu'
+                organization = 'University of Washington'
+                organizationUrl = 'https://www.cs.washington.edu/'
+            }
+        }
+
+        scm {
+            url = 'https://github.com/typetools/checker-framework.git'
+            connection = 'scm:git:git://github.com/typetools/checker-framework.git'
+            developerConnection = 'scm:git:ssh://git@github.com/typetools/checker-framework.git'
+        }
+    }
+}
diff --git a/checker-qual-android/build.gradle b/checker-qual-android/build.gradle
new file mode 100644
index 0000000..9ce17da
--- /dev/null
+++ b/checker-qual-android/build.gradle
@@ -0,0 +1,76 @@
+evaluationDependsOn(":checker-qual")
+
+task copySources(type: Copy) {
+    description 'Copy checker-qual source to checker-qual-android'
+
+    includeEmptyDirs = false
+    doFirst {
+        // Delete the directory in case a previously copied file should no longer be in checker-qual
+        delete file('src')
+    }
+    from files('../checker-qual/src/main')
+    include "**/*.java"
+    exclude "**/SignednessUtilExtra.java"
+    into file('src/main')
+
+    // Not read only because "replaceAnnotations" tasks writes to the files.
+    fileMode(0666)
+    dirMode(0777)
+}
+
+/**
+* Types annotated with runtime annotations are always kept in the main dex by the default Android Gradle plugin.
+* Using the standard Checker Framework annotations can lead to main dex overflows;
+* users of the Checker framework may find themselves unable to build their Android apps.
+* By contrast, class-retention annotations are stripped out before packaging by all build systems as a convention.
+*/
+task replaceAnnotations {
+    doLast {
+        fileTree(dir: 'src', include: "**/*.java").each {
+            it.text = it.text.replaceAll("RetentionPolicy.RUNTIME", "RetentionPolicy.CLASS")
+        }
+    }
+}
+replaceAnnotations.dependsOn copySources
+
+compileJava.dependsOn replaceAnnotations
+
+clean {
+    delete file('src')
+}
+
+apply from: rootProject.file("gradle-mvn-push.gradle")
+
+/** Adds information to the publication for uploading to Maven repositories. */
+final checkerQualAndroidPom(publication) {
+    sharedPublicationConfiguration(publication)
+    publication.from components.java
+    publication.pom {
+        name = 'Checker Qual Android'
+        description = 'checker-qual-android contains annotations (type qualifiers) that a programmer\n' +
+                        'writes to specify Java code for type-checking by the Checker Framework.\n' +
+                        '\n' +
+                        'The checker-qual-android artifact is identical to the checker-qual\n' +
+                        'artifact, except that in checker-qual-android annotations have classfile\n' +
+                        'retention.  The default Android Gradle plugin retains types annotated with\n' +
+                        'runtime annotations in the main dex, but strips out class-retention\n' +
+                        'annotations.\n'
+        licenses {
+            license {
+                name = 'The MIT License'
+                url = 'http://opensource.org/licenses/MIT'
+                distribution = 'repo'
+            }
+        }
+    }
+}
+publishing {
+    publications {
+        checkerQualAndroid(MavenPublication) {
+            checkerQualAndroidPom it
+        }
+    }
+}
+signing {
+    sign publishing.publications.checkerQualAndroid
+}
diff --git a/checker-qual/LICENSE.txt b/checker-qual/LICENSE.txt
new file mode 100644
index 0000000..9837c6b
--- /dev/null
+++ b/checker-qual/LICENSE.txt
@@ -0,0 +1,22 @@
+Checker Framework qualifiers
+Copyright 2004-present by the Checker Framework developers
+
+MIT License:
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/checker-qual/build.gradle b/checker-qual/build.gradle
new file mode 100644
index 0000000..f5cd3e3
--- /dev/null
+++ b/checker-qual/build.gradle
@@ -0,0 +1,51 @@
+buildscript {
+    repositories {
+        mavenCentral()
+    }
+    dependencies {
+        // Create OSGI bundles
+        classpath "biz.aQute.bnd:biz.aQute.bnd.gradle:5.3.0"
+        // Don't add implementation dependencies; checker-qual.jar should have no dependencies.
+    }
+}
+plugins {
+    id 'java-library'
+}
+
+apply plugin: 'biz.aQute.bnd.builder'
+
+jar {
+    manifest {
+        attributes('Export-Package': '*')
+    }
+}
+
+apply from: rootProject.file("gradle-mvn-push.gradle")
+
+/** Adds information to the publication for uploading to Maven repositories. */
+final checkerQualPom(publication) {
+    sharedPublicationConfiguration(publication)
+    publication.from components.java
+    publication.pom {
+        name = 'Checker Qual'
+        description = 'checker-qual contains annotations (type qualifiers) that a programmer\n' +
+                        'writes to specify Java code for type-checking by the Checker Framework.\n'
+        licenses {
+            license {
+                name = 'The MIT License'
+                url = 'http://opensource.org/licenses/MIT'
+                distribution = 'repo'
+            }
+        }
+    }
+}
+publishing {
+    publications {
+        checkerQual(MavenPublication) {
+            checkerQualPom it
+        }
+    }
+}
+signing {
+    sign publishing.publications.checkerQual
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/builder/qual/CalledMethods.java b/checker-qual/src/main/java/org/checkerframework/checker/builder/qual/CalledMethods.java
new file mode 100644
index 0000000..a6083b5
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/builder/qual/CalledMethods.java
@@ -0,0 +1,27 @@
+package org.checkerframework.checker.builder.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A deprecated variant of {@link org.checkerframework.checker.calledmethods.qual.CalledMethods}.
+ *
+ * <p>Lombok outputs this annotation. This annotation could be marked as deprecated, but that causes
+ * extra warnings when processing delombok'd code.
+ *
+ * @checker_framework.manual #called-methods-checker Called Methods Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+public @interface CalledMethods {
+  /**
+   * The names of methods that have definetely been called.
+   *
+   * @return the names of methods that have definetely been called
+   */
+  String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/builder/qual/NotCalledMethods.java b/checker-qual/src/main/java/org/checkerframework/checker/builder/qual/NotCalledMethods.java
new file mode 100644
index 0000000..8d831ce
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/builder/qual/NotCalledMethods.java
@@ -0,0 +1,31 @@
+package org.checkerframework.checker.builder.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An annotation speculatively used by Lombok's lombok.config checkerframework = true option. It has
+ * no meaning to the Called Methods Checker, which treats it as {@code @}{@link
+ * org.checkerframework.checker.calledmethods.qual.CalledMethods}{@code ()}.
+ *
+ * <p>A similar annotation might be supported in the future.
+ *
+ * <p>This annotation could be marked as deprecated, but that causes extra warnings when processing
+ * delombok'd code.
+ *
+ * @checker_framework.manual #called-methods-checker Called Methods Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+public @interface NotCalledMethods {
+  /**
+   * The names of the methods that have NOT been called.
+   *
+   * @return the names of the methods that have NOT been called
+   */
+  String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/builder/qual/ReturnsReceiver.java b/checker-qual/src/main/java/org/checkerframework/checker/builder/qual/ReturnsReceiver.java
new file mode 100644
index 0000000..05eb7c2
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/builder/qual/ReturnsReceiver.java
@@ -0,0 +1,24 @@
+package org.checkerframework.checker.builder.qual;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A deprecated variant of {@code org.checkerframework.common.returnsreceiver.qual.This}.
+ *
+ * <p>Lombok outputs this annotation. It is retained only for backwards-compatibility with Lombok's
+ * {@code checkerframework = true} lombok.config flag. It should not be used in new code, because it
+ * is TRUSTED, NOT CHECKED.
+ *
+ * <p>This annotation could be marked as deprecated, but that causes extra warnings when processing
+ * delombok'd code.
+ *
+ * @checker_framework.manual #called-methods-checker Called Methods Checker
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@Inherited
+public @interface ReturnsReceiver {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/calledmethods/qual/CalledMethods.java b/checker-qual/src/main/java/org/checkerframework/checker/calledmethods/qual/CalledMethods.java
new file mode 100644
index 0000000..1a861ec
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/calledmethods/qual/CalledMethods.java
@@ -0,0 +1,32 @@
+package org.checkerframework.checker.calledmethods.qual;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * If an expression has type {@code @CalledMethods({"m1", "m2"})}, then methods {@code m1} and
+ * {@code m2} have definitely been called on its value. Other methods might or might not have been
+ * called.
+ *
+ * <p>The subtyping relationship is:
+ *
+ * <pre>{@code @CalledMethods({"m1", "m2", "m3"}) <: @CalledMethods({"m1", "m2"})}</pre>
+ *
+ * @checker_framework.manual #called-methods-checker Called Methods Checker
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface CalledMethods {
+  /**
+   * Methods that have definitely been called on the expression whose type is annotated.
+   *
+   * @return methods that have definitely been called
+   */
+  public String[] value() default {};
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/calledmethods/qual/CalledMethodsBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/calledmethods/qual/CalledMethodsBottom.java
new file mode 100644
index 0000000..eb0b8a2
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/calledmethods/qual/CalledMethodsBottom.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.calledmethods.qual;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type for the Called Methods type system.
+ *
+ * <p>It should rarely be written by a programmer.
+ *
+ * @checker_framework.manual #called-methods-checker Called Methods Checker
+ */
+@SubtypeOf({CalledMethods.class, CalledMethodsPredicate.class})
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+public @interface CalledMethodsBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/calledmethods/qual/CalledMethodsPredicate.java b/checker-qual/src/main/java/org/checkerframework/checker/calledmethods/qual/CalledMethodsPredicate.java
new file mode 100644
index 0000000..38aebe0
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/calledmethods/qual/CalledMethodsPredicate.java
@@ -0,0 +1,31 @@
+package org.checkerframework.checker.calledmethods.qual;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * This annotation represents a predicate on {@code @}{@link CalledMethods} annotations. If method
+ * {@code c()}'s receiver type is annotated with {@code @CalledMethodsPredicate("a || b")}, then it
+ * is acceptable to call either method {@code a()} or method {@code b()} before calling method
+ * {@code c()}.
+ *
+ * @checker_framework.manual #called-methods-checker Called Methods Checker
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({CalledMethods.class})
+public @interface CalledMethodsPredicate {
+  /**
+   * A boolean expression constructed from the following grammar:
+   *
+   * <p>S &rarr; method name | S &amp;&amp; S | S || S | !S | (S)
+   *
+   * <p>The expression uses standard Java operator precedence: "!" then "&amp;&amp;" then "||".
+   *
+   * @return the boolean expression
+   */
+  String value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethods.java b/checker-qual/src/main/java/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethods.java
new file mode 100644
index 0000000..2b89814
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethods.java
@@ -0,0 +1,42 @@
+package org.checkerframework.checker.calledmethods.qual;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PostconditionAnnotation;
+import org.checkerframework.framework.qual.QualifierArgument;
+
+/**
+ * Indicates that the method, if it terminates successfully, always invokes the given methods on the
+ * given expressions.
+ *
+ * <p>Consider the following method:
+ *
+ * <pre>
+ * &#64;EnsuresCalledMethods(value = "#1", methods = "m")
+ * public void callM(T t) { ... }
+ * </pre>
+ *
+ * <p>This method guarantees that {@code t.m()} is always called before the method returns.
+ *
+ * @checker_framework.manual #called-methods-checker Called Methods Checker
+ */
+@PostconditionAnnotation(qualifier = CalledMethods.class)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface EnsuresCalledMethods {
+  /**
+   * The Java expressions to which the qualifier applies.
+   *
+   * @return the Java expressions to which the qualifier applies
+   * @see org.checkerframework.framework.qual.EnsuresQualifier
+   */
+  // Postconditions must use "value" as the name (conditional postconditions use "expression").
+  String[] value();
+
+  /**
+   * The methods guaranteed to be invoked on the expressions.
+   *
+   * @return the methods guaranteed to be invoked on the expressions
+   */
+  @QualifierArgument("value")
+  String[] methods();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethodsIf.java b/checker-qual/src/main/java/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethodsIf.java
new file mode 100644
index 0000000..edf5df0
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethodsIf.java
@@ -0,0 +1,73 @@
+package org.checkerframework.checker.calledmethods.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.ConditionalPostconditionAnnotation;
+import org.checkerframework.framework.qual.InheritedAnnotation;
+import org.checkerframework.framework.qual.QualifierArgument;
+
+/**
+ * Indicates that the method, if it terminates with the given result, invokes the given methods on
+ * the given expressions.
+ *
+ * @see EnsuresCalledMethods
+ * @see CalledMethods
+ * @checker_framework.manual #called-methods-checker Called Methods Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+@ConditionalPostconditionAnnotation(qualifier = CalledMethods.class)
+@InheritedAnnotation
+@Repeatable(EnsuresCalledMethodsIf.List.class)
+public @interface EnsuresCalledMethodsIf {
+  /**
+   * Returns Java expressions that have had the given methods called on them after the method
+   * returns {@link #result}.
+   *
+   * @return an array of Java expressions
+   * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions
+   */
+  String[] expression();
+
+  /**
+   * Returns the return value of the method under which the postcondition holds.
+   *
+   * @return the return value of the method under which the postcondition holds
+   */
+  boolean result();
+
+  /**
+   * The methods guaranteed to be invoked on the expressions if the result of the method is {@link
+   * #result}.
+   *
+   * @return the methods guaranteed to be invoked on the expressions if the result of the method is
+   *     {@link #result}
+   */
+  @QualifierArgument("value")
+  String[] methods();
+
+  /**
+   * A wrapper annotation that makes the {@link EnsuresCalledMethodsIf} annotation repeatable.
+   *
+   * <p>Programmers generally do not need to write this. It is created by Java when a programmer
+   * writes more than one {@link EnsuresCalledMethodsIf} annotation at the same location.
+   */
+  @Documented
+  @Retention(RetentionPolicy.RUNTIME)
+  @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+  @ConditionalPostconditionAnnotation(qualifier = CalledMethods.class)
+  @InheritedAnnotation
+  @interface List {
+    /**
+     * Return the repeatable annotations.
+     *
+     * @return the repeatable annotations
+     */
+    EnsuresCalledMethodsIf[] value();
+  }
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/compilermsgs/qual/CompilerMessageKey.java b/checker-qual/src/main/java/org/checkerframework/checker/compilermsgs/qual/CompilerMessageKey.java
new file mode 100644
index 0000000..cd9f177
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/compilermsgs/qual/CompilerMessageKey.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.compilermsgs.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * A string that is definitely a compiler message key.
+ *
+ * @checker_framework.manual #compilermsgs-checker Compiler Message Key Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownCompilerMessageKey.class)
+public @interface CompilerMessageKey {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/compilermsgs/qual/CompilerMessageKeyBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/compilermsgs/qual/CompilerMessageKeyBottom.java
new file mode 100644
index 0000000..911db2c
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/compilermsgs/qual/CompilerMessageKeyBottom.java
@@ -0,0 +1,26 @@
+package org.checkerframework.checker.compilermsgs.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the Compiler Message Key type system. Programmers should rarely write this
+ * type.
+ *
+ * @checker_framework.manual #compilermsgs-checker Compiler Message Key Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(CompilerMessageKey.class)
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@DefaultFor(TypeUseLocation.LOWER_BOUND)
+public @interface CompilerMessageKeyBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/compilermsgs/qual/UnknownCompilerMessageKey.java b/checker-qual/src/main/java/org/checkerframework/checker/compilermsgs/qual/UnknownCompilerMessageKey.java
new file mode 100644
index 0000000..1e8916e
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/compilermsgs/qual/UnknownCompilerMessageKey.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.compilermsgs.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * A {@code String} that might or might not be a compiler message key.
+ *
+ * @checker_framework.manual #compilermsgs-checker Compiler Message Key Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@InvisibleQualifier
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface UnknownCompilerMessageKey {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/compilermsgs/qual/package-info.java b/checker-qual/src/main/java/org/checkerframework/checker/compilermsgs/qual/package-info.java
new file mode 100644
index 0000000..f3c3136
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/compilermsgs/qual/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Qualifiers for the Compiler Message Key Checker.
+ *
+ * @checker_framework.manual #compilermsgs-checker Compiler Message Key Checker
+ */
+package org.checkerframework.checker.compilermsgs.qual;
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/AwtAlphaCompositingRule.java b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/AwtAlphaCompositingRule.java
new file mode 100644
index 0000000..c6f2849
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/AwtAlphaCompositingRule.java
@@ -0,0 +1,33 @@
+package org.checkerframework.checker.fenum.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Basic alpha compositing rules for combining source and destination colors to achieve blending and
+ * transparency effects with graphics and images (see {@link java.awt.AlphaComposite} for more
+ * details).
+ *
+ * @see java.awt.AlphaComposite#CLEAR
+ * @see java.awt.AlphaComposite#SRC
+ * @see java.awt.AlphaComposite#DST
+ * @see java.awt.AlphaComposite#SRC_OVER
+ * @see java.awt.AlphaComposite#DST_OVER
+ * @see java.awt.AlphaComposite#SRC_IN
+ * @see java.awt.AlphaComposite#DST_IN
+ * @see java.awt.AlphaComposite#SRC_OUT
+ * @see java.awt.AlphaComposite#DST_OUT
+ * @see java.awt.AlphaComposite#SRC_ATOP
+ * @see java.awt.AlphaComposite#DST_ATOP
+ * @see java.awt.AlphaComposite#XOR
+ * @checker_framework.manual #fenum-checker Fake Enum Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(FenumTop.class)
+public @interface AwtAlphaCompositingRule {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/AwtColorSpace.java b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/AwtColorSpace.java
new file mode 100644
index 0000000..0dbe271
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/AwtColorSpace.java
@@ -0,0 +1,51 @@
+package org.checkerframework.checker.fenum.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Color space tags to identify the specific color space of a Color object or, via a ColorModel
+ * object, of an Image, a BufferedImage, or a GraphicsDevice (see {@link java.awt.color.ColorSpace}
+ * for more details).
+ *
+ * @see java.awt.color.ColorSpace#TYPE_XYZ
+ * @see java.awt.color.ColorSpace#TYPE_Lab
+ * @see java.awt.color.ColorSpace#TYPE_Luv
+ * @see java.awt.color.ColorSpace#TYPE_YCbCr
+ * @see java.awt.color.ColorSpace#TYPE_Yxy
+ * @see java.awt.color.ColorSpace#TYPE_RGB
+ * @see java.awt.color.ColorSpace#TYPE_GRAY
+ * @see java.awt.color.ColorSpace#TYPE_HSV
+ * @see java.awt.color.ColorSpace#TYPE_HLS
+ * @see java.awt.color.ColorSpace#TYPE_CMYK
+ * @see java.awt.color.ColorSpace#TYPE_CMY
+ * @see java.awt.color.ColorSpace#TYPE_2CLR
+ * @see java.awt.color.ColorSpace#TYPE_3CLR
+ * @see java.awt.color.ColorSpace#TYPE_4CLR
+ * @see java.awt.color.ColorSpace#TYPE_5CLR
+ * @see java.awt.color.ColorSpace#TYPE_6CLR
+ * @see java.awt.color.ColorSpace#TYPE_7CLR
+ * @see java.awt.color.ColorSpace#TYPE_8CLR
+ * @see java.awt.color.ColorSpace#TYPE_9CLR
+ * @see java.awt.color.ColorSpace#TYPE_ACLR
+ * @see java.awt.color.ColorSpace#TYPE_BCLR
+ * @see java.awt.color.ColorSpace#TYPE_CCLR
+ * @see java.awt.color.ColorSpace#TYPE_DCLR
+ * @see java.awt.color.ColorSpace#TYPE_ECLR
+ * @see java.awt.color.ColorSpace#TYPE_FCLR
+ * @see java.awt.color.ColorSpace#CS_sRGB
+ * @see java.awt.color.ColorSpace#CS_LINEAR_RGB
+ * @see java.awt.color.ColorSpace#CS_CIEXYZ
+ * @see java.awt.color.ColorSpace#CS_PYCC
+ * @see java.awt.color.ColorSpace#CS_GRAY
+ * @checker_framework.manual #fenum-checker Fake Enum Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(FenumTop.class)
+public @interface AwtColorSpace {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/AwtCursorType.java b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/AwtCursorType.java
new file mode 100644
index 0000000..7e78009
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/AwtCursorType.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.fenum.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * AwtCursorType.
+ *
+ * @checker_framework.manual #fenum-checker Fake Enum Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(FenumTop.class)
+public @interface AwtCursorType {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/AwtFlowLayout.java b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/AwtFlowLayout.java
new file mode 100644
index 0000000..a5bc81f
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/AwtFlowLayout.java
@@ -0,0 +1,24 @@
+package org.checkerframework.checker.fenum.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Line alignments in a flow layout (see {@link java.awt.FlowLayout} for more details).
+ *
+ * @see java.awt.FlowLayout#LEFT
+ * @see java.awt.FlowLayout#CENTER
+ * @see java.awt.FlowLayout#RIGHT
+ * @see java.awt.FlowLayout#LEADING
+ * @see java.awt.FlowLayout#TRAILING
+ * @checker_framework.manual #fenum-checker Fake Enum Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(FenumTop.class)
+public @interface AwtFlowLayout {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/Fenum.java b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/Fenum.java
new file mode 100644
index 0000000..f17e9d4
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/Fenum.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.fenum.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * A generic fake enumeration qualifier that is parameterized by a name. It is written in source
+ * code as, for example, {@code @Fenum("cardSuit")} and {@code @Fenum("faceValue")}, which would be
+ * distinct fake enumerations.
+ *
+ * @checker_framework.manual #fenum-checker Fake Enum Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(FenumTop.class)
+public @interface Fenum {
+  String value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/FenumBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/FenumBottom.java
new file mode 100644
index 0000000..5607bd0
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/FenumBottom.java
@@ -0,0 +1,29 @@
+package org.checkerframework.checker.fenum.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the Fenum type system. Programmers should rarely write this type.
+ *
+ * <p>Its relationships are set up via the FenumAnnotatedTypeFactory.
+ *
+ * @checker_framework.manual #propkey-checker Property File Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+// Subtype relationships are set up by passing this class as a bottom
+// to the multigraph hierarchy constructor.
+@SubtypeOf({})
+@DefaultFor(TypeUseLocation.LOWER_BOUND)
+public @interface FenumBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/FenumTop.java b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/FenumTop.java
new file mode 100644
index 0000000..764b7f3
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/FenumTop.java
@@ -0,0 +1,24 @@
+package org.checkerframework.checker.fenum.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The top of the fake enumeration type hierarchy.
+ *
+ * @checker_framework.manual #fenum-checker Fake Enum Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@SubtypeOf({})
+@DefaultFor({TypeUseLocation.LOCAL_VARIABLE, TypeUseLocation.RESOURCE_VARIABLE})
+public @interface FenumTop {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/FenumUnqualified.java b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/FenumUnqualified.java
new file mode 100644
index 0000000..4eeaf96
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/FenumUnqualified.java
@@ -0,0 +1,27 @@
+package org.checkerframework.checker.fenum.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * An unqualified type. Such a type is incomparable to (that is, neither a subtype nor a supertype
+ * of) any fake enum type.
+ *
+ * <p>This annotation may not be written in source code; it is an implementation detail of the
+ * checker.
+ *
+ * @checker_framework.manual #fenum-checker Fake Enum Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({}) // empty target prevents programmers from writing this in a program
+@SubtypeOf({FenumTop.class})
+@DefaultQualifierInHierarchy
+@DefaultFor(TypeUseLocation.EXCEPTION_PARAMETER)
+public @interface FenumUnqualified {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/PolyFenum.java b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/PolyFenum.java
new file mode 100644
index 0000000..d203d9a
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/PolyFenum.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.fenum.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * A polymorphic qualifier for the fake enum type system.
+ *
+ * @checker_framework.manual #fenum-checker Fake Enum Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier(FenumTop.class)
+public @interface PolyFenum {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingBoxOrientation.java b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingBoxOrientation.java
new file mode 100644
index 0000000..1c079d5
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingBoxOrientation.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.fenum.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * SwingBoxOrientation.
+ *
+ * @checker_framework.manual #fenum-checker Fake Enum Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(FenumTop.class)
+public @interface SwingBoxOrientation {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingCompassDirection.java b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingCompassDirection.java
new file mode 100644
index 0000000..f89cd2d
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingCompassDirection.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.fenum.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * SwingCompassDirection.
+ *
+ * @checker_framework.manual #fenum-checker Fake Enum Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(FenumTop.class)
+public @interface SwingCompassDirection {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingElementOrientation.java b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingElementOrientation.java
new file mode 100644
index 0000000..8935db1
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingElementOrientation.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.fenum.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * SwingElementOrientation.
+ *
+ * @checker_framework.manual #fenum-checker Fake Enum Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(FenumTop.class)
+public @interface SwingElementOrientation {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingHorizontalOrientation.java b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingHorizontalOrientation.java
new file mode 100644
index 0000000..569f860
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingHorizontalOrientation.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.fenum.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * SwingHorizontalOrientation.
+ *
+ * @checker_framework.manual #fenum-checker Fake Enum Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(SwingBoxOrientation.class)
+public @interface SwingHorizontalOrientation {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingSplitPaneOrientation.java b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingSplitPaneOrientation.java
new file mode 100644
index 0000000..d555bf1
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingSplitPaneOrientation.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.fenum.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * SwingSplitPaneOrientation.
+ *
+ * @checker_framework.manual #fenum-checker Fake Enum Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(FenumTop.class)
+public @interface SwingSplitPaneOrientation {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingTextOrientation.java b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingTextOrientation.java
new file mode 100644
index 0000000..84833e6
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingTextOrientation.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.fenum.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * SwingTextOrientation.
+ *
+ * @checker_framework.manual #fenum-checker Fake Enum Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(FenumTop.class)
+public @interface SwingTextOrientation {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingTitleJustification.java b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingTitleJustification.java
new file mode 100644
index 0000000..ac51e16
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingTitleJustification.java
@@ -0,0 +1,25 @@
+package org.checkerframework.checker.fenum.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Vertical orientations for the title text of a {@link javax.swing.border.TitledBorder}.
+ *
+ * @see javax.swing.border.TitledBorder#DEFAULT_JUSTIFICATION
+ * @see javax.swing.border.TitledBorder#LEFT
+ * @see javax.swing.border.TitledBorder#CENTER
+ * @see javax.swing.border.TitledBorder#RIGHT
+ * @see javax.swing.border.TitledBorder#LEADING
+ * @see javax.swing.border.TitledBorder#TRAILING
+ * @checker_framework.manual #fenum-checker Fake Enum Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(FenumTop.class)
+public @interface SwingTitleJustification {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingTitlePosition.java b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingTitlePosition.java
new file mode 100644
index 0000000..e3ca36f
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingTitlePosition.java
@@ -0,0 +1,26 @@
+package org.checkerframework.checker.fenum.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Justifications for the title text of a {@link javax.swing.border.TitledBorder}.
+ *
+ * @see javax.swing.border.TitledBorder#DEFAULT_POSITION
+ * @see javax.swing.border.TitledBorder#ABOVE_TOP
+ * @see javax.swing.border.TitledBorder#TOP
+ * @see javax.swing.border.TitledBorder#BELOW_TOP
+ * @see javax.swing.border.TitledBorder#ABOVE_BOTTOM
+ * @see javax.swing.border.TitledBorder#BOTTOM
+ * @see javax.swing.border.TitledBorder#BELOW_BOTTOM
+ * @checker_framework.manual #fenum-checker Fake Enum Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(FenumTop.class)
+public @interface SwingTitlePosition {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingVerticalOrientation.java b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingVerticalOrientation.java
new file mode 100644
index 0000000..7a70857
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/fenum/qual/SwingVerticalOrientation.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.fenum.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * SwingVerticalOrientation.
+ *
+ * @checker_framework.manual #fenum-checker Fake Enum Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(SwingBoxOrientation.class)
+public @interface SwingVerticalOrientation {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/ConversionCategory.java b/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/ConversionCategory.java
new file mode 100644
index 0000000..3d1728c
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/ConversionCategory.java
@@ -0,0 +1,353 @@
+package org.checkerframework.checker.formatter.qual;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.StringJoiner;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.dataflow.qual.Pure;
+import org.checkerframework.framework.qual.AnnotatedFor;
+
+/**
+ * Elements of this enumeration are used in a {@link Format Format} annotation to indicate the valid
+ * types that may be passed as a format parameter. For example:
+ *
+ * <blockquote>
+ *
+ * <pre>{@literal @}Format({GENERAL, INT}) String f = "String '%s' has length %d";
+ *
+ * String.format(f, "Example", 7);</pre>
+ *
+ * </blockquote>
+ *
+ * The annotation indicates that the format string requires any Object as the first parameter
+ * ({@link ConversionCategory#GENERAL}) and an integer as the second parameter ({@link
+ * ConversionCategory#INT}).
+ *
+ * @see Format
+ * @checker_framework.manual #formatter-checker Format String Checker
+ */
+@SuppressWarnings("unchecked") // ".class" expressions in varargs position
+@AnnotatedFor("nullness")
+public enum ConversionCategory {
+  /** Use if the parameter can be of any type. Applicable for conversions b, B, h, H, s, S. */
+  GENERAL("bBhHsS", (Class<?>[]) null /* everything */),
+
+  /**
+   * Use if the parameter is of a basic types which represent Unicode characters: char, Character,
+   * byte, Byte, short, and Short. This conversion may also be applied to the types int and Integer
+   * when Character.isValidCodePoint(int) returns true. Applicable for conversions c, C.
+   */
+  CHAR("cC", Character.class, Byte.class, Short.class, Integer.class),
+
+  /**
+   * Use if the parameter is an integral type: byte, Byte, short, Short, int and Integer, long,
+   * Long, and BigInteger. Applicable for conversions d, o, x, X.
+   */
+  INT("doxX", Byte.class, Short.class, Integer.class, Long.class, BigInteger.class),
+
+  /**
+   * Use if the parameter is a floating-point type: float, Float, double, Double, and BigDecimal.
+   * Applicable for conversions e, E, f, g, G, a, A.
+   */
+  FLOAT("eEfgGaA", Float.class, Double.class, BigDecimal.class),
+
+  /**
+   * Use if the parameter is a type which is capable of encoding a date or time: long, Long,
+   * Calendar, and Date. Applicable for conversions t, T.
+   */
+  @SuppressWarnings("JdkObsolete")
+  TIME("tT", Long.class, Calendar.class, Date.class),
+
+  /**
+   * Use if the parameter is both a char and an int.
+   *
+   * <p>In a format string, multiple conversions may be applied to the same parameter. This is
+   * seldom needed, but the following is an example of such use:
+   *
+   * <pre>
+   *   format("Test %1$c %1$d", (int)42);
+   * </pre>
+   *
+   * In this example, the first parameter is interpreted as both a character and an int, therefore
+   * the parameter must be compatible with both conversion, and can therefore neither be char nor
+   * long. This intersection of conversions is called CHAR_AND_INT.
+   *
+   * <p>One other conversion intersection is interesting, namely the intersection of INT and TIME,
+   * resulting in INT_AND_TIME.
+   *
+   * <p>All other intersection either lead to an already existing type, or NULL, in which case it is
+   * illegal to pass object's of any type as parameter.
+   */
+  CHAR_AND_INT(null, Byte.class, Short.class, Integer.class),
+
+  /**
+   * Use if the parameter is both an int and a time.
+   *
+   * @see #CHAR_AND_INT
+   */
+  INT_AND_TIME(null, Long.class),
+
+  /**
+   * Use if no object of any type can be passed as parameter. In this case, the only legal value is
+   * null. This is seldomly needed, and indicates an error in most cases. For example:
+   *
+   * <pre>
+   *   format("Test %1$f %1$d", null);
+   * </pre>
+   *
+   * Only null can be legally passed, passing a value such as 4 or 4.2 would lead to an exception.
+   */
+  NULL(null),
+
+  /**
+   * Use if a parameter is not used by the formatter. This is seldomly needed, and indicates an
+   * error in most cases. For example:
+   *
+   * <pre>
+   *   format("Test %1$s %3$s", "a","unused","b");
+   * </pre>
+   *
+   * Only the first "a" and third "b" parameters are used, the second "unused" parameter is ignored.
+   */
+  UNUSED(null, (Class<?>[]) null /* everything */);
+
+  /** The argument types. Null means every type. */
+  @SuppressWarnings("ImmutableEnumChecker") // TODO: clean this up!
+  public final Class<?> @Nullable [] types;
+
+  /** The format specifier characters. Null means users cannot specify it directly. */
+  public final @Nullable String chars;
+
+  /**
+   * Create a new conversion category.
+   *
+   * @param chars the format specifier characters. Null means users cannot specify it directly.
+   * @param types the argument types. Null means every type.
+   */
+  ConversionCategory(@Nullable String chars, Class<?> @Nullable ... types) {
+    this.chars = chars;
+    if (types == null) {
+      this.types = types;
+    } else {
+      List<Class<?>> typesWithPrimitives = new ArrayList<>(types.length);
+      for (Class<?> type : types) {
+        typesWithPrimitives.add(type);
+        Class<?> unwrapped = unwrapPrimitive(type);
+        if (unwrapped != null) {
+          typesWithPrimitives.add(unwrapped);
+        }
+      }
+      this.types = typesWithPrimitives.toArray(new Class<?>[typesWithPrimitives.size()]);
+    }
+  }
+
+  /**
+   * If the given class is a primitive wrapper, return the corresponding primitive class. Otherwise
+   * return null.
+   *
+   * @param c a class
+   * @return the unwrapped primitive, or null
+   */
+  private static @Nullable Class<? extends Object> unwrapPrimitive(Class<?> c) {
+    if (c == Byte.class) {
+      return byte.class;
+    }
+    if (c == Character.class) {
+      return char.class;
+    }
+    if (c == Short.class) {
+      return short.class;
+    }
+    if (c == Integer.class) {
+      return int.class;
+    }
+    if (c == Long.class) {
+      return long.class;
+    }
+    if (c == Float.class) {
+      return float.class;
+    }
+    if (c == Double.class) {
+      return double.class;
+    }
+    if (c == Boolean.class) {
+      return boolean.class;
+    }
+    return null;
+  }
+
+  /**
+   * Converts a conversion character to a category. For example:
+   *
+   * <pre>{@code
+   * ConversionCategory.fromConversionChar('d') == ConversionCategory.INT
+   * }</pre>
+   *
+   * @param c a conversion character
+   * @return the category for the given conversion character
+   */
+  @SuppressWarnings("nullness:dereference.of.nullable") // `chars` field is non-null for these
+  public static ConversionCategory fromConversionChar(char c) {
+    for (ConversionCategory v : new ConversionCategory[] {GENERAL, CHAR, INT, FLOAT, TIME}) {
+      if (v.chars.contains(String.valueOf(c))) {
+        return v;
+      }
+    }
+    throw new IllegalArgumentException("Bad conversion character " + c);
+  }
+
+  private static <E> Set<E> arrayToSet(E[] a) {
+    return new HashSet<>(Arrays.asList(a));
+  }
+
+  public static boolean isSubsetOf(ConversionCategory a, ConversionCategory b) {
+    return intersect(a, b) == a;
+  }
+
+  /**
+   * Returns the intersection of two categories. This is seldomly needed.
+   *
+   * <blockquote>
+   *
+   * <pre>
+   * ConversionCategory.intersect(INT, TIME) == INT_AND_TIME;
+   * </pre>
+   *
+   * </blockquote>
+   *
+   * @param a a category
+   * @param b a category
+   * @return the intersection of the two categories (their greatest lower bound)
+   */
+  public static ConversionCategory intersect(ConversionCategory a, ConversionCategory b) {
+    if (a == UNUSED) {
+      return b;
+    }
+    if (b == UNUSED) {
+      return a;
+    }
+    if (a == GENERAL) {
+      return b;
+    }
+    if (b == GENERAL) {
+      return a;
+    }
+
+    @SuppressWarnings("nullness:argument" // `types` field is null only for UNUSED and GENERAL
+    )
+    Set<Class<?>> as = arrayToSet(a.types);
+    @SuppressWarnings("nullness:argument" // `types` field is null only for UNUSED and GENERAL
+    )
+    Set<Class<?>> bs = arrayToSet(b.types);
+    as.retainAll(bs); // intersection
+    for (ConversionCategory v :
+        new ConversionCategory[] {CHAR, INT, FLOAT, TIME, CHAR_AND_INT, INT_AND_TIME, NULL}) {
+      @SuppressWarnings("nullness:argument" // `types` field is null only for UNUSED and GENERAL
+      )
+      Set<Class<?>> vs = arrayToSet(v.types);
+      if (vs.equals(as)) {
+        return v;
+      }
+    }
+    throw new RuntimeException();
+  }
+
+  /**
+   * Returns the union of two categories. This is seldomly needed.
+   *
+   * <blockquote>
+   *
+   * <pre>
+   * ConversionCategory.union(INT, TIME) == GENERAL;
+   * </pre>
+   *
+   * </blockquote>
+   *
+   * @param a a category
+   * @param b a category
+   * @return the union of the two categories (their least upper bound)
+   */
+  public static ConversionCategory union(ConversionCategory a, ConversionCategory b) {
+    if (a == UNUSED || b == UNUSED) {
+      return UNUSED;
+    }
+    if (a == GENERAL || b == GENERAL) {
+      return GENERAL;
+    }
+    if ((a == CHAR_AND_INT && b == INT_AND_TIME) || (a == INT_AND_TIME && b == CHAR_AND_INT)) {
+      // This is special-cased because the union of a.types and b.types
+      // does not include BigInteger.class, whereas the types for INT does.
+      // Returning INT here to prevent returning GENERAL below.
+      return INT;
+    }
+
+    @SuppressWarnings("nullness:argument" // `types` field is null only for UNUSED and GENERAL
+    )
+    Set<Class<?>> as = arrayToSet(a.types);
+    @SuppressWarnings("nullness:argument" // `types` field is null only for UNUSED and GENERAL
+    )
+    Set<Class<?>> bs = arrayToSet(b.types);
+    as.addAll(bs); // union
+    for (ConversionCategory v :
+        new ConversionCategory[] {NULL, CHAR_AND_INT, INT_AND_TIME, CHAR, INT, FLOAT, TIME}) {
+      @SuppressWarnings("nullness:argument" // `types` field is null only for UNUSED and GENERAL
+      )
+      Set<Class<?>> vs = arrayToSet(v.types);
+      if (vs.equals(as)) {
+        return v;
+      }
+    }
+
+    return GENERAL;
+  }
+
+  /**
+   * Returns true if {@code argType} can be an argument used by this format specifier.
+   *
+   * @param argType an argument type
+   * @return true if {@code argType} can be an argument used by this format specifier
+   */
+  public boolean isAssignableFrom(Class<?> argType) {
+    if (types == null) {
+      return true;
+    }
+    if (argType == void.class) {
+      return true;
+    }
+    for (Class<?> c : types) {
+      if (c.isAssignableFrom(argType)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /** Returns a pretty printed {@link ConversionCategory}. */
+  @Pure
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    sb.append(name());
+    sb.append(" conversion category");
+
+    if (types == null || types.length == 0) {
+      return sb.toString();
+    }
+
+    StringJoiner sj = new StringJoiner(", ", "(one of: ", ")");
+    for (Class<?> cls : types) {
+      sj.add(cls.getSimpleName());
+    }
+    sb.append(" ");
+    sb.append(sj);
+
+    return sb.toString();
+  }
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/Format.java b/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/Format.java
new file mode 100644
index 0000000..878fce1
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/Format.java
@@ -0,0 +1,48 @@
+package org.checkerframework.checker.formatter.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * This annotation, attached to a String type, indicates that the String may be passed to {@link
+ * java.util.Formatter#format(String, Object...) Formatter.format} and similar methods.
+ *
+ * <p>The annotation's value represents the valid arguments that may be passed to the format method.
+ * For example:
+ *
+ * <blockquote>
+ *
+ * <pre>
+ * {@literal @}Format({GENERAL, INT}) String f = "String '%s' has length %d";
+ *
+ *  String.format(f, "Example", 7);
+ * </pre>
+ *
+ * </blockquote>
+ *
+ * The annotation indicates that the format string requires any Object as the first parameter
+ * ({@link ConversionCategory#GENERAL}) and an integer as the second parameter ({@link
+ * ConversionCategory#INT}). The format string accepts any values as additional parameters (because
+ * it ignores them).
+ *
+ * @see ConversionCategory
+ * @checker_framework.manual #formatter-checker Format String Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownFormat.class)
+public @interface Format {
+  /**
+   * An array of {@link ConversionCategory}, indicating the types of legal remaining arguments when
+   * a value of the annotated type is used as the first argument to {@link
+   * java.util.Formatter#format(String, Object...) Formatter.format} and similar methods.
+   *
+   * @return types that can be used as values when a value of this type is the format string
+   */
+  ConversionCategory[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/FormatBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/FormatBottom.java
new file mode 100644
index 0000000..9ce0ec0
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/FormatBottom.java
@@ -0,0 +1,25 @@
+package org.checkerframework.checker.formatter.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the Format String type system. Programmers should rarely write this type.
+ *
+ * @checker_framework.manual #formatter-checker Format String Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@SubtypeOf({Format.class, InvalidFormat.class})
+@DefaultFor(value = {TypeUseLocation.LOWER_BOUND})
+public @interface FormatBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/FormatMethod.java b/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/FormatMethod.java
new file mode 100644
index 0000000..1a851fb
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/FormatMethod.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.formatter.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * If this annotation is attached to a {@link java.util.Formatter#format(String, Object...)
+ * Formatter.format}-like method, then the first parameter of type String is treated as a format
+ * string for the following arguments. The Format String Checker ensures that the arguments passed
+ * as varargs are compatible with the format string argument, and also permits them to be passed to
+ * {@link java.util.Formatter#format(String, Object...) Formatter.format}-like methods within the
+ * body.
+ *
+ * @checker_framework.manual #formatter-checker Format String Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface FormatMethod {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/InvalidFormat.java b/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/InvalidFormat.java
new file mode 100644
index 0000000..d6597ee
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/InvalidFormat.java
@@ -0,0 +1,29 @@
+package org.checkerframework.checker.formatter.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * This annotation, attached to a {@link java.lang.String String} type, indicates that the string is
+ * not a legal format string. Passing the string to {@link java.util.Formatter#format(String,
+ * Object...) Formatter.format} or similar methods will lead to the exception message indicated in
+ * the annotation's value.
+ *
+ * @checker_framework.manual #formatter-checker Format String Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownFormat.class)
+public @interface InvalidFormat {
+  /**
+   * Using a value of the annotated type as the first argument to {@link
+   * java.util.Formatter#format(String, Object...) Formatter.format} or similar methods will lead to
+   * this exception message.
+   */
+  String value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/ReturnsFormat.java b/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/ReturnsFormat.java
new file mode 100644
index 0000000..ef34fd3
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/ReturnsFormat.java
@@ -0,0 +1,27 @@
+package org.checkerframework.checker.formatter.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Attach this annotation to a method with the following properties:
+ *
+ * <ul>
+ *   <li>The first parameter is a format string.
+ *   <li>The second parameter is a vararg that takes conversion categories.
+ *   <li>The method throws an exception if the format string's format specifiers do not match the
+ *       passed conversion categories.
+ *   <li>On success, the method returns the passed format string unmodified.
+ * </ul>
+ *
+ * An example is {@link org.checkerframework.checker.formatter.util.FormatUtil#asFormat}.
+ *
+ * @checker_framework.manual #formatter-checker Format String Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface ReturnsFormat {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/UnknownFormat.java b/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/UnknownFormat.java
new file mode 100644
index 0000000..e4da196
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/formatter/qual/UnknownFormat.java
@@ -0,0 +1,32 @@
+package org.checkerframework.checker.formatter.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The top qualifier.
+ *
+ * <p>A type annotation indicating that the run-time value might or might not be a valid format
+ * string.
+ *
+ * <p>This annotation may not be written in source code; it is an implementation detail of the
+ * checker.
+ *
+ * @checker_framework.manual #formatter-checker Format String Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@InvisibleQualifier
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+public @interface UnknownFormat {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/AlwaysSafe.java b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/AlwaysSafe.java
new file mode 100644
index 0000000..0730811
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/AlwaysSafe.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.guieffect.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Annotation to override the UI effect on a class, and make a field or method safe for non-UI code
+ * to use.
+ *
+ * @checker_framework.manual #guieffect-checker GUI Effect Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({UI.class})
+@DefaultQualifierInHierarchy
+public @interface AlwaysSafe {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/PolyUI.java b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/PolyUI.java
new file mode 100644
index 0000000..7586919
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/PolyUI.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.guieffect.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * Annotation for the polymorphic-UI effect.
+ *
+ * @checker_framework.manual #guieffect-checker GUI Effect Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier(UI.class)
+public @interface PolyUI {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/PolyUIEffect.java b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/PolyUIEffect.java
new file mode 100644
index 0000000..cf8cc04
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/PolyUIEffect.java
@@ -0,0 +1,18 @@
+package org.checkerframework.checker.guieffect.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for the polymorphic effect on methods, or on field accesses.
+ *
+ * @checker_framework.manual #guieffect-checker GUI Effect Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
+public @interface PolyUIEffect {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/PolyUIType.java b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/PolyUIType.java
new file mode 100644
index 0000000..2026273
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/PolyUIType.java
@@ -0,0 +1,18 @@
+package org.checkerframework.checker.guieffect.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for the polymorphic type declaration.
+ *
+ * @checker_framework.manual #guieffect-checker GUI Effect Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface PolyUIType {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/SafeEffect.java b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/SafeEffect.java
new file mode 100644
index 0000000..1d529d9
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/SafeEffect.java
@@ -0,0 +1,17 @@
+package org.checkerframework.checker.guieffect.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for the concrete safe effect on methods, or on field accesses.
+ *
+ * @checker_framework.manual #guieffect-checker GUI Effect Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
+public @interface SafeEffect {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/SafeType.java b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/SafeType.java
new file mode 100644
index 0000000..a1ced02
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/SafeType.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.guieffect.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Class declaration annotation to make methods default to {@code @AlwaysSafe}. While the normal
+ * default is already {@code @AlwaysSafe} methods, this is useful for a type inside a package marked
+ * {@code @UIPackage}.
+ *
+ * @checker_framework.manual #guieffect-checker GUI Effect Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface SafeType {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/UI.java b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/UI.java
new file mode 100644
index 0000000..615b4da
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/UI.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.guieffect.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Annotation for the UI effect.
+ *
+ * @checker_framework.manual #guieffect-checker GUI Effect Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({})
+public @interface UI {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/UIEffect.java b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/UIEffect.java
new file mode 100644
index 0000000..67a6d43
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/UIEffect.java
@@ -0,0 +1,17 @@
+package org.checkerframework.checker.guieffect.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for the concrete UI effect on methods, or on field accesses.
+ *
+ * @checker_framework.manual #guieffect-checker GUI Effect Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
+public @interface UIEffect {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/UIPackage.java b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/UIPackage.java
new file mode 100644
index 0000000..6f0a5f5
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/UIPackage.java
@@ -0,0 +1,17 @@
+package org.checkerframework.checker.guieffect.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Package annotation to make all classes within a package {@code @UIType}.
+ *
+ * @checker_framework.manual #guieffect-checker GUI Effect Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PACKAGE})
+public @interface UIPackage {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/UIType.java b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/UIType.java
new file mode 100644
index 0000000..b3cb665
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/guieffect/qual/UIType.java
@@ -0,0 +1,17 @@
+package org.checkerframework.checker.guieffect.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Class declaration annotation to make methods default to {@code @UI}.
+ *
+ * @checker_framework.manual #guieffect-checker GUI Effect Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface UIType {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/i18n/qual/LocalizableKey.java b/checker-qual/src/main/java/org/checkerframework/checker/i18n/qual/LocalizableKey.java
new file mode 100644
index 0000000..ce74615
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/i18n/qual/LocalizableKey.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.i18n.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Indicates that the {@code String} is a key into a property file or resource bundle containing
+ * Localized Strings.
+ *
+ * @checker_framework.manual #i18n-checker Internationalization Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownLocalizableKey.class)
+public @interface LocalizableKey {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/i18n/qual/LocalizableKeyBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/i18n/qual/LocalizableKeyBottom.java
new file mode 100644
index 0000000..712244a
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/i18n/qual/LocalizableKeyBottom.java
@@ -0,0 +1,26 @@
+package org.checkerframework.checker.i18n.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the Internationalization type system. Programmers should rarely write this
+ * type.
+ *
+ * @checker_framework.manual #i18n-checker Internationalization Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@SubtypeOf(LocalizableKey.class)
+@DefaultFor(TypeUseLocation.LOWER_BOUND)
+public @interface LocalizableKeyBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/i18n/qual/Localized.java b/checker-qual/src/main/java/org/checkerframework/checker/i18n/qual/Localized.java
new file mode 100644
index 0000000..663cb07
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/i18n/qual/Localized.java
@@ -0,0 +1,31 @@
+package org.checkerframework.checker.i18n.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.LiteralKind;
+import org.checkerframework.framework.qual.QualifierForLiterals;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Indicates that the {@code String} type has been localized and formatted for the target output
+ * locale.
+ *
+ * @checker_framework.manual #i18n-checker Internationalization Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownLocalized.class)
+@QualifierForLiterals({
+  // All literals except chars and strings, which may need to be localized.
+  // (null is bottom by default.)
+  LiteralKind.INT,
+  LiteralKind.LONG,
+  LiteralKind.FLOAT,
+  LiteralKind.DOUBLE,
+  LiteralKind.BOOLEAN
+})
+public @interface Localized {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/i18n/qual/UnknownLocalizableKey.java b/checker-qual/src/main/java/org/checkerframework/checker/i18n/qual/UnknownLocalizableKey.java
new file mode 100644
index 0000000..71a8448
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/i18n/qual/UnknownLocalizableKey.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.i18n.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Indicates that the {@code String} type has an unknown localizable key property.
+ *
+ * @checker_framework.manual #i18n-checker Internationalization Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@InvisibleQualifier
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface UnknownLocalizableKey {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/i18n/qual/UnknownLocalized.java b/checker-qual/src/main/java/org/checkerframework/checker/i18n/qual/UnknownLocalized.java
new file mode 100644
index 0000000..2bb0980
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/i18n/qual/UnknownLocalized.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.i18n.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Indicates that the {@code String} type has unknown localization properties.
+ *
+ * @checker_framework.manual #i18n-checker Internationalization Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@InvisibleQualifier
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface UnknownLocalized {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nChecksFormat.java b/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nChecksFormat.java
new file mode 100644
index 0000000..b37f899
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nChecksFormat.java
@@ -0,0 +1,27 @@
+package org.checkerframework.checker.i18nformatter.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is used internally to annotate {@link
+ * org.checkerframework.checker.i18nformatter.util.I18nFormatUtil#hasFormat} (and will potentially
+ * be used to annotate more such functions in the future).
+ *
+ * <p>Attach this annotation to a method with the following properties:
+ *
+ * <ul>
+ *   <li>The first parameter is a format string.
+ *   <li>The second parameter is a vararg that takes conversion categories.
+ *   <li>The method returns true if the format string is compatible with the conversion categories.
+ * </ul>
+ *
+ * @checker_framework.manual #i18n-formatter-checker Internationalization Format String Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface I18nChecksFormat {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nConversionCategory.java b/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nConversionCategory.java
new file mode 100644
index 0000000..e8ee3d3
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nConversionCategory.java
@@ -0,0 +1,204 @@
+package org.checkerframework.checker.i18nformatter.qual;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.StringJoiner;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.AnnotatedFor;
+
+/**
+ * Elements of this enumeration are used in a {@link I18nFormat} annotation to indicate the valid
+ * types that may be passed as a format parameter. For example:
+ *
+ * <pre>{@literal @}I18nFormat({GENERAL, NUMBER}) String f = "{0}{1, number}";
+ * MessageFormat.format(f, "Example", 0) // valid</pre>
+ *
+ * The annotation indicates that the format string requires any object as the first parameter
+ * ({@link I18nConversionCategory#GENERAL}) and a number as the second parameter ({@link
+ * I18nConversionCategory#NUMBER}).
+ *
+ * @checker_framework.manual #i18n-formatter-checker Internationalization Format String Checker
+ */
+@AnnotatedFor("nullness")
+public enum I18nConversionCategory {
+
+  /**
+   * Use if a parameter is not used by the formatter. For example, in
+   *
+   * <pre>
+   * MessageFormat.format(&quot;{1}&quot;, a, b);
+   * </pre>
+   *
+   * only the second argument ("b") is used. The first argument ("a") is ignored.
+   */
+  UNUSED(null /* everything */, null),
+
+  /** Use if the parameter can be of any type. */
+  GENERAL(null /* everything */, null),
+
+  /** Use if the parameter can be of date, time, or number types. */
+  DATE(new Class<?>[] {Date.class, Number.class}, new String[] {"date", "time"}),
+
+  /**
+   * Use if the parameter can be of number or choice types. An example of choice:
+   *
+   * <pre>{@code
+   * format("{0, choice, 0#zero|1#one|1<{0, number} is more than 1}", 2)
+   * }</pre>
+   *
+   * This will print "2 is more than 1".
+   */
+  NUMBER(new Class<?>[] {Number.class}, new String[] {"number", "choice"});
+
+  @SuppressWarnings("ImmutableEnumChecker") // TODO: clean this up!
+  public final Class<?> @Nullable [] types;
+
+  @SuppressWarnings("ImmutableEnumChecker") // TODO: clean this up!
+  public final String @Nullable [] strings;
+
+  I18nConversionCategory(Class<?> @Nullable [] types, String @Nullable [] strings) {
+    this.types = types;
+    this.strings = strings;
+  }
+
+  /** Used by {@link #stringToI18nConversionCategory}. */
+  static I18nConversionCategory[] namedCategories = new I18nConversionCategory[] {DATE, NUMBER};
+
+  /**
+   * Creates a conversion cagetogry from a string name.
+   *
+   * <pre>
+   * I18nConversionCategory.stringToI18nConversionCategory("number") == I18nConversionCategory.NUMBER;
+   * </pre>
+   *
+   * @return the I18nConversionCategory associated with the given string
+   */
+  @SuppressWarnings(
+      "nullness:iterating.over.nullable") // in namedCategories, `strings` field is non-null
+  public static I18nConversionCategory stringToI18nConversionCategory(String string) {
+    string = string.toLowerCase();
+    for (I18nConversionCategory v : namedCategories) {
+      for (String s : v.strings) {
+        if (s.equals(string)) {
+          return v;
+        }
+      }
+    }
+    throw new IllegalArgumentException("Invalid format type " + string);
+  }
+
+  private static <E> Set<E> arrayToSet(E[] a) {
+    return new HashSet<>(Arrays.asList(a));
+  }
+
+  /**
+   * Return true if a is a subset of b.
+   *
+   * @return true if a is a subset of b
+   */
+  public static boolean isSubsetOf(I18nConversionCategory a, I18nConversionCategory b) {
+    return intersect(a, b) == a;
+  }
+
+  /**
+   * Returns the intersection of the two given I18nConversionCategories.
+   *
+   * <blockquote>
+   *
+   * <pre>
+   * I18nConversionCategory.intersect(DATE, NUMBER) == NUMBER;
+   * </pre>
+   *
+   * </blockquote>
+   */
+  public static I18nConversionCategory intersect(
+      I18nConversionCategory a, I18nConversionCategory b) {
+    if (a == UNUSED) {
+      return b;
+    }
+    if (b == UNUSED) {
+      return a;
+    }
+    if (a == GENERAL) {
+      return b;
+    }
+    if (b == GENERAL) {
+      return a;
+    }
+
+    @SuppressWarnings("nullness:argument" // types field  is only null in UNUSED and GENERAL
+    )
+    Set<Class<?>> as = arrayToSet(a.types);
+    @SuppressWarnings("nullness:argument" // types field  is only null in UNUSED and GENERAL
+    )
+    Set<Class<?>> bs = arrayToSet(b.types);
+    as.retainAll(bs); // intersection
+    for (I18nConversionCategory v : new I18nConversionCategory[] {DATE, NUMBER}) {
+      @SuppressWarnings("nullness:argument") // in those values, `types` field is non-null
+      Set<Class<?>> vs = arrayToSet(v.types);
+      if (vs.equals(as)) {
+        return v;
+      }
+    }
+    throw new RuntimeException();
+  }
+
+  /**
+   * Returns the union of the two given I18nConversionCategories.
+   *
+   * <pre>
+   * I18nConversionCategory.intersect(DATE, NUMBER) == DATE;
+   * </pre>
+   */
+  public static I18nConversionCategory union(I18nConversionCategory a, I18nConversionCategory b) {
+    if (a == UNUSED || b == UNUSED) {
+      return UNUSED;
+    }
+    if (a == GENERAL || b == GENERAL) {
+      return GENERAL;
+    }
+    if (a == DATE || b == DATE) {
+      return DATE;
+    }
+    return NUMBER;
+  }
+
+  /**
+   * Returns true if {@code argType} can be an argument used by this format specifier.
+   *
+   * @param argType an argument type
+   * @return true if {@code argType} can be an argument used by this format specifier
+   */
+  public boolean isAssignableFrom(Class<?> argType) {
+    if (types == null) {
+      return true;
+    }
+    if (argType == void.class) {
+      return true;
+    }
+    for (Class<?> c : types) {
+      if (c.isAssignableFrom(argType)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /** Returns a pretty printed {@link I18nConversionCategory}. */
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder(this.name());
+    if (this.types == null) {
+      sb.append(" conversion category (all types)");
+    } else {
+      StringJoiner sj = new StringJoiner(", ", " conversion category (one of: ", ")");
+      for (Class<?> cls : this.types) {
+        sj.add(cls.getCanonicalName());
+      }
+      sb.append(sj);
+    }
+    return sb.toString();
+  }
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nFormat.java b/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nFormat.java
new file mode 100644
index 0000000..5e29edc
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nFormat.java
@@ -0,0 +1,42 @@
+package org.checkerframework.checker.i18nformatter.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * This annotation, attached to a String type, indicates that the String may be passed to {@link
+ * java.text.MessageFormat#format(String, Object...) MessageFormat.format}.
+ *
+ * <p>The annotation's value represents the valid arguments that may be passed to the format method.
+ * For example:
+ *
+ * <pre>{@literal @}I18nFormat({GENERAL, NUMBER}) String f;
+ *
+ * f = "{0}{1, number}"; // valid
+ * f = "{0} {1} {2}"; // error, the format string is stronger (more restrictive) than the specifiers.
+ * f = "{0, number} {1, number}"; // error, the format string is stronger (NUMBER is a subtype of GENERAL).
+ * </pre>
+ *
+ * The annotation indicates that the format string requires any object as the first parameter
+ * ({@link I18nConversionCategory#GENERAL}) and a number as the second parameter ({@link
+ * I18nConversionCategory#NUMBER}).
+ *
+ * @see I18nConversionCategory
+ * @checker_framework.manual #i18n-formatter-checker Internationalization Format String Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(I18nUnknownFormat.class)
+public @interface I18nFormat {
+  /**
+   * An array of {@link I18nConversionCategory}, indicating the types of legal remaining arguments
+   * when a value of the annotated type is used as the first argument to {@link
+   * java.text.MessageFormat#format(String, Object...) Message.format}.
+   */
+  I18nConversionCategory[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nFormatBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nFormatBottom.java
new file mode 100644
index 0000000..44637a3
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nFormatBottom.java
@@ -0,0 +1,26 @@
+package org.checkerframework.checker.i18nformatter.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the Internationalization Format String type system. Programmers should rarely
+ * write this type.
+ *
+ * @checker_framework.manual #i18n-formatter-checker Internationalization Format String Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@SubtypeOf({I18nFormat.class, I18nInvalidFormat.class, I18nFormatFor.class})
+@DefaultFor(value = {TypeUseLocation.LOWER_BOUND})
+public @interface I18nFormatBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nFormatFor.java b/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nFormatFor.java
new file mode 100644
index 0000000..a0e30d6
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nFormatFor.java
@@ -0,0 +1,43 @@
+package org.checkerframework.checker.i18nformatter.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * This annotation indicates that when a string of the annotated type is passed as the first
+ * argument to {@link java.text.MessageFormat#format(String, Object...)}, then the expression that
+ * is an argument to the annotation can be passed as the remaining arguments, in varargs style.
+ *
+ * <p>The annotation is used to annotate a method to ensure that an argument is of a particular type
+ * indicated by a format string.
+ *
+ * <p>Example:
+ *
+ * <pre> static void method(@I18nFormatFor("#2") String format, Object... arg2) {...}
+ *
+ * method("{0, number}", 2);</pre>
+ *
+ * This ensures that the second parameter ("#2") can be passed as the remaining arguments of {@link
+ * java.text.MessageFormat#format(String, Object...)}, when the first argument is {@code "format"}.
+ *
+ * @checker_framework.manual #i18n-formatter-checker Internationalization Format String Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(I18nUnknownFormat.class)
+public @interface I18nFormatFor {
+  /**
+   * Indicates which formal parameter is the arguments to the format method. The value should be
+   * {@code #} followed by the 1-based index of the formal parameter that is the arguments to the
+   * format method, e.g., {@code "#2"}.
+   *
+   * @return {@code #} followed by the 1-based index of the formal parameter that is the arguments
+   *     to the format method
+   */
+  String value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nInvalidFormat.java b/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nInvalidFormat.java
new file mode 100644
index 0000000..379082d
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nInvalidFormat.java
@@ -0,0 +1,26 @@
+package org.checkerframework.checker.i18nformatter.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * This annotation, attached to a {@link java.lang.String String} type, indicates that if the String
+ * is passed to {@link java.text.MessageFormat#format(String, Object...)}, an exception will result.
+ *
+ * @checker_framework.manual #i18n-formatter-checker Internationalization Format String Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(I18nUnknownFormat.class)
+public @interface I18nInvalidFormat {
+  /**
+   * Using a value of the annotated type as the first argument to {@link
+   * java.text.MessageFormat#format(String, Object...)} will lead to this exception message.
+   */
+  String value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nMakeFormat.java b/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nMakeFormat.java
new file mode 100644
index 0000000..a9d6641
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nMakeFormat.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.i18nformatter.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is used internally to annotate {@link java.util.ResourceBundle#getString}
+ * indicating the checker to check if the given key exist in the translation file and annotate the
+ * result string with the correct format annotation according to the corresponding key's value. This
+ * is done in {@link org.checkerframework.checker.i18nformatter.I18nFormatterTransfer}
+ *
+ * @checker_framework.manual #i18n-formatter-checker Internationalization Format String Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface I18nMakeFormat {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nUnknownFormat.java b/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nUnknownFormat.java
new file mode 100644
index 0000000..f8dbc7d
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nUnknownFormat.java
@@ -0,0 +1,29 @@
+package org.checkerframework.checker.i18nformatter.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The top qualifier.
+ *
+ * <p>A type annotation indicating that the run-time value might or might not be a valid i18n format
+ * string.
+ *
+ * @checker_framework.manual #i18n-formatter-checker Internationalization Format String Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@InvisibleQualifier
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface I18nUnknownFormat {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nValidFormat.java b/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nValidFormat.java
new file mode 100644
index 0000000..3285964
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nValidFormat.java
@@ -0,0 +1,18 @@
+package org.checkerframework.checker.i18nformatter.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is used internally to annotate {@link
+ * org.checkerframework.checker.i18nformatter.util.I18nFormatUtil#isFormat}.
+ *
+ * @checker_framework.manual #i18n-formatter-checker Internationalization Format String Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface I18nValidFormat {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/EnsuresLTLengthOf.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/EnsuresLTLengthOf.java
new file mode 100644
index 0000000..e799cd4
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/EnsuresLTLengthOf.java
@@ -0,0 +1,105 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.InheritedAnnotation;
+import org.checkerframework.framework.qual.JavaExpression;
+import org.checkerframework.framework.qual.PostconditionAnnotation;
+import org.checkerframework.framework.qual.QualifierArgument;
+
+/**
+ * Indicates that the value expressions evaluate to an integer whose value is less than the lengths
+ * of all the given sequences, if the method terminates successfully.
+ *
+ * <p>Consider the following example, from the Index Checker's regression tests:
+ *
+ * <pre>
+ * {@code @EnsuresLTLengthOf(value = "end", targetValue = "array", offset = "#1 - 1")
+ *  public void shiftIndex(@NonNegative int x) {
+ *      int newEnd = end - x;
+ *      if (newEnd < 0) throw new RuntimeException();
+ *      end = newEnd;
+ *  }
+ * }
+ * </pre>
+ *
+ * where {@code end} is annotated as {@code @NonNegative @LTEqLengthOf("array") int end;}
+ *
+ * <p>This method guarantees that {@code end} has type {@code @LTLengthOf(value="array", offset="x -
+ * 1")} after the method returns. This is useful in cases like this one:
+ *
+ * <pre>{@code
+ * public void useShiftIndex(@NonNegative int x) {
+ *    // :: error: (argument)
+ *    Arrays.fill(array, end, end + x, null);
+ *    shiftIndex(x);
+ *    Arrays.fill(array, end, end + x, null);
+ * }
+ * }</pre>
+ *
+ * The first call to {@code Arrays.fill} is rejected (hence the comment about an error). But, after
+ * calling {@code shiftIndex(x)}, {@code end} has an annotation that allows the {@code end + x} to
+ * be accepted as {@code @LTLengthOf("array")}.
+ *
+ * @see LTLengthOf
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+@PostconditionAnnotation(qualifier = LTLengthOf.class)
+@InheritedAnnotation
+@Repeatable(EnsuresLTLengthOf.List.class)
+public @interface EnsuresLTLengthOf {
+  /**
+   * The Java expressions that are less than the length of the given sequences on successful method
+   * termination.
+   *
+   * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions
+   */
+  @JavaExpression
+  String[] value();
+
+  /**
+   * Sequences, each of which is longer than the each of the expressions' value on successful method
+   * termination.
+   */
+  @JavaExpression
+  @QualifierArgument("value")
+  String[] targetValue();
+
+  /**
+   * This expression plus each of the value expressions is less than the length of the sequence on
+   * successful method termination. The {@code offset} element must ether be empty or the same
+   * length as {@code targetValue}.
+   *
+   * @return the offset expressions
+   */
+  @JavaExpression
+  @QualifierArgument("offset")
+  String[] offset() default {};
+
+  /**
+   * A wrapper annotation that makes the {@link EnsuresLTLengthOf} annotation repeatable.
+   *
+   * <p>Programmers generally do not need to write this. It is created by Java when a programmer
+   * writes more than one {@link EnsuresLTLengthOf} annotation at the same location.
+   */
+  @Documented
+  @Retention(RetentionPolicy.RUNTIME)
+  @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+  @PostconditionAnnotation(qualifier = LTLengthOf.class)
+  @InheritedAnnotation
+  @interface List {
+    /**
+     * Return the repeatable annotations.
+     *
+     * @return the repeatable annotations
+     */
+    EnsuresLTLengthOf[] value();
+  }
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/EnsuresLTLengthOfIf.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/EnsuresLTLengthOfIf.java
new file mode 100644
index 0000000..926d01b
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/EnsuresLTLengthOfIf.java
@@ -0,0 +1,110 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.ConditionalPostconditionAnnotation;
+import org.checkerframework.framework.qual.InheritedAnnotation;
+import org.checkerframework.framework.qual.JavaExpression;
+import org.checkerframework.framework.qual.QualifierArgument;
+
+/**
+ * Indicates that the given expressions evaluate to an integer whose value is less than the lengths
+ * of all the given sequences, if the method returns the given result (either true or false).
+ *
+ * <p>As an example, consider the following method:
+ *
+ * <pre>
+ *      &#64;EnsuresLTLengthOfIf(
+ *          expression = "end",
+ *          result = true,
+ *          targetValue = "array",
+ *          offset = "#1 - 1"
+ *      )
+ *      public boolean tryShiftIndex(&#64;NonNegative int x) {
+ *          int newEnd = end - x;
+ *          if (newEnd &#60; 0) {
+ *             return false;
+ *          }
+ *          end = newEnd;
+ *          return true;
+ *      }
+ * </pre>
+ *
+ * Calling this function ensures that the field {@code end} of the {@code this} object is of type
+ * {@code @LTLengthOf(value = "array", offset = "x - 1")}, for the value {@code x} that is passed as
+ * the argument. This allows the Index Checker to verify that {@code end + x} is an index into
+ * {@code array} in the following code:
+ *
+ * <pre>
+ *      public void useTryShiftIndex(&#64;NonNegative int x) {
+ *          if (tryShiftIndex(x)) {
+ *              Arrays.fill(array, end, end + x, null);
+ *          }
+ *      }
+ * </pre>
+ *
+ * @see LTLengthOf
+ * @see EnsuresLTLengthOf
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+@ConditionalPostconditionAnnotation(qualifier = LTLengthOf.class)
+@InheritedAnnotation
+@Repeatable(EnsuresLTLengthOfIf.List.class)
+public @interface EnsuresLTLengthOfIf {
+  /**
+   * Java expression(s) that are less than the length of the given sequences after the method
+   * returns the given result.
+   *
+   * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions
+   */
+  String[] expression();
+
+  /** The return value of the method that needs to hold for the postcondition to hold. */
+  boolean result();
+
+  /**
+   * Sequences, each of which is longer than each of the expressions' value after the method returns
+   * the given result.
+   */
+  @JavaExpression
+  @QualifierArgument("value")
+  String[] targetValue();
+
+  /**
+   * This expression plus each of the expressions is less than the length of the sequence after the
+   * method returns the given result. The {@code offset} element must ether be empty or the same
+   * length as {@code targetValue}.
+   *
+   * @return the offset expressions
+   */
+  @JavaExpression
+  @QualifierArgument("offset")
+  String[] offset() default {};
+
+  /**
+   * A wrapper annotation that makes the {@link EnsuresLTLengthOfIf} annotation repeatable.
+   *
+   * <p>Programmers generally do not need to write this. It is created by Java when a programmer
+   * writes more than one {@link EnsuresLTLengthOfIf} annotation at the same location.
+   */
+  @Documented
+  @Retention(RetentionPolicy.RUNTIME)
+  @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+  @ConditionalPostconditionAnnotation(qualifier = LTLengthOf.class)
+  @InheritedAnnotation
+  @interface List {
+    /**
+     * Return the repeatable annotations.
+     *
+     * @return the repeatable annotations
+     */
+    EnsuresLTLengthOfIf[] value();
+  }
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/GTENegativeOne.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/GTENegativeOne.java
new file mode 100644
index 0000000..034dc32
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/GTENegativeOne.java
@@ -0,0 +1,35 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The annotated expression evaluates to an integer greater than or equal to -1. ("GTE" stands for
+ * ``Greater Than or Equal to''.)
+ *
+ * <p>As an example use case, consider the definition of the read() method in java.io.InputStream:
+ *
+ * <pre>
+ *
+ *      Reads the next byte of data from the input stream. The value byte is returned as an int in the range 0 to 255.
+ *      If no byte is available because the end of the stream has been reached, the value -1 is returned.
+ *      This method blocks until input data is available, the end of the stream is detected, or an exception is thrown.
+ *      A subclass must provide an implementation of this method.
+ *
+ *      Returns: the next byte of data, or -1 if the end of the stream is reached.
+ *      Throws: IOException - if an I/O error occurs.
+ *
+ *     {@code public abstract @GTENegativeOne int read() throws IOException;}
+ * </pre>
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({LowerBoundUnknown.class})
+public @interface GTENegativeOne {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/HasSubsequence.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/HasSubsequence.java
new file mode 100644
index 0000000..4283e2f
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/HasSubsequence.java
@@ -0,0 +1,74 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.JavaExpression;
+
+/**
+ * The annotated sequence contains a subsequence that is equal to the value of some other
+ * expression. This annotation permits the Upper Bound Checker to translate indices for one sequence
+ * into indices for the other sequence.
+ *
+ * <p>Consider the following example:
+ *
+ * <pre><code>
+ *  class IntSubArray {
+ *    {@literal @}HasSubsequence(subsequence = "this", from = "this.start", to = "this.end")
+ *    int [] array;
+ *    {@literal @}IndexFor("array") int start;
+ *    {@literal @}IndexOrHigh("array") int end;
+ *  }
+ * </code></pre>
+ *
+ * The above annotations mean that the value of an {@code IntSubArray} object is equal to a
+ * subsequence of its {@code array} field.
+ *
+ * <p>These annotations imply the following relationships among {@code @}{@link IndexFor}
+ * annotations:
+ *
+ * <ul>
+ *   <li>If {@code i} is {@code @IndexFor("this")}, then {@code start + i} is
+ *       {@code @IndexFor("array")}.
+ *   <li>If {@code j} is {@code @IndexFor("array")}, then {@code j - start } is
+ *       {@code @IndexFor("this")}.
+ * </ul>
+ *
+ * When assigning an array {@code a} to {@code array}, 4 facts need to be true:
+ *
+ * <ul>
+ *   <li>{@code start} is {@code @NonNegative}.
+ *   <li>{@code end} is {@code @LTEqLengthOf("a")}.
+ *   <li>{@code start} is {@code @LessThan("end + 1")}.
+ *   <li>the value of {@code this} equals {@code array[start..end-1]}
+ * </ul>
+ *
+ * The Index Checker verifies the first 3 facts, but always issues a warning because it cannot prove
+ * the 4th fact. The programmer should should manually verify that the {@code subsequence} field is
+ * equal to the given subsequence and then suppress the warning.
+ *
+ * <p>For an example of how this annotation is used in practice, see the test GuavaPrimitives.java
+ * in /checker/tests/index/.
+ *
+ * <p>This annotation may only be written on fields.
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+public @interface HasSubsequence {
+  /** An expression that evaluates to the subsequence. */
+  @JavaExpression
+  String subsequence();
+
+  /** The index into this where the subsequence starts. */
+  @JavaExpression
+  String from();
+
+  /** The index into this, immediately past where the subsequence ends. */
+  @JavaExpression
+  String to();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/IndexFor.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/IndexFor.java
new file mode 100644
index 0000000..5393a55
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/IndexFor.java
@@ -0,0 +1,41 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An integer that can be used to index any of the given sequences.
+ *
+ * <p>For example, an expression with type {@code @IndexFor({"a", "b"})} is non-negative and is less
+ * than both {@code a.length} and {@code b.length}. The sequences {@code a} and {@code b} might have
+ * different lengths.
+ *
+ * <p>The <a
+ * href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/String.html#charAt(int)">
+ * {@code String.charAt(int)}</a> method is declared as
+ *
+ * <pre>{@code
+ * class String {
+ *   char charAt(@IndexFor("this") index) { ... }
+ * }
+ * }</pre>
+ *
+ * <p>Writing {@code @IndexFor("arr")} is equivalent to writing {@link NonNegative @NonNegative}
+ * {@link LTLengthOf @LTLengthOf("arr")}, and that is how it is treated internally by the checker.
+ * Thus, if you write an {@code @IndexFor("arr")} annotation, you might see warnings about
+ * {@code @NonNegative} or {@code @LTLengthOf}.
+ *
+ * @see NonNegative
+ * @see LTLengthOf
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+public @interface IndexFor {
+  /** Sequences that the annotated expression is a valid index for. */
+  String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/IndexOrHigh.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/IndexOrHigh.java
new file mode 100644
index 0000000..b2bbd6a
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/IndexOrHigh.java
@@ -0,0 +1,38 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An integer that, for each of the given sequences, is either a valid index or is equal to the
+ * sequence's length.
+ *
+ * <p>The <a
+ * href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Arrays.html#binarySearch(java.lang.Object%5B%5D,int,int,java.lang.Object)">
+ * {@code Arrays.binarySearch}</a> method is declared as
+ *
+ * <pre>{@code
+ * class Arrays {
+ *   int binarySearch(Object[] a, @IndexFor("#1") int fromIndex, @IndexOrHigh("#1") int toIndex, Object key)
+ * }
+ * }</pre>
+ *
+ * <p>Writing {@code @IndexOrHigh("arr")} is equivalent to writing {@link NonNegative @NonNegative}
+ * {@link LTEqLengthOf @LTEqLengthOf("arr")}, and that is how it is treated internally by the
+ * checker. Thus, if you write an {@code @IndexFor("arr")} annotation, you might see warnings about
+ * {@code @NonNegative} or {@code @LTEqLengthOf}.
+ *
+ * @see NonNegative
+ * @see LTLengthOf
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+public @interface IndexOrHigh {
+  /** Sequences that the annotated expression is a valid index for or is equal to the lengeth of. */
+  String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/IndexOrLow.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/IndexOrLow.java
new file mode 100644
index 0000000..1965d76
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/IndexOrLow.java
@@ -0,0 +1,37 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An integer that is either -1 or is a valid index for each of the given sequences.
+ *
+ * <p>The <a
+ * href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/String.html#indexOf(java.lang.String)">
+ * {@code String.indexOf(String)}</a> method is declared as
+ *
+ * <pre><code>
+ *   class String {
+ *    {@literal @}IndexOrLow("this") int indexOf(String str) { ... }
+ *   }
+ * </code></pre>
+ *
+ * <p>Writing {@code @IndexOrLow("arr")} is equivalent to writing {@link
+ * GTENegativeOne @GTENegativeOne} {@link LTLengthOf @LTLengthOf("arr")}, and that is how it is
+ * treated internally by the checker. Thus, if you write an {@code @IndexOrLow("arr")} annotation,
+ * you might see warnings about {@code @GTENegativeOne} or {@code @LTLengthOf}.
+ *
+ * @see GTENegativeOne
+ * @see LTLengthOf
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+public @interface IndexOrLow {
+  /** Sequences that the annotated expression is a valid index for (or it's -1). */
+  String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LTEqLengthOf.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LTEqLengthOf.java
new file mode 100644
index 0000000..1035cee
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LTEqLengthOf.java
@@ -0,0 +1,33 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.JavaExpression;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The annotated expression evaluates to an integer whose value is less than or equal to the lengths
+ * of all the given sequences. ("LTEq" stands for "Less than or equal to".)
+ *
+ * <p>For example, an expression with type {@code @LTLengthOf({"a", "b"})} is less than or equal to
+ * both {@code a.length} and {@code b.length}. The sequences {@code a} and {@code b} might have
+ * different lengths.
+ *
+ * <p>{@code @LTEqLengthOf({"a"})} = {@code @LTLengthOf(value={"a"}, offset=-1)}, and<br>
+ * {@code @LTEqLengthOf(value={"a"}, offset=x)} = {@code @LTLengthOf(value={"a"}, offset=x-1)} for
+ * any x.
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UpperBoundUnknown.class)
+public @interface LTEqLengthOf {
+  /** Sequences, each of which is at least as long as the annotated expression's value. */
+  @JavaExpression
+  public String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LTLengthOf.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LTLengthOf.java
new file mode 100644
index 0000000..770e19a
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LTLengthOf.java
@@ -0,0 +1,52 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.JavaExpression;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The annotated expression evaluates to an integer whose value is less than the lengths of all the
+ * given sequences. This annotation is rarely used; it is more common to use {@code @}{@link
+ * IndexFor}.
+ *
+ * <p>For example, an expression with type {@code @LTLengthOf({"a", "b"})} is less than both {@code
+ * a.length} and {@code b.length}. The sequences {@code a} and {@code b} might have different
+ * lengths.
+ *
+ * <p>The {@code @LTLengthOf} annotation takes an optional {@code offset} element. If it is
+ * nonempty, then the annotated expression plus the expression in {@code offset[i]} is less than the
+ * length of the sequence specified by {@code value[i]}.
+ *
+ * <p>For example, suppose expression {@code e} has type {@code @LTLengthOf(value = {"a", "b"},
+ * offset = {"-1", "x"})}. Then {@code e - 1} is less than {@code a.length}, and {@code e + x} is
+ * less than {@code b.length}.
+ *
+ * <p>It is an error to write a {@code LTLengthOf} annotation with a different number of sequences
+ * and offsets, if an offset is included.
+ *
+ * @see IndexFor
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(LTEqLengthOf.class)
+public @interface LTLengthOf {
+  /** Sequences, each of which is longer than the annotated expression's value. */
+  @JavaExpression
+  public String[] value();
+
+  /**
+   * This expression plus the annotated expression is less than the length of the sequence. The
+   * {@code offset} element must ether be empty or the same length as {@code value}.
+   *
+   * <p>The expressions in {@code offset} may be addition/subtraction of any number of Java
+   * expressions. For example, {@code @LessThanLengthOf(value = "a", offset = "x + y + 2"}}.
+   */
+  @JavaExpression
+  String[] offset() default {};
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LTOMLengthOf.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LTOMLengthOf.java
new file mode 100644
index 0000000..43a545d
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LTOMLengthOf.java
@@ -0,0 +1,38 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.JavaExpression;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The annotated expression evaluates to an integer whose value is at least 2 less than the lengths
+ * of all the given sequences.
+ *
+ * <p>For example, an expression with type {@code @LTLengthOf({"a", "b"})} is less than or equal to
+ * both {@code a.length-2} and {@code b.length-2}. Equivalently, it is less than both {@code
+ * a.length-1} and {@code b.length-1}. The sequences {@code a} and {@code b} might have different
+ * lengths.
+ *
+ * <p>In the annotation's name, "LTOM" stands for "less than one minus".
+ *
+ * <p>{@code @LTOMLengthOf({"a"})} = {@code @LTLengthOf(value={"a"}, offset=1)}, and<br>
+ * {@code @LTOMLengthOf(value={"a"}, offset=x)} = {@code @LTLengthOf(value={"a"}, offset=x+1)} for
+ * any x.
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(LTLengthOf.class)
+public @interface LTOMLengthOf {
+  /**
+   * Sequences, each of whose lengths is at least 1 larger than the annotated expression's value.
+   */
+  @JavaExpression
+  public String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LengthOf.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LengthOf.java
new file mode 100644
index 0000000..53adb1a
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LengthOf.java
@@ -0,0 +1,34 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An integer that, for each of the given sequences, is equal to the sequence's length.
+ *
+ * <p>This is treated as an {@link IndexOrHigh} annotation internally. This is an implementation
+ * detail that may change in the future, when this type may be used to implement more precise
+ * refinements.
+ *
+ * <p>The usual use case for the {@code LengthOf} annotation is in the defintions of custom
+ * collections. Consider the signature of java.lang.String#length():
+ *
+ * <pre>
+ *
+ *     {@code public @LengthOf("this") int length()}
+ * </pre>
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+// Has target of METHOD so that it is stored as a declaration annotation and the SameLen Checker can
+// read it.
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER, ElementType.METHOD})
+public @interface LengthOf {
+  /** Sequences that the annotated expression is equal to the length of. */
+  String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LessThan.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LessThan.java
new file mode 100644
index 0000000..8bcc1ba
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LessThan.java
@@ -0,0 +1,48 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.JavaExpression;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An annotation indicating the relationship between values with a byte, short, char, int, or long
+ * type.
+ *
+ * <p>If an expression's type has this annotation, then at run time, the expression evaluates to a
+ * value that is less than the value of the expression in the annotation.
+ *
+ * <p>{@code @LessThan("end + 1")} is equivalent to {@code @LessThanOrEqual("end")}.
+ *
+ * <p>Subtyping:
+ *
+ * <ul>
+ *   <li>{@code @LessThan({"a", "b"}) <: @LessThan({"a"})}
+ *   <li>{@code @LessThan({"a", "b"})} is not related to {@code @LessThan({"a", "c"})}.
+ * </ul>
+ *
+ * @checker_framework.manual #index-inequalities Index Chceker Inequalities
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+@SubtypeOf({LessThanUnknown.class})
+// TODO: I chose to implement less than rather than greater than because in most of the case studies
+// false positives, the bigger value is final or effectively final, so it can appear in a dependent
+// annotation without causing soundness issues.
+public @interface LessThan {
+  /**
+   * The annotated expression's value is less than this expression.
+   *
+   * <p>The expressions in {@code value} may be addition/subtraction of any number of Java
+   * expressions. For example, {@code @LessThan(value = "x + y + 2"}}.
+   *
+   * <p>The expression in {@code value} must be final or constant or the addition/subtract of final
+   * or constant expressions.
+   */
+  @JavaExpression
+  String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LessThanBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LessThanBottom.java
new file mode 100644
index 0000000..422f87e
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LessThanBottom.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The bottom type in the LessThan type system. Programmers should rarely write this type.
+ *
+ * @checker_framework.manual #index-inequalities Index Chceker Inequalities
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+@SubtypeOf({LessThan.class})
+public @interface LessThanBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LessThanUnknown.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LessThanUnknown.java
new file mode 100644
index 0000000..3b456c3
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LessThanUnknown.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The top qualifier for the LessThan type hierarchy. It indicates that no other expression is known
+ * to be larger than the annotated one.
+ *
+ * @checker_framework.manual #index-inequalities Index Chceker Inequalities
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface LessThanUnknown {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LowerBoundBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LowerBoundBottom.java
new file mode 100644
index 0000000..3cfe92b
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LowerBoundBottom.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type of the lower bound type system. A variable annotated with this value cannot take
+ * on any integer values.
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@SubtypeOf({Positive.class})
+public @interface LowerBoundBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LowerBoundUnknown.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LowerBoundUnknown.java
new file mode 100644
index 0000000..f9c9031
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/LowerBoundUnknown.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The annotated expression evaluates to value that might be -2 or lower. This is the top type for
+ * the Lower Bound type system. It should not have to be written by a programmer.
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface LowerBoundUnknown {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/NegativeIndexFor.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/NegativeIndexFor.java
new file mode 100644
index 0000000..2fd92db
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/NegativeIndexFor.java
@@ -0,0 +1,43 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.JavaExpression;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The annotated expression is between {@code -1} and {@code -a.length - 1}, inclusive, for each
+ * sequence {@code a} listed in the annotation.
+ *
+ * <p>This type should rarely (if ever) be written by programmers. It is inferred by the
+ * SearchIndexChecker when the result of a call to one of the JDK's binary search methods (like
+ * {@code Arrays.binarySearch}) is known to be less than zero. For example, consider the following
+ * code:
+ *
+ * <pre>
+ *
+ *     int index = Arrays.binarySearch(array, target);
+ *     if (index &#60; 0) {
+ *          // index's type here is &#64;NegativeIndexFor("array")
+ *          index = index * -1;
+ *          // now index's type is &#64;IndexFor("array")
+ *     }
+ * </pre>
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(SearchIndexFor.class)
+public @interface NegativeIndexFor {
+  /**
+   * Sequences for which this value is a "negative index"; that is, the expression is in the range
+   * {@code -1} to {@code -a.length - 1}, inclusive, for each sequence {@code a} given here.
+   */
+  @JavaExpression
+  public String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/NonNegative.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/NonNegative.java
new file mode 100644
index 0000000..40806f1
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/NonNegative.java
@@ -0,0 +1,26 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The annotated expression evaluates to an integer greater than or equal to 0.
+ *
+ * <p>Consider the following example, from a collection that wraps an array. This constructor
+ * creates the {@code delegate} array, which must have a non-negative size.
+ *
+ * <pre>{@code
+ * ArrayWrapper(@NonNegative int size) { delegate = new Object[size]; }
+ * }</pre>
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({GTENegativeOne.class})
+public @interface NonNegative {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/PolyIndex.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/PolyIndex.java
new file mode 100644
index 0000000..fa5c811
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/PolyIndex.java
@@ -0,0 +1,27 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * A polymorphic qualifier for the Lower Bound and Upper Bound type systems.
+ *
+ * <p>Writing {@code @PolyIndex} is equivalent to writing {@link PolyUpperBound @PolyUpperBound}
+ * {@link PolyLowerBound @PolyLowerBound}, and that is how it is treated internally by the checker.
+ * Thus, if you write an {@code @PolyIndex} annotation, you might see warnings about
+ * {@code @PolyUpperBound} or {@code @PolyLowerBound}.
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ * @see PolyUpperBound
+ * @see PolyLowerBound
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier(UpperBoundUnknown.class)
+public @interface PolyIndex {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/PolyLength.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/PolyLength.java
new file mode 100644
index 0000000..4d51237
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/PolyLength.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * Syntactic sugar for both @PolyValue and @PolySameLen.
+ *
+ * @see org.checkerframework.common.value.qual.PolyValue
+ * @see PolySameLen
+ * @checker_framework.manual #index-checker Index Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier(UpperBoundUnknown.class)
+public @interface PolyLength {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/PolyLowerBound.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/PolyLowerBound.java
new file mode 100644
index 0000000..824609a
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/PolyLowerBound.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * A polymorphic qualifier for the Lower Bound type system.
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier(LowerBoundUnknown.class)
+public @interface PolyLowerBound {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/PolySameLen.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/PolySameLen.java
new file mode 100644
index 0000000..89e7fc4
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/PolySameLen.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * A polymorphic qualifier for the SameLen type system.
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier(SameLenUnknown.class)
+public @interface PolySameLen {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/PolyUpperBound.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/PolyUpperBound.java
new file mode 100644
index 0000000..c8eaa92
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/PolyUpperBound.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * A polymorphic qualifier for the Upper Bound type system.
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier(UpperBoundUnknown.class)
+public @interface PolyUpperBound {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/Positive.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/Positive.java
new file mode 100644
index 0000000..7321a02
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/Positive.java
@@ -0,0 +1,30 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The annotated expression evaluates to an integer greater than or equal to 1.
+ *
+ * <p>As an example of a use-case for this type, consider the following code:
+ *
+ * <pre>{@code
+ * if (arr.length > 0) {
+ *    int j = arr[arr.length - 1];
+ * }
+ * }</pre>
+ *
+ * Without the knowing that {@code arr.length} is positive, the Index Checker cannot verify that
+ * accessing the last element of the array is safe - there might not be a last element!
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({NonNegative.class})
+public @interface Positive {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SameLen.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SameLen.java
new file mode 100644
index 0000000..db65d59
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SameLen.java
@@ -0,0 +1,26 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.JavaExpression;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An expression whose type has this annotation evaluates to a value that is a sequence, and that
+ * sequence has the same length as the given sequences. For example, if {@code b}'s type is
+ * annotated with {@code @SameLen("a")}, then {@code a} and {@code b} have the same length.
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(SameLenUnknown.class)
+public @interface SameLen {
+  /** A list of other sequences with the same length. */
+  @JavaExpression
+  String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SameLenBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SameLenBottom.java
new file mode 100644
index 0000000..df9b82b
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SameLenBottom.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the SameLen type system. Programmers should rarely write this type.
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@SubtypeOf(SameLen.class)
+public @interface SameLenBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SameLenUnknown.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SameLenUnknown.java
new file mode 100644
index 0000000..f090c95
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SameLenUnknown.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * This type represents any variable that isn't known to have the same length as another sequence.
+ * This is the top type of the Same Length type system. Programmers should not need to write this
+ * type.
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface SameLenUnknown {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SearchIndexBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SearchIndexBottom.java
new file mode 100644
index 0000000..54ac9eb
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SearchIndexBottom.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the Search Index type system. Programmers should rarely write this type.
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@SubtypeOf(NegativeIndexFor.class)
+public @interface SearchIndexBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SearchIndexFor.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SearchIndexFor.java
new file mode 100644
index 0000000..e53499a
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SearchIndexFor.java
@@ -0,0 +1,31 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.JavaExpression;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The annotated expression evaluates to an integer whose length is between {@code -a.length - 1}
+ * and {@code a.length - 1}, inclusive, for all sequences {@code a} listed in the annotation.
+ *
+ * <p>This is the return type of {@link java.util.Arrays#binarySearch(Object[],Object) {@code
+ * Arrays.binarySearch}} in the JDK.
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(SearchIndexUnknown.class)
+public @interface SearchIndexFor {
+  /**
+   * Sequences for which the annotated expression has the type of the result of a call to {@link
+   * java.util.Arrays#binarySearch(Object[],Object) {@code Arrays.binarySearch}}.
+   */
+  @JavaExpression
+  public String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SearchIndexUnknown.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SearchIndexUnknown.java
new file mode 100644
index 0000000..75bc343
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SearchIndexUnknown.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The top type for the SearchIndex type system. This indicates that the Index checker does not know
+ * any arrays that this integer is a {@link SearchIndexFor search index} for.
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface SearchIndexUnknown {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SubstringIndexBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SubstringIndexBottom.java
new file mode 100644
index 0000000..797aea4
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SubstringIndexBottom.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the Substring Index type system. Programmers should rarely write this type.
+ *
+ * @checker_framework.manual #index-substringindex Index Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@SubtypeOf(SubstringIndexFor.class)
+public @interface SubstringIndexBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SubstringIndexFor.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SubstringIndexFor.java
new file mode 100644
index 0000000..235d0fa
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SubstringIndexFor.java
@@ -0,0 +1,58 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.JavaExpression;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The annotated expression evaluates to either -1 or a non-negative integer less than the lengths
+ * of all the given sequences. The annotation {@code @SubstringIndexFor(args)} is like <code>
+ * {@literal @}{@link NonNegative} {@literal @}{@link LTLengthOf}(args)</code>, except that
+ * {@code @SubstringIndexFor(args)} additionally permits the value -1.
+ *
+ * <p>When multiple values or offsets are given, they are considered pairwise. For example,
+ * {@code @SubstringIndexFor(value={"a", "b"}, offset={"c", "d"})} is equivalent to writing both
+ * {@code @SubstringIndexFor(value="a", offset="c")} and {@code @SubstringIndexFor(value="b",
+ * offset="d")}.
+ *
+ * <p>The return types of JDK methods {@link java.lang.String#indexOf(String) String.indexOf} and
+ * {@link java.lang.String#lastIndexOf(String) String.lastIndexOf} are annotated
+ * {@code @SubstringIndexFor(value="this",offset="#1.length()-1")}. This means that the returned
+ * value is either -1 or it is less than or equal to the length of the receiver sequence minus the
+ * length of the sequence passed as the first argument.
+ *
+ * <p>The name of this annotation, "substring index for", is intended to mean that the annotated
+ * expression is a index of a substring (returned by {@code indexOf} or similar methods) for the
+ * specified sequence.
+ *
+ * @checker_framework.manual #index-substringindex Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(SubstringIndexUnknown.class)
+public @interface SubstringIndexFor {
+  /**
+   * Sequences, each of which is longer than the annotated expression plus the corresponding {@code
+   * offset}. (Exception: the annotated expression is also allowed to have the value -1.)
+   */
+  @JavaExpression
+  public String[] value();
+
+  /**
+   * This expression plus the annotated expression is less than the length of the corresponding
+   * sequence in the {@code value} array. (Exception: the annotated expression is also allowed to
+   * have the value -1.)
+   *
+   * <p>The {@code offset} array must either be empty or the same length as {@code value}.
+   *
+   * <p>The expressions in {@code offset} may be addition/subtraction of any number of Java
+   * expressions. For example, {@code @SubstringIndexFor(value = "a", offset = "b.length() - 1")}.
+   */
+  @JavaExpression
+  public String[] offset();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SubstringIndexUnknown.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SubstringIndexUnknown.java
new file mode 100644
index 0000000..94c4480
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/SubstringIndexUnknown.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The top type for the Substring Index type system. This indicates that the Index Checker does not
+ * know any sequences that this integer is a {@link SubstringIndexFor substring index} for.
+ *
+ * @checker_framework.manual #index-substringindex Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface SubstringIndexUnknown {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/UpperBoundBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/UpperBoundBottom.java
new file mode 100644
index 0000000..ed231a1
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/UpperBoundBottom.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the Upper Bound type system. Programmers should rarely write this type.
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@SubtypeOf({LTOMLengthOf.class, UpperBoundLiteral.class})
+public @interface UpperBoundBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/UpperBoundLiteral.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/UpperBoundLiteral.java
new file mode 100644
index 0000000..9a0ef13
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/UpperBoundLiteral.java
@@ -0,0 +1,30 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * A literal value. Programmers should rarely write this type.
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@SubtypeOf(LTEqLengthOf.class)
+public @interface UpperBoundLiteral {
+
+  /**
+   * Returns the value of the literal.
+   *
+   * @return the value of the literal
+   */
+  int value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/index/qual/UpperBoundUnknown.java b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/UpperBoundUnknown.java
new file mode 100644
index 0000000..8548028
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/index/qual/UpperBoundUnknown.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.index.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * A variable not known to have a relation to any sequence length. This is the top type of the Upper
+ * Bound type system. Programmers should not need to write this type.
+ *
+ * @checker_framework.manual #index-checker Index Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface UpperBoundUnknown {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/initialization/qual/FBCBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/initialization/qual/FBCBottom.java
new file mode 100644
index 0000000..5be6737
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/initialization/qual/FBCBottom.java
@@ -0,0 +1,29 @@
+package org.checkerframework.checker.initialization.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.LiteralKind;
+import org.checkerframework.framework.qual.QualifierForLiterals;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the initialization type system. Programmers should rarely write this type.
+ *
+ * <p>The "FBC" in the name stands for "Freedom Before Commitment", an approach that the
+ * Initialization Checker builds upon.
+ *
+ * @checker_framework.manual #initialization-checker Initialization Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@SubtypeOf({UnderInitialization.class, Initialized.class})
+@QualifierForLiterals(LiteralKind.NULL)
+public @interface FBCBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/initialization/qual/Initialized.java b/checker-qual/src/main/java/org/checkerframework/checker/initialization/qual/Initialized.java
new file mode 100644
index 0000000..cac3fc8
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/initialization/qual/Initialized.java
@@ -0,0 +1,36 @@
+package org.checkerframework.checker.initialization.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * This type qualifier belongs to the freedom-before-commitment initialization tracking type-system.
+ * This type-system is not used on its own, but in conjunction with some other type-system that
+ * wants to ensure safe initialization. For instance, {@link
+ * org.checkerframework.checker.nullness.NullnessChecker} uses freedom-before-commitment to track
+ * initialization of {@link NonNull} fields.
+ *
+ * <p>This type qualifier indicates that the object has been fully initialized; reading fields from
+ * such objects is fully safe and yields objects of the correct type.
+ *
+ * @checker_framework.manual #initialization-checker Initialization Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownInitialization.class)
+@DefaultQualifierInHierarchy
+@DefaultFor({
+  TypeUseLocation.IMPLICIT_UPPER_BOUND,
+  TypeUseLocation.IMPLICIT_LOWER_BOUND,
+  TypeUseLocation.EXCEPTION_PARAMETER
+})
+public @interface Initialized {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/initialization/qual/NotOnlyInitialized.java b/checker-qual/src/main/java/org/checkerframework/checker/initialization/qual/NotOnlyInitialized.java
new file mode 100644
index 0000000..89dc52e
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/initialization/qual/NotOnlyInitialized.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.initialization.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A declaration annotation for fields that indicates that a client might observe the field storing
+ * values that are {@link org.checkerframework.checker.initialization.qual.Initialized}, {@link
+ * org.checkerframework.checker.initialization.qual.UnderInitialization}, or {@link
+ * org.checkerframework.checker.initialization.qual.UnknownInitialization}, regardless of the
+ * initialization type annotation on the field's type. This is necessary to allow circular
+ * initialization as supported by freedom-before-commitment.
+ *
+ * @checker_framework.manual #initialization-checker Initialization Checker
+ */
+@Documented
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface NotOnlyInitialized {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/initialization/qual/UnderInitialization.java b/checker-qual/src/main/java/org/checkerframework/checker/initialization/qual/UnderInitialization.java
new file mode 100644
index 0000000..5f3c43e
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/initialization/qual/UnderInitialization.java
@@ -0,0 +1,52 @@
+package org.checkerframework.checker.initialization.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * This type qualifier indicates that an object is (definitely) in the process of being
+ * constructed/initialized. The type qualifier also indicates how much of the object has already
+ * been initialized. Please see the manual for examples of how to use the annotation (the link
+ * appears below).
+ *
+ * <p>Consider a class {@code B} that is a subtype of {@code A}. At the beginning of the constructor
+ * of {@code B}, {@code this} has the type {@code @UnderInitialization(A.class)}, since all fields
+ * of {@code A} have been initialized by the super-constructor. Inside the constructor body, as soon
+ * as all fields of {@code B} are initialized, then the type of {@code this} changes to
+ * {@code @UnderInitialization(B.class)}.
+ *
+ * <p>Code is allowed to store potentially not-fully-initialized objects in the fields of a
+ * partially-initialized object, as long as all initialization is complete by the end of the
+ * constructor.
+ *
+ * <p>What type qualifiers on the field are considered depends on the checker; for instance, the
+ * {@link org.checkerframework.checker.nullness.NullnessChecker} considers {@link NonNull}. The
+ * initialization type system is not used on its own, but in conjunction with some other type-system
+ * that wants to ensure safe initialization.
+ *
+ * <p>When an expression has type {@code @UnderInitialization}, then no aliases that are typed
+ * differently may exist.
+ *
+ * @checker_framework.manual #initialization-checker Initialization Checker
+ * @checker_framework.manual #underinitialization-examples Examples of the @UnderInitialization
+ *     annotation
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownInitialization.class)
+public @interface UnderInitialization {
+  /**
+   * The type-frame down to which the expression (of this type) has been initialized at least
+   * (inclusive). That is, an expression of type {@code @UnderInitialization(T.class)} has all
+   * type-frames initialized starting at {@code Object} down to (and including) {@code T}.
+   *
+   * @return the type whose fields are fully initialized
+   */
+  Class<?> value() default Object.class;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/initialization/qual/UnknownInitialization.java b/checker-qual/src/main/java/org/checkerframework/checker/initialization/qual/UnknownInitialization.java
new file mode 100644
index 0000000..42015af
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/initialization/qual/UnknownInitialization.java
@@ -0,0 +1,53 @@
+package org.checkerframework.checker.initialization.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * This type qualifier indicates how much of an object has been fully initialized. An object is
+ * fully initialized when each of its fields contains a value that satisfies the field's
+ * declaration.
+ *
+ * <p>An expression of type {@code @UnknownInitialization(T.class)} refers to an object that has all
+ * fields of {@code T} (and any super-classes) initialized. Just {@code @UnknownInitialization} is
+ * equivalent to {@code @UnknownInitialization(Object.class)}. Please see the manual for examples of
+ * how to use the annotation (the link appears below).
+ *
+ * <p>Reading a field of an object of type {@code @UnknownInitialization} might yield a value that
+ * does not correspond to the declared type qualifier for that field. For instance, consider a
+ * non-null field:
+ *
+ * <pre>@NonNull Object f;</pre>
+ *
+ * In a partially-initialized object, field {@code f} might be {@code null} despite its
+ * {@literal @}{@link NonNull} type annotation.
+ *
+ * <p>What type qualifiers on the field are considered depends on the checker; for instance, the
+ * {@link org.checkerframework.checker.nullness.NullnessChecker} considers {@link NonNull}. The
+ * initialization type system is not used on its own, but in conjunction with some other type-system
+ * that wants to ensure safe initialization.
+ *
+ * @checker_framework.manual #initialization-checker Initialization Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({})
+@DefaultFor({TypeUseLocation.LOCAL_VARIABLE, TypeUseLocation.RESOURCE_VARIABLE})
+public @interface UnknownInitialization {
+  /**
+   * The type-frame down to which the expression (of this type) has been initialized at least
+   * (inclusive). That is, an expression of type {@code @UnknownInitialization(T.class)} has all
+   * type-frames initialized starting at {@code Object} down to (and including) {@code T}.
+   *
+   * @return the type whose fields are fully initialized
+   */
+  Class<?> value() default Object.class;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/CompareToMethod.java b/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/CompareToMethod.java
new file mode 100644
index 0000000..8fc5212
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/CompareToMethod.java
@@ -0,0 +1,21 @@
+package org.checkerframework.checker.interning.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.InheritedAnnotation;
+
+/**
+ * Method declaration annotation that indicates a method has a specification like {@code
+ * compareTo()} or {@code compare()}. The Interning Checker permits use of {@code if (this == arg) {
+ * return 0; }} or {@code if (arg1 == arg2) { return 0; }} within the body.
+ *
+ * @checker_framework.manual #interning-checker Interning Checker
+ */
+@Documented
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@InheritedAnnotation
+public @interface CompareToMethod {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/EqualsMethod.java b/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/EqualsMethod.java
new file mode 100644
index 0000000..727024e
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/EqualsMethod.java
@@ -0,0 +1,21 @@
+package org.checkerframework.checker.interning.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.InheritedAnnotation;
+
+/**
+ * Method declaration annotation that indicates a method has a specification like {@code equals()}.
+ * The Interning Checker permits use of {@code this == arg} within the body. Can also be applied to
+ * a static two-argument method, in which case {@code arg1 == arg2} is permitted within the body.
+ *
+ * @checker_framework.manual #interning-checker Interning Checker
+ */
+@Documented
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@InheritedAnnotation
+public @interface EqualsMethod {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/FindDistinct.java b/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/FindDistinct.java
new file mode 100644
index 0000000..adda1fa
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/FindDistinct.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.interning.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This formal parameter annotation indicates that the method searches for the given value, using
+ * reference equality ({@code ==}).
+ *
+ * <p>Within the method, the formal parameter should be compared with {@code ==} rather than with
+ * {@code equals()}. However, any value may be passed to the method, and the Interning Checker does
+ * not verify that use of {@code ==} within the method is logically correct.
+ *
+ * @see org.checkerframework.checker.interning.InterningChecker
+ * @checker_framework.manual #interning-checker Interning Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface FindDistinct {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/InternMethod.java b/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/InternMethod.java
new file mode 100644
index 0000000..9157a72
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/InternMethod.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.interning.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.InheritedAnnotation;
+
+/**
+ * Method declaration annotation used to indicate that this method may be invoked on an uninterned
+ * object and that it returns an interned object.
+ *
+ * @checker_framework.manual #interning-checker Interning Checker
+ */
+@Documented
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@InheritedAnnotation
+public @interface InternMethod {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/Interned.java b/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/Interned.java
new file mode 100644
index 0000000..876bd79
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/Interned.java
@@ -0,0 +1,46 @@
+package org.checkerframework.checker.interning.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.LiteralKind;
+import org.checkerframework.framework.qual.QualifierForLiterals;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TypeKind;
+
+/**
+ * Indicates that a variable has been interned, i.e., that the variable refers to the canonical
+ * representation of an object.
+ *
+ * <p>To specify that all objects of a given type are interned, annotate the class declaration:
+ *
+ * <pre>
+ *   public @Interned class MyInternedClass { ... }
+ * </pre>
+ *
+ * This is equivalent to annotating every use of MyInternedClass, in a declaration or elsewhere. For
+ * example, enum classes are implicitly so annotated.
+ *
+ * @see org.checkerframework.checker.interning.InterningChecker
+ * @checker_framework.manual #interning-checker Interning Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownInterned.class)
+@QualifierForLiterals({LiteralKind.PRIMITIVE, LiteralKind.STRING}) // everything but NULL
+@DefaultFor(
+    typeKinds = {
+      TypeKind.BOOLEAN,
+      TypeKind.BYTE,
+      TypeKind.CHAR,
+      TypeKind.DOUBLE,
+      TypeKind.FLOAT,
+      TypeKind.INT,
+      TypeKind.LONG,
+      TypeKind.SHORT
+    })
+public @interface Interned {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/InternedDistinct.java b/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/InternedDistinct.java
new file mode 100644
index 0000000..c1e7fb5
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/InternedDistinct.java
@@ -0,0 +1,29 @@
+package org.checkerframework.checker.interning.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * Indicates that no other value is {@code equals()} to the given value. Therefore, it is correct to
+ * use == to test an InternedDistinct value for equality against any other value.
+ *
+ * <p>This is a stronger property than {@link Interned}, but a weaker property than every value of a
+ * Java type being interned.
+ *
+ * <p>This annotation is trusted, not verified.
+ *
+ * @see org.checkerframework.checker.interning.InterningChecker
+ * @checker_framework.manual #interning-checker Interning Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Interned.class)
+@DefaultFor(value = {TypeUseLocation.LOWER_BOUND})
+public @interface InternedDistinct {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/PolyInterned.java b/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/PolyInterned.java
new file mode 100644
index 0000000..fb657e4
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/PolyInterned.java
@@ -0,0 +1,24 @@
+package org.checkerframework.checker.interning.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * A polymorphic qualifier for the Interning type system.
+ *
+ * <p>Any method written using @PolyInterned conceptually has two versions: one in which every
+ * instance of @PolyInterned has been replaced by @Interned, and one in which every instance
+ * of @PolyInterned has been erased.
+ *
+ * @checker_framework.manual #interning-checker Interning Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier(UnknownInterned.class)
+public @interface PolyInterned {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/UnknownInterned.java b/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/UnknownInterned.java
new file mode 100644
index 0000000..c1a8b79
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/UnknownInterned.java
@@ -0,0 +1,25 @@
+package org.checkerframework.checker.interning.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The top qualifier for the Interning Checker. It indicates lack of knowledge about whether values
+ * are interned or not. It is not written by programmers, but is used internally by the type system.
+ *
+ * @see org.checkerframework.checker.interning.InterningChecker
+ * @checker_framework.manual #interning-checker Interning Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@InvisibleQualifier
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface UnknownInterned {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/UsesObjectEquals.java b/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/UsesObjectEquals.java
new file mode 100644
index 0000000..003e3cd
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/interning/qual/UsesObjectEquals.java
@@ -0,0 +1,25 @@
+package org.checkerframework.checker.interning.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Class declaration to indicate the class does not override {@code equals(Object)}, and therefore
+ * {@code a.equals(b)} and {@code a == b} behave identically.
+ *
+ * <p>A class may be annotated @UsesObjectEquals if neither it, nor any of its supertypes or
+ * subtypes, overrides {@code equals}. Therefore, it cannot be written on {@code Object} itself. It
+ * is most commonly written on a direct subclass of {@code Object}.
+ *
+ * @see org.checkerframework.checker.interning.InterningChecker
+ * @checker_framework.manual #interning-checker Interning Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Inherited
+public @interface UsesObjectEquals {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/EnsuresLockHeld.java b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/EnsuresLockHeld.java
new file mode 100644
index 0000000..262a9ee
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/EnsuresLockHeld.java
@@ -0,0 +1,56 @@
+package org.checkerframework.checker.lock.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.InheritedAnnotation;
+import org.checkerframework.framework.qual.PostconditionAnnotation;
+
+/**
+ * Indicates that the given expressions are held if the method terminates successfully.
+ *
+ * @see EnsuresLockHeldIf
+ * @checker_framework.manual #lock-checker Lock Checker
+ * @checker_framework.manual #ensureslockheld-examples Example use of @EnsuresLockHeld
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+@PostconditionAnnotation(qualifier = LockHeld.class)
+@InheritedAnnotation
+@Repeatable(EnsuresLockHeld.List.class)
+public @interface EnsuresLockHeld {
+  /**
+   * Returns Java expressions whose values are locks that are held after successful method
+   * termination.
+   *
+   * @return Java expressions whose values are locks that are held after successful method
+   *     termination
+   * @see <a href="https://checkerframework.org/manual/#java-expressions-as-arguments">Syntax of
+   *     Java expressions</a>
+   */
+  String[] value();
+
+  /**
+   * A wrapper annotation that makes the {@link EnsuresLockHeld} annotation repeatable.
+   *
+   * <p>Programmers generally do not need to write this. It is created by Java when a programmer
+   * writes more than one {@link EnsuresLockHeld} annotation at the same location.
+   */
+  @Documented
+  @Retention(RetentionPolicy.RUNTIME)
+  @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+  @PostconditionAnnotation(qualifier = LockHeld.class)
+  @InheritedAnnotation
+  @interface List {
+    /**
+     * Return the repeatable annotations.
+     *
+     * @return the repeatable annotations
+     */
+    EnsuresLockHeld[] value();
+  }
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/EnsuresLockHeldIf.java b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/EnsuresLockHeldIf.java
new file mode 100644
index 0000000..b9f9c20
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/EnsuresLockHeldIf.java
@@ -0,0 +1,67 @@
+package org.checkerframework.checker.lock.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.ConditionalPostconditionAnnotation;
+import org.checkerframework.framework.qual.InheritedAnnotation;
+
+/**
+ * Indicates that the given expressions are held if the method terminates successfully and returns
+ * the given result (either true or false).
+ *
+ * @see EnsuresLockHeld
+ * @checker_framework.manual #lock-checker Lock Checker
+ * @checker_framework.manual #ensureslockheld-examples Example use of @EnsuresLockHeldIf
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+@ConditionalPostconditionAnnotation(qualifier = LockHeld.class)
+@InheritedAnnotation
+@Repeatable(EnsuresLockHeldIf.List.class)
+public @interface EnsuresLockHeldIf {
+  /**
+   * Returns Java expressions whose values are locks that are held after the method returns the
+   * given result.
+   *
+   * @return Java expressions whose values are locks that are held after the method returns the
+   *     given result
+   * @see <a href="https://checkerframework.org/manual/#java-expressions-as-arguments">Syntax of
+   *     Java expressions</a>
+   */
+  // It would be clearer for users if this field were named "lock".
+  // However, method ContractsFromMethod.getConditionalPostconditions in the CF implementation
+  // assumes that conditional postconditions have a field named "expression".
+  String[] expression();
+
+  /**
+   * Returns the return value of the method under which the postconditions hold.
+   *
+   * @return the return value of the method under which the postconditions hold
+   */
+  boolean result();
+
+  /**
+   * A wrapper annotation that makes the {@link EnsuresLockHeldIf} annotation repeatable.
+   *
+   * <p>Programmers generally do not need to write this. It is created by Java when a programmer
+   * writes more than one {@link EnsuresLockHeldIf} annotation at the same location.
+   */
+  @Documented
+  @Retention(RetentionPolicy.RUNTIME)
+  @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+  @ConditionalPostconditionAnnotation(qualifier = LockHeld.class)
+  @InheritedAnnotation
+  @interface List {
+    /**
+     * Return the repeatable annotations.
+     *
+     * @return the repeatable annotations
+     */
+    EnsuresLockHeldIf[] value();
+  }
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/GuardSatisfied.java b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/GuardSatisfied.java
new file mode 100644
index 0000000..711ae16
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/GuardSatisfied.java
@@ -0,0 +1,43 @@
+package org.checkerframework.checker.lock.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * If a variable {@code x} has type {@code @GuardSatisfied}, then all lock expressions for {@code
+ * x}'s value are held.
+ *
+ * <p>Written on a formal parameter (including the receiver), this annotation indicates that the
+ * {@literal @}{@link GuardedBy} type for the corresponding actual argument at the method call site
+ * is unknown at the method definition site, but any lock expressions that guard it are known to be
+ * held prior to the method call.
+ *
+ * <p>For example, the formal parameter of the String copy constructor, {@link String#String(String
+ * s)}, is annotated with {@code @GuardSatisfied}. This requires that all locks guarding the actual
+ * argument are held when the constructor is called. However, the definition of the constructor does
+ * not need to know what those locks are (and it cannot know, because the constructor can be called
+ * by arbitrary code).
+ *
+ * @see GuardedBy
+ * @see Holding
+ * @checker_framework.manual #lock-checker Lock Checker
+ * @checker_framework.manual #lock-checker-polymorphism-example Lock Checker polymorphism example
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE_USE)
+@TargetLocations({TypeUseLocation.RECEIVER, TypeUseLocation.PARAMETER, TypeUseLocation.RETURN})
+@SubtypeOf(GuardedByUnknown.class) // TODO: Should @GuardSatisfied be in its own hierarchy?
+public @interface GuardSatisfied {
+  /**
+   * The index on the GuardSatisfied polymorphic qualifier. Defaults to -1 so that the user can
+   * write any index starting from 0.
+   */
+  int value() default -1;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/GuardedBy.java b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/GuardedBy.java
new file mode 100644
index 0000000..e5bc9c9
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/GuardedBy.java
@@ -0,0 +1,78 @@
+package org.checkerframework.checker.lock.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.JavaExpression;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TypeKind;
+import org.checkerframework.framework.qual.TypeUseLocation;
+import org.checkerframework.framework.qual.UpperBoundFor;
+
+/**
+ * Indicates that a thread may dereference the value referred to by the annotated variable only if
+ * the thread holds all the given lock expressions.
+ *
+ * <p>{@code @GuardedBy({})} is the default type qualifier.
+ *
+ * <p>The argument is a string or set of strings that indicates the expression(s) that must be held,
+ * using the <a href="https://checkerframework.org/manual/#java-expressions-as-arguments">syntax of
+ * Java expressions</a> described in the manual. The expressions evaluate to an intrinsic (built-in,
+ * synchronization) monitor or an explicit {@link java.util.concurrent.locks.Lock}. The expression
+ * {@code "<self>"} is also permitted; the type {@code @GuardedBy("<self>") Object o} indicates that
+ * the value referenced by {@code o} is guarded by the intrinsic (monitor) lock of the value
+ * referenced by {@code o}.
+ *
+ * <p>Two {@code @GuardedBy} annotations with different argument expressions are unrelated by
+ * subtyping.
+ *
+ * @see Holding
+ * @checker_framework.manual #lock-checker Lock Checker
+ * @checker_framework.manual #lock-examples-guardedby Example use of @GuardedBy
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(GuardedByUnknown.class)
+@DefaultQualifierInHierarchy
+// These are required because the default for local variables is @GuardedByUnknown, but if the local
+// variable is one of these type kinds, the default should be @GuardedByUnknown.
+@DefaultFor(
+    value = {TypeUseLocation.EXCEPTION_PARAMETER, TypeUseLocation.UPPER_BOUND},
+    typeKinds = {
+      TypeKind.BOOLEAN,
+      TypeKind.BYTE,
+      TypeKind.CHAR,
+      TypeKind.DOUBLE,
+      TypeKind.FLOAT,
+      TypeKind.INT,
+      TypeKind.LONG,
+      TypeKind.SHORT
+    },
+    types = {String.class, Void.class})
+@UpperBoundFor(
+    typeKinds = {
+      TypeKind.BOOLEAN,
+      TypeKind.BYTE,
+      TypeKind.CHAR,
+      TypeKind.DOUBLE,
+      TypeKind.FLOAT,
+      TypeKind.INT,
+      TypeKind.LONG,
+      TypeKind.SHORT
+    },
+    types = String.class)
+public @interface GuardedBy {
+  /**
+   * The Java value expressions that need to be held.
+   *
+   * @see <a href="https://checkerframework.org/manual/#java-expressions-as-arguments">Syntax of
+   *     Java expressions</a>
+   */
+  @JavaExpression
+  String[] value() default {};
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/GuardedByBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/GuardedByBottom.java
new file mode 100644
index 0000000..91a66e3
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/GuardedByBottom.java
@@ -0,0 +1,26 @@
+package org.checkerframework.checker.lock.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the GuardedBy type system. Programmers should rarely write this type.
+ *
+ * <p>If a variable {@code x} has type {@code @GuardedByBottom}, then the value referred to by
+ * {@code x} is {@code null} (or dead code) and can never be dereferenced.
+ *
+ * @checker_framework.manual #lock-checker Lock Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@SubtypeOf({GuardedBy.class, GuardSatisfied.class})
+public @interface GuardedByBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/GuardedByUnknown.java b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/GuardedByUnknown.java
new file mode 100644
index 0000000..08def36
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/GuardedByUnknown.java
@@ -0,0 +1,24 @@
+package org.checkerframework.checker.lock.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * It is unknown what locks guard the value referred to by the annotated variable. Therefore, the
+ * value can never be dereferenced. The locks that guard it might not even be in scope (might be
+ * inaccessible) at the location where the {@code @GuardedByUnknown} annotation is written.
+ *
+ * <p>{@code @GuardedByUnknown} is the top of the GuardedBy qualifier hierarchy. Any value can be
+ * assigned into a variable of type {@code @GuardedByUnknown}.
+ *
+ * @checker_framework.manual #lock-checker Lock Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({})
+public @interface GuardedByUnknown {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/Holding.java b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/Holding.java
new file mode 100644
index 0000000..3a862ae
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/Holding.java
@@ -0,0 +1,35 @@
+package org.checkerframework.checker.lock.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PreconditionAnnotation;
+
+/**
+ * Indicates a method precondition: the specified expressions must be held when the annotated method
+ * is invoked.
+ *
+ * <p>The argument is a string or set of strings that indicates the expression(s) that must be held,
+ * using the <a href="https://checkerframework.org/manual/#java-expressions-as-arguments">syntax of
+ * Java expressions</a> described in the manual. The expressions evaluate to an intrinsic (built-in,
+ * synchronization) monitor, or an explicit {@link java.util.concurrent.locks.Lock}.
+ *
+ * @see GuardedBy
+ * @checker_framework.manual #lock-checker Lock Checker
+ * @checker_framework.manual #lock-examples-holding Example use of @Holding
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+@PreconditionAnnotation(qualifier = LockHeld.class)
+public @interface Holding {
+  /**
+   * The Java expressions that need to be held.
+   *
+   * @see <a href="https://checkerframework.org/manual/#java-expressions-as-arguments">Syntax of
+   *     Java expressions</a>
+   */
+  String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/LockHeld.java b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/LockHeld.java
new file mode 100644
index 0000000..d77d8c0
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/LockHeld.java
@@ -0,0 +1,25 @@
+package org.checkerframework.checker.lock.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Indicates that an expression is used as a lock and the lock is known to be held on the current
+ * thread.
+ *
+ * <p>This annotation may not be written in source code; it is an implementation detail of the
+ * checker.
+ *
+ * @see LockPossiblyHeld
+ * @checker_framework.manual #lock-checker Lock Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({})
+@SubtypeOf(LockPossiblyHeld.class) // This is the bottom type in this hierarchy
+@InvisibleQualifier
+public @interface LockHeld {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/LockPossiblyHeld.java b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/LockPossiblyHeld.java
new file mode 100644
index 0000000..f9216d7
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/LockPossiblyHeld.java
@@ -0,0 +1,32 @@
+package org.checkerframework.checker.lock.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.LiteralKind;
+import org.checkerframework.framework.qual.QualifierForLiterals;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * Indicates that an expression is not known to be {@link LockHeld}.
+ *
+ * <p>This annotation may not be written in source code; it is an implementation detail of the
+ * checker.
+ *
+ * @see LockHeld
+ * @checker_framework.manual #lock-checker Lock Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({})
+@InvisibleQualifier
+@SubtypeOf({}) // The top type in the hierarchy
+@DefaultQualifierInHierarchy
+@DefaultFor(value = TypeUseLocation.LOWER_BOUND, types = Void.class)
+@QualifierForLiterals(LiteralKind.NULL)
+public @interface LockPossiblyHeld {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/LockingFree.java b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/LockingFree.java
new file mode 100644
index 0000000..e9737ea
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/LockingFree.java
@@ -0,0 +1,32 @@
+package org.checkerframework.checker.lock.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.dataflow.qual.Pure;
+import org.checkerframework.dataflow.qual.SideEffectFree;
+import org.checkerframework.framework.qual.InheritedAnnotation;
+
+/**
+ * The method neither acquires nor releases locks, nor do any of the methods that it calls. More
+ * specifically, the method is not {@code synchronized}, it contains no {@code synchronized} blocks,
+ * it contains no calls to {@code lock} or {@code unlock}, and it contains no calls to other
+ * non-{@code @LockingFree} methods.
+ *
+ * <p>{@code @LockingFree} provides a stronger guarantee than {@code @}{@link ReleasesNoLocks} and a
+ * weaker guarantee than {@code @}{@link SideEffectFree}.
+ *
+ * @see MayReleaseLocks
+ * @see ReleasesNoLocks
+ * @see SideEffectFree
+ * @see Pure
+ * @checker_framework.manual #lock-checker Lock Checker
+ * @checker_framework.manual #lock-lockingfree-example Example use of @LockingFree
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+@InheritedAnnotation
+public @interface LockingFree {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/MayReleaseLocks.java b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/MayReleaseLocks.java
new file mode 100644
index 0000000..80742fa
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/MayReleaseLocks.java
@@ -0,0 +1,27 @@
+package org.checkerframework.checker.lock.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.InheritedAnnotation;
+
+/**
+ * The method, or one of the methods it calls, might release locks that were held prior to the
+ * method being called. You can write this when you are certain the method releases locks, or when
+ * you don't know whether the method releases locks.
+ *
+ * @see ReleasesNoLocks
+ * @see LockingFree
+ * @see org.checkerframework.dataflow.qual.SideEffectFree
+ * @see org.checkerframework.dataflow.qual.Pure
+ * @checker_framework.manual #lock-checker Lock Checker
+ * @checker_framework.manual #lock-lockingfree-example Example use of @MayReleaseLocks
+ * @checker_framework.manual #annotating-libraries Annotating libraries
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+@InheritedAnnotation
+public @interface MayReleaseLocks {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/PolyGuardedBy.java b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/PolyGuardedBy.java
new file mode 100644
index 0000000..a0ff940
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/PolyGuardedBy.java
@@ -0,0 +1,37 @@
+/*
+TODO: Implement the functionality for @PolyGuardedBy and uncomment this.
+
+package org.checkerframework.checker.lock.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * A polymorphic qualifier for the GuardedBy type system.
+ * Indicates that it is unknown what the guards are or whether they are held.
+ * An expression whose type is {@code @PolyGuardedBy} cannot be dereferenced.
+ * Hence, unlike for {@code @GuardSatisfied}, when an expression of type {@code @PolyGuardedBy}
+ * is the LHS of an assignment, the locks guarding the RHS do not need to be held.
+ *
+ * <p>Any method written using {@code @PolyGuardedBy} conceptually has an
+ * arbitrary number of versions:  one in which every instance of
+ * {@code @PolyGuardedBy} has been replaced by {@code @}{@link GuardedByUnknown},
+ * one in which every instance of {@code @PolyGuardedBy} has been
+ * replaced by {@code @}{@link GuardedByBottom}, and ones in which every
+ * instance of {@code @PolyGuardedBy} has been replaced by {@code @}{@link GuardedBy},
+ * for every possible combination of map arguments.
+ *
+ * @see GuardedBy
+ * @checker_framework.manual #lock-checker Lock Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+// @PolymorphicQualifier(GuardedByUnknown.class)
+// @Documented
+// @Retention(RetentionPolicy.RUNTIME)
+// @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+// public @interface PolyGuardedBy {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/ReleasesNoLocks.java b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/ReleasesNoLocks.java
new file mode 100644
index 0000000..dc43239
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/lock/qual/ReleasesNoLocks.java
@@ -0,0 +1,41 @@
+package org.checkerframework.checker.lock.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.dataflow.qual.Pure;
+import org.checkerframework.dataflow.qual.SideEffectFree;
+import org.checkerframework.framework.qual.InheritedAnnotation;
+
+/**
+ * The method maintains a strictly nondecreasing lock held count on the current thread for any locks
+ * that were held prior to the method call. The same property must in general be true of all the
+ * methods it calls, which should themselves be annotated as {@code @ReleasesNoLocks} or a stronger
+ * annotation such as {@code @}{@link SideEffectFree}.
+ *
+ * <p>The method might acquire locks but then release them, or might acquire locks but not release
+ * them (in which case it should also be annotated with {@literal @}{@link EnsuresLockHeld} or
+ * {@literal @}{@link EnsuresLockHeldIf}).
+ *
+ * <p>This is the default for methods being type-checked that have no {@code @}{@link LockingFree},
+ * {@code @}{@link MayReleaseLocks}, {@code @}{@link SideEffectFree}, or {@code @}{@link Pure}
+ * annotation.
+ *
+ * <p>{@code @ReleasesNoLocks} provides a guarantee unlike {@code @}{@link MayReleaseLocks}, which
+ * provides no guarantees. However, {@code @ReleasesNoLocks} provides a weaker guarantee than
+ * {@code @}{@link LockingFree}.
+ *
+ * @see MayReleaseLocks
+ * @see LockingFree
+ * @see SideEffectFree
+ * @see Pure
+ * @checker_framework.manual #lock-checker Lock Checker
+ * @checker_framework.manual #lock-lockingfree-example Example use of @ReleasesNoLocks
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+@InheritedAnnotation
+public @interface ReleasesNoLocks {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/CreatesObligation.java b/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/CreatesObligation.java
new file mode 100644
index 0000000..e933c20
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/CreatesObligation.java
@@ -0,0 +1,104 @@
+package org.checkerframework.checker.mustcall.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.checker.calledmethods.qual.CalledMethods;
+import org.checkerframework.framework.qual.InheritedAnnotation;
+import org.checkerframework.framework.qual.JavaExpression;
+
+/**
+ * Indicates that the method resets the target's must-call type to its declared type. This
+ * effectively undoes flow-sensitive type refinement. The target is the {@code value}
+ * argument/element. More precisely, the method resets the target's must-call type to the least
+ * upper bound of its current must-call type and its declared must-call type.
+ *
+ * <p>When calling a method annotated as {@code @CreatesObligation("}<em>target</em>{@code ")}, the
+ * expression {@code target} must not have type {@code @}{@link CalledMethods}{@code ({})}. That is,
+ * {@code target}'s CalledMethods type must be non-empty.
+ *
+ * <p>{@code @CreatesObligation("this")} must be written on any method that assigns a non-final,
+ * owning field whose declared type has a must-call obligation.
+ *
+ * <p>This annotation is trusted, not checked. (Because this annotation can only add obligations,
+ * the analysis remains sound.)
+ *
+ * <p>For example, consider the following code, which uses a {@code @CreatesObligation} annotation
+ * to indicate that the {@code reset()} method re-assigns the {@code socket} field:
+ *
+ * <pre>
+ * &#64;MustCall("stop")
+ * class SocketContainer {
+ *     // Note that @MustCall("close") is the default type for java.net.Socket, but it
+ *     // is included on the next line for illustrative purposes. This example would function
+ *     // identically if that qualifier were omitted.
+ *     private @Owning @MustCall("close") Socket socket = ...;
+ *
+ *     &#64;EnsuresCalledMethods(value="this.socket", methods="close")
+ *     public void stop() throws IOException {
+ *       socket.close();
+ *     }
+ *
+ *    &#64;CreatesObligation("this")
+ *    public void reset() {
+ *      if (socket.isClosed()) {
+ *        socket = new Socket(...);
+ *      }
+ *    }
+ * }
+ * </pre>
+ *
+ * A client of {@code SocketContainer} is permitted to call {@code reset()} arbitrarily many times.
+ * Each time it does so, a new {@code Socket} might be created. A {@code SocketContainer}'s
+ * must-call obligation of "stop" is fulfilled only if {@code stop()} is called after the last call
+ * to {@code reset()}. The {@code @CreatesObligation} annotation on {@code reset()}'s declaration
+ * enforces this requirement: at any call to {@code reset()}, all called-methods information about
+ * the receiver is removed from the store of the Must Call Checker and the store of the Called
+ * Methods Checker, so the client has to "start over" as if a fresh {@code SocketContainer} object
+ * had been created.
+ *
+ * <p>When the -AnoAccumulationFrames command-line argument is passed to the checker, this
+ * annotation is ignored and all fields are treated as non-owning.
+ *
+ * @checker_framework.manual #must-call-checker Must Call Checker
+ */
+@Target({ElementType.METHOD})
+@InheritedAnnotation
+@Retention(RetentionPolicy.RUNTIME)
+@Repeatable(CreatesObligation.List.class)
+public @interface CreatesObligation {
+
+  /**
+   * The target of this annotation is stored in this field. The target must be an expression which
+   * can be refined in the store, such as a local variable or field.
+   *
+   * @return the expression to which must-call obligations are added when the annotated method is
+   *     invoked
+   */
+  @JavaExpression
+  String value() default "this";
+
+  /**
+   * A wrapper annotation that makes the {@link CreatesObligation} annotation repeatable.
+   *
+   * <p>Programmers generally do not need to write this. It is created by Java when a programmer
+   * writes more than one {@link CreatesObligation} annotation at the same location.
+   *
+   * @checker_framework.manual #must-call-checker Must Call Checker
+   */
+  @Documented
+  @Retention(RetentionPolicy.RUNTIME)
+  @Target({ElementType.METHOD})
+  @InheritedAnnotation
+  @interface List {
+    /**
+     * Return the repeatable annotations.
+     *
+     * @return the repeatable annotations
+     */
+    CreatesObligation[] value();
+  }
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/InheritableMustCall.java b/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/InheritableMustCall.java
new file mode 100644
index 0000000..0883979
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/InheritableMustCall.java
@@ -0,0 +1,26 @@
+package org.checkerframework.checker.mustcall.qual;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is an alias for {@link MustCall} that applies to the type on which it is written
+ * <b>and</b> all of its subtypes. It prevents the need to annotate each subtype with an {@link
+ * MustCall} annotation. This annotation may only be written on a class declaration.
+ *
+ * @checker_framework.manual #must-call-checker Must Call Checker
+ */
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface InheritableMustCall {
+  /**
+   * Methods that might need to be called on the expression whose type is annotated.
+   *
+   * @return methods that might need to be called
+   */
+  public String[] value() default {};
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/MustCall.java b/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/MustCall.java
new file mode 100644
index 0000000..e8bf584
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/MustCall.java
@@ -0,0 +1,38 @@
+package org.checkerframework.checker.mustcall.qual;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * An expression of type {@code @MustCall({"m1", "m2"})} may be obligated to call {@code m1()}
+ * and/or {@code m2()} before it is deallocated, but it is not obligated to call any other methods.
+ *
+ * <p>This annotation is enforced by the Object Construction Checker's {@code -AcheckMustCall} mode.
+ * It enforces that the methods {@code m1()} and {@code m2()} are called on the annotated expression
+ * before it is deallocated.
+ *
+ * <p>The subtyping relationship is:
+ *
+ * <pre>{@code @MustCall({"m1"}) <: @MustCall({"m1", "m2"})}</pre>
+ *
+ * @checker_framework.manual #must-call-checker Must Call Checker
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({MustCallUnknown.class})
+@DefaultQualifierInHierarchy
+@DefaultFor({TypeUseLocation.EXCEPTION_PARAMETER})
+public @interface MustCall {
+  /**
+   * Methods that might need to be called on the expression whose type is annotated.
+   *
+   * @return methods that might need to be called
+   */
+  public String[] value() default {};
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/MustCallAlias.java b/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/MustCallAlias.java
new file mode 100644
index 0000000..ce79ba4
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/MustCallAlias.java
@@ -0,0 +1,60 @@
+package org.checkerframework.checker.mustcall.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This polymorphic annotation represents an either-or must-call obligation. This annotation should
+ * always be used in pairs. On a method, it is written on some formal parameter type and on the
+ * method return type. On a constructor, it is written on some formal parameter type and on the
+ * result type. Fulfilling the must-call obligation of one is equivalent to fulfilling the must-call
+ * obligation of the other.
+ *
+ * <p>This annotation is useful for wrapper objects. For example, consider the declaration of {@code
+ * java.net.Socket#getOutputStream}:
+ *
+ * <pre>
+ * &#64;MustCall("close")
+ * class Socket {
+ *   &#64;MustCallAlias OutputStream getOutputStream(&#64;MustCallAlias Socket this) { ... }
+ * }</pre>
+ *
+ * Calling {@code close()} on the returned {@code OutputStream} will close the underlying socket,
+ * but the Socket may also be closed directly, which has the same effect.
+ *
+ * <h3>Verifying {@code @MustCallAlias} annotations</h3>
+ *
+ * Suppose that {@code @MustCallAlias} is written on the type of formal parameter {@code p}.
+ *
+ * <p>For a constructor:
+ *
+ * <ul>
+ *   <li>The constructor must always write p into exactly one field {@code f} of the new object.
+ *   <li>Field {@code f} must be annotated {@code @}{@link Owning}.
+ * </ul>
+ *
+ * For a method:
+ *
+ * <ul>
+ *   <li>All return sites must be calls to other methods or constructors with {@code @MustCallAlias}
+ *       return types, and this method's {@code @MustCallAlias} parameter must be passed in the
+ *       {@code MustCallAlias} position to that method or constructor (i.e., the calls must pass
+ *       {@code @MustCallAlias} parameter through a chain of {@code @MustCallAlias}-annotated
+ *       parameters and returns).
+ * </ul>
+ *
+ * When the -AnoResourceAliases command-line argument is passed to the checker, this annotation is
+ * treated identically to {@link PolyMustCall}.
+ *
+ * @checker_framework.manual #must-call-checker Must Call Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+// In Java 11, this can be:
+// @Target({ElementType.PARAMETER, ElementType.CONSTRUCTOR, ElementType.METHOD})
+@Target({ElementType.PARAMETER, ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.TYPE_USE})
+public @interface MustCallAlias {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/MustCallUnknown.java b/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/MustCallUnknown.java
new file mode 100644
index 0000000..727a839
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/MustCallUnknown.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.mustcall.qual;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The top qualifier in the Must Call type hierarchy. It represents a type that might have an
+ * obligation to call any set (even an infinite set!) of methods. This type contains every object.
+ * This type should rarely be written by a programmer.
+ *
+ * <p>The Object Construction Checker cannot verify that the property represented by this annotation
+ * is enforced; that is, the Object Construction Checker will always issue a warning when the value
+ * of an expression with this type might be de-allocated.
+ *
+ * @checker_framework.manual #must-call-checker Must Call Checker
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({})
+public @interface MustCallUnknown {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/NotOwning.java b/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/NotOwning.java
new file mode 100644
index 0000000..4090ac8
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/NotOwning.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.mustcall.qual;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation indicating that ownership should not be transferred to the annotated parameter, field,
+ * or (when this is written on a method) return type, for the purposes of Must Call checking.
+ *
+ * <p>Parameters and fields are treated as if they have this annotation by default unless they have
+ * {@link Owning}.
+ *
+ * <p>When the -AnoLightweightOwnership command-line argument is passed to the checker, this
+ * annotation and {@link Owning} are ignored.
+ *
+ * @checker_framework.manual #must-call-checker Must Call Checker
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
+public @interface NotOwning {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/Owning.java b/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/Owning.java
new file mode 100644
index 0000000..429a76e
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/Owning.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.mustcall.qual;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation indicating that ownership should be transferred to the annotated parameter, field, or
+ * (when written on a method) return type, for the purposes of Must Call checking.
+ *
+ * <p>Method return types are treated as if they have this annotation by default unless their method
+ * is annotated as {@link NotOwning}.
+ *
+ * <p>When the -AnoLightweightOwnership command-line argument is passed to the checker, this
+ * annotation and {@link NotOwning} are ignored.
+ *
+ * @checker_framework.manual #must-call-checker Must Call Checker
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
+public @interface Owning {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/PolyMustCall.java b/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/PolyMustCall.java
new file mode 100644
index 0000000..8347477
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/mustcall/qual/PolyMustCall.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.mustcall.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * The polymorphic qualifier for the Must Call type system.
+ *
+ * @checker_framework.manual #must-call-checker Must Call Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier(MustCallUnknown.class)
+public @interface PolyMustCall {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/AssertNonNullIfNonNull.java b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/AssertNonNullIfNonNull.java
new file mode 100644
index 0000000..68408f1
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/AssertNonNullIfNonNull.java
@@ -0,0 +1,49 @@
+package org.checkerframework.checker.nullness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that if the method returns a non-null value, then the value expressions are also
+ * non-null.
+ *
+ * <p><b>WARNING:</b> Type-checking for this annotation is <em>not implemented</em> at present.
+ *
+ * <p>Here is an example use:
+ *
+ * <pre><code>
+ *    {@literal @}AssertNonNullIfNonNull("id")
+ *    {@literal @}Pure
+ *     public @Nullable Long getId() {
+ *         return id;
+ *     }
+ * </code></pre>
+ *
+ * Note the direction of the implication. This annotation says that if the result is non-null, then
+ * the variable {@code id} is also non-null. The annotation does not say that if {@code id} is
+ * non-null, then the result is non-null. (There is not currently a way to say the latter, though it
+ * would also be useful.)
+ *
+ * <p>You should <em>not</em> write a formal parameter name or {@code this} as the argument of this
+ * annotation. In those cases, use the {@link PolyNull} annotation instead.
+ *
+ * @see NonNull
+ * @see PolyNull
+ * @see org.checkerframework.checker.nullness.NullnessChecker
+ * @checker_framework.manual #nullness-checker Nullness Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface AssertNonNullIfNonNull {
+
+  /**
+   * Java expression(s) that are non-null after the method returns a non-null value.
+   *
+   * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions
+   */
+  String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/EnsuresKeyFor.java b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/EnsuresKeyFor.java
new file mode 100644
index 0000000..de2c629
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/EnsuresKeyFor.java
@@ -0,0 +1,77 @@
+package org.checkerframework.checker.nullness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.InheritedAnnotation;
+import org.checkerframework.framework.qual.JavaExpression;
+import org.checkerframework.framework.qual.PostconditionAnnotation;
+import org.checkerframework.framework.qual.QualifierArgument;
+
+/**
+ * Indicates that the value expressions evaluate to a value that is a key in all the given maps, if
+ * the method terminates successfully.
+ *
+ * <p>Consider the following method from {@code java.util.Map}:
+ *
+ * <pre>
+ * &#64;EnsuresKeyFor(value="key", map="this")
+ * public @Nullable V put(K key, V value) { ... }
+ * </pre>
+ *
+ * <p>This method guarantees that {@code key} has type {@code @KeyFor("this")} after the method
+ * returns.
+ *
+ * @see KeyFor
+ * @see EnsuresKeyForIf
+ * @checker_framework.manual #map-key-checker Map Key Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+@PostconditionAnnotation(qualifier = KeyFor.class)
+@InheritedAnnotation
+@Repeatable(EnsuresKeyFor.List.class)
+public @interface EnsuresKeyFor {
+  /**
+   * Java expressions that are keys in the given maps on successful method termination.
+   *
+   * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions
+   */
+  String[] value();
+
+  /**
+   * Returns Java expressions whose values are maps, each of which contains each expression value as
+   * a key (after successful method termination).
+   *
+   * @return Java expressions whose values are maps, each of which contains each expression value as
+   *     a key (after successful method termination)
+   * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions
+   */
+  @JavaExpression
+  @QualifierArgument("value")
+  String[] map();
+
+  /**
+   * A wrapper annotation that makes the {@link EnsuresKeyFor} annotation repeatable.
+   *
+   * <p>Programmers generally do not need to write this. It is created by Java when a programmer
+   * writes more than one {@link EnsuresKeyFor} annotation at the same location.
+   */
+  @Documented
+  @Retention(RetentionPolicy.RUNTIME)
+  @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+  @PostconditionAnnotation(qualifier = KeyFor.class)
+  @InheritedAnnotation
+  @interface List {
+    /**
+     * Returns the repeatable annotations.
+     *
+     * @return the repeatable annotations
+     */
+    EnsuresKeyFor[] value();
+  }
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/EnsuresKeyForIf.java b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/EnsuresKeyForIf.java
new file mode 100644
index 0000000..cc60484
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/EnsuresKeyForIf.java
@@ -0,0 +1,80 @@
+package org.checkerframework.checker.nullness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.ConditionalPostconditionAnnotation;
+import org.checkerframework.framework.qual.InheritedAnnotation;
+import org.checkerframework.framework.qual.JavaExpression;
+import org.checkerframework.framework.qual.QualifierArgument;
+
+/**
+ * Indicates that the given expressions evaluate to a value that is a key in all the given maps, if
+ * the method returns the given result (either true or false).
+ *
+ * <p>As an example, consider the following method in {@code java.util.Map}:
+ *
+ * <pre>
+ *   &#64;EnsuresKeyForIf(result=true, expression="key", map="this")
+ *   public boolean containsKey(String key) { ... }
+ * </pre>
+ *
+ * If an invocation {@code m.containsKey(k)} returns true, then the type of {@code k} can be
+ * inferred to be {@code @KeyFor("m")}.
+ *
+ * @see KeyFor
+ * @see EnsuresKeyFor
+ * @checker_framework.manual #map-key-checker Map Key Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+@ConditionalPostconditionAnnotation(qualifier = KeyFor.class)
+@InheritedAnnotation
+@Repeatable(EnsuresKeyForIf.List.class)
+public @interface EnsuresKeyForIf {
+  /** The value the method must return, in order for the postcondition to hold. */
+  boolean result();
+
+  /**
+   * Java expressions that are keys in the given maps after the method returns the given result.
+   *
+   * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions
+   */
+  String[] expression();
+
+  /**
+   * Returns Java expressions whose values are maps, each of which contains each expression value as
+   * a key (after the method returns the given result).
+   *
+   * @return Java expressions whose values are maps, each of which contains each expression value as
+   *     a key (after the method returns the given result)
+   * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions
+   */
+  @JavaExpression
+  @QualifierArgument("value")
+  String[] map();
+
+  /**
+   * A wrapper annotation that makes the {@link EnsuresKeyForIf} annotation repeatable.
+   *
+   * <p>Programmers generally do not need to write this. It is created by Java when a programmer
+   * writes more than one {@link EnsuresKeyForIf} annotation at the same location.
+   */
+  @Documented
+  @Retention(RetentionPolicy.RUNTIME)
+  @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+  @ConditionalPostconditionAnnotation(qualifier = KeyFor.class)
+  @InheritedAnnotation
+  @interface List {
+    /**
+     * Returns the repeatable annotations.
+     *
+     * @return the repeatable annotations
+     */
+    EnsuresKeyForIf[] value();
+  }
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/EnsuresNonNull.java b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/EnsuresNonNull.java
new file mode 100644
index 0000000..011a9ff
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/EnsuresNonNull.java
@@ -0,0 +1,74 @@
+package org.checkerframework.checker.nullness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.InheritedAnnotation;
+import org.checkerframework.framework.qual.PostconditionAnnotation;
+
+// TODO: In a fix for https://tinyurl.com/cfissue/1917, add the text:  Every prefix expression is
+// also non-null; for example, {@code @EnsuresNonNull(expression="a.b.c")} implies that both {@code
+// a.b} and {@code a.b.c} are non-null.
+/**
+ * Indicates that the value expressions are non-null just after a method call, if the method
+ * terminates successfully.
+ *
+ * <p>This postcondition annotation is useful for methods that initialize a field:
+ *
+ * <pre><code>
+ * {@literal @}EnsuresNonNull("theMap")
+ *  void initialize() {
+ *    theMap = new HashMap&lt;&gt;();
+ *  }
+ * </code></pre>
+ *
+ * It can also be used for a method that fails if a given expression is null:
+ *
+ * <pre><code>
+ *  /** Throws an exception if the argument is null. *&#47;
+ * {@literal @}EnsuresNonNull("#1")
+ *  void assertNonNull(Object arg) { ... }
+ * </code></pre>
+ *
+ * @see NonNull
+ * @see org.checkerframework.checker.nullness.NullnessChecker
+ * @checker_framework.manual #nullness-checker Nullness Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+@PostconditionAnnotation(qualifier = NonNull.class)
+@InheritedAnnotation
+@Repeatable(EnsuresNonNull.List.class)
+public @interface EnsuresNonNull {
+  /**
+   * Returns Java expressions that are {@link NonNull} after successful method termination.
+   *
+   * @return Java expressions that are {@link NonNull} after successful method termination
+   * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions
+   */
+  String[] value();
+
+  /**
+   * A wrapper annotation that makes the {@link EnsuresNonNull} annotation repeatable.
+   *
+   * <p>Programmers generally do not need to write this. It is created by Java when a programmer
+   * writes more than one {@link EnsuresNonNull} annotation at the same location.
+   */
+  @Documented
+  @Retention(RetentionPolicy.RUNTIME)
+  @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+  @PostconditionAnnotation(qualifier = NonNull.class)
+  @InheritedAnnotation
+  @interface List {
+    /**
+     * Returns the repeatable annotations.
+     *
+     * @return the repeatable annotations
+     */
+    EnsuresNonNull[] value();
+  }
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/EnsuresNonNullIf.java b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/EnsuresNonNullIf.java
new file mode 100644
index 0000000..2d216cc
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/EnsuresNonNullIf.java
@@ -0,0 +1,112 @@
+package org.checkerframework.checker.nullness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.ConditionalPostconditionAnnotation;
+import org.checkerframework.framework.qual.InheritedAnnotation;
+
+// TODO: In a fix for https://tinyurl.com/cfissue/1917, add the text:  Every prefix expression is
+// also non-null; for example, {@code @EnsuresNonNullIf(expression="a.b.c", results=true)} implies
+// that both {@code a.b} and {@code a.b.c} are non-null if the method returns {@code true}.
+/**
+ * Indicates that the given expressions are non-null, if the method returns the given result (either
+ * true or false).
+ *
+ * <p>Here are ways this conditional postcondition annotation can be used:
+ *
+ * <p><b>Method parameters:</b> A common example is that the {@code equals} method is annotated as
+ * follows:
+ *
+ * <pre>{@code   @EnsuresNonNullIf(expression="#1", result=true)
+ *   public boolean equals(@Nullable Object obj) { ... }}</pre>
+ *
+ * because, if {@code equals} returns true, then the first (#1) argument to {@code equals} was not
+ * null.
+ *
+ * <p><b>Fields:</b> The value expressions can refer to fields, even private ones. For example:
+ *
+ * <pre>{@code   @EnsuresNonNullIf(expression="this.derived", result=true)
+ *   public boolean isDerived() {
+ *     return (this.derived != null);
+ *   }}</pre>
+ *
+ * As another example, an {@code Iterator} may cache the next value that will be returned, in which
+ * case its {@code hasNext} method could be annotated as:
+ *
+ * <pre>{@code   @EnsuresNonNullIf(expression="next_cache", result=true)
+ *   public boolean hasNext() {
+ *     if (next_cache == null) {
+ *       return false;
+ *     }
+ *     ...
+ *   }}</pre>
+ *
+ * An {@code EnsuresNonNullIf} annotation that refers to a private field is useful for verifying
+ * that client code performs needed checks in the right order, even if the client code cannot
+ * directly affect the field.
+ *
+ * <p><b>Method calls:</b> If {@link Class#isArray()} returns true, then {@link
+ * Class#getComponentType()} returns non-null. You can express this relationship as:
+ *
+ * <pre>{@code   @EnsuresNonNullIf(expression="getComponentType()", result=true)
+ *   public native @Pure boolean isArray();}</pre>
+ *
+ * You can write two {@code @EnsuresNonNullIf} annotations on a single method:
+ *
+ * <pre><code>
+ * &nbsp;   @EnsuresNonNullIf(expression="outputFile", result=true)
+ * &nbsp;   @EnsuresNonNullIf(expression="memoryOutputStream", result=false)
+ *     public boolean isThresholdExceeded() { ... }
+ * </code></pre>
+ *
+ * @see NonNull
+ * @see EnsuresNonNull
+ * @see org.checkerframework.checker.nullness.NullnessChecker
+ * @checker_framework.manual #nullness-checker Nullness Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+@ConditionalPostconditionAnnotation(qualifier = NonNull.class)
+@InheritedAnnotation
+@Repeatable(EnsuresNonNullIf.List.class)
+public @interface EnsuresNonNullIf {
+  /**
+   * Returns Java expression(s) that are non-null after the method returns the given result.
+   *
+   * @return Java expression(s) that are non-null after the method returns the given result
+   * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions
+   */
+  String[] expression();
+
+  /**
+   * Returns the return value of the method under which the postcondition holds.
+   *
+   * @return the return value of the method under which the postcondition holds
+   */
+  boolean result();
+
+  /**
+   * * A wrapper annotation that makes the {@link EnsuresNonNullIf} annotation repeatable.
+   *
+   * <p>Programmers generally do not need to write this. It is created by Java when a programmer
+   * writes more than one {@link EnsuresNonNullIf} annotation at the same location.
+   */
+  @Documented
+  @Retention(RetentionPolicy.RUNTIME)
+  @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+  @ConditionalPostconditionAnnotation(qualifier = NonNull.class)
+  @InheritedAnnotation
+  @interface List {
+    /**
+     * Returns the repeatable annotations.
+     *
+     * @return the repeatable annotations
+     */
+    EnsuresNonNullIf[] value();
+  }
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/KeyFor.java b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/KeyFor.java
new file mode 100644
index 0000000..396f716
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/KeyFor.java
@@ -0,0 +1,51 @@
+package org.checkerframework.checker.nullness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.JavaExpression;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Indicates that the value assigned to the annotated variable is a key for at least the given
+ * map(s).
+ *
+ * <p>The value of the annotation is the reference name of the map. Suppose that {@code config} is a
+ * {@code Map<String, String>}. Then the declaration
+ *
+ * <pre>{@code   @KeyFor("config") String key = "HOSTNAME"; }</pre>
+ *
+ * indicates that "HOSTNAME" is a key in {@code config}.
+ *
+ * <p>The value of the annotation can also be a set of reference names of the maps. If {@code
+ * defaultConfig} is also a {@code Map<String, String>}, then
+ *
+ * <pre>{@code   @KeyFor({"config","defaultConfig"}) String key = "HOSTNAME"; }</pre>
+ *
+ * indicates that "HOSTNAME" is a key in {@code config} and in {@code defaultConfig}.
+ *
+ * <p>You do not usually need to write {@code @KeyFor} on the key type in a map. That is, you can
+ * declare variable {@code Map<String, Integer> myMap;} and the Nullness Checker will apply
+ * {@code @KeyFor} as appropriate. If you redundantly write {@code @KeyFor}, as in {@code
+ * Map<@KeyFor("myMap") String, Integer> myMap;}, then your code is more verbose, and more seriously
+ * the Nullness Checker will issue errors when calling methods such as {@code Map.put}.
+ *
+ * @see EnsuresKeyFor
+ * @see EnsuresKeyForIf
+ * @checker_framework.manual #map-key-checker Map Key Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownKeyFor.class)
+public @interface KeyFor {
+  /**
+   * Java expression(s) that evaluate to a map for which the annotated type is a key.
+   *
+   * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions
+   */
+  @JavaExpression
+  public String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/KeyForBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/KeyForBottom.java
new file mode 100644
index 0000000..c879956
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/KeyForBottom.java
@@ -0,0 +1,27 @@
+package org.checkerframework.checker.nullness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the Map Key type system. Programmers should rarely write this type.
+ *
+ * <p>There are no values of this type (not even {@code null}).
+ *
+ * @checker_framework.manual #map-key-checker Map Key Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@InvisibleQualifier
+@SubtypeOf(KeyFor.class)
+public @interface KeyForBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/MonotonicNonNull.java b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/MonotonicNonNull.java
new file mode 100644
index 0000000..8608c15
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/MonotonicNonNull.java
@@ -0,0 +1,51 @@
+package org.checkerframework.checker.nullness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.MonotonicQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Indicates that once the field (or variable) becomes non-null, it never becomes null again. There
+ * is no guarantee that the field ever becomes non-null, but if it does, it will stay non-null.
+ *
+ * <p>Example use cases include lazy initialization and framework-based initialization in a
+ * lifecycle method other than the constructor.
+ *
+ * <p>A monotonically non-null field has these two properties:
+ *
+ * <ol>
+ *   <li>The field may be assigned only non-null values.
+ *   <li>The field may be re-assigned as often as desired.
+ * </ol>
+ *
+ * <p>When the field is first read within a method, the field cannot be assumed to be non-null.
+ * After a check that a {@code @MonotonicNonNull} field holds a non-null value, all subsequent
+ * accesses <em>within that method</em> can be assumed to be non-null, even after arbitrary external
+ * method calls that might access the field.
+ *
+ * <p>{@code @MonotonicNonNull} gives stronger guarantees than {@link Nullable}. After a check that
+ * a {@link Nullable} field holds a non-null value, only accesses until the next non-{@link
+ * org.checkerframework.dataflow.qual.SideEffectFree} method is called can be assumed to be
+ * non-null.
+ *
+ * <p>To indicate that a {@code @MonotonicNonNull} or {@code @Nullable} field is non-null whenever a
+ * particular method is called, use {@code @}{@link RequiresNonNull}.
+ *
+ * <p>Final fields are treated as MonotonicNonNull by default.
+ *
+ * @see EnsuresNonNull
+ * @see RequiresNonNull
+ * @see MonotonicQualifier
+ * @see org.checkerframework.checker.nullness.NullnessChecker
+ * @checker_framework.manual #nullness-checker Nullness Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE_USE)
+@SubtypeOf(Nullable.class)
+@MonotonicQualifier(NonNull.class)
+public @interface MonotonicNonNull {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/NonNull.java b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/NonNull.java
new file mode 100644
index 0000000..430d711
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/NonNull.java
@@ -0,0 +1,56 @@
+package org.checkerframework.checker.nullness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.LiteralKind;
+import org.checkerframework.framework.qual.QualifierForLiterals;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TypeKind;
+import org.checkerframework.framework.qual.TypeUseLocation;
+import org.checkerframework.framework.qual.UpperBoundFor;
+
+/**
+ * If an expression's type is qualified by {@code @NonNull}, then the expression never evaluates to
+ * {@code null}. (Unless the program has a bug; annotations specify intended behavior.)
+ *
+ * <p>For fields of a class, the {@link NonNull} annotation indicates that this field is never
+ * {@code null} <em>after the class has been fully initialized</em>. For static fields, the {@link
+ * NonNull} annotation indicates that this field is never {@code null} <em>after the containing
+ * class is initialized</em>. "Fully initialized" essentially means that the Java constructor has
+ * completed. See the <a
+ * href="https://checkerframework.org/manual/#initialization-checker">Initialization Checker
+ * documentation</a> for more details.
+ *
+ * <p>This annotation is rarely written in source code, because it is the default.
+ *
+ * @see Nullable
+ * @see MonotonicNonNull
+ * @checker_framework.manual #nullness-checker Nullness Checker
+ * @checker_framework.manual #initialization-checker Initialization Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(MonotonicNonNull.class)
+@QualifierForLiterals(LiteralKind.STRING)
+@DefaultQualifierInHierarchy
+@DefaultFor(TypeUseLocation.EXCEPTION_PARAMETER)
+@UpperBoundFor(
+    typeKinds = {
+      TypeKind.PACKAGE,
+      TypeKind.INT,
+      TypeKind.BOOLEAN,
+      TypeKind.CHAR,
+      TypeKind.DOUBLE,
+      TypeKind.FLOAT,
+      TypeKind.LONG,
+      TypeKind.SHORT,
+      TypeKind.BYTE
+    })
+public @interface NonNull {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/Nullable.java b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/Nullable.java
new file mode 100644
index 0000000..3dd6cf5
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/Nullable.java
@@ -0,0 +1,35 @@
+package org.checkerframework.checker.nullness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.LiteralKind;
+import org.checkerframework.framework.qual.QualifierForLiterals;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * {@link Nullable} is a type annotation that makes no commitments about whether the value is {@code
+ * null}. Equivalently, the type includes the {@code null} value.
+ *
+ * <p>The Nullness Checker issues an error if {@code null} is assigned an an expression of {@link
+ * NonNull} type.
+ *
+ * <p>Programmers typically write {@code @Nullable} to indicate that the value is not known to be
+ * {@link NonNull}. However, since {@code @Nullable} is a supertype of {@code @NonNull}, an
+ * expression that never evaluates to {@code null} can have a declared type of {@code @Nullable}.
+ *
+ * @see NonNull
+ * @see MonotonicNonNull
+ * @see org.checkerframework.checker.nullness.NullnessChecker
+ * @checker_framework.manual #nullness-checker Nullness Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({})
+@QualifierForLiterals(LiteralKind.NULL)
+@DefaultFor(types = Void.class)
+public @interface Nullable {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/PolyKeyFor.java b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/PolyKeyFor.java
new file mode 100644
index 0000000..6a89836
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/PolyKeyFor.java
@@ -0,0 +1,26 @@
+package org.checkerframework.checker.nullness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * A polymorphic qualifier for the Map Key (@KeyFor) type system.
+ *
+ * <p>Any method written using {@code @PolyKeyFor} conceptually has an arbitrary number of versions:
+ * one in which every instance of {@code @PolyKeyFor} has been replaced by {@code @}{@link
+ * UnknownKeyFor}, one in which every instance of {@code @}{@link PolyKeyFor} has been replaced by
+ * {@code @}{@link KeyForBottom}, and ones in which every instance of {@code @PolyKeyFor} has been
+ * replaced by {@code @}{@code KeyFor}, for every possible combination of map arguments.
+ *
+ * @checker_framework.manual #nullness-checker Nullness Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier(UnknownKeyFor.class)
+public @interface PolyKeyFor {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/PolyNull.java b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/PolyNull.java
new file mode 100644
index 0000000..35b10a0
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/PolyNull.java
@@ -0,0 +1,24 @@
+package org.checkerframework.checker.nullness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * A polymorphic qualifier for the non-null type system.
+ *
+ * <p>Any method written using {@link PolyNull} conceptually has two versions: one in which every
+ * instance of {@link PolyNull} has been replaced by {@link NonNull}, and one in which every
+ * instance of {@link PolyNull} has been replaced by {@link Nullable}.
+ *
+ * @checker_framework.manual #nullness-checker Nullness Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier(Nullable.class)
+public @interface PolyNull {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/RequiresNonNull.java b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/RequiresNonNull.java
new file mode 100644
index 0000000..e1a73e5
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/RequiresNonNull.java
@@ -0,0 +1,69 @@
+package org.checkerframework.checker.nullness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PreconditionAnnotation;
+
+// TODO: In a fix for https://tinyurl.com/cfissue/1917, add the text:  Every prefix expression must
+// also be non-null; for example, {@code @RequiresNonNull(expression="a.b.c")} implies that both
+// {@code a.b} and {@code a.b.c} must be non-null.
+/**
+ * Indicates a method precondition: the method expects the specified expressions to be non-null when
+ * the annotated method is invoked.
+ *
+ * <p>For example:
+ * <!-- The "&nbsp;" is to hide the at-signs from Javadoc. -->
+ *
+ * <pre>
+ * class MyClass {
+ * &nbsp; @Nullable Object field1;
+ * &nbsp; @Nullable Object field2;
+ *
+ * &nbsp; @RequiresNonNull({"field1", "#1.field1"})
+ *   void method1(@NonNull MyClass other) {
+ *     field1.toString();           // OK, this.field1 is known to be non-null
+ *     field2.toString();           // error, might throw NullPointerException
+ *     other.field1.toString();     // OK, other.field1 is known to be non-null
+ *     other.field2.toString();     // error, might throw NullPointerException
+ *   }
+ *
+ *   void method2() {
+ *     MyClass other = new MyClass();
+ *
+ *     field1 = new Object();
+ *     other.field1 = new Object();
+ *     method1(other);                   // OK, satisfies method precondition
+ *
+ *     field1 = null;
+ *     other.field1 = new Object();
+ *     method1(other);                   // error, does not satisfy this.field1 method precondition
+ *
+ *     field1 = new Object();
+ *     other.field1 = null;
+ *     method1(other);                   // error, does not satisfy other.field1 method precondition
+ *   }
+ * }
+ * </pre>
+ *
+ * Do not use this annotation for formal parameters (instead, give them a {@code @NonNull} type,
+ * which is the default and need not be written). The {@code @RequiresNonNull} annotation is
+ * intended for other expressions, such as field accesses or method calls.
+ *
+ * @checker_framework.manual #nullness-checker Nullness Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+@PreconditionAnnotation(qualifier = NonNull.class)
+public @interface RequiresNonNull {
+  /**
+   * The Java expressions that need to be {@link
+   * org.checkerframework.checker.nullness.qual.NonNull}.
+   *
+   * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions
+   */
+  String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/UnknownKeyFor.java b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/UnknownKeyFor.java
new file mode 100644
index 0000000..19e423c
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/nullness/qual/UnknownKeyFor.java
@@ -0,0 +1,33 @@
+package org.checkerframework.checker.nullness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.LiteralKind;
+import org.checkerframework.framework.qual.QualifierForLiterals;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * Used internally by the type system; should never be written by a programmer.
+ *
+ * <p>Indicates that the value assigned to the annotated variable is not known to be a key for any
+ * map. It is the top type qualifier in the {@link KeyFor} hierarchy. It is also the default type
+ * qualifier.
+ *
+ * @checker_framework.manual #map-key-checker Map Key Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@InvisibleQualifier
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+@DefaultFor(value = TypeUseLocation.LOWER_BOUND, types = Void.class)
+@QualifierForLiterals(LiteralKind.NULL)
+public @interface UnknownKeyFor {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/optional/qual/MaybePresent.java b/checker-qual/src/main/java/org/checkerframework/checker/optional/qual/MaybePresent.java
new file mode 100644
index 0000000..b37ac12
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/optional/qual/MaybePresent.java
@@ -0,0 +1,21 @@
+package org.checkerframework.checker.optional.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The {@link java.util.Optional Optional} container may or may not contain a value.
+ *
+ * @checker_framework.manual #optional-checker Optional Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface MaybePresent {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/optional/qual/OptionalBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/optional/qual/OptionalBottom.java
new file mode 100644
index 0000000..755f071
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/optional/qual/OptionalBottom.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.optional.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The bottom type qualifier for the Optional Checker. The only value of this type is {@code null}.
+ * Programmers rarely write this annotation.
+ *
+ * @checker_framework.manual #optional-checker Optional Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({Present.class})
+public @interface OptionalBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/optional/qual/PolyPresent.java b/checker-qual/src/main/java/org/checkerframework/checker/optional/qual/PolyPresent.java
new file mode 100644
index 0000000..e462ed7
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/optional/qual/PolyPresent.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.optional.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * A polymorphic qualifier for the Optional type system.
+ *
+ * @checker_framework.manual #optional-checker Optional Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier(MaybePresent.class)
+public @interface PolyPresent {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/optional/qual/Present.java b/checker-qual/src/main/java/org/checkerframework/checker/optional/qual/Present.java
new file mode 100644
index 0000000..90c59e2
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/optional/qual/Present.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.optional.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The {@link java.util.Optional Optional} container definitely contains a (non-null) value.
+ *
+ * @checker_framework.manual #optional-checker Optional Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({MaybePresent.class})
+public @interface Present {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/propkey/qual/PropertyKey.java b/checker-qual/src/main/java/org/checkerframework/checker/propkey/qual/PropertyKey.java
new file mode 100644
index 0000000..712fc8f
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/propkey/qual/PropertyKey.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.propkey.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Indicates that the {@code String} type can be used as key in a property file or resource bundle.
+ *
+ * @checker_framework.manual #propkey-checker Property File Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownPropertyKey.class)
+public @interface PropertyKey {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/propkey/qual/PropertyKeyBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/propkey/qual/PropertyKeyBottom.java
new file mode 100644
index 0000000..e3b40a9
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/propkey/qual/PropertyKeyBottom.java
@@ -0,0 +1,26 @@
+package org.checkerframework.checker.propkey.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the PropertyKeyChecker (and associated checkers) qualifier hierarchy.
+ * Programmers should rarely write this type.
+ *
+ * @checker_framework.manual #propkey-checker Property File Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@SubtypeOf(PropertyKey.class)
+@DefaultFor(TypeUseLocation.LOWER_BOUND)
+public @interface PropertyKeyBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/propkey/qual/UnknownPropertyKey.java b/checker-qual/src/main/java/org/checkerframework/checker/propkey/qual/UnknownPropertyKey.java
new file mode 100644
index 0000000..89a55a0
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/propkey/qual/UnknownPropertyKey.java
@@ -0,0 +1,21 @@
+package org.checkerframework.checker.propkey.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Indicates that the {@code String} type has an unknown property key property.
+ *
+ * @checker_framework.manual #propkey-checker Property File Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface UnknownPropertyKey {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/regex/qual/PartialRegex.java b/checker-qual/src/main/java/org/checkerframework/checker/regex/qual/PartialRegex.java
new file mode 100644
index 0000000..2519b67
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/regex/qual/PartialRegex.java
@@ -0,0 +1,32 @@
+package org.checkerframework.checker.regex.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Indicates a String that is not a syntactically valid regular expression. The String itself can be
+ * stored as a parameter to the annotation, allowing the Regex Checker to verify some concatenations
+ * of partial regular expression Strings.
+ *
+ * <p>This annotation may not be written in source code; it is an implementation detail of the Regex
+ * Checker.
+ *
+ * @checker_framework.manual #regex-checker Regex Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({}) // empty target prevents programmers from writing this in a program
+@InvisibleQualifier
+@SubtypeOf(org.checkerframework.checker.regex.qual.UnknownRegex.class)
+public @interface PartialRegex {
+
+  /**
+   * The String qualified by this annotation. Used to verify concatenation of partial regular
+   * expressions. Defaults to the empty String.
+   */
+  String value() default "";
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/regex/qual/PolyRegex.java b/checker-qual/src/main/java/org/checkerframework/checker/regex/qual/PolyRegex.java
new file mode 100644
index 0000000..ea81c50
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/regex/qual/PolyRegex.java
@@ -0,0 +1,24 @@
+package org.checkerframework.checker.regex.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * A polymorphic qualifier for the Regex type system.
+ *
+ * <p>Any method written using {@link PolyRegex} conceptually has two versions: one in which every
+ * instance of {@link PolyRegex} has been replaced by {@link Regex}, and one in which every instance
+ * of {@link PolyRegex} has been replaced by {@link UnknownRegex}.
+ *
+ * @checker_framework.manual #regex-checker Regex Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier(UnknownRegex.class)
+public @interface PolyRegex {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/regex/qual/Regex.java b/checker-qual/src/main/java/org/checkerframework/checker/regex/qual/Regex.java
new file mode 100644
index 0000000..9f7e674
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/regex/qual/Regex.java
@@ -0,0 +1,28 @@
+package org.checkerframework.checker.regex.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * If a type is annotated as {@code @Regex(n)}, then the run-time value is a regular expression with
+ * <em>n</em> capturing groups.
+ *
+ * <p>For example, if an expression's type is <em>@Regex(2) String</em>, then at run time its value
+ * will be a legal regular expression with at least two capturing groups. The type states that
+ * possible run-time values include {@code "(a*)(b*)"}, {@code "a(b?)c(d?)e"}, and {@code
+ * "(.)(.)(.)"}, but not {@code "hello"} nor {@code "(good)bye"} nor {@code "(a*)(b*)("}.
+ *
+ * @checker_framework.manual #regex-checker Regex Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownRegex.class)
+public @interface Regex {
+  /** The number of groups in the regular expression. Defaults to 0. */
+  int value() default 0;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/regex/qual/RegexBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/regex/qual/RegexBottom.java
new file mode 100644
index 0000000..e0f226b
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/regex/qual/RegexBottom.java
@@ -0,0 +1,27 @@
+package org.checkerframework.checker.regex.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the Regex type system. Programmers should rarely write this type.
+ *
+ * @checker_framework.manual #regex-checker Regex Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@InvisibleQualifier
+@SubtypeOf({Regex.class, org.checkerframework.checker.regex.qual.PartialRegex.class})
+@DefaultFor(value = {TypeUseLocation.LOWER_BOUND})
+public @interface RegexBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/regex/qual/UnknownRegex.java b/checker-qual/src/main/java/org/checkerframework/checker/regex/qual/UnknownRegex.java
new file mode 100644
index 0000000..ea1948b
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/regex/qual/UnknownRegex.java
@@ -0,0 +1,26 @@
+package org.checkerframework.checker.regex.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * Represents the top of the Regex qualifier hierarchy.
+ *
+ * @checker_framework.manual #regex-checker Regex Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@InvisibleQualifier
+@DefaultQualifierInHierarchy
+@SubtypeOf({})
+public @interface UnknownRegex {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/ArrayWithoutPackage.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/ArrayWithoutPackage.java
new file mode 100644
index 0000000..880dcc4
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/ArrayWithoutPackage.java
@@ -0,0 +1,21 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An identifier or primitive type, followed by any number of array square brackets.
+ *
+ * <p>Example: Foobar[][] Example: Baz22
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({FullyQualifiedName.class, ClassGetSimpleName.class})
+public @interface ArrayWithoutPackage {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/BinaryName.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/BinaryName.java
new file mode 100644
index 0000000..c1a8acb
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/BinaryName.java
@@ -0,0 +1,39 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Represents a binary name as defined in the <a
+ * href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-13.html#jls-13.1">Java Language
+ * Specification, section 13.1</a>.
+ *
+ * <p>For example, in
+ *
+ * <pre>
+ *  package org.checkerframework.checker.signature;
+ *  public class SignatureChecker {
+ *    private class Inner {}
+ *  }
+ * </pre>
+ *
+ * the binary names for the two types are org.checkerframework.checker.signature.SignatureChecker
+ * and org.checkerframework.checker.signature.SignatureChecker$Inner.
+ *
+ * <p>Binary names and {@linkplain InternalForm internal form} only differ by the use of '.' vs. '/'
+ * as package separator.
+ *
+ * <p>The binary name should not be confused with the {@linkplain InternalForm internal form}, which
+ * is a variant of the binary name that actually appears in the class file.
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({BinaryNameOrPrimitiveType.class})
+public @interface BinaryName {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/BinaryNameOrPrimitiveType.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/BinaryNameOrPrimitiveType.java
new file mode 100644
index 0000000..c2d36f7
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/BinaryNameOrPrimitiveType.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Represents a primitive type name or a {@link BinaryName binary name}.
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({ClassGetName.class, FqBinaryName.class})
+public @interface BinaryNameOrPrimitiveType {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/BinaryNameWithoutPackage.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/BinaryNameWithoutPackage.java
new file mode 100644
index 0000000..7a28a75
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/BinaryNameWithoutPackage.java
@@ -0,0 +1,28 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Represents a string that is a {@link BinaryName}, an {@link InternalForm}, and a {@link
+ * ClassGetName}. The string represents a class that is in the unnamed package (also known as the
+ * default package).
+ *
+ * <p>Examples:
+ *
+ * <pre>{@code
+ * MyClass
+ * MyClass$22
+ * }</pre>
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({BinaryName.class, InternalForm.class})
+public @interface BinaryNameWithoutPackage {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/CanonicalName.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/CanonicalName.java
new file mode 100644
index 0000000..4ea4b01
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/CanonicalName.java
@@ -0,0 +1,49 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Canonical names have the same syntactic form as {@link FullyQualifiedName fully-qualified name}s.
+ * Every canonical name is a fully-qualified name, but not every fully-qualified name is a canonical
+ * name.
+ *
+ * <p><a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-6.html#jls-6.7">JLS section
+ * 6.7</a> gives the following example:
+ *
+ * <blockquote>
+ *
+ * The difference between a fully qualified name and a canonical name can be seen in code such as:
+ *
+ * <pre>{@code
+ * package p;
+ * class O1 { class I {} }
+ * class O2 extends O1 {}
+ * }</pre>
+ *
+ * Both {@code p.O1.I} and {@code p.O2.I} are fully qualified names that denote the member class
+ * {@code I}, but only {@code p.O1.I} is its canonical name.
+ *
+ * </blockquote>
+ *
+ * Given a character sequence that is a fully-qualified name, there is no way to know whether or not
+ * it is a canonical name, without examining the program it refers to. Type-checking determines that
+ * a string is a {@code CanonicalName} based on provenance (what method produced the string), rather
+ * than the contents of the string.
+ *
+ * @see FullyQualifiedName
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({
+  FullyQualifiedName.class,
+  CanonicalNameOrEmpty.class,
+  CanonicalNameOrPrimitiveType.class
+})
+public @interface CanonicalName {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/CanonicalNameAndBinaryName.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/CanonicalNameAndBinaryName.java
new file mode 100644
index 0000000..c096a3f
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/CanonicalNameAndBinaryName.java
@@ -0,0 +1,24 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * This is a string that is a valid {@linkplain
+ * org.checkerframework.checker.signature.qual.CanonicalName canonical name} and a valid {@linkplain
+ * org.checkerframework.checker.signature.qual.BinaryName binary name}. It represents a non-array,
+ * non-inner, non-primitive class.
+ *
+ * <p>Examples: int, MyClass, java.lang, java.lang.Integer
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({CanonicalName.class, DotSeparatedIdentifiers.class})
+public @interface CanonicalNameAndBinaryName {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/CanonicalNameOrEmpty.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/CanonicalNameOrEmpty.java
new file mode 100644
index 0000000..bf347b1
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/CanonicalNameOrEmpty.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Either a {@link CanonicalName} or the empty string.
+ *
+ * @see CanonicalName
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(SignatureUnknown.class)
+public @interface CanonicalNameOrEmpty {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/CanonicalNameOrPrimitiveType.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/CanonicalNameOrPrimitiveType.java
new file mode 100644
index 0000000..d56e5bd
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/CanonicalNameOrPrimitiveType.java
@@ -0,0 +1,24 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * This is a string that is a valid {@linkplain CanonicalName canonical name} and a valid
+ * {@linkplain BinaryNameOrPrimitiveType binary name or primitive type}. It represents a primitive
+ * type or a non-array, non-inner class, where the latter is represented by dot-separated
+ * identifiers.
+ *
+ * <p>Examples: int, MyClass, java.lang.Integer
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({DotSeparatedIdentifiersOrPrimitiveType.class})
+public @interface CanonicalNameOrPrimitiveType {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/ClassGetName.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/ClassGetName.java
new file mode 100644
index 0000000..c5bed39
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/ClassGetName.java
@@ -0,0 +1,35 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The type representation used by the {@link Class#getName()}, {@link Class#forName(String)}, and
+ * {@link Class#forName(String, boolean, ClassLoader)} methods. This format is:
+ *
+ * <ul>
+ *   <li>for any non-array type, the {@link BinaryName binary name}
+ *   <li>for any array type, a format like the {@link FieldDescriptor field descriptor}, but using
+ *       '.' where the field descriptor uses '/'
+ * </ul>
+ *
+ * <p>Examples include
+ *
+ * <pre>
+ *   java.lang.String
+ *   [Ljava.lang.Object;
+ *   int
+ *   [[[I
+ * </pre>
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(SignatureUnknown.class)
+public @interface ClassGetName {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/ClassGetSimpleName.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/ClassGetSimpleName.java
new file mode 100644
index 0000000..ca75e87
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/ClassGetSimpleName.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The format produced by the {@link Class#getSimpleName()} method. It is an identifier or the empty
+ * string (for an anonymous class), followed by an number of array square brackets.
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(SignatureUnknown.class)
+public @interface ClassGetSimpleName {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/DotSeparatedIdentifiers.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/DotSeparatedIdentifiers.java
new file mode 100644
index 0000000..bbc2227
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/DotSeparatedIdentifiers.java
@@ -0,0 +1,24 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * This is a string that is a valid {@linkplain
+ * org.checkerframework.checker.signature.qual.FullyQualifiedName fully qualified name} and a valid
+ * {@linkplain org.checkerframework.checker.signature.qual.BinaryName binary name}. It represents a
+ * non-array, non-inner, non-primitive class: dot-separated identifiers.
+ *
+ * <p>Examples: int, MyClass, java.lang, java.lang.Integer
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({DotSeparatedIdentifiersOrPrimitiveType.class, BinaryName.class})
+public @interface DotSeparatedIdentifiers {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/DotSeparatedIdentifiersOrPrimitiveType.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/DotSeparatedIdentifiersOrPrimitiveType.java
new file mode 100644
index 0000000..f50ce6c
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/DotSeparatedIdentifiersOrPrimitiveType.java
@@ -0,0 +1,25 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * This is a string that is a valid {@linkplain
+ * org.checkerframework.checker.signature.qual.FullyQualifiedName fully qualified name} and a valid
+ * {@linkplain org.checkerframework.checker.signature.qual.BinaryNameOrPrimitiveType binary name or
+ * primitive type}. It represents a primitive type or a non-array, non-inner class, where the latter
+ * is represented by dot-separated identifiers.
+ *
+ * <p>Examples: int, MyClass, java.lang.Integer
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({FullyQualifiedName.class, BinaryNameOrPrimitiveType.class})
+public @interface DotSeparatedIdentifiersOrPrimitiveType {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/FieldDescriptor.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/FieldDescriptor.java
new file mode 100644
index 0000000..a069898
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/FieldDescriptor.java
@@ -0,0 +1,34 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Represents a field descriptor (JVM type format) as defined in the <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.3.2">Java Virtual
+ * Machine Specification, section 4.3.2</a>.
+ *
+ * <p>For example, in
+ *
+ * <pre>
+ *  package org.checkerframework.checker.signature;
+ *  public class SignatureChecker {
+ *    private class Inner {}
+ *  }
+ * </pre>
+ *
+ * the field descriptors for the two types are
+ * Lorg/checkerframework/checker/signature/SignatureChecker; and
+ * Lorg/checkerframework/checker/signature/SignatureChecker$Inner; .
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(SignatureUnknown.class)
+public @interface FieldDescriptor {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/FieldDescriptorForPrimitive.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/FieldDescriptorForPrimitive.java
new file mode 100644
index 0000000..3b4bb26
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/FieldDescriptorForPrimitive.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Represents a field descriptor (JVM type format) for a primitive as defined in the <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.3.2">Java Virtual
+ * Machine Specification, section 4.3.2</a>.
+ *
+ * <p>Must be one of B, C, D, F, I, J, S, Z.
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({FieldDescriptorWithoutPackage.class, Identifier.class})
+public @interface FieldDescriptorForPrimitive {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/FieldDescriptorWithoutPackage.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/FieldDescriptorWithoutPackage.java
new file mode 100644
index 0000000..ac2817e
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/FieldDescriptorWithoutPackage.java
@@ -0,0 +1,26 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Represents a {@link FieldDescriptor field descriptor} for a primitive or for an array whose base
+ * type is primitive or in the unnamed package.
+ *
+ * <p>Examples: I [[J MyClass MyClass$22 [LMyClass; [LMyClass$22
+ *
+ * <p>Field descriptor (JVM type format) is defined in the <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.3.2">Java Virtual
+ * Machine Specification, section 4.3.2</a>.
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({ClassGetName.class, FieldDescriptor.class})
+public @interface FieldDescriptorWithoutPackage {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/FqBinaryName.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/FqBinaryName.java
new file mode 100644
index 0000000..32af0d6
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/FqBinaryName.java
@@ -0,0 +1,34 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An extension of binary name format to represent primitives and arrays. It is just like
+ * fully-qualified name format, but uses "$" rather than "." to indicate a nested class.
+ *
+ * <p>Examples include
+ *
+ * <pre>
+ *   int
+ *   int[][]
+ *   java.lang.String
+ *   java.lang.String[]
+ *   pkg.Outer$Inner
+ *   pkg.Outer$Inner[]
+ * </pre>
+ *
+ * <p>This is not a format defined by the Java language or platform, but is a convenient format for
+ * users to unambiguously specify a type.
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(SignatureUnknown.class)
+public @interface FqBinaryName {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/FullyQualifiedName.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/FullyQualifiedName.java
new file mode 100644
index 0000000..4ddb441
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/FullyQualifiedName.java
@@ -0,0 +1,49 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * A sequence of dot-separated identifiers, followed by any number of array square brackets.
+ * Represents a fully-qualified name as defined in the <a
+ * href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-6.html#jls-6.7">Java Language
+ * Specification, section 6.7</a>.
+ *
+ * <p>Examples:
+ *
+ * <pre>{@code
+ * int
+ * MyClass
+ * java.lang.Integer
+ * int[][]
+ * MyClass[]
+ * java.lang.Integer[][][]
+ * }</pre>
+ *
+ * <p>in
+ *
+ * <pre>
+ *  package org.checkerframework.checker.signature;
+ *  public class SignatureChecker {
+ *    private class Inner {}
+ *  }
+ * </pre>
+ *
+ * the fully-qualified names for the two types are
+ * org.checkerframework.checker.signature.SignatureChecker and
+ * org.checkerframework.checker.signature.SignatureChecker.Inner.
+ *
+ * <p>Fully-qualified names and {@linkplain BinaryName binary names} are the same for top-level
+ * classes and only differ by a '.' vs. '$' for inner classes.
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(FqBinaryName.class)
+public @interface FullyQualifiedName {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/Identifier.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/Identifier.java
new file mode 100644
index 0000000..c08108a
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/Identifier.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An identifier.
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@SubtypeOf({
+  DotSeparatedIdentifiers.class,
+  BinaryNameWithoutPackage.class,
+  IdentifierOrPrimitiveType.class
+})
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+public @interface Identifier {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/IdentifierOrPrimitiveType.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/IdentifierOrPrimitiveType.java
new file mode 100644
index 0000000..64313c8
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/IdentifierOrPrimitiveType.java
@@ -0,0 +1,21 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An identifier or a primitive type.
+ *
+ * <p>Example: Foobar, Baz22, int, float
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({ArrayWithoutPackage.class, DotSeparatedIdentifiersOrPrimitiveType.class})
+public @interface IdentifierOrPrimitiveType {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/InternalForm.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/InternalForm.java
new file mode 100644
index 0000000..cec44ee
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/InternalForm.java
@@ -0,0 +1,30 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The syntax for binary names that appears in a class file, as defined in the <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.2">JVM
+ * Specification, section 4.2</a>. A {@linkplain BinaryName binary name} is conceptually the name
+ * for the class or interface in a compiled binary, but the actual representation of that name in
+ * its class file is slightly different.
+ *
+ * <p>Internal form is the same as the binary name, but with periods ({@code .}) replaced by forward
+ * slashes ({@code /}).
+ *
+ * <p>Programmers more often use the binary name, leaving the internal form as a JVM implementation
+ * detail.
+ *
+ * @see BinaryName
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(SignatureUnknown.class)
+public @interface InternalForm {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/MethodDescriptor.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/MethodDescriptor.java
new file mode 100644
index 0000000..61f4e70
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/MethodDescriptor.java
@@ -0,0 +1,34 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Represents a method descriptor (JVM representation of method signature) as defined in the <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.3.3">Java Virtual
+ * Machine Specification, section 4.3.3</a>.
+ *
+ * <p>Example:
+ *
+ * <pre>
+ *  package edu.cs.washington;
+ *  public class BinaryName {
+ *    private class Inner {
+ *      public void method(Object obj, int i) {}
+ *    }
+ *  }
+ * </pre>
+ *
+ * In this example method descriptor for method 'method': (Ljava/lang/Object;I)Z
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(SignatureUnknown.class)
+public @interface MethodDescriptor {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/PolySignature.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/PolySignature.java
new file mode 100644
index 0000000..89c05ef
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/PolySignature.java
@@ -0,0 +1,25 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * A polymorphic qualifier for the Signature type system.
+ *
+ * <p>Any method written using {@code @PolySignature} conceptually has two versions: one in which
+ * every instance of {@code @PolySignature String} has been replaced by {@code @Signature String},
+ * and one in which every instance of {@code @PolySignature String} has been replaced by {@code
+ * String}.
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier(SignatureUnknown.class)
+public @interface PolySignature {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/PrimitiveType.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/PrimitiveType.java
new file mode 100644
index 0000000..9d1e72e
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/PrimitiveType.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * A primitive type. One of: boolean, byte, char, double, float, int, long, short.
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@SubtypeOf({IdentifierOrPrimitiveType.class, CanonicalName.class})
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+public @interface PrimitiveType {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/SignatureBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/SignatureBottom.java
new file mode 100644
index 0000000..67adb0e
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/SignatureBottom.java
@@ -0,0 +1,30 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the Signature String type system. Programmers should rarely write this type.
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@SubtypeOf({
+  FieldDescriptorForPrimitive.class,
+  PrimitiveType.class,
+  CanonicalNameAndBinaryName.class,
+  MethodDescriptor.class
+})
+@DefaultFor({TypeUseLocation.LOWER_BOUND})
+public @interface SignatureBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/SignatureUnknown.java b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/SignatureUnknown.java
new file mode 100644
index 0000000..ddac82f
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signature/qual/SignatureUnknown.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.signature.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Top qualifier in the type hierarchy.
+ *
+ * <p>This annotation may not be written in source code; it is an implementation detail of the
+ * checker.
+ *
+ * @checker_framework.manual #signature-checker Signature Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({}) // empty target prevents programmers from writing this in a program
+@DefaultQualifierInHierarchy
+@SubtypeOf({})
+public @interface SignatureUnknown {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/PolySigned.java b/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/PolySigned.java
new file mode 100644
index 0000000..d07dd51
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/PolySigned.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.signedness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * A polymorphic qualifier for the signedness type system.
+ *
+ * @checker_framework.manual #signedness-checker Signedness Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier(UnknownSignedness.class)
+public @interface PolySigned {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/Signed.java b/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/Signed.java
new file mode 100644
index 0000000..e316b1c
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/Signed.java
@@ -0,0 +1,43 @@
+package org.checkerframework.checker.signedness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TypeKind;
+import org.checkerframework.framework.qual.UpperBoundFor;
+
+/**
+ * The value is to be interpreted as signed. That is, if the most significant bit in the bitwise
+ * representation is set, then the bits should be interpreted as a negative number.
+ *
+ * @checker_framework.manual #signedness-checker Signedness Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({UnknownSignedness.class})
+@DefaultFor(
+    typeKinds = {
+      TypeKind.BYTE,
+      TypeKind.INT,
+      TypeKind.LONG,
+      TypeKind.SHORT,
+      TypeKind.FLOAT,
+      TypeKind.DOUBLE
+    },
+    types = {
+      java.lang.Byte.class,
+      java.lang.Integer.class,
+      java.lang.Long.class,
+      java.lang.Short.class,
+      java.lang.Float.class,
+      java.lang.Double.class
+    })
+@UpperBoundFor(
+    typeKinds = {TypeKind.FLOAT, TypeKind.DOUBLE},
+    types = {java.lang.Float.class, java.lang.Double.class})
+public @interface Signed {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/SignedPositive.java b/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/SignedPositive.java
new file mode 100644
index 0000000..ef4ef02
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/SignedPositive.java
@@ -0,0 +1,27 @@
+package org.checkerframework.checker.signedness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The expression's value is in the signed positive range; that is, its most significant bit is not
+ * set. The value has the same interpretation as {@link Signed} and {@link Unsigned} &mdash; both
+ * interpretations are equivalent.
+ *
+ * <p>Programmers should rarely write {@code @SignedPositive}. Instead, the programmer should write
+ * {@link Signed} or {@link Unsigned} to indicate how the programmer intends the value to be
+ * interpreted.
+ *
+ * <p>Internally, this is translated to the {@code @}{@link SignednessGlb} annotation. This means
+ * that programmers do not see this annotation in error messages.
+ *
+ * @see SignednessGlb
+ * @checker_framework.manual #signedness-checker Signedness Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+public @interface SignedPositive {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/SignedPositiveFromUnsigned.java b/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/SignedPositiveFromUnsigned.java
new file mode 100644
index 0000000..ca17613
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/SignedPositiveFromUnsigned.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.signedness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The expression is {@code @}{@link SignedPositive}, and its value came from widening a value that
+ * is allowed to be interpreted as unsigned.
+ *
+ * <p>Programmers should rarely write this annotation.
+ *
+ * @see SignednessGlb
+ * @checker_framework.manual #signedness-checker Signedness Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({SignednessGlb.class})
+public @interface SignedPositiveFromUnsigned {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/SignednessBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/SignednessBottom.java
new file mode 100644
index 0000000..31b8a7c
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/SignednessBottom.java
@@ -0,0 +1,25 @@
+package org.checkerframework.checker.signedness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the Signedness type system. Programmers should rarely write this type.
+ *
+ * <p>This is the type of the {@code null} literal.
+ *
+ * @checker_framework.manual #signedness-checker Signedness Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@SubtypeOf({SignedPositiveFromUnsigned.class})
+public @interface SignednessBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/SignednessGlb.java b/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/SignednessGlb.java
new file mode 100644
index 0000000..1a7150d
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/SignednessGlb.java
@@ -0,0 +1,43 @@
+package org.checkerframework.checker.signedness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.LiteralKind;
+import org.checkerframework.framework.qual.QualifierForLiterals;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Client code may interpret the value either as {@link Signed} or as {@link Unsigned}. This
+ * primarily applies to values whose most significant bit is not set {@link SignedPositive}, and
+ * thus the value has the same interpretation as signed or unsigned.
+ *
+ * <p>As a special case, the Signedness Checker also applies this annotation to manifest literals.
+ * This permits a value like {@code -1} or {@code 255} or {@code 0xFF} to be used in both signed and
+ * unsigned contexts. The Signedness Checker has no way of knowing how a programmer intended a
+ * literal to be used, so it does not issue warnings for any uses of a literal. (An alternate design
+ * would require the programmer to explicitly annotate every manifest literal whose most significant
+ * bit is set. That might detect more errors, at the cost of much greater programmer annotation
+ * effort.)
+ *
+ * <p>The programmer should not write this annotation. Instead, the programmer should write {@link
+ * Signed} or {@link Unsigned} to indicate how the programmer intends the value to be interpreted.
+ * For a value whose most significant bit is not set and different clients may treat it differently
+ * (say, the return value of certain library routines, or certain constant fields), the programmer
+ * should write {@code @}{@link SignedPositive} instead of {@code @SignednessGlb}.
+ *
+ * <p>The "Glb" in the name stands for "greatest lower bound", because this type is the greatest
+ * lower bound of the types {@link Signed} and {@link Unsigned}; that is, this type is a subtype of
+ * both of those types.
+ *
+ * @see SignedPositive
+ * @checker_framework.manual #signedness-checker Signedness Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({Unsigned.class, Signed.class})
+@QualifierForLiterals({LiteralKind.INT, LiteralKind.LONG, LiteralKind.CHAR})
+public @interface SignednessGlb {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/UnknownSignedness.java b/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/UnknownSignedness.java
new file mode 100644
index 0000000..0049b7c
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/UnknownSignedness.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.signedness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * The value's signedness is not known to the Signedness Checker. This is also used for non-numeric
+ * values, which cannot have a signedness.
+ *
+ * @checker_framework.manual #signedness-checker Signedness Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface UnknownSignedness {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/Unsigned.java b/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/Unsigned.java
new file mode 100644
index 0000000..534c5ac
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/signedness/qual/Unsigned.java
@@ -0,0 +1,30 @@
+package org.checkerframework.checker.signedness.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TypeKind;
+import org.checkerframework.framework.qual.UpperBoundFor;
+
+/**
+ * The value is to be interpreted as unsigned. That is, if the most significant bit in the bitwise
+ * representation is set, then the bits should be interpreted as a large positive number rather than
+ * as a negative number.
+ *
+ * @checker_framework.manual #signedness-checker Signedness Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({UnknownSignedness.class})
+@DefaultFor(
+    typeKinds = {TypeKind.CHAR},
+    types = {java.lang.Character.class})
+@UpperBoundFor(
+    typeKinds = {TypeKind.CHAR},
+    types = {java.lang.Character.class})
+public @interface Unsigned {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/tainting/qual/PolyTainted.java b/checker-qual/src/main/java/org/checkerframework/checker/tainting/qual/PolyTainted.java
new file mode 100644
index 0000000..0f481e6
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/tainting/qual/PolyTainted.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.tainting.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * A polymorphic qualifier for the Tainting type system.
+ *
+ * @checker_framework.manual #tainting-checker Tainting Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier(Tainted.class)
+public @interface PolyTainted {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/tainting/qual/Tainted.java b/checker-qual/src/main/java/org/checkerframework/checker/tainting/qual/Tainted.java
new file mode 100644
index 0000000..bc523dc
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/tainting/qual/Tainted.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.tainting.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Denotes a possibly-tainted value: at run time, the value might be tainted or might be untainted.
+ *
+ * @see Untainted
+ * @see org.checkerframework.checker.tainting.TaintingChecker
+ * @checker_framework.manual #tainting-checker Tainting Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@DefaultQualifierInHierarchy
+@SubtypeOf({})
+public @interface Tainted {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/tainting/qual/Untainted.java b/checker-qual/src/main/java/org/checkerframework/checker/tainting/qual/Untainted.java
new file mode 100644
index 0000000..83d48f5
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/tainting/qual/Untainted.java
@@ -0,0 +1,25 @@
+package org.checkerframework.checker.tainting.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.LiteralKind;
+import org.checkerframework.framework.qual.QualifierForLiterals;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * Denotes a reference that is untainted, i.e. can be trusted.
+ *
+ * @checker_framework.manual #tainting-checker Tainting Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Tainted.class)
+@QualifierForLiterals(LiteralKind.STRING)
+@DefaultFor(TypeUseLocation.LOWER_BOUND)
+public @interface Untainted {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/A.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/A.java
new file mode 100644
index 0000000..ce46d19
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/A.java
@@ -0,0 +1,21 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Ampere.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Current.class)
+public @interface A {
+  Prefix value() default Prefix.one;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Acceleration.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Acceleration.java
new file mode 100644
index 0000000..fcd64b6
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Acceleration.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Units of acceleration.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownUnits.class)
+public @interface Acceleration {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Angle.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Angle.java
new file mode 100644
index 0000000..bc764db
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Angle.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Units of measure for angles.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownUnits.class)
+public @interface Angle {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Area.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Area.java
new file mode 100644
index 0000000..14dcf93
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Area.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Units of areas.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownUnits.class)
+public @interface Area {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/C.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/C.java
new file mode 100644
index 0000000..bdda8f0
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/C.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Degree Centigrade (Celsius).
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Temperature.class)
+public @interface C {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Current.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Current.java
new file mode 100644
index 0000000..fc49e8c
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Current.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Electric current.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownUnits.class)
+public @interface Current {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Force.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Force.java
new file mode 100644
index 0000000..0152b30
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Force.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Units of force.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownUnits.class)
+public @interface Force {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/K.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/K.java
new file mode 100644
index 0000000..a00b979
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/K.java
@@ -0,0 +1,21 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Kelvin (unit of temperature).
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Temperature.class)
+public @interface K {
+  Prefix value() default Prefix.one;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Length.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Length.java
new file mode 100644
index 0000000..994acf2
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Length.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Units of length.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownUnits.class)
+public @interface Length {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Luminance.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Luminance.java
new file mode 100644
index 0000000..0d7dd66
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Luminance.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Units of luminance.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownUnits.class)
+public @interface Luminance {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Mass.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Mass.java
new file mode 100644
index 0000000..b0337b2
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Mass.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Units of mass.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownUnits.class)
+public @interface Mass {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/MixedUnits.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/MixedUnits.java
new file mode 100644
index 0000000..08dcc37
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/MixedUnits.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * MixedUnits is the result of multiplying or dividing units, where no more specific unit is known
+ * from a UnitsRelations implementation.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({}) // forbids a programmer from writing it in a program
+@SubtypeOf(UnknownUnits.class)
+public @interface MixedUnits {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/N.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/N.java
new file mode 100644
index 0000000..1e91a14
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/N.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Newton.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Force.class)
+@SuppressWarnings("checkstyle:typename")
+public @interface N {
+  Prefix value() default Prefix.one;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/PolyUnit.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/PolyUnit.java
new file mode 100644
index 0000000..0435cb4
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/PolyUnit.java
@@ -0,0 +1,44 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * A polymorphic qualifier for the units-of-measure type system implemented by the Units Checker.
+ *
+ * <p>Any method written using @PolyUnit conceptually has many versions: in each one, every instance
+ * of @PolyUnit has been replaced by a different unit qualifier such as @kg (kilograms) or @h
+ * (hours).
+ *
+ * <p>The following example shows how method {@code triplePolyUnit} can be used to process either
+ * meters or seconds:
+ *
+ * <pre><code>
+ * {@literal @}PolyUnit int triplePolyUnit(@PolyUnit int amount) {
+ *    return 3*amount;
+ *  }
+ *
+ *  void testPolyUnit() {
+ *   {@literal @}m int m1 = 7 * UnitsTools.m;
+ *   {@literal @}m int m2 = triplePolyUnit(m1);
+ *
+ *   {@literal @}s int sec1 = 7 * UnitsTools.s;
+ *   {@literal @}s int sec2 = triplePolyUnit(sec1);
+ *
+ *    // :: error: (assignment)
+ *   {@literal @}s int sec3 = triplePolyUnit(m1);
+ *  }
+ * </code></pre>
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier(UnknownUnits.class)
+public @interface PolyUnit {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Prefix.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Prefix.java
new file mode 100644
index 0000000..0f1a7b8
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Prefix.java
@@ -0,0 +1,78 @@
+package org.checkerframework.checker.units.qual;
+
+/**
+ * SI prefixes.
+ *
+ * <p>From <a
+ * href="https://en.wikipedia.org/wiki/SI_prefix">http://en.wikipedia.org/wiki/SI_prefix</a>:
+ *
+ * <pre>
+ * yotta   Y   1000^8     10^24    1000000000000000000000000   Septillion      Quadrillion     1991
+ * zetta   Z   1000^7     10^21    1000000000000000000000      Sextillion      Trilliard       1991
+ * exa     E   1000^6     10^18    1000000000000000000         Quintillion     Trillion        1975
+ * peta    P   1000^5     10^15    1000000000000000            Quadrillion     Billiard        1975
+ * tera    T   1000^4     10^12    1000000000000               Trillion        Billion         1960
+ * giga    G   1000^3     10^9     1000000000                  Billion         Milliard        1960
+ * mega    M   1000^2     10^6     1000000                     Million                         1960
+ * kilo    k   1000^1     10^3     1000                        Thousand                        1795
+ * hecto   h   1000^2/3   10^2     100                         Hundred                         1795
+ * deca    da  1000^1/3   10^1     10                          Ten                             1795
+ * 1000^0     10^0     1                           One
+ * deci    d   1000^-1/3  10^-1    0.1                         Tenth                           1795
+ * centi   c   1000^-2/3  10^-2    0.01                        Hundredth                       1795
+ * milli   m   1000^-1    10^-3    0.001                       Thousandth                      1795
+ * micro   my  1000^-2    10^-6    0.000001                    Millionth                       1960
+ * nano    n   1000^-3    10^-9    0.000000001                 Billionth       Milliardth      1960
+ * pico    p   1000^-4    10^-12   0.000000000001              Trillionth      Billionth       1960
+ * femto   f   1000^-5    10^-15   0.000000000000001           Quadrillionth   Billiardth      1964
+ * atto    a   1000^-6    10^-18   0.000000000000000001        Quintillionth   Trillionth      1964
+ * zepto   z   1000^-7    10^-21   0.000000000000000000001     Sextillionth    Trilliardth     1991
+ * yocto   y   1000^-8    10^-24   0.000000000000000000000001  Septillionth    Quadrillionth   1991
+ * </pre>
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+public enum Prefix {
+  /** SI prefix for 10^24. */
+  yotta,
+  /** SI prefix for 10^21. */
+  zetta,
+  /** SI prefix for 10^18. */
+  exa,
+  /** SI prefix for 10^15. */
+  peta,
+  /** SI prefix for 10^12. */
+  tera,
+  /** SI prefix for 10^9. */
+  giga,
+  /** SI prefix for 10^6. */
+  mega,
+  /** SI prefix for 10^3. */
+  kilo,
+  /** SI prefix for 10^2. */
+  hecto,
+  /** SI prefix for 10^1. */
+  deca,
+  /** SI prefix for 10^0, or 1. */
+  one,
+  /** SI prefix for 10^-1. */
+  deci,
+  /** SI prefix for 10^-2. */
+  centi,
+  /** SI prefix for 10^-3. */
+  milli,
+  /** SI prefix for 10^-6. */
+  micro,
+  /** SI prefix for 10^-9. */
+  nano,
+  /** SI prefix for 10^-12. */
+  pico,
+  /** SI prefix for 10^-15. */
+  femto,
+  /** SI prefix for 10^-18. */
+  atto,
+  /** SI prefix for 10^-21. */
+  zepto,
+  /** SI prefix for 10^-24. */
+  yocto
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Speed.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Speed.java
new file mode 100644
index 0000000..94fe348
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Speed.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Units of speed.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownUnits.class)
+public @interface Speed {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Substance.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Substance.java
new file mode 100644
index 0000000..214f981
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Substance.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Units of substance, such as mole (@{@link mol}).
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownUnits.class)
+public @interface Substance {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Temperature.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Temperature.java
new file mode 100644
index 0000000..e251f8c
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Temperature.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Units of temperature.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownUnits.class)
+public @interface Temperature {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Time.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Time.java
new file mode 100644
index 0000000..ecf7b91
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Time.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Units of time.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownUnits.class)
+public @interface Time {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/UnitsBottom.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/UnitsBottom.java
new file mode 100644
index 0000000..8e1f454
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/UnitsBottom.java
@@ -0,0 +1,25 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the Units type system. Programmers should rarely write this type.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@SubtypeOf({}) // needs to be done programmatically
+@DefaultFor(TypeUseLocation.LOWER_BOUND)
+public @interface UnitsBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/UnitsMultiple.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/UnitsMultiple.java
new file mode 100644
index 0000000..60942d4
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/UnitsMultiple.java
@@ -0,0 +1,32 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Define the relation between a base unit and the current unit.
+ *
+ * <p>TODO: add support for factors and more general formulas? E.g. it would be cool if the relation
+ * hour &rarr; minute and Fahrenheit &rarr; Celsius could be expressed.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+public @interface UnitsMultiple {
+  /**
+   * Returns the base unit to use.
+   *
+   * @return the base unit to use
+   */
+  Class<? extends Annotation> quantity();
+
+  /**
+   * Returns the scaling prefix.
+   *
+   * @return the scaling prefix
+   */
+  Prefix prefix() default Prefix.one;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/UnitsRelations.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/UnitsRelations.java
new file mode 100644
index 0000000..c8c0756
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/UnitsRelations.java
@@ -0,0 +1,29 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Specify the class that knows how to handle the meta-annotated unit when put in relation (plus,
+ * multiply, ...) with another unit. That class is a subtype of interface {@link
+ * org.checkerframework.checker.units.UnitsRelations}.
+ *
+ * @see org.checkerframework.checker.units.UnitsRelations
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+public @interface UnitsRelations {
+  /**
+   * Returns the subclass of {@link org.checkerframework.checker.units.UnitsRelations} to use.
+   *
+   * @return the subclass of {@link org.checkerframework.checker.units.UnitsRelations} to use
+   */
+  // The more precise type is Class<? extends org.checkerframework.checker.units.UnitsRelations>,
+  // but org.checkerframework.checker.units.UnitsRelations is not in checker-qual.jar, nor can
+  // it be since it uses AnnotatedTypeMirrors.  So this declaration uses a less precise type, and
+  // UnitsAnnotatedTypeFactory checks that the argument implements
+  // org.checkerframework.checker.units.UnitsRelations.
+  Class<?> value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/UnknownUnits.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/UnknownUnits.java
new file mode 100644
index 0000000..70d98c0
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/UnknownUnits.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * UnknownUnits is the top type of the type hierarchy.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@InvisibleQualifier
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface UnknownUnits {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Volume.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Volume.java
new file mode 100644
index 0000000..a387cc2
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/Volume.java
@@ -0,0 +1,19 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Units of volume.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(UnknownUnits.class)
+public @interface Volume {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/cd.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/cd.java
new file mode 100644
index 0000000..3952193
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/cd.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Candela (unit of luminance).
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Luminance.class)
+@SuppressWarnings("checkstyle:typename")
+public @interface cd {
+  Prefix value() default Prefix.one;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/degrees.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/degrees.java
new file mode 100644
index 0000000..a4d7ae6
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/degrees.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Degrees.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Angle.class)
+@SuppressWarnings("checkstyle:typename")
+public @interface degrees {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/g.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/g.java
new file mode 100644
index 0000000..54c0da1
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/g.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Gram.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Mass.class)
+@SuppressWarnings("checkstyle:typename")
+public @interface g {
+  Prefix value() default Prefix.one;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/h.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/h.java
new file mode 100644
index 0000000..6a568a9
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/h.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Hour.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Time.class)
+// TODO: support arbitrary factors?
+// @UnitsMultiple(quantity=s.class, factor=3600)
+@SuppressWarnings("checkstyle:typename")
+public @interface h {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/kN.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/kN.java
new file mode 100644
index 0000000..fc8e99b
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/kN.java
@@ -0,0 +1,21 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Kilonewton.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Force.class)
+@UnitsMultiple(quantity = N.class, prefix = Prefix.kilo)
+@SuppressWarnings("checkstyle:typename")
+public @interface kN {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/kg.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/kg.java
new file mode 100644
index 0000000..714cdfb
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/kg.java
@@ -0,0 +1,21 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Kilogram.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Mass.class)
+@UnitsMultiple(quantity = g.class, prefix = Prefix.kilo)
+@SuppressWarnings("checkstyle:typename")
+public @interface kg {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/km.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/km.java
new file mode 100644
index 0000000..c2cb32d
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/km.java
@@ -0,0 +1,21 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Kilometer.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Length.class)
+@UnitsMultiple(quantity = m.class, prefix = Prefix.kilo)
+@SuppressWarnings("checkstyle:typename")
+public @interface km {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/km2.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/km2.java
new file mode 100644
index 0000000..590d0fe
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/km2.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Square kilometer.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Area.class)
+@SuppressWarnings("checkstyle:typename")
+public @interface km2 {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/km3.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/km3.java
new file mode 100644
index 0000000..8dc4f86
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/km3.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Cubic kilometer.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Volume.class)
+@SuppressWarnings("checkstyle:typename")
+public @interface km3 {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/kmPERh.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/kmPERh.java
new file mode 100644
index 0000000..28abf4b
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/kmPERh.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Kilometer per hour.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Speed.class)
+@SuppressWarnings("checkstyle:typename")
+public @interface kmPERh {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/m.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/m.java
new file mode 100644
index 0000000..0b9da5c
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/m.java
@@ -0,0 +1,27 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Meter.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Length.class)
+// This is the default:
+// @UnitsRelations(org.checkerframework.checker.units.UnitsRelationsDefault.class)
+// If you want an alias for "m", e.g. "Meter", simply create that
+// annotation and add this meta-annotation:
+// @UnitsMultiple(quantity=m.class, prefix=Prefix.one)
+@SuppressWarnings("checkstyle:typename")
+public @interface m {
+  Prefix value() default Prefix.one;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/m2.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/m2.java
new file mode 100644
index 0000000..dc4473d
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/m2.java
@@ -0,0 +1,23 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Square meter.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Area.class)
+@SuppressWarnings("checkstyle:typename")
+public @interface m2 {
+  // does this make sense? Is it multiple of (m^2)? Or (multiple of m)^2?
+  Prefix value() default Prefix.one;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/m3.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/m3.java
new file mode 100644
index 0000000..48de6bb
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/m3.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Cubic meter.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Volume.class)
+@SuppressWarnings("checkstyle:typename")
+public @interface m3 {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/mPERs.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/mPERs.java
new file mode 100644
index 0000000..b626b34
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/mPERs.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Meter per second.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Speed.class)
+@SuppressWarnings("checkstyle:typename")
+public @interface mPERs {
+  Prefix value() default Prefix.one;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/mPERs2.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/mPERs2.java
new file mode 100644
index 0000000..71f2440
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/mPERs2.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Meter per second squared.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Acceleration.class)
+@SuppressWarnings("checkstyle:typename")
+public @interface mPERs2 {
+  Prefix value() default Prefix.one;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/min.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/min.java
new file mode 100644
index 0000000..b729aa0
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/min.java
@@ -0,0 +1,21 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Minute.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Time.class)
+@SuppressWarnings("checkstyle:typename")
+// TODO: @UnitsMultiple(quantity=s.class, factor=60)
+public @interface min {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/mm.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/mm.java
new file mode 100644
index 0000000..dff9961
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/mm.java
@@ -0,0 +1,21 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Millimeter.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Length.class)
+@UnitsMultiple(quantity = m.class, prefix = Prefix.milli)
+@SuppressWarnings("checkstyle:typename")
+public @interface mm {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/mm2.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/mm2.java
new file mode 100644
index 0000000..2e55698
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/mm2.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Square millimeter.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Area.class)
+@SuppressWarnings("checkstyle:typename")
+public @interface mm2 {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/mm3.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/mm3.java
new file mode 100644
index 0000000..dc84f01
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/mm3.java
@@ -0,0 +1,20 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Cubic millimeter.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Volume.class)
+@SuppressWarnings("checkstyle:typename")
+public @interface mm3 {}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/mol.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/mol.java
new file mode 100644
index 0000000..a1ea94e
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/mol.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Mole (unit of {@link Substance}).
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Substance.class)
+@SuppressWarnings("checkstyle:typename")
+public @interface mol {
+  Prefix value() default Prefix.one;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/radians.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/radians.java
new file mode 100644
index 0000000..1493949
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/radians.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Radians.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Angle.class)
+@SuppressWarnings("checkstyle:typename")
+public @interface radians {
+  Prefix value() default Prefix.one;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/s.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/s.java
new file mode 100644
index 0000000..89b93fa
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/s.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * A second (1/60 of a minute).
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Time.class)
+@SuppressWarnings("checkstyle:typename")
+public @interface s {
+  Prefix value() default Prefix.one;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/checker/units/qual/t.java b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/t.java
new file mode 100644
index 0000000..ca254a0
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/checker/units/qual/t.java
@@ -0,0 +1,22 @@
+package org.checkerframework.checker.units.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Metric ton.
+ *
+ * @checker_framework.manual #units-checker Units Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf(Mass.class)
+// TODO: support arbitrary factors?
+// @UnitsMultiple(quantity=kg.class, factor=1000)
+@SuppressWarnings("checkstyle:typename")
+public @interface t {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/aliasing/qual/LeakedToResult.java b/checker-qual/src/main/java/org/checkerframework/common/aliasing/qual/LeakedToResult.java
new file mode 100644
index 0000000..1e692e3
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/aliasing/qual/LeakedToResult.java
@@ -0,0 +1,32 @@
+package org.checkerframework.common.aliasing.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * This annotation is used on a formal parameter to indicate that the parameter may be returned, but
+ * it is not otherwise leaked. (A parameter is leaked if it is stored in a field where it could be
+ * accessed later, and in that case this annotation would not apply.)
+ *
+ * <p>For example, the receiver parameter of {@link StringBuffer#append(String s)} is annotated as
+ * {@code @LeakedToResult}, because the method returns the updated receiver.
+ *
+ * <p>This annotation is currently trusted, not checked.
+ *
+ * @see NonLeaked
+ * @checker_framework.manual #aliasing-checker Aliasing Checker
+ */
+
+// This is a type qualifier because of a checker framework limitation (Issue 383), but its hierarchy
+// is ignored. Once the stub parser gets updated to read non-type-qualifiers annotations on stub
+// files, this annotation won't be a type qualifier anymore.
+
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE})
+@SubtypeOf({NonLeaked.class})
+public @interface LeakedToResult {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/aliasing/qual/MaybeAliased.java b/checker-qual/src/main/java/org/checkerframework/common/aliasing/qual/MaybeAliased.java
new file mode 100644
index 0000000..241fdcb
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/aliasing/qual/MaybeAliased.java
@@ -0,0 +1,28 @@
+package org.checkerframework.common.aliasing.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * An expression with this type might have an alias. In other words, some other expression,
+ * evaluated at the same program point, might evaluate to the exact same object value.
+ *
+ * @see Unique
+ * @checker_framework.manual #aliasing-checker Aliasing Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+@DefaultFor(
+    value = {TypeUseLocation.UPPER_BOUND, TypeUseLocation.LOWER_BOUND},
+    types = Void.class)
+public @interface MaybeAliased {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/aliasing/qual/MaybeLeaked.java b/checker-qual/src/main/java/org/checkerframework/common/aliasing/qual/MaybeLeaked.java
new file mode 100644
index 0000000..9038b6b
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/aliasing/qual/MaybeLeaked.java
@@ -0,0 +1,28 @@
+package org.checkerframework.common.aliasing.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Temporary type qualifier:
+ *
+ * <p>This is the default type qualifier for the Leaked hierarchy.
+ *
+ * <p>Once the stub parser gets updated to read non-type-qualifier annotations on stub files (Issue
+ * 383), this annotation can be removed, and {@link NonLeaked} and {@link LeakedToResult} can be
+ * made to be type annotations but not type qualifiers and not in a type hierarchy.
+ *
+ * @checker_framework.manual #aliasing-checker Aliasing Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({})
+@DefaultQualifierInHierarchy
+@SubtypeOf({LeakedToResult.class})
+@InvisibleQualifier
+public @interface MaybeLeaked {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/aliasing/qual/NonLeaked.java b/checker-qual/src/main/java/org/checkerframework/common/aliasing/qual/NonLeaked.java
new file mode 100644
index 0000000..3fca72c
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/aliasing/qual/NonLeaked.java
@@ -0,0 +1,31 @@
+package org.checkerframework.common.aliasing.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * This annotation is used on a formal parameter to indicate that the parameter is not leaked
+ * (stored in a location that could be accessed later) nor returned by the method body.
+ *
+ * <p>For example, the parameter of {@link String#String(String s)} is {@code @NonLeaked}, because
+ * the method only uses the parameter to make a copy of it.
+ *
+ * <p>This annotation is currently trusted, not checked.
+ *
+ * @see LeakedToResult
+ * @checker_framework.manual #aliasing-checker Aliasing Checker
+ */
+
+// This is a type qualifier because of a checker framework limitation (Issue 383), but its hierarchy
+// is ignored. Once the stub parser gets updated to read non-type-qualifiers annotations on stub
+// files, this annotation won't be a type qualifier anymore.
+
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE})
+@SubtypeOf({})
+public @interface NonLeaked {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/aliasing/qual/Unique.java b/checker-qual/src/main/java/org/checkerframework/common/aliasing/qual/Unique.java
new file mode 100644
index 0000000..6194511
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/aliasing/qual/Unique.java
@@ -0,0 +1,25 @@
+package org.checkerframework.common.aliasing.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An expression with this type has no aliases. In other words, no other expression, evaluated at
+ * the same program point, would evaluate to the exact same object value.
+ *
+ * <p>A constructor's return type should be annotated with {@code @Unique} if the constructor does
+ * not leak references to the constructed object. For example, the {@code String()} constructor
+ * return type is annotated as {@code @Unique}.
+ *
+ * @see MaybeAliased
+ * @checker_framework.manual #aliasing-checker Aliasing Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({MaybeAliased.class})
+public @interface Unique {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/initializedfields/qual/EnsuresInitializedFields.java b/checker-qual/src/main/java/org/checkerframework/common/initializedfields/qual/EnsuresInitializedFields.java
new file mode 100644
index 0000000..6c3c5ed
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/initializedfields/qual/EnsuresInitializedFields.java
@@ -0,0 +1,59 @@
+package org.checkerframework.common.initializedfields.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.InheritedAnnotation;
+import org.checkerframework.framework.qual.PostconditionAnnotation;
+import org.checkerframework.framework.qual.QualifierArgument;
+
+/**
+ * A method postcondition annotation indicates which fields the method definitely initializes.
+ *
+ * @checker_framework.manual #initialized-fields-checker Initialized Fields Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+@PostconditionAnnotation(qualifier = InitializedFields.class)
+@InheritedAnnotation
+@Repeatable(EnsuresInitializedFields.List.class)
+public @interface EnsuresInitializedFields {
+  /**
+   * The object whose fields this method initializes.
+   *
+   * @return object whose fields are initialized
+   */
+  public String[] value() default {"this"};
+
+  /**
+   * Fields that this method initializes.
+   *
+   * @return fields that this method initializes
+   */
+  @QualifierArgument("value")
+  public String[] fields();
+
+  /**
+   * A wrapper annotation that makes the {@link EnsuresInitializedFields} annotation repeatable.
+   *
+   * <p>Programmers generally do not need to write this. It is created by Java when a programmer
+   * writes more than one {@link EnsuresInitializedFields} annotation at the same location.
+   */
+  @Documented
+  @Retention(RetentionPolicy.RUNTIME)
+  @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+  @PostconditionAnnotation(qualifier = InitializedFields.class)
+  @InheritedAnnotation
+  @interface List {
+    /**
+     * Return the repeatable annotations.
+     *
+     * @return the repeatable annotations
+     */
+    EnsuresInitializedFields[] value();
+  }
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/initializedfields/qual/InitializedFields.java b/checker-qual/src/main/java/org/checkerframework/common/initializedfields/qual/InitializedFields.java
new file mode 100644
index 0000000..d83042c
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/initializedfields/qual/InitializedFields.java
@@ -0,0 +1,26 @@
+package org.checkerframework.common.initializedfields.qual;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * Indicates which fields have definitely been initialized.
+ *
+ * @checker_framework.manual #initialized-fields-checker Initialized Fields Checker
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface InitializedFields {
+  /**
+   * Fields that have been initialized.
+   *
+   * @return the initialized fields
+   */
+  public String[] value() default {};
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/initializedfields/qual/InitializedFieldsBottom.java b/checker-qual/src/main/java/org/checkerframework/common/initializedfields/qual/InitializedFieldsBottom.java
new file mode 100644
index 0000000..2f16939
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/initializedfields/qual/InitializedFieldsBottom.java
@@ -0,0 +1,21 @@
+package org.checkerframework.common.initializedfields.qual;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type qualifier for the Initialized Fields type system. It is the type of {@code null}.
+ * Programmers should rarely write this qualifier.
+ *
+ * @checker_framework.manual #initialized-fields-checker Initialized Fields Checker
+ */
+@SubtypeOf({InitializedFields.class})
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+public @interface InitializedFieldsBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/initializedfields/qual/PolyInitializedFields.java b/checker-qual/src/main/java/org/checkerframework/common/initializedfields/qual/PolyInitializedFields.java
new file mode 100644
index 0000000..1f25542
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/initializedfields/qual/PolyInitializedFields.java
@@ -0,0 +1,14 @@
+package org.checkerframework.common.initializedfields.qual;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * Polymorphic qualifier for the Initialized Fields type system.
+ *
+ * @checker_framework.manual #initialized-fields-checker Initialized Fields Checker
+ */
+@PolymorphicQualifier(InitializedFields.class)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+public @interface PolyInitializedFields {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/ClassBound.java b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/ClassBound.java
new file mode 100644
index 0000000..6f0d8cf
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/ClassBound.java
@@ -0,0 +1,26 @@
+package org.checkerframework.common.reflection.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * This represents a {@code Class<T>} object whose run-time value is equal to or a subtype of one of
+ * the arguments.
+ *
+ * @checker_framework.manual #methodval-and-classval-checkers ClassVal Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({UnknownClass.class})
+public @interface ClassBound {
+  /**
+   * The <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-13.html#jls-13.1">binary
+   * name</a> of the class or classes that upper-bound the values of this Class object.
+   */
+  String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/ClassVal.java b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/ClassVal.java
new file mode 100644
index 0000000..5d3ea55
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/ClassVal.java
@@ -0,0 +1,31 @@
+package org.checkerframework.common.reflection.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * This represents a {@link java.lang.Class Class&lt;T&gt;} object where the set of possible values
+ * of T is known at compile time. If only one argument is given, then the exact value of T is known.
+ * If more than one argument is given, then the value of T is one of those classes.
+ *
+ * @checker_framework.manual #methodval-and-classval-checkers ClassVal Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({UnknownClass.class})
+public @interface ClassVal {
+  /**
+   * The name of the type that this Class object represents. The name is a "fully-qualified binary
+   * name" ({@link org.checkerframework.checker.signature.qual.FqBinaryName}): a primitive or <a
+   * href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-13.html#jls-13.1">binary name</a>,
+   * possibly followed by some number of array brackets.
+   *
+   * @return the name of the type that this Class object represents
+   */
+  String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/ClassValBottom.java b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/ClassValBottom.java
new file mode 100644
index 0000000..757845f
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/ClassValBottom.java
@@ -0,0 +1,25 @@
+package org.checkerframework.common.reflection.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the ClassVal type system. Programmers should rarely write this type.
+ *
+ * @checker_framework.manual #methodval-and-classval-checkers ClassVal Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@InvisibleQualifier
+@SubtypeOf({ClassVal.class, ClassBound.class})
+public @interface ClassValBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/ForName.java b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/ForName.java
new file mode 100644
index 0000000..0a568e9
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/ForName.java
@@ -0,0 +1,21 @@
+package org.checkerframework.common.reflection.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for methods like {@code Class.forName}. Their signature is
+ *
+ * <pre><code>
+ * &nbsp;@ClassVal("name") Class method(@BinaryName String name) {...}
+ * </code></pre>
+ *
+ * @checker_framework.manual #reflection-resolution Reflection resolution
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface ForName {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/GetClass.java b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/GetClass.java
new file mode 100644
index 0000000..bd97c1a
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/GetClass.java
@@ -0,0 +1,18 @@
+package org.checkerframework.common.reflection.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for methods like {@code Object.getClassName}. Their signature is:<br>
+ * {@code @}{@link ClassBound}{@code ("ReceiverType") Class method(ReceiverType this) {...}}
+ *
+ * @checker_framework.manual #reflection-resolution Reflection resolution
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface GetClass {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/GetConstructor.java b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/GetConstructor.java
new file mode 100644
index 0000000..db4b9bc
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/GetConstructor.java
@@ -0,0 +1,19 @@
+package org.checkerframework.common.reflection.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for methods like {@code Class.getConstructor}, whose signature is: <br>
+ * {@code @}{@link MethodVal}{@code (classname=c, methodname="<init>", params=p) Constructor<T>
+ * method(Class<c> this, Object... params)}
+ *
+ * @checker_framework.manual #reflection-resolution Reflection resolution
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface GetConstructor {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/GetMethod.java b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/GetMethod.java
new file mode 100644
index 0000000..f1aba33
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/GetMethod.java
@@ -0,0 +1,20 @@
+package org.checkerframework.common.reflection.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for methods like {@code Class.getMethod} and {@code Class.getDeclaredMethod}, whose
+ * signature is: <br>
+ * {@code {@link MethodVal}(classname=c, methodname=m, params=p) Method getMyMethod(Class<c> this,
+ * String m, Object... params)}
+ *
+ * @checker_framework.manual #reflection-resolution Reflection resolution
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface GetMethod {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/Invoke.java b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/Invoke.java
new file mode 100644
index 0000000..431631c
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/Invoke.java
@@ -0,0 +1,19 @@
+package org.checkerframework.common.reflection.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for methods like {@code Method.invoke}, whose signature is: <br>
+ * {@code Object method({@link MethodVal}(classname=c, methodname=m, params=p) Method this, Object
+ * obj, Object... args)}
+ *
+ * @checker_framework.manual #reflection-resolution Reflection resolution
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface Invoke {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/MethodVal.java b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/MethodVal.java
new file mode 100644
index 0000000..451109c
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/MethodVal.java
@@ -0,0 +1,39 @@
+package org.checkerframework.common.reflection.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * This represents a set of {@link java.lang.reflect.Method Method} or {@link
+ * java.lang.reflect.Constructor Constructor} values. If an expression's type has
+ * {@code @MethodVal}, then the expression's run-time value is one of those values.
+ *
+ * <p>Each of {@code @MethodVal}'s argument lists must be of equal length, and { className[i],
+ * methodName[i], params[i] } represents one of the {@code Method} or {@code Constructor} values in
+ * the set.
+ *
+ * @checker_framework.manual #methodval-and-classval-checkers MethodVal Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({UnknownMethod.class})
+public @interface MethodVal {
+  /**
+   * The <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-13.html#jls-13.1">binary
+   * name</a> of the class that declares this method.
+   */
+  String[] className();
+
+  /**
+   * The name of the method that this Method object represents. Use {@code <init>} for constructors.
+   */
+  String[] methodName();
+
+  /** The number of parameters to the method. */
+  int[] params();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/MethodValBottom.java b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/MethodValBottom.java
new file mode 100644
index 0000000..c99f874
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/MethodValBottom.java
@@ -0,0 +1,25 @@
+package org.checkerframework.common.reflection.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the MethodVal type system. Programmers should rarely write this type.
+ *
+ * @checker_framework.manual #methodval-and-classval-checkers MethodVal Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@InvisibleQualifier
+@SubtypeOf({MethodVal.class})
+public @interface MethodValBottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/NewInstance.java b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/NewInstance.java
new file mode 100644
index 0000000..5efda6c
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/NewInstance.java
@@ -0,0 +1,19 @@
+package org.checkerframework.common.reflection.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for methods like {@code Constructor.newInstance}, whose signature is: <br>
+ * {@code T method(}{@link MethodVal}{@code (classname=c, methodname="<init>", params=p) Constructor
+ * this, Object... args)}
+ *
+ * @checker_framework.manual #reflection-resolution Reflection resolution
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface NewInstance {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/UnknownClass.java b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/UnknownClass.java
new file mode 100644
index 0000000..f89c5e9
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/UnknownClass.java
@@ -0,0 +1,29 @@
+package org.checkerframework.common.reflection.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * Represents a Class object whose run-time value is not known at compile time. Also represents
+ * non-Class values.
+ *
+ * <p>This annotation is the default in the hierarchy.
+ *
+ * @checker_framework.manual #methodval-and-classval-checkers ClassVal Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@InvisibleQualifier
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface UnknownClass {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/UnknownMethod.java b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/UnknownMethod.java
new file mode 100644
index 0000000..3454775
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/reflection/qual/UnknownMethod.java
@@ -0,0 +1,30 @@
+package org.checkerframework.common.reflection.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * Represents a {@link java.lang.reflect.Method Method} or {@link java.lang.reflect.Constructor
+ * Constructor} expression whose run-time value is not known at compile time. Also represents
+ * non-Method, non-Constructor values.
+ *
+ * <p>This annotation is the default in the hierarchy.
+ *
+ * @checker_framework.manual #methodval-and-classval-checkers MethodVal Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@InvisibleQualifier
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface UnknownMethod {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/returnsreceiver/qual/BottomThis.java b/checker-qual/src/main/java/org/checkerframework/common/returnsreceiver/qual/BottomThis.java
new file mode 100644
index 0000000..99dd4fc
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/returnsreceiver/qual/BottomThis.java
@@ -0,0 +1,22 @@
+package org.checkerframework.common.returnsreceiver.qual;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type for the Returns Receiver Checker's type system. Programmers should rarely write
+ * this type.
+ *
+ * @checker_framework.manual #returns-receiver-checker Returns Receiver Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@SubtypeOf({UnknownThis.class})
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+public @interface BottomThis {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/returnsreceiver/qual/This.java b/checker-qual/src/main/java/org/checkerframework/common/returnsreceiver/qual/This.java
new file mode 100644
index 0000000..4d30a59
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/returnsreceiver/qual/This.java
@@ -0,0 +1,47 @@
+package org.checkerframework.common.returnsreceiver.qual;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * Write {@code @This} on the return type of a method that always returns its receiver ({@code
+ * this}). For example:
+ *
+ * <pre><code>
+ * class MyBuilder {
+ *   &#064;This MyBuilder setName(String name) {
+ *     this.name = name;
+ *     return this;
+ *   }
+ * }
+ * </code></pre>
+ *
+ * <p>Strictly speaking, this is a polymorphic annotation, but when you write it on a return type,
+ * the Returns Receiver Checker automatically adds it to the receiver, so the above method is
+ * equivalent to:
+ *
+ * <pre><code>
+ * &#064;This MyBuilder setName(@This MyBuilder this, String name) {
+ *   this.name = name;
+ *   return this;
+ * }
+ * </code></pre>
+ *
+ * <p>While it would be natural to make {@code @This} the default annotation for receivers, it leads
+ * to false positives warnings due to <a
+ * href="https://github.com/typetools/checker-framework/issues/2931">https://github.com/typetools/checker-framework/issues/2931</a>,
+ * so this defaulting is currently elided.
+ *
+ * @checker_framework.manual #returns-receiver-checker Returns Receiver Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier
+@TargetLocations({TypeUseLocation.RECEIVER, TypeUseLocation.RETURN})
+public @interface This {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/returnsreceiver/qual/UnknownThis.java b/checker-qual/src/main/java/org/checkerframework/common/returnsreceiver/qual/UnknownThis.java
new file mode 100644
index 0000000..6d1d282
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/returnsreceiver/qual/UnknownThis.java
@@ -0,0 +1,26 @@
+package org.checkerframework.common.returnsreceiver.qual;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultFor;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.LiteralKind;
+import org.checkerframework.framework.qual.QualifierForLiterals;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The top type for the Returns Receiver Checker's type system. Values of the annotated type might
+ * be the receiver ({@code this}) or might not. Programmers should rarely write this type.
+ *
+ * @checker_framework.manual #returns-receiver-checker Returns Receiver Checker
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@DefaultQualifierInHierarchy
+@SubtypeOf({})
+@QualifierForLiterals(LiteralKind.NULL)
+@DefaultFor(value = TypeUseLocation.LOWER_BOUND)
+public @interface UnknownThis {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/subtyping/qual/Bottom.java b/checker-qual/src/main/java/org/checkerframework/common/subtyping/qual/Bottom.java
new file mode 100644
index 0000000..b60bf2f
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/subtyping/qual/Bottom.java
@@ -0,0 +1,32 @@
+package org.checkerframework.common.subtyping.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * A special annotation intended solely for representing the bottom type in the qualifier hierarchy.
+ * It should not be used! Instead, each type system should define its own dedicated bottom type.
+ *
+ * <p>This qualifier is used automatically if the existing qualifiers do not have a bottom type.
+ * This only works the user never runs two type systems together. Furthermore, because it has no
+ * {@code @RetentionPolicy} meta-annotation, this qualifier will not be stored in bytecode. So, only
+ * use this qualifier during prototyping of very simple type systems. For realistic systems,
+ * introduce a top and bottom qualifier that gets stored in bytecode.
+ *
+ * <p>To use this qualifier, the type system designer needs to use methods like {@code
+ * org.checkerframework.framework.type.treeannotator.ImplicitsTreeAnnotator#addTreeKind(com.sun.source.tree.Tree.Kind,
+ * javax.lang.model.element.AnnotationMirror)} to add default annotations and needs to manually add
+ * the bottom qualifier to the qualifier hierarchy.
+ *
+ * @see org.checkerframework.framework.type.QualifierHierarchy#getBottomAnnotations()
+ * @checker_framework.manual #subtyping-checker Subtyping Checker
+ */
+@Documented
+@SubtypeOf({})
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+public @interface Bottom {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/subtyping/qual/Unqualified.java b/checker-qual/src/main/java/org/checkerframework/common/subtyping/qual/Unqualified.java
new file mode 100644
index 0000000..df08edb
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/subtyping/qual/Unqualified.java
@@ -0,0 +1,27 @@
+package org.checkerframework.common.subtyping.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * A special annotation intended solely for representing an unqualified type in the qualifier
+ * hierarchy, as an argument to {@link SubtypeOf#value()}, in a type qualifier declaration.
+ *
+ * <p>This annotation may not be written in source code; it is an implementation detail of the
+ * checker.
+ *
+ * <p>Use this qualifier only when experimenting with very simple type systems. For any more
+ * realistic type systems, introduce a top and bottom qualifier that gets stored in bytecode.
+ *
+ * @checker_framework.manual #subtyping-checker Subtyping Checker
+ */
+@Documented
+@Retention(RetentionPolicy.SOURCE) // don't store in class file
+@Target({}) // empty target prevents programmers from writing this in a program.
+@InvisibleQualifier
+@SubtypeOf({})
+public @interface Unqualified {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportCall.java b/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportCall.java
new file mode 100644
index 0000000..e680208
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportCall.java
@@ -0,0 +1,22 @@
+package org.checkerframework.common.util.report.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Report all calls of a method that has this annotation, including calls of methods that override
+ * this method. Note that calls through a supertype, where the method is not annotated, cannot be
+ * reported.
+ *
+ * <p>For example, assume three classes A, B, and C, that each implement/override a method m and A
+ * &lt;: B &lt;: C. Assume that B.m is annotated as ReportCall. Calls of A.m and B.m will then be
+ * reported, but calls of C.m will not be reported, even though the C reference might point to a B
+ * object. Therefore, add the ReportCall annotation high enough in the subtype hierarchy.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface ReportCall {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportCreation.java b/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportCreation.java
new file mode 100644
index 0000000..689691c
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportCreation.java
@@ -0,0 +1,17 @@
+package org.checkerframework.common.util.report.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Report all instantiations of a class/interface that has this annotation, including any subclass.
+ * Report all invocations of a particular constructor. (There is no overriding of constructors, so
+ * use on a constructor reports only that particular constructor.)
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.CONSTRUCTOR})
+public @interface ReportCreation {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportInherit.java b/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportInherit.java
new file mode 100644
index 0000000..f3582f0
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportInherit.java
@@ -0,0 +1,13 @@
+package org.checkerframework.common.util.report.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Report all types that extend/implement a type that has this annotation. */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface ReportInherit {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportOverride.java b/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportOverride.java
new file mode 100644
index 0000000..2dfebef
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportOverride.java
@@ -0,0 +1,13 @@
+package org.checkerframework.common.util.report.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Report all methods that override a method with this annotation. */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface ReportOverride {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportReadWrite.java b/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportReadWrite.java
new file mode 100644
index 0000000..2fe0532
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportReadWrite.java
@@ -0,0 +1,13 @@
+package org.checkerframework.common.util.report.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Report all read or write access to a field with this annotation. */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface ReportReadWrite {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportUnqualified.java b/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportUnqualified.java
new file mode 100644
index 0000000..2354cef
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportUnqualified.java
@@ -0,0 +1,22 @@
+package org.checkerframework.common.util.report.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An annotation intended solely for representing an unqualified type in the qualifier hierarchy for
+ * the Report Checker.
+ */
+@Documented
+@Retention(RetentionPolicy.SOURCE) // do not store in class file
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+@InvisibleQualifier
+public @interface ReportUnqualified {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportUse.java b/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportUse.java
new file mode 100644
index 0000000..91b7f64
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportUse.java
@@ -0,0 +1,13 @@
+package org.checkerframework.common.util.report.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Report all uses of a type that has this annotation. Can also be used on a package. */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PACKAGE, ElementType.TYPE})
+public @interface ReportUse {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportWrite.java b/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportWrite.java
new file mode 100644
index 0000000..f7bf265
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/util/report/qual/ReportWrite.java
@@ -0,0 +1,13 @@
+package org.checkerframework.common.util.report.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Report all write accesses to a field with this annotation. */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface ReportWrite {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/ArrayLen.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/ArrayLen.java
new file mode 100644
index 0000000..20b19a1
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/ArrayLen.java
@@ -0,0 +1,28 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An annotation indicating the length of an array or a string. If an expression's type has this
+ * annotation, then at run time, the expression evaluates to an array or a string whose length is
+ * one of the annotation's arguments.
+ *
+ * <p>For example, {@code String @ArrayLen(2) []} is the type for an array of two strings, and
+ * {@code String @ArrayLen({1, 2, 4, 8}) []} is the type for an array that contains 1, 2, 4, or 8
+ * strings.
+ *
+ * @checker_framework.manual #constant-value-checker Constant Value Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+@SubtypeOf({UnknownVal.class})
+public @interface ArrayLen {
+  /** The possible lengths of the array. */
+  int[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/ArrayLenRange.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/ArrayLenRange.java
new file mode 100644
index 0000000..4597c44
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/ArrayLenRange.java
@@ -0,0 +1,26 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An expression with this type evaluates to an array or a string whose length is in the given
+ * range. The bounds are inclusive; for example, {@code @ArrayLenRange(from=6, to=9)} represents an
+ * array or a string with four possible values for its length: 6, 7, 8, and 9.
+ *
+ * @checker_framework.manual #constant-value-checker Constant Value Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+@SubtypeOf(UnknownVal.class)
+public @interface ArrayLenRange {
+  /** Smallest value in the range, inclusive. */
+  int from() default 0;
+  /** Largest value in the range, inclusive. */
+  int to() default Integer.MAX_VALUE;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/BoolVal.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/BoolVal.java
new file mode 100644
index 0000000..66f5a7f
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/BoolVal.java
@@ -0,0 +1,23 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An annotation indicating the possible values for a bool type. If an expression's type has this
+ * annotation, then at run time, the expression evaluates to one of the annotation's arguments.
+ *
+ * @checker_framework.manual #constant-value-checker Constant Value Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+@SubtypeOf({UnknownVal.class})
+public @interface BoolVal {
+  /** The values that the expression might evaluate to. */
+  boolean[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/BottomVal.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/BottomVal.java
new file mode 100644
index 0000000..82a1243
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/BottomVal.java
@@ -0,0 +1,37 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.InvisibleQualifier;
+import org.checkerframework.framework.qual.SubtypeOf;
+import org.checkerframework.framework.qual.TargetLocations;
+import org.checkerframework.framework.qual.TypeUseLocation;
+
+/**
+ * The bottom type in the Constant Value type system. Programmers should rarely write this type.
+ *
+ * @checker_framework.manual #constant-value-checker Constant Value Checker
+ * @checker_framework.manual #bottom-type the bottom type
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND})
+@SubtypeOf({
+  ArrayLen.class,
+  BoolVal.class,
+  DoubleVal.class,
+  IntVal.class,
+  StringVal.class,
+  MatchesRegex.class,
+  ArrayLenRange.class,
+  IntRange.class,
+  IntRangeFromPositive.class,
+  IntRangeFromGTENegativeOne.class,
+  IntRangeFromNonNegative.class
+})
+@InvisibleQualifier
+public @interface BottomVal {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/DoubleVal.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/DoubleVal.java
new file mode 100644
index 0000000..1bfab7a
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/DoubleVal.java
@@ -0,0 +1,26 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An annotation indicating the possible values for a double or float type. If an expression's type
+ * has this annotation, then at run time, the expression evaluates to one of the annotation's
+ * arguments.
+ *
+ * <p>Annotation for values
+ *
+ * @checker_framework.manual #constant-value-checker Constant Value Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+@SubtypeOf({UnknownVal.class})
+public @interface DoubleVal {
+  /** The values that the expression might evaluate to. */
+  double[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/EnsuresMinLenIf.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/EnsuresMinLenIf.java
new file mode 100644
index 0000000..9fe5089
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/EnsuresMinLenIf.java
@@ -0,0 +1,74 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.ConditionalPostconditionAnnotation;
+import org.checkerframework.framework.qual.InheritedAnnotation;
+import org.checkerframework.framework.qual.QualifierArgument;
+
+/**
+ * Indicates that the value of the given expression is a sequence containing at least the given
+ * number of elements, if the method returns the given result (either true or false).
+ *
+ * <p>When the annotated method returns {@code result}, then all the expressions in {@code
+ * expression} are considered to be {@code MinLen(targetValue)}.
+ *
+ * @see MinLen
+ * @checker_framework.manual #constant-value-checker Constant Value Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+@ConditionalPostconditionAnnotation(qualifier = MinLen.class)
+@InheritedAnnotation
+@Repeatable(EnsuresMinLenIf.List.class)
+public @interface EnsuresMinLenIf {
+  /**
+   * Returns Java expression(s) that are a sequence with the given minimum length after the method
+   * returns {@link #result}.
+   *
+   * @return an array of Java expression(s), each of which is a sequence with the given minimum
+   *     length after the method returns {@link #result}
+   * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions
+   */
+  String[] expression();
+
+  /**
+   * Returns the return value of the method under which the postcondition to hold.
+   *
+   * @return the return value of the method under which the postcondition to hold
+   */
+  boolean result();
+
+  /**
+   * Returns the minimum number of elements in the sequence.
+   *
+   * @return the minimum number of elements in the sequence
+   */
+  @QualifierArgument("value")
+  int targetValue() default 0;
+
+  /**
+   * A wrapper annotation that makes the {@link EnsuresMinLenIf} annotation repeatable.
+   *
+   * <p>Programmers generally do not need to write this. It is created by Java when a programmer
+   * writes more than one {@link EnsuresMinLenIf} annotation at the same location.
+   */
+  @Documented
+  @Retention(RetentionPolicy.RUNTIME)
+  @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+  @ConditionalPostconditionAnnotation(qualifier = MinLen.class)
+  @InheritedAnnotation
+  @interface List {
+    /**
+     * Return the repeatable annotations.
+     *
+     * @return the repeatable annotations
+     */
+    EnsuresMinLenIf[] value();
+  }
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/EnumVal.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/EnumVal.java
new file mode 100644
index 0000000..c07b669
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/EnumVal.java
@@ -0,0 +1,29 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An annotation indicating the possible values for an enum type. If an expression's type has this
+ * annotation, then at run time, the expression evaluates to one of the enum values named by the
+ * arguments. EnumVal uses the simple name of the enum value: the EnumVal type corresponding to
+ * {@code MyEnum.MY_VALUE} is {@code @EnumVal("MY_VALUE")}.
+ *
+ * <p>This annotation is treated as {@link StringVal} internally by the Constant Value Checker.
+ *
+ * @checker_framework.manual #constant-value-checker Constant Value Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+public @interface EnumVal {
+  /**
+   * The simple names of the possible enum values for an expression with the annotated type.
+   *
+   * @return the simple names of the possible enum values for an expression with the annotated type
+   */
+  String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/IntRange.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/IntRange.java
new file mode 100644
index 0000000..be8de9d
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/IntRange.java
@@ -0,0 +1,33 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An expression with this type evaluates to an integral value (byte, short, char, int, or long) in
+ * the given range. The bounds are inclusive. For example, the following declaration allows the 12
+ * values 0, 1, ..., 11:
+ *
+ * <pre>{@code @IntRange(from=0, to=11) int month;}</pre>
+ *
+ * <p>If only one of the {@code to} and {@code from} fields is set, then the other will default to
+ * the max/min value of the type of the variable that is annotated. (In other words, the defaults
+ * {@code Long.MIN_VALUE} and {@code Long.MAX_VALUE} are used only for \code{long}; appropriate
+ * values are used for other types.)
+ *
+ * @checker_framework.manual #constant-value-checker Constant Value Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+@SubtypeOf(UnknownVal.class)
+public @interface IntRange {
+  /** Smallest value in the range, inclusive. */
+  long from() default Long.MIN_VALUE;
+  /** Largest value in the range, inclusive. */
+  long to() default Long.MAX_VALUE;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/IntRangeFromGTENegativeOne.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/IntRangeFromGTENegativeOne.java
new file mode 100644
index 0000000..fc65c4a
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/IntRangeFromGTENegativeOne.java
@@ -0,0 +1,33 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An expression with this type is exactly the same as an {@link IntRange} annotation whose {@code
+ * from} field is {@code -1} and whose {@code to} field is {@code Integer.MAX_VALUE}. However, this
+ * annotation is derived from an {@code org.checkerframework.checker.index.qual.GTENegativeOne}
+ * annotation.
+ *
+ * <p>IntRangeFromGTENegativeOne annotations derived from GTENegativeOne annotations are used to
+ * create IntRange annotations, but IntRangeFromGTENegativeOne annotations are not checked when they
+ * appear on the left hand side of expressions. Therefore, the Index Checker MUST be run on any code
+ * with @GTENegativeOne annotations on the left-hand side of expressions, since the Value Checker
+ * will derive information from them but not check them.
+ *
+ * <p>It is an error to write this annotation directly. {@code @GTENegativeOne} or {@code
+ * IntRange(from = -1, to = Integer.MAX_VALUE)} should always be written instead. This annotation is
+ * not retained in bytecode, but is replaced with {@code @UnknownVal}, so that it is not enforced on
+ * method boundaries. The {@code @GTENegativeOne} annotation it replaced is retained in bytecode by
+ * the Lower Bound Checker instead.
+ *
+ * @checker_framework.manual #constant-value-checker Constant Value Checker
+ */
+@Documented
+@Retention(RetentionPolicy.SOURCE)
+@Target({})
+@SubtypeOf(UnknownVal.class)
+public @interface IntRangeFromGTENegativeOne {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/IntRangeFromNonNegative.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/IntRangeFromNonNegative.java
new file mode 100644
index 0000000..434ff25
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/IntRangeFromNonNegative.java
@@ -0,0 +1,33 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An expression with this type is exactly the same as an {@link IntRange} annotation whose {@code
+ * from} field is {@code 0} and whose {@code to} field is {@code Integer.MAX_VALUE}. However, this
+ * annotation is derived from an {@code org.checkerframework.checker.index.qual.NonNegative}
+ * annotation.
+ *
+ * <p>IntRangeFromNonNegative annotations derived from NonNegative annotations are used to create
+ * IntRange annotations, but IntRangeFromNonNegative annotations are not checked when they appear on
+ * the left hand side of expressions. Therefore, the Index Checker MUST be run on any code
+ * with @NonNegative annotations on the left-hand side of expressions, since the Value Checker will
+ * derive information from them but not check them.
+ *
+ * <p>It is an error to write this annotation directly. {@code @NonNegative} or {@code IntRange(from
+ * = 0, to = Integer.MAX_VALUE)} should always be written instead. This annotation is not retained
+ * in bytecode, but is replaced with {@code @UnknownVal}, so that it is not enforced on method
+ * boundaries. The {@code @NonNegative} annotation it replaced is retained in bytecode by the Lower
+ * Bound Checker instead.
+ *
+ * @checker_framework.manual #constant-value-checker Constant Value Checker
+ */
+@Documented
+@Retention(RetentionPolicy.SOURCE)
+@Target({})
+@SubtypeOf(UnknownVal.class)
+public @interface IntRangeFromNonNegative {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/IntRangeFromPositive.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/IntRangeFromPositive.java
new file mode 100644
index 0000000..4941505
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/IntRangeFromPositive.java
@@ -0,0 +1,33 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An expression with this type is exactly the same as an {@link IntRange} annotation whose {@code
+ * from} field is {@code 1} and whose {@code to} field is {@code Integer.MAX_VALUE}. However, this
+ * annotation is derived from an {@code org.checkerframework.checker.index.qual.Positive}
+ * annotation.
+ *
+ * <p>IntRangeFromPositive annotations derived from Positive annotations are used to create IntRange
+ * annotations, but IntRangeFromPositive annotations are not checked when they appear on the left
+ * hand side of expressions. Therefore, the Index Checker MUST be run on any code with @Positive
+ * annotations on the left-hand side of expressions, since the Value Checker will derive information
+ * from them but not check them.
+ *
+ * <p>It is an error to write this annotation directly. {@code @Positive} or {@code IntRange(from =
+ * 1, to = Integer.MAX_VALUE)} should always be written instead. This annotation is not retained in
+ * bytecode, but is replaced with {@code @UnknownVal}, so that it is not enforced on method
+ * boundaries. The {@code @Positive} annotation it replaced is retained in bytecode by the Lower
+ * Bound Checker instead.
+ *
+ * @checker_framework.manual #constant-value-checker Constant Value Checker
+ */
+@Documented
+@Retention(RetentionPolicy.SOURCE)
+@Target({})
+@SubtypeOf(UnknownVal.class)
+public @interface IntRangeFromPositive {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/IntVal.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/IntVal.java
new file mode 100644
index 0000000..3ab290f
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/IntVal.java
@@ -0,0 +1,24 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An annotation indicating the possible values for a byte, short, char, int, or long type. If an
+ * expression's type has this annotation, then at run time, the expression evaluates to one of the
+ * annotation's arguments.
+ *
+ * @checker_framework.manual #constant-value-checker Constant Value Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+@SubtypeOf({UnknownVal.class})
+public @interface IntVal {
+  /** The values that the expression might evaluate to. */
+  long[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/MatchesRegex.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/MatchesRegex.java
new file mode 100644
index 0000000..76eee09
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/MatchesRegex.java
@@ -0,0 +1,32 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An annotation indicating the possible values for a String type. The annotation's arguments are
+ * Java regular expressions. If an expression's type has this annotation, then at run time, the
+ * expression evaluates to a string that matches at least one of the regular expressions. Matching
+ * is via the <a
+ * href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/String.html#matches(java.lang.String)">java.lang.String#matches</a>
+ * method, which matches against the entire string (it does not look for a match against a
+ * substring).
+ *
+ * @checker_framework.manual #constant-value-checker Constant Value Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+@SubtypeOf({UnknownVal.class})
+public @interface MatchesRegex {
+  /**
+   * A set of Java regular expressions.
+   *
+   * @return the regular expressions
+   */
+  String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/MinLen.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/MinLen.java
new file mode 100644
index 0000000..7384c2f
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/MinLen.java
@@ -0,0 +1,24 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The value of the annotated expression is a sequence containing at least the given number of
+ * elements. An alias for an {@link ArrayLenRange} annotation with a {@code from} field and the
+ * maximum possible value for an array length ({@code Integer.MAX_VALUE}) as its {@code to} field.
+ *
+ * <p>This annotation is used extensively by the Index Chcker.
+ *
+ * @checker_framework.manual #constant-value-checker Constant Value Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+public @interface MinLen {
+  /** The minimum number of elements in this sequence. */
+  int value() default 0;
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/MinLenFieldInvariant.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/MinLenFieldInvariant.java
new file mode 100644
index 0000000..bf12001
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/MinLenFieldInvariant.java
@@ -0,0 +1,34 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.FieldInvariant;
+
+/**
+ * A specialization of {@link FieldInvariant} for specifying the minimum length of an array. A class
+ * can be annotated with both this annotation and a {@link FieldInvariant} annotation.
+ *
+ * @checker_framework.manual #field-invariants Field invariants
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Inherited
+public @interface MinLenFieldInvariant {
+
+  /**
+   * Min length of the array. Must be greater than the min length of the array as declared in the
+   * superclass.
+   */
+  int[] minLen();
+
+  /**
+   * The field that has an array length qualifier in the class on which the field invariant is
+   * written. The field must be final and declared in a superclass.
+   */
+  String[] field();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/PolyValue.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/PolyValue.java
new file mode 100644
index 0000000..8ae998b
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/PolyValue.java
@@ -0,0 +1,20 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.PolymorphicQualifier;
+
+/**
+ * A polymorphic qualifier for the Constant Value Checker.
+ *
+ * @checker_framework.manual #constant-value-checker Constant Value Checker
+ * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
+@PolymorphicQualifier(UnknownVal.class)
+public @interface PolyValue {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/StaticallyExecutable.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/StaticallyExecutable.java
new file mode 100644
index 0000000..7dc91cb
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/StaticallyExecutable.java
@@ -0,0 +1,19 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * StaticallyExecutable is a method annotation that indicates that the compiler is allowed to run
+ * the method at compile time, if all of the method's arguments are compile-time constants. It is
+ * used by the Constant Value Checker.
+ *
+ * @checker_framework.manual #constant-value-checker Constant Value Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface StaticallyExecutable {}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/StringVal.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/StringVal.java
new file mode 100644
index 0000000..6f0ccb4
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/StringVal.java
@@ -0,0 +1,23 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * An annotation indicating the possible values for a String type. If an expression's type has this
+ * annotation, then at run time, the expression evaluates to one of the annotation's arguments.
+ *
+ * @checker_framework.manual #constant-value-checker Constant Value Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+@SubtypeOf({UnknownVal.class})
+public @interface StringVal {
+  /** The values that the expression might evaluate to. */
+  String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/common/value/qual/UnknownVal.java b/checker-qual/src/main/java/org/checkerframework/common/value/qual/UnknownVal.java
new file mode 100644
index 0000000..bcc6b9d
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/common/value/qual/UnknownVal.java
@@ -0,0 +1,22 @@
+package org.checkerframework.common.value.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.checkerframework.framework.qual.DefaultQualifierInHierarchy;
+import org.checkerframework.framework.qual.SubtypeOf;
+
+/**
+ * UnknownVal is a type annotation indicating that the expression's value is not known at compile
+ * type.
+ *
+ * @checker_framework.manual #constant-value-checker Constant Value Checker
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+@SubtypeOf({})
+@DefaultQualifierInHierarchy
+public @interface UnknownVal {}
diff --git a/checker-qual/src/main/java/org/checkerframework/dataflow/qual/Deterministic.java b/checker-qual/src/main/java/org/checkerframework/dataflow/qual/Deterministic.java
new file mode 100644
index 0000000..693898c
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/dataflow/qual/Deterministic.java
@@ -0,0 +1,92 @@
+package org.checkerframework.dataflow.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A method is called <em>deterministic</em> if it returns the same value (according to {@code ==})
+ * every time it is called with the same parameters and in the same environment. The parameters
+ * include the receiver, and the environment includes all of the Java heap (that is, all fields of
+ * all objects and all static variables).
+ *
+ * <p>Determinism refers to the return value during a non-exceptional execution. If a method throws
+ * an exception, the Throwable does not have to be exactly the same object on each invocation (and
+ * generally should not be, to capture the correct stack trace).
+ *
+ * <p>This annotation is important to pluggable type-checking because, after a call to a
+ * {@code @Deterministic} method, flow-sensitive type refinement can assume that anything learned
+ * about the first invocation is true about subsequent invocations (so long as no
+ * non-{@code @}{@link SideEffectFree} method call intervenes). For example, the following code
+ * never suffers a null pointer exception, so the Nullness Checker need not issue a warning:
+ *
+ * <pre>{@code
+ * if (x.myDeterministicMethod() != null) {
+ *   x.myDeterministicMethod().hashCode();
+ * }
+ * }</pre>
+ *
+ * <p>Note that {@code @Deterministic} guarantees that the result is identical according to {@code
+ * ==}, <b>not</b> just equal according to {@code equals()}. This means that writing
+ * {@code @Deterministic} on a method that returns a reference (including a String) is often
+ * erroneous unless the returned value is cached or interned.
+ *
+ * <p>Also see {@link Pure}, which means both deterministic and {@link SideEffectFree}.
+ *
+ * <p><b>Analysis:</b> The Checker Framework performs a conservative analysis to verify a
+ * {@code @Deterministic} annotation. The Checker Framework issues a warning if the method uses any
+ * of the following Java constructs:
+ *
+ * <ol>
+ *   <li>Assignment to any expression, except for local variables and method parameters.<br>
+ *       (Note that storing into an array element, such a {@code a[i] = x}, is not an assignment to
+ *       a variable and is therefore forbidden.)
+ *   <li>A method invocation of a method that is not {@link Deterministic}.
+ *   <li>Construction of a new object.
+ *   <li>Catching any exceptions. This restriction prevents a method from obtaining a reference to a
+ *       newly-created exception object and using these objects (or some property thereof) to change
+ *       the method's return value. For instance, the following method must be forbidden.
+ *       <!-- "<code>" instead of "{@code ...}" because of at-sign at beginning of line -->
+ *       <pre><code>@Deterministic
+ * int f() {
+ *   try {
+ *     int b = 0;
+ *     int a = 1/b;
+ *   } catch (Throwable t) {
+ *     return t.hashCode();
+ *   }
+ *   return 0;
+ * }
+ * </code></pre>
+ * </ol>
+ *
+ * When a constructor is annotated as {@code Deterministic} (or {@code @Pure}), that means that all
+ * the fields are deterministic (the same values, if the arguments are the same). The constructed
+ * object itself is different. That is, a constructor <em>invocation</em> is never deterministic
+ * since it returns a different new object each time.
+ *
+ * <p>Note that the rules for checking currently imply that every {@code Deterministic} method is
+ * also {@link SideEffectFree}. This might change in the future; in general, a deterministic method
+ * does not need to be side-effect-free.
+ *
+ * <p>These rules are conservative: any code that passes the checks is deterministic, but the
+ * Checker Framework may issue false positive warnings, for code that uses one of the forbidden
+ * constructs but is deterministic nonetheless.
+ *
+ * <p>In fact, the rules are so conservative that checking is currently disabled by default, but can
+ * be enabled via the {@code -AcheckPurityAnnotations} command-line option.
+ *
+ * <p>This annotation is inherited by subtypes, just as if it were meta-annotated with
+ * {@code @InheritedAnnotation}.
+ *
+ * @checker_framework.manual #type-refinement-purity Side effects, determinism, purity, and
+ *     flow-sensitive analysis
+ */
+// @InheritedAnnotation cannot be written here, because "dataflow" project cannot depend on
+// "framework" project.
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface Deterministic {}
diff --git a/checker-qual/src/main/java/org/checkerframework/dataflow/qual/Pure.java b/checker-qual/src/main/java/org/checkerframework/dataflow/qual/Pure.java
new file mode 100644
index 0000000..82cdb59
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/dataflow/qual/Pure.java
@@ -0,0 +1,37 @@
+package org.checkerframework.dataflow.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * {@code Pure} is a method annotation that means both {@link SideEffectFree} and {@link
+ * Deterministic}. The more important of these, when performing pluggable type-checking, is usually
+ * {@link SideEffectFree}.
+ *
+ * <p>For a discussion of the meaning of {@code Pure} on a constructor, see the documentation of
+ * {@link Deterministic}.
+ *
+ * <p>This annotation is inherited by subtypes, just as if it were meta-annotated with
+ * {@code @InheritedAnnotation}.
+ *
+ * @checker_framework.manual #type-refinement-purity Side effects, determinism, purity, and
+ *     flow-sensitive analysis
+ */
+// @InheritedAnnotation cannot be written here, because "dataflow" project cannot depend on
+// "framework" project.
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface Pure {
+  /** The type of purity. */
+  public static enum Kind {
+    /** The method has no visible side effects. */
+    SIDE_EFFECT_FREE,
+
+    /** The method returns exactly the same value when called in the same environment. */
+    DETERMINISTIC
+  }
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/dataflow/qual/SideEffectFree.java b/checker-qual/src/main/java/org/checkerframework/dataflow/qual/SideEffectFree.java
new file mode 100644
index 0000000..da33d80
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/dataflow/qual/SideEffectFree.java
@@ -0,0 +1,58 @@
+package org.checkerframework.dataflow.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A method is called <em>side-effect-free</em> if it has no visible side-effects, such as setting a
+ * field of an object that existed before the method was called.
+ *
+ * <p>Only the visible side effects are important. The method is allowed to cache the answer to a
+ * computationally expensive query, for instance. It is also allowed to modify newly-created
+ * objects, and a constructor is side-effect-free if it does not modify any objects that existed
+ * before it was called.
+ *
+ * <p>This annotation is important to pluggable type-checking because if some fact about an object
+ * is known before a call to such a method, then the fact is still known afterwards, even if the
+ * fact is about some non-final field. When any non-{@code @SideEffectFree} method is called, then a
+ * pluggable type-checker must assume that any field of any accessible object might have been
+ * modified, which annuls the effect of flow-sensitive type refinement and prevents the pluggable
+ * type-checker from making conclusions that are obvious to a programmer.
+ *
+ * <p>Also see {@link Pure}, which means both side-effect-free and {@link Deterministic}.
+ *
+ * <p><b>Analysis:</b> The Checker Framework performs a conservative analysis to verify a
+ * {@code @SideEffectFree} annotation. The Checker Framework issues a warning if the method uses any
+ * of the following Java constructs:
+ *
+ * <ol>
+ *   <li>Assignment to any expression, except for local variables and method parameters.<br>
+ *       (Note that storing into an array element, such a {@code a[i] = x}, is not an assignment to
+ *       a variable and is therefore forbidden.)
+ *   <li>A method invocation of a method that is not {@code @SideEffectFree}.
+ *   <li>Construction of a new object where the constructor is not {@code @SideEffectFree}.
+ * </ol>
+ *
+ * These rules are conservative: any code that passes the checks is side-effect-free, but the
+ * Checker Framework may issue false positive warnings, for code that uses one of the forbidden
+ * constructs but is side-effect-free nonetheless. In particular, a method that caches its result
+ * will be rejected.
+ *
+ * <p>In fact, the rules are so conservative that checking is currently disabled by default, but can
+ * be enabled via the {@code -AcheckPurityAnnotations} command-line option.
+ *
+ * <p>This annotation is inherited by subtypes, just as if it were meta-annotated with
+ * {@code @InheritedAnnotation}.
+ *
+ * @checker_framework.manual #type-refinement-purity Side effects, determinism, purity, and
+ *     flow-sensitive analysis
+ */
+// @InheritedAnnotation cannot be written here, because "dataflow" project cannot depend on
+// "framework" project.
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface SideEffectFree {}
diff --git a/checker-qual/src/main/java/org/checkerframework/dataflow/qual/TerminatesExecution.java b/checker-qual/src/main/java/org/checkerframework/dataflow/qual/TerminatesExecution.java
new file mode 100644
index 0000000..412c4be
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/dataflow/qual/TerminatesExecution.java
@@ -0,0 +1,39 @@
+package org.checkerframework.dataflow.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * {@code TerminatesExecution} is a method annotation that indicates that a method terminates the
+ * execution of the program. This can be used to annotate methods such as {@code System.exit()}, or
+ * methods that unconditionally throw an exception.
+ *
+ * <p>The annotation enables flow-sensitive type refinement to be more precise. For example, after
+ *
+ * <pre>
+ * if (x == null) {
+ *   System.err.println("Bad value supplied");
+ *   System.exit(1);
+ * }
+ * </pre>
+ *
+ * the Nullness Checker can determine that {@code x} is non-null.
+ *
+ * <p>The annotation is a <em>trusted</em> annotation, meaning that it is not checked whether the
+ * annotated method really does terminate the program.
+ *
+ * <p>This annotation is inherited by subtypes, just as if it were meta-annotated with
+ * {@code @InheritedAnnotation}.
+ *
+ * @checker_framework.manual #type-refinement Automatic type refinement (flow-sensitive type
+ *     qualifier inference)
+ */
+// @InheritedAnnotation cannot be written here, because "dataflow" project cannot depend on
+// "framework" project.
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface TerminatesExecution {}
diff --git a/checker-qual/src/main/java/org/checkerframework/framework/qual/AnnotatedFor.java b/checker-qual/src/main/java/org/checkerframework/framework/qual/AnnotatedFor.java
new file mode 100644
index 0000000..df857d2
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/framework/qual/AnnotatedFor.java
@@ -0,0 +1,41 @@
+package org.checkerframework.framework.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that this class has been annotated for the given type system. For example,
+ * {@code @AnnotatedFor({"nullness", "regex"})} indicates that the class has been annotated with
+ * annotations such as {@code @Nullable} and {@code @Regex}.
+ *
+ * <p>You should only use this annotation in a partially-annotated library. There is no point to
+ * using it in a fully-annotated library nor in an application that does not export APIs for
+ * clients.
+ *
+ * <p>This annotation has no effect unless the {@code
+ * -AuseConservativeDefaultsForUncheckedCode=source} command-line argument is supplied. Ordinarily,
+ * the {@code -AuseConservativeDefaultsForUncheckedCode=source} command-line argument causes
+ * unannotated locations to be defaulted using conservative defaults, and it suppresses all
+ * warnings. However, a class with a relevant {@code @AnnotatedFor} annotation is always defaulted
+ * normally (typically using the CLIMB-to-top rule), and typechecking warnings are issued.
+ *
+ * @checker_framework.manual #compiling-libraries Compiling partially-annotated libraries
+ */
+@Documented
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PACKAGE})
+public @interface AnnotatedFor {
+  /**
+   * Returns the type systems for which the class has been annotated. Legal arguments are any string
+   * that may be passed to the {@code -processor} command-line argument: the fully-qualified class
+   * name for the checker, or a shorthand for built-in checkers. Using the annotation with no
+   * arguments, as in {@code @AnnotatedFor({})}, has no effect.
+   *
+   * @return the type systems for which the class has been annotated
+   * @checker_framework.manual #shorthand-for-checkers Short names for built-in checkers
+   */
+  String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/framework/qual/CFComment.java b/checker-qual/src/main/java/org/checkerframework/framework/qual/CFComment.java
new file mode 100644
index 0000000..f9ef370
--- /dev/null
+++ b/checker-qual/src/main/java/org/checkerframework/framework/qual/CFComment.java
@@ -0,0 +1,41 @@
+package org.checkerframework.framework.qual;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This annotation is for comments related to the Checker Framework.
+ *
+ * <p>Using {@code @CFComment} makes it easy to find Checker-Framework-related comments, and to copy
+ * those comments from one version of a codebase to another (using the Annotation File Utilities).
+ *
+ * <p>Here is an example:
+ *
+ * <pre><code>
+ * {@literal @}CFComment("interning: factory methods guarantee that all elements are interned")
+ *  public class MyClass {
+ *   {@literal @}CFComment({"nullness: non-null return type is more specific than in superclass",
+ *                "signedness: comment related to Signedness type system"})
+ *    public String myMethod() { ... }
+ * }
+ * </code></pre>
+ *
+ * <p>As a matter of style, programmers should use this annotation on the most deeply nested element
+ * to which the comment applies (e.g., local variable rather than method, and method rather than
+ * class).
+ *
+ * @checker_framework.manual #library-tips-dont-change-the-code Don't change the code
+ */
+@Documented
+@Retention(RetentionPolicy.SOURCE)
+public @interface CFComment {
+  /**
+   * Comments about Checker Framework annotations. The text is not interpreted by the Checker
+   * Framework.
+   *
+   * <p>If you prefix each comment by the name of the type system, the comments are easier to
+   * understand and search for.
+   */
+  String[] value();
+}
diff --git a/checker-qual/src/main/java/org/checkerframework/framework/qual/ConditionalPostconditionAnnotation.java b/checker-qual/src/main/java/org/checkerframework/framework/qual/ConditionalPostconditionAnnotation.java
new file mode 100644
index 00