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 → method name | S && S | S || S | !S | (S)
+ *
+ * <p>The expression uses standard Java operator precedence: "!" then "&&" 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>
+ * @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("{1}", 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>
+ * @EnsuresLTLengthOfIf(
+ * expression = "end",
+ * result = true,
+ * targetValue = "array",
+ * offset = "#1 - 1"
+ * )
+ * public boolean tryShiftIndex(@NonNegative int x) {
+ * int newEnd = end - x;
+ * if (newEnd < 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(@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 < 0) {
+ * // index's type here is @NegativeIndexFor("array")
+ * index = index * -1;
+ * // now index's type is @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>
+ * @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 = ...;
+ *
+ * @EnsuresCalledMethods(value="this.socket", methods="close")
+ * public void stop() throws IOException {
+ * socket.close();
+ * }
+ *
+ * @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>
+ * @MustCall("close")
+ * class Socket {
+ * @MustCallAlias OutputStream getOutputStream(@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>
+ * @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>
+ * @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<>();
+ * }
+ * </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. */
+ * {@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>
+ * @EnsuresNonNullIf(expression="outputFile", result=true)
+ * @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 " " is to hide the at-signs from Javadoc. -->
+ *
+ * <pre>
+ * class MyClass {
+ * @Nullable Object field1;
+ * @Nullable Object field2;
+ *
+ * @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} — 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 → minute and Fahrenheit → 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<T>} 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>
+ * @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 {
+ * @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>
+ * @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
+ * <: B <: 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