diff --git a/.azure/Makefile b/.azure/Makefile new file mode 100644 index 00000000000..11283bbf72b --- /dev/null +++ b/.azure/Makefile @@ -0,0 +1,16 @@ +all default: azure-pipelines.yml + +%: %.m4 defs.m4 + @chmod -f +w $@ || true + m4 $< > $@ +# Squeeze multiple blank lines into one. + cat -s $@ > $@.tmp +# Remove leading blank lines. + sed '/[^[:blank:]]/,$$!d' $@.tmp > $@ +# Remove trailing blank lines. + sed -e :a -e '/^\s*$$/{$$d;N;ba' -e '}' $@ > $@.tmp + mv -f $@.tmp $@ + @chmod -w $@ + +clean: + rm -f azure-pipelines.yml diff --git a/.azure/azure-pipelines.yml b/.azure/azure-pipelines.yml new file mode 100644 index 00000000000..acf95469eda --- /dev/null +++ b/.azure/azure-pipelines.yml @@ -0,0 +1,396 @@ +# DO NOT EDIT azure-pipelines.yml. Edit azure-pipelines.yml.m4 and defs.m4 instead. + +variables: + system.debug: true + +jobs: + +- job: build_jdk + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk21-plus:latest + steps: + - bash: | + whoami + git config --get remote.origin.url + pwd + ls -al + env | sort + displayName: show environment + - bash: pwd && ls && bash ./configure --with-jtreg=/usr/share/jtreg --disable-warnings-as-errors + displayName: configure + - bash: make jdk + timeoutInMinutes: 90 + displayName: make jdk + ## This works only after `make images` + # - bash: build/*/images/jdk/bin/java -version + # displayName: version + ## Don't run tests, which pass only with old version of tools (compilers, etc.). + # - bash: make -C /jdk run-test-tier1 + # displayName: make run-test-tier1 + +- job: build_jdk21u + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk21-plus:latest + timeoutInMinutes: 0 + steps: + - bash: | + whoami + git config --get remote.origin.url + pwd + ls -al + env | sort + displayName: show environment + - bash: | + set -ex + if test -d /tmp/$USER/git-scripts ; \ + then git -C /tmp/$USER/git-scripts pull -q > /dev/null 2>&1 ; \ + else mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git ; \ + fi + displayName: git-scripts + - bash: | + set -ex + if test -d /tmp/$USER/plume-scripts ; \ + then git -C /tmp/$USER/plume-scripts pull -q > /dev/null 2>&1 ; \ + else mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/plume-scripts.git ; \ + fi + displayName: plume-scripts + # This creates ../jdk21u . + # Run `git-clone-related` without a limit on depth, because if the depth is + # too small, the merge will fail. Don't use "--filter=blob:none" because that + # leads to "fatal: remote error: filter 'combine' not supported". + - bash: | + set -ex + echo "pwd = $(pwd)" + if test -d ../jdk21u; then + echo "../jdk21u should not exist yet" + false + fi + df . + /tmp/$USER/git-scripts/git-clone-related typetools jdk21u ../jdk21u --single-branch + git config --global user.email "you@example.com" + git config --global user.name "Your Name" + git config --global core.longpaths true + git config --global core.protectNTFS false + cd ../jdk21u + git diff --exit-code + echo $? + displayName: clone-related-jdk21u + - bash: | + cd ../jdk21u && git status + eval $(/tmp/$USER/plume-scripts/ci-info typetools) + set + echo "About to run: git pull --no-edit https://github.com/${CI_ORGANIZATION}/jdk ${CI_BRANCH_NAME}" + displayName: git merge plan + - bash: | + set -ex + git config --global user.email "you@example.com" + git config --global user.name "Your Name" + git config --global pull.ff true + git config --global pull.rebase false + git config --global core.longpaths true + git config --global core.protectNTFS false + cd ../jdk21u && git status + eval $(/tmp/$USER/plume-scripts/ci-info typetools) + set + echo "About to run: git pull --no-edit https://github.com/${CI_ORGANIZATION}/jdk ${CI_BRANCH_NAME}" + cd ../jdk21u && git pull --no-edit https://github.com/${CI_ORGANIZATION}/jdk ${CI_BRANCH_NAME} || (git --version && git show | head -100 && git status && git diff | head -1000 && echo "Merge failed; see 'Pull request merge conflicts' at https://github.com/typetools/jdk/blob/master/README.md" && false) + displayName: git merge + - bash: cd ../jdk21u && export JT_HOME=/usr/share/jtreg && bash ./configure --with-jtreg --disable-warnings-as-errors + displayName: configure + - bash: cd ../jdk21u && make jdk + displayName: make jdk + ## This works only after `make images` + # - bash: cd ../jdk21u && build/*/images/jdk/bin/java -version + # displayName: version + # - bash: make -C /jdk21u run-test-tier1 + # timeoutInMinutes: 0 + # displayName: make run-test-tier1 + # - bash: make -C /jdk21u :test/jdk:tier1 + ## Temporarily comment out because of trouble finding junit and jasm + # - bash: cd ../jdk21u && make run-test TEST="jtreg:test/jdk:tier1" + # timeoutInMinutes: 0 + # displayName: make run-test + +- job: cftests_junit_jdk11 + timeoutInMinutes: 120 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk11:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-junit.sh) + displayName: test-cftests-junit.sh +- job: cftests_nonjunit_jdk11 + timeoutInMinutes: 120 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk11:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-nonjunit.sh) + displayName: test-cftests-nonjunit.sh +- job: cftests_inference_jdk11 + timeoutInMinutes: 120 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk11:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-inference.sh) + displayName: test-cftests-inference.sh +- job: cftests_typecheck_jdk11 + timeoutInMinutes: 120 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk11:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-typecheck.sh) + displayName: test-typecheck.sh +- job: cftests_junit_jdk17 + timeoutInMinutes: 120 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk17:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-junit.sh) + displayName: test-cftests-junit.sh +- job: cftests_nonjunit_jdk17 + timeoutInMinutes: 120 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk17:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-nonjunit.sh) + displayName: test-cftests-nonjunit.sh +- job: cftests_inference_jdk17 + timeoutInMinutes: 120 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk17:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-inference.sh) + displayName: test-cftests-inference.sh +- job: cftests_typecheck_jdk17 + timeoutInMinutes: 120 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk17:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-typecheck.sh) + displayName: test-typecheck.sh +- job: cftests_junit_jdk21 + timeoutInMinutes: 120 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk21:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-junit.sh) + displayName: test-cftests-junit.sh +- job: cftests_nonjunit_jdk21 + timeoutInMinutes: 120 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk21:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-nonjunit.sh) + displayName: test-cftests-nonjunit.sh +- job: cftests_inference_jdk21 + timeoutInMinutes: 120 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk21:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-inference.sh) + displayName: test-cftests-inference.sh +- job: cftests_typecheck_jdk21 + timeoutInMinutes: 120 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk21:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-typecheck.sh) + displayName: test-typecheck.sh +- job: cftests_junit_jdk25 + timeoutInMinutes: 120 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk25:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-junit.sh) + displayName: test-cftests-junit.sh +- job: cftests_nonjunit_jdk25 + timeoutInMinutes: 120 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk25:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-nonjunit.sh) + displayName: test-cftests-nonjunit.sh +- job: cftests_inference_jdk25 + timeoutInMinutes: 120 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk25:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-inference.sh) + displayName: test-cftests-inference.sh +- job: cftests_typecheck_jdk25 + timeoutInMinutes: 120 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk25:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-typecheck.sh) + displayName: test-typecheck.sh + +- job: test_daikon_part1 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk17:latest + timeoutInMinutes: 70 + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-daikon-part1.sh) + displayName: test-daikon-part1.sh +- job: test_daikon_part2 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk17:latest + timeoutInMinutes: 70 + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-daikon-part2.sh) + displayName: test-daikon-part2.sh +- job: test_daikon_part3 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk17:latest + timeoutInMinutes: 70 + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-daikon-part3.sh) + displayName: test-daikon-part3.sh + +- job: test_plume_lib + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk17:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-plume-lib.sh) + displayName: test-plume-lib.sh diff --git a/.azure/azure-pipelines.yml.m4 b/.azure/azure-pipelines.yml.m4 new file mode 100644 index 00000000000..10ef642376a --- /dev/null +++ b/.azure/azure-pipelines.yml.m4 @@ -0,0 +1,146 @@ +# DO NOT EDIT azure-pipelines.yml. Edit azure-pipelines.yml.m4 and defs.m4 instead. + +changequote +changequote(`[',`]')dnl +include([defs.m4])dnl +variables: + system.debug: true + +jobs: + +- job: build_jdk + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk21-plus:latest + steps: + - bash: | + whoami + git config --get remote.origin.url + pwd + ls -al + env | sort + displayName: show environment + - bash: pwd && ls && bash ./configure --with-jtreg=/usr/share/jtreg --disable-warnings-as-errors + displayName: configure + - bash: make jdk + timeoutInMinutes: 90 + displayName: make jdk + ## This works only after `make images` + # - bash: build/*/images/jdk/bin/java -version + # displayName: version + ## Don't run tests, which pass only with old version of tools (compilers, etc.). + # - bash: make -C /jdk run-test-tier1 + # displayName: make run-test-tier1 + +- job: build_jdk21u + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk21-plus:latest + timeoutInMinutes: 0 + steps: + - bash: | + whoami + git config --get remote.origin.url + pwd + ls -al + env | sort + displayName: show environment + - bash: | + set -ex + if test -d /tmp/$USER/git-scripts ; \ + then git -C /tmp/$USER/git-scripts pull -q > /dev/null 2>&1 ; \ + else mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git ; \ + fi + displayName: git-scripts + - bash: | + set -ex + if test -d /tmp/$USER/plume-scripts ; \ + then git -C /tmp/$USER/plume-scripts pull -q > /dev/null 2>&1 ; \ + else mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/plume-scripts.git ; \ + fi + displayName: plume-scripts + # This creates ../jdk21u . + # Run `git-clone-related` without a limit on depth, because if the depth is + # too small, the merge will fail. Don't use "--filter=blob:none" because that + # leads to "fatal: remote error: filter 'combine' not supported". + - bash: | + set -ex + echo "pwd = $(pwd)" + if test -d ../jdk21u; then + echo "../jdk21u should not exist yet" + false + fi + df . + /tmp/$USER/git-scripts/git-clone-related typetools jdk21u ../jdk21u --single-branch + git config --global user.email "you@example.com" + git config --global user.name "Your Name" + git config --global core.longpaths true + git config --global core.protectNTFS false + cd ../jdk21u + git diff --exit-code + echo $? + displayName: clone-related-jdk21u + - bash: | + cd ../jdk21u && git status + eval $(/tmp/$USER/plume-scripts/ci-info typetools) + set + echo "About to run: git pull --no-edit https://github.com/${CI_ORGANIZATION}/jdk ${CI_BRANCH_NAME}" + displayName: git merge plan + - bash: | + set -ex + git config --global user.email "you@example.com" + git config --global user.name "Your Name" + git config --global pull.ff true + git config --global pull.rebase false + git config --global core.longpaths true + git config --global core.protectNTFS false + cd ../jdk21u && git status + eval $(/tmp/$USER/plume-scripts/ci-info typetools) + set + echo "About to run: git pull --no-edit https://github.com/${CI_ORGANIZATION}/jdk ${CI_BRANCH_NAME}" + cd ../jdk21u && git pull --no-edit https://github.com/${CI_ORGANIZATION}/jdk ${CI_BRANCH_NAME} || (git --version && git show | head -100 && git status && git diff | head -1000 && echo "Merge failed; see 'Pull request merge conflicts' at https://github.com/typetools/jdk/blob/master/README.md" && false) + displayName: git merge + - bash: cd ../jdk21u && export JT_HOME=/usr/share/jtreg && bash ./configure --with-jtreg --disable-warnings-as-errors + displayName: configure + - bash: cd ../jdk21u && make jdk + displayName: make jdk + ## This works only after `make images` + # - bash: cd ../jdk21u && build/*/images/jdk/bin/java -version + # displayName: version + # - bash: make -C /jdk21u run-test-tier1 + # timeoutInMinutes: 0 + # displayName: make run-test-tier1 + # - bash: make -C /jdk21u :test/jdk:tier1 + ## Temporarily comment out because of trouble finding junit and jasm + # - bash: cd ../jdk21u && make run-test TEST="jtreg:test/jdk:tier1" + # timeoutInMinutes: 0 + # displayName: make run-test + +cftests_job(junit, cftests-junit, 11) +cftests_job(nonjunit, cftests-nonjunit, 11) +cftests_job(inference, cftests-inference, 11) +cftests_job(typecheck, typecheck, 11) +cftests_job(junit, cftests-junit, 17) +cftests_job(nonjunit, cftests-nonjunit, 17) +cftests_job(inference, cftests-inference, 17) +cftests_job(typecheck, typecheck, 17) +cftests_job(junit, cftests-junit, 21) +cftests_job(nonjunit, cftests-nonjunit, 21) +cftests_job(inference, cftests-inference, 21) +cftests_job(typecheck, typecheck, 21) +cftests_job(junit, cftests-junit, 25) +cftests_job(nonjunit, cftests-nonjunit, 25) +cftests_job(inference, cftests-inference, 25) +cftests_job(typecheck, typecheck, 25) + +daikon_job(1) +daikon_job(2) +daikon_job(3) + +plume_lib_job(canary_version) + +ifelse([ +Local Variables: +eval: (add-hook 'after-save-hook '(lambda () (run-command nil "make")) nil 'local) +end: +])dnl diff --git a/.azure/defs.m4 b/.azure/defs.m4 new file mode 100644 index 00000000000..1d651873c28 --- /dev/null +++ b/.azure/defs.m4 @@ -0,0 +1,186 @@ +changequote +define(`LBRACKET',`[')dnl +define(`RBRACKET',`]')dnl +changequote(`[',`]')dnl +ifelse([The built-in "dnl" m4 macro means "discard to next line",])dnl +define([canary_os], [ubuntu])dnl +define([canary_version], [25])dnl +define([latest_version], [25])dnl +define([canary_test], [canary_os[]canary_version])dnl +define([docker_testing], [])dnl +ifelse([uncomment the next line to use the "testing" Docker images])dnl +ifelse([define([docker_testing], [-testing])])dnl +dnl +define([cftests_job], [dnl +- job: cftests_$1_jdk$3 + timeoutInMinutes: 120 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk$3:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-$2.sh) + displayName: test-$2.sh])dnl +dnl +define([junit_job], [dnl + - job: junit_jdk$1 +ifelse($1,canary_version,,[ dependsOn: + - canary_jobs + - junit_jdk[]canary_version +])dnl + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk$1[]docker_testing:latest + timeoutInMinutes: 70 + steps: + - checkout: self + fetchDepth: 25 + - bash: export ORG_GRADLE_PROJECT_jdkTestVersion=$1 && ./checker/bin-devel/test-cftests-junit.sh + displayName: test-cftests-junit.sh])dnl +dnl +define([nonjunit_job], [dnl + - job: nonjunit_jdk$1 +ifelse($1,canary_version,,[ dependsOn: + - canary_jobs + - nonjunit_jdk[]canary_version +])dnl + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk$1[]docker_testing:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: export ORG_GRADLE_PROJECT_jdkTestVersion=$1 && ./checker/bin-devel/test-cftests-nonjunit.sh + displayName: test-cftests-nonjunit.sh])dnl +dnl +define([inference_job], [dnl +ifelse($1,canary_version,[dnl + # Split into part1 and part2 only for the inference job that "canary_jobs" depends on. + - job: inference_part1_jdk$1 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk$1[]docker_testing:latest + timeoutInMinutes: 90 + steps: + - checkout: self + fetchDepth: 25 + - bash: export ORG_GRADLE_PROJECT_jdkTestVersion=$1 && ./checker/bin-devel/test-cftests-inference-part1.sh + displayName: test-cftests-inference-part1.sh + - job: inference_part2_jdk$1 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk$1[]docker_testing:latest + timeoutInMinutes: 90 + steps: + - checkout: self + fetchDepth: 25 + - bash: export ORG_GRADLE_PROJECT_jdkTestVersion=$1 && ./checker/bin-devel/test-cftests-inference-part2.sh + displayName: test-cftests-inference-part2.sh +],[dnl + - job: inference_jdk$1 + dependsOn: + - canary_jobs + - inference_part1_jdk[]canary_version + - inference_part2_jdk[]canary_version + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk$1[]docker_testing:latest + timeoutInMinutes: 90 + steps: + - checkout: self + fetchDepth: 25 + - bash: export ORG_GRADLE_PROJECT_jdkTestVersion=$1 && ./checker/bin-devel/test-cftests-inference.sh + displayName: test-cftests-inference.sh +])dnl +])dnl +dnl +define([misc_job], [dnl + - job: misc_jdk$1 +ifelse($1,canary_version,,$1,latest_version,,[ dependsOn: + - canary_jobs + - misc_jdk[]canary_version +])dnl + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk$1-plus[]docker_testing:latest + steps: + - checkout: self + # Unlimited fetchDepth (0) for misc jobs, because of need to make contributors.tex. + fetchDepth: 0 + - bash: export ORG_GRADLE_PROJECT_jdkTestVersion=$1 && ./checker/bin-devel/test-misc.sh + displayName: test-misc.sh])dnl +dnl +define([typecheck_job], [dnl +ifelse($1,canary_version,[dnl + - job: typecheck_part1_jdk$1 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk$1[]docker_testing:latest + steps: + - checkout: self + fetchDepth: 1000 + - bash: export ORG_GRADLE_PROJECT_jdkTestVersion=$1 && ./checker/bin-devel/test-typecheck-part1.sh + displayName: test-typecheck-part1.sh + - job: typecheck_part2_jdk$1 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk$1[]docker_testing:latest + steps: + - checkout: self + fetchDepth: 1000 + - bash: export ORG_GRADLE_PROJECT_jdkTestVersion=$1 && ./checker/bin-devel/test-typecheck-part2.sh + displayName: test-typecheck-part2.sh], [dnl + - job: typecheck_jdk$1 + dependsOn: + - canary_jobs + - typecheck_part1_jdk[]canary_version + - typecheck_part2_jdk[]canary_version + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk$1[]docker_testing:latest + steps: + - checkout: self + fetchDepth: 1000 + - bash: export ORG_GRADLE_PROJECT_jdkTestVersion=$1 && ./checker/bin-devel/test-typecheck.sh + displayName: test-typecheck.sh])])dnl +dnl +define([daikon_job], [dnl +- job: test_daikon_part$1 + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk17:latest + timeoutInMinutes: 70 + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-daikon-part$1.sh) + displayName: test-daikon-part$1.sh])dnl +dnl +define([plume_lib_job], [dnl +- job: test_plume_lib + pool: + vmImage: 'ubuntu-latest' + container: mdernst/cf-ubuntu-jdk17:latest + steps: + - checkout: self + fetchDepth: 25 + - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/plume-lib/git-scripts.git + displayName: clone git-scripts + - bash: /tmp/$USER/git-scripts/git-clone-related typetools checker-framework + displayName: clone checker-framework + - bash: (cd ../checker-framework && checker/bin-devel/test-plume-lib.sh) + displayName: test-plume-lib.sh])dnl +ifelse([ +Local Variables: +eval: (add-hook 'after-save-hook '(lambda () (run-command nil "make")) nil 'local) +end: +])dnl diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 00000000000..68de9706e58 --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended", + ":automergeDisabled", + ":automergeRequireAllStatusChecks", + "schedule:nonOfficeHours" + ], + "minimumReleaseAge": "7 days", + "prConcurrentLimit": 5, + "timezone": "America/Los_Angeles", + "packageRules": [ + { + "description": "Group non-major GitHub Actions updates", + "matchManagers": ["github-actions"], + "matchUpdateTypes": ["minor", "patch", "pin", "digest"], + "groupName": "GitHub Actions non-major updates" + } + ] +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000000..e174b8dff28 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,165 @@ +name: CI tests + +on: + schedule: + - cron: '0 7 * * *' # Runs daily at 2:00 AM EST + pull_request: + push: + branches: [ "master" ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ !contains(github.ref, 'heads/master') }} + +jobs: + build_jdk: + name: Build the JDK + runs-on: ubuntu-latest + permissions: + contents: read + env: + JAVA_VERSION: 17 + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v6.0.0 + with: + java-version: 17 + distribution: 'zulu' + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install --only-upgrade apt + sudo apt-get install gcc-10 g++-10 libcups2-dev libasound2-dev libfontconfig1-dev \ + libx11-dev libxext-dev libxrender-dev libxrandr-dev libxtst-dev libxt-dev + - name: Install jtreg + run: | + wget https://builds.shipilev.net/jtreg/jtreg-7.5%2B1.zip -O /tmp/jtreg.zip + unzip /tmp/jtreg.zip -d /tmp/ + - name: Configure the JDK + run: bash ./configure --with-jtreg=/tmp/jtreg --disable-warnings-as-errors + - name: Build the JDK + run: make jdk + + CF: + name: ${{ matrix.script }} on JDK ${{ matrix.java_version }} + runs-on: ubuntu-latest + permissions: + contents: read + strategy: + fail-fast: false + matrix: + script: ['cftests-junit', 'cftests-nonjunit'] + java_version: ['8', '11', '17', '21', '25', '27'] + env: + JAVA_VERSION: ${{ matrix.java_version }} + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 for Gradle to run on + uses: actions/setup-java@v6.0.0 + with: + # Install JDK 21 first, to make it available to Gradle using `gradle.properties` below. + java-version: '21' + distribution: 'zulu' + - name: Set up JDK ${{ matrix.java_version }} + uses: actions/setup-java@v6.0.0 + with: + java-version: ${{ matrix.java_version }} + distribution: 'zulu' + - name: Inject JAVA_HOME_21_64 into `gradle.properties` to always use JDK 21 for Gradle + run: mkdir ~/.gradle && echo "org.gradle.java.home=$JAVA_HOME_21_X64" >> ~/.gradle/gradle.properties + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v6.3.0 + + - name: Setup Bazel + uses: bazel-contrib/setup-bazel@0.19.0 + if: ${{ matrix.script == 'cftests-nonjunit' }} + with: + bazelisk-cache: true + disk-cache: ${{ github.workflow }} + repository-cache: true + + - name: Clone plume-scripts + run: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/plume-scripts.git + + - name: Clone git-scripts + run: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/git-scripts.git + + - name: Clone checker-framework + run: /tmp/$USER/git-scripts/git-clone-related eisop checker-framework + + - name: Run test script checker/bin-devel/test-${{ matrix.script }}.sh + run: ./checker/bin-devel/test-${{ matrix.script }}.sh + working-directory: ../checker-framework + env: + ORG_GRADLE_PROJECT_useJdkVersion: ${{ matrix.java_version }} + + extra: + name: ${{ matrix.script }} on JDK ${{ matrix.java_version }} + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + script: ['plume-lib', 'daikon'] + java_version: ['21'] + env: + JAVA_VERSION: ${{ matrix.java_version }} + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK ${{ matrix.java_version }} + uses: actions/setup-java@v6.0.0 + with: + java-version: ${{ matrix.java_version }} + distribution: 'zulu' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v6.3.0 + + - name: Clone plume-scripts + run: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/plume-scripts.git + + - name: Clone git-scripts + run: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/git-scripts.git + + - name: Clone checker-framework + run: /tmp/$USER/git-scripts/git-clone-related eisop checker-framework + + - name: Run test script checker/bin-devel/test-${{ matrix.script }}.sh + run: ./checker/bin-devel/test-${{ matrix.script }}.sh + working-directory: ../checker-framework + + Consistency: + name: JDK consistency on JDK ${{ matrix.java_version }} + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + java_version: ['21'] + env: + JAVA_VERSION: ${{ matrix.java_version }} + steps: + - uses: actions/checkout@v4 + - name: Set up JDK ${{ matrix.java_version }} + uses: actions/setup-java@v6.0.0 + with: + java-version: ${{ matrix.java_version }} + distribution: 'zulu' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v6.3.0 + + - name: Clone plume-scripts + run: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/plume-scripts.git + + - name: Clone git-scripts + run: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/git-scripts.git + + - name: Clone checker-framework + run: /tmp/$USER/git-scripts/git-clone-related eisop checker-framework + + - name: Run test script checker/bin-devel/check-jdk-consistency.sh + run: ./checker/bin-devel/check-jdk-consistency.sh + working-directory: ../checker-framework diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml-orig similarity index 100% rename from .github/workflows/main.yml rename to .github/workflows/main.yml-orig diff --git a/README-diffing.el b/README-diffing.el new file mode 100644 index 00000000000..dd5120bc1c6 --- /dev/null +++ b/README-diffing.el @@ -0,0 +1,33 @@ +;; Given a context diff between the Java JDK and the Checker Framework's +;; annotated JDK, run these commands to reduce the size of the diffs. Most +;; remaining diffs indicate an unintentional edit that should be reverted in the +;; annotated JDK. + +(progn + (save-excursion + (goto-char (point-min)) + + (save-excursion + (delete-matching-lines "^\\+import org.checkerframework.*;$" nil nil t)) + + (save-excursion + (replace-string "\n \n+\n" "\n \n")) + + (save-excursion + (delete-matching-lines (concat "^\\+" annotation-line-regex "$"))) + + (save-excursion + (query-replace-regexp "@[A-Z][A-Za-z0-9_]* " "")) + (save-excursion + (query-replace-regexp "@[A-Z][A-Za-z0-9_]*([^()\n]*) " "")) + (save-excursion + (query-replace " []" "[]")) + (save-excursion + (query-replace " ..." "...")) + (save-excursion + (query-replace-regexp " \\([A-Za-z0-9_]*(\\)[A-Z][A-Za-z0-9_.]*\\(<[A-Z]\\(, ?[A-Z]\\)*>\\)? this, " " \\1")) + (save-excursion + (query-replace-regexp " \\([A-Za-z0-9_]*(\\)[A-Z][A-Za-z0-9_.]*\\(<[A-Z]\\(, ?[A-Z]\\)*>\\)? this)" " \\1)")) + (save-excursion + (query-replace-regexp " extends Object\\([,>]\\)" "\\1")) + )) diff --git a/README-merging.el b/README-merging.el new file mode 100644 index 00000000000..5b657bd00aa --- /dev/null +++ b/README-merging.el @@ -0,0 +1 @@ +;; See file diff-resolve.el diff --git a/README.md b/README.md index c8c7c7d73b6..1e9d4e13522 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,51 @@ # EISOP fork of the JDK This fork of the JDK contains type annotations for pluggable type-checking. +It is called "the annotated JDK". It does *not* contain annotations for certain files (because annotations in them cause build failures, especially in the interim builds): - * the jdk.rmic module - * objectweb/asm files - * src/java.base/share/classes/java/time/* - * src/jdk.compiler/share/classes/com/sun/tools/javac/* + +* the jdk.rmic module +* objectweb/asm files +* src/java.base/share/classes/java/time/* +* src/jdk.compiler/share/classes/com/sun/tools/javac/* Annotations for classes that exist in JDK version X but were removed later appear in jdkX.astub files, such as jdk11.astub, in repository -https://github.com/eisop/checker-framework/ . - + . ## Building -See file `azure-pipelines.yml`. Briefly: +You **do not need to build** the annotated JDK in order to use it in the Checker +Framework. -``` +Put the annotated JDK in a directory named `jdk/` that is a sibling of your +`checker-framework/` directory. Now, when you build the Checker Framework +(e.g., `cd checker-framework && ./gradlew assemble`), it will automatically +incorporate the annotated JDK into the resulting Checker Framework binaries. +The `jdk/` and `checker-framework/` directories can be clones of the relevant +repositories, or they can be (hard or soft) symbolic links to the clones. + +If there is a mistake in an annotated JDK file (such as a typo in an annotation +name or a missing `import` statement), the entire file is ignored. CI builds +the JDK in order to detect such errors. + +If you want to build the JDK rather than just use it from the Checker Framework, +see file `.azure/azure-pipelines.yml`. Briefly: + +```sh bash configure --disable-warnings-as-errors --with-jtreg make jdk ``` You might need to change `--with-jtreg` to one of these: -``` + +```sh --with-jtreg=/usr/share/jtreg --with-jtreg=$HOME/bin/install/jtreg ``` - ## Contributing We welcome pull requests that add new annotations or correct existing ones. @@ -37,127 +53,136 @@ Thanks in advance for your contributions! When adding annotations, please annotate an entire file at a time, and add an `@AnnotatedFor` annotation on the class declaration. The rationale is explained -at https://checkerframework.org/manual/#library-tips-fully-annotate . - +at . ## Relationship to other repositories The typetools:jdk fork is not up to date with respect to `openjdk:jdk` (the current OpenJDK version). The typetools:jdk fork contains all commits through -the release of JDK 20 (that is, the last commit that is in both openjdk:jdk and -in openjdk:jdk20u): -https://github.com/typetools/jdk/commit/d562d3fcbe22a0443037c5b447e1a41401275814 +the release of JDK 21 (that is, the last commit that is in both openjdk:jdk and +in openjdk:jdk21u): + The typetools:jdk fork is an ancestor of JDK release forks such as -typetools:jdk17u. The typetools:jdk fork may not compile, because the commit of +typetools:jdk21u. The typetools:jdk fork may not compile, because the commit of openjdk:jdk on which it is based may not compile, due to changes to tools such -as compilers. Repositories such as jdk11u, jdk17u, and jdk20u have been updated +as compilers. Repositories such as jdk11u, jdk17u, and jdk21u have been updated and do compile. This fork's annotations are pulled into those repositories, in order to build an -annotated JDK. We do not write annotations in (say) typetools:jdk20u, because +annotated JDK. We do not write annotations in (say) typetools:jdk21u, because it would be painful to get them into typetools:jdk21u due to subsequent commits. - ## Pull request merge conflicts -If a pull request is failing with a merge conflict in `jdk17u`, first -update jdk17u from its upstreams, using the directions in section -"The typetools/jdk17u repository" below. +If a pull request is failing with a merge conflict in `jdk21u`, first +update jdk21u from its upstreams, using the directions in section +"The typetools/jdk21u repository" below. If that does not resolve the issue, then do the following in a clone of the branch of `jdk` whose pull request is failing. -``` + + +```sh BRANCH=`git rev-parse --abbrev-ref HEAD` URL=`git config --get remote.origin.url` SLUG=${URL#*:} ORG=${SLUG%/*} -JDK17DIR=../jdk17u-fork-$ORG-branch-$BRANCH -JDK17URL=`echo "$URL" | sed 's/jdk/jdk17u/'` +JDK21DIR=../jdk21u-fork-$ORG-branch-$BRANCH +JDK21URL=`echo "$URL" | sed 's/jdk/jdk21u/'` echo BRANCH=$BRANCH echo URL=$URL -echo JDK17DIR=$JDK17DIR -echo JDK17URL=$JDK17URL -if [ -d $JDK17DIR ] ; then - (cd $JDK17DIR && git pull) +echo JDK21DIR=$JDK21DIR +echo JDK21URL=$JDK21URL +if [ -d $JDK21DIR ] ; then + (cd $JDK21DIR && git pull) else - git clone $JDK17URL $JDK17DIR && (cd $JDK17DIR && (git checkout $BRANCH || git checkout -b $BRANCH)) + git clone $JDK21URL $JDK21DIR && (cd $JDK21DIR && (git checkout $BRANCH || git checkout -b $BRANCH)) fi -cd $JDK17DIR +cd $JDK21DIR git pull $URL $BRANCH ``` Manual step: resolve conflicts and complete the merge. -``` +```sh git push --set-upstream origin $BRANCH ``` Manual step: restart the pull request CI job. -After the pull request is merged to https://github.com/typetools/jdk, -follow the instructions at https://github.com/typetools/jdk17u to update -jdk17u, taking guidance from the merge done in the fork of jdk17u to -resolve conflicts. Then, discard the branch in the fork of jdk17u. - +After the pull request is merged to , +follow the instructions at to update +jdk21u, taking guidance from the merge done in the fork of jdk21u to +resolve conflicts. Then, discard the branch in the fork of jdk21u. ## Qualifier definitions The java.base module contains a copy of the Checker Framework qualifiers (type annotations). To update that copy, run the command below from this directory: -``` +```sh (cd $CHECKERFRAMEWORK && rm -rf checker-qual/build/libs && ./gradlew :checker-qual:sourcesJar) && \ rm -f checker-qual-sources.jar && \ cp -p $CHECKERFRAMEWORK/checker-qual/build/libs/checker-qual-*-sources.jar checker-qual-sources.jar && \ (cd src/java.base/share/classes && rm -rf org/checkerframework && \ unzip ../../../../checker-qual-sources.jar -x 'META-INF*' && \ chmod -R u+w org/checkerframework) && \ -jar tf checker-qual-sources.jar | grep '\.java$' | sed 's/\/[^/]*\.java/;/' | sed 's/\//./g' | sed 's/^/ exports /' | sort | uniq +jar tf checker-qual.jar | grep '\.java$' | sed 's/\/[^/]*\.java/;/' | sed 's/\//./g' | sed 's/^/ exports /' | sort -u ``` The result of the command will be a list of export lines. Replace the existing export lines present in `src/java.base/share/classes/module-info.java` with the newly-generated list of -exports. If no new packages were added, then there are likely going to be no -changes to the `module-info.java` file. +exports. If no new packages were added, then likely no changes are needed +in the `module-info.java` file. Commit the changes. Do not include the top-level `checker-qual-source.jar` file, but include any new `.java` files in a `qual/` directory. +## The typetools/jdk21u repository -## The typetools/jdk17u repository +The typetools/jdk21u repository is a merge of `openjdk/jdk21u` and `typetools/jdk`. +That is, it is a fork of `openjdk/jdk21u`, with Checker Framework type annotations. -The `typetools/jdk17u` repository is a merge of `openjdk/jdk17u` and `typetools/jdk`. -That is, it is a fork of `openjdk/jdk17u`, with Checker Framework type annotations. - -**Do not edit the `typetools/jdk17u` repository.** +**Do not edit the `typetools/jdk21u` repository.** Make changes in the `typetools/jdk` repository. -(Note that this README file appears in both the `typetools/jdk` and `typetools/jdk17u` repositories!) +(Note that this README file appears in both the `typetools/jdk` +and `typetools/jdk21u` repositories!) -To update jdk17u from its upstreams: -``` -cd jdk17u +To update jdk21u from its upstreams: +(These are the only edits to jdk21u allowed, plus changes needed to resolve +merge conflicts.) + +```sh +cd jdk21u git pull -git pull https://github.com/openjdk/jdk17u.git +git pull https://github.com/openjdk/jdk21u.git git pull https://github.com/typetools/jdk.git ``` +## Upgrading to a new version of Java -## Updating - -Whenever a new Java release is made, this repository should be updated to pull in more commits from upstream. Here are some commands to run when updating to JDK ${VER}. +Whenever Oracle releases a new version of Java, this repository should be +updated to pull in more commits from upstream. Here are some commands to run +when updating to JDK ${VER}. -Fork into typetools: https://github.com/openjdk/jdk${VER}u +Fork into typetools: Clone jdk${VER}u repositories into, say, $t/libraries/ . -Determine the last commit in both openjdk:jdk and in openjdk:jdk${VER}u: -run `git log --graph | tac` on both and find the common prefix. +Determine the last commit in both openjdk:jdk and in openjdk:jdk${VER}u: run +```sh +git log --graph | tac > git-log-reversed.txt ``` -last_common_commit=d562d3fcbe22a0443037c5b447e1a41401275814 + +on both and find the common prefix. + +```sh +VER=21 +last_common_commit=bb377b26730f3d9da7c76e0d171517e811cef3ce cd $t/libraries git clone -- git@github.com:openjdk/jdk.git jdk-fork-openjdk-commit-${last_common_commit} cd jdk-fork-openjdk-commit-${last_common_commit} @@ -167,29 +192,63 @@ cd $t/libraries/jdk-fork-${USER}-branch-jdk${VER} git pull ../jdk-fork-openjdk-commit-${last_common_commit} ``` +Resolve the merge conflicts. The commands in `README-merging.el` automate a +great deal of work (requires using Emacs). + +Replace uses of the old JDK version (such as 17) with the new one (such as 21). + +* In this file +* In .azure/azure-pipelines.yml.m4 + +Make a fork of jdk21u. Follow the instructions in "The typetools/jdk21u +repository" above, except replace +`git pull https://github.com/typetools/jdk.git` +by the JDK you are currently working on. + +Build JDK 21u (not the main JDK!). + +Diff JDK 21 with the upstream commit of OpenJDK, to detect unintentional edits. +The commands in `README-diffing.el` automate a great deal of work (requires +using Emacs). + +```sh +cd jdk21u-fork-typetools +git pull ../jdk-fork-${USER}-branch-jdk21 +``` + +Push and wait for CI to pass. + +Find all `.java` files that contain both `@AnnotatedFor` and a relevant `@since` +in Javadoc. For example, the regex "@since[ \t](18|19|20|21)". For each +relevant `@since`, add annotations for all the type systems in `@AnnotatedFor`. +Note: I have not yet done this for JDK 18-21. + +DO NOT squash-and-merge the pull request. Both the jdk and jdk21u repositories +need to be merged, retaining history. + +For Michael Ernst only: update `~/bin/src/mdedots/share/mdevcupdate` +to refer to jdk21u, not jdk17u. ## Design The goal of this repository is to write Checker Framework annotations in JDK source code. In order to compile, it is necessary that definitions of those annotations are available -- in a module such as java.base, or on the -classpath. I tried putting them in `java.base` (which worked for JDK 11), +classpath. Putting them in `java.base` worked for JDK 11, but I wasn't able to make that work for JDK 17. - ## Upstream README follows The remainder of this file is the `README.md` from `openjdk/jdk`. - -# Welcome to the JDK! +# Welcome to the JDK For build instructions please see the [online documentation](https://openjdk.org/groups/build/doc/building.html), or either of these files: -- [doc/building.html](doc/building.html) (html version) -- [doc/building.md](doc/building.md) (markdown version) +* [doc/building.html](doc/building.html) (html version) +* [doc/building.md](doc/building.md) (markdown version) See for more information about the OpenJDK Community and the JDK and see for JDK issue diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index ab45375e9f4..00000000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,205 +0,0 @@ -# variables: -# system.debug: true - -jobs: - -- job: build_jdk - pool: - vmImage: 'ubuntu-latest' - container: wmdietl/cf-ubuntu-jdk21-plus:latest - steps: - - bash: | - whoami - git config --get remote.origin.url - pwd - ls -al - env | sort - displayName: show environment - - bash: | - wget https://builds.shipilev.net/jtreg/jtreg-7.5%2B1.zip -O /tmp/jtreg.zip - unzip /tmp/jtreg.zip -d /tmp/ - displayName: Install jtreg7 - - bash: pwd && ls && bash ./configure --with-jtreg=/tmp/jtreg --disable-warnings-as-errors - displayName: configure - - bash: make jdk - timeoutInMinutes: 90 - displayName: make jdk - ## This works only after `make images` - # - bash: build/*/images/jdk/bin/java -version - # displayName: version - ## Don't run tests, which pass only with old version of tools (compilers, etc.). - # - bash: make -C /jdk run-test-tier1 - # displayName: make run-test-tier1 - -# - job: build_jdk17u -# pool: -# vmImage: 'ubuntu-latest' -# container: wmdietl/cf-ubuntu-jdk17-plus:latest -# timeoutInMinutes: 0 -# steps: -# - bash: | -# whoami -# git config --get remote.origin.url -# pwd -# ls -al -# env | sort -# displayName: show environment -# - bash: | -# set -ex -# if [ -d /tmp/$USER/git-scripts ]; \ -# then git -C /tmp/$USER/git-scripts pull -q > /dev/null 2>&1 ; \ -# else mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/eisop-plume-lib/git-scripts.git ; \ -# fi -# displayName: git-scripts -# - bash: | -# set -ex -# if [ -d /tmp/$USER/plume-scripts ]; \ -# then git -C /tmp/$USER/plume-scripts pull -q > /dev/null 2>&1 ; \ -# else mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/eisop-plume-lib/plume-scripts.git ; \ -# fi -# displayName: plume-scripts -# # This creates ../jdk17u . -# # If the depth is too small, the merge will fail. However, we cannot use "--filter=blob:none" -# # because that leads to "fatal: remote error: filter 'combine' not supported". -# - bash: | -# set -ex -# pwd -# ls -al .. || true -# ls -al ../jdk17u || true -# df . -# /tmp/$USER/git-scripts/git-clone-related typetools jdk17u ../jdk17u --depth 999 -# git config --global user.email "you@example.com" -# git config --global user.name "Your Name" -# git config --global core.longpaths true -# git config --global core.protectNTFS false -# cd ../jdk17u && git status -# git diff --exit-code -# echo $? -# displayName: clone-related-jdk17u -# - bash: | -# set -ex -# git config --global user.email "you@example.com" -# git config --global user.name "Your Name" -# git config --global pull.ff true -# git config --global pull.rebase false -# git config --global core.longpaths true -# git config --global core.protectNTFS false -# eval `/tmp/$USER/plume-scripts/ci-info eisop` -# cd ../jdk17u && git status -# echo "About to run: git pull --no-edit https://github.com/${CI_ORGANIZATION}/jdk ${CI_BRANCH}" -# cd ../jdk17u && git pull --no-edit https://github.com/${CI_ORGANIZATION}/jdk ${CI_BRANCH} || (git --version && git show && git status && echo "Merge failed; see 'Pull request merge conflicts' at https://github.com/eisop/jdk/blob/master/README.md" && false) -# displayName: git merge -# - bash: cd ../jdk17u && export JT_HOME=/usr/share/jtreg && bash ./configure --with-jtreg=/usr/share/jtreg --disable-warnings-as-errors -# displayName: configure -# - bash: cd ../jdk17u && make jdk -# displayName: make jdk -# ## This works only after `make images` -# # - bash: cd ../jdk17u && build/*/images/jdk/bin/java -version -# # displayName: version -# # - bash: make -C /jdk17u run-test-tier1 -# # timeoutInMinutes: 0 -# # displayName: make run-test-tier1 -# # - bash: make -C /jdk17u :test/jdk:tier1 -# ## Temporarily comment out because of trouble finding junit and jasm -# # - bash: cd ../jdk17u && make run-test TEST="jtreg:test/jdk:tier1" -# # timeoutInMinutes: 0 -# # displayName: make run-test - -- job: test_cftests_all_jdk8 - timeoutInMinutes: 105 - pool: - vmImage: 'ubuntu-latest' - container: wmdietl/cf-ubuntu-jdk8:latest - steps: - - checkout: self - fetchDepth: 25 - - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/plume-scripts.git - displayName: clone plume-scripts - - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth 1 -q https://github.com/eisop-plume-lib/git-scripts.git - displayName: clone git-scripts - - bash: /tmp/$USER/git-scripts/git-clone-related eisop checker-framework - displayName: clone checker-framework - - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-all.sh) - displayName: test-cftests-all.sh - -- job: test_cftests_all_jdk11 - timeoutInMinutes: 120 - pool: - vmImage: 'ubuntu-latest' - container: wmdietl/cf-ubuntu-jdk11:latest - steps: - - checkout: self - fetchDepth: 25 - - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/eisop-plume-lib/git-scripts.git - displayName: clone git-scripts - - bash: /tmp/$USER/git-scripts/git-clone-related eisop checker-framework - displayName: clone checker-framework - - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-all.sh) - displayName: test-cftests-all.sh -## Here is how to create artifacts that can be downloaded. -# - bash: (cd ../checker-framework/checker/build/jtregJdk11/ && tar -czvf all.tgz all) -# condition: succeededOrFailed() -# displayName: tar jtregJdk11/all -# - publish: $(System.DefaultWorkingDirectory)/../checker-framework/checker/build/jtregJdk11/all.tgz -# artifact: all.tgz -# condition: failed() -# displayName: publish all.tgz - -- job: test_cftests_all_jdk17 - timeoutInMinutes: 120 - pool: - vmImage: 'ubuntu-latest' - container: wmdietl/cf-ubuntu-jdk17:latest - steps: - - checkout: self - fetchDepth: 25 - - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/eisop-plume-lib/git-scripts.git - displayName: clone git-scripts - - bash: /tmp/$USER/git-scripts/git-clone-related eisop checker-framework - displayName: clone checker-framework - - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-all.sh) - displayName: test-cftests-all.sh - -- job: test_cftests_all_jdk_latest - timeoutInMinutes: 120 - pool: - vmImage: 'ubuntu-latest' - container: wmdietl/cf-ubuntu-jdk-latest:latest - steps: - - checkout: self - fetchDepth: 25 - - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/eisop-plume-lib/git-scripts.git - displayName: clone git-scripts - - bash: /tmp/$USER/git-scripts/git-clone-related eisop checker-framework - displayName: clone checker-framework - - bash: (cd ../checker-framework && checker/bin-devel/test-cftests-all.sh) - displayName: test-cftests-all.sh - -- job: test_daikon - pool: - vmImage: 'ubuntu-latest' - container: wmdietl/cf-ubuntu-jdk17:latest - timeoutInMinutes: 70 - steps: - - checkout: self - fetchDepth: 25 - - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/eisop-plume-lib/git-scripts.git - displayName: clone git-scripts - - bash: /tmp/$USER/git-scripts/git-clone-related eisop checker-framework - displayName: clone checker-framework - - bash: (cd ../checker-framework && checker/bin-devel/test-daikon.sh) - displayName: test-daikon.sh - -- job: test_plume_lib - pool: - vmImage: 'ubuntu-latest' - container: wmdietl/cf-ubuntu-jdk17:latest - steps: - - checkout: self - fetchDepth: 25 - - bash: mkdir -p /tmp/$USER && git -C /tmp/$USER clone --depth=1 -q https://github.com/eisop-plume-lib/git-scripts.git - displayName: clone git-scripts - - bash: /tmp/$USER/git-scripts/git-clone-related eisop checker-framework - displayName: clone checker-framework - - bash: (cd ../checker-framework && checker/bin-devel/test-plume-lib.sh) - displayName: test-plume-lib.sh diff --git a/configure b/configure old mode 100644 new mode 100755 diff --git a/make/CompileInterimLangtools.gmk b/make/CompileInterimLangtools.gmk index dc3d02d2d04..034e078d4f8 100644 --- a/make/CompileInterimLangtools.gmk +++ b/make/CompileInterimLangtools.gmk @@ -87,8 +87,9 @@ TARGETS += $(COPY_PREVIEW_FEATURES) # would require the source files to be copied into directories named after the # actual interim modules. -## DON'T PUT COMMAS within this macro definition, as in +# DON'T PUT COMMAS within this macro definition, as in # --add-exports java.base/org.checkerframework.checker.builder.qual=java.compiler.interim,jdk.compiler.interim \ +# The export to javacserver.shared does not seem to have any effect. # Param 1 - Name of module to compile define SetupInterimModule @@ -116,6 +117,13 @@ define SetupInterimModule --patch-module java.base=$(BUILDTOOLS_OUTPUTDIR)/gensrc/java.base.interim \ --add-exports java.base/jdk.internal.javac=java.compiler.interim \ --add-exports java.base/jdk.internal.javac=jdk.compiler.interim \ + --add-exports java.base/org.checkerframework.checker.builder.qual=java.compiler.interim \ + --add-exports java.base/org.checkerframework.checker.builder.qual=jdk.compiler.interim \ + --add-exports java.base/org.checkerframework.checker.builder.qual=jdk.javadoc.interim \ + --add-exports java.base/org.checkerframework.checker.builder.qual=javacserver.shared \ + --add-exports java.base/org.checkerframework.checker.nullness.qual=build.tools.pandocfilter.json \ + --add-exports java.base/org.checkerframework.dataflow.qual=build.tools.pandocfilter.json \ + --add-exports java.base/org.checkerframework.dataflow.qual=javacserver.shared \ --add-exports jdk.internal.opt/jdk.internal.opt=jdk.compiler.interim \ --add-exports jdk.internal.opt/jdk.internal.opt=jdk.javadoc.interim, \ )) diff --git a/make/langtools/tools/javacserver/shared/PortFile.java b/make/langtools/tools/javacserver/shared/PortFile.java index 2e4283a22b3..25da9c49396 100644 --- a/make/langtools/tools/javacserver/shared/PortFile.java +++ b/make/langtools/tools/javacserver/shared/PortFile.java @@ -25,6 +25,8 @@ package javacserver.shared; +// import org.checkerframework.dataflow.qual.Pure; + import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -134,6 +136,8 @@ public void getValues() { /** * Did the locking and getValues succeed? */ + + // @Pure public boolean containsPortInfo() { return containsPortInfo; } diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.cpp b/src/hotspot/cpu/aarch64/assembler_aarch64.cpp index afeb19e906e..b23c89ebdab 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.cpp @@ -441,7 +441,7 @@ void Assembler::bang_stack_with_offset(int offset) { Unimplemented(); } bool asm_util::operand_valid_for_immediate_bits(int64_t imm, unsigned nbits) { guarantee(nbits == 8 || nbits == 12, "invalid nbits value"); - uint64_t uimm = (uint64_t)uabs((jlong)imm); + uint64_t uimm = (uint64_t)g_uabs((jlong)imm); if (uimm < (UCONST64(1) << nbits)) return true; if (uimm < (UCONST64(1) << (2 * nbits)) diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index a53d8329645..f6ba7b0841b 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -922,7 +922,7 @@ class Assembler : public AbstractAssembler { static const uint64_t branch_range = NOT_DEBUG(128 * M) DEBUG_ONLY(2 * M); static bool reachable_from_branch_at(address branch, address target) { - return uabs(target - branch) < branch_range; + return g_uabs(target - branch) < branch_range; } // Unconditional branch (immediate) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 3be34786f19..df5b55d84bc 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -2556,7 +2556,7 @@ void MacroAssembler::wrap_add_sub_imm_insn(Register Rd, Register Rn, uint64_t im if (fits) { (this->*insn1)(Rd, Rn, imm); } else { - if (uabs(imm) < (1 << 24)) { + if (g_uabs(imm) < (1 << 24)) { (this->*insn1)(Rd, Rn, imm & -(1 << 12)); (this->*insn1)(Rd, Rd, imm & ((1 << 12)-1)); } else { diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index c30234aae38..465f8e73eda 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -1116,7 +1116,7 @@ class StubGenerator: public StubCodeGenerator { void copy_memory_small(DecoratorSet decorators, BasicType type, Register s, Register d, Register count, int step) { bool is_backwards = step < 0; - size_t granularity = uabs(step); + size_t granularity = g_uabs(step); int direction = is_backwards ? -1 : 1; Label Lword, Lint, Lshort, Lbyte; @@ -1175,7 +1175,7 @@ class StubGenerator: public StubCodeGenerator { Register s, Register d, Register count, int step) { copy_direction direction = step < 0 ? copy_backwards : copy_forwards; bool is_backwards = step < 0; - unsigned int granularity = uabs(step); + unsigned int granularity = g_uabs(step); const Register t0 = r3, t1 = r4; // <= 80 (or 96 for SIMD) bytes do inline. Direction doesn't matter because we always diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 02fbf5bfbf7..4c0812279fc 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -2899,7 +2899,7 @@ enum Nf { static const unsigned long branch_range = 1 * M; static bool reachable_from_branch_at(address branch, address target) { - return uabs(target - branch) < branch_range; + return g_uabs(target - branch) < branch_range; } Assembler(CodeBuffer* code) : AbstractAssembler(code), _in_compressible_region(true) {} diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 60c1fc8c3d5..ccaf8352e82 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -866,7 +866,7 @@ class StubGenerator: public StubCodeGenerator { * goto copy_small; * } * bool is_backwards = step < 0; - * int granularity = uabs(step); + * int granularity = g_uabs(step); * count = count * granularity; * count bytes * * if (is_backwards) { @@ -896,7 +896,7 @@ class StubGenerator: public StubCodeGenerator { void copy_memory_v(Register s, Register d, Register count, int step) { bool is_backward = step < 0; - int granularity = uabs(step); + int granularity = g_uabs(step); const Register src = x30, dst = x31, vl = x14, cnt = x15, tmp1 = x16, tmp2 = x17; assert_different_registers(s, d, cnt, vl, tmp1, tmp2); @@ -952,7 +952,7 @@ class StubGenerator: public StubCodeGenerator { } bool is_backwards = step < 0; - int granularity = uabs(step); + int granularity = g_uabs(step); const Register src = x30, dst = x31, cnt = x15, tmp3 = x16, tmp4 = x17, tmp5 = x14, tmp6 = x13; const Register gct1 = x28, gct2 = x29, gct3 = t2; diff --git a/src/hotspot/share/opto/mulnode.cpp b/src/hotspot/share/opto/mulnode.cpp index 0636bcd31dc..f130c1aa2ad 100644 --- a/src/hotspot/share/opto/mulnode.cpp +++ b/src/hotspot/share/opto/mulnode.cpp @@ -245,7 +245,7 @@ Node *MulINode::Ideal(PhaseGVN *phase, bool can_reshape) { // Check for negative constant; if so negate the final result bool sign_flip = false; - unsigned int abs_con = uabs(con); + unsigned int abs_con = g_uabs(con); if (abs_con != (unsigned int)con) { sign_flip = true; } @@ -410,7 +410,7 @@ Node *MulLNode::Ideal(PhaseGVN *phase, bool can_reshape) { // Check for negative constant; if so negate the final result bool sign_flip = false; - julong abs_con = uabs(con); + julong abs_con = g_uabs(con); if (abs_con != (julong)con) { sign_flip = true; } diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index 30f71ea4e97..c364bd2062d 100644 --- a/src/hotspot/share/opto/subnode.cpp +++ b/src/hotspot/share/opto/subnode.cpp @@ -1843,14 +1843,14 @@ const Type* AbsNode::Value(PhaseGVN* phase) const { case Type::Int: { const TypeInt* ti = t1->is_int(); if (ti->is_con()) { - return TypeInt::make(uabs(ti->get_con())); + return TypeInt::make(g_uabs(ti->get_con())); } break; } case Type::Long: { const TypeLong* tl = t1->is_long(); if (tl->is_con()) { - return TypeLong::make(uabs(tl->get_con())); + return TypeLong::make(g_uabs(tl->get_con())); } break; } diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index becaf795799..3652779bf3b 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -1148,7 +1148,7 @@ inline bool is_even(intx x) { return !is_odd(x); } // abs methods which cannot overflow and so are well-defined across // the entire domain of integer types. -static inline unsigned int uabs(unsigned int n) { +static inline unsigned int g_uabs(unsigned int n) { union { unsigned int result; int value; @@ -1157,7 +1157,7 @@ static inline unsigned int uabs(unsigned int n) { if (value < 0) result = 0-result; return result; } -static inline julong uabs(julong n) { +static inline julong g_uabs(julong n) { union { julong result; jlong value; @@ -1166,8 +1166,8 @@ static inline julong uabs(julong n) { if (value < 0) result = 0-result; return result; } -static inline julong uabs(jlong n) { return uabs((julong)n); } -static inline unsigned int uabs(int n) { return uabs((unsigned int)n); } +static inline julong g_uabs(jlong n) { return g_uabs((julong)n); } +static inline unsigned int g_uabs(int n) { return g_uabs((unsigned int)n); } // "to" should be greater than "from." inline intx byte_size(void* from, void* to) { diff --git a/src/java.base/share/classes/java/io/BufferedInputStream.java b/src/java.base/share/classes/java/io/BufferedInputStream.java index 96f4282a7f6..47dff4d2657 100644 --- a/src/java.base/share/classes/java/io/BufferedInputStream.java +++ b/src/java.base/share/classes/java/io/BufferedInputStream.java @@ -402,8 +402,7 @@ private int read1(byte[] b, int off, int len) throws IOException { * or an I/O error occurs. * @throws IndexOutOfBoundsException {@inheritDoc} */ - public @GTENegativeOne @LTEqLengthOf({"#1"}) int read(byte[] b, @IndexOrHigh({"#1"}) int off, @LTLengthOf(value={"#1"}, offset={"#2 - 1"}) @NonNegative int len) - throws IOException { + public @GTENegativeOne @LTEqLengthOf({"#1"}) int read(byte[] b, @IndexOrHigh({"#1"}) int off, @LTLengthOf(value={"#1"}, offset={"#2 - 1"}) @NonNegative int len) throws IOException { if (lock != null) { lock.lock(); try { diff --git a/src/java.base/share/classes/java/io/BufferedOutputStream.java b/src/java.base/share/classes/java/io/BufferedOutputStream.java index c0df5bdfff2..097478bbaa2 100644 --- a/src/java.base/share/classes/java/io/BufferedOutputStream.java +++ b/src/java.base/share/classes/java/io/BufferedOutputStream.java @@ -202,7 +202,7 @@ private void implWrite(int b) throws IOException { * @throws IndexOutOfBoundsException {@inheritDoc} */ @Override - public synchronized void write(@PolySigned byte[] b, @IndexOrHigh({"#1"}) int off, @LTLengthOf(value={"#1"}, offset={"#2 - 1"}) @NonNegative int len) throws IOException { + public void write(@PolySigned byte[] b, @IndexOrHigh({"#1"}) int off, @LTLengthOf(value={"#1"}, offset={"#2 - 1"}) @NonNegative int len) throws IOException { if (lock != null) { lock.lock(); try { diff --git a/src/java.base/share/classes/java/io/BufferedReader.java b/src/java.base/share/classes/java/io/BufferedReader.java index d2b1c6feda5..0d6078cbe62 100644 --- a/src/java.base/share/classes/java/io/BufferedReader.java +++ b/src/java.base/share/classes/java/io/BufferedReader.java @@ -38,7 +38,6 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import java.util.Iterator; @@ -708,7 +707,6 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") public String next(/*@NonEmpty Iterator this*/) { if (nextLine != null || hasNext()) { String line = nextLine; diff --git a/src/java.base/share/classes/java/io/ByteArrayOutputStream.java b/src/java.base/share/classes/java/io/ByteArrayOutputStream.java index 1ecbc2b40a6..82f15e487a6 100644 --- a/src/java.base/share/classes/java/io/ByteArrayOutputStream.java +++ b/src/java.base/share/classes/java/io/ByteArrayOutputStream.java @@ -227,8 +227,8 @@ public synchronized void reset() { * @return String decoded from the buffer's contents. * @since 1.1 */ - @Override @SideEffectFree + @Override public synchronized String toString(@GuardSatisfied ByteArrayOutputStream this) { return new String(buf, 0, count); } diff --git a/src/java.base/share/classes/java/io/Console.java b/src/java.base/share/classes/java/io/Console.java index c28538f09db..efeade4033b 100644 --- a/src/java.base/share/classes/java/io/Console.java +++ b/src/java.base/share/classes/java/io/Console.java @@ -105,7 +105,7 @@ * @author Xueming Shen * @since 1.6 */ -@AnnotatedFor({"formatter", "index", "initialization", "interning", "nullness"}) +@AnnotatedFor({"formatter", "index", "initialization", "interning", "nullness"}) public sealed @UsesObjectEquals class Console implements Flushable permits ProxyingConsole { /** * Package private no-arg constructor. @@ -365,7 +365,6 @@ private static UnsupportedOperationException newUnsupportedOperationException() } private static native String encoding(); - static final Charset CHARSET; static { Charset cs = null; diff --git a/src/java.base/share/classes/java/io/EOFException.java b/src/java.base/share/classes/java/io/EOFException.java index dcc1315e762..ab2b9a86ba1 100644 --- a/src/java.base/share/classes/java/io/EOFException.java +++ b/src/java.base/share/classes/java/io/EOFException.java @@ -25,6 +25,9 @@ package java.io; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Signals that an end of file or end of stream has been reached * unexpectedly during input. @@ -38,6 +41,7 @@ * @see java.io.IOException * @since 1.0 */ +@AnnotatedFor({"nullness"}) public class EOFException extends IOException { @java.io.Serial private static final long serialVersionUID = 6433858223774886977L; @@ -58,7 +62,7 @@ public EOFException() { * * @param s the detail message. */ - public EOFException(String s) { + public EOFException(@Nullable String s) { super(s); } } diff --git a/src/java.base/share/classes/java/io/File.java b/src/java.base/share/classes/java/io/File.java index f54288e8b55..d59cabfbfbe 100644 --- a/src/java.base/share/classes/java/io/File.java +++ b/src/java.base/share/classes/java/io/File.java @@ -476,7 +476,8 @@ public File(URI uri) { * pathname, or the empty string if this pathname's name sequence * is empty */ - @SideEffectFree // pure with respect to .equals but not == + @CFComment({"pure with respect to .equals but not =="}) + @SideEffectFree public String getName() { int index = path.lastIndexOf(separatorChar); if (index < prefixLength) return path.substring(prefixLength); @@ -497,7 +498,8 @@ public String getName() { * does not name a parent */ @Pure - @SideEffectFree // pure with respect to .equals but not == + @CFComment({"pure with respect to .equals but not =="}) + @SideEffectFree public @Nullable String getParent(@GuardSatisfied File this) { int index = path.lastIndexOf(separatorChar); if (index < prefixLength) { @@ -525,7 +527,8 @@ public String getName() { * @since 1.2 */ @Pure - @SideEffectFree // pure with respect to .equals but not == + @CFComment({"pure with respect to .equals but not =="}) + @SideEffectFree public @Nullable File getParentFile(@GuardSatisfied File this) { String p = this.getParent(); if (p == null) return null; @@ -542,7 +545,8 @@ public String getName() { * * @return The string form of this abstract pathname */ - @SideEffectFree // pure with respect to .equals but not == + @CFComment({"pure with respect to .equals but not =="}) + @SideEffectFree public String getPath() { return path; } @@ -605,7 +609,8 @@ public String getAbsolutePath() { * * @since 1.2 */ - @SideEffectFree // pure with respect to .equals but not == + @CFComment({"pure with respect to .equals but not =="}) + @SideEffectFree public File getAbsoluteFile() { String absPath = getAbsolutePath(); if (getClass() != File.class) { @@ -652,8 +657,10 @@ public File getAbsoluteFile() { * @since 1.1 * @see Path#toRealPath */ - @SideEffectFree // pure with respect to .equals but not == - @ReleasesNoLocks // rest of file is not annotated for the Lock Checker + @CFComment({"rest of file is not annotated for the Lock Checker", + "pure with respect to .equals but not =="}) + @SideEffectFree + @ReleasesNoLocks public String getCanonicalPath() throws IOException { if (isInvalid()) { throw new IOException("Invalid file path"); @@ -682,7 +689,8 @@ public String getCanonicalPath() throws IOException { * @since 1.2 * @see Path#toRealPath */ - @SideEffectFree // pure with respect to .equals but not == + @CFComment({"pure with respect to .equals but not =="}) + @SideEffectFree public File getCanonicalFile() throws IOException { String canonPath = getCanonicalPath(); if (getClass() != File.class) { @@ -691,7 +699,8 @@ public File getCanonicalFile() throws IOException { return new File(canonPath, FS.prefixLength(canonPath)); } - @SideEffectFree // pure with respect to .equals but not == + @CFComment({"pure with respect to .equals but not =="}) + @SideEffectFree private static String slashify(String path, boolean isDirectory) { String p = path; if (File.separatorChar != '/') @@ -726,7 +735,8 @@ private static String slashify(String path, boolean isDirectory) { * {@link #toURI() toURI} method, and then converting the URI into a URL * via the {@link java.net.URI#toURL() URI.toURL} method. */ - @SideEffectFree // pure with respect to .equals but not == + @CFComment({"pure with respect to .equals but not =="}) + @SideEffectFree @Deprecated public URL toURL() throws MalformedURLException { if (isInvalid()) { @@ -778,7 +788,8 @@ public URL toURL() throws MalformedURLException { * @see java.net.URI#toURL() * @since 1.4 */ - @SideEffectFree // pure with respect to .equals but not == + @CFComment({"pure with respect to .equals but not =="}) + @SideEffectFree public URI toURI() { try { File f = getAbsoluteFile(); diff --git a/src/java.base/share/classes/java/io/FileNotFoundException.java b/src/java.base/share/classes/java/io/FileNotFoundException.java index 8d13aa3fdb9..331447c4d7b 100644 --- a/src/java.base/share/classes/java/io/FileNotFoundException.java +++ b/src/java.base/share/classes/java/io/FileNotFoundException.java @@ -25,6 +25,8 @@ package java.io; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; /** * Signals that an attempt to open the file denoted by a specified pathname @@ -39,6 +41,7 @@ * @since 1.0 */ +@AnnotatedFor({"nullness"}) public class FileNotFoundException extends IOException { @java.io.Serial private static final long serialVersionUID = -897856973823710492L; @@ -60,7 +63,7 @@ public FileNotFoundException() { * * @param s the detail message. */ - public FileNotFoundException(String s) { + public FileNotFoundException(@Nullable String s) { super(s); } @@ -73,7 +76,7 @@ public FileNotFoundException(String s) { * * @since 1.2 */ - private FileNotFoundException(String path, String reason) { + private FileNotFoundException(String path, @Nullable String reason) { super(path + ((reason == null) ? "" : " (" + reason + ")")); diff --git a/src/java.base/share/classes/java/io/IOError.java b/src/java.base/share/classes/java/io/IOError.java index 622143db9a8..1d6e6fbe2ab 100644 --- a/src/java.base/share/classes/java/io/IOError.java +++ b/src/java.base/share/classes/java/io/IOError.java @@ -25,12 +25,15 @@ package java.io; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; /** * Thrown when a serious I/O error has occurred. * * @author Xueming Shen * @since 1.6 */ +@AnnotatedFor({"nullness"}) public class IOError extends Error { /** * Constructs a new instance of IOError with the specified cause. The @@ -42,7 +45,7 @@ public class IOError extends Error { * The cause of this error, or {@code null} if the cause * is not known */ - public IOError(Throwable cause) { + public IOError(@Nullable Throwable cause) { super(cause); } diff --git a/src/java.base/share/classes/java/io/InputStream.java b/src/java.base/share/classes/java/io/InputStream.java index 9880c38a7f7..ddcf1ecaff9 100644 --- a/src/java.base/share/classes/java/io/InputStream.java +++ b/src/java.base/share/classes/java/io/InputStream.java @@ -25,12 +25,12 @@ package java.io; -import org.checkerframework.checker.mustcall.qual.MustCall; import org.checkerframework.checker.index.qual.GTENegativeOne; import org.checkerframework.checker.index.qual.IndexOrHigh; import org.checkerframework.checker.index.qual.LTEqLengthOf; import org.checkerframework.checker.index.qual.LTLengthOf; import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.mustcall.qual.MustCall; import org.checkerframework.framework.qual.AnnotatedFor; import java.util.ArrayList; diff --git a/src/java.base/share/classes/java/io/NotActiveException.java b/src/java.base/share/classes/java/io/NotActiveException.java index 3b8b281cbf4..7835518fdd0 100644 --- a/src/java.base/share/classes/java/io/NotActiveException.java +++ b/src/java.base/share/classes/java/io/NotActiveException.java @@ -25,11 +25,15 @@ package java.io; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Thrown when serialization or deserialization is not active. * * @since 1.1 */ +@AnnotatedFor({"nullness"}) public class NotActiveException extends ObjectStreamException { @java.io.Serial @@ -40,7 +44,7 @@ public class NotActiveException extends ObjectStreamException { * * @param reason a String describing the reason for the exception. */ - public NotActiveException(String reason) { + public NotActiveException(@Nullable String reason) { super(reason); } diff --git a/src/java.base/share/classes/java/io/NotSerializableException.java b/src/java.base/share/classes/java/io/NotSerializableException.java index d1010188272..a660b09e233 100644 --- a/src/java.base/share/classes/java/io/NotSerializableException.java +++ b/src/java.base/share/classes/java/io/NotSerializableException.java @@ -25,6 +25,9 @@ package java.io; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Thrown when an instance is required to have a Serializable interface. * The serialization runtime or the class of the instance can throw @@ -32,6 +35,7 @@ * * @since 1.1 */ +@AnnotatedFor({"nullness"}) public class NotSerializableException extends ObjectStreamException { @java.io.Serial @@ -42,7 +46,7 @@ public class NotSerializableException extends ObjectStreamException { * * @param classname Class of the instance being serialized/deserialized. */ - public NotSerializableException(String classname) { + public NotSerializableException(@Nullable String classname) { super(classname); } diff --git a/src/java.base/share/classes/java/io/OptionalDataException.java b/src/java.base/share/classes/java/io/OptionalDataException.java index f98bf079e8e..e62169b36fd 100644 --- a/src/java.base/share/classes/java/io/OptionalDataException.java +++ b/src/java.base/share/classes/java/io/OptionalDataException.java @@ -24,6 +24,8 @@ */ package java.io; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Exception indicating the failure of an object read operation due to * unread primitive data, or the end of data belonging to a serialized @@ -44,6 +46,7 @@ * * @since 1.1 */ +@AnnotatedFor({"nullness"}) public class OptionalDataException extends ObjectStreamException { @java.io.Serial diff --git a/src/java.base/share/classes/java/io/PrintWriter.java b/src/java.base/share/classes/java/io/PrintWriter.java index 026c0699451..f4a0d5268f7 100644 --- a/src/java.base/share/classes/java/io/PrintWriter.java +++ b/src/java.base/share/classes/java/io/PrintWriter.java @@ -120,8 +120,7 @@ private static Charset toCharset(String csn) * {@code printf}, or {@code format} methods will * flush the output buffer */ - public @MustCallAlias PrintWriter(@MustCallAlias Writer out, - boolean autoFlush) { + public @MustCallAlias PrintWriter(@MustCallAlias Writer out, boolean autoFlush) { super(out); this.out = out; this.autoFlush = autoFlush; diff --git a/src/java.base/share/classes/java/io/StreamCorruptedException.java b/src/java.base/share/classes/java/io/StreamCorruptedException.java index 5124c5ce657..408443f8a5b 100644 --- a/src/java.base/share/classes/java/io/StreamCorruptedException.java +++ b/src/java.base/share/classes/java/io/StreamCorruptedException.java @@ -25,12 +25,15 @@ package java.io; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; /** * Thrown when control information that was read from an object stream * violates internal consistency checks. * * @since 1.1 */ +@AnnotatedFor({"nullness"}) public class StreamCorruptedException extends ObjectStreamException { @java.io.Serial @@ -41,7 +44,7 @@ public class StreamCorruptedException extends ObjectStreamException { * * @param reason String describing the reason for the exception. */ - public StreamCorruptedException(String reason) { + public StreamCorruptedException(@Nullable String reason) { super(reason); } diff --git a/src/java.base/share/classes/java/io/SyncFailedException.java b/src/java.base/share/classes/java/io/SyncFailedException.java index e940b5a7e56..aedabf3add3 100644 --- a/src/java.base/share/classes/java/io/SyncFailedException.java +++ b/src/java.base/share/classes/java/io/SyncFailedException.java @@ -25,6 +25,9 @@ package java.io; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Signals that a sync operation has failed. * @@ -33,6 +36,7 @@ * @see java.io.IOException * @since 1.1 */ +@AnnotatedFor({"nullness"}) public class SyncFailedException extends IOException { @java.io.Serial private static final long serialVersionUID = -2353342684412443330L; @@ -43,7 +47,7 @@ public class SyncFailedException extends IOException { * * @param desc a String describing the exception. */ - public SyncFailedException(String desc) { + public SyncFailedException(@Nullable String desc) { super(desc); } } diff --git a/src/java.base/share/classes/java/io/UTFDataFormatException.java b/src/java.base/share/classes/java/io/UTFDataFormatException.java index bb8eb3b7d81..cc45ea2d3d3 100644 --- a/src/java.base/share/classes/java/io/UTFDataFormatException.java +++ b/src/java.base/share/classes/java/io/UTFDataFormatException.java @@ -25,6 +25,9 @@ package java.io; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Signals that a malformed string in * modified UTF-8 @@ -42,6 +45,7 @@ * @see java.io.IOException * @since 1.0 */ +@AnnotatedFor({"nullness"}) public class UTFDataFormatException extends IOException { @java.io.Serial private static final long serialVersionUID = 420743449228280612L; @@ -63,7 +67,7 @@ public UTFDataFormatException() { * * @param s the detail message. */ - public UTFDataFormatException(String s) { + public UTFDataFormatException(@Nullable String s) { super(s); } } diff --git a/src/java.base/share/classes/java/io/UnsupportedEncodingException.java b/src/java.base/share/classes/java/io/UnsupportedEncodingException.java index b80f453f5c6..48440f8ae19 100644 --- a/src/java.base/share/classes/java/io/UnsupportedEncodingException.java +++ b/src/java.base/share/classes/java/io/UnsupportedEncodingException.java @@ -24,12 +24,16 @@ */ package java.io; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * The Character Encoding is not supported. * * @author Asmus Freytag * @since 1.1 */ +@AnnotatedFor({"nullness"}) public class UnsupportedEncodingException extends IOException { @@ -47,7 +51,7 @@ public UnsupportedEncodingException() { * Constructs an UnsupportedEncodingException with a detail message. * @param s Describes the reason for the exception. */ - public UnsupportedEncodingException(String s) { + public UnsupportedEncodingException(@Nullable String s) { super(s); } } diff --git a/src/java.base/share/classes/java/io/WriteAbortedException.java b/src/java.base/share/classes/java/io/WriteAbortedException.java index 67e89574fa8..24ad3072853 100644 --- a/src/java.base/share/classes/java/io/WriteAbortedException.java +++ b/src/java.base/share/classes/java/io/WriteAbortedException.java @@ -26,6 +26,7 @@ package java.io; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; /** * Signals that one of the ObjectStreamExceptions was thrown during a @@ -37,6 +38,7 @@ * * @since 1.1 */ +@AnnotatedFor({"nullness"}) public class WriteAbortedException extends ObjectStreamException { @java.io.Serial private static final long serialVersionUID = -3326426625597282442L; @@ -51,7 +53,7 @@ public class WriteAbortedException extends ObjectStreamException { * @serial */ @Deprecated(since="17") - public Exception detail; + public @Nullable Exception detail; /** * Constructs a WriteAbortedException with a string describing @@ -59,7 +61,7 @@ public class WriteAbortedException extends ObjectStreamException { * @param s String describing the exception. * @param ex Exception causing the abort. */ - public WriteAbortedException(String s, Exception ex) { + public WriteAbortedException(@Nullable String s, @Nullable Exception ex) { super(s); initCause(null); // Disallow subsequent initCause detail = ex; diff --git a/src/java.base/share/classes/java/lang/Boolean.java b/src/java.base/share/classes/java/lang/Boolean.java index 8c9db13c582..e2f0f0e4d3d 100644 --- a/src/java.base/share/classes/java/lang/Boolean.java +++ b/src/java.base/share/classes/java/lang/Boolean.java @@ -241,9 +241,9 @@ public static boolean parseBoolean(@Nullable String s) { * * @return a string representation of this object. */ - @Override @StaticallyExecutable @SideEffectFree + @Override public @StringVal({"true", "false"}) String toString() { return String.valueOf(value); } diff --git a/src/java.base/share/classes/java/lang/Byte.java b/src/java.base/share/classes/java/lang/Byte.java index 0fc0480840e..b134b239f82 100644 --- a/src/java.base/share/classes/java/lang/Byte.java +++ b/src/java.base/share/classes/java/lang/Byte.java @@ -484,8 +484,8 @@ public Byte(String s) throws NumberFormatException { * @return a string representation of the value of this object in * base 10. */ - @Override @SideEffectFree + @Override public @ArrayLen({1,2,3,4}) String toString() { return Integer.toString(value); } diff --git a/src/java.base/share/classes/java/lang/CharSequence.java b/src/java.base/share/classes/java/lang/CharSequence.java index e79f030b6ed..6205b94885a 100644 --- a/src/java.base/share/classes/java/lang/CharSequence.java +++ b/src/java.base/share/classes/java/lang/CharSequence.java @@ -34,7 +34,6 @@ import org.checkerframework.checker.nonempty.qual.NonEmpty; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import java.util.NoSuchElementException; @@ -174,7 +173,6 @@ public boolean hasNext() { return cur < length(); } - @SideEffectsOnly("this") public int nextInt(@NonEmpty CharIterator this) { if (hasNext()) { return charAt(cur++); @@ -251,7 +249,6 @@ public boolean hasNext() { return cur < length(); } - @SideEffectsOnly("this") public int nextInt(@NonEmpty CodePointIterator this) { final int length = length(); diff --git a/src/java.base/share/classes/java/lang/Character.java b/src/java.base/share/classes/java/lang/Character.java index 6f61f863c54..0cca9a02153 100644 --- a/src/java.base/share/classes/java/lang/Character.java +++ b/src/java.base/share/classes/java/lang/Character.java @@ -9103,9 +9103,9 @@ public boolean equals(@Nullable Object obj) { * * @return a string representation of this object. */ - @Override @SideEffectFree @StaticallyExecutable + @Override public @ArrayLen(1) String toString() { return String.valueOf(value); } diff --git a/src/java.base/share/classes/java/lang/Double.java b/src/java.base/share/classes/java/lang/Double.java index 80129b34fd7..585904e9af3 100644 --- a/src/java.base/share/classes/java/lang/Double.java +++ b/src/java.base/share/classes/java/lang/Double.java @@ -843,9 +843,9 @@ public static boolean isNaN(double v) { * @return {@code true} if the value of the argument is positive * infinity or negative infinity; {@code false} otherwise. */ - @IntrinsicCandidate @Pure @StaticallyExecutable + @IntrinsicCandidate public static boolean isInfinite(double v) { return Math.abs(v) > MAX_VALUE; } @@ -864,9 +864,9 @@ public static boolean isInfinite(double v) { * floating-point value, {@code false} otherwise. * @since 1.8 */ - @IntrinsicCandidate @Pure @StaticallyExecutable + @IntrinsicCandidate public static boolean isFinite(double d) { return Math.abs(d) <= Double.MAX_VALUE; } diff --git a/src/java.base/share/classes/java/lang/Enum.java b/src/java.base/share/classes/java/lang/Enum.java index dca7ee40686..967fa47b1db 100644 --- a/src/java.base/share/classes/java/lang/Enum.java +++ b/src/java.base/share/classes/java/lang/Enum.java @@ -27,10 +27,10 @@ import org.checkerframework.checker.index.qual.NonNegative; import org.checkerframework.checker.initialization.qual.UnknownInitialization; -import org.checkerframework.checker.nullness.qual.UnknownKeyFor; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.lock.qual.GuardedByUnknown; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.UnknownKeyFor; import org.checkerframework.checker.tainting.qual.Tainted; import org.checkerframework.common.value.qual.PolyValue; import org.checkerframework.dataflow.qual.Pure; @@ -232,6 +232,7 @@ protected final Object clone(@GuardSatisfied Enum this) throws CloneNotSuppor * same enum type. The natural order implemented by this * method is the order in which the constants are declared. */ + @SuppressWarnings({"rawtypes"}) public final int compareTo(@UnknownKeyFor @Tainted E o) { Enum other = o; Enum self = this; diff --git a/src/java.base/share/classes/java/lang/Float.java b/src/java.base/share/classes/java/lang/Float.java index 4c1a88efee2..98aea693d9f 100644 --- a/src/java.base/share/classes/java/lang/Float.java +++ b/src/java.base/share/classes/java/lang/Float.java @@ -606,9 +606,9 @@ public static boolean isNaN(float v) { * @return {@code true} if the argument is positive infinity or * negative infinity; {@code false} otherwise. */ - @IntrinsicCandidate @Pure @StaticallyExecutable + @IntrinsicCandidate public static boolean isInfinite(float v) { return Math.abs(v) > MAX_VALUE; } @@ -628,8 +628,8 @@ public static boolean isInfinite(float v) { * floating-point value, {@code false} otherwise. * @since 1.8 */ - @IntrinsicCandidate @StaticallyExecutable + @IntrinsicCandidate public static boolean isFinite(float f) { return Math.abs(f) <= Float.MAX_VALUE; } diff --git a/src/java.base/share/classes/java/lang/IllegalCallerException.java b/src/java.base/share/classes/java/lang/IllegalCallerException.java index 68c3ff00d9f..e0d1f355a98 100644 --- a/src/java.base/share/classes/java/lang/IllegalCallerException.java +++ b/src/java.base/share/classes/java/lang/IllegalCallerException.java @@ -25,12 +25,16 @@ package java.lang; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Thrown to indicate that a method has been called by an inappropriate caller. * * @since 9 * @see StackWalker#getCallerClass */ +@AnnotatedFor({"nullness"}) public class IllegalCallerException extends RuntimeException { /** * Constructs an IllegalCallerException with no detail message. @@ -45,7 +49,7 @@ public IllegalCallerException() { * * @param s the String that contains a detailed message (can be null) */ - public IllegalCallerException(String s) { + public IllegalCallerException(@Nullable String s) { super(s); } @@ -56,7 +60,7 @@ public IllegalCallerException(String s) { * @param message the detail message (can be null) * @param cause the cause (can be null) */ - public IllegalCallerException(String message, Throwable cause) { + public IllegalCallerException(@Nullable String message, @Nullable Throwable cause) { super(message, cause); } @@ -67,7 +71,7 @@ public IllegalCallerException(String message, Throwable cause) { * * @param cause the cause (can be null) */ - public IllegalCallerException(Throwable cause) { + public IllegalCallerException(@Nullable Throwable cause) { super(cause); } diff --git a/src/java.base/share/classes/java/lang/InheritableThreadLocal.java b/src/java.base/share/classes/java/lang/InheritableThreadLocal.java index 2641fd6f25b..3335bc2c974 100644 --- a/src/java.base/share/classes/java/lang/InheritableThreadLocal.java +++ b/src/java.base/share/classes/java/lang/InheritableThreadLocal.java @@ -29,6 +29,7 @@ import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; + /** * This class extends {@code ThreadLocal} to provide inheritance of values * from parent thread to child thread: when a child thread is created, the diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index 1aed99355d4..63f113950e8 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -1591,9 +1591,9 @@ public static int compare(int x, int y) { * unsigned values * @since 1.8 */ - @IntrinsicCandidate @Pure @StaticallyExecutable + @IntrinsicCandidate public static int compareUnsigned(@Unsigned int x, @Unsigned int y) { return compare(x + MIN_VALUE, y + MIN_VALUE); } @@ -1639,9 +1639,9 @@ public static int compareUnsigned(@Unsigned int x, @Unsigned int y) { * @see #remainderUnsigned * @since 1.8 */ - @IntrinsicCandidate @Pure @StaticallyExecutable + @IntrinsicCandidate public static @Unsigned int divideUnsigned(@Unsigned int dividend, @Unsigned int divisor) { // In lieu of tricky code, for now just use long arithmetic. return (int)(toUnsignedLong(dividend) / toUnsignedLong(divisor)); @@ -1659,9 +1659,9 @@ public static int compareUnsigned(@Unsigned int x, @Unsigned int y) { * @see #divideUnsigned * @since 1.8 */ - @IntrinsicCandidate @Pure @StaticallyExecutable + @IntrinsicCandidate public static @Unsigned int remainderUnsigned(@Unsigned int dividend, @Unsigned int divisor) { // In lieu of tricky code, for now just use long arithmetic. return (int)(toUnsignedLong(dividend) % toUnsignedLong(divisor)); @@ -1875,9 +1875,9 @@ public static int lowestOneBit(@UnknownSignedness int i) { * specified {@code int} value. * @since 1.5 */ - @IntrinsicCandidate @Pure @StaticallyExecutable + @IntrinsicCandidate public static @SignednessGlb int reverse(@PolySigned int i) { // HD, Figure 7-1 i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555; diff --git a/src/java.base/share/classes/java/lang/Iterable.java b/src/java.base/share/classes/java/lang/Iterable.java index 89990f6f8f7..2b0cacbbfbc 100644 --- a/src/java.base/share/classes/java/lang/Iterable.java +++ b/src/java.base/share/classes/java/lang/Iterable.java @@ -24,6 +24,7 @@ */ package java.lang; +import org.checkerframework.checker.index.qual.PolyGrowShrink; import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.common.aliasing.qual.NonLeaked; import org.checkerframework.framework.qual.AnnotatedFor; @@ -50,7 +51,7 @@ public interface Iterable { * * @return an Iterator. */ - @PolyNonEmpty Iterator iterator(@PolyNonEmpty Iterable this); + @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty Iterable this); /** * Performs the given action for each element of the {@code Iterable} diff --git a/src/java.base/share/classes/java/lang/LayerInstantiationException.java b/src/java.base/share/classes/java/lang/LayerInstantiationException.java index 6c1469df79b..ad86fb4745d 100644 --- a/src/java.base/share/classes/java/lang/LayerInstantiationException.java +++ b/src/java.base/share/classes/java/lang/LayerInstantiationException.java @@ -25,12 +25,16 @@ package java.lang; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Thrown when creating a {@linkplain ModuleLayer module layer} fails. * * @see ModuleLayer * @since 9 */ +@AnnotatedFor({"nullness"}) public class LayerInstantiationException extends RuntimeException { @java.io.Serial private static final long serialVersionUID = -906239691613568347L; @@ -48,7 +52,7 @@ public LayerInstantiationException() { * @param msg * The detail message; can be {@code null} */ - public LayerInstantiationException(String msg) { + public LayerInstantiationException(@Nullable String msg) { super(msg); } @@ -58,7 +62,7 @@ public LayerInstantiationException(String msg) { * @param cause * The cause; can be {@code null} */ - public LayerInstantiationException(Throwable cause) { + public LayerInstantiationException(@Nullable Throwable cause) { super(cause); } @@ -71,7 +75,7 @@ public LayerInstantiationException(Throwable cause) { * @param cause * The cause; can be {@code null} */ - public LayerInstantiationException(String msg, Throwable cause) { + public LayerInstantiationException(@Nullable String msg, @Nullable Throwable cause) { super(msg, cause); } } diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index 6a12d9ba3cc..24c8f1f14f0 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -1732,9 +1732,9 @@ public static int compare(long x, long y) { * unsigned values * @since 1.8 */ - @IntrinsicCandidate @Pure @StaticallyExecutable + @IntrinsicCandidate public static int compareUnsigned(@Unsigned long x, @Unsigned long y) { return compare(x + MIN_VALUE, y + MIN_VALUE); } @@ -1758,9 +1758,9 @@ public static int compareUnsigned(@Unsigned long x, @Unsigned long y) { * @see #remainderUnsigned * @since 1.8 */ - @IntrinsicCandidate @Pure @StaticallyExecutable + @IntrinsicCandidate public static @Unsigned long divideUnsigned(@Unsigned long dividend, @Unsigned long divisor) { /* See Hacker's Delight (2nd ed), section 9.3 */ if (divisor >= 0) { @@ -1783,9 +1783,9 @@ public static int compareUnsigned(@Unsigned long x, @Unsigned long y) { * @see #divideUnsigned * @since 1.8 */ - @IntrinsicCandidate @Pure @StaticallyExecutable + @IntrinsicCandidate public static @Unsigned long remainderUnsigned(@Unsigned long dividend, @Unsigned long divisor) { /* See Hacker's Delight (2nd ed), section 9.3 */ if (divisor >= 0) { @@ -2012,9 +2012,9 @@ public static long lowestOneBit(@UnknownSignedness long i) { * specified {@code long} value. * @since 1.5 */ - @IntrinsicCandidate @Pure @StaticallyExecutable + @IntrinsicCandidate public static @SignednessGlb long reverse(@PolySigned long i) { // HD, Figure 7-1 i = (i & 0x5555555555555555L) << 1 | (i >>> 1) & 0x5555555555555555L; diff --git a/src/java.base/share/classes/java/lang/Math.java b/src/java.base/share/classes/java/lang/Math.java index 75fdc4754e1..ed9a8899556 100644 --- a/src/java.base/share/classes/java/lang/Math.java +++ b/src/java.base/share/classes/java/lang/Math.java @@ -799,8 +799,8 @@ public static double pow(double a, double b) { * @see java.lang.Integer#MAX_VALUE * @see java.lang.Integer#MIN_VALUE */ - @IntrinsicCandidate @Pure + @IntrinsicCandidate public static int round(float a) { int intBits = Float.floatToRawIntBits(a); int biasedExp = (intBits & FloatConsts.EXP_BIT_MASK) @@ -850,8 +850,8 @@ public static int round(float a) { * @see java.lang.Long#MAX_VALUE * @see java.lang.Long#MIN_VALUE */ - @IntrinsicCandidate @Pure + @IntrinsicCandidate public static long round(double a) { long longBits = Double.doubleToRawLongBits(a); long biasedExp = (longBits & DoubleConsts.EXP_BIT_MASK) diff --git a/src/java.base/share/classes/java/lang/ProcessBuilder.java b/src/java.base/share/classes/java/lang/ProcessBuilder.java index 8f43981a775..8fbb26db26d 100644 --- a/src/java.base/share/classes/java/lang/ProcessBuilder.java +++ b/src/java.base/share/classes/java/lang/ProcessBuilder.java @@ -31,7 +31,6 @@ import org.checkerframework.framework.qual.AnnotatedFor; import jdk.internal.util.OperatingSystem; - import java.io.File; import java.io.FileDescriptor; import java.io.IOException; diff --git a/src/java.base/share/classes/java/lang/Record.java b/src/java.base/share/classes/java/lang/Record.java index 8317b19dbd2..35232720c95 100644 --- a/src/java.base/share/classes/java/lang/Record.java +++ b/src/java.base/share/classes/java/lang/Record.java @@ -26,6 +26,8 @@ import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.signedness.qual.UnknownSignedness; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; /** * This is the common base class of all Java language record classes. @@ -90,6 +92,7 @@ * @jls 8.10 Record Types * @since 16 */ +@AnnotatedFor({"initialization", "nullness"}) public abstract class Record { /** * Constructor for record classes to call. @@ -143,7 +146,7 @@ protected Record() {} * argument; {@code false} otherwise. */ @Override - public abstract boolean equals(@GuardSatisfied Record this, @GuardSatisfied Object obj); + public abstract boolean equals(@GuardSatisfied Record this, @GuardSatisfied @Nullable Object obj); /** * Returns a hash code value for the record. diff --git a/src/java.base/share/classes/java/lang/ReflectiveOperationException.java b/src/java.base/share/classes/java/lang/ReflectiveOperationException.java index 0c79de008be..fe27804a775 100644 --- a/src/java.base/share/classes/java/lang/ReflectiveOperationException.java +++ b/src/java.base/share/classes/java/lang/ReflectiveOperationException.java @@ -25,6 +25,9 @@ package java.lang; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Common superclass of exceptions thrown by reflective operations in * core reflection. @@ -32,6 +35,7 @@ * @see LinkageError * @since 1.7 */ +@AnnotatedFor({"nullness"}) public class ReflectiveOperationException extends Exception { @java.io.Serial static final long serialVersionUID = 123456789L; @@ -53,7 +57,7 @@ public ReflectiveOperationException() { * @param message the detail message. The detail message is saved for * later retrieval by the {@link #getMessage()} method. */ - public ReflectiveOperationException(String message) { + public ReflectiveOperationException(@Nullable String message) { super(message); } @@ -72,7 +76,7 @@ public ReflectiveOperationException(String message) { * permitted, and indicates that the cause is nonexistent or * unknown.) */ - public ReflectiveOperationException(String message, Throwable cause) { + public ReflectiveOperationException(@Nullable String message, @Nullable Throwable cause) { super(message, cause); } @@ -86,7 +90,7 @@ public ReflectiveOperationException(String message, Throwable cause) { * permitted, and indicates that the cause is nonexistent or * unknown.) */ - public ReflectiveOperationException(Throwable cause) { + public ReflectiveOperationException(@Nullable Throwable cause) { super(cause); } } diff --git a/src/java.base/share/classes/java/lang/Runtime.java b/src/java.base/share/classes/java/lang/Runtime.java index 7af75280438..85934893b83 100644 --- a/src/java.base/share/classes/java/lang/Runtime.java +++ b/src/java.base/share/classes/java/lang/Runtime.java @@ -534,7 +534,7 @@ public Process exec(@Untainted String command, @Untainted String @Nullable [] en * * @see ProcessBuilder */ - public Process exec(@Untainted String [] cmdarray) throws IOException { + public Process exec(@Untainted String[] cmdarray) throws IOException { return exec(cmdarray, null, null); } diff --git a/src/java.base/share/classes/java/lang/Short.java b/src/java.base/share/classes/java/lang/Short.java index 0795e219af7..78f370124b6 100644 --- a/src/java.base/share/classes/java/lang/Short.java +++ b/src/java.base/share/classes/java/lang/Short.java @@ -490,9 +490,9 @@ public Short(String s) throws NumberFormatException { * @return a string representation of the value of this object in * base 10. */ - @Override @SideEffectFree @StaticallyExecutable + @Override public @ArrayLen({1, 2, 3, 4, 5, 6}) String toString() { return Integer.toString(value); } diff --git a/src/java.base/share/classes/java/lang/StackStreamFactory.java b/src/java.base/share/classes/java/lang/StackStreamFactory.java index 2900a4f31ce..37fb1188aea 100644 --- a/src/java.base/share/classes/java/lang/StackStreamFactory.java +++ b/src/java.base/share/classes/java/lang/StackStreamFactory.java @@ -26,7 +26,6 @@ import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import jdk.internal.reflect.MethodAccessor; import jdk.internal.reflect.ConstructorAccessor; import java.lang.StackWalker.Option; @@ -375,7 +374,6 @@ private void setContinuation(Continuation cont) { * * @see #tryNextFrame */ - @SideEffectsOnly("this") final Class nextFrame() { if (!hasNext()) { return null; diff --git a/src/java.base/share/classes/java/lang/StackTraceElement.java b/src/java.base/share/classes/java/lang/StackTraceElement.java index 3f4adc1a4d1..9ef9094ebc0 100644 --- a/src/java.base/share/classes/java/lang/StackTraceElement.java +++ b/src/java.base/share/classes/java/lang/StackTraceElement.java @@ -28,6 +28,7 @@ import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.signature.qual.FullyQualifiedName; +import org.checkerframework.checker.signature.qual.Identifier; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; import org.checkerframework.framework.qual.AnnotatedFor; @@ -127,7 +128,7 @@ public final class StackTraceElement implements java.io.Serializable { * @since 1.5 * @revised 9 */ - public StackTraceElement(@FullyQualifiedName String declaringClass, String methodName, + public StackTraceElement(@FullyQualifiedName String declaringClass, @Identifier String methodName, @Nullable String fileName, int lineNumber) { this(null, null, null, declaringClass, methodName, fileName, lineNumber); } @@ -165,7 +166,7 @@ public StackTraceElement(@FullyQualifiedName String declaringClass, String metho */ public StackTraceElement(String classLoaderName, String moduleName, String moduleVersion, - String declaringClass, String methodName, + String declaringClass, @Identifier String methodName, String fileName, int lineNumber) { this.classLoaderName = classLoaderName; this.moduleName = moduleName; @@ -278,7 +279,7 @@ public String getClassLoaderName() { * @return the name of the method containing the execution point * represented by this stack trace element. */ - public String getMethodName(@GuardSatisfied StackTraceElement this) { + public @Identifier String getMethodName(@GuardSatisfied StackTraceElement this) { return methodName; } @@ -367,8 +368,8 @@ public boolean isNativeMethod(@GuardSatisfied StackTraceElement this) { * @revised 9 * @see Throwable#printStackTrace() */ - @Override @SideEffectFree + @Override public String toString(@GuardSatisfied StackTraceElement this) { int estimatedLength = length(classLoaderName) + 1 + length(moduleName) + 1 diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 7a68dbfa1bd..fb318111bce 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -571,7 +571,6 @@ private static Void rangeCheck(char[] value, int offset, int count) { */ @SideEffectFree @StaticallyExecutable - @SuppressWarnings("removal") public @Unique String(@PolySigned byte @GuardSatisfied [] bytes, @IndexOrHigh({"#1"}) int offset, @LTLengthOf(value={"#1"}, offset={"#2 - 1"}) @NonNegative int length, Charset charset) { this(Objects.requireNonNull(charset), bytes, checkBoundsOffCount(offset, length, bytes.length), length); } @@ -583,7 +582,7 @@ private static Void rangeCheck(char[] value, int offset, int count) { * disambiguate it against other similar methods of this class. */ @SuppressWarnings("removal") - private String(Charset charset, byte[] bytes, int offset, int length) { + private @Unique String(Charset charset, @PolySigned byte @GuardSatisfied [] bytes, @IndexOrHigh({"#1"}) int offset, @LTLengthOf(value={"#1"}, offset={"#2 - 1"}) @NonNegative int length) { if (length == 0) { this.value = "".value; this.coder = "".coder; @@ -3479,8 +3478,7 @@ public String replace(@GuardSatisfied CharSequence target, @GuardSatisfied CharS return split(regex, limit, true); } - private String[] split(String regex, int limit, boolean withDelimiters) { - /* fastpath if the regex is a + private String[] split(String regex, int limit, boolean withDelimiters) { /* fastpath if the regex is a * (1) one-char String and this character is not one of the * RegEx's meta characters ".$|()[{^?*+\\", or * (2) two-char String and the first char is the backslash and @@ -3627,7 +3625,7 @@ private String[] split(char ch, int limit, boolean withDelimiters) { */ @SideEffectFree @StaticallyExecutable - public static String join(CharSequence delimiter, CharSequence... elements) { + public static String join(CharSequence delimiter, @Nullable CharSequence... elements) { var delim = delimiter.toString(); var elems = new String[elements.length]; for (int i = 0; i < elements.length; i++) { @@ -3723,7 +3721,7 @@ static String join(String prefix, String suffix, String delimiter, String[] elem @SideEffectFree @StaticallyExecutable public static String join(CharSequence delimiter, - Iterable elements) { + Iterable elements) { Objects.requireNonNull(delimiter); Objects.requireNonNull(elements); var delim = delimiter.toString(); @@ -4640,7 +4638,7 @@ public static String format(@GuardSatisfied @Nullable Locale l, String format, @ * */ @SideEffectFree - public String formatted(Object... args) { + public String formatted(@Nullable Object... args) { return new Formatter().format(this, args).toString(); } diff --git a/src/java.base/share/classes/java/lang/StringBuffer.java b/src/java.base/share/classes/java/lang/StringBuffer.java index 3ab2df5af4a..b190f11f944 100644 --- a/src/java.base/share/classes/java/lang/StringBuffer.java +++ b/src/java.base/share/classes/java/lang/StringBuffer.java @@ -30,12 +30,12 @@ import org.checkerframework.checker.index.qual.NonNegative; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.common.aliasing.qual.LeakedToResult; +import org.checkerframework.common.aliasing.qual.NonLeaked; +import org.checkerframework.common.aliasing.qual.Unique; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; import org.checkerframework.framework.qual.AnnotatedFor; -import org.checkerframework.common.aliasing.qual.Unique; -import org.checkerframework.common.aliasing.qual.LeakedToResult; -import org.checkerframework.common.aliasing.qual.NonLeaked; import java.io.IOException; import java.io.ObjectInputStream; @@ -726,6 +726,7 @@ public synchronized StringBuffer reverse() { return this; } + @SideEffectFree /** * @throws IllegalArgumentException {@inheritDoc} * @@ -748,8 +749,8 @@ public synchronized StringBuffer repeat(CharSequence cs, int count) { return this; } - @IntrinsicCandidate @Override + @IntrinsicCandidate @SideEffectFree public synchronized String toString(@GuardSatisfied StringBuffer this) { if (toStringCache == null) { diff --git a/src/java.base/share/classes/java/lang/StringBuilder.java b/src/java.base/share/classes/java/lang/StringBuilder.java index 2886543c2b2..11266a99d20 100644 --- a/src/java.base/share/classes/java/lang/StringBuilder.java +++ b/src/java.base/share/classes/java/lang/StringBuilder.java @@ -34,7 +34,6 @@ import org.checkerframework.checker.regex.qual.PolyRegex; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import jdk.internal.vm.annotation.IntrinsicCandidate; @@ -100,7 +99,7 @@ * @see java.lang.String * @since 1.5 */ -@AnnotatedFor({"lock", "nullness", "index", "regex", "sideeffectsonly"}) +@AnnotatedFor({"lock", "nullness", "index", "regex"}) public final class StringBuilder extends AbstractStringBuilder implements Appendable, java.io.Serializable, Comparable, CharSequence @@ -182,14 +181,12 @@ public int compareTo(StringBuilder another) { } @Override - @SideEffectsOnly("this") public StringBuilder append(@GuardSatisfied @Nullable Object obj) { return append(String.valueOf(obj)); } @Override @IntrinsicCandidate - @SideEffectsOnly("this") public StringBuilder append(@Nullable String str) { super.append(str); return this; @@ -214,14 +211,12 @@ public StringBuilder append(@Nullable String str) { * @param sb the {@code StringBuffer} to append. * @return a reference to this object. */ - @SideEffectsOnly("this") public StringBuilder append(@Nullable StringBuffer sb) { super.append(sb); return this; } @Override - @SideEffectsOnly("this") public StringBuilder append(@Nullable CharSequence s) { super.append(s); return this; @@ -231,14 +226,12 @@ public StringBuilder append(@Nullable CharSequence s) { * @throws IndexOutOfBoundsException {@inheritDoc} */ @Override - @SideEffectsOnly("this") public StringBuilder append(@Nullable CharSequence s, @IndexOrHigh({"#1"}) int start, @IndexOrHigh({"#1"}) int end) { super.append(s, start, end); return this; } @Override - @SideEffectsOnly("this") public StringBuilder append(char[] str) { super.append(str); return this; @@ -248,14 +241,12 @@ public StringBuilder append(char[] str) { * @throws IndexOutOfBoundsException {@inheritDoc} */ @Override - @SideEffectsOnly("this") public StringBuilder append(char[] str, @IndexOrHigh({"#1"}) int offset, @LTLengthOf(value={"#1"}, offset={"#2 - 1"}) @NonNegative int len) { super.append(str, offset, len); return this; } @Override - @SideEffectsOnly("this") public StringBuilder append(boolean b) { super.append(b); return this; @@ -263,7 +254,6 @@ public StringBuilder append(boolean b) { @Override @IntrinsicCandidate - @SideEffectsOnly("this") public StringBuilder append(char c) { super.append(c); return this; @@ -271,28 +261,24 @@ public StringBuilder append(char c) { @Override @IntrinsicCandidate - @SideEffectsOnly("this") public StringBuilder append(int i) { super.append(i); return this; } @Override - @SideEffectsOnly("this") public StringBuilder append(long lng) { super.append(lng); return this; } @Override - @SideEffectsOnly("this") public StringBuilder append(float f) { super.append(f); return this; } @Override - @SideEffectsOnly("this") public StringBuilder append(double d) { super.append(d); return this; @@ -302,7 +288,6 @@ public StringBuilder append(double d) { * @since 1.5 */ @Override - @SideEffectsOnly("this") public StringBuilder appendCodePoint(int codePoint) { super.appendCodePoint(codePoint); return this; @@ -312,7 +297,6 @@ public StringBuilder appendCodePoint(int codePoint) { * @throws StringIndexOutOfBoundsException {@inheritDoc} */ @Override - @SideEffectsOnly("this") public StringBuilder delete(@NonNegative int start, @NonNegative int end) { super.delete(start, end); return this; @@ -322,7 +306,6 @@ public StringBuilder delete(@NonNegative int start, @NonNegative int end) { * @throws StringIndexOutOfBoundsException {@inheritDoc} */ @Override - @SideEffectsOnly("this") public StringBuilder deleteCharAt(@NonNegative int index) { super.deleteCharAt(index); return this; @@ -332,7 +315,6 @@ public StringBuilder deleteCharAt(@NonNegative int index) { * @throws StringIndexOutOfBoundsException {@inheritDoc} */ @Override - @SideEffectsOnly("this") public StringBuilder replace(@NonNegative int start, @NonNegative int end, String str) { super.replace(start, end, str); return this; @@ -342,7 +324,6 @@ public StringBuilder replace(@NonNegative int start, @NonNegative int end, Strin * @throws StringIndexOutOfBoundsException {@inheritDoc} */ @Override - @SideEffectsOnly("this") public StringBuilder insert(@NonNegative int index, char[] str, @IndexOrHigh({"#2"}) int offset, @IndexOrHigh({"#2"}) int len) { @@ -354,7 +335,6 @@ public StringBuilder insert(@NonNegative int index, char[] str, @IndexOrHigh({"# * @throws StringIndexOutOfBoundsException {@inheritDoc} */ @Override - @SideEffectsOnly("this") public StringBuilder insert(@NonNegative int offset, @GuardSatisfied @Nullable Object obj) { super.insert(offset, obj); return this; @@ -364,7 +344,6 @@ public StringBuilder insert(@NonNegative int offset, @GuardSatisfied @Nullable O * @throws StringIndexOutOfBoundsException {@inheritDoc} */ @Override - @SideEffectsOnly("this") public StringBuilder insert(@NonNegative int offset, @Nullable String str) { super.insert(offset, str); return this; @@ -374,7 +353,6 @@ public StringBuilder insert(@NonNegative int offset, @Nullable String str) { * @throws StringIndexOutOfBoundsException {@inheritDoc} */ @Override - @SideEffectsOnly("this") public StringBuilder insert(@NonNegative int offset, char[] str) { super.insert(offset, str); return this; @@ -384,7 +362,6 @@ public StringBuilder insert(@NonNegative int offset, char[] str) { * @throws IndexOutOfBoundsException {@inheritDoc} */ @Override - @SideEffectsOnly("this") public StringBuilder insert(@NonNegative int dstOffset, @Nullable CharSequence s) { super.insert(dstOffset, s); return this; @@ -394,7 +371,6 @@ public StringBuilder insert(@NonNegative int dstOffset, @Nullable CharSequence s * @throws IndexOutOfBoundsException {@inheritDoc} */ @Override - @SideEffectsOnly("this") public StringBuilder insert(@NonNegative int dstOffset, @Nullable CharSequence s, @NonNegative int start, @NonNegative int end) { @@ -406,7 +382,6 @@ public StringBuilder insert(@NonNegative int dstOffset, @Nullable CharSequence s * @throws StringIndexOutOfBoundsException {@inheritDoc} */ @Override - @SideEffectsOnly("this") public StringBuilder insert(@NonNegative int offset, boolean b) { super.insert(offset, b); return this; @@ -416,7 +391,6 @@ public StringBuilder insert(@NonNegative int offset, boolean b) { * @throws IndexOutOfBoundsException {@inheritDoc} */ @Override - @SideEffectsOnly("this") public StringBuilder insert(@NonNegative int offset, char c) { super.insert(offset, c); return this; @@ -426,7 +400,6 @@ public StringBuilder insert(@NonNegative int offset, char c) { * @throws StringIndexOutOfBoundsException {@inheritDoc} */ @Override - @SideEffectsOnly("this") public StringBuilder insert(@NonNegative int offset, int i) { super.insert(offset, i); return this; @@ -436,7 +409,6 @@ public StringBuilder insert(@NonNegative int offset, int i) { * @throws StringIndexOutOfBoundsException {@inheritDoc} */ @Override - @SideEffectsOnly("this") public StringBuilder insert(@NonNegative int offset, long l) { super.insert(offset, l); return this; @@ -446,7 +418,6 @@ public StringBuilder insert(@NonNegative int offset, long l) { * @throws StringIndexOutOfBoundsException {@inheritDoc} */ @Override - @SideEffectsOnly("this") public StringBuilder insert(@NonNegative int offset, float f) { super.insert(offset, f); return this; @@ -456,7 +427,6 @@ public StringBuilder insert(@NonNegative int offset, float f) { * @throws StringIndexOutOfBoundsException {@inheritDoc} */ @Override - @SideEffectsOnly("this") public StringBuilder insert(@NonNegative int offset, double d) { super.insert(offset, d); return this; @@ -487,12 +457,12 @@ public StringBuilder insert(@NonNegative int offset, double d) { } @Override - @SideEffectsOnly("this") public StringBuilder reverse() { super.reverse(); return this; } + @SideEffectFree /** * @throws IllegalArgumentException {@inheritDoc} * @@ -515,8 +485,8 @@ public StringBuilder repeat(CharSequence cs, int count) { return this; } - @IntrinsicCandidate @Override + @IntrinsicCandidate @SideEffectFree public @PolyRegex String toString(@GuardSatisfied @PolyRegex StringBuilder this) { // Create a copy, don't share the array diff --git a/src/java.base/share/classes/java/lang/Thread.java b/src/java.base/share/classes/java/lang/Thread.java index b0c2b9f267d..179899dbb99 100644 --- a/src/java.base/share/classes/java/lang/Thread.java +++ b/src/java.base/share/classes/java/lang/Thread.java @@ -1419,8 +1419,7 @@ public Thread(@Nullable ThreadGroup group, @Nullable Runnable task, String name) * @since 1.4 * @see Inheritance when creating threads */ - public Thread(@Nullable ThreadGroup group, @Nullable Runnable task, String name, - long stackSize) { + public Thread(@Nullable ThreadGroup group, @Nullable Runnable task, String name, long stackSize) { this(group, checkName(name), 0, task, stackSize, null); } diff --git a/src/java.base/share/classes/java/lang/ThreadGroup.java b/src/java.base/share/classes/java/lang/ThreadGroup.java index 78a23555768..f994598eee3 100644 --- a/src/java.base/share/classes/java/lang/ThreadGroup.java +++ b/src/java.base/share/classes/java/lang/ThreadGroup.java @@ -85,18 +85,6 @@ * * @since 1.0 */ - -/* The locking strategy for this code is to try to lock only one level of the - * tree wherever possible, but otherwise to lock from the bottom up. - * That is, from child thread groups to parents. - * This has the advantage of limiting the number of locks that need to be held - * and in particular avoids having to grab the lock for the root thread group, - * (or a global lock) which would be a source of contention on a - * multi-processor system with many thread groups. - * This policy often leads to taking a snapshot of the state of a thread group - * and working off of that snapshot, rather than holding the thread group locked - * while we work on the children. - */ @AnnotatedFor({"index", "interning", "lock", "nullness"}) public @UsesObjectEquals class ThreadGroup implements Thread.UncaughtExceptionHandler { /** @@ -263,7 +251,7 @@ public final boolean isDaemon(@GuardSatisfied ThreadGroup this) { */ @Pure @Deprecated(since="16", forRemoval=true) - public synchronized boolean isDestroyed(@GuardSatisfied ThreadGroup this) { + public boolean isDestroyed(@GuardSatisfied ThreadGroup this) { return false; } @@ -323,8 +311,6 @@ public final void setDaemon(boolean daemon) { * @see java.lang.SecurityException * @see java.lang.ThreadGroup#checkAccess() */ - @CFComment({"index: groupSnapshot.length = ngroupsSnapshot by #0.1", - "for the else case, ngroupsSnapshot will be null and it will never enter the group as nGroups will be 0"}) @SuppressWarnings("index:array.access.unsafe.high") public final void setMaxPriority(int pri) { checkAccess(); @@ -401,8 +387,6 @@ public final void checkAccess() { * group and in any other thread group that has this thread * group as an ancestor */ - @CFComment({"index: groupSnapshot.length = ngroupsSnapshot by #0.1", - "for the else case, ngroupsSnapshot will be null and it will never enter the group as nGroups will be 0"}) @SuppressWarnings("index:array.access.unsafe.high") public @NonNegative int activeCount() { int n = 0; @@ -436,7 +420,7 @@ public final void checkAccess() { * if {@linkplain #checkAccess checkAccess} determines that * the current thread cannot access this thread group */ - public @NonNegative int enumerate(@PolyNull Thread[] list) { + public @NonNegative int enumerate(Thread[] list) { return enumerate(list, true); } @@ -471,7 +455,7 @@ public final void checkAccess() { * if {@linkplain #checkAccess checkAccess} determines that * the current thread cannot access this thread group */ - public @NonNegative int enumerate(@PolyNull Thread[] list, boolean recurse) { + public @NonNegative int enumerate(Thread[] list, boolean recurse) { Objects.requireNonNull(list); checkAccess(); int n = 0; @@ -502,10 +486,8 @@ public final void checkAccess() { * @return the number of thread groups with this thread group as * an ancestor */ - @CFComment({"index: groupSnapshot.length = ngroupsSnapshot by #0.1", - "for the else case, ngroupsSnapshot will be null and it will never enter the group as nGroups will be 0"}) @SuppressWarnings("index:array.access.unsafe.high") - public @NonNegative int activeGroupCount() { + public int activeGroupCount() { int n = 0; for (ThreadGroup group : synchronizedSubgroups()) { n = n + group.activeGroupCount() + 1; @@ -533,7 +515,7 @@ public final void checkAccess() { * if {@linkplain #checkAccess checkAccess} determines that * the current thread cannot access this thread group */ - public @NonNegative int enumerate(@PolyNull ThreadGroup[] list) { + public @NonNegative int enumerate(ThreadGroup[] list) { return enumerate(list, true); } @@ -567,9 +549,8 @@ public final void checkAccess() { * if {@linkplain #checkAccess checkAccess} determines that * the current thread cannot access this thread group */ - public @NonNegative int enumerate(@PolyNull ThreadGroup[] list, boolean recurse) { - Objects.requireNonNull(list); - checkAccess(); + public @NonNegative int enumerate(ThreadGroup[] list, boolean recurse) { + Objects.requireNonNull(list); checkAccess(); return enumerate(list, 0, recurse); } @@ -577,9 +558,6 @@ public final void checkAccess() { * Add a reference to each subgroup to the given array, starting at * the given index. Returns the new index. */ - @CFComment({"index: groupSnapshot.length = ngroupsSnapshot by #0.1", - "for the else case ngroupsSnapshot will be null and it will never enter the group as nGroups will be 0"}) - @SuppressWarnings("index:array.access.unsafe.high") private @NonNegative int enumerate(ThreadGroup[] list, @NonNegative int i, boolean recurse) { List subgroups = synchronizedSubgroups(); for (int j = 0; j < subgroups.size() && i < list.length; j++) { @@ -615,8 +593,6 @@ public final void stop() { * @see java.lang.ThreadGroup#checkAccess() * @since 1.2 */ - @CFComment({" groupSnapshot.length = ngroupsSnapshot by #0.1", - "for the else case, ngroupsSnapshot will be null and it will never enter the group as nGroups will be 0"}) @SuppressWarnings("index:array.access.unsafe.high") public final void interrupt() { checkAccess(); @@ -645,9 +621,8 @@ public final void suspend() { * @deprecated This method was originally specified to resume all threads * in the thread group. */ - @CFComment({"index: // groupSnapshot.length = ngroupsSnapshot by #0.1", - "for the else case, ngroupsSnapshot will be null and it will never enter the group as nGroups will be 0"}) @Deprecated(since="1.2", forRemoval=true) + @SuppressWarnings({"removal", "index:array.access.unsafe.high"}) public final void resume() { throw new UnsupportedOperationException(); } @@ -661,6 +636,7 @@ public final void resume() { * there are no live threads in the group and it is otherwise * unreachable. */ + @SuppressWarnings("index:array.access.unsafe.high") @Deprecated(since="16", forRemoval=true) public final void destroy() { } @@ -669,8 +645,6 @@ public final void destroy() { * Prints information about this thread group to the standard * output. This method is useful only for debugging. */ - @CFComment({"index: groupSnapshot.length = ngroupsSnapshot by #0.1", - "for the else case, ngroupsSnapshot will be null and it will never enter the group as nGroups will be 0"}) @SuppressWarnings("index:array.access.unsafe.high") public void list() { Map> map = new HashMap<>(); diff --git a/src/java.base/share/classes/java/lang/ThreadLocal.java b/src/java.base/share/classes/java/lang/ThreadLocal.java index f3fb82e38b7..501a671dee6 100644 --- a/src/java.base/share/classes/java/lang/ThreadLocal.java +++ b/src/java.base/share/classes/java/lang/ThreadLocal.java @@ -30,6 +30,9 @@ import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; +import org.checkerframework.checker.interning.qual.UsesObjectEquals; +import org.checkerframework.framework.qual.AnnotatedFor; + import java.lang.ref.WeakReference; import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/java.base/share/classes/java/lang/constant/ClassDesc.java b/src/java.base/share/classes/java/lang/constant/ClassDesc.java index 60adc7f1ab1..3a6a24342bb 100644 --- a/src/java.base/share/classes/java/lang/constant/ClassDesc.java +++ b/src/java.base/share/classes/java/lang/constant/ClassDesc.java @@ -24,6 +24,8 @@ */ package java.lang.constant; +import org.checkerframework.checker.signature.qual.FieldDescriptor; + import java.lang.invoke.MethodHandles; import java.lang.invoke.TypeDescriptor; import java.util.stream.Stream; @@ -361,7 +363,7 @@ else if (isArray()) { * @return the descriptor string * @jvms 4.3.2 Field Descriptors */ - String descriptorString(); + @FieldDescriptor String descriptorString(); @Override Class resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException; diff --git a/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java b/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java index ff750ccc893..5c2478adb4d 100644 --- a/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java +++ b/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java @@ -24,6 +24,8 @@ */ package java.lang.constant; +import org.checkerframework.checker.signature.qual.MethodDescriptor; + import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.invoke.TypeDescriptor; @@ -195,7 +197,7 @@ static MethodTypeDesc of(ClassDesc returnDesc, ClassDesc... paramDescs) { * @return the method type descriptor string * @jvms 4.3.3 Method Descriptors */ - String descriptorString(); + @MethodDescriptor String descriptorString(); /** * Returns a human-readable descriptor for this method type, using the diff --git a/src/java.base/share/classes/java/lang/invoke/AbstractConstantGroup.java b/src/java.base/share/classes/java/lang/invoke/AbstractConstantGroup.java index 1863d17c082..58661dcd5c0 100644 --- a/src/java.base/share/classes/java/lang/invoke/AbstractConstantGroup.java +++ b/src/java.base/share/classes/java/lang/invoke/AbstractConstantGroup.java @@ -28,7 +28,6 @@ import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.util.*; import jdk.internal.vm.annotation.Stable; @@ -100,7 +99,6 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") public Object next(@NonEmpty AsIterator this) { int i = bumpIndex(); if (resolving) diff --git a/src/java.base/share/classes/java/lang/invoke/LambdaConversionException.java b/src/java.base/share/classes/java/lang/invoke/LambdaConversionException.java index f3950c47c16..a1ecdcee651 100644 --- a/src/java.base/share/classes/java/lang/invoke/LambdaConversionException.java +++ b/src/java.base/share/classes/java/lang/invoke/LambdaConversionException.java @@ -25,11 +25,15 @@ package java.lang.invoke; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * LambdaConversionException * * @since 1.8 */ +@AnnotatedFor({"nullness"}) public class LambdaConversionException extends Exception { @java.io.Serial private static final long serialVersionUID = 292L + 8L; @@ -44,7 +48,7 @@ public LambdaConversionException() { * Constructs a {@code LambdaConversionException} with a message. * @param message the detail message */ - public LambdaConversionException(String message) { + public LambdaConversionException(@Nullable String message) { super(message); } @@ -53,7 +57,7 @@ public LambdaConversionException(String message) { * @param message the detail message * @param cause the cause */ - public LambdaConversionException(String message, Throwable cause) { + public LambdaConversionException(@Nullable String message, @Nullable Throwable cause) { super(message, cause); } @@ -61,7 +65,7 @@ public LambdaConversionException(String message, Throwable cause) { * Constructs a {@code LambdaConversionException} with a cause. * @param cause the cause */ - public LambdaConversionException(Throwable cause) { + public LambdaConversionException(@Nullable Throwable cause) { super(cause); } @@ -73,7 +77,7 @@ public LambdaConversionException(Throwable cause) { * @param enableSuppression whether or not suppressed exceptions are enabled * @param writableStackTrace whether or not the stack trace is writable */ - public LambdaConversionException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + public LambdaConversionException(@Nullable String message, @Nullable Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } } diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java index 3dfd9c061bf..370d182fe1a 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java @@ -25,6 +25,9 @@ package java.lang.invoke; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + import jdk.internal.loader.ClassLoaders; import jdk.internal.vm.annotation.IntrinsicCandidate; @@ -440,6 +443,7 @@ * @author John Rose, JSR 292 EG * @since 1.7 */ +@AnnotatedFor({"nullness"}) public abstract sealed class MethodHandle implements Constable permits NativeMethodHandle, DirectMethodHandle, DelegatingMethodHandle, BoundMethodHandle { @@ -500,7 +504,8 @@ public MethodType type() { * @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call */ @IntrinsicCandidate - public final native @PolymorphicSignature Object invokeExact(Object... args) throws Throwable; + public final native @PolymorphicSignature @Nullable Object invokeExact(Object... args) + throws Throwable; /** * Invokes the method handle, allowing any caller type descriptor, @@ -538,7 +543,8 @@ public MethodType type() { * @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call */ @IntrinsicCandidate - public final native @PolymorphicSignature Object invoke(Object... args) throws Throwable; + public final native @PolymorphicSignature @Nullable Object invoke(Object... args) + throws Throwable; /** * Private method for trusted invocation of a method handle respecting simplified signatures. @@ -727,7 +733,7 @@ public MethodType type() { * @throws Throwable anything thrown by the target method invocation * @see MethodHandles#spreadInvoker */ - public Object invokeWithArguments(Object... arguments) throws Throwable { + public @Nullable Object invokeWithArguments(Object @Nullable ... arguments) throws Throwable { // Note: Jumbo argument lists are handled in the variable-arity subclass. MethodType invocationType = MethodType.genericMethodType(arguments == null ? 0 : arguments.length); return invocationType.invokers().spreadInvoker(0).invokeExact(asType(invocationType), arguments); @@ -754,7 +760,7 @@ public Object invokeWithArguments(Object... arguments) throws Throwable { * @throws WrongMethodTypeException if the target's type cannot be adjusted to take the given number of {@code Object} arguments * @throws Throwable anything thrown by the target method invocation */ - public Object invokeWithArguments(java.util.List arguments) throws Throwable { + public @Nullable Object invokeWithArguments(java.util.List arguments) throws Throwable { return invokeWithArguments(arguments.toArray()); } diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java index 391d8bbb959..38c63bb1884 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -70,7 +70,8 @@ * @author jrose */ /*non-public*/ -@AnnotatedFor({"interning"}) abstract @UsesObjectEquals class MethodHandleImpl { +@AnnotatedFor({"interning"}) +abstract @UsesObjectEquals class MethodHandleImpl { /// Factory methods to create method handles: diff --git a/src/java.base/share/classes/java/lang/invoke/StringConcatException.java b/src/java.base/share/classes/java/lang/invoke/StringConcatException.java index 575e0019329..80fa794c783 100644 --- a/src/java.base/share/classes/java/lang/invoke/StringConcatException.java +++ b/src/java.base/share/classes/java/lang/invoke/StringConcatException.java @@ -25,12 +25,16 @@ package java.lang.invoke; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * StringConcatException is thrown by {@link StringConcatFactory} when linkage * invariants are violated. * * @since 9 */ +@AnnotatedFor({"nullness"}) public class StringConcatException extends Exception { @java.io.Serial private static final long serialVersionUID = 292L + 9L; @@ -39,7 +43,7 @@ public class StringConcatException extends Exception { * Constructs an exception with a message * @param msg exception message */ - public StringConcatException(String msg) { + public StringConcatException(@Nullable String msg) { super(msg); } @@ -48,7 +52,7 @@ public StringConcatException(String msg) { * @param msg exception message * @param cause throwable cause */ - public StringConcatException(String msg, Throwable cause) { + public StringConcatException(@Nullable String msg, @Nullable Throwable cause) { super(msg, cause); } } diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandle.java b/src/java.base/share/classes/java/lang/invoke/VarHandle.java index 2ffa75cf12b..3500e1d9d2c 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/VarHandle.java @@ -25,6 +25,9 @@ package java.lang.invoke; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + import java.lang.constant.ClassDesc; import java.lang.constant.Constable; import java.lang.constant.ConstantDesc; @@ -471,6 +474,7 @@ * @see MethodType * @since 9 */ +@AnnotatedFor({"nullness"}) public abstract sealed class VarHandle implements Constable permits IndirectVarHandle, VarHandleSegmentViewBase, VarHandleByteArrayAsChars.ByteArrayViewVarHandle, @@ -568,7 +572,7 @@ public boolean hasInvokeExactBehavior() { public final native @MethodHandle.PolymorphicSignature @IntrinsicCandidate - Object get(Object... args); + @Nullable Object get(Object... args); /** * Sets the value of a variable to the {@code newValue}, with memory @@ -626,7 +630,7 @@ public boolean hasInvokeExactBehavior() { public final native @MethodHandle.PolymorphicSignature @IntrinsicCandidate - Object getVolatile(Object... args); + @Nullable Object getVolatile(Object... args); /** * Sets the value of a variable to the {@code newValue}, with memory @@ -686,7 +690,7 @@ public boolean hasInvokeExactBehavior() { public final native @MethodHandle.PolymorphicSignature @IntrinsicCandidate - Object getOpaque(Object... args); + @Nullable Object getOpaque(Object... args); /** * Sets the value of a variable to the {@code newValue}, in program order, @@ -750,7 +754,7 @@ public boolean hasInvokeExactBehavior() { public final native @MethodHandle.PolymorphicSignature @IntrinsicCandidate - Object getAcquire(Object... args); + @Nullable Object getAcquire(Object... args); /** * Sets the value of a variable to the {@code newValue}, and ensures that @@ -852,7 +856,7 @@ public boolean hasInvokeExactBehavior() { public final native @MethodHandle.PolymorphicSignature @IntrinsicCandidate - Object compareAndExchange(Object... args); + @Nullable Object compareAndExchange(Object... args); /** * Atomically sets the value of a variable to the {@code newValue} with the @@ -887,7 +891,7 @@ public boolean hasInvokeExactBehavior() { public final native @MethodHandle.PolymorphicSignature @IntrinsicCandidate - Object compareAndExchangeAcquire(Object... args); + @Nullable Object compareAndExchangeAcquire(Object... args); /** * Atomically sets the value of a variable to the {@code newValue} with the @@ -922,7 +926,7 @@ public boolean hasInvokeExactBehavior() { public final native @MethodHandle.PolymorphicSignature @IntrinsicCandidate - Object compareAndExchangeRelease(Object... args); + @Nullable Object compareAndExchangeRelease(Object... args); // Weak (spurious failures allowed) @@ -1107,7 +1111,7 @@ public boolean hasInvokeExactBehavior() { public final native @MethodHandle.PolymorphicSignature @IntrinsicCandidate - Object getAndSet(Object... args); + @Nullable Object getAndSet(Object... args); /** * Atomically sets the value of a variable to the {@code newValue} with the @@ -1140,7 +1144,7 @@ public boolean hasInvokeExactBehavior() { public final native @MethodHandle.PolymorphicSignature @IntrinsicCandidate - Object getAndSetAcquire(Object... args); + @Nullable Object getAndSetAcquire(Object... args); /** * Atomically sets the value of a variable to the {@code newValue} with the @@ -1173,7 +1177,7 @@ public boolean hasInvokeExactBehavior() { public final native @MethodHandle.PolymorphicSignature @IntrinsicCandidate - Object getAndSetRelease(Object... args); + @Nullable Object getAndSetRelease(Object... args); // Primitive adders // Throw UnsupportedOperationException for refs diff --git a/src/java.base/share/classes/java/lang/invoke/WrongMethodTypeException.java b/src/java.base/share/classes/java/lang/invoke/WrongMethodTypeException.java index e7dfa83900a..e09370ebeb4 100644 --- a/src/java.base/share/classes/java/lang/invoke/WrongMethodTypeException.java +++ b/src/java.base/share/classes/java/lang/invoke/WrongMethodTypeException.java @@ -25,6 +25,9 @@ package java.lang.invoke; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Thrown to indicate that code has attempted to call a method handle * via the wrong method type. As with the bytecode representation of @@ -40,6 +43,7 @@ * @author John Rose, JSR 292 EG * @since 1.7 */ +@AnnotatedFor({"nullness"}) public class WrongMethodTypeException extends RuntimeException { @java.io.Serial private static final long serialVersionUID = 292L; @@ -57,7 +61,7 @@ public WrongMethodTypeException() { * * @param s the detail message. */ - public WrongMethodTypeException(String s) { + public WrongMethodTypeException(@Nullable String s) { super(s); } @@ -70,7 +74,7 @@ public WrongMethodTypeException(String s) { */ //FIXME: make this public in MR1 /*non-public*/ - WrongMethodTypeException(String s, Throwable cause) { + WrongMethodTypeException(@Nullable String s, @Nullable Throwable cause) { super(s, cause); } @@ -82,7 +86,7 @@ public WrongMethodTypeException(String s) { */ //FIXME: make this public in MR1 /*non-public*/ - WrongMethodTypeException(Throwable cause) { + WrongMethodTypeException(@Nullable Throwable cause) { super(cause); } } diff --git a/src/java.base/share/classes/java/lang/module/FindException.java b/src/java.base/share/classes/java/lang/module/FindException.java index 71bea3e94b1..f0c22e5a0b1 100644 --- a/src/java.base/share/classes/java/lang/module/FindException.java +++ b/src/java.base/share/classes/java/lang/module/FindException.java @@ -25,6 +25,9 @@ package java.lang.module; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Thrown by a {@link ModuleFinder ModuleFinder} when an error occurs finding * a module. Also thrown by {@link @@ -35,6 +38,7 @@ * @since 9 */ +@AnnotatedFor({"nullness"}) public class FindException extends RuntimeException { @java.io.Serial private static final long serialVersionUID = -5817081036963388391L; @@ -52,7 +56,7 @@ public FindException() { * @param msg * The detail message; can be {@code null} */ - public FindException(String msg) { + public FindException(@Nullable String msg) { super(msg); } @@ -62,7 +66,7 @@ public FindException(String msg) { * @param cause * The cause; can be {@code null} */ - public FindException(Throwable cause) { + public FindException(@Nullable Throwable cause) { super(cause); } @@ -75,7 +79,7 @@ public FindException(Throwable cause) { * @param cause * The cause; can be {@code null} */ - public FindException(String msg, Throwable cause) { + public FindException(@Nullable String msg, @Nullable Throwable cause) { super(msg, cause); } } diff --git a/src/java.base/share/classes/java/lang/module/ResolutionException.java b/src/java.base/share/classes/java/lang/module/ResolutionException.java index b9b96b70acb..7340fef8850 100644 --- a/src/java.base/share/classes/java/lang/module/ResolutionException.java +++ b/src/java.base/share/classes/java/lang/module/ResolutionException.java @@ -25,6 +25,9 @@ package java.lang.module; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Thrown when resolving a set of modules, or resolving a set of modules with * service binding, fails. @@ -32,6 +35,7 @@ * @see Configuration * @since 9 */ +@AnnotatedFor({"nullness"}) public class ResolutionException extends RuntimeException { @java.io.Serial private static final long serialVersionUID = -1031186845316729450L; @@ -48,7 +52,7 @@ public ResolutionException() { } * @param msg * The detail message; can be {@code null} */ - public ResolutionException(String msg) { + public ResolutionException(@Nullable String msg) { super(msg); } @@ -58,7 +62,7 @@ public ResolutionException(String msg) { * @param cause * The cause; can be {@code null} */ - public ResolutionException(Throwable cause) { + public ResolutionException(@Nullable Throwable cause) { super(cause); } @@ -71,7 +75,7 @@ public ResolutionException(Throwable cause) { * @param cause * The cause; can be {@code null} */ - public ResolutionException(String msg, Throwable cause) { + public ResolutionException(@Nullable String msg, @Nullable Throwable cause) { super(msg, cause); } diff --git a/src/java.base/share/classes/java/lang/ref/Reference.java b/src/java.base/share/classes/java/lang/ref/Reference.java index da2488d99fd..c05d1eda529 100644 --- a/src/java.base/share/classes/java/lang/ref/Reference.java +++ b/src/java.base/share/classes/java/lang/ref/Reference.java @@ -52,6 +52,7 @@ */ @AnnotatedFor({"lock", "nullness"}) +@SuppressWarnings({"rawtypes"}) public abstract sealed class Reference permits PhantomReference, SoftReference, WeakReference, FinalReference { diff --git a/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java b/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java index a1e380bc825..029ee2b9c8b 100644 --- a/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java +++ b/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java @@ -62,6 +62,7 @@ boolean enqueue(Reference r) { private volatile Reference head; private long queueLength = 0; + @SuppressWarnings({"unchecked"}) private final ReentrantLock lock; private final Condition notEmpty; @@ -69,6 +70,7 @@ void signal() { notEmpty.signalAll(); } + @SuppressWarnings({"unchecked"}) void await() throws InterruptedException { notEmpty.await(); } diff --git a/src/java.base/share/classes/java/lang/reflect/Method.java b/src/java.base/share/classes/java/lang/reflect/Method.java index 5922c4c2aa7..113ce47f00c 100644 --- a/src/java.base/share/classes/java/lang/reflect/Method.java +++ b/src/java.base/share/classes/java/lang/reflect/Method.java @@ -28,6 +28,7 @@ import org.checkerframework.checker.interning.qual.Interned; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.signature.qual.Identifier; import org.checkerframework.common.reflection.qual.Invoke; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; @@ -243,7 +244,7 @@ public Class getDeclaringClass() { * object, as a {@code String}. */ @Override - public @Interned String getName() { + public @Interned @Identifier String getName() { return name; } diff --git a/src/java.base/share/classes/java/lang/runtime/StrongReferenceKey.java b/src/java.base/share/classes/java/lang/runtime/StrongReferenceKey.java index 3665cad96cc..61988f85185 100644 --- a/src/java.base/share/classes/java/lang/runtime/StrongReferenceKey.java +++ b/src/java.base/share/classes/java/lang/runtime/StrongReferenceKey.java @@ -25,6 +25,12 @@ package java.lang.runtime; +import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.qual.Pure; +import org.checkerframework.dataflow.qual.SideEffectFree; + import java.util.Objects; /** @@ -64,7 +70,9 @@ public void unused() { } @Override - public boolean equals(Object obj) { + @Pure + @EnsuresNonNullIf(expression="#1", result=true) + public boolean equals(@Nullable Object obj) { // Necessary when comparing an unwrapped key if (obj instanceof ReferenceKey key) { obj = key.get(); diff --git a/src/java.base/share/classes/java/math/MathContext.java b/src/java.base/share/classes/java/math/MathContext.java index b8d6b3f4a75..c92dbd6881c 100644 --- a/src/java.base/share/classes/java/math/MathContext.java +++ b/src/java.base/share/classes/java/math/MathContext.java @@ -28,6 +28,7 @@ */ package java.math; + import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; diff --git a/src/java.base/share/classes/java/net/NetworkInterface.java b/src/java.base/share/classes/java/net/NetworkInterface.java index f30a07fc16d..6d6941c2a5e 100644 --- a/src/java.base/share/classes/java/net/NetworkInterface.java +++ b/src/java.base/share/classes/java/net/NetworkInterface.java @@ -410,7 +410,7 @@ public static Stream networkInterfaces() } private static Enumeration enumerationFromArray(T[] a) { - return new Enumeration() { + return new Enumeration<>() { int i = 0; @Override diff --git a/src/java.base/share/classes/java/net/URL.java b/src/java.base/share/classes/java/net/URL.java index 56c7f6c8496..1b393cf871c 100644 --- a/src/java.base/share/classes/java/net/URL.java +++ b/src/java.base/share/classes/java/net/URL.java @@ -33,7 +33,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import java.io.File; @@ -1512,7 +1511,6 @@ public boolean hasNext() { return getNext(); } - @SideEffectsOnly("this") public URLStreamHandlerProvider next(/*@NonEmpty Iterator this*/) { if (!getNext()) throw new NoSuchElementException(); diff --git a/src/java.base/share/classes/java/net/package-info.java b/src/java.base/share/classes/java/net/package-info.java index b94dc5ba7b2..27fdf96aedf 100644 --- a/src/java.base/share/classes/java/net/package-info.java +++ b/src/java.base/share/classes/java/net/package-info.java @@ -160,6 +160,6 @@ @DefaultQualifier(value = KeyForBottom.class, locations = TypeUseLocation.LOWER_BOUND) @SuppressWarnings("doclint:reference") // cross-module links package java.net; +import org.checkerframework.checker.nullness.qual.KeyForBottom; import org.checkerframework.framework.qual.DefaultQualifier; import org.checkerframework.framework.qual.TypeUseLocation; -import org.checkerframework.checker.nullness.qual.KeyForBottom; diff --git a/src/java.base/share/classes/java/nio/charset/Charset.java b/src/java.base/share/classes/java/nio/charset/Charset.java index 5cb2e1a6dfc..7ee6a477c10 100644 --- a/src/java.base/share/classes/java/nio/charset/Charset.java +++ b/src/java.base/share/classes/java/nio/charset/Charset.java @@ -28,7 +28,6 @@ import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import jdk.internal.misc.ThreadTracker; import jdk.internal.misc.VM; @@ -370,7 +369,6 @@ public boolean hasNext() { return getNext(); } - @SideEffectsOnly("this") public CharsetProvider next(/*@NonEmpty Iterator this*/) { if (!getNext()) throw new NoSuchElementException(); diff --git a/src/java.base/share/classes/java/nio/file/AccessDeniedException.java b/src/java.base/share/classes/java/nio/file/AccessDeniedException.java index 10f0fda3955..d45fca83c0b 100644 --- a/src/java.base/share/classes/java/nio/file/AccessDeniedException.java +++ b/src/java.base/share/classes/java/nio/file/AccessDeniedException.java @@ -25,6 +25,9 @@ package java.nio.file; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Checked exception thrown when a file system operation is denied, typically * due to a file permission or other access check. @@ -36,7 +39,7 @@ * * @since 1.7 */ - +@AnnotatedFor({"nullness"}) public class AccessDeniedException extends FileSystemException { @@ -49,7 +52,7 @@ public class AccessDeniedException * @param file * a string identifying the file or {@code null} if not known */ - public AccessDeniedException(String file) { + public AccessDeniedException(@Nullable String file) { super(file); } @@ -63,7 +66,7 @@ public AccessDeniedException(String file) { * @param reason * a reason message with additional information or {@code null} */ - public AccessDeniedException(String file, String other, String reason) { + public AccessDeniedException(@Nullable String file, @Nullable String other, @Nullable String reason) { super(file, other, reason); } } diff --git a/src/java.base/share/classes/java/nio/file/AtomicMoveNotSupportedException.java b/src/java.base/share/classes/java/nio/file/AtomicMoveNotSupportedException.java index e08ba0a343c..59a60350485 100644 --- a/src/java.base/share/classes/java/nio/file/AtomicMoveNotSupportedException.java +++ b/src/java.base/share/classes/java/nio/file/AtomicMoveNotSupportedException.java @@ -25,6 +25,9 @@ package java.nio.file; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Checked exception thrown when a file cannot be moved as an atomic file system * operation. @@ -32,6 +35,7 @@ * @since 1.7 */ +@AnnotatedFor({"nullness"}) public class AtomicMoveNotSupportedException extends FileSystemException { @@ -48,9 +52,9 @@ public class AtomicMoveNotSupportedException * @param reason * a reason message with additional information or {@code null} */ - public AtomicMoveNotSupportedException(String source, - String target, - String reason) + public AtomicMoveNotSupportedException(@Nullable String source, + @Nullable String target, + @Nullable String reason) { super(source, target, reason); } diff --git a/src/java.base/share/classes/java/nio/file/DirectoryIteratorException.java b/src/java.base/share/classes/java/nio/file/DirectoryIteratorException.java index 51fb08759e0..5944e3d4a4a 100644 --- a/src/java.base/share/classes/java/nio/file/DirectoryIteratorException.java +++ b/src/java.base/share/classes/java/nio/file/DirectoryIteratorException.java @@ -31,6 +31,9 @@ import java.io.ObjectInputStream; import java.io.InvalidObjectException; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Runtime exception thrown if an I/O error is encountered when iterating over * the entries in a directory. The I/O error is retrieved as an {@link @@ -40,6 +43,7 @@ * @see DirectoryStream */ +@AnnotatedFor({"nullness"}) public final class DirectoryIteratorException extends ConcurrentModificationException { diff --git a/src/java.base/share/classes/java/nio/file/DirectoryNotEmptyException.java b/src/java.base/share/classes/java/nio/file/DirectoryNotEmptyException.java index 563e0830f06..1dc2c7543ba 100644 --- a/src/java.base/share/classes/java/nio/file/DirectoryNotEmptyException.java +++ b/src/java.base/share/classes/java/nio/file/DirectoryNotEmptyException.java @@ -25,6 +25,8 @@ package java.nio.file; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; /** * Checked exception thrown when a file system operation fails because a * directory is not empty. @@ -32,6 +34,7 @@ * @since 1.7 */ +@AnnotatedFor({"nullness"}) public class DirectoryNotEmptyException extends FileSystemException { @@ -44,7 +47,7 @@ public class DirectoryNotEmptyException * @param dir * a string identifying the directory or {@code null} if not known */ - public DirectoryNotEmptyException(String dir) { + public DirectoryNotEmptyException(@Nullable String dir) { super(dir); } } diff --git a/src/java.base/share/classes/java/nio/file/FileAlreadyExistsException.java b/src/java.base/share/classes/java/nio/file/FileAlreadyExistsException.java index 90fcbba25be..0586d5e28f4 100644 --- a/src/java.base/share/classes/java/nio/file/FileAlreadyExistsException.java +++ b/src/java.base/share/classes/java/nio/file/FileAlreadyExistsException.java @@ -25,6 +25,9 @@ package java.nio.file; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Checked exception thrown when an attempt is made to create a file or * directory and a file of that name already exists. @@ -32,6 +35,7 @@ * @since 1.7 */ +@AnnotatedFor({"nullness"}) public class FileAlreadyExistsException extends FileSystemException { @@ -44,7 +48,7 @@ public class FileAlreadyExistsException * @param file * a string identifying the file or {@code null} if not known */ - public FileAlreadyExistsException(String file) { + public FileAlreadyExistsException(@Nullable String file) { super(file); } @@ -58,7 +62,7 @@ public FileAlreadyExistsException(String file) { * @param reason * a reason message with additional information or {@code null} */ - public FileAlreadyExistsException(String file, String other, String reason) { + public FileAlreadyExistsException(@Nullable String file, @Nullable String other, @Nullable String reason) { super(file, other, reason); } } diff --git a/src/java.base/share/classes/java/nio/file/FileStore.java b/src/java.base/share/classes/java/nio/file/FileStore.java index bb97ed4995f..b810f25d242 100644 --- a/src/java.base/share/classes/java/nio/file/FileStore.java +++ b/src/java.base/share/classes/java/nio/file/FileStore.java @@ -27,6 +27,7 @@ import org.checkerframework.checker.interning.qual.UsesObjectEquals; import org.checkerframework.framework.qual.AnnotatedFor; +import org.checkerframework.checker.nullness.qual.Nullable; import java.nio.file.attribute.*; import java.io.IOException; @@ -46,7 +47,7 @@ * @since 1.7 */ -@AnnotatedFor({"interning"}) +@AnnotatedFor({"interning", "nullness"}) public abstract @UsesObjectEquals class FileStore { /** @@ -215,7 +216,7 @@ public long getBlockSize() throws IOException { * @return a file store attribute view of the specified type or * {@code null} if the attribute view is not available */ - public abstract V + public abstract V getFileStoreAttributeView(Class type); /** @@ -251,5 +252,5 @@ public long getBlockSize() throws IOException { * @throws IOException * if an I/O error occurs */ - public abstract Object getAttribute(String attribute) throws IOException; + public abstract @Nullable Object getAttribute(String attribute) throws IOException; } diff --git a/src/java.base/share/classes/java/nio/file/FileSystem.java b/src/java.base/share/classes/java/nio/file/FileSystem.java index 4020b481d0e..794f861615c 100644 --- a/src/java.base/share/classes/java/nio/file/FileSystem.java +++ b/src/java.base/share/classes/java/nio/file/FileSystem.java @@ -28,6 +28,7 @@ import org.checkerframework.checker.interning.qual.UsesObjectEquals; import org.checkerframework.checker.mustcall.qual.InheritableMustCall; import org.checkerframework.framework.qual.AnnotatedFor; +import org.checkerframework.framework.qual.CFComment; import java.nio.file.attribute.*; import java.nio.file.spi.FileSystemProvider; @@ -100,7 +101,7 @@ */ @AnnotatedFor({"interning", "mustcall"}) -// FileSystem_s cannot leak - their close() method is a convenience for closing the channels/files/etc that they wrap +@CFComment({"FileSystem_s cannot leak. Their close() method is a convenience for closing the channels/files/etc that they wrap."}) @InheritableMustCall({}) public abstract @UsesObjectEquals class FileSystem implements Closeable diff --git a/src/java.base/share/classes/java/nio/file/FileSystemAlreadyExistsException.java b/src/java.base/share/classes/java/nio/file/FileSystemAlreadyExistsException.java index 0f4be9f393a..afa5750db97 100644 --- a/src/java.base/share/classes/java/nio/file/FileSystemAlreadyExistsException.java +++ b/src/java.base/share/classes/java/nio/file/FileSystemAlreadyExistsException.java @@ -25,6 +25,9 @@ package java.nio.file; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Runtime exception thrown when an attempt is made to create a file system that * already exists. @@ -32,6 +35,7 @@ * @since 1.7 */ +@AnnotatedFor({"nullness"}) public class FileSystemAlreadyExistsException extends RuntimeException { @@ -50,7 +54,7 @@ public FileSystemAlreadyExistsException() { * @param msg * the detail message */ - public FileSystemAlreadyExistsException(String msg) { + public FileSystemAlreadyExistsException(@Nullable String msg) { super(msg); } } diff --git a/src/java.base/share/classes/java/nio/file/FileSystemLoopException.java b/src/java.base/share/classes/java/nio/file/FileSystemLoopException.java index 0cea2e94abf..b0e0df2dd36 100644 --- a/src/java.base/share/classes/java/nio/file/FileSystemLoopException.java +++ b/src/java.base/share/classes/java/nio/file/FileSystemLoopException.java @@ -25,6 +25,9 @@ package java.nio.file; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Checked exception thrown when a file system loop, or cycle, is encountered. * @@ -32,6 +35,7 @@ * @see Files#walkFileTree */ +@AnnotatedFor({"nullness"}) public class FileSystemLoopException extends FileSystemException { @@ -45,7 +49,7 @@ public class FileSystemLoopException * a string identifying the file causing the cycle or {@code null} if * not known */ - public FileSystemLoopException(String file) { + public FileSystemLoopException(@Nullable String file) { super(file); } } diff --git a/src/java.base/share/classes/java/nio/file/FileSystemNotFoundException.java b/src/java.base/share/classes/java/nio/file/FileSystemNotFoundException.java index 0b170fba9a7..c26f478007e 100644 --- a/src/java.base/share/classes/java/nio/file/FileSystemNotFoundException.java +++ b/src/java.base/share/classes/java/nio/file/FileSystemNotFoundException.java @@ -25,12 +25,16 @@ package java.nio.file; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; /** * Runtime exception thrown when a file system cannot be found. * * @since 1.7 */ +@AnnotatedFor({"nullness"}) public class FileSystemNotFoundException extends RuntimeException { @@ -49,7 +53,7 @@ public FileSystemNotFoundException() { * @param msg * the detail message */ - public FileSystemNotFoundException(String msg) { + public FileSystemNotFoundException(@Nullable String msg) { super(msg); } } diff --git a/src/java.base/share/classes/java/nio/file/FileSystems.java b/src/java.base/share/classes/java/nio/file/FileSystems.java index 2574689bc2d..8067e17200e 100644 --- a/src/java.base/share/classes/java/nio/file/FileSystems.java +++ b/src/java.base/share/classes/java/nio/file/FileSystems.java @@ -28,6 +28,7 @@ import org.checkerframework.checker.interning.qual.UsesObjectEquals; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.AnnotatedFor; +import org.checkerframework.checker.nullness.qual.Nullable; import java.nio.file.spi.FileSystemProvider; import java.net.URI; diff --git a/src/java.base/share/classes/java/nio/file/FileTreeIterator.java b/src/java.base/share/classes/java/nio/file/FileTreeIterator.java index 1015bb8f2c1..5e6442f0a92 100644 --- a/src/java.base/share/classes/java/nio/file/FileTreeIterator.java +++ b/src/java.base/share/classes/java/nio/file/FileTreeIterator.java @@ -28,7 +28,6 @@ import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.io.Closeable; import java.io.IOException; @@ -112,7 +111,6 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") public Event next(@NonEmpty FileTreeIterator this) { if (!walker.isOpen()) throw new IllegalStateException(); diff --git a/src/java.base/share/classes/java/nio/file/FileVisitor.java b/src/java.base/share/classes/java/nio/file/FileVisitor.java index 9020c0ef163..839006c3e71 100644 --- a/src/java.base/share/classes/java/nio/file/FileVisitor.java +++ b/src/java.base/share/classes/java/nio/file/FileVisitor.java @@ -28,6 +28,9 @@ import java.nio.file.attribute.BasicFileAttributes; import java.io.IOException; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * A visitor of files. An implementation of this interface is provided to the * {@link Files#walkFileTree Files.walkFileTree} methods to visit each file in @@ -96,6 +99,7 @@ * @since 1.7 */ +@AnnotatedFor({"nullness"}) public interface FileVisitor { /** @@ -173,6 +177,6 @@ FileVisitResult visitFileFailed(T file, IOException exc) * @throws IOException * if an I/O error occurs */ - FileVisitResult postVisitDirectory(T dir, IOException exc) + FileVisitResult postVisitDirectory(T dir, @Nullable IOException exc) throws IOException; } diff --git a/src/java.base/share/classes/java/nio/file/Files.java b/src/java.base/share/classes/java/nio/file/Files.java index 8c6184d96d1..34edc66924a 100644 --- a/src/java.base/share/classes/java/nio/file/Files.java +++ b/src/java.base/share/classes/java/nio/file/Files.java @@ -34,7 +34,6 @@ import org.checkerframework.checker.signedness.qual.PolySigned; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; @@ -1826,7 +1825,7 @@ private static List loadInstalledDetectors() { * the attribute view type is not available */ @ReleasesNoLocks - public static @Nullable V getFileAttributeView(Path path, + public static V getFileAttributeView(Path path, Class type, LinkOption... options) { @@ -3868,7 +3867,6 @@ public boolean hasNext() { throw new UncheckedIOException(e.getCause()); } } - @SideEffectsOnly("this") @Override public Path next(/*@NonEmpty Iterator this*/) { try { diff --git a/src/java.base/share/classes/java/nio/file/InvalidPathException.java b/src/java.base/share/classes/java/nio/file/InvalidPathException.java index bb28b61b83b..83f77419327 100644 --- a/src/java.base/share/classes/java/nio/file/InvalidPathException.java +++ b/src/java.base/share/classes/java/nio/file/InvalidPathException.java @@ -25,6 +25,8 @@ package java.nio.file; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Unchecked exception thrown when path string cannot be converted into a * {@link Path} because the path string contains invalid characters, or @@ -33,6 +35,7 @@ * @since 1.7 */ +@AnnotatedFor({"nullness"}) public class InvalidPathException extends IllegalArgumentException { diff --git a/src/java.base/share/classes/java/nio/file/LinkPermission.java b/src/java.base/share/classes/java/nio/file/LinkPermission.java index 81921f059cb..a0efa0ceb4e 100644 --- a/src/java.base/share/classes/java/nio/file/LinkPermission.java +++ b/src/java.base/share/classes/java/nio/file/LinkPermission.java @@ -27,6 +27,9 @@ import java.security.BasicPermission; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * The {@code Permission} class for link creation operations. * @@ -66,6 +69,7 @@ * @see Files#createLink * @see Files#createSymbolicLink */ +@AnnotatedFor({"nullness"}) public final class LinkPermission extends BasicPermission { @java.io.Serial static final long serialVersionUID = -1441492453772213220L; @@ -102,7 +106,7 @@ public LinkPermission(String name) { * @throws IllegalArgumentException * if name is empty or invalid, or actions is a non-empty string */ - public LinkPermission(String name, String actions) { + public LinkPermission(String name, @Nullable String actions) { super(name); checkName(name); if (actions != null && !actions.isEmpty()) { diff --git a/src/java.base/share/classes/java/nio/file/NoSuchFileException.java b/src/java.base/share/classes/java/nio/file/NoSuchFileException.java index 73c37e60d57..56858158e39 100644 --- a/src/java.base/share/classes/java/nio/file/NoSuchFileException.java +++ b/src/java.base/share/classes/java/nio/file/NoSuchFileException.java @@ -25,6 +25,9 @@ package java.nio.file; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Checked exception thrown when an attempt is made to access a file that does * not exist. @@ -32,6 +35,7 @@ * @since 1.7 */ +@AnnotatedFor({"nullness"}) public class NoSuchFileException extends FileSystemException { @@ -44,7 +48,7 @@ public class NoSuchFileException * @param file * a string identifying the file or {@code null} if not known. */ - public NoSuchFileException(String file) { + public NoSuchFileException(@Nullable String file) { super(file); } @@ -58,7 +62,7 @@ public NoSuchFileException(String file) { * @param reason * a reason message with additional information or {@code null} */ - public NoSuchFileException(String file, String other, String reason) { + public NoSuchFileException(@Nullable String file, @Nullable String other, @Nullable String reason) { super(file, other, reason); } } diff --git a/src/java.base/share/classes/java/nio/file/NotDirectoryException.java b/src/java.base/share/classes/java/nio/file/NotDirectoryException.java index 225bd2494ff..bad62317c77 100644 --- a/src/java.base/share/classes/java/nio/file/NotDirectoryException.java +++ b/src/java.base/share/classes/java/nio/file/NotDirectoryException.java @@ -25,6 +25,9 @@ package java.nio.file; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Checked exception thrown when a file system operation, intended for a * directory, fails because the file is not a directory. @@ -32,6 +35,7 @@ * @since 1.7 */ +@AnnotatedFor({"nullness"}) public class NotDirectoryException extends FileSystemException { @@ -44,7 +48,7 @@ public class NotDirectoryException * @param file * a string identifying the file or {@code null} if not known */ - public NotDirectoryException(String file) { + public NotDirectoryException(@Nullable String file) { super(file); } } diff --git a/src/java.base/share/classes/java/nio/file/NotLinkException.java b/src/java.base/share/classes/java/nio/file/NotLinkException.java index 02563d35a11..cc8eb09aa1d 100644 --- a/src/java.base/share/classes/java/nio/file/NotLinkException.java +++ b/src/java.base/share/classes/java/nio/file/NotLinkException.java @@ -25,6 +25,9 @@ package java.nio.file; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Checked exception thrown when a file system operation fails because a file * is not a symbolic link. @@ -32,6 +35,7 @@ * @since 1.7 */ +@AnnotatedFor({"nullness"}) public class NotLinkException extends FileSystemException { @@ -44,7 +48,7 @@ public class NotLinkException * @param file * a string identifying the file or {@code null} if not known */ - public NotLinkException(String file) { + public NotLinkException(@Nullable String file) { super(file); } @@ -58,7 +62,7 @@ public NotLinkException(String file) { * @param reason * a reason message with additional information or {@code null} */ - public NotLinkException(String file, String other, String reason) { + public NotLinkException(@Nullable String file, @Nullable String other, @Nullable String reason) { super(file, other, reason); } } diff --git a/src/java.base/share/classes/java/nio/file/Path.java b/src/java.base/share/classes/java/nio/file/Path.java index a5e263acdae..aea2a499b13 100644 --- a/src/java.base/share/classes/java/nio/file/Path.java +++ b/src/java.base/share/classes/java/nio/file/Path.java @@ -30,7 +30,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import java.io.File; @@ -962,7 +961,6 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") public Path next(/*@NonEmpty Iterator this*/) { if (i < getNameCount()) { Path result = getName(i); diff --git a/src/java.base/share/classes/java/nio/file/ProviderMismatchException.java b/src/java.base/share/classes/java/nio/file/ProviderMismatchException.java index 70c1fad64ab..78d9d0cb40b 100644 --- a/src/java.base/share/classes/java/nio/file/ProviderMismatchException.java +++ b/src/java.base/share/classes/java/nio/file/ProviderMismatchException.java @@ -25,6 +25,9 @@ package java.nio.file; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Unchecked exception thrown when an attempt is made to invoke a method on an * object created by one file system provider with a parameter created by a @@ -32,6 +35,7 @@ * * @since 1.7 */ +@AnnotatedFor({"nullness"}) public class ProviderMismatchException extends java.lang.IllegalArgumentException { @@ -50,7 +54,7 @@ public ProviderMismatchException() { * @param msg * the detail message */ - public ProviderMismatchException(String msg) { + public ProviderMismatchException(@Nullable String msg) { super(msg); } } diff --git a/src/java.base/share/classes/java/nio/file/ProviderNotFoundException.java b/src/java.base/share/classes/java/nio/file/ProviderNotFoundException.java index 804f4996de2..192eae1f802 100644 --- a/src/java.base/share/classes/java/nio/file/ProviderNotFoundException.java +++ b/src/java.base/share/classes/java/nio/file/ProviderNotFoundException.java @@ -25,12 +25,16 @@ package java.nio.file; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Runtime exception thrown when a provider of the required type cannot be found. * * @since 1.7 */ +@AnnotatedFor({"nullness"}) public class ProviderNotFoundException extends RuntimeException { @@ -49,7 +53,7 @@ public ProviderNotFoundException() { * @param msg * the detail message */ - public ProviderNotFoundException(String msg) { + public ProviderNotFoundException(@Nullable String msg) { super(msg); } } diff --git a/src/java.base/share/classes/java/nio/file/ReadOnlyFileSystemException.java b/src/java.base/share/classes/java/nio/file/ReadOnlyFileSystemException.java index d187ef96b68..4284144164f 100644 --- a/src/java.base/share/classes/java/nio/file/ReadOnlyFileSystemException.java +++ b/src/java.base/share/classes/java/nio/file/ReadOnlyFileSystemException.java @@ -25,6 +25,8 @@ package java.nio.file; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Unchecked exception thrown when an attempt is made to update an object * associated with a {@link FileSystem#isReadOnly() read-only} {@code FileSystem}. @@ -32,6 +34,7 @@ * @since 1.7 */ +@AnnotatedFor({"nullness"}) public class ReadOnlyFileSystemException extends UnsupportedOperationException { diff --git a/src/java.base/share/classes/java/nio/file/SecureDirectoryStream.java b/src/java.base/share/classes/java/nio/file/SecureDirectoryStream.java index 445a80b8e37..ede8640439d 100644 --- a/src/java.base/share/classes/java/nio/file/SecureDirectoryStream.java +++ b/src/java.base/share/classes/java/nio/file/SecureDirectoryStream.java @@ -29,6 +29,9 @@ import java.util.Set; import java.io.IOException; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * A {@code DirectoryStream} that defines operations on files that are located * relative to an open directory. A {@code SecureDirectoryStream} is intended @@ -57,6 +60,7 @@ * @since 1.7 */ +@AnnotatedFor({"nullness"}) public interface SecureDirectoryStream extends DirectoryStream { @@ -272,7 +276,7 @@ void move(T srcpath, SecureDirectoryStream targetdir, T targetpath) * this directory stream, or {@code null} if the attribute view * type is not available */ - V getFileAttributeView(Class type); + @Nullable V getFileAttributeView(Class type); /** * Returns a new file attribute view to access the file attributes of a file @@ -307,7 +311,7 @@ void move(T srcpath, SecureDirectoryStream targetdir, T targetpath) * type is not available * */ - V getFileAttributeView(T path, + @Nullable V getFileAttributeView(T path, Class type, LinkOption... options); } diff --git a/src/java.base/share/classes/java/nio/file/SimpleFileVisitor.java b/src/java.base/share/classes/java/nio/file/SimpleFileVisitor.java index b4e9713c8e5..d9dacce1270 100644 --- a/src/java.base/share/classes/java/nio/file/SimpleFileVisitor.java +++ b/src/java.base/share/classes/java/nio/file/SimpleFileVisitor.java @@ -26,6 +26,7 @@ package java.nio.file; import org.checkerframework.checker.interning.qual.UsesObjectEquals; +import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.AnnotatedFor; import java.nio.file.attribute.BasicFileAttributes; @@ -43,7 +44,7 @@ * @since 1.7 */ -@AnnotatedFor({"interning"}) +@AnnotatedFor({"interning", "nullness"}) public @UsesObjectEquals class SimpleFileVisitor implements FileVisitor { /** * Initializes a new instance of this class. @@ -105,7 +106,7 @@ public FileVisitResult visitFileFailed(T file, IOException exc) * of the directory to terminate prematurely. */ @Override - public FileVisitResult postVisitDirectory(T dir, IOException exc) + public FileVisitResult postVisitDirectory(T dir, @Nullable IOException exc) throws IOException { Objects.requireNonNull(dir); diff --git a/src/java.base/share/classes/java/nio/file/WatchEvent.java b/src/java.base/share/classes/java/nio/file/WatchEvent.java index ab74d5f2e2e..4770a7247d5 100644 --- a/src/java.base/share/classes/java/nio/file/WatchEvent.java +++ b/src/java.base/share/classes/java/nio/file/WatchEvent.java @@ -25,6 +25,9 @@ package java.nio.file; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * An event or a repeated event for an object that is registered with a {@link * WatchService}. @@ -44,7 +47,8 @@ * @since 1.7 */ -public interface WatchEvent { +@AnnotatedFor({"nullness"}) +public interface WatchEvent { /** * An event kind, for the purposes of identification. @@ -53,7 +57,7 @@ public interface WatchEvent { * @since 1.7 * @see StandardWatchEventKinds */ - public static interface Kind { + public static interface Kind { /** * Returns the name of the event kind. * diff --git a/src/java.base/share/classes/java/nio/file/WatchService.java b/src/java.base/share/classes/java/nio/file/WatchService.java index bf7475742db..53bcd262a7d 100644 --- a/src/java.base/share/classes/java/nio/file/WatchService.java +++ b/src/java.base/share/classes/java/nio/file/WatchService.java @@ -31,6 +31,7 @@ import org.checkerframework.checker.mustcall.qual.InheritableMustCall; import org.checkerframework.framework.qual.AnnotatedFor; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A watch service that watches registered objects for changes and @@ -105,7 +106,7 @@ * * @see FileSystem#newWatchService */ -@AnnotatedFor({"mustcall"}) +@AnnotatedFor({"mustcall", "nullness"}) @InheritableMustCall({}) public interface WatchService extends Closeable @@ -140,7 +141,7 @@ public interface WatchService * @throws ClosedWatchServiceException * if this watch service is closed */ - WatchKey poll(); + @Nullable WatchKey poll(); /** * Retrieves and removes the next watch key, waiting if necessary up to the @@ -160,7 +161,7 @@ public interface WatchService * @throws InterruptedException * if interrupted while waiting */ - WatchKey poll(long timeout, TimeUnit unit) + @Nullable WatchKey poll(long timeout, TimeUnit unit) throws InterruptedException; /** diff --git a/src/java.base/share/classes/java/nio/file/attribute/BasicFileAttributeView.java b/src/java.base/share/classes/java/nio/file/attribute/BasicFileAttributeView.java index 80657e67a04..13ce4d341f2 100644 --- a/src/java.base/share/classes/java/nio/file/attribute/BasicFileAttributeView.java +++ b/src/java.base/share/classes/java/nio/file/attribute/BasicFileAttributeView.java @@ -30,6 +30,9 @@ import java.io.IOException; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * A file attribute view that provides a view of a basic set of file * attributes common to many file systems. The basic set of file attributes @@ -103,7 +106,7 @@ * * @since 1.7 */ -@AnnotatedFor("nullness") +@AnnotatedFor({"nullness"}) public interface BasicFileAttributeView extends FileAttributeView { diff --git a/src/java.base/share/classes/java/nio/file/attribute/BasicFileAttributes.java b/src/java.base/share/classes/java/nio/file/attribute/BasicFileAttributes.java index d08e4b81bab..b615103598f 100644 --- a/src/java.base/share/classes/java/nio/file/attribute/BasicFileAttributes.java +++ b/src/java.base/share/classes/java/nio/file/attribute/BasicFileAttributes.java @@ -27,6 +27,7 @@ import org.checkerframework.checker.index.qual.NonNegative; import org.checkerframework.framework.qual.AnnotatedFor; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Basic attributes associated with a file in a file system. @@ -46,7 +47,7 @@ * @see BasicFileAttributeView */ -@AnnotatedFor({"index"}) +@AnnotatedFor({"index", "nullness"}) public interface BasicFileAttributes { /** @@ -155,5 +156,5 @@ public interface BasicFileAttributes { * * @see java.nio.file.Files#walkFileTree */ - Object fileKey(); + @Nullable Object fileKey(); } diff --git a/src/java.base/share/classes/java/nio/file/spi/FileSystemProvider.java b/src/java.base/share/classes/java/nio/file/spi/FileSystemProvider.java index 19a0305072f..a14fda28ce3 100644 --- a/src/java.base/share/classes/java/nio/file/spi/FileSystemProvider.java +++ b/src/java.base/share/classes/java/nio/file/spi/FileSystemProvider.java @@ -26,6 +26,7 @@ package java.nio.file.spi; import org.checkerframework.checker.interning.qual.UsesObjectEquals; +import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.AnnotatedFor; import java.nio.channels.AsynchronousFileChannel; @@ -113,7 +114,7 @@ * @since 1.7 */ -@AnnotatedFor({"interning"}) +@AnnotatedFor({"interning", "nullness"}) public abstract @UsesObjectEquals class FileSystemProvider { // lock using when loading providers private static final Object lock = new Object(); @@ -584,7 +585,7 @@ public FileChannel newFileChannel(Path path, */ public AsynchronousFileChannel newAsynchronousFileChannel(Path path, Set options, - ExecutorService executor, + @Nullable ExecutorService executor, FileAttribute... attrs) throws IOException { @@ -1072,7 +1073,7 @@ public abstract void checkAccess(Path path, AccessMode... modes) * @return a file attribute view of the specified type, or {@code null} if * the attribute view type is not available */ - public abstract V + public abstract V getFileAttributeView(Path path, Class type, LinkOption... options); /** diff --git a/src/java.base/share/classes/java/nio/file/spi/FileTypeDetector.java b/src/java.base/share/classes/java/nio/file/spi/FileTypeDetector.java index 1b6ec728f8b..6ab4304cd97 100644 --- a/src/java.base/share/classes/java/nio/file/spi/FileTypeDetector.java +++ b/src/java.base/share/classes/java/nio/file/spi/FileTypeDetector.java @@ -25,6 +25,7 @@ package java.nio.file.spi; +import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.interning.qual.UsesObjectEquals; import org.checkerframework.framework.qual.AnnotatedFor; @@ -50,7 +51,7 @@ * @since 1.7 */ -@AnnotatedFor({"interning"}) +@AnnotatedFor({"interning", "nullable"}) public abstract @UsesObjectEquals class FileTypeDetector { private static Void checkPermission() { @@ -108,6 +109,6 @@ protected FileTypeDetector() { * RFC 2045: Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies * @see java.nio.file.Files#probeContentType */ - public abstract String probeContentType(Path path) + public abstract @Nullable String probeContentType(Path path) throws IOException; } diff --git a/src/java.base/share/classes/java/security/AllPermission.java b/src/java.base/share/classes/java/security/AllPermission.java index 9d48d1d8db4..a60c1ff3ee9 100644 --- a/src/java.base/share/classes/java/security/AllPermission.java +++ b/src/java.base/share/classes/java/security/AllPermission.java @@ -230,7 +230,7 @@ public Enumeration elements() { private boolean hasMore = all_allowed; @EnsuresNonEmptyIf(result = true, expression = "this") - public boolean hasMoreElements(/**/) { + public boolean hasMoreElements() { return hasMore; } diff --git a/src/java.base/share/classes/java/security/Principal.java b/src/java.base/share/classes/java/security/Principal.java index 978aea42ed1..8d0ec70c256 100644 --- a/src/java.base/share/classes/java/security/Principal.java +++ b/src/java.base/share/classes/java/security/Principal.java @@ -58,7 +58,7 @@ public interface Principal { */ @Pure @EnsuresNonNullIf(expression="#1", result=true) - boolean equals(@Nullable Object another); + boolean equals(Object another); /** * Returns a string representation of this {@code Principal}. diff --git a/src/java.base/share/classes/java/security/Provider.java b/src/java.base/share/classes/java/security/Provider.java index fcd8a6f3f24..22ebc08a5c8 100644 --- a/src/java.base/share/classes/java/security/Provider.java +++ b/src/java.base/share/classes/java/security/Provider.java @@ -25,9 +25,9 @@ package java.security; -import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.PolyNull; +import org.checkerframework.checker.signedness.qual.UnknownSignedness; import jdk.internal.event.SecurityProviderServiceEvent; diff --git a/src/java.base/share/classes/java/security/UnresolvedPermission.java b/src/java.base/share/classes/java/security/UnresolvedPermission.java index 57ac8a98493..7023c2eea70 100644 --- a/src/java.base/share/classes/java/security/UnresolvedPermission.java +++ b/src/java.base/share/classes/java/security/UnresolvedPermission.java @@ -341,9 +341,9 @@ public boolean implies(Permission p) { * and has the same type (class) name, permission name, actions, and * certificates as this object. */ - @Override @Pure @EnsuresNonNullIf(expression="#1", result=true) + @Override public boolean equals(@Nullable Object obj) { if (obj == this) return true; diff --git a/src/java.base/share/classes/java/util/AbstractCollection.java b/src/java.base/share/classes/java/util/AbstractCollection.java index f6023a25da4..87cc5edd01d 100644 --- a/src/java.base/share/classes/java/util/AbstractCollection.java +++ b/src/java.base/share/classes/java/util/AbstractCollection.java @@ -26,6 +26,8 @@ package java.util; import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; @@ -94,7 +96,7 @@ protected AbstractCollection() { * @return an iterator over the elements contained in this collection */ @SideEffectFree - public abstract @PolyNonEmpty Iterator iterator(@PolyNonEmpty AbstractCollection this); + public abstract @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty AbstractCollection this); @Pure public abstract @NonNegative int size(@GuardSatisfied AbstractCollection this); @@ -294,7 +296,7 @@ public boolean add(@GuardSatisfied AbstractCollection this, E e) { * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ - public boolean remove(@GuardSatisfied AbstractCollection this, @GuardSatisfied @UnknownSignedness Object o) { + public boolean remove(@GuardSatisfied @Shrinkable AbstractCollection this, @GuardSatisfied @UnknownSignedness Object o) { Iterator it = iterator(); if (o==null) { while (it.hasNext()) { @@ -387,7 +389,7 @@ public boolean addAll(@GuardSatisfied AbstractCollection this, Collection this, Collection c) { + public boolean removeAll(@GuardSatisfied @Shrinkable AbstractCollection this, Collection c) { Objects.requireNonNull(c); boolean modified = false; Iterator it = iterator(); @@ -422,7 +424,7 @@ public boolean removeAll(@GuardSatisfied AbstractCollection this, Collection< * @see #remove(Object) * @see #contains(Object) */ - public boolean retainAll(@GuardSatisfied AbstractCollection this, Collection c) { + public boolean retainAll(@GuardSatisfied @Shrinkable AbstractCollection this, Collection c) { Objects.requireNonNull(c); boolean modified = false; Iterator it = iterator(); @@ -451,7 +453,7 @@ public boolean retainAll(@GuardSatisfied AbstractCollection this, Collection< * * @throws UnsupportedOperationException {@inheritDoc} */ - public void clear(@GuardSatisfied AbstractCollection this) { + public void clear(@GuardSatisfied @Shrinkable AbstractCollection this) { Iterator it = iterator(); while (it.hasNext()) { it.next(); diff --git a/src/java.base/share/classes/java/util/AbstractList.java b/src/java.base/share/classes/java/util/AbstractList.java index b93bb921d40..01d5928725c 100644 --- a/src/java.base/share/classes/java/util/AbstractList.java +++ b/src/java.base/share/classes/java/util/AbstractList.java @@ -28,15 +28,17 @@ import org.checkerframework.checker.index.qual.GTENegativeOne; import org.checkerframework.checker.index.qual.IndexFor; import org.checkerframework.checker.index.qual.IndexOrHigh; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; @@ -185,7 +187,7 @@ public void add(@GuardSatisfied AbstractList this, @IndexOrHigh({"this"}) int * @throws UnsupportedOperationException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} */ - public E remove(@GuardSatisfied AbstractList this, @IndexFor({"this"}) int index) { + public E remove(@GuardSatisfied @Shrinkable AbstractList this, @IndexFor({"this"}) int index) { throw new UnsupportedOperationException(); } @@ -263,7 +265,7 @@ public E remove(@GuardSatisfied AbstractList this, @IndexFor({"this"}) int in * @throws UnsupportedOperationException if the {@code clear} operation * is not supported by this list */ - public void clear(@GuardSatisfied AbstractList this) { + public void clear(@GuardSatisfied @Shrinkable AbstractList this) { removeRange(0, size()); } @@ -320,7 +322,7 @@ public boolean addAll(@GuardSatisfied AbstractList this, @IndexOrHigh({"this" * @return an iterator over the elements in this list in proper sequence */ @SideEffectFree - public Iterator iterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty AbstractList this) { return new Itr(); } @@ -332,7 +334,7 @@ public Iterator iterator() { * * @see #listIterator(int) */ - public ListIterator listIterator() { + public @PolyGrowShrink @PolyNonEmpty ListIterator listIterator(@PolyGrowShrink @PolyNonEmpty AbstractList this) { return listIterator(0); } @@ -359,7 +361,7 @@ public ListIterator listIterator() { * * @throws IndexOutOfBoundsException {@inheritDoc} */ - public ListIterator listIterator(final @IndexOrHigh({"this"}) int index) { + public @PolyGrowShrink ListIterator listIterator(@PolyGrowShrink AbstractList this, final @IndexOrHigh({"this"}) int index) { rangeCheckForAdd(index); return new ListItr(index); @@ -391,7 +393,6 @@ public boolean hasNext() { return cursor != size(); } - @SideEffectsOnly("this") public E next(@NonEmpty Itr this) { checkForComodification(); try { @@ -522,7 +523,7 @@ public void add(E e) { * {@code (fromIndex > toIndex)} */ @SideEffectFree - public List subList(@GuardSatisfied AbstractList this, @IndexOrHigh({"this"}) int fromIndex, @IndexOrHigh({"this"}) int toIndex) { + public @PolyGrowShrink List subList(@GuardSatisfied @PolyGrowShrink AbstractList this, @IndexOrHigh({"this"}) int fromIndex, @IndexOrHigh({"this"}) int toIndex) { subListRangeCheck(fromIndex, toIndex, size()); return (this instanceof RandomAccess ? new RandomAccessSubList<>(this, fromIndex, toIndex) : @@ -622,7 +623,7 @@ public int hashCode(@GuardSatisfied AbstractList this) { * @param fromIndex index of first element to be removed * @param toIndex index after last element to be removed */ - protected void removeRange(@IndexOrHigh({"this"}) int fromIndex, @IndexOrHigh({"this"}) int toIndex) { + protected void removeRange(@GuardSatisfied @Shrinkable AbstractList this, @IndexOrHigh({"this"}) int fromIndex, @IndexOrHigh({"this"}) int toIndex) { ListIterator it = listIterator(fromIndex); for (int i=0, n=toIndex-fromIndex; i this*/) { if (hasNext()) return i.next(); @@ -890,7 +890,6 @@ public boolean hasPrevious() { return previousIndex() >= 0; } - @SideEffectsOnly("this") public E previous() { if (hasPrevious()) return i.previous(); diff --git a/src/java.base/share/classes/java/util/AbstractMap.java b/src/java.base/share/classes/java/util/AbstractMap.java index 806a5146c43..5c8db70bcf5 100644 --- a/src/java.base/share/classes/java/util/AbstractMap.java +++ b/src/java.base/share/classes/java/util/AbstractMap.java @@ -37,7 +37,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; @@ -390,7 +389,6 @@ public boolean hasNext() { return i.hasNext(); } - @SideEffectsOnly("this") public K next(/*@NonEmpty Iterator this*/) { return i.next().getKey(); } @@ -457,7 +455,6 @@ public boolean hasNext() { return i.hasNext(); } - @SideEffectsOnly("this") public V next(/*@NonEmpty Iterator this*/) { return i.next().getValue(); } diff --git a/src/java.base/share/classes/java/util/AbstractQueue.java b/src/java.base/share/classes/java/util/AbstractQueue.java index b5cdfce96f9..5c991c3b784 100644 --- a/src/java.base/share/classes/java/util/AbstractQueue.java +++ b/src/java.base/share/classes/java/util/AbstractQueue.java @@ -35,6 +35,7 @@ package java.util; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.NonEmpty; @@ -116,7 +117,7 @@ public boolean add(@GuardSatisfied AbstractQueue this, E e) { * @return the head of this queue * @throws NoSuchElementException if this queue is empty */ - public E remove(@GuardSatisfied @NonEmpty AbstractQueue this) { + public E remove(@GuardSatisfied @NonEmpty @Shrinkable AbstractQueue this) { E x = poll(); if (x != null) return x; @@ -150,7 +151,7 @@ public E element(@GuardSatisfied @NonEmpty AbstractQueue this) { *

This implementation repeatedly invokes {@link #poll poll} until it * returns {@code null}. */ - public void clear(@GuardSatisfied AbstractQueue this) { + public void clear(@GuardSatisfied @Shrinkable AbstractQueue this) { while (poll() != null) ; } diff --git a/src/java.base/share/classes/java/util/AbstractSequentialList.java b/src/java.base/share/classes/java/util/AbstractSequentialList.java index ce06ac0cdae..dfa76cdf439 100644 --- a/src/java.base/share/classes/java/util/AbstractSequentialList.java +++ b/src/java.base/share/classes/java/util/AbstractSequentialList.java @@ -25,7 +25,10 @@ package java.util; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; import org.checkerframework.framework.qual.AnnotatedFor; @@ -177,7 +180,7 @@ public void add(@GuardSatisfied AbstractSequentialList this, int index, E ele * @throws UnsupportedOperationException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} */ - public E remove(@GuardSatisfied AbstractSequentialList this, int index) { + public E remove(@GuardSatisfied @Shrinkable AbstractSequentialList this, int index) { try { ListIterator e = listIterator(index); E outCast = e.next(); @@ -246,7 +249,7 @@ public boolean addAll(@GuardSatisfied AbstractSequentialList this, int index, * @return an iterator over the elements in this list (in proper sequence) */ @SideEffectFree - public Iterator iterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty AbstractSequentialList this) { return listIterator(); } @@ -260,5 +263,5 @@ public Iterator iterator() { * sequence) * @throws IndexOutOfBoundsException {@inheritDoc} */ - public abstract ListIterator listIterator(int index); + public abstract @PolyGrowShrink ListIterator listIterator(@PolyGrowShrink AbstractSequentialList this, int index); } diff --git a/src/java.base/share/classes/java/util/ArrayDeque.java b/src/java.base/share/classes/java/util/ArrayDeque.java index 40a6a0deba2..fd4351a35ef 100644 --- a/src/java.base/share/classes/java/util/ArrayDeque.java +++ b/src/java.base/share/classes/java/util/ArrayDeque.java @@ -35,6 +35,8 @@ package java.util; import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; @@ -48,7 +50,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import java.io.Serializable; @@ -374,7 +375,7 @@ public boolean offerLast(E e) { /** * @throws NoSuchElementException {@inheritDoc} */ - public E removeFirst(@GuardSatisfied @NonEmpty ArrayDeque this) { + public E removeFirst(@GuardSatisfied @NonEmpty @Shrinkable ArrayDeque this) { E e = pollFirst(); if (e == null) throw new NoSuchElementException(); @@ -384,14 +385,14 @@ public E removeFirst(@GuardSatisfied @NonEmpty ArrayDeque this) { /** * @throws NoSuchElementException {@inheritDoc} */ - public E removeLast(@GuardSatisfied @NonEmpty ArrayDeque this) { + public E removeLast(@GuardSatisfied @NonEmpty @Shrinkable ArrayDeque this) { E e = pollLast(); if (e == null) throw new NoSuchElementException(); return e; } - public @Nullable E pollFirst(@GuardSatisfied ArrayDeque this) { + public @Nullable E pollFirst(@GuardSatisfied @Shrinkable ArrayDeque this) { final Object[] es; final int h; E e = elementAt(es = elements, h = head); @@ -402,7 +403,7 @@ public E removeLast(@GuardSatisfied @NonEmpty ArrayDeque this) { return e; } - public @Nullable E pollLast(@GuardSatisfied ArrayDeque this) { + public @Nullable E pollLast(@GuardSatisfied @Shrinkable ArrayDeque this) { final Object[] es; final int t; E e = elementAt(es = elements, t = dec(tail, es.length)); @@ -455,7 +456,7 @@ public E getLast(@GuardSatisfied @NonEmpty ArrayDeque this) { * @param o element to be removed from this deque, if present * @return {@code true} if the deque contained the specified element */ - public boolean removeFirstOccurrence(@GuardSatisfied ArrayDeque this, @Nullable Object o) { + public boolean removeFirstOccurrence(@GuardSatisfied @Shrinkable ArrayDeque this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { if (o != null) { final Object[] es = elements; for (int i = head, end = tail, to = (i <= end) ? end : es.length; @@ -483,7 +484,7 @@ public boolean removeFirstOccurrence(@GuardSatisfied ArrayDeque this, @Nullab * @param o element to be removed from this deque, if present * @return {@code true} if the deque contained the specified element */ - public boolean removeLastOccurrence(@GuardSatisfied ArrayDeque this, @Nullable Object o) { + public boolean removeLastOccurrence(@GuardSatisfied @Shrinkable ArrayDeque this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { if (o != null) { final Object[] es = elements; for (int i = tail, end = head, to = (i >= end) ? end : 0; @@ -540,7 +541,7 @@ public boolean offer(@GuardSatisfied ArrayDeque this, E e) { * @return the head of the queue represented by this deque * @throws NoSuchElementException {@inheritDoc} */ - public E remove(@GuardSatisfied @NonEmpty ArrayDeque this) { + public E remove(@GuardSatisfied @NonEmpty @Shrinkable ArrayDeque this) { return removeFirst(); } @@ -554,7 +555,7 @@ public E remove(@GuardSatisfied @NonEmpty ArrayDeque this) { * @return the head of the queue represented by this deque, or * {@code null} if this deque is empty */ - public @Nullable E poll(@GuardSatisfied ArrayDeque this) { + public @Nullable E poll(@GuardSatisfied @Shrinkable ArrayDeque this) { return pollFirst(); } @@ -611,7 +612,7 @@ public void push(@GuardSatisfied ArrayDeque this, E e) { * of the stack represented by this deque) * @throws NoSuchElementException {@inheritDoc} */ - public E pop(@GuardSatisfied @NonEmpty ArrayDeque this) { + public E pop(@GuardSatisfied @NonEmpty @Shrinkable ArrayDeque this) { return removeFirst(); } @@ -693,11 +694,11 @@ public boolean isEmpty(@GuardSatisfied ArrayDeque this) { * @return an iterator over the elements in this deque */ @SideEffectFree - public @PolyNonEmpty Iterator iterator(@PolyNonEmpty ArrayDeque this) { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty ArrayDeque this) { return new DeqIterator(); } - public @PolyNonEmpty Iterator descendingIterator(@PolyNonEmpty ArrayDeque this) { + public @PolyGrowShrink @PolyNonEmpty Iterator descendingIterator(@PolyGrowShrink @PolyNonEmpty ArrayDeque this) { return new DescendingIterator(); } @@ -722,7 +723,6 @@ public final boolean hasNext() { return remaining > 0; } - @SideEffectsOnly("this") public E next(@NonEmpty DeqIterator this) { if (remaining <= 0) throw new NoSuchElementException(); @@ -926,7 +926,7 @@ public void forEach(Consumer action) { /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeIf(Predicate filter) { + public boolean removeIf(@Shrinkable ArrayDeque this, Predicate filter) { Objects.requireNonNull(filter); return bulkRemove(filter); } @@ -934,7 +934,7 @@ public boolean removeIf(Predicate filter) { /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeAll(Collection c) { + public boolean removeAll(@Shrinkable ArrayDeque this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> c.contains(e)); } @@ -942,7 +942,7 @@ public boolean removeAll(Collection c) { /** * @throws NullPointerException {@inheritDoc} */ - public boolean retainAll(Collection c) { + public boolean retainAll(@GuardSatisfied @Shrinkable ArrayDeque this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> !c.contains(e)); } @@ -1058,7 +1058,7 @@ public boolean contains(@GuardSatisfied ArrayDeque this, @GuardSatisfied @Nul * @param o element to be removed from this deque, if present * @return {@code true} if this deque contained the specified element */ - public boolean remove(@GuardSatisfied ArrayDeque this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { + public boolean remove(@GuardSatisfied @Shrinkable ArrayDeque this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { return removeFirstOccurrence(o); } @@ -1066,7 +1066,7 @@ public boolean remove(@GuardSatisfied ArrayDeque this, @GuardSatisfied @Nulla * Removes all of the elements from this deque. * The deque will be empty after this call returns. */ - public void clear(@GuardSatisfied ArrayDeque this) { + public void clear(@GuardSatisfied @Shrinkable ArrayDeque this) { circularClear(elements, head, tail); head = tail = 0; } diff --git a/src/java.base/share/classes/java/util/ArrayList.java b/src/java.base/share/classes/java/util/ArrayList.java index 39962efeb08..eab7ee3ccd5 100644 --- a/src/java.base/share/classes/java/util/ArrayList.java +++ b/src/java.base/share/classes/java/util/ArrayList.java @@ -27,6 +27,8 @@ import org.checkerframework.checker.index.qual.GTENegativeOne; import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; @@ -40,7 +42,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; @@ -501,7 +502,6 @@ public E getLast() { * @return the element previously at the specified position * @throws IndexOutOfBoundsException {@inheritDoc} */ - @SideEffectsOnly("this") public E set(@GuardSatisfied ArrayList this, @NonNegative int index, E element) { Objects.checkIndex(index, size); E oldValue = elementData(index); @@ -514,7 +514,6 @@ public E set(@GuardSatisfied ArrayList this, @NonNegative int index, E elemen * bytecode size under 35 (the -XX:MaxInlineSize default value), * which helps when add(E) is called in a C1-compiled loop. */ - @SideEffectsOnly("this") private void add(E e, Object[] elementData, int s) { if (s == elementData.length) elementData = grow(); @@ -528,7 +527,6 @@ private void add(E e, Object[] elementData, int s) { * @param e element to be appended to this list * @return {@code true} (as specified by {@link Collection#add}) */ - @SideEffectsOnly("this") @EnsuresNonEmpty("this") public boolean add(@GuardSatisfied ArrayList this, E e) { modCount++; @@ -545,7 +543,6 @@ public boolean add(@GuardSatisfied ArrayList this, E e) { * @param element element to be inserted * @throws IndexOutOfBoundsException {@inheritDoc} */ - @SideEffectsOnly("this") public void add(@GuardSatisfied ArrayList this, @NonNegative int index, E element) { rangeCheckForAdd(index); modCount++; @@ -587,7 +584,7 @@ public void addLast(E element) { * @return the element that was removed from the list * @throws IndexOutOfBoundsException {@inheritDoc} */ - public E remove(@GuardSatisfied ArrayList this, @NonNegative int index) { + public E remove(@GuardSatisfied @Shrinkable ArrayList this, @NonNegative int index) { Objects.checkIndex(index, size); final Object[] es = elementData; @@ -734,7 +731,7 @@ int hashCodeRange(int from, int to) { * @param o element to be removed from this list, if present * @return {@code true} if this list contained the specified element */ - public boolean remove(@GuardSatisfied ArrayList this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { + public boolean remove(@GuardSatisfied @Shrinkable ArrayList this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { final Object[] es = elementData; final int size = this.size; int i = 0; @@ -770,7 +767,7 @@ private void fastRemove(Object[] es, int i) { * Removes all of the elements from this list. The list will * be empty after this call returns. */ - public void clear(@GuardSatisfied ArrayList this) { + public void clear(@GuardSatisfied @Shrinkable ArrayList this) { modCount++; final Object[] es = elementData; for (int to = size, i = size = 0; i < to; i++) @@ -790,7 +787,6 @@ public void clear(@GuardSatisfied ArrayList this) { * @return {@code true} if this list changed as a result of the call * @throws NullPointerException if the specified collection is null */ - @SideEffectsOnly("this") public boolean addAll(@GuardSatisfied ArrayList this, Collection c) { Object[] a = c.toArray(); modCount++; @@ -821,7 +817,6 @@ public boolean addAll(@GuardSatisfied ArrayList this, Collection * @throws IndexOutOfBoundsException {@inheritDoc} * @throws NullPointerException if the specified collection is null */ - @SideEffectsOnly("this") public boolean addAll(@GuardSatisfied ArrayList this, @NonNegative int index, Collection c) { rangeCheckForAdd(index); @@ -858,7 +853,7 @@ public boolean addAll(@GuardSatisfied ArrayList this, @NonNegative int index, * toIndex > size() || * toIndex < fromIndex}) */ - protected void removeRange(int fromIndex, int toIndex) { + protected void removeRange(@GuardSatisfied @Shrinkable ArrayList this, int fromIndex, int toIndex) { if (fromIndex > toIndex) { throw new IndexOutOfBoundsException( outOfBoundsMsg(fromIndex, toIndex)); @@ -913,7 +908,7 @@ private static String outOfBoundsMsg(int fromIndex, int toIndex) { * or if the specified collection is null * @see Collection#contains(Object) */ - public boolean removeAll(Collection c) { + public boolean removeAll(@Shrinkable ArrayList this, Collection c) { return batchRemove(c, false, 0, size); } @@ -933,7 +928,7 @@ public boolean removeAll(Collection c) { * or if the specified collection is null * @see Collection#contains(Object) */ - public boolean retainAll(Collection c) { + public boolean retainAll(@GuardSatisfied @Shrinkable ArrayList this, Collection c) { return batchRemove(c, true, 0, size); } @@ -1045,7 +1040,7 @@ private void readObject(java.io.ObjectInputStream s) * * @throws IndexOutOfBoundsException {@inheritDoc} */ - public ListIterator listIterator(@NonNegative int index) { + public @PolyGrowShrink ListIterator listIterator(@PolyGrowShrink ArrayList this, @NonNegative int index) { rangeCheckForAdd(index); return new ListItr(index); } @@ -1058,7 +1053,7 @@ public ListIterator listIterator(@NonNegative int index) { * * @see #listIterator(int) */ - public ListIterator listIterator() { + public @PolyGrowShrink @PolyNonEmpty ListIterator listIterator(@PolyGrowShrink @PolyNonEmpty ArrayList this) { return new ListItr(0); } @@ -1070,7 +1065,7 @@ public ListIterator listIterator() { * @return an iterator over the elements in this list in proper sequence */ @SideEffectFree - public Iterator iterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty ArrayList this) { return new Itr(); } @@ -1092,7 +1087,6 @@ public boolean hasNext() { } @SuppressWarnings("unchecked") - @SideEffectsOnly("this") public E next(@NonEmpty Itr this) { checkForComodification(); int i = cursor; @@ -1235,7 +1229,7 @@ public void add(E e) { * @throws IndexOutOfBoundsException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ - public List subList(@NonNegative int fromIndex, @NonNegative int toIndex) { + public @PolyGrowShrink List subList(@GuardSatisfied @PolyGrowShrink ArrayList this, @NonNegative int fromIndex, @NonNegative int toIndex) { subListRangeCheck(fromIndex, toIndex, size); return new SubList<>(this, fromIndex, toIndex); } @@ -1430,7 +1424,6 @@ public boolean hasNext() { } @SuppressWarnings("unchecked") - @SideEffectsOnly("this") public E next(/*@NonEmpty ListIterator this*/) { checkForComodification(); int i = cursor; @@ -1796,7 +1789,7 @@ private static boolean isClear(long[] bits, int i) { * @throws NullPointerException {@inheritDoc} */ @Override - public boolean removeIf(Predicate filter) { + public boolean removeIf(@Shrinkable ArrayList this, Predicate filter) { return removeIf(filter, 0, size); } @@ -1804,7 +1797,7 @@ public boolean removeIf(Predicate filter) { * Removes all elements satisfying the given predicate, from index * i (inclusive) to index end (exclusive). */ - boolean removeIf(Predicate filter, int i, final int end) { + boolean removeIf(@Shrinkable ArrayList this, Predicate filter, int i, final int end) { Objects.requireNonNull(filter); int expectedModCount = modCount; final Object[] es = elementData; diff --git a/src/java.base/share/classes/java/util/Arrays.java b/src/java.base/share/classes/java/util/Arrays.java index ee3c1a016e9..3e24f799a08 100644 --- a/src/java.base/share/classes/java/util/Arrays.java +++ b/src/java.base/share/classes/java/util/Arrays.java @@ -44,7 +44,6 @@ import org.checkerframework.common.value.qual.MinLen; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; @@ -3522,6 +3521,8 @@ public static void fill(@PolyInterned @PolyNull @PolySigned Object[] a, @IndexOr */ @SideEffectFree @SuppressWarnings("unchecked") + @CFComment("The return type is refined when safe. See " + + "https://github.com/eisop/checker-framework/blob/17991582bc3a35509f15065b051d8e4c45c3e9ae/checker/src/main/java/org/checkerframework/checker/nullness/NullnessNoInitAnnotatedTypeFactory.java#L756") public static @Nullable T[] copyOf(T[] original, @NonNegative int newLength) { return (T[]) copyOf(original, newLength, original.getClass()); } @@ -3552,6 +3553,8 @@ public static void fill(@PolyInterned @PolyNull @PolySigned Object[] a, @IndexOr */ @SideEffectFree @IntrinsicCandidate + @CFComment("The return type is refined when safe. See " + + "https://github.com/eisop/checker-framework/blob/17991582bc3a35509f15065b051d8e4c45c3e9ae/checker/src/main/java/org/checkerframework/checker/nullness/NullnessNoInitAnnotatedTypeFactory.java#L756") public static @Nullable T[] copyOf(U[] original, @NonNegative int newLength, Class newType) { @SuppressWarnings("unchecked") T[] copy = ((Object)newType == (Object)Object[].class) @@ -4413,7 +4416,6 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") public E next(@NonEmpty ArrayItr this) { int i = cursor; if (i >= a.length) { @@ -4672,7 +4674,7 @@ public static int hashCode(double @Nullable [] a) { * @since 1.5 */ @Pure - public static int hashCode(@PolyInterned @PolyNull @PolySigned Object @GuardSatisfied @Nullable [] a) { + public static int hashCode(@PolyInterned @PolyNull @PolySigned Object @GuardSatisfied @Nullable [] a) { if (a == null) return 0; @@ -4714,7 +4716,7 @@ public static int hashCode(@PolyInterned @PolyNull @PolySigned Object @GuardSati * @since 1.5 */ @Pure - public static int deepHashCode(@PolyInterned @PolyNull @PolySigned Object @GuardSatisfied @Nullable [] a) { + public static int deepHashCode(@PolyInterned @PolyNull @PolySigned Object @GuardSatisfied @Nullable [] a) { if (a == null) return 0; diff --git a/src/java.base/share/classes/java/util/Collection.java b/src/java.base/share/classes/java/util/Collection.java index f0eb976ca4a..c8f14803210 100644 --- a/src/java.base/share/classes/java/util/Collection.java +++ b/src/java.base/share/classes/java/util/Collection.java @@ -26,6 +26,8 @@ package java.util; import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; @@ -326,7 +328,7 @@ public interface Collection extends Iterable { * @return an {@code Iterator} over the elements in this collection */ @SideEffectFree - @PolyNonEmpty Iterator iterator(@PolyNonEmpty Collection this); + @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty Collection this); /** * Returns an array containing all of the elements in this collection. @@ -508,7 +510,7 @@ default T[] toArray(IntFunction generator) { * @throws UnsupportedOperationException if the {@code remove} operation * is not supported by this collection */ - boolean remove(@GuardSatisfied Collection this, @UnknownSignedness Object o); + boolean remove(@GuardSatisfied @Shrinkable Collection this, @UnknownSignedness Object o); // Bulk Operations @@ -585,7 +587,7 @@ default T[] toArray(IntFunction generator) { * @see #remove(Object) * @see #contains(Object) */ - boolean removeAll(@GuardSatisfied Collection this, Collection c); + boolean removeAll(@GuardSatisfied @Shrinkable Collection this, Collection c); /** * Removes all of the elements of this collection that satisfy the given @@ -609,7 +611,7 @@ default T[] toArray(IntFunction generator) { * supported. * @since 1.8 */ - default boolean removeIf(Predicate filter) { + default boolean removeIf(@Shrinkable Collection this, Predicate filter) { Objects.requireNonNull(filter); boolean removed = false; final Iterator each = iterator(); @@ -644,7 +646,7 @@ default boolean removeIf(Predicate filter) { * @see #remove(Object) * @see #contains(Object) */ - boolean retainAll(@GuardSatisfied Collection this, Collection c); + boolean retainAll(@GuardSatisfied @Shrinkable Collection this, Collection c); /** * Removes all of the elements from this collection (optional operation). @@ -653,7 +655,7 @@ default boolean removeIf(Predicate filter) { * @throws UnsupportedOperationException if the {@code clear} operation * is not supported by this collection */ - void clear(@GuardSatisfied Collection this); + void clear(@GuardSatisfied @Shrinkable Collection this); // Comparison and hashing diff --git a/src/java.base/share/classes/java/util/Collections.java b/src/java.base/share/classes/java/util/Collections.java index 5c9713dd80b..1e5565cf647 100644 --- a/src/java.base/share/classes/java/util/Collections.java +++ b/src/java.base/share/classes/java/util/Collections.java @@ -27,6 +27,7 @@ import org.checkerframework.checker.index.qual.GTENegativeOne; import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.index.qual.PolyGrowShrink; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; @@ -44,7 +45,6 @@ import org.checkerframework.common.value.qual.StaticallyExecutable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; @@ -198,6 +198,7 @@ public static > void sort(List list) { * found to violate the {@link Comparator} contract * @see List#sort(Comparator) */ + @SuppressWarnings({"unchecked", "rawtypes"}) public static void sort(List list, @Nullable Comparator c) { list.sort(c); } @@ -681,7 +682,7 @@ public static > T min(Collection T min(Collection coll, @Nullable Comparator comp) { @@ -758,7 +759,7 @@ public static > T max(Collection T max(Collection coll, @Nullable Comparator comp) { @@ -1074,7 +1075,7 @@ public static boolean replaceAll(List list, @Nullable T oldVal, T newVal) */ @SuppressWarnings("unchecked") @SideEffectFree - public static @PolyNonEmpty Collection unmodifiableCollection(@PolyNonEmpty Collection c) { + public static @PolyGrowShrink @PolyNonEmpty Collection unmodifiableCollection(@PolyGrowShrink @PolyNonEmpty Collection c) { if (c.getClass() == UnmodifiableCollection.class) { return (Collection) c; } @@ -1113,14 +1114,13 @@ static class UnmodifiableCollection implements Collection, Serializable { public String toString() {return c.toString();} @SideEffectFree - public @PolyNonEmpty Iterator iterator(@PolyNonEmpty UnmodifiableCollection this) { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty UnmodifiableCollection this) { return new Iterator<>() { private final Iterator i = c.iterator(); @Pure @EnsuresNonEmptyIf(result = true, expression = "this") public boolean hasNext() {return i.hasNext();} - @SideEffectsOnly("this") public E next(/*@NonEmpty Iterator this*/) {return i.next();} public void remove() { throw new UnsupportedOperationException(); @@ -1520,7 +1520,7 @@ public NavigableSet tailSet(E fromElement, boolean inclusive) { * @return an unmodifiable view of the specified list. */ @SuppressWarnings("unchecked") - public static @PolyNonEmpty List unmodifiableList(@PolyNonEmpty List list) { + public static @PolyGrowShrink @PolyNonEmpty List unmodifiableList(@PolyGrowShrink @PolyNonEmpty List list) { if (list.getClass() == UnmodifiableList.class || list.getClass() == UnmodifiableRandomAccessList.class) { return (List) list; } @@ -1574,7 +1574,7 @@ public void sort(Comparator c) { throw new UnsupportedOperationException(); } - public @PolyNonEmpty ListIterator listIterator(@PolyNonEmpty UnmodifiableList this) {return listIterator(0);} + public @PolyGrowShrink @PolyNonEmpty ListIterator listIterator(@PolyGrowShrink @PolyNonEmpty UnmodifiableList this) {return listIterator(0);} public ListIterator listIterator(final int index) { return new ListIterator<>() { @@ -1584,11 +1584,9 @@ public ListIterator listIterator(final int index) { @Pure @EnsuresNonEmptyIf(result = true, expression = "this") public boolean hasNext() {return i.hasNext();} - @SideEffectsOnly("this") public E next(/*@NonEmpty ListIterator this*/) {return i.next();} @Pure public boolean hasPrevious() {return i.hasPrevious();} - @SideEffectsOnly("this") public E previous() {return i.previous();} public int nextIndex() {return i.nextIndex();} public int previousIndex() {return i.previousIndex();} @@ -1928,7 +1926,6 @@ public Iterator> iterator() { public boolean hasNext() { return i.hasNext(); } - @SideEffectsOnly("this") public Map.Entry next(/*@NonEmpty Iterator> this*/) { return new UnmodifiableEntry<>(i.next()); } @@ -2348,11 +2345,11 @@ public NavigableMap tailMap(K fromKey, boolean inclusive) * @param c the collection to be "wrapped" in a synchronized collection. * @return a synchronized view of the specified collection. */ - public static Collection synchronizedCollection(Collection c) { + public static @PolyGrowShrink @PolyNonEmpty Collection synchronizedCollection(@PolyGrowShrink @PolyNonEmpty Collection c) { return new SynchronizedCollection<>(c); } - static Collection synchronizedCollection(Collection c, Object mutex) { + static @PolyGrowShrink @PolyNonEmpty Collection synchronizedCollection(@PolyGrowShrink @PolyNonEmpty Collection c, Object mutex) { return new SynchronizedCollection<>(c, mutex); } @@ -2764,13 +2761,13 @@ public NavigableSet tailSet(E fromElement, boolean inclusive) { * @param list the list to be "wrapped" in a synchronized list. * @return a synchronized view of the specified list. */ - public static List synchronizedList(List list) { + public static @PolyGrowShrink @PolyNonEmpty List synchronizedList(@PolyGrowShrink @PolyNonEmpty List list) { return (list instanceof RandomAccess ? new SynchronizedRandomAccessList<>(list) : new SynchronizedList<>(list)); } - static List synchronizedList(List list, Object mutex) { + static @PolyGrowShrink @PolyNonEmpty List synchronizedList(@PolyGrowShrink @PolyNonEmpty List list, Object mutex) { return (list instanceof RandomAccess ? new SynchronizedRandomAccessList<>(list, mutex) : new SynchronizedList<>(list, mutex)); @@ -3441,7 +3438,7 @@ public NavigableMap tailMap(K fromKey, boolean inclusive) { * @return a dynamically typesafe view of the specified collection * @since 1.5 */ - public static Collection checkedCollection(Collection c, + public static @PolyGrowShrink @PolyNonEmpty Collection checkedCollection(@PolyGrowShrink @PolyNonEmpty Collection c, Class type) { return new CheckedCollection<>(c, type); } @@ -3517,7 +3514,6 @@ public Iterator iterator() { @Pure @EnsuresNonEmptyIf(result = true, expression = "this") public boolean hasNext() { return it.hasNext(); } - @SideEffectsOnly("this") public E next(/*@NonEmpty Iterator this*/) { return it.next(); } public void remove() { it.remove(); } public void forEachRemaining(Consumer action) { @@ -3611,7 +3607,7 @@ public boolean removeIf(Predicate filter) { * @return a dynamically typesafe view of the specified queue * @since 1.8 */ - public static Queue checkedQueue(Queue queue, Class type) { + public static @PolyGrowShrink @PolyNonEmpty Queue checkedQueue(@PolyGrowShrink @PolyNonEmpty Queue queue, Class type) { return new CheckedQueue<>(queue, type); } @@ -3866,7 +3862,7 @@ public NavigableSet tailSet(E fromElement, boolean inclusive) { * @return a dynamically typesafe view of the specified list * @since 1.5 */ - public static List checkedList(List list, Class type) { + public static @PolyGrowShrink @PolyNonEmpty List checkedList(@PolyGrowShrink @PolyNonEmpty List list, Class type) { return (list instanceof RandomAccess ? new CheckedRandomAccessList<>(list, type) : new CheckedList<>(list, type)); @@ -3916,7 +3912,6 @@ public ListIterator listIterator(final int index) { @Pure @EnsuresNonEmptyIf(result = true, expression = "this") public boolean hasNext() { return i.hasNext(); } - @SideEffectsOnly("this") public E next(/*@NonEmpty ListIterator this*/) { return i.next(); } public boolean hasPrevious() { return i.hasPrevious(); } public E previous() { return i.previous(); } @@ -4240,7 +4235,6 @@ public Iterator> iterator() { @Pure @EnsuresNonEmptyIf(result = true, expression = "this") public boolean hasNext() { return i.hasNext(); } - @SideEffectsOnly("this") public void remove() { i.remove(); } public Map.Entry next(/*@NonEmpty Iterator> this*/) { @@ -4696,7 +4690,6 @@ private static class EmptyIterator implements Iterator { @Pure @EnsuresNonEmptyIf(result = true, expression = "this") public boolean hasNext() { return false; } - @SideEffectsOnly("this") public E next(@NonEmpty EmptyIterator this) { throw new NoSuchElementException(); } public void remove(@NonEmpty EmptyIterator this) { throw new IllegalStateException(); } @Override @@ -5239,7 +5232,6 @@ static Iterator singletonIterator(final E e) { public boolean hasNext() { return hasNext; } - @SideEffectsOnly("this") public E next(/*@NonEmpty Iterator this*/) { if (hasNext) { hasNext = false; @@ -5637,6 +5629,7 @@ public E get(int index) { return element; } + @SideEffectFree @Override public void forEach(Consumer action) { Objects.requireNonNull(action); @@ -6326,7 +6319,7 @@ private SequencedMap map() { * @return the queue * @since 1.6 */ - public static Queue asLifoQueue(Deque deque) { + public static @PolyGrowShrink @PolyNonEmpty Queue asLifoQueue(@PolyGrowShrink @PolyNonEmpty Deque deque) { return new AsLIFOQueue<>(Objects.requireNonNull(deque)); } diff --git a/src/java.base/share/classes/java/util/ConcurrentModificationException.java b/src/java.base/share/classes/java/util/ConcurrentModificationException.java index 7161225bad4..4cb5999265c 100644 --- a/src/java.base/share/classes/java/util/ConcurrentModificationException.java +++ b/src/java.base/share/classes/java/util/ConcurrentModificationException.java @@ -25,6 +25,9 @@ package java.util; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * This exception may be thrown by methods that have detected concurrent * modification of an object when such modification is not permissible. @@ -67,6 +70,7 @@ * @see AbstractList * @since 1.2 */ +@AnnotatedFor({"nullness"}) public class ConcurrentModificationException extends RuntimeException { @java.io.Serial private static final long serialVersionUID = -3666751008965953603L; @@ -84,7 +88,7 @@ public ConcurrentModificationException() { * * @param message the detail message pertaining to this exception. */ - public ConcurrentModificationException(String message) { + public ConcurrentModificationException(@Nullable String message) { super(message); } @@ -99,7 +103,7 @@ public ConcurrentModificationException(String message) { * unknown.) * @since 1.7 */ - public ConcurrentModificationException(Throwable cause) { + public ConcurrentModificationException(@Nullable Throwable cause) { super(cause); } @@ -119,7 +123,7 @@ public ConcurrentModificationException(Throwable cause) { * unknown.) * @since 1.7 */ - public ConcurrentModificationException(String message, Throwable cause) { + public ConcurrentModificationException(@Nullable String message, @Nullable Throwable cause) { super(message, cause); } } diff --git a/src/java.base/share/classes/java/util/Date.java b/src/java.base/share/classes/java/util/Date.java index 5956a7fd179..c8f9244a5da 100644 --- a/src/java.base/share/classes/java/util/Date.java +++ b/src/java.base/share/classes/java/util/Date.java @@ -983,8 +983,8 @@ static final long getMillisOf(Date date) { * @since 1.2 * @throws NullPointerException if {@code anotherDate} is null. */ - @Override @Pure + @Override public int compareTo(@GuardSatisfied Date this, @GuardSatisfied Date anotherDate) { return Long.compare(getMillisOf(this), getMillisOf(anotherDate)); } diff --git a/src/java.base/share/classes/java/util/Deque.java b/src/java.base/share/classes/java/util/Deque.java index 9f2f4fb7648..385575bb9bf 100644 --- a/src/java.base/share/classes/java/util/Deque.java +++ b/src/java.base/share/classes/java/util/Deque.java @@ -36,10 +36,13 @@ package java.util; import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; @@ -302,7 +305,7 @@ public interface Deque extends Queue, SequencedCollection { * @return the head of this deque * @throws NoSuchElementException if this deque is empty */ - E removeFirst(@GuardSatisfied @NonEmpty Deque this); + E removeFirst(@GuardSatisfied @NonEmpty @Shrinkable Deque this); /** * Retrieves and removes the last element of this deque. This method @@ -312,7 +315,7 @@ public interface Deque extends Queue, SequencedCollection { * @return the tail of this deque * @throws NoSuchElementException if this deque is empty */ - E removeLast(@GuardSatisfied @NonEmpty Deque this); + E removeLast(@GuardSatisfied @NonEmpty @Shrinkable Deque this); /** * Retrieves and removes the first element of this deque, @@ -320,7 +323,7 @@ public interface Deque extends Queue, SequencedCollection { * * @return the head of this deque, or {@code null} if this deque is empty */ - @Nullable E pollFirst(@GuardSatisfied Deque this); + @Nullable E pollFirst(@GuardSatisfied @Shrinkable Deque this); /** * Retrieves and removes the last element of this deque, @@ -328,7 +331,7 @@ public interface Deque extends Queue, SequencedCollection { * * @return the tail of this deque, or {@code null} if this deque is empty */ - @Nullable E pollLast(@GuardSatisfied Deque this); + @Nullable E pollLast(@GuardSatisfied @Shrinkable Deque this); /** * Retrieves, but does not remove, the first element of this deque. @@ -340,7 +343,7 @@ public interface Deque extends Queue, SequencedCollection { * @throws NoSuchElementException if this deque is empty */ @EnsuresNonEmpty("this") - E getFirst(@GuardSatisfied @NonEmpty Deque this); + E getFirst(@GuardSatisfied @NonEmpty @Shrinkable Deque this); /** * Retrieves, but does not remove, the last element of this deque. @@ -351,7 +354,7 @@ public interface Deque extends Queue, SequencedCollection { * @throws NoSuchElementException if this deque is empty */ @EnsuresNonEmpty("this") - E getLast(@GuardSatisfied @NonEmpty Deque this); + E getLast(@GuardSatisfied @NonEmpty @Shrinkable Deque this); /** * Retrieves, but does not remove, the first element of this deque, @@ -359,7 +362,8 @@ public interface Deque extends Queue, SequencedCollection { * * @return the head of this deque, or {@code null} if this deque is empty */ - @Nullable E peekFirst(); + @Pure + @Nullable E peekFirst(@GuardSatisfied Deque this); /** * Retrieves, but does not remove, the last element of this deque, @@ -367,7 +371,8 @@ public interface Deque extends Queue, SequencedCollection { * * @return the tail of this deque, or {@code null} if this deque is empty */ - @Nullable E peekLast(); + @Pure + @Nullable E peekLast(@GuardSatisfied Deque this); /** * Removes the first occurrence of the specified element from this deque. @@ -386,7 +391,7 @@ public interface Deque extends Queue, SequencedCollection { * deque does not permit null elements * ({@linkplain Collection##optional-restrictions optional}) */ - boolean removeFirstOccurrence(@GuardSatisfied Deque this, Object o); + boolean removeFirstOccurrence(@GuardSatisfied @Shrinkable Deque this, Object o); /** * Removes the last occurrence of the specified element from this deque. @@ -405,7 +410,7 @@ public interface Deque extends Queue, SequencedCollection { * deque does not permit null elements * ({@linkplain Collection##optional-restrictions optional}) */ - boolean removeLastOccurrence(@GuardSatisfied Deque this, Object o); + boolean removeLastOccurrence(@GuardSatisfied @Shrinkable Deque this, Object o); // *** Queue methods *** @@ -468,7 +473,7 @@ public interface Deque extends Queue, SequencedCollection { * @return the head of the queue represented by this deque * @throws NoSuchElementException if this deque is empty */ - E remove(@GuardSatisfied @NonEmpty Deque this); + E remove(@GuardSatisfied @NonEmpty @Shrinkable Deque this); /** * Retrieves and removes the head of the queue represented by this deque @@ -480,7 +485,7 @@ public interface Deque extends Queue, SequencedCollection { * @return the first element of this deque, or {@code null} if * this deque is empty */ - @Nullable E poll(@GuardSatisfied Deque this); + @Nullable E poll(@GuardSatisfied @Shrinkable Deque this); /** * Retrieves, but does not remove, the head of the queue represented by @@ -505,7 +510,8 @@ public interface Deque extends Queue, SequencedCollection { * @return the head of the queue represented by this deque, or * {@code null} if this deque is empty */ - @Nullable E peek(); + @Pure + @Nullable E peek(@GuardSatisfied Deque this); /** * Adds all of the elements in the specified collection at the end @@ -565,7 +571,7 @@ public interface Deque extends Queue, SequencedCollection { * of the stack represented by this deque) * @throws NoSuchElementException if this deque is empty */ - E pop(@GuardSatisfied @NonEmpty Deque this); + E pop(@GuardSatisfied @NonEmpty @Shrinkable Deque this); // *** Collection methods *** @@ -589,7 +595,7 @@ public interface Deque extends Queue, SequencedCollection { * deque does not permit null elements * ({@linkplain Collection##optional-restrictions optional}) */ - boolean remove(@GuardSatisfied Deque this, @UnknownSignedness Object o); + boolean remove(@GuardSatisfied @Shrinkable Deque this, @UnknownSignedness Object o); /** * Returns {@code true} if this deque contains the specified element. @@ -624,7 +630,7 @@ public interface Deque extends Queue, SequencedCollection { * @return an iterator over the elements in this deque in proper sequence */ @SideEffectFree - Iterator iterator(); + @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty Deque this); /** * Returns an iterator over the elements in this deque in reverse diff --git a/src/java.base/share/classes/java/util/EnumMap.java b/src/java.base/share/classes/java/util/EnumMap.java index 1d170eda873..880386c3749 100644 --- a/src/java.base/share/classes/java/util/EnumMap.java +++ b/src/java.base/share/classes/java/util/EnumMap.java @@ -39,7 +39,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; diff --git a/src/java.base/share/classes/java/util/Enumeration.java b/src/java.base/share/classes/java/util/Enumeration.java index 5a51f493177..6298b0a0e85 100644 --- a/src/java.base/share/classes/java/util/Enumeration.java +++ b/src/java.base/share/classes/java/util/Enumeration.java @@ -29,7 +29,6 @@ import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; /** @@ -133,7 +132,6 @@ default Iterator asIterator() { @Override public boolean hasNext() { return hasMoreElements(); } - @SideEffectsOnly("this") @Override public E next(/*@NonEmpty Iterator this*/) { return nextElement(); } diff --git a/src/java.base/share/classes/java/util/Formatter.java b/src/java.base/share/classes/java/util/Formatter.java index f872eb03d64..0d57162b4bb 100644 --- a/src/java.base/share/classes/java/util/Formatter.java +++ b/src/java.base/share/classes/java/util/Formatter.java @@ -4665,6 +4665,8 @@ public static boolean containsAny(int flags, int f) { return (flags & f) != 0; } + @Pure + @EnsuresNonEmptyIf(result = true, expression = "this") private static int add(int flags, int f) { return flags | f; } diff --git a/src/java.base/share/classes/java/util/HashMap.java b/src/java.base/share/classes/java/util/HashMap.java index 23bcf9e7b96..d259da5c4d8 100644 --- a/src/java.base/share/classes/java/util/HashMap.java +++ b/src/java.base/share/classes/java/util/HashMap.java @@ -39,7 +39,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; @@ -1649,7 +1648,6 @@ public final boolean hasNext() { return next != null; } - @SideEffectsOnly("this") final Node nextNode(@NonEmpty HashIterator this) { Node[] t; Node e = next; diff --git a/src/java.base/share/classes/java/util/HashSet.java b/src/java.base/share/classes/java/util/HashSet.java index fbdbb831a12..d54e501f294 100644 --- a/src/java.base/share/classes/java/util/HashSet.java +++ b/src/java.base/share/classes/java/util/HashSet.java @@ -26,6 +26,7 @@ package java.util; import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.index.qual.PolyGrowShrink; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; @@ -36,7 +37,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import java.io.InvalidObjectException; @@ -194,7 +194,7 @@ public HashSet(@NonNegative int initialCapacity) { * @see ConcurrentModificationException */ @SideEffectFree - public @PolyNonEmpty Iterator iterator(@PolyNonEmpty HashSet this) { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty HashSet this) { return map.keySet().iterator(); } @@ -246,7 +246,6 @@ public boolean contains(@GuardSatisfied HashSet this, @GuardSatisfied @Nullab * @return {@code true} if this set did not already contain the specified * element */ - @SideEffectsOnly("this") @EnsuresNonEmpty("this") public boolean add(@GuardSatisfied HashSet this, E e) { return map.put(e, PRESENT)==null; @@ -264,7 +263,6 @@ public boolean add(@GuardSatisfied HashSet this, E e) { * @param o object to be removed from this set, if present * @return {@code true} if the set contained the specified element */ - @SideEffectsOnly("this") public boolean remove(@GuardSatisfied HashSet this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { return map.remove(o)==PRESENT; } @@ -273,7 +271,6 @@ public boolean remove(@GuardSatisfied HashSet this, @GuardSatisfied @Nullable * Removes all of the elements from this set. * The set will be empty after this call returns. */ - @SideEffectsOnly("this") public void clear(@GuardSatisfied HashSet this) { map.clear(); } diff --git a/src/java.base/share/classes/java/util/Hashtable.java b/src/java.base/share/classes/java/util/Hashtable.java index ef82f08a25b..b6673e0533b 100644 --- a/src/java.base/share/classes/java/util/Hashtable.java +++ b/src/java.base/share/classes/java/util/Hashtable.java @@ -39,7 +39,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; @@ -1548,7 +1547,6 @@ public boolean hasNext() { return hasMoreElements(); } - @SideEffectsOnly("this") public T next(@NonEmpty Enumerator this) { if (Hashtable.this.modCount != expectedModCount) throw new ConcurrentModificationException(); diff --git a/src/java.base/share/classes/java/util/IdentityHashMap.java b/src/java.base/share/classes/java/util/IdentityHashMap.java index 6b70ff06197..d35b58c2411 100644 --- a/src/java.base/share/classes/java/util/IdentityHashMap.java +++ b/src/java.base/share/classes/java/util/IdentityHashMap.java @@ -37,7 +37,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; @@ -782,7 +781,6 @@ public boolean hasNext() { return false; } - @SideEffectsOnly("this") protected int nextIndex(@NonEmpty IdentityHashMapIterator this) { if (modCount != expectedModCount) throw new ConcurrentModificationException(); diff --git a/src/java.base/share/classes/java/util/ImmutableCollections.java b/src/java.base/share/classes/java/util/ImmutableCollections.java index a92d80bb60d..348ab7e48fc 100644 --- a/src/java.base/share/classes/java/util/ImmutableCollections.java +++ b/src/java.base/share/classes/java/util/ImmutableCollections.java @@ -34,7 +34,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.io.IOException; import java.io.InvalidObjectException; @@ -389,7 +388,6 @@ public boolean hasNext() { return cursor != size; } - @SideEffectsOnly("this") public E next(@NonEmpty ListItr this) { try { int i = cursor; @@ -852,7 +850,7 @@ public int hashCode() { @Override public Iterator iterator() { - return new Iterator() { + return new Iterator<>() { private int idx = (e1 == EMPTY) ? 1 : 2; @Override @@ -863,7 +861,6 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") @SuppressWarnings("unchecked") public E next(/*@NonEmpty Iterator this*/) { if (idx == 1) { @@ -1001,7 +998,6 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") public E next(@NonEmpty SetNIterator this) { if (remaining > 0) { E element; @@ -1323,7 +1319,6 @@ public boolean hasNext() { return remaining > 0; } - @SideEffectsOnly("this") private int nextIndex() { int idx = this.idx; if (REVERSE) { diff --git a/src/java.base/share/classes/java/util/InvalidPropertiesFormatException.java b/src/java.base/share/classes/java/util/InvalidPropertiesFormatException.java index 3b1801b90fd..cea97b53750 100644 --- a/src/java.base/share/classes/java/util/InvalidPropertiesFormatException.java +++ b/src/java.base/share/classes/java/util/InvalidPropertiesFormatException.java @@ -25,6 +25,9 @@ package java.util; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + import java.io.NotSerializableException; import java.io.IOException; @@ -43,6 +46,7 @@ * @serial exclude */ +@AnnotatedFor({"nullness"}) public class InvalidPropertiesFormatException extends IOException { @java.io.Serial @@ -55,7 +59,7 @@ public class InvalidPropertiesFormatException extends IOException { * @param cause the cause (which is saved for later retrieval by the * {@link Throwable#getCause()} method). */ - public InvalidPropertiesFormatException(Throwable cause) { + public InvalidPropertiesFormatException(@Nullable Throwable cause) { super(cause==null ? null : cause.toString()); this.initCause(cause); } @@ -67,7 +71,7 @@ public InvalidPropertiesFormatException(Throwable cause) { * @param message the detail message. The detail message is saved for * later retrieval by the {@link Throwable#getMessage()} method. */ - public InvalidPropertiesFormatException(String message) { + public InvalidPropertiesFormatException(@Nullable String message) { super(message); } diff --git a/src/java.base/share/classes/java/util/Iterator.java b/src/java.base/share/classes/java/util/Iterator.java index 873f17166e9..6bff1b79443 100644 --- a/src/java.base/share/classes/java/util/Iterator.java +++ b/src/java.base/share/classes/java/util/Iterator.java @@ -25,11 +25,11 @@ package java.util; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; import org.checkerframework.framework.qual.Covariant; @@ -87,7 +87,6 @@ public interface Iterator { * @return the next element in the iteration * @throws NoSuchElementException if the iteration has no more elements */ - @SideEffectsOnly("this") E next(@GuardSatisfied @NonEmpty Iterator this); /** @@ -115,7 +114,7 @@ public interface Iterator { * been called after the last call to the {@code next} * method */ - default void remove(@GuardSatisfied Iterator this) { + default void remove(@GuardSatisfied @Shrinkable Iterator this) { throw new UnsupportedOperationException("remove"); } diff --git a/src/java.base/share/classes/java/util/JumboEnumSet.java b/src/java.base/share/classes/java/util/JumboEnumSet.java index dab2efe1d80..75ea15f8307 100644 --- a/src/java.base/share/classes/java/util/JumboEnumSet.java +++ b/src/java.base/share/classes/java/util/JumboEnumSet.java @@ -25,17 +25,18 @@ package java.util; +import org.checkerframework.checker.index.qual.PolyGrowShrink; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.checker.index.qual.NonNegative; import org.checkerframework.dataflow.qual.Pure; @@ -108,7 +109,7 @@ void complement() { * * @return an iterator over the elements contained in this set */ - public Iterator iterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty JumboEnumSet this) { return new EnumSetIterator<>(); } @@ -150,7 +151,6 @@ public boolean hasNext() { @Override @SuppressWarnings("unchecked") - @SideEffectsOnly("this") public E next(@NonEmpty EnumSetIterator this) { if (!hasNext()) throw new NoSuchElementException(); diff --git a/src/java.base/share/classes/java/util/LinkedHashMap.java b/src/java.base/share/classes/java/util/LinkedHashMap.java index 00d181f507f..3afc9a99e87 100644 --- a/src/java.base/share/classes/java/util/LinkedHashMap.java +++ b/src/java.base/share/classes/java/util/LinkedHashMap.java @@ -36,7 +36,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import java.util.function.Consumer; @@ -713,7 +712,7 @@ final T[] valuesToArray(T[] a, boolean reversed) { final class LinkedKeySet extends AbstractSet implements SequencedSet { final boolean reversed; LinkedKeySet(boolean reversed) { this.reversed = reversed; } - @Pure + @Pure public final int size() { return size; } public final void clear() { LinkedHashMap.this.clear(); } @SideEffectFree @@ -826,7 +825,7 @@ public SequencedCollection sequencedValues() { final class LinkedValues extends AbstractCollection implements SequencedCollection { final boolean reversed; LinkedValues(boolean reversed) { this.reversed = reversed; } - @Pure + @Pure public final int size() { return size; } public final void clear() { LinkedHashMap.this.clear(); } @SideEffectFree @@ -938,7 +937,7 @@ final class LinkedEntrySet extends AbstractSet> implements SequencedSet> { final boolean reversed; LinkedEntrySet(boolean reversed) { this.reversed = reversed; } - @Pure + @Pure public final int size() { return size; } public final void clear() { LinkedHashMap.this.clear(); } @SideEffectFree @@ -1054,7 +1053,6 @@ public final boolean hasNext() { return next != null; } - @SideEffectsOnly("this") final LinkedHashMap.Entry nextNode(@NonEmpty LinkedHashIterator this) { LinkedHashMap.Entry e = next; if (modCount != expectedModCount) diff --git a/src/java.base/share/classes/java/util/LinkedList.java b/src/java.base/share/classes/java/util/LinkedList.java index f029090eecd..f079b134dab 100644 --- a/src/java.base/share/classes/java/util/LinkedList.java +++ b/src/java.base/share/classes/java/util/LinkedList.java @@ -27,6 +27,8 @@ import org.checkerframework.checker.index.qual.GTENegativeOne; import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.lock.qual.ReleasesNoLocks; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; @@ -39,7 +41,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; @@ -295,7 +296,7 @@ public E getLast(@GuardSatisfied @NonEmpty LinkedList this) { * @return the first element from this list * @throws NoSuchElementException if this list is empty */ - public E removeFirst(@GuardSatisfied @NonEmpty LinkedList this) { + public E removeFirst(@GuardSatisfied @NonEmpty @Shrinkable LinkedList this) { final Node f = first; if (f == null) throw new NoSuchElementException(); @@ -308,7 +309,7 @@ public E removeFirst(@GuardSatisfied @NonEmpty LinkedList this) { * @return the last element from this list * @throws NoSuchElementException if this list is empty */ - public E removeLast(@GuardSatisfied @NonEmpty LinkedList this) { + public E removeLast(@GuardSatisfied @NonEmpty @Shrinkable LinkedList this) { final Node l = last; if (l == null) throw new NoSuchElementException(); @@ -389,7 +390,7 @@ public boolean add(@GuardSatisfied LinkedList this, E e) { * @return {@code true} if this list contained the specified element */ @ReleasesNoLocks - public boolean remove(@GuardSatisfied LinkedList this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { + public boolean remove(@GuardSatisfied @Shrinkable LinkedList this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { if (o == null) { for (Node x = first; x != null; x = x.next) { if (x.item == null) { @@ -482,7 +483,7 @@ public boolean addAll(@GuardSatisfied LinkedList this, @NonNegative int index * Removes all of the elements from this list. * The list will be empty after this call returns. */ - public void clear(@GuardSatisfied LinkedList this) { + public void clear(@GuardSatisfied @Shrinkable LinkedList this) { // Clearing all of the links between nodes is "unnecessary", but: // - helps a generational GC if the discarded nodes inhabit // more than one generation @@ -559,7 +560,7 @@ public void add(@GuardSatisfied LinkedList this, @NonNegative int index, E el * @return the element previously at the specified position * @throws IndexOutOfBoundsException {@inheritDoc} */ - public E remove(@GuardSatisfied LinkedList this, @NonNegative int index) { + public E remove(@GuardSatisfied @Shrinkable LinkedList this, @NonNegative int index) { checkElementIndex(index); return unlink(node(index)); } @@ -710,7 +711,7 @@ public E element(@GuardSatisfied @NonEmpty LinkedList this) { * @return the head of this list, or {@code null} if this list is empty * @since 1.5 */ - public @Nullable E poll(@GuardSatisfied LinkedList this) { + public @Nullable E poll(@GuardSatisfied @Shrinkable LinkedList this) { final Node f = first; return (f == null) ? null : unlinkFirst(f); } @@ -722,7 +723,7 @@ public E element(@GuardSatisfied @NonEmpty LinkedList this) { * @throws NoSuchElementException if this list is empty * @since 1.5 */ - public E remove(@GuardSatisfied @NonEmpty LinkedList this) { + public E remove(@GuardSatisfied @NonEmpty @Shrinkable LinkedList this) { return removeFirst(); } @@ -798,7 +799,7 @@ public boolean offerLast(E e) { * this list is empty * @since 1.6 */ - public @Nullable E pollFirst(@GuardSatisfied LinkedList this) { + public @Nullable E pollFirst(@GuardSatisfied @Shrinkable LinkedList this) { final Node f = first; return (f == null) ? null : unlinkFirst(f); } @@ -811,7 +812,7 @@ public boolean offerLast(E e) { * this list is empty * @since 1.6 */ - public @Nullable E pollLast(@GuardSatisfied LinkedList this) { + public @Nullable E pollLast(@GuardSatisfied @Shrinkable LinkedList this) { final Node l = last; return (l == null) ? null : unlinkLast(l); } @@ -840,7 +841,7 @@ public void push(@GuardSatisfied LinkedList this, E e) { * @throws NoSuchElementException if this list is empty * @since 1.6 */ - public E pop(@GuardSatisfied @NonEmpty LinkedList this) { + public E pop(@GuardSatisfied @NonEmpty @Shrinkable LinkedList this) { return removeFirst(); } @@ -853,7 +854,7 @@ public E pop(@GuardSatisfied @NonEmpty LinkedList this) { * @return {@code true} if the list contained the specified element * @since 1.6 */ - public boolean removeFirstOccurrence(@GuardSatisfied LinkedList this, @Nullable Object o) { + public boolean removeFirstOccurrence(@GuardSatisfied @Shrinkable LinkedList this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { return remove(o); } @@ -866,7 +867,7 @@ public boolean removeFirstOccurrence(@GuardSatisfied LinkedList this, @Nullab * @return {@code true} if the list contained the specified element * @since 1.6 */ - public boolean removeLastOccurrence(@GuardSatisfied LinkedList this, @Nullable Object o) { + public boolean removeLastOccurrence(@GuardSatisfied @Shrinkable LinkedList this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { if (o == null) { for (Node x = last; x != null; x = x.prev) { if (x.item == null) { @@ -906,7 +907,7 @@ public boolean removeLastOccurrence(@GuardSatisfied LinkedList this, @Nullabl * @throws IndexOutOfBoundsException {@inheritDoc} * @see List#listIterator(int) */ - public ListIterator listIterator(@NonNegative int index) { + public @PolyGrowShrink @PolyNonEmpty ListIterator listIterator(@PolyGrowShrink @PolyNonEmpty LinkedList this, @NonNegative int index) { checkPositionIndex(index); return new ListItr(index); } @@ -929,7 +930,6 @@ public boolean hasNext() { return nextIndex < size; } - @SideEffectsOnly("this") public E next(@NonEmpty ListItr this) { checkForComodification(); if (!hasNext()) @@ -1028,7 +1028,7 @@ private static class Node { /** * @since 1.6 */ - public Iterator descendingIterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator descendingIterator(@PolyGrowShrink @PolyNonEmpty LinkedList this) { return new DescendingIterator(); } @@ -1042,7 +1042,6 @@ private class DescendingIterator implements Iterator { public boolean hasNext() { return itr.hasPrevious(); } - @SideEffectsOnly("this") public E next(@NonEmpty DescendingIterator this) { return itr.previous(); } diff --git a/src/java.base/share/classes/java/util/List.java b/src/java.base/share/classes/java/util/List.java index df6433df210..2ffcdeea06a 100644 --- a/src/java.base/share/classes/java/util/List.java +++ b/src/java.base/share/classes/java/util/List.java @@ -29,6 +29,8 @@ import org.checkerframework.checker.index.qual.IndexFor; import org.checkerframework.checker.index.qual.IndexOrHigh; import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.lock.qual.ReleasesNoLocks; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; @@ -41,7 +43,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; @@ -207,7 +208,7 @@ public interface List extends SequencedCollection { * @return an iterator over the elements in this list in proper sequence */ @SideEffectFree - @PolyNonEmpty Iterator iterator(@PolyNonEmpty List this); + @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty List this); /** * Returns an array containing all of the elements in this list in proper @@ -296,7 +297,6 @@ public interface List extends SequencedCollection { * prevents it from being added to this list */ @ReleasesNoLocks - @SideEffectsOnly("this") @EnsuresNonEmpty("this") boolean add(@GuardSatisfied List this, E e); @@ -321,8 +321,7 @@ public interface List extends SequencedCollection { * @throws UnsupportedOperationException if the {@code remove} operation * is not supported by this list */ - @SideEffectsOnly("this") - boolean remove(@GuardSatisfied List this, @UnknownSignedness Object o); + boolean remove(@GuardSatisfied @Shrinkable List this, @UnknownSignedness Object o); // Bulk Modification Operations @@ -369,7 +368,6 @@ public interface List extends SequencedCollection { * specified collection prevents it from being added to this list * @see #add(Object) */ - @SideEffectsOnly("this") @EnsuresNonEmptyIf(result = true, expression = "this") boolean addAll(@GuardSatisfied List this, Collection c); @@ -400,7 +398,6 @@ public interface List extends SequencedCollection { * @throws IndexOutOfBoundsException if the index is out of range * ({@code index < 0 || index > size()}) */ - @SideEffectsOnly("this") @EnsuresNonEmptyIf(result = true, expression = "this") boolean addAll(@GuardSatisfied List this, @IndexOrHigh({"this"}) int index, Collection c); @@ -422,7 +419,7 @@ public interface List extends SequencedCollection { * @see #remove(Object) * @see #contains(Object) */ - boolean removeAll(@GuardSatisfied List this, Collection c); + boolean removeAll(@GuardSatisfied @Shrinkable List this, Collection c); /** * Retains only the elements in this list that are contained in the @@ -444,7 +441,7 @@ public interface List extends SequencedCollection { * @see #remove(Object) * @see #contains(Object) */ - boolean retainAll(@GuardSatisfied List this, Collection c); + boolean retainAll(@GuardSatisfied @Shrinkable List this, Collection c); /** * Replaces each element of this list with the result of applying the @@ -560,7 +557,7 @@ default void sort(@Nullable Comparator c) { * @throws UnsupportedOperationException if the {@code clear} operation * is not supported by this list */ - void clear(@GuardSatisfied List this); + void clear(@GuardSatisfied @Shrinkable List this); // Comparison and hashing @@ -656,7 +653,6 @@ default void sort(@Nullable Comparator c) { * ({@code index < 0 || index > size()}) */ @ReleasesNoLocks - @SideEffectsOnly("this") void add(@GuardSatisfied List this, @IndexOrHigh({"this"}) int index, E element); /** @@ -673,7 +669,7 @@ default void sort(@Nullable Comparator c) { * ({@code index < 0 || index >= size()}) */ @ReleasesNoLocks - E remove(@GuardSatisfied List this, @IndexFor({"this"}) int index); + E remove(@GuardSatisfied @Shrinkable List this, @IndexFor({"this"}) int index); // Search Operations @@ -728,7 +724,7 @@ default void sort(@Nullable Comparator c) { * @return a list iterator over the elements in this list (in proper * sequence) */ - ListIterator listIterator(); + @PolyGrowShrink @PolyNonEmpty ListIterator listIterator(@PolyGrowShrink @PolyNonEmpty List this); /** * Returns a list iterator over the elements in this list (in proper @@ -745,7 +741,7 @@ default void sort(@Nullable Comparator c) { * @throws IndexOutOfBoundsException if the index is out of range * ({@code index < 0 || index > size()}) */ - ListIterator listIterator(@IndexOrHigh({"this"}) int index); + @PolyGrowShrink @PolyNonEmpty ListIterator listIterator(@PolyGrowShrink @PolyNonEmpty List this, @IndexOrHigh({"this"}) int index); // View @@ -784,7 +780,7 @@ default void sort(@Nullable Comparator c) { * fromIndex > toIndex}) */ @SideEffectFree - List subList(@GuardSatisfied List this, @IndexOrHigh({"this"}) int fromIndex, @IndexOrHigh({"this"}) int toIndex); + @PolyGrowShrink List subList(@GuardSatisfied @PolyGrowShrink List this, @IndexOrHigh({"this"}) int fromIndex, @IndexOrHigh({"this"}) int toIndex); /** * Creates a {@link Spliterator} over the elements in this list. diff --git a/src/java.base/share/classes/java/util/ListIterator.java b/src/java.base/share/classes/java/util/ListIterator.java index b0202663da6..3330d98ce20 100644 --- a/src/java.base/share/classes/java/util/ListIterator.java +++ b/src/java.base/share/classes/java/util/ListIterator.java @@ -31,8 +31,8 @@ import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; +import org.checkerframework.framework.qual.CFComment; /** * An iterator for lists that allows the programmer @@ -81,7 +81,7 @@ public interface ListIterator extends Iterator { * @return {@code true} if the list iterator has more elements when * traversing the list in the forward direction */ - @Pure // @Pure is not necessary here: it's inherited from Iterator + @CFComment({"@Pure is not necessary here, because it's inherited from Iterator"}) @EnsuresNonEmptyIf(result = true, expression = "this") boolean hasNext(); @@ -95,7 +95,6 @@ public interface ListIterator extends Iterator { * @return the next element in the list * @throws NoSuchElementException if the iteration has no next element */ - @SideEffectsOnly("this") E next(@GuardSatisfied @NonEmpty ListIterator this); /** diff --git a/src/java.base/share/classes/java/util/Map.java b/src/java.base/share/classes/java/util/Map.java index 89c4cb19d0b..2471e750925 100644 --- a/src/java.base/share/classes/java/util/Map.java +++ b/src/java.base/share/classes/java/util/Map.java @@ -933,7 +933,7 @@ default void replaceAll(BiFunction function) */ @CFComment("nullness: key and value are not @Nullable because this map might not permit null values") default boolean remove(@GuardSatisfied @UnknownSignedness Object key, @GuardSatisfied @UnknownSignedness Object value) { - Object curValue = (key); + Object curValue = get(key); if (!Objects.equals(curValue, value) || (curValue == null && !containsKey(key))) { return false; @@ -1189,8 +1189,8 @@ default boolean replace(K key, V oldValue, V newValue) { * ({@linkplain Collection##optional-restrictions optional}) * @since 1.8 */ - default @PolyNull V computeIfPresent(K key, - BiFunction remappingFunction) { + default @Nullable V computeIfPresent(K key, + BiFunction remappingFunction) { Objects.requireNonNull(remappingFunction); V oldValue; if ((oldValue = get(key)) != null) { @@ -1275,8 +1275,8 @@ default boolean replace(K key, V oldValue, V newValue) { * ({@linkplain Collection##optional-restrictions optional}) * @since 1.8 */ - default @PolyNull V compute(K key, - BiFunction remappingFunction) { + default @Nullable V compute(K key, + BiFunction remappingFunction) { Objects.requireNonNull(remappingFunction); V oldValue = get(key); @@ -1373,8 +1373,8 @@ default boolean replace(K key, V oldValue, V newValue) { * null * @since 1.8 */ - default @PolyNull V merge(K key, @NonNull V value, - BiFunction remappingFunction) { + default @Nullable V merge(K key, @NonNull V value, + BiFunction remappingFunction) { Objects.requireNonNull(remappingFunction); Objects.requireNonNull(value); V oldValue = get(key); diff --git a/src/java.base/share/classes/java/util/MissingResourceException.java b/src/java.base/share/classes/java/util/MissingResourceException.java index 535852a433b..32fdb6c1878 100644 --- a/src/java.base/share/classes/java/util/MissingResourceException.java +++ b/src/java.base/share/classes/java/util/MissingResourceException.java @@ -40,6 +40,9 @@ package java.util; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Signals that a resource is missing. * @see java.lang.Exception @@ -47,6 +50,7 @@ * @author Mark Davis * @since 1.1 */ +@AnnotatedFor({"nullness"}) public class MissingResourceException extends RuntimeException { /** @@ -56,7 +60,7 @@ public class MissingResourceException extends RuntimeException { * @param className the name of the resource class * @param key the key for the missing resource. */ - public MissingResourceException(String s, String className, String key) { + public MissingResourceException(@Nullable String s, String className, String key) { super(s); this.className = className; this.key = key; @@ -80,7 +84,7 @@ public MissingResourceException(String s, String className, String key) { * permitted, and indicates that the cause is nonexistent * or unknown.) */ - MissingResourceException(String message, String className, String key, Throwable cause) { + MissingResourceException(@Nullable String message, String className, String key, @Nullable Throwable cause) { super(message, cause); this.className = className; this.key = key; diff --git a/src/java.base/share/classes/java/util/NavigableSet.java b/src/java.base/share/classes/java/util/NavigableSet.java index 40acb93d33b..3bcdf187920 100644 --- a/src/java.base/share/classes/java/util/NavigableSet.java +++ b/src/java.base/share/classes/java/util/NavigableSet.java @@ -35,7 +35,9 @@ package java.util; +import org.checkerframework.checker.index.qual.PolyGrowShrink; import org.checkerframework.checker.lock.qual.GuardSatisfied; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.SideEffectFree; import org.checkerframework.framework.qual.AnnotatedFor; @@ -174,7 +176,7 @@ public interface NavigableSet extends SortedSet { * @return an iterator over the elements in this set, in ascending order */ @SideEffectFree - Iterator iterator(); + @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty NavigableSet this); /** * Returns a reverse order view of the elements contained in this set. diff --git a/src/java.base/share/classes/java/util/NoSuchElementException.java b/src/java.base/share/classes/java/util/NoSuchElementException.java index 28c20367958..332374c6461 100644 --- a/src/java.base/share/classes/java/util/NoSuchElementException.java +++ b/src/java.base/share/classes/java/util/NoSuchElementException.java @@ -25,6 +25,9 @@ package java.util; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Thrown by various accessor methods to indicate that the element being requested * does not exist. @@ -33,6 +36,7 @@ * @see java.util.Iterator#next() * @since 1.0 */ +@AnnotatedFor({"nullness"}) public class NoSuchElementException extends RuntimeException { @java.io.Serial private static final long serialVersionUID = 6769829250639411880L; @@ -54,7 +58,7 @@ public NoSuchElementException() { * {@link #getCause()} method), or null * @since 15 */ - public NoSuchElementException(String s, Throwable cause) { + public NoSuchElementException(@Nullable String s, @Nullable Throwable cause) { super(s, cause); } @@ -68,7 +72,7 @@ public NoSuchElementException(String s, Throwable cause) { * {@link #getCause()} method) * @since 15 */ - public NoSuchElementException(Throwable cause) { + public NoSuchElementException(@Nullable Throwable cause) { super(cause); } @@ -79,7 +83,7 @@ public NoSuchElementException(Throwable cause) { * * @param s the detail message. */ - public NoSuchElementException(String s) { + public NoSuchElementException(@Nullable String s) { super(s); } } diff --git a/src/java.base/share/classes/java/util/Objects.java b/src/java.base/share/classes/java/util/Objects.java index 41019bc16eb..9544c1cce49 100644 --- a/src/java.base/share/classes/java/util/Objects.java +++ b/src/java.base/share/classes/java/util/Objects.java @@ -279,8 +279,8 @@ public static int compare(@GuardSatisfied @Nullable @UnknownSignedness T a, * @throws NullPointerException if {@code obj} is {@code null} */ @EnsuresNonNull("#1") - @ForceInline @SideEffectFree + @ForceInline public static @NonNull T requireNonNull(@GuardSatisfied @NonNull @UnknownSignedness T obj, @Nullable String message) { if (obj == null) throw new NullPointerException(message); diff --git a/src/java.base/share/classes/java/util/Optional.java b/src/java.base/share/classes/java/util/Optional.java index b047cb36a0a..5a0f6091868 100644 --- a/src/java.base/share/classes/java/util/Optional.java +++ b/src/java.base/share/classes/java/util/Optional.java @@ -216,7 +216,7 @@ public boolean isEmpty() { * {@code null} */ @OptionalEliminator - public void ifPresent(Consumer action) { + public void ifPresent(Consumer action) { if (value != null) { action.accept(value); } @@ -235,7 +235,7 @@ public void ifPresent(Consumer action) { * @since 9 */ @OptionalEliminator - public void ifPresentOrElse(Consumer action, Runnable emptyAction) { + public void ifPresentOrElse(Consumer action, Runnable emptyAction) { if (value != null) { action.accept(value); } else { @@ -255,7 +255,7 @@ public void ifPresentOrElse(Consumer action, Runnable emptyAction) { * @throws NullPointerException if the predicate is {@code null} */ @OptionalPropagator - public Optional filter(Predicate predicate) { + public Optional filter(Predicate predicate) { Objects.requireNonNull(predicate); if (isEmpty()) { return this; @@ -300,7 +300,7 @@ public Optional filter(Predicate predicate) { @CFComment({"@SideEffectFree: the mapper must not have side effects."}) @OptionalPropagator @SideEffectFree - public Optional map(Function mapper) { + public Optional map(Function mapper) { Objects.requireNonNull(mapper); if (isEmpty()) { return empty(); @@ -329,7 +329,7 @@ public Optional map(Function mapper) { * returns a {@code null} result */ @OptionalPropagator - public Optional flatMap(Function> mapper) { + public Optional flatMap(Function> mapper) { Objects.requireNonNull(mapper); if (isEmpty()) { return empty(); @@ -381,7 +381,7 @@ public Optional or(Supplier> supplier) { * @since 9 */ @SideEffectFree - public Stream stream() { + public Stream<@NonNull T> stream() { if (isEmpty()) { return Stream.empty(); } else { diff --git a/src/java.base/share/classes/java/util/PriorityQueue.java b/src/java.base/share/classes/java/util/PriorityQueue.java index 424685eade2..9cd7735b994 100644 --- a/src/java.base/share/classes/java/util/PriorityQueue.java +++ b/src/java.base/share/classes/java/util/PriorityQueue.java @@ -26,7 +26,9 @@ package java.util; import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.index.qual.PolyGrowShrink; import org.checkerframework.checker.index.qual.Positive; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; @@ -39,7 +41,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; @@ -379,7 +380,7 @@ private int indexOf(@GuardSatisfied @Nullable @UnknownSignedness Object o) { * @param o element to be removed from this queue, if present * @return {@code true} if this queue changed as a result of the call */ - public boolean remove(@GuardSatisfied PriorityQueue this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { + public boolean remove(@GuardSatisfied @Shrinkable PriorityQueue this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { int i = indexOf(o); if (i == -1) return false; @@ -394,7 +395,7 @@ public boolean remove(@GuardSatisfied PriorityQueue this, @GuardSatisfied @Nu * * @param o element to be removed from this queue, if present */ - void removeEq(Object o) { + void removeEq(@GuardSatisfied @Shrinkable PriorityQueue this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { final Object[] es = queue; for (int i = 0, n = size; i < n; i++) { if (o == es[i]) { @@ -491,7 +492,7 @@ public boolean contains(@GuardSatisfied PriorityQueue this, @GuardSatisfied @ * @return an iterator over the elements in this queue */ @SideEffectFree - public Iterator iterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty PriorityQueue this) { return new Itr(); } @@ -544,7 +545,6 @@ public boolean hasNext() { (forgetMeNot != null && !forgetMeNot.isEmpty()); } - @SideEffectsOnly("this") public E next(@NonEmpty Itr this) { if (expectedModCount != modCount) throw new ConcurrentModificationException(); @@ -591,7 +591,7 @@ public void remove() { * Removes all of the elements from this priority queue. * The queue will be empty after this call returns. */ - public void clear(@GuardSatisfied PriorityQueue this) { + public void clear(@GuardSatisfied @Shrinkable PriorityQueue this) { modCount++; final Object[] es = queue; for (int i = 0, n = size; i < n; i++) @@ -599,7 +599,7 @@ public void clear(@GuardSatisfied PriorityQueue this) { size = 0; } - public @Nullable E poll(@GuardSatisfied PriorityQueue this) { + public @Nullable E poll(@GuardSatisfied @Shrinkable PriorityQueue this) { final Object[] es; final E result; @@ -631,7 +631,7 @@ public void clear(@GuardSatisfied PriorityQueue this) { * position before i. This fact is used by iterator.remove so as to * avoid missing traversing elements. */ - E removeAt(int i) { + E removeAt(@GuardSatisfied @NonEmpty @Shrinkable PriorityQueue this, int i) { // assert i >= 0 && i < size; final Object[] es = queue; modCount++; @@ -922,7 +922,7 @@ public int characteristics() { /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeIf(Predicate filter) { + public boolean removeIf(@GuardSatisfied @Shrinkable PriorityQueue this, Predicate filter) { Objects.requireNonNull(filter); return bulkRemove(filter); } @@ -930,7 +930,7 @@ public boolean removeIf(Predicate filter) { /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeAll(Collection c) { + public boolean removeAll(@GuardSatisfied @Shrinkable PriorityQueue this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> c.contains(e)); } @@ -938,7 +938,7 @@ public boolean removeAll(Collection c) { /** * @throws NullPointerException {@inheritDoc} */ - public boolean retainAll(Collection c) { + public boolean retainAll(@GuardSatisfied @Shrinkable PriorityQueue this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> !c.contains(e)); } diff --git a/src/java.base/share/classes/java/util/Queue.java b/src/java.base/share/classes/java/util/Queue.java index 0c7343acc26..81af386824e 100644 --- a/src/java.base/share/classes/java/util/Queue.java +++ b/src/java.base/share/classes/java/util/Queue.java @@ -35,6 +35,7 @@ package java.util; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; @@ -194,7 +195,7 @@ public interface Queue extends Collection { * @return the head of this queue * @throws NoSuchElementException if this queue is empty */ - E remove(@GuardSatisfied @NonEmpty Queue this); + E remove(@GuardSatisfied @NonEmpty @Shrinkable Queue this); /** * Retrieves and removes the head of this queue, @@ -202,7 +203,7 @@ public interface Queue extends Collection { * * @return the head of this queue, or {@code null} if this queue is empty */ - @Nullable E poll(@GuardSatisfied Queue this); + @Nullable E poll(@GuardSatisfied @Shrinkable Queue this); /** * Retrieves, but does not remove, the head of this queue. This method @@ -220,7 +221,8 @@ public interface Queue extends Collection { * * @return the head of this queue, or {@code null} if this queue is empty */ - @Nullable E peek(); + @Pure + @Nullable E peek(@GuardSatisfied Queue this); @CFComment("Copied from Collection to make it annotatable") @Pure diff --git a/src/java.base/share/classes/java/util/RegularEnumSet.java b/src/java.base/share/classes/java/util/RegularEnumSet.java index ca26abc0f53..1e1fc49ae02 100644 --- a/src/java.base/share/classes/java/util/RegularEnumSet.java +++ b/src/java.base/share/classes/java/util/RegularEnumSet.java @@ -26,17 +26,18 @@ package java.util; import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.index.qual.PolyGrowShrink; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; /** @@ -87,7 +88,7 @@ void complement() { * * @return an iterator over the elements contained in this set */ - public Iterator iterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty RegularEnumSet this) { return new EnumSetIterator<>(); } @@ -114,7 +115,6 @@ public boolean hasNext() { return unseen != 0; } - @SideEffectsOnly("this") @SuppressWarnings("unchecked") public E next(@NonEmpty EnumSetIterator this) { if (unseen == 0) diff --git a/src/java.base/share/classes/java/util/Scanner.java b/src/java.base/share/classes/java/util/Scanner.java index bf688f497b5..7e1f1b16fda 100644 --- a/src/java.base/share/classes/java/util/Scanner.java +++ b/src/java.base/share/classes/java/util/Scanner.java @@ -39,7 +39,6 @@ import org.checkerframework.common.value.qual.IntRange; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import java.io.*; @@ -1490,7 +1489,6 @@ public boolean hasNext(@GuardSatisfied Scanner this) { * @throws IllegalStateException if this scanner is closed * @see java.util.Iterator */ - @SideEffectsOnly("this") public String next(@GuardSatisfied @NonEmpty Scanner this) { ensureOpen(); clearCaches(); @@ -1553,7 +1551,6 @@ public boolean hasNext(@GuardSatisfied Scanner this, String pattern) { * @throws NoSuchElementException if no such tokens are available * @throws IllegalStateException if this scanner is closed */ - @SideEffectsOnly("this") public String next(@GuardSatisfied @NonEmpty Scanner this, String pattern) { return next(patternCache.forName(pattern)); } @@ -1604,7 +1601,6 @@ public boolean hasNext(@GuardSatisfied Scanner this, Pattern pattern) { * @throws NoSuchElementException if no more tokens are available * @throws IllegalStateException if this scanner is closed */ - @SideEffectsOnly("this") public String next(@GuardSatisfied @NonEmpty Scanner this, Pattern pattern) { ensureOpen(); if (pattern == null) @@ -1678,7 +1674,6 @@ public boolean hasNextLine() { * @throws NoSuchElementException if no line was found * @throws IllegalStateException if this scanner is closed */ - @SideEffectsOnly("this") public String nextLine(@GuardSatisfied @NonEmpty Scanner this) { modCount++; if (hasNextPattern == linePattern()) @@ -1928,7 +1923,6 @@ public boolean hasNextBoolean(@GuardSatisfied Scanner this) { * @throws NoSuchElementException if input is exhausted * @throws IllegalStateException if this scanner is closed */ - @SideEffectsOnly("this") public boolean nextBoolean(@GuardSatisfied @NonEmpty Scanner this) { clearCaches(); return Boolean.parseBoolean(next(boolPattern())); @@ -1995,7 +1989,6 @@ public boolean hasNextByte(@GuardSatisfied Scanner this, @Positive @IntRange(fro * @throws NoSuchElementException if input is exhausted * @throws IllegalStateException if this scanner is closed */ - @SideEffectsOnly("this") public @PolySigned byte nextByte(@GuardSatisfied @NonEmpty Scanner this) { return nextByte(defaultRadix); } @@ -2031,7 +2024,6 @@ public boolean hasNextByte(@GuardSatisfied Scanner this, @Positive @IntRange(fro * @throws IllegalStateException if this scanner is closed * @throws IllegalArgumentException if the radix is out of range */ - @SideEffectsOnly("this") public @PolySigned byte nextByte(@GuardSatisfied @NonEmpty Scanner this, @Positive @IntRange(from = 2, to = 36) int radix) { // Check cached result if ((typeCache != null) && (typeCache instanceof Byte) @@ -2115,7 +2107,6 @@ public boolean hasNextShort(@GuardSatisfied Scanner this, @Positive @IntRange(fr * @throws NoSuchElementException if input is exhausted * @throws IllegalStateException if this scanner is closed */ - @SideEffectsOnly("this") public @PolySigned short nextShort(@GuardSatisfied @NonEmpty Scanner this) { return nextShort(defaultRadix); } @@ -2151,7 +2142,6 @@ public boolean hasNextShort(@GuardSatisfied Scanner this, @Positive @IntRange(fr * @throws IllegalStateException if this scanner is closed * @throws IllegalArgumentException if the radix is out of range */ - @SideEffectsOnly("this") public @PolySigned short nextShort(@GuardSatisfied @NonEmpty Scanner this, @Positive @IntRange(from = 2, to = 36) int radix) { // Check cached result if ((typeCache != null) && (typeCache instanceof Short) @@ -2259,7 +2249,6 @@ private String processIntegerToken(String token) { * @throws NoSuchElementException if input is exhausted * @throws IllegalStateException if this scanner is closed */ - @SideEffectsOnly("this") public @PolySigned int nextInt(@GuardSatisfied @NonEmpty Scanner this) { return nextInt(defaultRadix); } @@ -2295,7 +2284,6 @@ private String processIntegerToken(String token) { * @throws IllegalStateException if this scanner is closed * @throws IllegalArgumentException if the radix is out of range */ - @SideEffectsOnly("this") public @PolySigned int nextInt(@GuardSatisfied @NonEmpty Scanner this, @Positive @IntRange(from = 2, to = 36) int radix) { // Check cached result if ((typeCache != null) && (typeCache instanceof Integer) @@ -2379,7 +2367,6 @@ public boolean hasNextLong(@GuardSatisfied Scanner this, @Positive @IntRange(fro * @throws NoSuchElementException if input is exhausted * @throws IllegalStateException if this scanner is closed */ - @SideEffectsOnly("this") public @PolySigned long nextLong(@GuardSatisfied @NonEmpty Scanner this) { return nextLong(defaultRadix); } @@ -2415,7 +2402,6 @@ public boolean hasNextLong(@GuardSatisfied Scanner this, @Positive @IntRange(fro * @throws IllegalStateException if this scanner is closed * @throws IllegalArgumentException if the radix is out of range */ - @SideEffectsOnly("this") public @PolySigned long nextLong(@GuardSatisfied @NonEmpty Scanner this, @Positive @IntRange(from = 2, to = 36) int radix) { // Check cached result if ((typeCache != null) && (typeCache instanceof Long) @@ -2541,7 +2527,6 @@ public boolean hasNextFloat(@GuardSatisfied Scanner this) { * @throws NoSuchElementException if input is exhausted * @throws IllegalStateException if this scanner is closed */ - @SideEffectsOnly("this") public float nextFloat(@GuardSatisfied @NonEmpty Scanner this) { // Check cached result if ((typeCache != null) && (typeCache instanceof Float)) { @@ -2610,7 +2595,6 @@ public boolean hasNextDouble(@GuardSatisfied Scanner this) { * @throws NoSuchElementException if the input is exhausted * @throws IllegalStateException if this scanner is closed */ - @SideEffectsOnly("this") public double nextDouble(@GuardSatisfied @NonEmpty Scanner this) { // Check cached result if ((typeCache != null) && (typeCache instanceof Double)) { @@ -2695,7 +2679,6 @@ public boolean hasNextBigInteger(@GuardSatisfied Scanner this, @IntRange(from = * @throws NoSuchElementException if the input is exhausted * @throws IllegalStateException if this scanner is closed */ - @SideEffectsOnly("this") public BigInteger nextBigInteger(@GuardSatisfied @NonEmpty Scanner this) { return nextBigInteger(defaultRadix); } @@ -2726,7 +2709,6 @@ public BigInteger nextBigInteger(@GuardSatisfied @NonEmpty Scanner this) { * @throws IllegalStateException if this scanner is closed * @throws IllegalArgumentException if the radix is out of range */ - @SideEffectsOnly("this") public BigInteger nextBigInteger(@GuardSatisfied @NonEmpty Scanner this, @IntRange(from = 2, to = 36) int radix) { // Check cached result if ((typeCache != null) && (typeCache instanceof BigInteger val) @@ -2793,7 +2775,6 @@ public boolean hasNextBigDecimal(@GuardSatisfied Scanner this) { * @throws NoSuchElementException if the input is exhausted * @throws IllegalStateException if this scanner is closed */ - @SideEffectsOnly("this") public BigDecimal nextBigDecimal(@GuardSatisfied @NonEmpty Scanner this) { // Check cached result if ((typeCache != null) && (typeCache instanceof BigDecimal val)) { diff --git a/src/java.base/share/classes/java/util/ServiceConfigurationError.java b/src/java.base/share/classes/java/util/ServiceConfigurationError.java index 0645f00d125..bdd012e9723 100644 --- a/src/java.base/share/classes/java/util/ServiceConfigurationError.java +++ b/src/java.base/share/classes/java/util/ServiceConfigurationError.java @@ -25,6 +25,8 @@ package java.util; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; /** * Error thrown when something goes wrong while locating, loading, or @@ -35,6 +37,7 @@ * @see ServiceLoader */ +@AnnotatedFor({"nullness"}) public class ServiceConfigurationError extends Error { @@ -48,7 +51,7 @@ public class ServiceConfigurationError * @param msg The message, or {@code null} if there is no message * */ - public ServiceConfigurationError(String msg) { + public ServiceConfigurationError(@Nullable String msg) { super(msg); } @@ -60,7 +63,7 @@ public ServiceConfigurationError(String msg) { * @param cause The cause, or {@code null} if the cause is nonexistent * or unknown */ - public ServiceConfigurationError(String msg, Throwable cause) { + public ServiceConfigurationError(@Nullable String msg, @Nullable Throwable cause) { super(msg, cause); } diff --git a/src/java.base/share/classes/java/util/ServiceLoader.java b/src/java.base/share/classes/java/util/ServiceLoader.java index f8574ad10e6..fb2c7cf1077 100644 --- a/src/java.base/share/classes/java/util/ServiceLoader.java +++ b/src/java.base/share/classes/java/util/ServiceLoader.java @@ -32,7 +32,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import java.io.BufferedReader; @@ -978,7 +977,6 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") public Provider next(@NonEmpty LayerLookupIterator this) { if (!hasNext()) throw new NoSuchElementException(); @@ -1299,7 +1297,6 @@ public boolean hasNext() { @SuppressWarnings("removal") @Override - @SideEffectsOnly("this") public Provider next(@NonEmpty LazyClassPathLookupIterator this) { if (acc == null) { return nextService(); @@ -1330,7 +1327,6 @@ public boolean hasNext() { return (first.hasNext() || second.hasNext()); } @Override - @SideEffectsOnly("this") public Provider next(/*@NonEmpty Iterator> this*/) { if (first.hasNext()) { return first.next(); @@ -1419,7 +1415,6 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") public S next(/*@NonEmpty Iterator this*/) { checkReloadCount(); S next; diff --git a/src/java.base/share/classes/java/util/Set.java b/src/java.base/share/classes/java/util/Set.java index d2e6f5c7847..914bfe89d5d 100644 --- a/src/java.base/share/classes/java/util/Set.java +++ b/src/java.base/share/classes/java/util/Set.java @@ -26,6 +26,7 @@ package java.util; import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.index.qual.PolyGrowShrink; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; @@ -178,7 +179,7 @@ public interface Set extends Collection { * @return an iterator over the elements in this set */ @SideEffectFree - @PolyNonEmpty Iterator iterator(@PolyNonEmpty Set this); + @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty Set this); /** * Returns an array containing all of the elements in this set. diff --git a/src/java.base/share/classes/java/util/Spliterators.java b/src/java.base/share/classes/java/util/Spliterators.java index 63a5d699f44..945746a1d20 100644 --- a/src/java.base/share/classes/java/util/Spliterators.java +++ b/src/java.base/share/classes/java/util/Spliterators.java @@ -28,7 +28,6 @@ import org.checkerframework.checker.nonempty.qual.NonEmpty; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.util.function.Consumer; import java.util.function.DoubleConsumer; import java.util.function.IntConsumer; @@ -699,7 +698,6 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") public T next(@NonEmpty Adapter this) { if (!valueReady && !hasNext()) throw new NoSuchElementException(); @@ -761,7 +759,6 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") public int nextInt(@NonEmpty Adapter this) { if (!valueReady && !hasNext()) throw new NoSuchElementException(); @@ -819,7 +816,6 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") public long nextLong(@NonEmpty Adapter this) { if (!valueReady && !hasNext()) throw new NoSuchElementException(); @@ -877,7 +873,6 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") public double nextDouble(@NonEmpty Adapter this) { if (!valueReady && !hasNext()) throw new NoSuchElementException(); diff --git a/src/java.base/share/classes/java/util/Stack.java b/src/java.base/share/classes/java/util/Stack.java index 4a735f9d0b4..5b6363abafe 100644 --- a/src/java.base/share/classes/java/util/Stack.java +++ b/src/java.base/share/classes/java/util/Stack.java @@ -25,8 +25,10 @@ package java.util; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; +import org.checkerframework.checker.nonempty.qual.NonEmpty; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; import org.checkerframework.framework.qual.AnnotatedFor; @@ -87,7 +89,7 @@ public E push(@GuardSatisfied Stack this, E item) { * of the {@code Vector} object). * @throws EmptyStackException if this stack is empty. */ - public synchronized E pop(@GuardSatisfied Stack this) { + public synchronized E pop(@GuardSatisfied @NonEmpty @Shrinkable Stack this) { E obj; int len = size(); diff --git a/src/java.base/share/classes/java/util/TreeMap.java b/src/java.base/share/classes/java/util/TreeMap.java index 337676c1856..f153893f594 100644 --- a/src/java.base/share/classes/java/util/TreeMap.java +++ b/src/java.base/share/classes/java/util/TreeMap.java @@ -39,7 +39,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; @@ -1568,7 +1567,6 @@ public final boolean hasNext() { return next != null; } - @SideEffectsOnly("this") final Entry nextEntry() { Entry e = next; if (e == null) @@ -1580,7 +1578,6 @@ final Entry nextEntry() { return e; } - @SideEffectsOnly("this") final Entry prevEntry() { Entry e = next; if (e == null) @@ -2118,7 +2115,6 @@ public final boolean hasNext() { return next != null && next.key != fenceKey; } - @SideEffectsOnly("this") final TreeMap.Entry nextEntry() { TreeMap.Entry e = next; if (e == null || e.key == fenceKey) @@ -2130,7 +2126,6 @@ final TreeMap.Entry nextEntry() { return e; } - @SideEffectsOnly("this") final TreeMap.Entry prevEntry() { TreeMap.Entry e = next; if (e == null || e.key == fenceKey) diff --git a/src/java.base/share/classes/java/util/TreeSet.java b/src/java.base/share/classes/java/util/TreeSet.java index 26e036f243d..b4770fab88f 100644 --- a/src/java.base/share/classes/java/util/TreeSet.java +++ b/src/java.base/share/classes/java/util/TreeSet.java @@ -26,6 +26,7 @@ package java.util; import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.index.qual.PolyGrowShrink; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; @@ -198,7 +199,7 @@ public TreeSet(@Nullable Comparator comparator) { * @return an iterator over the elements in this set in ascending order */ @SideEffectFree - public @PolyNonEmpty Iterator iterator(@PolyNonEmpty TreeSet this) { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty TreeSet this) { return m.navigableKeySet().iterator(); } @@ -208,7 +209,7 @@ public TreeSet(@Nullable Comparator comparator) { * @return an iterator over the elements in this set in descending order * @since 1.6 */ - public @PolyNonEmpty Iterator descendingIterator(@PolyNonEmpty TreeSet this) { + public @PolyGrowShrink @PolyNonEmpty Iterator descendingIterator(@PolyGrowShrink @PolyNonEmpty TreeSet this) { return m.descendingKeySet().iterator(); } @@ -346,7 +347,7 @@ public boolean addAll(@GuardSatisfied TreeSet this, Collection * @since 1.6 */ @SideEffectFree - public NavigableSet subSet(@GuardSatisfied TreeSet this, @GuardSatisfied E fromElement, boolean fromInclusive, + public @PolyGrowShrink NavigableSet subSet(@GuardSatisfied @PolyGrowShrink TreeSet this, @GuardSatisfied E fromElement, boolean fromInclusive, @GuardSatisfied E toElement, boolean toInclusive) { return new TreeSet<>(m.subMap(fromElement, fromInclusive, toElement, toInclusive)); @@ -361,7 +362,7 @@ public NavigableSet subSet(@GuardSatisfied TreeSet this, @GuardSatisfied E * @since 1.6 */ @SideEffectFree - public NavigableSet headSet(@GuardSatisfied TreeSet this, @GuardSatisfied E toElement, boolean inclusive) { + public @PolyGrowShrink NavigableSet headSet(@GuardSatisfied @PolyGrowShrink TreeSet this, @GuardSatisfied E toElement, boolean inclusive) { return new TreeSet<>(m.headMap(toElement, inclusive)); } @@ -374,7 +375,7 @@ public NavigableSet headSet(@GuardSatisfied TreeSet this, @GuardSatisfied * @since 1.6 */ @SideEffectFree - public NavigableSet tailSet(@GuardSatisfied TreeSet this, @GuardSatisfied E fromElement, boolean inclusive) { + public @PolyGrowShrink NavigableSet tailSet(@GuardSatisfied @PolyGrowShrink TreeSet this, @GuardSatisfied E fromElement, boolean inclusive) { return new TreeSet<>(m.tailMap(fromElement, inclusive)); } @@ -386,7 +387,7 @@ public NavigableSet tailSet(@GuardSatisfied TreeSet this, @GuardSatisfied * @throws IllegalArgumentException {@inheritDoc} */ @SideEffectFree - public SortedSet subSet(@GuardSatisfied TreeSet this, @GuardSatisfied E fromElement, @GuardSatisfied E toElement) { + public @PolyGrowShrink SortedSet subSet(@GuardSatisfied @PolyGrowShrink TreeSet this, @GuardSatisfied E fromElement, @GuardSatisfied E toElement) { return subSet(fromElement, true, toElement, false); } @@ -398,7 +399,7 @@ public SortedSet subSet(@GuardSatisfied TreeSet this, @GuardSatisfied E fr * @throws IllegalArgumentException {@inheritDoc} */ @SideEffectFree - public SortedSet headSet(@GuardSatisfied TreeSet this, E toElement) { + public @PolyGrowShrink SortedSet headSet(@GuardSatisfied @PolyGrowShrink TreeSet this, E toElement) { return headSet(toElement, false); } @@ -410,7 +411,7 @@ public SortedSet headSet(@GuardSatisfied TreeSet this, E toElement) { * @throws IllegalArgumentException {@inheritDoc} */ @SideEffectFree - public SortedSet tailSet(@GuardSatisfied TreeSet this, E fromElement) { + public @PolyGrowShrink SortedSet tailSet(@GuardSatisfied @PolyGrowShrink TreeSet this, E fromElement) { return tailSet(fromElement, true); } diff --git a/src/java.base/share/classes/java/util/Vector.java b/src/java.base/share/classes/java/util/Vector.java index d7bd79fb888..f6a71faefe2 100644 --- a/src/java.base/share/classes/java/util/Vector.java +++ b/src/java.base/share/classes/java/util/Vector.java @@ -27,6 +27,8 @@ import org.checkerframework.checker.index.qual.GTENegativeOne; import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; @@ -38,7 +40,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; @@ -294,7 +295,7 @@ private Object[] grow() { * @param newSize the new size of this vector * @throws ArrayIndexOutOfBoundsException if the new size is negative */ - public synchronized void setSize(@GuardSatisfied Vector this, @NonNegative int newSize) { + public synchronized void setSize(@GuardSatisfied @Shrinkable Vector this, @NonNegative int newSize) { modCount++; if (newSize > elementData.length) grow(newSize); @@ -349,7 +350,7 @@ public synchronized boolean isEmpty(@GuardSatisfied Vector this) { * @return an enumeration of the components of this vector * @see Iterator */ - public Enumeration elements() { + public @PolyGrowShrink @PolyNonEmpty Enumeration elements(@PolyGrowShrink @PolyNonEmpty Vector this) { return new Enumeration() { int count = 0; @@ -573,7 +574,7 @@ public synchronized void setElementAt(@GuardSatisfied Vector this, E obj, @No * @throws ArrayIndexOutOfBoundsException if the index is out of range * ({@code index < 0 || index >= size()}) */ - public synchronized void removeElementAt(@GuardSatisfied Vector this, @NonNegative int index) { + public synchronized void removeElementAt(@GuardSatisfied @Shrinkable Vector this, @NonNegative int index) { if (index >= elementCount) { throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); @@ -661,7 +662,7 @@ public synchronized void addElement(@GuardSatisfied Vector this, E obj) { * @return {@code true} if the argument was a component of this * vector; {@code false} otherwise. */ - public synchronized boolean removeElement(@GuardSatisfied Vector this, Object obj) { + public synchronized boolean removeElement(@GuardSatisfied @Shrinkable Vector this, Object obj) { modCount++; int i = indexOf(obj); if (i >= 0) { @@ -677,7 +678,7 @@ public synchronized boolean removeElement(@GuardSatisfied Vector this, Object *

This method is identical in functionality to the {@link #clear} * method (which is part of the {@link List} interface). */ - public synchronized void removeAllElements(@GuardSatisfied Vector this) { + public synchronized void removeAllElements(@GuardSatisfied @Shrinkable Vector this) { final Object[] es = elementData; for (int to = elementCount, i = elementCount = 0; i < to; i++) es[i] = null; @@ -824,7 +825,6 @@ private void add(E e, Object[] elementData, int s) { * @return {@code true} (as specified by {@link Collection#add}) * @since 1.2 */ - @SideEffectsOnly("this") @EnsuresNonEmpty("this") public synchronized boolean add(@GuardSatisfied Vector this, E e) { modCount++; @@ -843,7 +843,7 @@ public synchronized boolean add(@GuardSatisfied Vector this, E e) { * @return true if the Vector contained the specified element * @since 1.2 */ - public boolean remove(@GuardSatisfied Vector this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { + public boolean remove(@GuardSatisfied @Shrinkable Vector this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { return removeElement(o); } @@ -873,7 +873,7 @@ public void add(@GuardSatisfied Vector this, @NonNegative int index, E elemen * ({@code index < 0 || index >= size()}) * @since 1.2 */ - public synchronized E remove(@GuardSatisfied Vector this, @NonNegative int index) { + public synchronized E remove(@GuardSatisfied @Shrinkable Vector this, @NonNegative int index) { modCount++; if (index >= elementCount) throw new ArrayIndexOutOfBoundsException(index); @@ -894,7 +894,7 @@ public synchronized E remove(@GuardSatisfied Vector this, @NonNegative int in * * @since 1.2 */ - public void clear(@GuardSatisfied Vector this) { + public void clear(@GuardSatisfied @Shrinkable Vector this) { removeAllElements(); } @@ -962,7 +962,7 @@ public boolean addAll(@GuardSatisfied Vector this, Collection c) * or if the specified collection is null * @since 1.2 */ - public boolean removeAll(@GuardSatisfied Vector this, Collection c) { + public boolean removeAll(@GuardSatisfied @Shrinkable Vector this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> c.contains(e)); } @@ -986,7 +986,7 @@ public boolean removeAll(@GuardSatisfied Vector this, Collection this, Collection c) { + public boolean retainAll(@GuardSatisfied @Shrinkable Vector this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> !c.contains(e)); } @@ -996,7 +996,7 @@ public boolean retainAll(@GuardSatisfied Vector this, Collection filter) { + public boolean removeIf(@Shrinkable Vector this, Predicate filter) { Objects.requireNonNull(filter); return bulkRemove(filter); } @@ -1158,7 +1158,7 @@ public synchronized String toString(@GuardSatisfied Vector this) { * {@code (fromIndex > toIndex)} */ @SideEffectFree - public synchronized List subList(@GuardSatisfied Vector this, int fromIndex, int toIndex) { + public synchronized @PolyGrowShrink List subList(@GuardSatisfied @PolyGrowShrink Vector this, int fromIndex, int toIndex) { return Collections.synchronizedList(super.subList(fromIndex, toIndex), this); } @@ -1170,7 +1170,7 @@ public synchronized List subList(@GuardSatisfied Vector this, int fromInde * This call shortens the list by {@code (toIndex - fromIndex)} elements. * (If {@code toIndex==fromIndex}, this operation has no effect.) */ - protected synchronized void removeRange(int fromIndex, int toIndex) { + protected synchronized void removeRange(@GuardSatisfied @Shrinkable Vector this, int fromIndex, int toIndex) { modCount++; shiftTailOverGap(elementData, fromIndex, toIndex); } @@ -1241,7 +1241,7 @@ private void writeObject(java.io.ObjectOutputStream s) * * @throws IndexOutOfBoundsException {@inheritDoc} */ - public synchronized ListIterator listIterator(@NonNegative int index) { + public synchronized @PolyGrowShrink ListIterator listIterator(@PolyGrowShrink Vector this, @NonNegative int index) { if (index < 0 || index > elementCount) throw new IndexOutOfBoundsException("Index: "+index); return new ListItr(index); @@ -1255,7 +1255,7 @@ public synchronized ListIterator listIterator(@NonNegative int index) { * * @see #listIterator(int) */ - public synchronized ListIterator listIterator() { + public synchronized @PolyGrowShrink @PolyNonEmpty ListIterator listIterator(@PolyGrowShrink Vector this) { return new ListItr(0); } @@ -1267,7 +1267,7 @@ public synchronized ListIterator listIterator() { * @return an iterator over the elements in this list in proper sequence */ @SideEffectFree - public synchronized Iterator iterator() { + public synchronized @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty Vector this) { return new Itr(); } @@ -1287,7 +1287,6 @@ public boolean hasNext() { return cursor != elementCount; } - @SideEffectsOnly("this") public E next(@NonEmpty Itr this) { synchronized (Vector.this) { checkForComodification(); diff --git a/src/java.base/share/classes/java/util/WeakHashMap.java b/src/java.base/share/classes/java/util/WeakHashMap.java index 0bf358ec1f6..1a403a8a56c 100644 --- a/src/java.base/share/classes/java/util/WeakHashMap.java +++ b/src/java.base/share/classes/java/util/WeakHashMap.java @@ -38,7 +38,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; @@ -839,7 +838,6 @@ public boolean hasNext() { } /** The common parts of next() across different types of iterators */ - @SideEffectsOnly("this") protected Entry nextEntry() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); diff --git a/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java b/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java index b3fba4e2da2..900c6a41c7c 100644 --- a/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java @@ -35,17 +35,19 @@ package java.util.concurrent; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.PolyNull; import org.checkerframework.checker.signedness.qual.PolySigned; import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import java.lang.ref.WeakReference; @@ -417,7 +419,7 @@ public boolean offer(E e, long timeout, TimeUnit unit) } } - public @Nullable E poll() { + public @Nullable E poll(@GuardSatisfied @Shrinkable ArrayBlockingQueue this) { final ReentrantLock lock = this.lock; lock.lock(); try { @@ -427,7 +429,7 @@ public boolean offer(E e, long timeout, TimeUnit unit) } } - public E take() throws InterruptedException { + public E take(@GuardSatisfied @Shrinkable ArrayBlockingQueue this) throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { @@ -439,7 +441,7 @@ public E take() throws InterruptedException { } } - public @Nullable E poll(long timeout, TimeUnit unit) throws InterruptedException { + public @Nullable E poll(@GuardSatisfied @Shrinkable ArrayBlockingQueue this, long timeout, TimeUnit unit) throws InterruptedException { long nanos = unit.toNanos(timeout); final ReentrantLock lock = this.lock; lock.lockInterruptibly(); @@ -524,7 +526,7 @@ public int remainingCapacity() { * @param o element to be removed from this queue, if present * @return {@code true} if this queue changed as a result of the call */ - public boolean remove(@GuardSatisfied @Nullable @UnknownSignedness Object o) { + public boolean remove(@Shrinkable ArrayBlockingQueue this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { if (o == null) return false; final ReentrantLock lock = this.lock; lock.lock(); @@ -675,7 +677,7 @@ public String toString() { * Atomically removes all of the elements from this queue. * The queue will be empty after this call returns. */ - public void clear() { + public void clear(@GuardSatisfied @Shrinkable ArrayBlockingQueue this) { final ReentrantLock lock = this.lock; lock.lock(); try { @@ -714,7 +716,7 @@ private static void circularClear(Object[] items, int i, int end) { * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ - public int drainTo(Collection c) { + public int drainTo(@GuardSatisfied @Shrinkable ArrayBlockingQueue this, Collection c) { return drainTo(c, Integer.MAX_VALUE); } @@ -724,7 +726,7 @@ public int drainTo(Collection c) { * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ - public int drainTo(Collection c, int maxElements) { + public int drainTo(@GuardSatisfied @Shrinkable ArrayBlockingQueue this, Collection c, int maxElements) { Objects.requireNonNull(c); if (c == this) throw new IllegalArgumentException(); @@ -776,7 +778,7 @@ else if (i > take) * * @return an iterator over the elements in this queue in proper sequence */ - public Iterator iterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty ArrayBlockingQueue this) { return new Itr(); } @@ -1230,7 +1232,6 @@ private void noNext() { } } - @SideEffectsOnly("this") public E next(@NonEmpty Itr this) { final E e = nextItem; if (e == null) @@ -1490,7 +1491,7 @@ public void forEach(Consumer action) { /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeIf(Predicate filter) { + public boolean removeIf(@Shrinkable ArrayBlockingQueue this, Predicate filter) { Objects.requireNonNull(filter); return bulkRemove(filter); } @@ -1498,7 +1499,7 @@ public boolean removeIf(Predicate filter) { /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeAll(Collection c) { + public boolean removeAll(@Shrinkable ArrayBlockingQueue this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> c.contains(e)); } @@ -1506,7 +1507,7 @@ public boolean removeAll(Collection c) { + public boolean retainAll(@GuardSatisfied @Shrinkable ArrayBlockingQueue this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> !c.contains(e)); } diff --git a/src/java.base/share/classes/java/util/concurrent/BlockingDeque.java b/src/java.base/share/classes/java/util/concurrent/BlockingDeque.java index 2180e76e280..6356ee6d378 100644 --- a/src/java.base/share/classes/java/util/concurrent/BlockingDeque.java +++ b/src/java.base/share/classes/java/util/concurrent/BlockingDeque.java @@ -35,9 +35,13 @@ package java.util.concurrent; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; +import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.signedness.qual.UnknownSignedness; @@ -355,7 +359,7 @@ boolean offerLast(E e, long timeout, TimeUnit unit) * @return the head of this deque * @throws InterruptedException if interrupted while waiting */ - E takeFirst() throws InterruptedException; + E takeFirst(@Shrinkable BlockingDeque this) throws InterruptedException; /** * Retrieves and removes the last element of this deque, waiting @@ -364,7 +368,7 @@ boolean offerLast(E e, long timeout, TimeUnit unit) * @return the tail of this deque * @throws InterruptedException if interrupted while waiting */ - E takeLast() throws InterruptedException; + E takeLast(@Shrinkable BlockingDeque this) throws InterruptedException; /** * Retrieves and removes the first element of this deque, waiting @@ -379,7 +383,7 @@ boolean offerLast(E e, long timeout, TimeUnit unit) * waiting time elapses before an element is available * @throws InterruptedException if interrupted while waiting */ - @Nullable E pollFirst(long timeout, TimeUnit unit) + @Nullable E pollFirst(@Shrinkable BlockingDeque this, long timeout, TimeUnit unit) throws InterruptedException; /** @@ -395,7 +399,7 @@ boolean offerLast(E e, long timeout, TimeUnit unit) * waiting time elapses before an element is available * @throws InterruptedException if interrupted while waiting */ - @Nullable E pollLast(long timeout, TimeUnit unit) + @Nullable E pollLast(@Shrinkable BlockingDeque this, long timeout, TimeUnit unit) throws InterruptedException; /** @@ -414,7 +418,7 @@ boolean offerLast(E e, long timeout, TimeUnit unit) * @throws NullPointerException if the specified element is null * (optional) */ - boolean removeFirstOccurrence(Object o); + boolean removeFirstOccurrence(@Shrinkable BlockingDeque this, Object o); /** * Removes the last occurrence of the specified element from this deque. @@ -432,7 +436,7 @@ boolean offerLast(E e, long timeout, TimeUnit unit) * @throws NullPointerException if the specified element is null * (optional) */ - boolean removeLastOccurrence(Object o); + boolean removeLastOccurrence(@Shrinkable BlockingDeque this, Object o); // *** BlockingQueue methods *** @@ -527,7 +531,7 @@ boolean offer(E e, long timeout, TimeUnit unit) * @return the head of the queue represented by this deque * @throws NoSuchElementException if this deque is empty */ - E remove(@NonEmpty BlockingDeque this); + E remove(@GuardSatisfied @NonEmpty @Shrinkable BlockingDeque this); /** * Retrieves and removes the head of the queue represented by this deque @@ -538,7 +542,7 @@ boolean offer(E e, long timeout, TimeUnit unit) * * @return the head of this deque, or {@code null} if this deque is empty */ - @Nullable E poll(); + @Nullable E poll(@Shrinkable BlockingDeque this); /** * Retrieves and removes the head of the queue represented by this deque @@ -550,7 +554,7 @@ boolean offer(E e, long timeout, TimeUnit unit) * @return the head of this deque * @throws InterruptedException if interrupted while waiting */ - E take() throws InterruptedException; + E take(@Shrinkable BlockingDeque this) throws InterruptedException; /** * Retrieves and removes the head of the queue represented by this deque @@ -564,7 +568,7 @@ boolean offer(E e, long timeout, TimeUnit unit) * specified waiting time elapses before an element is available * @throws InterruptedException if interrupted while waiting */ - @Nullable E poll(long timeout, TimeUnit unit) + @Nullable E poll(@Shrinkable BlockingDeque this, long timeout, TimeUnit unit) throws InterruptedException; /** @@ -589,6 +593,7 @@ boolean offer(E e, long timeout, TimeUnit unit) * * @return the head of this deque, or {@code null} if this deque is empty */ + @Pure @Nullable E peek(); /** @@ -610,7 +615,7 @@ boolean offer(E e, long timeout, TimeUnit unit) * @throws NullPointerException if the specified element is null * (optional) */ - boolean remove(@UnknownSignedness Object o); + boolean remove(@Shrinkable BlockingDeque this, @UnknownSignedness Object o); /** * Returns {@code true} if this deque contains the specified element. @@ -644,7 +649,7 @@ boolean offer(E e, long timeout, TimeUnit unit) * @return an iterator over the elements in this deque in proper sequence */ @SideEffectFree - Iterator iterator(); + @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty BlockingDeque this); // *** Stack methods *** diff --git a/src/java.base/share/classes/java/util/concurrent/BlockingQueue.java b/src/java.base/share/classes/java/util/concurrent/BlockingQueue.java index b4e99d9d203..7ad116a16c3 100644 --- a/src/java.base/share/classes/java/util/concurrent/BlockingQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/BlockingQueue.java @@ -35,6 +35,8 @@ package java.util.concurrent; +import org.checkerframework.checker.index.qual.Shrinkable; +import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; @@ -317,7 +319,7 @@ boolean offer(E e, long timeout, TimeUnit unit) * @throws NullPointerException if the specified element is null * (optional) */ - boolean remove(@UnknownSignedness Object o); + boolean remove(@Shrinkable BlockingQueue this, @UnknownSignedness Object o); /** * Returns {@code true} if this queue contains the specified element. @@ -359,7 +361,7 @@ boolean offer(E e, long timeout, TimeUnit unit) * queue, or some property of an element of this queue prevents * it from being added to the specified collection */ - int drainTo(Collection c); + int drainTo(@GuardSatisfied @Shrinkable BlockingQueue this, Collection c); /** * Removes at most the given number of available elements from @@ -384,5 +386,5 @@ boolean offer(E e, long timeout, TimeUnit unit) * queue, or some property of an element of this queue prevents * it from being added to the specified collection */ - int drainTo(Collection c, int maxElements); + int drainTo(@GuardSatisfied @Shrinkable BlockingQueue this, Collection c, int maxElements); } diff --git a/src/java.base/share/classes/java/util/concurrent/BrokenBarrierException.java b/src/java.base/share/classes/java/util/concurrent/BrokenBarrierException.java index 11f126e015a..fb1e2fa1a97 100644 --- a/src/java.base/share/classes/java/util/concurrent/BrokenBarrierException.java +++ b/src/java.base/share/classes/java/util/concurrent/BrokenBarrierException.java @@ -35,6 +35,9 @@ package java.util.concurrent; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Exception thrown when a thread tries to wait upon a barrier that is * in a broken state, or which enters the broken state while the thread @@ -45,6 +48,7 @@ * @since 1.5 * @author Doug Lea */ +@AnnotatedFor({"nullness"}) public class BrokenBarrierException extends Exception { private static final long serialVersionUID = 7117394618823254244L; @@ -60,7 +64,7 @@ public BrokenBarrierException() {} * * @param message the detail message */ - public BrokenBarrierException(String message) { + public BrokenBarrierException(@Nullable String message) { super(message); } } diff --git a/src/java.base/share/classes/java/util/concurrent/CompletionException.java b/src/java.base/share/classes/java/util/concurrent/CompletionException.java index 2a3cfc56adf..8a076475815 100644 --- a/src/java.base/share/classes/java/util/concurrent/CompletionException.java +++ b/src/java.base/share/classes/java/util/concurrent/CompletionException.java @@ -35,6 +35,9 @@ package java.util.concurrent; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Exception thrown when an error or other exception is encountered * in the course of completing a result or task. @@ -42,6 +45,7 @@ * @since 1.8 * @author Doug Lea */ +@AnnotatedFor({"nullness"}) public class CompletionException extends RuntimeException { private static final long serialVersionUID = 7830266012832686185L; @@ -59,7 +63,7 @@ protected CompletionException() { } * * @param message the detail message */ - protected CompletionException(String message) { + protected CompletionException(@Nullable String message) { super(message); } @@ -71,7 +75,7 @@ protected CompletionException(String message) { * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method) */ - public CompletionException(String message, Throwable cause) { + public CompletionException(@Nullable String message, @Nullable Throwable cause) { super(message, cause); } @@ -84,7 +88,7 @@ public CompletionException(String message, Throwable cause) { * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method) */ - public CompletionException(Throwable cause) { + public CompletionException(@Nullable Throwable cause) { super(cause); } } diff --git a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java index e900a1df368..497c4280834 100644 --- a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java @@ -50,7 +50,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import java.io.ObjectStreamField; diff --git a/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java b/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java index 2d8e66e2300..e5c0c9964c2 100644 --- a/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java @@ -35,10 +35,13 @@ package java.util.concurrent; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -47,7 +50,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import java.lang.invoke.MethodHandles; @@ -928,7 +930,7 @@ public E getLast(@NonEmpty ConcurrentLinkedDeque this) { return screenNullResult(peekLast()); } - public @Nullable E pollFirst() { + public @Nullable E pollFirst(@GuardSatisfied @Shrinkable ConcurrentLinkedDeque this) { restart: for (;;) { for (Node first = first(), p = first;;) { final E item; @@ -949,7 +951,7 @@ public E getLast(@NonEmpty ConcurrentLinkedDeque this) { } } - public @Nullable E pollLast() { + public @Nullable E pollLast(@GuardSatisfied @Shrinkable ConcurrentLinkedDeque this) { restart: for (;;) { for (Node last = last(), p = last;;) { final E item; @@ -973,14 +975,14 @@ public E getLast(@NonEmpty ConcurrentLinkedDeque this) { /** * @throws NoSuchElementException {@inheritDoc} */ - public E removeFirst(@NonEmpty ConcurrentLinkedDeque this) { + public E removeFirst(@GuardSatisfied @NonEmpty @Shrinkable ConcurrentLinkedDeque this) { return screenNullResult(pollFirst()); } /** * @throws NoSuchElementException {@inheritDoc} */ - public E removeLast(@NonEmpty ConcurrentLinkedDeque this) { + public E removeLast(@GuardSatisfied @NonEmpty @Shrinkable ConcurrentLinkedDeque this) { return screenNullResult(pollLast()); } @@ -1010,19 +1012,19 @@ public boolean add(E e) { return offerLast(e); } - public @Nullable E poll() { return pollFirst(); } + public @Nullable E poll(@Shrinkable ConcurrentLinkedDeque this) { return pollFirst(); } @Pure public @Nullable E peek() { return peekFirst(); } /** * @throws NoSuchElementException {@inheritDoc} */ - public E remove(@NonEmpty ConcurrentLinkedDeque this) { return removeFirst(); } + public E remove(@NonEmpty @Shrinkable ConcurrentLinkedDeque this) { return removeFirst(); } /** * @throws NoSuchElementException {@inheritDoc} */ - public E pop(@NonEmpty ConcurrentLinkedDeque this) { return removeFirst(); } + public E pop(@GuardSatisfied @NonEmpty @Shrinkable ConcurrentLinkedDeque this) { return removeFirst(); } /** * @throws NoSuchElementException {@inheritDoc} @@ -1046,7 +1048,7 @@ public boolean add(E e) { * @return {@code true} if the deque contained the specified element * @throws NullPointerException if the specified element is null */ - public boolean removeFirstOccurrence(Object o) { + public boolean removeFirstOccurrence(@Shrinkable ConcurrentLinkedDeque this, Object o) { Objects.requireNonNull(o); for (Node p = first(); p != null; p = succ(p)) { final E item; @@ -1072,7 +1074,7 @@ public boolean removeFirstOccurrence(Object o) { * @return {@code true} if the deque contained the specified element * @throws NullPointerException if the specified element is null */ - public boolean removeLastOccurrence(Object o) { + public boolean removeLastOccurrence(@Shrinkable ConcurrentLinkedDeque this, Object o) { Objects.requireNonNull(o); for (Node p = last(); p != null; p = pred(p)) { final E item; @@ -1164,7 +1166,7 @@ public int size() { * @return {@code true} if the deque contained the specified element * @throws NullPointerException if the specified element is null */ - public boolean remove(@GuardSatisfied @UnknownSignedness Object o) { + public boolean remove(@Shrinkable ConcurrentLinkedDeque this, @GuardSatisfied @UnknownSignedness Object o) { return removeFirstOccurrence(o); } @@ -1234,7 +1236,7 @@ else if (p.prev == p) // NEXT_TERMINATOR /** * Removes all of the elements from this deque. */ - public void clear() { + public void clear(@GuardSatisfied @Shrinkable ConcurrentLinkedDeque this) { while (pollFirst() != null) ; } @@ -1367,7 +1369,7 @@ else if (a != null && size <= a.length) { * @return an iterator over the elements in this deque in proper sequence */ @SideEffectFree - public Iterator iterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty ConcurrentLinkedDeque this) { return new Itr(); } @@ -1381,7 +1383,7 @@ public Iterator iterator() { * * @return an iterator over the elements in this deque in reverse order */ - public Iterator descendingIterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator descendingIterator(@PolyGrowShrink @PolyNonEmpty ConcurrentLinkedDeque this) { return new DescendingItr(); } @@ -1442,7 +1444,6 @@ public boolean hasNext() { return nextItem != null; } - @SideEffectsOnly("this") public E next(@NonEmpty AbstractItr this) { E item = nextItem; if (item == null) throw new NoSuchElementException(); @@ -1635,7 +1636,7 @@ private void readObject(java.io.ObjectInputStream s) /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeIf(Predicate filter) { + public boolean removeIf(@Shrinkable ConcurrentLinkedDeque this, Predicate filter) { Objects.requireNonNull(filter); return bulkRemove(filter); } @@ -1643,7 +1644,7 @@ public boolean removeIf(Predicate filter) { /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeAll(Collection c) { + public boolean removeAll(@Shrinkable ConcurrentLinkedDeque this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> c.contains(e)); } @@ -1651,7 +1652,7 @@ public boolean removeAll(Collection c) { + public boolean retainAll(@GuardSatisfied @Shrinkable ConcurrentLinkedDeque this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> !c.contains(e)); } diff --git a/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java b/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java index a8c029fdd3f..5f8ccec2186 100644 --- a/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java @@ -35,10 +35,13 @@ package java.util.concurrent; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.PolyNull; @@ -46,7 +49,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import java.lang.invoke.MethodHandles; @@ -396,7 +398,7 @@ else if (p == q) } } - public @Nullable E poll() { + public @Nullable E poll(@GuardSatisfied @Shrinkable ConcurrentLinkedQueue this) { restartFromHead: for (;;) { for (Node h = head, p = h, q;; p = q) { final E item; @@ -540,7 +542,7 @@ public boolean contains(@GuardSatisfied @UnknownSignedness Object o) { * @param o element to be removed from this queue, if present * @return {@code true} if this queue changed as a result of the call */ - public boolean remove(@GuardSatisfied @UnknownSignedness Object o) { + public boolean remove(@Shrinkable ConcurrentLinkedQueue this, @GuardSatisfied @UnknownSignedness Object o) { if (o == null) return false; restartFromHead: for (;;) { for (Node p = head, pred = null; p != null; ) { @@ -750,7 +752,7 @@ else if (a != null && size <= a.length) { * @return an iterator over the elements in this queue in proper sequence */ @SideEffectFree - public Iterator iterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty ConcurrentLinkedQueue this) { return new Itr(); } @@ -799,7 +801,6 @@ public boolean hasNext() { return nextItem != null; } - @SideEffectsOnly("this") public E next(@NonEmpty Itr this) { final Node pred = nextNode; if (pred == null) throw new NoSuchElementException(); @@ -988,7 +989,7 @@ public Spliterator spliterator() { /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeIf(Predicate filter) { + public boolean removeIf(@Shrinkable ConcurrentLinkedQueue this, Predicate filter) { Objects.requireNonNull(filter); return bulkRemove(filter); } @@ -996,7 +997,7 @@ public boolean removeIf(Predicate filter) { /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeAll(Collection c) { + public boolean removeAll(@Shrinkable ConcurrentLinkedQueue this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> c.contains(e)); } @@ -1004,12 +1005,12 @@ public boolean removeAll(Collection c) { + public boolean retainAll(@GuardSatisfied @Shrinkable ConcurrentLinkedQueue this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> !c.contains(e)); } - public void clear() { + public void clear(@GuardSatisfied @Shrinkable ConcurrentLinkedQueue this) { bulkRemove(e -> true); } diff --git a/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java index 9920296736f..42d47a97c72 100644 --- a/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java @@ -47,7 +47,6 @@ import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; import org.checkerframework.framework.qual.AnnotatedFor; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; diff --git a/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java index 2c648ebc57d..1e02531ced6 100644 --- a/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java @@ -35,10 +35,12 @@ package java.util.concurrent; +import org.checkerframework.checker.index.qual.PolyGrowShrink; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -294,7 +296,7 @@ public void clear() { * @return an iterator over the elements in this set in ascending order */ @SideEffectFree - public Iterator iterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty ConcurrentSkipListSet this) { return m.navigableKeySet().iterator(); } @@ -303,7 +305,7 @@ public Iterator iterator() { * * @return an iterator over the elements in this set in descending order */ - public Iterator descendingIterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator descendingIterator(@PolyGrowShrink @PolyNonEmpty ConcurrentSkipListSet this) { return m.descendingKeySet().iterator(); } @@ -457,7 +459,7 @@ public void addLast(E e) { * {@code toElement} is null * @throws IllegalArgumentException {@inheritDoc} */ - public NavigableSet subSet(E fromElement, + public @PolyGrowShrink @PolyNonEmpty NavigableSet subSet(@PolyGrowShrink @PolyNonEmpty ConcurrentSkipListSet this, E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { @@ -471,7 +473,7 @@ public NavigableSet subSet(E fromElement, * @throws NullPointerException if {@code toElement} is null * @throws IllegalArgumentException {@inheritDoc} */ - public NavigableSet headSet(E toElement, boolean inclusive) { + public @PolyGrowShrink @PolyNonEmpty NavigableSet headSet(@PolyGrowShrink @PolyNonEmpty ConcurrentSkipListSet this, E toElement, boolean inclusive) { return new ConcurrentSkipListSet(m.headMap(toElement, inclusive)); } @@ -480,7 +482,7 @@ public NavigableSet headSet(E toElement, boolean inclusive) { * @throws NullPointerException if {@code fromElement} is null * @throws IllegalArgumentException {@inheritDoc} */ - public NavigableSet tailSet(E fromElement, boolean inclusive) { + public @PolyGrowShrink @PolyNonEmpty NavigableSet tailSet(@PolyGrowShrink @PolyNonEmpty ConcurrentSkipListSet this, E fromElement, boolean inclusive) { return new ConcurrentSkipListSet(m.tailMap(fromElement, inclusive)); } @@ -490,7 +492,7 @@ public NavigableSet tailSet(E fromElement, boolean inclusive) { * {@code toElement} is null * @throws IllegalArgumentException {@inheritDoc} */ - public NavigableSet subSet(E fromElement, E toElement) { + public @PolyGrowShrink @PolyNonEmpty NavigableSet subSet(@PolyGrowShrink @PolyNonEmpty ConcurrentSkipListSet this, E fromElement, E toElement) { return subSet(fromElement, true, toElement, false); } @@ -499,7 +501,7 @@ public NavigableSet subSet(E fromElement, E toElement) { * @throws NullPointerException if {@code toElement} is null * @throws IllegalArgumentException {@inheritDoc} */ - public NavigableSet headSet(E toElement) { + public @PolyGrowShrink @PolyNonEmpty NavigableSet headSet(@PolyGrowShrink @PolyNonEmpty ConcurrentSkipListSet this, E toElement) { return headSet(toElement, false); } @@ -508,7 +510,7 @@ public NavigableSet headSet(E toElement) { * @throws NullPointerException if {@code fromElement} is null * @throws IllegalArgumentException {@inheritDoc} */ - public NavigableSet tailSet(E fromElement) { + public @PolyGrowShrink @PolyNonEmpty NavigableSet tailSet(@PolyGrowShrink @PolyNonEmpty ConcurrentSkipListSet this, E fromElement) { return tailSet(fromElement, true); } @@ -524,7 +526,7 @@ public NavigableSet tailSet(E fromElement) { * * @return a reverse order view of this set */ - public NavigableSet descendingSet() { + public @PolyGrowShrink @PolyNonEmpty NavigableSet descendingSet(@PolyGrowShrink @PolyNonEmpty ConcurrentSkipListSet this) { return new ConcurrentSkipListSet(m.descendingMap()); } diff --git a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java index 7081b7c3d7d..a88fce84ea7 100644 --- a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java +++ b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java @@ -34,10 +34,13 @@ package java.util.concurrent; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -46,7 +49,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.lang.invoke.VarHandle; import java.lang.reflect.Field; @@ -544,7 +546,7 @@ public void addLast(E e) { * * @throws IndexOutOfBoundsException {@inheritDoc} */ - public E remove(int index) { + public E remove(@GuardSatisfied @Shrinkable CopyOnWriteArrayList this, int index) { synchronized (lock) { Object[] es = getArray(); int len = es.length; @@ -607,7 +609,7 @@ public E removeLast() { * @param o element to be removed from this list, if present * @return {@code true} if this list contained the specified element */ - public boolean remove(@GuardSatisfied @Nullable @UnknownSignedness Object o) { + public boolean remove(@Shrinkable CopyOnWriteArrayList this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { Object[] snapshot = getArray(); int index = indexOfRange(o, snapshot, 0, snapshot.length); return index >= 0 && remove(o, snapshot, index); @@ -617,7 +619,7 @@ public boolean remove(@GuardSatisfied @Nullable @UnknownSignedness Object o) { * A version of remove(Object) using the strong hint that given * recent snapshot contains o at the given index. */ - private boolean remove(@GuardSatisfied @Nullable @UnknownSignedness Object o, Object[] snapshot, int index) { + private boolean remove(@Shrinkable CopyOnWriteArrayList this, @GuardSatisfied @Nullable @UnknownSignedness Object o, Object[] snapshot, int index) { synchronized (lock) { Object[] current = getArray(); int len = current.length; @@ -660,7 +662,7 @@ private boolean remove(@GuardSatisfied @Nullable @UnknownSignedness Object o, Ob * @throws IndexOutOfBoundsException if fromIndex or toIndex out of range * ({@code fromIndex < 0 || toIndex > size() || toIndex < fromIndex}) */ - void removeRange(int fromIndex, int toIndex) { + void removeRange(@GuardSatisfied @Shrinkable CopyOnWriteArrayList this, int fromIndex, int toIndex) { synchronized (lock) { Object[] es = getArray(); int len = es.length; @@ -755,7 +757,7 @@ public boolean containsAll(Collection c) { * or if the specified collection is null * @see #remove(Object) */ - public boolean removeAll(Collection c) { + public boolean removeAll(@Shrinkable CopyOnWriteArrayList this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> c.contains(e)); } @@ -776,7 +778,7 @@ public boolean removeAll(Collection c) { + public boolean retainAll(@GuardSatisfied @Shrinkable CopyOnWriteArrayList this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> !c.contains(e)); } @@ -823,7 +825,7 @@ public int addAllAbsent(Collection c) { * Removes all of the elements from this list. * The list will be empty after this call returns. */ - public void clear() { + public void clear(@GuardSatisfied @Shrinkable CopyOnWriteArrayList this) { synchronized (lock) { setArray(new Object[0]); } @@ -916,7 +918,7 @@ public void forEach(Consumer action) { /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeIf(Predicate filter) { + public boolean removeIf(@Shrinkable CopyOnWriteArrayList this, Predicate filter) { Objects.requireNonNull(filter); return bulkRemove(filter); } @@ -1127,7 +1129,7 @@ public int hashCode() { * * @return an iterator over the elements in this list in proper sequence */ - public Iterator iterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty CopyOnWriteArrayList this) { return new COWIterator(getArray(), 0); } @@ -1139,7 +1141,7 @@ public Iterator iterator() { * traversing the iterator. The iterator does NOT support the * {@code remove}, {@code set} or {@code add} methods. */ - public ListIterator listIterator() { + public @PolyGrowShrink @PolyNonEmpty ListIterator listIterator(@PolyGrowShrink @PolyNonEmpty CopyOnWriteArrayList this) { return new COWIterator(getArray(), 0); } @@ -1153,7 +1155,7 @@ public ListIterator listIterator() { * * @throws IndexOutOfBoundsException {@inheritDoc} */ - public ListIterator listIterator(int index) { + public @PolyGrowShrink ListIterator listIterator(@PolyGrowShrink CopyOnWriteArrayList this, int index) { Object[] es = getArray(); int len = es.length; if (index < 0 || index > len) @@ -1204,7 +1206,6 @@ public boolean hasPrevious() { } @SuppressWarnings("unchecked") - @SideEffectsOnly("this") public E next(@NonEmpty COWIterator this) { if (! hasNext()) throw new NoSuchElementException(); @@ -1212,7 +1213,6 @@ public E next(@NonEmpty COWIterator this) { } @SuppressWarnings("unchecked") - @SideEffectsOnly("this") public E previous() { if (! hasPrevious()) throw new NoSuchElementException(); @@ -1282,7 +1282,7 @@ public void forEachRemaining(Consumer action) { * @return a view of the specified range within this list * @throws IndexOutOfBoundsException {@inheritDoc} */ - public List subList(int fromIndex, int toIndex) { + public @PolyGrowShrink List subList(@PolyGrowShrink CopyOnWriteArrayList this, int fromIndex, int toIndex) { synchronized (lock) { Object[] es = getArray(); int len = es.length; @@ -1477,6 +1477,7 @@ public E get(int index) { } } + @Pure public E getFirst() { synchronized (lock) { if (size == 0) @@ -1713,7 +1714,6 @@ public boolean hasNext() { return nextIndex() < size; } - @SideEffectsOnly("this") public E next(@NonEmpty COWSubListIterator this) { if (hasNext()) return it.next(); diff --git a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArraySet.java b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArraySet.java index 017289436ca..b0078296d26 100644 --- a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArraySet.java +++ b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArraySet.java @@ -35,10 +35,12 @@ package java.util.concurrent; +import org.checkerframework.checker.index.qual.PolyGrowShrink; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -405,7 +407,7 @@ public boolean retainAll(Collection iterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty CopyOnWriteArraySet this) { return al.iterator(); } diff --git a/src/java.base/share/classes/java/util/concurrent/DelayQueue.java b/src/java.base/share/classes/java/util/concurrent/DelayQueue.java index 98e91af580d..493fa19b734 100644 --- a/src/java.base/share/classes/java/util/concurrent/DelayQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/DelayQueue.java @@ -45,10 +45,13 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import static java.util.concurrent.TimeUnit.NANOSECONDS; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.lock.qual.GuardSatisfied; +import org.checkerframework.checker.index.qual.Shrinkable; import java.util.AbstractQueue; import java.util.Collection; import java.util.Iterator; @@ -225,7 +228,7 @@ public boolean offer(E e, long timeout, TimeUnit unit) { * @return the expired head of this queue, or {@code null} if this * queue has no elements with an expired delay */ - public @Nullable E poll() { + public @Nullable E poll(@GuardSatisfied @Shrinkable DelayQueue this) { final ReentrantLock lock = this.lock; lock.lock(); try { @@ -246,7 +249,7 @@ public boolean offer(E e, long timeout, TimeUnit unit) { * @return the expired head of this queue * @throws InterruptedException {@inheritDoc} */ - public E take() throws InterruptedException { + public E take(@GuardSatisfied @Shrinkable DelayQueue this) throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { @@ -291,7 +294,7 @@ public E take() throws InterruptedException { * an expired delay becomes available * @throws InterruptedException {@inheritDoc} */ - public @Nullable E poll(long timeout, TimeUnit unit) throws InterruptedException { + public @Nullable E poll(@GuardSatisfied @Shrinkable DelayQueue this, long timeout, TimeUnit unit) throws InterruptedException { long nanos = unit.toNanos(timeout); final ReentrantLock lock = this.lock; lock.lockInterruptibly(); @@ -382,7 +385,7 @@ public int size() { * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ - public int drainTo(Collection c) { + public int drainTo(@GuardSatisfied @Shrinkable DelayQueue this, Collection c) { return drainTo(c, Integer.MAX_VALUE); } @@ -392,7 +395,7 @@ public int drainTo(Collection c) { * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ - public int drainTo(Collection c, int maxElements) { + public int drainTo(@GuardSatisfied @Shrinkable DelayQueue this, Collection c, int maxElements) { Objects.requireNonNull(c); if (c == this) throw new IllegalArgumentException(); @@ -422,7 +425,7 @@ public int drainTo(Collection c, int maxElements) { * Elements with an unexpired delay are not waited for; they are * simply discarded from the queue. */ - public void clear() { + public void clear(@GuardSatisfied @Shrinkable DelayQueue this) { final ReentrantLock lock = this.lock; lock.lock(); try { @@ -516,7 +519,7 @@ public int remainingCapacity() { * Removes a single instance of the specified element from this * queue, if it is present, whether or not it has expired. */ - public boolean remove(@UnknownSignedness Object o) { + public boolean remove(@Shrinkable DelayQueue this, @UnknownSignedness Object o) { final ReentrantLock lock = this.lock; lock.lock(); try { @@ -555,7 +558,7 @@ void removeEQ(Object o) { * @return an iterator over the elements in this queue */ @SideEffectFree - public Iterator iterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty DelayQueue this) { return new Itr(toArray()); } @@ -579,7 +582,6 @@ public boolean hasNext() { } @SuppressWarnings("unchecked") - @SideEffectsOnly("this") public E next(@NonEmpty Itr this) { if (cursor >= array.length) throw new NoSuchElementException(); diff --git a/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java b/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java index d25e44d2d16..c4479427497 100644 --- a/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java +++ b/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java @@ -35,17 +35,19 @@ package java.util.concurrent; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.PolyNull; import org.checkerframework.checker.signedness.qual.PolySigned; import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import java.util.AbstractQueue; @@ -258,7 +260,7 @@ private boolean linkLast(Node node) { /** * Removes and returns first element, or null if empty. */ - private E unlinkFirst() { + private E unlinkFirst(@Shrinkable LinkedBlockingDeque this) { // assert lock.isHeldByCurrentThread(); Node f = first; if (f == null) @@ -280,7 +282,7 @@ private E unlinkFirst() { /** * Removes and returns last element, or null if empty. */ - private E unlinkLast() { + private E unlinkLast(@Shrinkable LinkedBlockingDeque this) { // assert lock.isHeldByCurrentThread(); Node l = last; if (l == null) @@ -302,7 +304,7 @@ private E unlinkLast() { /** * Unlinks x. */ - void unlink(Node x) { + void unlink(@Shrinkable LinkedBlockingDeque this, Node x) { // assert lock.isHeldByCurrentThread(); // assert x.item != null; Node p = x.prev; @@ -455,7 +457,7 @@ public boolean offerLast(E e, long timeout, TimeUnit unit) /** * @throws NoSuchElementException {@inheritDoc} */ - public E removeFirst(@NonEmpty LinkedBlockingDeque this) { + public E removeFirst(@GuardSatisfied @NonEmpty @Shrinkable LinkedBlockingDeque this) { E x = pollFirst(); if (x == null) throw new NoSuchElementException(); return x; @@ -464,13 +466,13 @@ public E removeFirst(@NonEmpty LinkedBlockingDeque this) { /** * @throws NoSuchElementException {@inheritDoc} */ - public E removeLast(@NonEmpty LinkedBlockingDeque this) { + public E removeLast(@GuardSatisfied @NonEmpty @Shrinkable LinkedBlockingDeque this) { E x = pollLast(); if (x == null) throw new NoSuchElementException(); return x; } - public @Nullable E pollFirst() { + public @Nullable E pollFirst(@GuardSatisfied @Shrinkable LinkedBlockingDeque this) { final ReentrantLock lock = this.lock; lock.lock(); try { @@ -480,7 +482,7 @@ public E removeLast(@NonEmpty LinkedBlockingDeque this) { } } - public @Nullable E pollLast() { + public @Nullable E pollLast(@GuardSatisfied @Shrinkable LinkedBlockingDeque this) { final ReentrantLock lock = this.lock; lock.lock(); try { @@ -490,7 +492,7 @@ public E removeLast(@NonEmpty LinkedBlockingDeque this) { } } - public E takeFirst() throws InterruptedException { + public E takeFirst(@GuardSatisfied @Shrinkable LinkedBlockingDeque this) throws InterruptedException { final ReentrantLock lock = this.lock; lock.lock(); try { @@ -503,7 +505,7 @@ public E takeFirst() throws InterruptedException { } } - public E takeLast() throws InterruptedException { + public E takeLast(@GuardSatisfied @Shrinkable LinkedBlockingDeque this) throws InterruptedException { final ReentrantLock lock = this.lock; lock.lock(); try { @@ -516,7 +518,7 @@ public E takeLast() throws InterruptedException { } } - public @Nullable E pollFirst(long timeout, TimeUnit unit) + public @Nullable E pollFirst(@GuardSatisfied @Shrinkable LinkedBlockingDeque this, long timeout, TimeUnit unit) throws InterruptedException { long nanos = unit.toNanos(timeout); final ReentrantLock lock = this.lock; @@ -534,7 +536,7 @@ public E takeLast() throws InterruptedException { } } - public @Nullable E pollLast(long timeout, TimeUnit unit) + public @Nullable E pollLast(@GuardSatisfied @Shrinkable LinkedBlockingDeque this, long timeout, TimeUnit unit) throws InterruptedException { long nanos = unit.toNanos(timeout); final ReentrantLock lock = this.lock; @@ -592,7 +594,7 @@ public E getLast(@NonEmpty LinkedBlockingDeque this) { } } - public boolean removeFirstOccurrence(Object o) { + public boolean removeFirstOccurrence(@Shrinkable LinkedBlockingDeque this, Object o) { if (o == null) return false; final ReentrantLock lock = this.lock; lock.lock(); @@ -609,7 +611,7 @@ public boolean removeFirstOccurrence(Object o) { } } - public boolean removeLastOccurrence(Object o) { + public boolean removeLastOccurrence(@Shrinkable LinkedBlockingDeque this, Object o) { if (o == null) return false; final ReentrantLock lock = this.lock; lock.lock(); @@ -678,19 +680,19 @@ public boolean offer(E e, long timeout, TimeUnit unit) * @return the head of the queue represented by this deque * @throws NoSuchElementException if this deque is empty */ - public E remove(@NonEmpty LinkedBlockingDeque this) { + public E remove(@GuardSatisfied @NonEmpty @Shrinkable LinkedBlockingDeque this) { return removeFirst(); } - public @Nullable E poll() { + public @Nullable E poll(@GuardSatisfied @Shrinkable LinkedBlockingDeque this) { return pollFirst(); } - public E take() throws InterruptedException { + public E take(@GuardSatisfied @Shrinkable LinkedBlockingDeque this) throws InterruptedException { return takeFirst(); } - public @Nullable E poll(long timeout, TimeUnit unit) throws InterruptedException { + public @Nullable E poll(@GuardSatisfied @Shrinkable LinkedBlockingDeque this, long timeout, TimeUnit unit) throws InterruptedException { return pollFirst(timeout, unit); } @@ -740,7 +742,7 @@ public int remainingCapacity() { * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ - public int drainTo(Collection c) { + public int drainTo(@GuardSatisfied @Shrinkable LinkedBlockingDeque this, Collection c) { return drainTo(c, Integer.MAX_VALUE); } @@ -750,7 +752,7 @@ public int drainTo(Collection c) { * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ - public int drainTo(Collection c, int maxElements) { + public int drainTo(@GuardSatisfied @Shrinkable LinkedBlockingDeque this, Collection c, int maxElements) { Objects.requireNonNull(c); if (c == this) throw new IllegalArgumentException(); @@ -783,7 +785,7 @@ public void push(E e) { /** * @throws NoSuchElementException {@inheritDoc} */ - public E pop(@NonEmpty LinkedBlockingDeque this) { + public E pop(@GuardSatisfied @NonEmpty @Shrinkable LinkedBlockingDeque this) { return removeFirst(); } @@ -803,7 +805,7 @@ public E pop(@NonEmpty LinkedBlockingDeque this) { * @param o element to be removed from this deque, if present * @return {@code true} if this deque changed as a result of the call */ - public boolean remove(@GuardSatisfied @Nullable @UnknownSignedness Object o) { + public boolean remove(@Shrinkable LinkedBlockingDeque this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { return removeFirstOccurrence(o); } @@ -998,7 +1000,7 @@ public String toString() { * Atomically removes all of the elements from this deque. * The deque will be empty after this call returns. */ - public void clear() { + public void clear(@GuardSatisfied @Shrinkable LinkedBlockingDeque this) { final ReentrantLock lock = this.lock; lock.lock(); try { @@ -1038,7 +1040,7 @@ Node succ(Node p) { * * @return an iterator over the elements in this deque in proper sequence */ - public Iterator iterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty LinkedBlockingDeque this) { return new Itr(); } @@ -1052,7 +1054,7 @@ public Iterator iterator() { * * @return an iterator over the elements in this deque in reverse order */ - public Iterator descendingIterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator descendingIterator(@PolyGrowShrink @PolyNonEmpty LinkedBlockingDeque this) { return new DescendingItr(); } @@ -1106,7 +1108,6 @@ public boolean hasNext() { return next != null; } - @SideEffectsOnly("this") public E next(@NonEmpty AbstractItr this) { Node p; if ((p = next) == null) @@ -1354,7 +1355,7 @@ void forEachFrom(Consumer action, Node p) { /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeIf(Predicate filter) { + public boolean removeIf(@Shrinkable LinkedBlockingDeque this, Predicate filter) { Objects.requireNonNull(filter); return bulkRemove(filter); } @@ -1362,7 +1363,7 @@ public boolean removeIf(Predicate filter) { /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeAll(Collection c) { + public boolean removeAll(@Shrinkable LinkedBlockingDeque this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> c.contains(e)); } @@ -1370,7 +1371,7 @@ public boolean removeAll(Collection c) { + public boolean retainAll(@GuardSatisfied @Shrinkable LinkedBlockingDeque this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> !c.contains(e)); } diff --git a/src/java.base/share/classes/java/util/concurrent/LinkedBlockingQueue.java b/src/java.base/share/classes/java/util/concurrent/LinkedBlockingQueue.java index 4336f5a701c..c260d22481a 100644 --- a/src/java.base/share/classes/java/util/concurrent/LinkedBlockingQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/LinkedBlockingQueue.java @@ -35,16 +35,18 @@ package java.util.concurrent; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.PolyNull; import org.checkerframework.checker.signedness.qual.PolySigned; import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import java.util.AbstractQueue; @@ -438,7 +440,7 @@ public boolean offer(E e) { return true; } - public E take() throws InterruptedException { + public E take(@GuardSatisfied @Shrinkable LinkedBlockingQueue this) throws InterruptedException { final E x; final int c; final AtomicInteger count = this.count; @@ -460,7 +462,7 @@ public E take() throws InterruptedException { return x; } - public @Nullable E poll(long timeout, TimeUnit unit) throws InterruptedException { + public @Nullable E poll(@GuardSatisfied @Shrinkable LinkedBlockingQueue this, long timeout, TimeUnit unit) throws InterruptedException { final E x; final int c; long nanos = unit.toNanos(timeout); @@ -485,7 +487,7 @@ public E take() throws InterruptedException { return x; } - public @Nullable E poll() { + public @Nullable E poll(@GuardSatisfied @Shrinkable LinkedBlockingQueue this) { final AtomicInteger count = this.count; if (count.get() == 0) return null; @@ -549,7 +551,7 @@ void unlink(Node p, Node pred) { * @param o element to be removed from this queue, if present * @return {@code true} if this queue changed as a result of the call */ - public boolean remove(@GuardSatisfied @Nullable @UnknownSignedness Object o) { + public boolean remove(@Shrinkable LinkedBlockingQueue this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { if (o == null) return false; fullyLock(); try { @@ -680,7 +682,7 @@ public String toString() { * Atomically removes all of the elements from this queue. * The queue will be empty after this call returns. */ - public void clear() { + public void clear(@GuardSatisfied @Shrinkable LinkedBlockingQueue this) { fullyLock(); try { for (Node p, h = head; (p = h.next) != null; h = p) { @@ -702,7 +704,7 @@ public void clear() { * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ - public int drainTo(Collection c) { + public int drainTo(@GuardSatisfied @Shrinkable LinkedBlockingQueue this, Collection c) { return drainTo(c, Integer.MAX_VALUE); } @@ -712,7 +714,7 @@ public int drainTo(Collection c) { * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ - public int drainTo(Collection c, int maxElements) { + public int drainTo(@GuardSatisfied @Shrinkable LinkedBlockingQueue this, Collection c, int maxElements) { Objects.requireNonNull(c); if (c == this) throw new IllegalArgumentException(); @@ -772,7 +774,7 @@ Node succ(Node p) { * * @return an iterator over the elements in this queue in proper sequence */ - public Iterator iterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty LinkedBlockingQueue this) { return new Itr(); } @@ -805,7 +807,6 @@ public boolean hasNext() { return next != null; } - @SideEffectsOnly("this") public E next(@NonEmpty Itr this) { Node p; if ((p = next) == null) @@ -1037,7 +1038,7 @@ void forEachFrom(Consumer action, Node p) { /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeIf(Predicate filter) { + public boolean removeIf(@Shrinkable LinkedBlockingQueue this, Predicate filter) { Objects.requireNonNull(filter); return bulkRemove(filter); } @@ -1045,7 +1046,7 @@ public boolean removeIf(Predicate filter) { /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeAll(Collection c) { + public boolean removeAll(@Shrinkable LinkedBlockingQueue this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> c.contains(e)); } @@ -1053,7 +1054,7 @@ public boolean removeAll(Collection c) { + public boolean retainAll(@GuardSatisfied @Shrinkable LinkedBlockingQueue this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> !c.contains(e)); } diff --git a/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java b/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java index 32c35fb732b..be770c7f155 100644 --- a/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java @@ -35,10 +35,13 @@ package java.util.concurrent; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.PolyNull; @@ -46,7 +49,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.framework.qual.AnnotatedFor; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; @@ -922,7 +924,6 @@ public final boolean hasNext() { return nextNode != null; } - @SideEffectsOnly("this") public final E next(@NonEmpty Itr this) { final Node p; if ((p = nextNode) == null) throw new NoSuchElementException(); @@ -1255,7 +1256,7 @@ public boolean add(E e) { * * @throws NullPointerException if the specified element is null */ - public boolean tryTransfer(E e) { + public boolean tryTransfer(@GuardSatisfied @Shrinkable LinkedTransferQueue this, E e) { return xfer(e, true, NOW, 0L) == null; } @@ -1270,7 +1271,7 @@ public boolean tryTransfer(E e) { * * @throws NullPointerException if the specified element is null */ - public void transfer(E e) throws InterruptedException { + public void transfer(@GuardSatisfied @Shrinkable LinkedTransferQueue this, E e) throws InterruptedException { if (xfer(e, true, SYNC, 0L) != null) { Thread.interrupted(); // failure possible only due to interrupt throw new InterruptedException(); @@ -1291,7 +1292,7 @@ public void transfer(E e) throws InterruptedException { * * @throws NullPointerException if the specified element is null */ - public boolean tryTransfer(E e, long timeout, TimeUnit unit) + public boolean tryTransfer(@GuardSatisfied @Shrinkable LinkedTransferQueue this, E e, long timeout, TimeUnit unit) throws InterruptedException { if (xfer(e, true, TIMED, unit.toNanos(timeout)) == null) return true; @@ -1300,7 +1301,7 @@ public boolean tryTransfer(E e, long timeout, TimeUnit unit) throw new InterruptedException(); } - public E take() throws InterruptedException { + public E take(@GuardSatisfied @Shrinkable LinkedTransferQueue this) throws InterruptedException { E e = xfer(null, false, SYNC, 0L); if (e != null) return e; @@ -1308,14 +1309,14 @@ public E take() throws InterruptedException { throw new InterruptedException(); } - public @Nullable E poll(long timeout, TimeUnit unit) throws InterruptedException { + public @Nullable E poll(@GuardSatisfied @Shrinkable LinkedTransferQueue this, long timeout, TimeUnit unit) throws InterruptedException { E e = xfer(null, false, TIMED, unit.toNanos(timeout)); if (e != null || !Thread.interrupted()) return e; throw new InterruptedException(); } - public @Nullable E poll() { + public @Nullable E poll(@GuardSatisfied @Shrinkable LinkedTransferQueue this) { return xfer(null, false, NOW, 0L); } @@ -1323,7 +1324,7 @@ public E take() throws InterruptedException { * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ - public int drainTo(Collection c) { + public int drainTo(@GuardSatisfied @Shrinkable LinkedTransferQueue this, Collection c) { Objects.requireNonNull(c); if (c == this) throw new IllegalArgumentException(); @@ -1337,7 +1338,7 @@ public int drainTo(Collection c) { * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ - public int drainTo(Collection c, int maxElements) { + public int drainTo(@GuardSatisfied @Shrinkable LinkedTransferQueue this, Collection c, int maxElements) { Objects.requireNonNull(c); if (c == this) throw new IllegalArgumentException(); @@ -1356,7 +1357,7 @@ public int drainTo(Collection c, int maxElements) { * * @return an iterator over the elements in this queue in proper sequence */ - public Iterator iterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty LinkedTransferQueue this) { return new Itr(); } @@ -1440,7 +1441,7 @@ public int getWaitingConsumerCount() { * @param o element to be removed from this queue, if present * @return {@code true} if this queue changed as a result of the call */ - public boolean remove(@GuardSatisfied @Nullable @UnknownSignedness Object o) { + public boolean remove(@Shrinkable LinkedTransferQueue this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { if (o == null) return false; restartFromHead: for (;;) { for (Node p = head, pred = null; p != null; ) { @@ -1560,7 +1561,7 @@ private void readObject(java.io.ObjectInputStream s) /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeIf(Predicate filter) { + public boolean removeIf(@Shrinkable LinkedTransferQueue this, Predicate filter) { Objects.requireNonNull(filter); return bulkRemove(filter); } @@ -1568,7 +1569,7 @@ public boolean removeIf(Predicate filter) { /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeAll(Collection c) { + public boolean removeAll(@Shrinkable LinkedTransferQueue this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> c.contains(e)); } @@ -1576,12 +1577,12 @@ public boolean removeAll(Collection c) { + public boolean retainAll(@GuardSatisfied @Shrinkable LinkedTransferQueue this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> !c.contains(e)); } - public void clear() { + public void clear(@GuardSatisfied @Shrinkable LinkedTransferQueue this) { bulkRemove(e -> true); } diff --git a/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java b/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java index f615c714a28..93fa3b5eb85 100644 --- a/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java @@ -35,17 +35,19 @@ package java.util.concurrent; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmpty; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; import org.checkerframework.checker.nonempty.qual.NonEmpty; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.PolyNull; import org.checkerframework.checker.signedness.qual.PolySigned; import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import java.lang.invoke.MethodHandles; @@ -531,7 +533,7 @@ public boolean offer(E e, long timeout, TimeUnit unit) { return offer(e); // never need to block } - public @Nullable E poll() { + public @Nullable E poll(@GuardSatisfied @Shrinkable PriorityBlockingQueue this) { final ReentrantLock lock = this.lock; lock.lock(); try { @@ -541,7 +543,7 @@ public boolean offer(E e, long timeout, TimeUnit unit) { } } - public E take() throws InterruptedException { + public E take(@GuardSatisfied @Shrinkable PriorityBlockingQueue this) throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); E result; @@ -554,7 +556,7 @@ public E take() throws InterruptedException { return result; } - public @Nullable E poll(long timeout, TimeUnit unit) throws InterruptedException { + public @Nullable E poll(@GuardSatisfied @Shrinkable PriorityBlockingQueue this, long timeout, TimeUnit unit) throws InterruptedException { long nanos = unit.toNanos(timeout); final ReentrantLock lock = this.lock; lock.lockInterruptibly(); @@ -659,7 +661,7 @@ private void removeAt(int i) { * @param o element to be removed from this queue, if present * @return {@code true} if this queue changed as a result of the call */ - public boolean remove(@Nullable @UnknownSignedness Object o) { + public boolean remove(@Shrinkable PriorityBlockingQueue this, @Nullable @UnknownSignedness Object o) { final ReentrantLock lock = this.lock; lock.lock(); try { @@ -724,7 +726,7 @@ public String toString() { * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ - public int drainTo(Collection c) { + public int drainTo(@GuardSatisfied @Shrinkable PriorityBlockingQueue this, Collection c) { return drainTo(c, Integer.MAX_VALUE); } @@ -734,7 +736,7 @@ public int drainTo(Collection c) { * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ - public int drainTo(Collection c, int maxElements) { + public int drainTo(@GuardSatisfied @Shrinkable PriorityBlockingQueue this, Collection c, int maxElements) { Objects.requireNonNull(c); if (c == this) throw new IllegalArgumentException(); @@ -758,7 +760,7 @@ public int drainTo(Collection c, int maxElements) { * Atomically removes all of the elements from this queue. * The queue will be empty after this call returns. */ - public void clear() { + public void clear(@GuardSatisfied @Shrinkable PriorityBlockingQueue this) { final ReentrantLock lock = this.lock; lock.lock(); try { @@ -856,7 +858,7 @@ public void clear() { * * @return an iterator over the elements in this queue */ - public Iterator iterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty PriorityBlockingQueue this) { return new Itr(toArray()); } @@ -878,7 +880,6 @@ public boolean hasNext() { return cursor < array.length; } - @SideEffectsOnly("this") public E next(@NonEmpty Itr this) { if (cursor >= array.length) throw new NoSuchElementException(); @@ -1030,7 +1031,7 @@ public Spliterator spliterator() { /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeIf(Predicate filter) { + public boolean removeIf(@Shrinkable PriorityBlockingQueue this, Predicate filter) { Objects.requireNonNull(filter); return bulkRemove(filter); } @@ -1038,7 +1039,7 @@ public boolean removeIf(Predicate filter) { /** * @throws NullPointerException {@inheritDoc} */ - public boolean removeAll(Collection c) { + public boolean removeAll(@Shrinkable PriorityBlockingQueue this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> c.contains(e)); } @@ -1046,7 +1047,7 @@ public boolean removeAll(Collection c) { + public boolean retainAll(@GuardSatisfied @Shrinkable PriorityBlockingQueue this, Collection c) { Objects.requireNonNull(c); return bulkRemove(e -> !c.contains(e)); } diff --git a/src/java.base/share/classes/java/util/concurrent/RejectedExecutionException.java b/src/java.base/share/classes/java/util/concurrent/RejectedExecutionException.java index 87feef49513..8529b89af11 100644 --- a/src/java.base/share/classes/java/util/concurrent/RejectedExecutionException.java +++ b/src/java.base/share/classes/java/util/concurrent/RejectedExecutionException.java @@ -35,6 +35,9 @@ package java.util.concurrent; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + /** * Exception thrown by an {@link Executor} when a task cannot be * accepted for execution. @@ -42,6 +45,7 @@ * @since 1.5 * @author Doug Lea */ +@AnnotatedFor({"nullness"}) public class RejectedExecutionException extends RuntimeException { private static final long serialVersionUID = -375805702767069545L; @@ -60,7 +64,7 @@ public RejectedExecutionException() { } * * @param message the detail message */ - public RejectedExecutionException(String message) { + public RejectedExecutionException(@Nullable String message) { super(message); } @@ -72,7 +76,7 @@ public RejectedExecutionException(String message) { * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method) */ - public RejectedExecutionException(String message, Throwable cause) { + public RejectedExecutionException(@Nullable String message, @Nullable Throwable cause) { super(message, cause); } @@ -85,7 +89,7 @@ public RejectedExecutionException(String message, Throwable cause) { * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method) */ - public RejectedExecutionException(Throwable cause) { + public RejectedExecutionException(@Nullable Throwable cause) { super(cause); } } diff --git a/src/java.base/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java b/src/java.base/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java index b40a6a0ed12..d1c9a0d7fe9 100644 --- a/src/java.base/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java +++ b/src/java.base/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java @@ -43,7 +43,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.framework.qual.AnnotatedFor; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.NANOSECONDS; @@ -1353,7 +1352,6 @@ public boolean hasNext() { return cursor < array.length; } - @SideEffectsOnly("this") public Runnable next(@NonEmpty Itr this) { if (cursor >= array.length) throw new NoSuchElementException(); diff --git a/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java b/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java index 212d0380048..3c1a35a93bf 100644 --- a/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java @@ -36,8 +36,11 @@ package java.util.concurrent; +import org.checkerframework.checker.index.qual.PolyGrowShrink; +import org.checkerframework.checker.index.qual.Shrinkable; import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.nonempty.qual.EnsuresNonEmptyIf; +import org.checkerframework.checker.nonempty.qual.PolyNonEmpty; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.PolyNull; @@ -894,7 +897,7 @@ public boolean offer(E e) { * @return the head of this queue * @throws InterruptedException {@inheritDoc} */ - public E take() throws InterruptedException { + public E take(@GuardSatisfied @Shrinkable SynchronousQueue this) throws InterruptedException { E e = transferer.transfer(null, false, 0); if (e != null) return e; @@ -911,7 +914,7 @@ public E take() throws InterruptedException { * specified waiting time elapses before an element is present * @throws InterruptedException {@inheritDoc} */ - public @Nullable E poll(long timeout, TimeUnit unit) throws InterruptedException { + public @Nullable E poll(@GuardSatisfied @Shrinkable SynchronousQueue this, long timeout, TimeUnit unit) throws InterruptedException { E e = transferer.transfer(null, true, unit.toNanos(timeout)); if (e != null || !Thread.interrupted()) return e; @@ -925,7 +928,7 @@ public E take() throws InterruptedException { * @return the head of this queue, or {@code null} if no * element is available */ - public @Nullable E poll() { + public @Nullable E poll(@GuardSatisfied @Shrinkable SynchronousQueue this) { return transferer.transfer(null, true, 0); } @@ -966,7 +969,7 @@ public int remainingCapacity() { * Does nothing. * A {@code SynchronousQueue} has no internal capacity. */ - public void clear() { + public void clear(@GuardSatisfied @Shrinkable SynchronousQueue this) { } /** @@ -989,7 +992,7 @@ public boolean contains(@GuardSatisfied @Nullable @UnknownSignedness Object o) { * @param o the element to remove * @return {@code false} */ - public boolean remove(@GuardSatisfied @Nullable @UnknownSignedness Object o) { + public boolean remove(@Shrinkable SynchronousQueue this, @GuardSatisfied @Nullable @UnknownSignedness Object o) { return false; } @@ -1012,7 +1015,7 @@ public boolean containsAll(Collection c) { * @param c the collection * @return {@code false} */ - public boolean removeAll(Collection c) { + public boolean removeAll(@Shrinkable SynchronousQueue this, Collection c) { return false; } @@ -1023,7 +1026,7 @@ public boolean removeAll(Collection c) { * @param c the collection * @return {@code false} */ - public boolean retainAll(Collection c) { + public boolean retainAll(@GuardSatisfied @Shrinkable SynchronousQueue this, Collection c) { return false; } @@ -1046,7 +1049,7 @@ public boolean retainAll(Collection c) { * @return an empty iterator */ @SideEffectFree - public Iterator iterator() { + public @PolyGrowShrink @PolyNonEmpty Iterator iterator(@PolyGrowShrink @PolyNonEmpty SynchronousQueue this) { return Collections.emptyIterator(); } @@ -1100,7 +1103,7 @@ public String toString() { * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ - public int drainTo(Collection c) { + public int drainTo(@GuardSatisfied @Shrinkable SynchronousQueue this, Collection c) { Objects.requireNonNull(c); if (c == this) throw new IllegalArgumentException(); @@ -1116,7 +1119,7 @@ public int drainTo(Collection c) { * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} */ - public int drainTo(Collection c, int maxElements) { + public int drainTo(@GuardSatisfied @Shrinkable SynchronousQueue this, Collection c, int maxElements) { Objects.requireNonNull(c); if (c == this) throw new IllegalArgumentException(); diff --git a/src/java.base/share/classes/java/util/regex/Matcher.java b/src/java.base/share/classes/java/util/regex/Matcher.java index 3c515170c9d..408d2e014b2 100644 --- a/src/java.base/share/classes/java/util/regex/Matcher.java +++ b/src/java.base/share/classes/java/util/regex/Matcher.java @@ -35,7 +35,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import java.io.IOException; @@ -1355,7 +1354,6 @@ class MatchResultIterator implements Iterator { int expectedCount = -1; @Override - @SideEffectsOnly("this") public MatchResult next(@NonEmpty MatchResultIterator this) { if (expectedCount >= 0 && expectedCount != modCount) throw new ConcurrentModificationException(); diff --git a/src/java.base/share/classes/java/util/regex/Pattern.java b/src/java.base/share/classes/java/util/regex/Pattern.java index fc1ccc07132..34dc95c5b39 100644 --- a/src/java.base/share/classes/java/util/regex/Pattern.java +++ b/src/java.base/share/classes/java/util/regex/Pattern.java @@ -35,7 +35,6 @@ import org.checkerframework.common.value.qual.MinLen; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; @@ -1159,7 +1158,7 @@ public static Pattern compile(@Regex String regex, int flags) { * @return The source of this pattern */ @Pure - public String pattern() { + public @PolyRegex String pattern(@PolyRegex Pattern this) { return pattern; } @@ -1172,7 +1171,7 @@ public String pattern() { * @since 1.5 */ @Pure - public String toString(@GuardSatisfied Pattern this) { + public @PolyRegex String toString(@GuardSatisfied @PolyRegex Pattern this) { return pattern; } @@ -6085,7 +6084,6 @@ class MatcherIterator implements Iterator { // > 0 if there are N next empty elements private int emptyElementCount; - @SideEffectsOnly("this") public String next(@NonEmpty MatcherIterator this) { if (!hasNext()) throw new NoSuchElementException(); diff --git a/src/java.base/share/classes/java/util/stream/AbstractSpinedBuffer.java b/src/java.base/share/classes/java/util/stream/AbstractSpinedBuffer.java index e766529d266..56f011bb397 100644 --- a/src/java.base/share/classes/java/util/stream/AbstractSpinedBuffer.java +++ b/src/java.base/share/classes/java/util/stream/AbstractSpinedBuffer.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff --git a/src/java.base/share/classes/java/util/stream/Collectors.java b/src/java.base/share/classes/java/util/stream/Collectors.java index f960de7d359..4245073c121 100644 --- a/src/java.base/share/classes/java/util/stream/Collectors.java +++ b/src/java.base/share/classes/java/util/stream/Collectors.java @@ -1980,6 +1980,7 @@ private static final class Partition } @Override + @SideEffectFree public int size() { return 2; } diff --git a/src/java.base/share/classes/java/util/stream/Stream.java b/src/java.base/share/classes/java/util/stream/Stream.java index c63fcc78295..7193a7d7e86 100644 --- a/src/java.base/share/classes/java/util/stream/Stream.java +++ b/src/java.base/share/classes/java/util/stream/Stream.java @@ -1,5 +1,5 @@ /* -* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index 9a96de226d3..81a30a68e84 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -36,7 +36,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.signedness.qual.SignedPositive; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.framework.qual.CFComment; @@ -529,14 +528,12 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") public T nextElement(@NonEmpty ZipEntryIterator this) { return next(); } @Override @SuppressWarnings("unchecked") - @SideEffectsOnly("this") public T next(@NonEmpty ZipEntryIterator this) { synchronized (ZipFile.this) { ensureOpen(); diff --git a/src/java.base/share/classes/javax/net/ssl/X509KeyManager.java b/src/java.base/share/classes/javax/net/ssl/X509KeyManager.java index 759a01c31f2..e83f21310a6 100644 --- a/src/java.base/share/classes/javax/net/ssl/X509KeyManager.java +++ b/src/java.base/share/classes/javax/net/ssl/X509KeyManager.java @@ -83,7 +83,7 @@ public interface X509KeyManager extends KeyManager { * are no matches. */ @Nullable String chooseClientAlias(String[] keyType, Principal @Nullable [] issuers, - @Nullable Socket socket); + @Nullable Socket socket); /** * Get the matching aliases for authenticating the server side of a secure @@ -114,7 +114,7 @@ public interface X509KeyManager extends KeyManager { * are no matches. */ @Nullable String chooseServerAlias(String keyType, Principal @Nullable [] issuers, - @Nullable Socket socket); + @Nullable Socket socket); /** * Returns the certificate chain associated with the given alias. diff --git a/src/java.base/share/classes/javax/security/auth/Subject.java b/src/java.base/share/classes/javax/security/auth/Subject.java index 54a8c778242..7be2073cb03 100644 --- a/src/java.base/share/classes/javax/security/auth/Subject.java +++ b/src/java.base/share/classes/javax/security/auth/Subject.java @@ -34,7 +34,6 @@ import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.io.IOException; import java.io.ObjectInputStream; @@ -1207,7 +1206,6 @@ public boolean hasNext() { return i.hasNext(); } - @SideEffectsOnly("this") public E next(/*@NonEmpty Iterator this*/) { if (which != Subject.PRIV_CREDENTIAL_SET) { return i.next(); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassfileVersionImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassfileVersionImpl.java index e79696ad582..fbd16f8a090 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassfileVersionImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassfileVersionImpl.java @@ -26,6 +26,12 @@ import jdk.internal.classfile.ClassfileVersion; +import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.qual.Pure; +import org.checkerframework.dataflow.qual.SideEffectFree; + public final class ClassfileVersionImpl extends AbstractElement implements ClassfileVersion { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java index e5b2a8fc663..1f5e21a7bdd 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/InterfacesImpl.java @@ -27,6 +27,12 @@ import java.util.List; import java.util.stream.Collectors; +import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.qual.Pure; +import org.checkerframework.dataflow.qual.SideEffectFree; + import jdk.internal.classfile.constantpool.ClassEntry; import jdk.internal.classfile.Interfaces; diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index e36c8c36889..3fee1936d1d 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -82,8 +82,8 @@ exports org.checkerframework.checker.fenum.qual; exports org.checkerframework.checker.formatter.qual; exports org.checkerframework.checker.guieffect.qual; - exports org.checkerframework.checker.i18n.qual; exports org.checkerframework.checker.i18nformatter.qual; + exports org.checkerframework.checker.i18n.qual; exports org.checkerframework.checker.index.qual; exports org.checkerframework.checker.initialization.qual; exports org.checkerframework.checker.interning.qual; @@ -96,6 +96,7 @@ exports org.checkerframework.checker.regex.qual; exports org.checkerframework.checker.signature.qual; exports org.checkerframework.checker.signedness.qual; + exports org.checkerframework.checker.sqlquotes.qual; exports org.checkerframework.checker.tainting.qual; exports org.checkerframework.checker.units.qual; exports org.checkerframework.common.aliasing.qual; diff --git a/src/java.base/share/classes/org/checkerframework/checker/builder/qual/CalledMethods.java b/src/java.base/share/classes/org/checkerframework/checker/builder/qual/CalledMethods.java index 9d27516f9de..1944baff64e 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/builder/qual/CalledMethods.java +++ b/src/java.base/share/classes/org/checkerframework/checker/builder/qual/CalledMethods.java @@ -21,7 +21,7 @@ /** * The names of methods that have definitely been called. * - * @return the names of methods that have definetely been called + * @return the names of methods that have definitely been called */ String[] value(); } diff --git a/src/java.base/share/classes/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethods.java b/src/java.base/share/classes/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethods.java index d3728957fd0..ef86d39da3a 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethods.java +++ b/src/java.base/share/classes/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethods.java @@ -78,7 +78,7 @@ @PostconditionAnnotation(qualifier = CalledMethods.class) public static @interface List { /** - * Return the repeatable annotations. + * Returns the repeatable annotations. * * @return the repeatable annotations */ diff --git a/src/java.base/share/classes/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethodsIf.java b/src/java.base/share/classes/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethodsIf.java index 62177670599..12c36c1319c 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethodsIf.java +++ b/src/java.base/share/classes/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethodsIf.java @@ -65,7 +65,7 @@ @InheritedAnnotation public static @interface List { /** - * Return the repeatable annotations. + * Returns the repeatable annotations. * * @return the repeatable annotations */ diff --git a/src/java.base/share/classes/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethodsOnException.java b/src/java.base/share/classes/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethodsOnException.java index 5d2d7e6f26c..b8b991727e4 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethodsOnException.java +++ b/src/java.base/share/classes/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethodsOnException.java @@ -23,8 +23,8 @@ * public void callM(T t) { ... } * * - *

The callM method promises to always call {@code t.m()} before throwing any kind - * of {@link Exception}. + *

The {@code callM} method promises to always call {@code t.m()} before throwing any kind of + * {@link Exception}. * *

Note that {@code EnsuresCalledMethodsOnException} only describes behavior for {@link * Exception} (and by extension {@link RuntimeException}, {@link NullPointerException}, etc.) but @@ -64,7 +64,7 @@ // /** // * Returns the exception types under which the postcondition holds. // * - // * @return the exception types under which the postcondition holds. + // * @return the exception types under which the postcondition holds // */ // Class[] exceptions(); @@ -89,7 +89,7 @@ @InheritedAnnotation public static @interface List { /** - * Return the repeatable annotations. + * Returns the repeatable annotations. * * @return the repeatable annotations */ diff --git a/src/java.base/share/classes/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethodsVarArgs.java b/src/java.base/share/classes/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethodsVarargs.java similarity index 91% rename from src/java.base/share/classes/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethodsVarArgs.java rename to src/java.base/share/classes/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethodsVarargs.java index 553ebc5ebd4..ac528e9e733 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethodsVarArgs.java +++ b/src/java.base/share/classes/org/checkerframework/checker/calledmethods/qual/EnsuresCalledMethodsVarargs.java @@ -10,7 +10,7 @@ *

Consider the following method: * *

- * @EnsuresCalledMethodsVarArgs("m")
+ * @EnsuresCalledMethodsVarargs("m")
  * public void callMOnAll(S s, T t...) { ... }
  * 
* @@ -20,7 +20,7 @@ *

This annotation is not checked. An error will always be issued when it is used. */ @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) -public @interface EnsuresCalledMethodsVarArgs { +public @interface EnsuresCalledMethodsVarargs { /** * Returns the methods guaranteed to be invoked on the varargs parameters. diff --git a/src/java.base/share/classes/org/checkerframework/checker/formatter/qual/ConversionCategory.java b/src/java.base/share/classes/org/checkerframework/checker/formatter/qual/ConversionCategory.java index e1cc6f47edb..6e58c945d7c 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/formatter/qual/ConversionCategory.java +++ b/src/java.base/share/classes/org/checkerframework/checker/formatter/qual/ConversionCategory.java @@ -2,7 +2,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.framework.qual.AnnotatedFor; import java.math.BigDecimal; import java.math.BigInteger; @@ -35,7 +34,6 @@ * @checker_framework.manual #formatter-checker Format String Checker */ @SuppressWarnings("unchecked") // ".class" expressions in varargs position -@AnnotatedFor({"initialization", "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 */), @@ -146,7 +144,7 @@ public enum ConversionCategory { typesWithPrimitives.add(unwrapped); } } - this.types = typesWithPrimitives.toArray(new Class[typesWithPrimitives.size()]); + this.types = typesWithPrimitives.toArray(new Class[0]); } } diff --git a/src/java.base/share/classes/org/checkerframework/checker/i18nformatter/qual/I18nConversionCategory.java b/src/java.base/share/classes/org/checkerframework/checker/i18nformatter/qual/I18nConversionCategory.java index e8ec0a2d762..642ac30d5f4 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/i18nformatter/qual/I18nConversionCategory.java +++ b/src/java.base/share/classes/org/checkerframework/checker/i18nformatter/qual/I18nConversionCategory.java @@ -1,7 +1,6 @@ package org.checkerframework.checker.i18nformatter.qual; import org.checkerframework.checker.nullness.qual.Nullable; -import org.checkerframework.framework.qual.AnnotatedFor; import java.util.Arrays; import java.util.Date; @@ -22,7 +21,6 @@ * * @checker_framework.manual #i18n-formatter-checker Internationalization Format String Checker */ -@AnnotatedFor({"initialization", "nullness"}) public enum I18nConversionCategory { /** @@ -96,7 +94,7 @@ private static Set arrayToSet(E[] a) { } /** - * Return true if a is a subset of b. + * Returns true if a is a subset of b. * * @return true if a is a subset of b */ diff --git a/src/java.base/share/classes/org/checkerframework/checker/index/qual/BottomGrowShrink.java b/src/java.base/share/classes/org/checkerframework/checker/index/qual/BottomGrowShrink.java new file mode 100644 index 00000000000..95f336c5e09 --- /dev/null +++ b/src/java.base/share/classes/org/checkerframework/checker/index/qual/BottomGrowShrink.java @@ -0,0 +1,22 @@ +package org.checkerframework.checker.index.qual; + +import org.checkerframework.framework.qual.SubtypeOf; + +import 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 bottom qualifier in the GrowShrink hierarchy. Programmers should rarely write this type. + * + * @checker_framework.manual #bottom-type the bottom type + */ +// Reinstate when lists are supported: +// * @checker_framework.manual #growonly-checker Grow-only Checker +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) +@SubtypeOf({GrowOnly.class, UncheckedShrinkable.class}) +public @interface BottomGrowShrink {} diff --git a/src/java.base/share/classes/org/checkerframework/checker/index/qual/EnsuresLTLengthOf.java b/src/java.base/share/classes/org/checkerframework/checker/index/qual/EnsuresLTLengthOf.java index abc186b8321..526980b78e2 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/index/qual/EnsuresLTLengthOf.java +++ b/src/java.base/share/classes/org/checkerframework/checker/index/qual/EnsuresLTLengthOf.java @@ -22,7 +22,9 @@ * {@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(); + * if (newEnd < 0) { + * throw new RuntimeException(); + * } * end = newEnd; * } * } @@ -98,7 +100,7 @@ @InheritedAnnotation public static @interface List { /** - * Return the repeatable annotations. + * Returns the repeatable annotations. * * @return the repeatable annotations */ diff --git a/src/java.base/share/classes/org/checkerframework/checker/index/qual/EnsuresLTLengthOfIf.java b/src/java.base/share/classes/org/checkerframework/checker/index/qual/EnsuresLTLengthOfIf.java index b0630a0e2f3..1eb982bb272 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/index/qual/EnsuresLTLengthOfIf.java +++ b/src/java.base/share/classes/org/checkerframework/checker/index/qual/EnsuresLTLengthOfIf.java @@ -108,7 +108,7 @@ @InheritedAnnotation public static @interface List { /** - * Return the repeatable annotations. + * Returns the repeatable annotations. * * @return the repeatable annotations */ diff --git a/src/java.base/share/classes/org/checkerframework/checker/index/qual/GrowOnly.java b/src/java.base/share/classes/org/checkerframework/checker/index/qual/GrowOnly.java new file mode 100644 index 00000000000..3648a73d1c7 --- /dev/null +++ b/src/java.base/share/classes/org/checkerframework/checker/index/qual/GrowOnly.java @@ -0,0 +1,22 @@ +package org.checkerframework.checker.index.qual; + +import org.checkerframework.framework.qual.SubtypeOf; + +import 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 expression of type {@code @GrowOnly} may not be used to remove elements, e.g., by calling + * {@code remove()} or {@code clear()} on it. The underlying collection is guaranteed not to shrink + * via operations on aliases. + */ +// Reinstate when lists are supported: +// * @checker_framework.manual #growonly-checker Grow-only Checker +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) +@SubtypeOf({UnshrinkableRef.class}) +public @interface GrowOnly {} diff --git a/src/java.base/share/classes/org/checkerframework/checker/index/qual/IndexFor.java b/src/java.base/share/classes/org/checkerframework/checker/index/qual/IndexFor.java index e08773c837e..3a0a4a7d1ed 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/index/qual/IndexFor.java +++ b/src/java.base/share/classes/org/checkerframework/checker/index/qual/IndexFor.java @@ -19,7 +19,7 @@ * *

{@code
  * class String {
- *   char charAt(@IndexFor("this") index) { ... }
+ *   char charAt(@IndexFor("this") int index) { ... }
  * }
  * }
* diff --git a/src/java.base/share/classes/org/checkerframework/checker/index/qual/PolyGrowShrink.java b/src/java.base/share/classes/org/checkerframework/checker/index/qual/PolyGrowShrink.java new file mode 100644 index 00000000000..03f151a914d --- /dev/null +++ b/src/java.base/share/classes/org/checkerframework/checker/index/qual/PolyGrowShrink.java @@ -0,0 +1,23 @@ +package org.checkerframework.checker.index.qual; + +import org.checkerframework.framework.qual.PolymorphicQualifier; + +import 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 polymorphic qualifier for @GrowOnly type system. + * + * @checker_framework.manual #index-checker Index Checker + * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism + */ +// Reinstate when lists are supported: +// * @checker_framework.manual #growonly-checker Grow-only Checker +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) +@PolymorphicQualifier(UnshrinkableRef.class) +public @interface PolyGrowShrink {} diff --git a/src/java.base/share/classes/org/checkerframework/checker/optional/qual/OptionalBottom.java b/src/java.base/share/classes/org/checkerframework/checker/index/qual/Shrinkable.java similarity index 50% rename from src/java.base/share/classes/org/checkerframework/checker/optional/qual/OptionalBottom.java rename to src/java.base/share/classes/org/checkerframework/checker/index/qual/Shrinkable.java index 3205701f76b..44aa707b816 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/optional/qual/OptionalBottom.java +++ b/src/java.base/share/classes/org/checkerframework/checker/index/qual/Shrinkable.java @@ -1,4 +1,4 @@ -package org.checkerframework.checker.optional.qual; +package org.checkerframework.checker.index.qual; import org.checkerframework.framework.qual.SubtypeOf; @@ -9,13 +9,13 @@ import java.lang.annotation.Target; /** - * 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 + * An expression of type {@code @Shrinkable} may be used to remove elements, e.g., by calling {@code + * remove()} or {@code clear()} on it. */ +// Reinstate when lists are supported: +// * @checker_framework.manual #growonly-checker Grow-only Checker @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) -@SubtypeOf({Present.class}) -public @interface OptionalBottom {} +@SubtypeOf({UnshrinkableRef.class}) +public @interface Shrinkable {} diff --git a/src/java.base/share/classes/org/checkerframework/checker/index/qual/UncheckedShrinkable.java b/src/java.base/share/classes/org/checkerframework/checker/index/qual/UncheckedShrinkable.java new file mode 100644 index 00000000000..559cfc410dc --- /dev/null +++ b/src/java.base/share/classes/org/checkerframework/checker/index/qual/UncheckedShrinkable.java @@ -0,0 +1,30 @@ +package org.checkerframework.checker.index.qual; + +import org.checkerframework.framework.qual.SubtypeOf; + +import 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 expression of type {@code @UncheckedShrinkable} may be used to remove elements, e.g., by + * calling {@code remove()} or {@code clear()} on it. + * + *

The Index Checker does not issue warnings about possible {@code IndexOutOfBoundsException}s + * when the collection has type {@code UncheckedShrinkable}. + * + *

Thus, {@code @UncheckedShrinkable} is combination of {@code @}{@link Shrinkable} and a warning + * suppression. It is particularly useful when first annotating a codebase, to temporarily suppress + * some warnings while focusing on others. + * + * @checker_framework.manual #index-checker Index Checker + */ +// Reinstate when lists are supported: +// * @checker_framework.manual #growonly-checker Grow-only Checker +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) +@SubtypeOf({Shrinkable.class}) +public @interface UncheckedShrinkable {} diff --git a/src/java.base/share/classes/org/checkerframework/checker/index/qual/UnshrinkableRef.java b/src/java.base/share/classes/org/checkerframework/checker/index/qual/UnshrinkableRef.java new file mode 100644 index 00000000000..027507ebd47 --- /dev/null +++ b/src/java.base/share/classes/org/checkerframework/checker/index/qual/UnshrinkableRef.java @@ -0,0 +1,26 @@ +package org.checkerframework.checker.index.qual; + +import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; +import org.checkerframework.framework.qual.InvisibleQualifier; +import org.checkerframework.framework.qual.SubtypeOf; + +import 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 expression of type {@code @UnshrinkableRef} may not be used to remove elements, e.g., by + * calling {@code remove()} or {@code clear()} on it. The collection might be shrunk by some other + * reference that aliases the expression of type {@code @UnshrinkableRef}. + */ +// Reinstate when lists are supported: +// * @checker_framework.manual #growonly-checker Grow-only Checker +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) +@SubtypeOf({}) +@DefaultQualifierInHierarchy +@InvisibleQualifier +public @interface UnshrinkableRef {} diff --git a/src/java.base/share/classes/org/checkerframework/checker/initialization/qual/EnsuresInitialized.java b/src/java.base/share/classes/org/checkerframework/checker/initialization/qual/EnsuresInitialized.java new file mode 100644 index 00000000000..811c76c137a --- /dev/null +++ b/src/java.base/share/classes/org/checkerframework/checker/initialization/qual/EnsuresInitialized.java @@ -0,0 +1,62 @@ +package org.checkerframework.checker.initialization.qual; + +import org.checkerframework.framework.qual.InheritedAnnotation; +import org.checkerframework.framework.qual.PostconditionAnnotation; + +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; + +/** + * A method postcondition annotation that guarantees that the given Java expressions are {@link + * Initialized} after the method terminates successfully. + * + *

This annotation is useful when a method initializes a field of an object that is currently + * {@link UnderInitialization} (or {@link UnknownInitialization}). It tells the Initialization + * Checker that the field has been assigned a value. + * + *

If the receiver is already fully {@link Initialized}, this annotation provides no new + * information and is trivially true. If you also want to guarantee that a reference field is not + * null (for the Nullness Checker), use {@link + * org.checkerframework.checker.nullness.qual.EnsuresNonNull} instead, which implies initialization + * but also provides a nullness guarantee. + * + *

Note: This is an Initialization Checker postcondition, distinct from {@link + * org.checkerframework.common.initializedfields.qual.EnsuresInitializedFields} which is used by the + * standalone Initialized Fields Checker. + * + * @checker_framework.manual #initialization-checker Initialization Checker + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) +@PostconditionAnnotation(qualifier = Initialized.class) +@InheritedAnnotation +@Repeatable(EnsuresInitialized.List.class) +public @interface EnsuresInitialized { + /** + * The Java expressions that are initialized upon successful method termination. + * + * @return the Java expressions that are initialized + * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions + */ + String[] value(); + + /** A wrapper annotation that makes the {@link EnsuresInitialized} annotation repeatable. */ + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) + @PostconditionAnnotation(qualifier = Initialized.class) + @InheritedAnnotation + public static @interface List { + /** + * Return the repeatable annotations. + * + * @return the repeatable annotations + */ + EnsuresInitialized[] value(); + } +} diff --git a/src/java.base/share/classes/org/checkerframework/checker/lock/qual/EnsuresLockHeld.java b/src/java.base/share/classes/org/checkerframework/checker/lock/qual/EnsuresLockHeld.java index 8b76dfd8562..76acd828015 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/lock/qual/EnsuresLockHeld.java +++ b/src/java.base/share/classes/org/checkerframework/checker/lock/qual/EnsuresLockHeld.java @@ -48,7 +48,7 @@ @InheritedAnnotation public static @interface List { /** - * Return the repeatable annotations. + * Returns the repeatable annotations. * * @return the repeatable annotations */ diff --git a/src/java.base/share/classes/org/checkerframework/checker/lock/qual/EnsuresLockHeldIf.java b/src/java.base/share/classes/org/checkerframework/checker/lock/qual/EnsuresLockHeldIf.java index 2e4ca1c556a..4b25377e10c 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/lock/qual/EnsuresLockHeldIf.java +++ b/src/java.base/share/classes/org/checkerframework/checker/lock/qual/EnsuresLockHeldIf.java @@ -36,8 +36,8 @@ * 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 + * @return the Java expressions whose values are locks that are held after the method returns + * the given result * @see Syntax of * Java expressions */ @@ -59,7 +59,7 @@ @InheritedAnnotation public static @interface List { /** - * Return the repeatable annotations. + * Returns the repeatable annotations. * * @return the repeatable annotations */ diff --git a/src/java.base/share/classes/org/checkerframework/checker/mustcall/qual/CreatesMustCallFor.java b/src/java.base/share/classes/org/checkerframework/checker/mustcall/qual/CreatesMustCallFor.java index b1c71880a61..be2690f41dd 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/mustcall/qual/CreatesMustCallFor.java +++ b/src/java.base/share/classes/org/checkerframework/checker/mustcall/qual/CreatesMustCallFor.java @@ -104,7 +104,7 @@ @InheritedAnnotation public static @interface List { /** - * Return the repeatable annotations. + * Returns the repeatable annotations. * * @return the repeatable annotations */ diff --git a/src/java.base/share/classes/org/checkerframework/checker/mustcall/qual/MustCall.java b/src/java.base/share/classes/org/checkerframework/checker/mustcall/qual/MustCall.java index c9357960e9f..c646dfbf5c8 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/mustcall/qual/MustCall.java +++ b/src/java.base/share/classes/org/checkerframework/checker/mustcall/qual/MustCall.java @@ -14,9 +14,9 @@ * 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. * - *

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. + *

This annotation can be enforced by running the Resource Leak Checker. It enforces that the + * methods {@code m1()} and {@code m2()} are called on the annotated expression before it is + * deallocated. * *

The subtyping relationship is: * diff --git a/src/java.base/share/classes/org/checkerframework/checker/mustcall/qual/MustCallUnknown.java b/src/java.base/share/classes/org/checkerframework/checker/mustcall/qual/MustCallUnknown.java index 7f234fc1fac..3b42d05c232 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/mustcall/qual/MustCallUnknown.java +++ b/src/java.base/share/classes/org/checkerframework/checker/mustcall/qual/MustCallUnknown.java @@ -12,9 +12,9 @@ * 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. * - *

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. + *

The Resource Leak Checker cannot verify that the property represented by this annotation is + * enforced; that is, the Resource Leak 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 */ diff --git a/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/EnsuresNonEmpty.java b/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/EnsuresNonEmpty.java index d997df2fc83..17993d6c3e6 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/EnsuresNonEmpty.java +++ b/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/EnsuresNonEmpty.java @@ -1,11 +1,12 @@ package org.checkerframework.checker.nonempty.qual; +import org.checkerframework.framework.qual.InheritedAnnotation; +import org.checkerframework.framework.qual.PostconditionAnnotation; + import 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; -import org.checkerframework.framework.qual.PostconditionAnnotation; /** * Indicates that a particular expression evaluates to a non-empty value, if the method terminates @@ -35,19 +36,20 @@ * * @see NonEmpty * @see org.checkerframework.checker.nonempty.NonEmptyChecker - * @checker_framework.manual #non-empty-checker Non-Empty Checker */ +// Reinstate when the Non-Empty Checker is publicized. +// * @checker_framework.manual #non-empty-checker Non-Empty Checker @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) @PostconditionAnnotation(qualifier = NonEmpty.class) @InheritedAnnotation public @interface EnsuresNonEmpty { - /** - * The expression (a collection, iterator, iterable, or map) that is non-empty, if the method - * returns normally. - * - * @return the expression (a collection, iterator, iterable, or map) that is non-empty, if the - * method returns normally - */ - String[] value(); + /** + * The expression (a collection, iterator, iterable, or map) that is non-empty, if the method + * returns normally. + * + * @return the expression (a collection, iterator, iterable, or map) that is non-empty, if the + * method returns normally + */ + String[] value(); } diff --git a/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/EnsuresNonEmptyIf.java b/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/EnsuresNonEmptyIf.java index b5af54e90cd..83600e58e00 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/EnsuresNonEmptyIf.java +++ b/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/EnsuresNonEmptyIf.java @@ -1,12 +1,13 @@ package org.checkerframework.checker.nonempty.qual; +import org.checkerframework.framework.qual.ConditionalPostconditionAnnotation; +import org.checkerframework.framework.qual.InheritedAnnotation; + import java.lang.annotation.Documented; import java.lang.annotation.ElementType; 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 specific expressions are non-empty, if the method returns the given result @@ -44,8 +45,9 @@ * * @see NonEmpty * @see EnsuresNonEmpty - * @checker_framework.manual #non-empty-checker Non-Empty Checker */ +// Reinstate when the Non-Empty Checker is publicized. +// * @checker_framework.manual #non-empty-checker Non-Empty Checker @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) @@ -53,35 +55,35 @@ @InheritedAnnotation public @interface EnsuresNonEmptyIf { - /** - * A return value of the method; when the method returns that value, the postcondition holds. - * - * @return the return value of the method for which the postcondition holds - */ - boolean result(); + /** + * A return value of the method; when the method returns that value, the postcondition holds. + * + * @return the return value of the method for which the postcondition holds + */ + boolean result(); - /** - * Returns the Java expressions that are non-empty after the method returns the given result. - * - * @return the Java expressions that are non-empty after the method returns the given result - */ - String[] expression(); + /** + * Returns the Java expressions that are non-empty after the method returns the given result. + * + * @return the Java expressions that are non-empty after the method returns the given result + */ + String[] expression(); - /** - * A wrapper annotation that makes the {@link EnsuresNonEmptyIf} annotation repeatable. - * - *

Programmers generally do not need to write ths. It is created by Java when a programmer - * writes more than one {@link EnsuresNonEmptyIf} annotation at the same location. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) - @ConditionalPostconditionAnnotation(qualifier = NonEmpty.class) - @interface List { /** - * Returns the repeatable annotations. + * A wrapper annotation that makes the {@link EnsuresNonEmptyIf} annotation repeatable. * - * @return the repeatable annotations + *

Programmers generally do not need to write ths. It is created by Java when a programmer + * writes more than one {@link EnsuresNonEmptyIf} annotation at the same location. */ - EnsuresNonEmptyIf[] value(); - } + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) + @ConditionalPostconditionAnnotation(qualifier = NonEmpty.class) + @interface List { + /** + * Returns the repeatable annotations. + * + * @return the repeatable annotations + */ + EnsuresNonEmptyIf[] value(); + } } diff --git a/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/NonEmpty.java b/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/NonEmpty.java index d5a7f8c15d5..cd340f2c163 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/NonEmpty.java +++ b/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/NonEmpty.java @@ -1,18 +1,20 @@ package org.checkerframework.checker.nonempty.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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.Collection Collection}, {@link java.util.Iterator Iterator}, {@link - * java.lang.Iterable Iterable}, or {@link java.util.Map Map} is definitely non-empty. - * - * @checker_framework.manual #non-empty-checker Non-Empty Checker + * The {@link java.util.Collection Collection}, {@link java.util.Iterator Iterator}, {@link Iterable + * Iterable}, or {@link java.util.Map Map}, or {@link java.util.stream.Stream Stream} is definitely + * non-empty. */ +// Reinstate when the Non-Empty Checker is publicized. +// * @checker_framework.manual #non-empty-checker Non-Empty Checker @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) diff --git a/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/PolyNonEmpty.java b/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/PolyNonEmpty.java index dd538314595..e70fd57eabd 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/PolyNonEmpty.java +++ b/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/PolyNonEmpty.java @@ -1,18 +1,20 @@ package org.checkerframework.checker.nonempty.qual; +import org.checkerframework.framework.qual.PolymorphicQualifier; + import java.lang.annotation.Documented; import 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-Empty type system. * - * @checker_framework.manual #non-empty-checker Non-Empty Checker * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism */ +// Reinstate when the Non-Empty Checker is publicized. +// * @checker_framework.manual #non-empty-checker Non-Empty Checker @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) diff --git a/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/RequiresNonEmpty.java b/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/RequiresNonEmpty.java index 45b46d4233d..7deeeef4306 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/RequiresNonEmpty.java +++ b/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/RequiresNonEmpty.java @@ -1,11 +1,13 @@ package org.checkerframework.checker.nonempty.qual; +import org.checkerframework.framework.qual.PreconditionAnnotation; + 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.PreconditionAnnotation; /** * Indicates a method precondition: the specified expressions that may be a {@link @@ -62,35 +64,40 @@ * This annotation should not be used for formal parameters (instead, give them a {@code @NonEmpty} * type). The {@code @RequiresNonEmpty} annotation is intended for non-parameter expressions, such * as field accesses or method calls. - * - * @checker_framework.manual #non-empty-checker Non-Empty Checker */ +// Reinstate when the Non-Empty Checker is publicized. +// * @checker_framework.manual #non-empty-checker Non-Empty Checker @Documented @Retention(RetentionPolicy.RUNTIME) +@Repeatable(RequiresNonEmpty.List.class) @Target({ElementType.METHOD, ElementType.PARAMETER}) @PreconditionAnnotation(qualifier = NonEmpty.class) public @interface RequiresNonEmpty { - /** - * The Java {@link java.util.Collection collection}, {@link java.util.Iterator iterator}, {@link - * java.lang.Iterable iterable}, or {@link java.util.Map map} that must be non-empty. - * - * @return the Java expression that must be non-empty - */ - String[] value(); + /** + * The Java {@link java.util.Collection collection}, {@link java.util.Iterator iterator}, {@link + * java.lang.Iterable iterable}, or {@link java.util.Map map} that must be non-empty. + * + * @return the Java expression that must be non-empty + */ + String[] value(); - /** - * A wrapper annotation that makes the {@link RequiresNonEmpty} annotation repeatable. - * - *

Programmers generally do not need to write this. It is created by Java when a programmer - * writes more than one {@link RequiresNonEmpty} annotation at the same location. - */ - @interface List { /** - * Returns the repeatable annotations. + * A wrapper annotation that makes the {@link RequiresNonEmpty} annotation repeatable. * - * @return the repeatable annotations + *

Programmers generally do not need to write this. It is created by Java when a programmer + * writes more than one {@link RequiresNonEmpty} annotation at the same location. */ - RequiresNonEmpty[] value(); - } + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD, ElementType.PARAMETER}) + @PreconditionAnnotation(qualifier = NonEmpty.class) + @interface List { + /** + * Returns the repeatable annotations. + * + * @return the repeatable annotations + */ + RequiresNonEmpty[] value(); + } } diff --git a/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/UnknownNonEmpty.java b/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/UnknownNonEmpty.java index 65900f7fa12..93b062e51e9 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/UnknownNonEmpty.java +++ b/src/java.base/share/classes/org/checkerframework/checker/nonempty/qual/UnknownNonEmpty.java @@ -1,19 +1,21 @@ package org.checkerframework.checker.nonempty.qual; +import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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.Collection Collection}, {@link java.util.Iterator Iterator}, {@link - * java.lang.Iterable Iterable}, or {@link java.util.Map Map} may or may not be empty. - * - * @checker_framework.manual #non-empty-checker Non-Empty Checker + * java.lang.Iterable Iterable}, {@link java.util.Map Map}, or {@link java.util.stream.Stream + * Stream} may or may not be empty. */ +// Reinstate when the Non-Empty Checker is publicized. +// * @checker_framework.manual #non-empty-checker Non-Empty Checker @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) diff --git a/src/java.base/share/classes/org/checkerframework/checker/optional/qual/EnsuresPresent.java b/src/java.base/share/classes/org/checkerframework/checker/optional/qual/EnsuresPresent.java index a0037970bf8..e96a1552312 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/optional/qual/EnsuresPresent.java +++ b/src/java.base/share/classes/org/checkerframework/checker/optional/qual/EnsuresPresent.java @@ -10,10 +10,10 @@ import java.lang.annotation.Target; /** - * Indicates that the expression evaluates to a non-empty Optional, if the method terminates + * Indicates that the expression evaluates to a present Optional, if the method terminates * successfully. * - *

This postcondition annotation is useful for methods that construct a non-empty Optional: + *

This postcondition annotation is useful for methods that construct a present Optional: * *


  *   {@literal @}EnsuresPresent("optStr")
diff --git a/src/java.base/share/classes/org/checkerframework/checker/signature/qual/BinaryNameWithoutPackage.java b/src/java.base/share/classes/org/checkerframework/checker/signature/qual/BinaryNameWithoutPackage.java
deleted file mode 100644
index becf579afed..00000000000
--- a/src/java.base/share/classes/org/checkerframework/checker/signature/qual/BinaryNameWithoutPackage.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.checkerframework.checker.signature.qual;
-
-import org.checkerframework.framework.qual.SubtypeOf;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * 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).
- *
- * 

Examples: - * - *

{@code
- * MyClass
- * MyClass$22
- * }
- * - * @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/src/java.base/share/classes/org/checkerframework/checker/signature/qual/CanonicalName.java b/src/java.base/share/classes/org/checkerframework/checker/signature/qual/CanonicalName.java index 862398dfc86..7c35c7eb2a5 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/signature/qual/CanonicalName.java +++ b/src/java.base/share/classes/org/checkerframework/checker/signature/qual/CanonicalName.java @@ -17,7 +17,6 @@ * 6.7 gives the following example: * *
- * * The difference between a fully qualified name and a canonical name can be seen in code such as: * *
{@code
@@ -28,7 +27,6 @@
  *
  * 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.
- *
  * 
* * Given a character sequence that is a fully-qualified name, there is no way to know whether or not diff --git a/src/java.base/share/classes/org/checkerframework/checker/signature/qual/Identifier.java b/src/java.base/share/classes/org/checkerframework/checker/signature/qual/Identifier.java index 31126dd0644..8d8a2981318 100644 --- a/src/java.base/share/classes/org/checkerframework/checker/signature/qual/Identifier.java +++ b/src/java.base/share/classes/org/checkerframework/checker/signature/qual/Identifier.java @@ -13,11 +13,7 @@ * * @checker_framework.manual #signature-checker Signature Checker */ -@SubtypeOf({ - DotSeparatedIdentifiers.class, - BinaryNameWithoutPackage.class, - IdentifierOrPrimitiveType.class -}) +@SubtypeOf({DotSeparatedIdentifiers.class, IdentifierOrPrimitiveType.class, InternalForm.class}) @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) diff --git a/src/java.base/share/classes/org/checkerframework/checker/sqlquotes/qual/SqlEvenQuotes.java b/src/java.base/share/classes/org/checkerframework/checker/sqlquotes/qual/SqlEvenQuotes.java new file mode 100644 index 00000000000..af3631f7e3d --- /dev/null +++ b/src/java.base/share/classes/org/checkerframework/checker/sqlquotes/qual/SqlEvenQuotes.java @@ -0,0 +1,28 @@ +package org.checkerframework.checker.sqlquotes.qual; + +import org.checkerframework.framework.qual.SubtypeOf; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Denotes a String that contains either zero or an even number of unescaped single quotes — + * i.e., there must be either zero or an even number of {@code '} characters in a SqlEvenQuotes + * String that are not preceded immediately by another {@code '} character. (Thus, all SqlEvenQuotes + * Strings ultimately contain an even number of {@code '} characters.) A SqlEvenQuotes String is + * syntactical to be passed to query execution methods and is guaranteed not to affect whether + * subsequent concatenations are interpreted as SQL command code or as SQL query values. + * + *

Common use cases include: SQL query fragments, such as "SELECT * FROM"; properly sanitized + * user input; and complete SQL queries, such as "SELECT * FROM table WHERE field = 'value'". + * + * @checker_framework.manual #sql-quotes-checker SQL Quotes Checker + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) +@SubtypeOf(SqlQuotesUnknown.class) +public @interface SqlEvenQuotes {} diff --git a/src/java.base/share/classes/org/checkerframework/checker/sqlquotes/qual/SqlOddQuotes.java b/src/java.base/share/classes/org/checkerframework/checker/sqlquotes/qual/SqlOddQuotes.java new file mode 100644 index 00000000000..63735eec194 --- /dev/null +++ b/src/java.base/share/classes/org/checkerframework/checker/sqlquotes/qual/SqlOddQuotes.java @@ -0,0 +1,30 @@ +package org.checkerframework.checker.sqlquotes.qual; + +import org.checkerframework.framework.qual.SubtypeOf; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Denotes a String that contains an odd number of unescaped single quotes -- i.e., there must be an + * odd number of ' characters in a SqlOddQuotes String that are not preceded immediately by another + * ' character. (Thus, all SqlOddQuotes Strings ultimately contain an odd number of single quotes, + * escaped or otherwise.) SqlOddQuotes Strings are not syntactical to be passed to query execution + * methods. + * + *

Common use cases include: SQL query fragments to be concatenated with user input, such as + * "SELECT * FROM table WHERE field = '"; SQL query fragments containing user input but missing an + * ending single quote, such as "SELECT * FROM table WHERE field = 'value"; connecting punctuation, + * such as "', "; and any combinations of the above with paired-off single quotes, such as "SELECT * + * FROM table WHERE field1 = 'value1', field2 = 'value2', field3 = '". + * + * @checker_framework.manual #sql-quotes-checker SQL Quotes Checker + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) +@SubtypeOf(SqlQuotesUnknown.class) +public @interface SqlOddQuotes {} diff --git a/src/java.base/share/classes/org/checkerframework/checker/sqlquotes/qual/SqlQuotesBottom.java b/src/java.base/share/classes/org/checkerframework/checker/sqlquotes/qual/SqlQuotesBottom.java new file mode 100644 index 00000000000..7d0f77c14c8 --- /dev/null +++ b/src/java.base/share/classes/org/checkerframework/checker/sqlquotes/qual/SqlQuotesBottom.java @@ -0,0 +1,28 @@ +package org.checkerframework.checker.sqlquotes.qual; + +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; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Represents the bottom of the SQL Quotes qualifier hierarchy. + * + * @checker_framework.manual #sql-quotes-checker SQL Quotes Checker + * @checker_framework.manual #bottom-type the bottom type + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) +@TargetLocations({TypeUseLocation.LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND}) +@InvisibleQualifier +@SubtypeOf({SqlEvenQuotes.class, SqlOddQuotes.class}) +@DefaultFor(value = {TypeUseLocation.LOWER_BOUND}) +public @interface SqlQuotesBottom {} diff --git a/src/java.base/share/classes/org/checkerframework/checker/sqlquotes/qual/SqlQuotesUnknown.java b/src/java.base/share/classes/org/checkerframework/checker/sqlquotes/qual/SqlQuotesUnknown.java new file mode 100644 index 00000000000..f0ea9e0182b --- /dev/null +++ b/src/java.base/share/classes/org/checkerframework/checker/sqlquotes/qual/SqlQuotesUnknown.java @@ -0,0 +1,26 @@ +package org.checkerframework.checker.sqlquotes.qual; + +import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; +import org.checkerframework.framework.qual.SubtypeOf; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Represents the top of the SQL Quotes qualifier hierarchy. Used to denote a String of which the + * quoting is unknown. Using a SqlQuotesUnknown Strings within a SQL query may be, or lead to, a SQL + * injection vulnerability. + * + *

Common use cases include unsanitized user input. + * + * @checker_framework.manual #sql-quotes-checker SQL Quotes Checker + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) +@SubtypeOf({}) +@DefaultQualifierInHierarchy +public @interface SqlQuotesUnknown {} diff --git a/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/LeakedToResult.java b/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/LeakedToResult.java index b93160bde9c..2fa75945acb 100644 --- a/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/LeakedToResult.java +++ b/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/LeakedToResult.java @@ -1,11 +1,12 @@ package org.checkerframework.common.aliasing.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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 diff --git a/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/MaybeAliased.java b/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/MaybeAliased.java index 241fdcbd9d4..409382e15e3 100644 --- a/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/MaybeAliased.java +++ b/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/MaybeAliased.java @@ -1,14 +1,15 @@ package org.checkerframework.common.aliasing.qual; +import org.checkerframework.framework.qual.DefaultFor; +import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; +import org.checkerframework.framework.qual.SubtypeOf; +import org.checkerframework.framework.qual.TypeUseLocation; + import java.lang.annotation.Documented; import 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, @@ -23,6 +24,6 @@ @SubtypeOf({}) @DefaultQualifierInHierarchy @DefaultFor( - value = {TypeUseLocation.UPPER_BOUND, TypeUseLocation.LOWER_BOUND}, - types = Void.class) + value = {TypeUseLocation.UPPER_BOUND, TypeUseLocation.LOWER_BOUND}, + types = Void.class) public @interface MaybeAliased {} diff --git a/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/MaybeLeaked.java b/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/MaybeLeaked.java index 9038b6b75b0..0d421fc3242 100644 --- a/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/MaybeLeaked.java +++ b/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/MaybeLeaked.java @@ -1,12 +1,13 @@ package org.checkerframework.common.aliasing.qual; +import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; +import org.checkerframework.framework.qual.InvisibleQualifier; +import org.checkerframework.framework.qual.SubtypeOf; + 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: diff --git a/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/NonLeaked.java b/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/NonLeaked.java index ad0b07366d5..2417f2e4275 100644 --- a/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/NonLeaked.java +++ b/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/NonLeaked.java @@ -1,11 +1,12 @@ package org.checkerframework.common.aliasing.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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 diff --git a/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/Unique.java b/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/Unique.java index 61945114567..af66458ffa7 100644 --- a/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/Unique.java +++ b/src/java.base/share/classes/org/checkerframework/common/aliasing/qual/Unique.java @@ -1,11 +1,12 @@ package org.checkerframework.common.aliasing.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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 diff --git a/src/java.base/share/classes/org/checkerframework/common/initializedfields/qual/EnsuresInitializedFields.java b/src/java.base/share/classes/org/checkerframework/common/initializedfields/qual/EnsuresInitializedFields.java index 11e768f2294..85d7b3680c7 100644 --- a/src/java.base/share/classes/org/checkerframework/common/initializedfields/qual/EnsuresInitializedFields.java +++ b/src/java.base/share/classes/org/checkerframework/common/initializedfields/qual/EnsuresInitializedFields.java @@ -1,14 +1,15 @@ package org.checkerframework.common.initializedfields.qual; +import org.checkerframework.framework.qual.InheritedAnnotation; +import org.checkerframework.framework.qual.PostconditionAnnotation; +import org.checkerframework.framework.qual.QualifierArgument; + 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. @@ -22,38 +23,38 @@ @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"}; + /** + * 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(); + /** + * 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. - * - *

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 - public static @interface List { /** - * Return the repeatable annotations. + * A wrapper annotation that makes the {@link EnsuresInitializedFields} annotation repeatable. * - * @return the repeatable annotations + *

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. */ - EnsuresInitializedFields[] value(); - } + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) + @PostconditionAnnotation(qualifier = InitializedFields.class) + @InheritedAnnotation + public static @interface List { + /** + * Returns the repeatable annotations. + * + * @return the repeatable annotations + */ + EnsuresInitializedFields[] value(); + } } diff --git a/src/java.base/share/classes/org/checkerframework/common/initializedfields/qual/InitializedFields.java b/src/java.base/share/classes/org/checkerframework/common/initializedfields/qual/InitializedFields.java index d83042cc0a0..18ea2e2693a 100644 --- a/src/java.base/share/classes/org/checkerframework/common/initializedfields/qual/InitializedFields.java +++ b/src/java.base/share/classes/org/checkerframework/common/initializedfields/qual/InitializedFields.java @@ -1,11 +1,12 @@ package org.checkerframework.common.initializedfields.qual; +import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; +import org.checkerframework.framework.qual.SubtypeOf; + import 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. @@ -17,10 +18,10 @@ @SubtypeOf({}) @DefaultQualifierInHierarchy public @interface InitializedFields { - /** - * Fields that have been initialized. - * - * @return the initialized fields - */ - public String[] value() default {}; + /** + * Fields that have been initialized. + * + * @return the initialized fields + */ + public String[] value() default {}; } diff --git a/src/java.base/share/classes/org/checkerframework/common/initializedfields/qual/InitializedFieldsBottom.java b/src/java.base/share/classes/org/checkerframework/common/initializedfields/qual/InitializedFieldsBottom.java index 2f16939d206..628c199eca5 100644 --- a/src/java.base/share/classes/org/checkerframework/common/initializedfields/qual/InitializedFieldsBottom.java +++ b/src/java.base/share/classes/org/checkerframework/common/initializedfields/qual/InitializedFieldsBottom.java @@ -1,12 +1,13 @@ package org.checkerframework.common.initializedfields.qual; +import org.checkerframework.framework.qual.SubtypeOf; +import org.checkerframework.framework.qual.TargetLocations; +import org.checkerframework.framework.qual.TypeUseLocation; + import 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}. @@ -17,5 +18,5 @@ @SubtypeOf({InitializedFields.class}) @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) -@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND}) +@TargetLocations({TypeUseLocation.LOWER_BOUND, TypeUseLocation.UPPER_BOUND}) public @interface InitializedFieldsBottom {} diff --git a/src/java.base/share/classes/org/checkerframework/common/initializedfields/qual/PolyInitializedFields.java b/src/java.base/share/classes/org/checkerframework/common/initializedfields/qual/PolyInitializedFields.java index 1f25542d80a..7b8788cbe89 100644 --- a/src/java.base/share/classes/org/checkerframework/common/initializedfields/qual/PolyInitializedFields.java +++ b/src/java.base/share/classes/org/checkerframework/common/initializedfields/qual/PolyInitializedFields.java @@ -1,14 +1,20 @@ package org.checkerframework.common.initializedfields.qual; +import org.checkerframework.framework.qual.PolymorphicQualifier; + +import java.lang.annotation.Documented; import 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; /** * Polymorphic qualifier for the Initialized Fields type system. * * @checker_framework.manual #initialized-fields-checker Initialized Fields Checker */ +@Documented +@Retention(RetentionPolicy.RUNTIME) @PolymorphicQualifier(InitializedFields.class) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) public @interface PolyInitializedFields {} diff --git a/src/java.base/share/classes/org/checkerframework/common/reflection/qual/ClassBound.java b/src/java.base/share/classes/org/checkerframework/common/reflection/qual/ClassBound.java index 0cae3ff79e3..8aa0aee983f 100644 --- a/src/java.base/share/classes/org/checkerframework/common/reflection/qual/ClassBound.java +++ b/src/java.base/share/classes/org/checkerframework/common/reflection/qual/ClassBound.java @@ -1,11 +1,12 @@ package org.checkerframework.common.reflection.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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} object whose run-time value is equal to or a subtype of one of @@ -18,9 +19,9 @@ @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @SubtypeOf({UnknownClass.class}) public @interface ClassBound { - /** - * The binary - * name of the class or classes that upper-bound the values of this Class object. - */ - String[] value(); + /** + * The binary + * name of the class or classes that upper-bound the values of this Class object. + */ + String[] value(); } diff --git a/src/java.base/share/classes/org/checkerframework/common/reflection/qual/ClassVal.java b/src/java.base/share/classes/org/checkerframework/common/reflection/qual/ClassVal.java index 424efe40bb8..3fb622077f0 100644 --- a/src/java.base/share/classes/org/checkerframework/common/reflection/qual/ClassVal.java +++ b/src/java.base/share/classes/org/checkerframework/common/reflection/qual/ClassVal.java @@ -1,11 +1,12 @@ package org.checkerframework.common.reflection.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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 @@ -19,13 +20,13 @@ @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 binary name, - * possibly followed by some number of array brackets. - * - * @return the name of the type that this Class object represents - */ - String[] value(); + /** + * 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 binary + * name, possibly followed by some number of array brackets. + * + * @return the name of the type that this Class object represents + */ + String[] value(); } diff --git a/src/java.base/share/classes/org/checkerframework/common/reflection/qual/ClassValBottom.java b/src/java.base/share/classes/org/checkerframework/common/reflection/qual/ClassValBottom.java index 757845f4e03..e68c8281686 100644 --- a/src/java.base/share/classes/org/checkerframework/common/reflection/qual/ClassValBottom.java +++ b/src/java.base/share/classes/org/checkerframework/common/reflection/qual/ClassValBottom.java @@ -1,14 +1,15 @@ package org.checkerframework.common.reflection.qual; +import org.checkerframework.framework.qual.InvisibleQualifier; +import org.checkerframework.framework.qual.SubtypeOf; +import org.checkerframework.framework.qual.TargetLocations; +import org.checkerframework.framework.qual.TypeUseLocation; + import java.lang.annotation.Documented; import 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. @@ -19,7 +20,7 @@ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) -@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND}) +@TargetLocations({TypeUseLocation.LOWER_BOUND, TypeUseLocation.UPPER_BOUND}) @InvisibleQualifier @SubtypeOf({ClassVal.class, ClassBound.class}) public @interface ClassValBottom {} diff --git a/src/java.base/share/classes/org/checkerframework/common/reflection/qual/MethodVal.java b/src/java.base/share/classes/org/checkerframework/common/reflection/qual/MethodVal.java index 3c7612321b0..1a053e6a1a4 100644 --- a/src/java.base/share/classes/org/checkerframework/common/reflection/qual/MethodVal.java +++ b/src/java.base/share/classes/org/checkerframework/common/reflection/qual/MethodVal.java @@ -1,11 +1,12 @@ package org.checkerframework.common.reflection.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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 @@ -23,17 +24,18 @@ @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @SubtypeOf({UnknownMethod.class}) public @interface MethodVal { - /** - * The binary - * name of the class that declares this method. - */ - String[] className(); + /** + * The binary + * name of the class that declares this method. + */ + String[] className(); - /** - * The name of the method that this Method object represents. Use {@code } for constructors. - */ - String[] methodName(); + /** + * The name of the method that this Method object represents. Use {@code } for + * constructors. + */ + String[] methodName(); - /** The number of parameters to the method. */ - int[] params(); + /** The number of parameters to the method. */ + int[] params(); } diff --git a/src/java.base/share/classes/org/checkerframework/common/reflection/qual/MethodValBottom.java b/src/java.base/share/classes/org/checkerframework/common/reflection/qual/MethodValBottom.java index c99f8740ccf..3e39e6b04d2 100644 --- a/src/java.base/share/classes/org/checkerframework/common/reflection/qual/MethodValBottom.java +++ b/src/java.base/share/classes/org/checkerframework/common/reflection/qual/MethodValBottom.java @@ -1,14 +1,15 @@ package org.checkerframework.common.reflection.qual; +import org.checkerframework.framework.qual.InvisibleQualifier; +import org.checkerframework.framework.qual.SubtypeOf; +import org.checkerframework.framework.qual.TargetLocations; +import org.checkerframework.framework.qual.TypeUseLocation; + import java.lang.annotation.Documented; import 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. @@ -19,7 +20,7 @@ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) -@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND}) +@TargetLocations({TypeUseLocation.LOWER_BOUND, TypeUseLocation.UPPER_BOUND}) @InvisibleQualifier @SubtypeOf({MethodVal.class}) public @interface MethodValBottom {} diff --git a/src/java.base/share/classes/org/checkerframework/common/reflection/qual/UnknownClass.java b/src/java.base/share/classes/org/checkerframework/common/reflection/qual/UnknownClass.java index f89c5e9f2c5..ccea4c45929 100644 --- a/src/java.base/share/classes/org/checkerframework/common/reflection/qual/UnknownClass.java +++ b/src/java.base/share/classes/org/checkerframework/common/reflection/qual/UnknownClass.java @@ -1,16 +1,17 @@ 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; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + /** * Represents a Class object whose run-time value is not known at compile time. Also represents * non-Class values. @@ -22,7 +23,7 @@ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) -@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND}) +@TargetLocations({TypeUseLocation.ALL}) @InvisibleQualifier @SubtypeOf({}) @DefaultQualifierInHierarchy diff --git a/src/java.base/share/classes/org/checkerframework/common/reflection/qual/UnknownMethod.java b/src/java.base/share/classes/org/checkerframework/common/reflection/qual/UnknownMethod.java index 34547759c13..bf556909632 100644 --- a/src/java.base/share/classes/org/checkerframework/common/reflection/qual/UnknownMethod.java +++ b/src/java.base/share/classes/org/checkerframework/common/reflection/qual/UnknownMethod.java @@ -1,16 +1,17 @@ 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; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + /** * 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 @@ -23,7 +24,7 @@ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) -@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND}) +@TargetLocations({TypeUseLocation.ALL}) @InvisibleQualifier @SubtypeOf({}) @DefaultQualifierInHierarchy diff --git a/src/java.base/share/classes/org/checkerframework/common/returnsreceiver/qual/BottomThis.java b/src/java.base/share/classes/org/checkerframework/common/returnsreceiver/qual/BottomThis.java index 99dd4fcb56b..a3e0f92d8bf 100644 --- a/src/java.base/share/classes/org/checkerframework/common/returnsreceiver/qual/BottomThis.java +++ b/src/java.base/share/classes/org/checkerframework/common/returnsreceiver/qual/BottomThis.java @@ -1,12 +1,13 @@ package org.checkerframework.common.returnsreceiver.qual; +import org.checkerframework.framework.qual.SubtypeOf; +import org.checkerframework.framework.qual.TargetLocations; +import org.checkerframework.framework.qual.TypeUseLocation; + import 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 @@ -18,5 +19,5 @@ @SubtypeOf({UnknownThis.class}) @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) -@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND}) +@TargetLocations({TypeUseLocation.LOWER_BOUND, TypeUseLocation.UPPER_BOUND}) public @interface BottomThis {} diff --git a/src/java.base/share/classes/org/checkerframework/common/returnsreceiver/qual/This.java b/src/java.base/share/classes/org/checkerframework/common/returnsreceiver/qual/This.java index 4d30a59c72a..646aee27a90 100644 --- a/src/java.base/share/classes/org/checkerframework/common/returnsreceiver/qual/This.java +++ b/src/java.base/share/classes/org/checkerframework/common/returnsreceiver/qual/This.java @@ -1,12 +1,13 @@ package org.checkerframework.common.returnsreceiver.qual; +import org.checkerframework.framework.qual.PolymorphicQualifier; +import org.checkerframework.framework.qual.TargetLocations; +import org.checkerframework.framework.qual.TypeUseLocation; + import 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 diff --git a/src/java.base/share/classes/org/checkerframework/common/returnsreceiver/qual/UnknownThis.java b/src/java.base/share/classes/org/checkerframework/common/returnsreceiver/qual/UnknownThis.java index 7ada21419f1..eafa025cdfd 100644 --- a/src/java.base/share/classes/org/checkerframework/common/returnsreceiver/qual/UnknownThis.java +++ b/src/java.base/share/classes/org/checkerframework/common/returnsreceiver/qual/UnknownThis.java @@ -1,9 +1,5 @@ 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.InvisibleQualifier; @@ -12,6 +8,11 @@ import org.checkerframework.framework.qual.SubtypeOf; import org.checkerframework.framework.qual.TypeUseLocation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + /** * 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. diff --git a/src/java.base/share/classes/org/checkerframework/common/subtyping/qual/Bottom.java b/src/java.base/share/classes/org/checkerframework/common/subtyping/qual/Bottom.java index 4e3f318ea79..93c521d8964 100644 --- a/src/java.base/share/classes/org/checkerframework/common/subtyping/qual/Bottom.java +++ b/src/java.base/share/classes/org/checkerframework/common/subtyping/qual/Bottom.java @@ -1,12 +1,13 @@ 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; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + /** * 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. @@ -28,5 +29,5 @@ @Documented @SubtypeOf({}) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) -@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND}) +@TargetLocations({TypeUseLocation.LOWER_BOUND, TypeUseLocation.UPPER_BOUND}) public @interface Bottom {} diff --git a/src/java.base/share/classes/org/checkerframework/common/subtyping/qual/Unqualified.java b/src/java.base/share/classes/org/checkerframework/common/subtyping/qual/Unqualified.java index df08edb7b9b..ab339ca71ea 100644 --- a/src/java.base/share/classes/org/checkerframework/common/subtyping/qual/Unqualified.java +++ b/src/java.base/share/classes/org/checkerframework/common/subtyping/qual/Unqualified.java @@ -1,11 +1,12 @@ package org.checkerframework.common.subtyping.qual; +import org.checkerframework.framework.qual.InvisibleQualifier; +import org.checkerframework.framework.qual.SubtypeOf; + 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 diff --git a/src/java.base/share/classes/org/checkerframework/common/util/report/qual/ReportUnqualified.java b/src/java.base/share/classes/org/checkerframework/common/util/report/qual/ReportUnqualified.java index d0bd11cf21b..8345f9bfa2c 100644 --- a/src/java.base/share/classes/org/checkerframework/common/util/report/qual/ReportUnqualified.java +++ b/src/java.base/share/classes/org/checkerframework/common/util/report/qual/ReportUnqualified.java @@ -1,13 +1,14 @@ package org.checkerframework.common.util.report.qual; +import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; +import org.checkerframework.framework.qual.InvisibleQualifier; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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 diff --git a/src/java.base/share/classes/org/checkerframework/common/util/report/qual/ReportUse.java b/src/java.base/share/classes/org/checkerframework/common/util/report/qual/ReportUse.java index 91b7f646529..b9077e2a005 100644 --- a/src/java.base/share/classes/org/checkerframework/common/util/report/qual/ReportUse.java +++ b/src/java.base/share/classes/org/checkerframework/common/util/report/qual/ReportUse.java @@ -6,8 +6,22 @@ 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. */ +/** + * Report all uses of a type that has this annotation. Can also be used on a package. + * + *

When written on a package, {@code @ReportUse} applies to that package and its subpackages by + * default. Set {@link #applyToSubpackages()} to false to limit it to the package itself; doing so + * does not block an applicable {@code @ReportUse} on an enclosing package. + */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.PACKAGE, ElementType.TYPE}) -public @interface ReportUse {} +public @interface ReportUse { + + /** + * When used on a package, whether this annotation should also apply to subpackages. + * + * @return whether this annotation should be inherited by subpackages + */ + boolean applyToSubpackages() default true; +} diff --git a/src/java.base/share/classes/org/checkerframework/common/value/qual/ArrayLen.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/ArrayLen.java index 20b19a15bd6..85c2f5b4d6b 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/ArrayLen.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/ArrayLen.java @@ -1,11 +1,12 @@ package org.checkerframework.common.value.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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 @@ -23,6 +24,6 @@ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) @SubtypeOf({UnknownVal.class}) public @interface ArrayLen { - /** The possible lengths of the array. */ - int[] value(); + /** The possible lengths of the array. */ + int[] value(); } diff --git a/src/java.base/share/classes/org/checkerframework/common/value/qual/ArrayLenRange.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/ArrayLenRange.java index 4a1d8baccaa..1dfd0d97e74 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/ArrayLenRange.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/ArrayLenRange.java @@ -1,11 +1,12 @@ package org.checkerframework.common.value.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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 @@ -19,17 +20,17 @@ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) @SubtypeOf(UnknownVal.class) public @interface ArrayLenRange { - /** - * Smallest value in the range, inclusive. - * - * @return the smallest value in the range, inclusive - */ - int from() default 0; + /** + * Smallest value in the range, inclusive. + * + * @return the smallest value in the range, inclusive + */ + int from() default 0; - /** - * Largest value in the range, inclusive. - * - * @return the largest value in the range, inclusive - */ - int to() default Integer.MAX_VALUE; + /** + * Largest value in the range, inclusive. + * + * @return the largest value in the range, inclusive + */ + int to() default Integer.MAX_VALUE; } diff --git a/src/java.base/share/classes/org/checkerframework/common/value/qual/BoolVal.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/BoolVal.java index 66f5a7fcbeb..adbb4d2d06f 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/BoolVal.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/BoolVal.java @@ -1,11 +1,12 @@ package org.checkerframework.common.value.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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 @@ -18,6 +19,6 @@ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) @SubtypeOf({UnknownVal.class}) public @interface BoolVal { - /** The values that the expression might evaluate to. */ - boolean[] value(); + /** The values that the expression might evaluate to. */ + boolean[] value(); } diff --git a/src/java.base/share/classes/org/checkerframework/common/value/qual/BottomVal.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/BottomVal.java index 8cc40598788..26b00d63827 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/BottomVal.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/BottomVal.java @@ -1,14 +1,15 @@ package org.checkerframework.common.value.qual; +import org.checkerframework.framework.qual.InvisibleQualifier; +import org.checkerframework.framework.qual.SubtypeOf; +import org.checkerframework.framework.qual.TargetLocations; +import org.checkerframework.framework.qual.TypeUseLocation; + import java.lang.annotation.Documented; import 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. @@ -19,20 +20,20 @@ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) -@TargetLocations({TypeUseLocation.EXPLICIT_LOWER_BOUND, TypeUseLocation.EXPLICIT_UPPER_BOUND}) +@TargetLocations({TypeUseLocation.UPPER_BOUND, TypeUseLocation.LOWER_BOUND}) @SubtypeOf({ - ArrayLen.class, - BoolVal.class, - DoubleVal.class, - IntVal.class, - StringVal.class, - MatchesRegex.class, - DoesNotMatchRegex.class, - ArrayLenRange.class, - IntRange.class, - IntRangeFromPositive.class, - IntRangeFromGTENegativeOne.class, - IntRangeFromNonNegative.class + ArrayLen.class, + BoolVal.class, + DoubleVal.class, + IntVal.class, + StringVal.class, + MatchesRegex.class, + DoesNotMatchRegex.class, + ArrayLenRange.class, + IntRange.class, + IntRangeFromPositive.class, + IntRangeFromGTENegativeOne.class, + IntRangeFromNonNegative.class }) @InvisibleQualifier public @interface BottomVal {} diff --git a/src/java.base/share/classes/org/checkerframework/common/value/qual/DoesNotMatchRegex.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/DoesNotMatchRegex.java index 8fde439d8e7..8fb1c2667e1 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/DoesNotMatchRegex.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/DoesNotMatchRegex.java @@ -1,11 +1,12 @@ package org.checkerframework.common.value.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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 @@ -23,10 +24,10 @@ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) @SubtypeOf({UnknownVal.class}) public @interface DoesNotMatchRegex { - /** - * A set of Java regular expressions. - * - * @return the regular expressions - */ - String[] value(); + /** + * A set of Java regular expressions. + * + * @return the regular expressions + */ + String[] value(); } diff --git a/src/java.base/share/classes/org/checkerframework/common/value/qual/DoubleVal.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/DoubleVal.java index 1bfab7a21d7..612ec4da291 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/DoubleVal.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/DoubleVal.java @@ -1,11 +1,12 @@ package org.checkerframework.common.value.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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 @@ -21,6 +22,6 @@ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) @SubtypeOf({UnknownVal.class}) public @interface DoubleVal { - /** The values that the expression might evaluate to. */ - double[] value(); + /** The values that the expression might evaluate to. */ + double[] value(); } diff --git a/src/java.base/share/classes/org/checkerframework/common/value/qual/EnsuresMinLenIf.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/EnsuresMinLenIf.java index 89c04613c33..2b93ba81649 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/EnsuresMinLenIf.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/EnsuresMinLenIf.java @@ -1,14 +1,15 @@ package org.checkerframework.common.value.qual; +import org.checkerframework.framework.qual.ConditionalPostconditionAnnotation; +import org.checkerframework.framework.qual.InheritedAnnotation; +import org.checkerframework.framework.qual.QualifierArgument; + 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 @@ -27,48 +28,48 @@ @InheritedAnnotation @Repeatable(EnsuresMinLenIf.List.class) public @interface EnsuresMinLenIf { - /** - * 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 return value of the method under which the postcondition holds. + * + * @return the return value of the method under which the postcondition holds + */ + boolean result(); - /** - * 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 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 minimum number of elements in the sequence. - * - * @return the minimum number of elements in the sequence - */ - @QualifierArgument("value") - int targetValue() default 0; + /** + * 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. - * - *

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 - public static @interface List { /** - * Return the repeatable annotations. + * A wrapper annotation that makes the {@link EnsuresMinLenIf} annotation repeatable. * - * @return the repeatable annotations + *

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. */ - EnsuresMinLenIf[] value(); - } + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) + @ConditionalPostconditionAnnotation(qualifier = MinLen.class) + @InheritedAnnotation + public static @interface List { + /** + * Returns the repeatable annotations. + * + * @return the repeatable annotations + */ + EnsuresMinLenIf[] value(); + } } diff --git a/src/java.base/share/classes/org/checkerframework/common/value/qual/EnumVal.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/EnumVal.java index c07b66938ca..cfd60863271 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/EnumVal.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/EnumVal.java @@ -20,10 +20,11 @@ @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(); + /** + * 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/src/java.base/share/classes/org/checkerframework/common/value/qual/IntRange.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/IntRange.java index 74c99b47815..db16428bb02 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/IntRange.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/IntRange.java @@ -1,11 +1,12 @@ package org.checkerframework.common.value.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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 @@ -26,17 +27,17 @@ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) @SubtypeOf(UnknownVal.class) public @interface IntRange { - /** - * Largest value in the range, inclusive. - * - * @return the largest value in the range, inclusive - */ - long from() default Long.MIN_VALUE; + /** + * Smallest value in the range, inclusive. + * + * @return the smallest value in the range, inclusive + */ + long from() default Long.MIN_VALUE; - /** - * Largest value in the range, inclusive. - * - * @return the largest value in the range, inclusive - */ - long to() default Long.MAX_VALUE; + /** + * Largest value in the range, inclusive. + * + * @return the largest value in the range, inclusive + */ + long to() default Long.MAX_VALUE; } diff --git a/src/java.base/share/classes/org/checkerframework/common/value/qual/IntRangeFromGTENegativeOne.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/IntRangeFromGTENegativeOne.java index fc65c4a9f20..c1cbd3a1673 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/IntRangeFromGTENegativeOne.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/IntRangeFromGTENegativeOne.java @@ -1,10 +1,11 @@ package org.checkerframework.common.value.qual; +import org.checkerframework.framework.qual.SubtypeOf; + 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 @@ -27,6 +28,8 @@ * @checker_framework.manual #constant-value-checker Constant Value Checker */ @Documented +// Do not store in class file: this is only an internal alias of an Index Checker qualifier, such as +// @GTENegativeOne, which is stored instead. @Retention(RetentionPolicy.SOURCE) @Target({}) @SubtypeOf(UnknownVal.class) diff --git a/src/java.base/share/classes/org/checkerframework/common/value/qual/IntRangeFromNonNegative.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/IntRangeFromNonNegative.java index 434ff259de3..ecce8296e88 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/IntRangeFromNonNegative.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/IntRangeFromNonNegative.java @@ -1,10 +1,11 @@ package org.checkerframework.common.value.qual; +import org.checkerframework.framework.qual.SubtypeOf; + 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 @@ -27,6 +28,8 @@ * @checker_framework.manual #constant-value-checker Constant Value Checker */ @Documented +// Do not store in class file: this is only an internal alias of an Index Checker qualifier, such as +// @NonNegative, which is stored instead. @Retention(RetentionPolicy.SOURCE) @Target({}) @SubtypeOf(UnknownVal.class) diff --git a/src/java.base/share/classes/org/checkerframework/common/value/qual/IntRangeFromPositive.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/IntRangeFromPositive.java index 4941505975a..f1cfc6084f3 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/IntRangeFromPositive.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/IntRangeFromPositive.java @@ -1,10 +1,11 @@ package org.checkerframework.common.value.qual; +import org.checkerframework.framework.qual.SubtypeOf; + 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 @@ -27,6 +28,8 @@ * @checker_framework.manual #constant-value-checker Constant Value Checker */ @Documented +// Do not store in class file: this is only an internal alias of an Index Checker qualifier, such as +// @Positive, which is stored instead. @Retention(RetentionPolicy.SOURCE) @Target({}) @SubtypeOf(UnknownVal.class) diff --git a/src/java.base/share/classes/org/checkerframework/common/value/qual/IntVal.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/IntVal.java index 3ab290f1e7d..6ee20087e74 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/IntVal.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/IntVal.java @@ -1,11 +1,12 @@ package org.checkerframework.common.value.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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 @@ -19,6 +20,6 @@ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) @SubtypeOf({UnknownVal.class}) public @interface IntVal { - /** The values that the expression might evaluate to. */ - long[] value(); + /** The values that the expression might evaluate to. */ + long[] value(); } diff --git a/src/java.base/share/classes/org/checkerframework/common/value/qual/MatchesRegex.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/MatchesRegex.java index 5c10b127c35..49fa1377a88 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/MatchesRegex.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/MatchesRegex.java @@ -1,11 +1,12 @@ package org.checkerframework.common.value.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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 @@ -23,10 +24,10 @@ @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(); + /** + * A set of Java regular expressions. + * + * @return the regular expressions + */ + String[] value(); } diff --git a/src/java.base/share/classes/org/checkerframework/common/value/qual/MinLen.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/MinLen.java index a05c8431bbf..63a5a04367b 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/MinLen.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/MinLen.java @@ -19,6 +19,6 @@ @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; + /** The minimum number of elements in this sequence. */ + int value() default 0; } diff --git a/src/java.base/share/classes/org/checkerframework/common/value/qual/MinLenFieldInvariant.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/MinLenFieldInvariant.java index bf120018cd3..ffe7d404fd0 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/MinLenFieldInvariant.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/MinLenFieldInvariant.java @@ -1,12 +1,13 @@ package org.checkerframework.common.value.qual; +import org.checkerframework.framework.qual.FieldInvariant; + 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 @@ -20,15 +21,15 @@ @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(); + /** + * 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(); + /** + * 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/src/java.base/share/classes/org/checkerframework/common/value/qual/PolyValue.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/PolyValue.java index 8ae998b9b7f..99e6ddec353 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/PolyValue.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/PolyValue.java @@ -1,11 +1,12 @@ package org.checkerframework.common.value.qual; +import org.checkerframework.framework.qual.PolymorphicQualifier; + import java.lang.annotation.Documented; import 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. diff --git a/src/java.base/share/classes/org/checkerframework/common/value/qual/StringVal.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/StringVal.java index 6f0ccb4dd77..95472e9746f 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/StringVal.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/StringVal.java @@ -1,11 +1,12 @@ package org.checkerframework.common.value.qual; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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 @@ -18,6 +19,6 @@ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) @SubtypeOf({UnknownVal.class}) public @interface StringVal { - /** The values that the expression might evaluate to. */ - String[] value(); + /** The values that the expression might evaluate to. */ + String[] value(); } diff --git a/src/java.base/share/classes/org/checkerframework/common/value/qual/UnknownVal.java b/src/java.base/share/classes/org/checkerframework/common/value/qual/UnknownVal.java index 1ae28c0f75b..fdbd1ff373c 100644 --- a/src/java.base/share/classes/org/checkerframework/common/value/qual/UnknownVal.java +++ b/src/java.base/share/classes/org/checkerframework/common/value/qual/UnknownVal.java @@ -1,13 +1,14 @@ package org.checkerframework.common.value.qual; +import org.checkerframework.framework.qual.DefaultQualifierInHierarchy; +import org.checkerframework.framework.qual.InvisibleQualifier; +import org.checkerframework.framework.qual.SubtypeOf; + import java.lang.annotation.Documented; import 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; /** * UnknownVal is a type annotation indicating that the expression's value is not known at compile diff --git a/src/java.base/share/classes/org/checkerframework/dataflow/qual/AssertMethod.java b/src/java.base/share/classes/org/checkerframework/dataflow/qual/AssertMethod.java index 4dd0ee58614..ed29b6be34e 100644 --- a/src/java.base/share/classes/org/checkerframework/dataflow/qual/AssertMethod.java +++ b/src/java.base/share/classes/org/checkerframework/dataflow/qual/AssertMethod.java @@ -14,9 +14,9 @@ *

The annotation enables flow-sensitive type refinement to be more precise. For example, if * {@code Assertions.assertTrue} is annotated as follows: * - *

@AssertMethod(value = AssertionFailedError.class)
+ * 
{@code @AssertMethod(value = AssertionFailedError.class)
  * public static void assertFalse(boolean condition);
- * 
+ * }
* * Then, in the code below, the Optional Checker can determine that {@code optional} has a value and * the call to {@code Optional#get} will not throw an exception. @@ -38,32 +38,32 @@ @Target(ElementType.METHOD) public @interface AssertMethod { - /** - * The class of the exception thrown by this method. The default is {@link AssertionError}. - * - * @return class of the exception thrown by this method - */ - Class value() default AssertionError.class; + /** + * The class of the exception thrown by this method. The default is {@link AssertionError}. + * + * @return class of the exception thrown by this method + */ + Class value() default AssertionError.class; - /** - * The one-based index of the boolean parameter that is tested. - * - * @return the one-based index of the boolean parameter that is tested - */ - int parameter() default 1; + /** + * The one-based index of the boolean parameter that is tested. + * + * @return the one-based index of the boolean parameter that is tested + */ + int parameter() default 1; - /** - * Returns whether this method asserts that the boolean expression is false. - * - *

For example, Junit's Assertions.assertFalse(...) - * throws an exception if the first argument is false. So it is annotated as follows: - * - *

@AssertMethod(value = AssertionFailedError.class, isAssertFalse = true)
-   * public static void assertFalse(boolean condition);
-   * 
- * - * @return the value for {@link #parameter} on which the method throws an exception - */ - boolean isAssertFalse() default false; + /** + * Returns true if this method asserts that the boolean expression is false. + * + *

For example, JUnit's Assertions.assertFalse(...) + * throws an exception if the first argument is false. So it is annotated as follows: + * + *

{@code @AssertMethod(value = AssertionFailedError.class, isAssertFalse = true)
+     * public static void assertFalse(boolean condition);
+     * }
+ * + * @return the value for {@link #parameter} on which the method throws an exception + */ + boolean isAssertFalse() default false; } diff --git a/src/java.base/share/classes/org/checkerframework/dataflow/qual/Deterministic.java b/src/java.base/share/classes/org/checkerframework/dataflow/qual/Deterministic.java index c56484f0dd6..b31734493bc 100644 --- a/src/java.base/share/classes/org/checkerframework/dataflow/qual/Deterministic.java +++ b/src/java.base/share/classes/org/checkerframework/dataflow/qual/Deterministic.java @@ -18,9 +18,10 @@ * *

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: + * about the first invocation is true about subsequent invocations, so long as the environment does + * not change in between. For example, if {@code myDeterministicMethod} is also {@link + * SideEffectFree}, the following code never suffers a null pointer exception, so the Nullness + * Checker need not issue a warning: * *

{@code
  * if (x.myDeterministicMethod() != null) {
@@ -28,6 +29,29 @@
  * }
  * }
* + *

The environment can change between the two invocations because of an intervening call to a + * non-{@code @}{@link SideEffectFree} method, but also because of the first invocation itself: + * determinism does not prevent a method from modifying the heap. For example, the following method + * is deterministic according to the definition above, but it is not side-effect-free, and in the + * code above its second invocation returns {@code null} (assuming {@code this.f} was initially + * non-null): + * + *

{@code
+ * Object myDeterministicMethod() {
+ *   Object o = this.f;
+ *   this.f = null;
+ *   return o;
+ * }
+ * }
+ * + *

Nevertheless, the Checker Framework currently assumes that repeated invocations of any + * {@code @Deterministic} method return the same value, even if the method is not + * {@code @SideEffectFree}. This assumption is justified only when the annotation is checked, + * because the checking rules below forbid side effects in a {@code @Deterministic} method, and + * checking is disabled by default. Therefore, do not write {@code @Deterministic} on a method that + * has side effects, such as the one above. To state that a method is both deterministic and + * side-effect-free, write {@link Pure}. + * *

Note that {@code @Deterministic} guarantees that the result is identical according to {@code * ==}, not just equal according to {@code equals()}. This means that writing * {@code @Deterministic} on a method that returns a reference (including a String) is often diff --git a/src/java.base/share/classes/org/checkerframework/dataflow/qual/Pure.java b/src/java.base/share/classes/org/checkerframework/dataflow/qual/Pure.java index 82cdb596879..6c7ddbdc26b 100644 --- a/src/java.base/share/classes/org/checkerframework/dataflow/qual/Pure.java +++ b/src/java.base/share/classes/org/checkerframework/dataflow/qual/Pure.java @@ -11,6 +11,13 @@ * Deterministic}. The more important of these, when performing pluggable type-checking, is usually * {@link SideEffectFree}. * + *

For pluggable type-checking, {@link SideEffectFree} lets flow-sensitive type refinement keep + * facts about the heap across a call to the method, and {@link Deterministic} lets it assume that a + * later invocation of the method, with the same arguments and in the same environment, returns the + * same value as an earlier one. Because a deterministic method that is not side-effect-free can + * change the environment itself, both are needed for a fact learned about the result of one + * invocation to hold for the result of the next; see {@link Deterministic} for an example. + * *

For a discussion of the meaning of {@code Pure} on a constructor, see the documentation of * {@link Deterministic}. * @@ -26,12 +33,12 @@ @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 type of purity. */ + 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 - } + /** The method returns exactly the same value when called in the same environment. */ + DETERMINISTIC + } } diff --git a/src/java.base/share/classes/org/checkerframework/dataflow/qual/SideEffectFree.java b/src/java.base/share/classes/org/checkerframework/dataflow/qual/SideEffectFree.java index da33d80443e..00d1fab83a5 100644 --- a/src/java.base/share/classes/org/checkerframework/dataflow/qual/SideEffectFree.java +++ b/src/java.base/share/classes/org/checkerframework/dataflow/qual/SideEffectFree.java @@ -22,7 +22,10 @@ * 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. * - *

Also see {@link Pure}, which means both side-effect-free and {@link Deterministic}. + *

Being side-effect-free does not imply that two invocations of the method return the same + * value. Also see {@link Pure}, which means both side-effect-free and {@link Deterministic}, and + * which lets a pluggable type-checker assume that repeated invocations with the same arguments + * return the same value, so long as no other side effect intervenes. * *

Analysis: The Checker Framework performs a conservative analysis to verify a * {@code @SideEffectFree} annotation. The Checker Framework issues a warning if the method uses any diff --git a/src/java.base/share/classes/org/checkerframework/dataflow/qual/SideEffectsOnly.java b/src/java.base/share/classes/org/checkerframework/dataflow/qual/SideEffectsOnly.java deleted file mode 100644 index ab6a7dd1718..00000000000 --- a/src/java.base/share/classes/org/checkerframework/dataflow/qual/SideEffectsOnly.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.checkerframework.dataflow.qual; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import org.checkerframework.framework.qual.JavaExpression; - -/** - * A method annotated with the declaration annotation {@code @SideEffectsOnly("A", "B")} changes the - * value of at most the expressions A and B. All other expressions have the same value before and - * after a call to the method. - * - * @checker_framework.manual #type-refinement-purity Specifying side effects - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) -public @interface SideEffectsOnly { - /** - * An upper bound on the expressions that this method might change the value of. - * - * @return the Java expressions that the annotated method might side-effect - * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions - */ - @JavaExpression - public String[] value(); -} diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/AnnotatedFor.java b/src/java.base/share/classes/org/checkerframework/framework/qual/AnnotatedFor.java index 8c2844ee992..f7e5e3650c2 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/AnnotatedFor.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/AnnotatedFor.java @@ -2,6 +2,7 @@ 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; @@ -23,20 +24,61 @@ * 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. * + *

This annotation is stored in class files and is available via reflection at run time. + * + *

An {@code @AnnotatedFor} on a package also applies to subpackages, unless the {@code + * applyToSubpackages} field is set to false. Setting it to false does not block an applicable + * {@code @AnnotatedFor} on an enclosing package. + * + *

You may write multiple {@code @AnnotatedFor} annotations at the same location, for example to + * give two type systems different {@code applyToSubpackages} settings on one package: + * + *

+ *   {@literal @}AnnotatedFor(value = "nullness", applyToSubpackages = false)
+ *   {@literal @}AnnotatedFor(value = "index", applyToSubpackages = true)
+ *   package mypackage;
+ * 
+ * * @checker_framework.manual #compiling-libraries Compiling partially-annotated libraries */ @Documented -@Retention(RetentionPolicy.SOURCE) +@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PACKAGE}) +@Repeatable(AnnotatedFor.List.class) 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(); + /** + * 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(); + + /** + * When used on a package, whether this annotation should also apply to subpackages. + * + * @return whether this annotation should be inherited by subpackages + */ + boolean applyToSubpackages() default true; + + /** + * A wrapper annotation that makes the {@link AnnotatedFor} annotation repeatable. + * + *

Programmers generally do not need to write this. It is created by Java when a programmer + * writes more than one {@link AnnotatedFor} annotation at the same location. + */ + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PACKAGE}) + public static @interface List { + /** + * Returns the repeatable annotations. + * + * @return the repeatable annotations + */ + AnnotatedFor[] value(); + } } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/CFComment.java b/src/java.base/share/classes/org/checkerframework/framework/qual/CFComment.java index f9ef370b591..3429d5f8b15 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/CFComment.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/CFComment.java @@ -25,17 +25,21 @@ * to which the comment applies (e.g., local variable rather than method, and method rather than * class). * + *

This annotation has source retention: its comments are for people who read and maintain the + * source code, and the Checker Framework does not interpret them, so they are not stored in class + * files. + * * @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. - * - *

If you prefix each comment by the name of the type system, the comments are easier to - * understand and search for. - */ - String[] value(); + /** + * Comments about Checker Framework annotations. The text is not interpreted by the Checker + * Framework. + * + *

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/src/java.base/share/classes/org/checkerframework/framework/qual/ConditionalPostconditionAnnotation.java b/src/java.base/share/classes/org/checkerframework/framework/qual/ConditionalPostconditionAnnotation.java index 9b7feb69237..ac65025991e 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/ConditionalPostconditionAnnotation.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/ConditionalPostconditionAnnotation.java @@ -65,10 +65,10 @@ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.ANNOTATION_TYPE}) public @interface ConditionalPostconditionAnnotation { - /** - * The qualifier that will be established as a postcondition. - * - *

This element is analogous to {@link EnsuresQualifierIf#qualifier()}. - */ - Class qualifier(); + /** + * The qualifier that will be established as a postcondition. + * + *

This element is analogous to {@link EnsuresQualifierIf#qualifier()}. + */ + Class qualifier(); } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/Covariant.java b/src/java.base/share/classes/org/checkerframework/framework/qual/Covariant.java index 1599464f6ac..ac79c2e99db 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/Covariant.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/Covariant.java @@ -32,6 +32,6 @@ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface Covariant { - /** The zero-based indices of the type parameters that should be treated covariantly. */ - int[] value(); + /** The zero-based indices of the type parameters that should be treated covariantly. */ + int[] value(); } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/DefaultFor.java b/src/java.base/share/classes/org/checkerframework/framework/qual/DefaultFor.java index f1c0fde504d..2b75ecf37a9 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/DefaultFor.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/DefaultFor.java @@ -16,6 +16,13 @@ *

  • all uses of a particular kind of type. * * + * An example is the declaration + * + *
    
    + * {@literal @}DefaultFor(TypeUseLocation.LOWER_BOUND)
    + * {@literal @}interface MyAnno {}
    + * 
    + * *

    The default applies to every match for any of this annotation's conditions. * * @see TypeUseLocation @@ -26,62 +33,62 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface DefaultFor { - /** - * Returns the locations to which the annotation should be applied. - * - * @return the locations to which the annotation should be applied - */ - TypeUseLocation[] value() default {}; + /** + * Returns the locations to which the annotation should be applied. + * + * @return the locations to which the annotation should be applied + */ + TypeUseLocation[] value() default {}; - /** - * Returns {@link TypeKind}s of types for which an annotation should be implicitly added. - * - * @return {@link TypeKind}s of types for which an annotation should be implicitly added - */ - TypeKind[] typeKinds() default {}; + /** + * Returns {@link TypeKind}s of types for which an annotation should be implicitly added. + * + * @return {@link TypeKind}s of types for which an annotation should be implicitly added + */ + TypeKind[] typeKinds() default {}; - /** - * Returns {@link Class}es for which an annotation should be applied. For example, if - * {@code @MyAnno} is meta-annotated with {@code @DefaultFor(classes=String.class)}, then every - * occurrence of {@code String} is actually {@code @MyAnno String}. - * - *

    Only the given types, not their subtypes, receive the default. For instance, if the {@code - * types} element contains only {@code Iterable}, then the default does not apply to a variable or - * expression of type {@code Collection} which is a subtype of {@code Iterable}. - * - * @return {@link Class}es for which an annotation should be applied - */ - Class[] types() default {}; + /** + * Returns {@link Class}es for which an annotation should be applied. For example, if + * {@code @MyAnno} is meta-annotated with {@code @DefaultFor(classes=String.class)}, then every + * occurrence of {@code String} is actually {@code @MyAnno String}. + * + *

    Only the given types, not their subtypes, receive the default. For instance, if the {@code + * types} element contains only {@code Iterable}, then the default does not apply to a variable + * or expression of type {@code Collection} which is a subtype of {@code Iterable}. + * + * @return {@link Class}es for which an annotation should be applied + */ + Class[] types() default {}; - /** - * Returns regular expressions matching names of variables, to whose types the annotation should - * be applied as a default. If a regular expression matches the name of a method, the annotation - * is applied as a default to the return type. - * - *

    The regular expression must match the entire variable or method name. For example, to match - * any name that contains "foo", use ".*foo.*". - * - *

    The default does not apply if the name matches any of the regexes in {@link - * #namesExceptions}. - * - *

    This affects formal parameter types only if one of the following is true: - * - *

      - *
    • The method's source code is available; that is, the method is type-checked along with - * client calls. - *
    • When the method was compiled in a previous run of javac, either the processor was run or - * the {@code -g} command-line option was provided. - *
    - * - * @return regular expressions matching variables to whose type an annotation should be applied - */ - String[] names() default {}; + /** + * Returns regular expressions matching names of variables, to whose types the annotation should + * be applied as a default. If a regular expression matches the name of a method, the annotation + * is applied as a default to the return type. + * + *

    The regular expression must match the entire variable or method name. For example, to + * match any name that contains "foo", use ".*foo.*". + * + *

    The default does not apply if the name matches any of the regexes in {@link + * #namesExceptions}. + * + *

    This affects formal parameter types only if one of the following is true: + * + *

      + *
    • The method's source code is available; that is, the method is type-checked along with + * client calls. + *
    • When the method was compiled in a previous run of javac, either the processor was run + * or the {@code -g} command-line option was provided. + *
    + * + * @return regular expressions matching variables to whose type an annotation should be applied + */ + String[] names() default {}; - /** - * Returns exceptions to regular expression rules. - * - * @return exceptions to regular expression rules - * @see #names - */ - String[] namesExceptions() default {}; + /** + * Returns exceptions to regular expression rules. + * + * @return exceptions to regular expression rules + * @see #names + */ + String[] namesExceptions() default {}; } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/DefaultQualifier.java b/src/java.base/share/classes/org/checkerframework/framework/qual/DefaultQualifier.java index 7409d914144..f791c1762b9 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/DefaultQualifier.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/DefaultQualifier.java @@ -26,6 +26,9 @@ *   class MyClass { ... } *
  • * + *

    Defaults on a package also apply to subpackages, unless the {@code applyToSubpackages} field + * is set to false. + * *

    This annotation currently has no effect in stub files. * * @see org.checkerframework.framework.qual.TypeUseLocation @@ -34,44 +37,8 @@ * @checker_framework.manual #defaults Default qualifier for unannotated types */ @Documented -@Retention(RetentionPolicy.SOURCE) +@Retention(RetentionPolicy.RUNTIME) @Target({ - ElementType.PACKAGE, - ElementType.TYPE, - ElementType.CONSTRUCTOR, - ElementType.METHOD, - ElementType.FIELD, - ElementType.LOCAL_VARIABLE, - ElementType.PARAMETER -}) -@Repeatable(DefaultQualifier.List.class) -public @interface DefaultQualifier { - - /** - * The Class for the default annotation. - * - *

    To prevent affecting other type systems, always specify an annotation in your own type - * hierarchy. (For example, do not set {@link - * org.checkerframework.common.subtyping.qual.Unqualified} as the default.) - */ - Class value(); - - /** - * Returns the locations to which the annotation should be applied. - * - * @return the locations to which the annotation should be applied - */ - TypeUseLocation[] locations() default {TypeUseLocation.ALL}; - - /** - * A wrapper annotation that makes the {@link DefaultQualifier} annotation repeatable. - * - *

    Programmers generally do not need to write this. It is created by Java when a programmer - * writes more than one {@link DefaultQualifier} annotation at the same location. - */ - @Documented - @Retention(RetentionPolicy.RUNTIME) - @Target({ ElementType.PACKAGE, ElementType.TYPE, ElementType.CONSTRUCTOR, @@ -79,13 +46,56 @@ ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.PARAMETER - }) - public static @interface List { +}) +@Repeatable(DefaultQualifier.List.class) +public @interface DefaultQualifier { + + /** + * The Class for the default annotation. + * + *

    To prevent affecting other type systems, always specify an annotation in your own type + * hierarchy. (For example, do not set {@link + * org.checkerframework.common.subtyping.qual.Unqualified} as the default.) + */ + Class value(); + + /** + * Returns the locations to which the annotation should be applied. + * + * @return the locations to which the annotation should be applied + */ + TypeUseLocation[] locations() default {TypeUseLocation.ALL}; + + /** + * When used on a package, whether the defaults should also apply to subpackages. + * + * @return whether the default should be inherited by subpackages + */ + boolean applyToSubpackages() default true; + /** - * Return the repeatable annotations. + * A wrapper annotation that makes the {@link DefaultQualifier} annotation repeatable. * - * @return the repeatable annotations + *

    Programmers generally do not need to write this. It is created by Java when a programmer + * writes more than one {@link DefaultQualifier} annotation at the same location. */ - DefaultQualifier[] value(); - } + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ + ElementType.PACKAGE, + ElementType.TYPE, + ElementType.CONSTRUCTOR, + ElementType.METHOD, + ElementType.FIELD, + ElementType.LOCAL_VARIABLE, + ElementType.PARAMETER + }) + public static @interface List { + /** + * Returns the repeatable annotations. + * + * @return the repeatable annotations + */ + DefaultQualifier[] value(); + } } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/DefaultQualifierForUse.java b/src/java.base/share/classes/org/checkerframework/framework/qual/DefaultQualifierForUse.java index c88065e8d1a..961ed0421f9 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/DefaultQualifierForUse.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/DefaultQualifierForUse.java @@ -15,6 +15,6 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface DefaultQualifierForUse { - /** Qualifier to add to all unannotated uses of the type with this declaration annotation. */ - Class[] value() default {}; + /** Qualifier to add to all unannotated uses of the type with this declaration annotation. */ + Class[] value() default {}; } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/EnsuresQualifier.java b/src/java.base/share/classes/org/checkerframework/framework/qual/EnsuresQualifier.java index 3c897376109..bce3e983009 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/EnsuresQualifier.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/EnsuresQualifier.java @@ -36,37 +36,39 @@ @InheritedAnnotation @Repeatable(EnsuresQualifier.List.class) public @interface EnsuresQualifier { - /** - * Returns the Java expressions for which the qualifier holds after successful method termination. - * - * @return the Java expressions for which the qualifier holds after successful method termination - * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions - */ - String[] expression(); + /** + * Returns the Java expressions for which the qualifier holds after successful method + * termination. + * + * @return the Java expressions for which the qualifier holds after successful method + * termination + * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions + */ + String[] expression(); - /** - * Returns the qualifier that is guaranteed to hold on successful termination of the method. - * - * @return the qualifier that is guaranteed to hold on successful termination of the method - */ - Class qualifier(); + /** + * Returns the qualifier that is guaranteed to hold on successful termination of the method. + * + * @return the qualifier that is guaranteed to hold on successful termination of the method + */ + Class qualifier(); - /** - * A wrapper annotation that makes the {@link EnsuresQualifier} annotation repeatable. - * - *

    Programmers generally do not need to write this. It is created by Java when a programmer - * writes more than one {@link EnsuresQualifier} annotation at the same location. - */ - @Documented - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) - @InheritedAnnotation - public static @interface List { /** - * Return the repeatable annotations. + * A wrapper annotation that makes the {@link EnsuresQualifier} annotation repeatable. * - * @return the repeatable annotations + *

    Programmers generally do not need to write this. It is created by Java when a programmer + * writes more than one {@link EnsuresQualifier} annotation at the same location. */ - EnsuresQualifier[] value(); - } + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) + @InheritedAnnotation + public static @interface List { + /** + * Returns the repeatable annotations. + * + * @return the repeatable annotations + */ + EnsuresQualifier[] value(); + } } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/EnsuresQualifierIf.java b/src/java.base/share/classes/org/checkerframework/framework/qual/EnsuresQualifierIf.java index e5e6734255d..b44fff876e3 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/EnsuresQualifierIf.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/EnsuresQualifierIf.java @@ -39,48 +39,48 @@ @InheritedAnnotation @Repeatable(EnsuresQualifierIf.List.class) public @interface EnsuresQualifierIf { - /** - * Returns the return value of the method that needs to hold for the postcondition to hold. - * - * @return the return value of the method that needs to hold for the postcondition to hold - */ - boolean result(); + /** + * Returns the return value of the method that needs to hold for the postcondition to hold. + * + * @return the return value of the method that needs to hold for the postcondition to hold + */ + boolean result(); - /** - * Returns the Java expressions for which the qualifier holds if the method terminates with return - * value {@link #result()}. - * - * @return the Java expressions for which the qualifier holds if the method terminates with return - * value {@link #result()} - * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions - */ - String[] expression(); + /** + * Returns the Java expressions for which the qualifier holds if the method terminates with + * return value {@link #result()}. + * + * @return the Java expressions for which the qualifier holds if the method terminates with + * return value {@link #result()} + * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions + */ + String[] expression(); - /** - * Returns the qualifier that is guaranteed to hold if the method terminates with return value - * {@link #result()}. - * - * @return the qualifier that is guaranteed to hold if the method terminates with return value - * {@link #result()} - */ - Class qualifier(); + /** + * Returns the qualifier that is guaranteed to hold if the method terminates with return value + * {@link #result()}. + * + * @return the qualifier that is guaranteed to hold if the method terminates with return value + * {@link #result()} + */ + Class qualifier(); - /** - * A wrapper annotation that makes the {@link EnsuresQualifierIf} annotation repeatable. - * - *

    Programmers generally do not need to write this. It is created by Java when a programmer - * writes more than one {@link EnsuresQualifierIf} annotation at the same location. - */ - @Documented - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.METHOD}) - @InheritedAnnotation - public static @interface List { /** - * Return the repeatable annotations. + * A wrapper annotation that makes the {@link EnsuresQualifierIf} annotation repeatable. * - * @return the repeatable annotations + *

    Programmers generally do not need to write this. It is created by Java when a programmer + * writes more than one {@link EnsuresQualifierIf} annotation at the same location. */ - EnsuresQualifierIf[] value(); - } + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD}) + @InheritedAnnotation + public static @interface List { + /** + * Returns the repeatable annotations. + * + * @return the repeatable annotations + */ + EnsuresQualifierIf[] value(); + } } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/FieldInvariant.java b/src/java.base/share/classes/org/checkerframework/framework/qual/FieldInvariant.java index 037312637f6..2f5d65e8cf5 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/FieldInvariant.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/FieldInvariant.java @@ -27,14 +27,15 @@ @Inherited public @interface FieldInvariant { - /** - * The qualifier on the field. Must be a subtype of the qualifier on the declaration of the field. - */ - Class[] qualifier(); + /** + * The qualifier on the field. Must be a subtype of the qualifier on the declaration of the + * field. + */ + Class[] qualifier(); - /** - * The field that has a more precise type, in the class on which the {@code FieldInvariant} - * annotation is written. The field must be declared in a superclass and must be {@code final}. - */ - String[] field(); + /** + * The field that has a more precise type, in the class on which the {@code FieldInvariant} + * annotation is written. The field must be declared in a superclass and must be {@code final}. + */ + String[] field(); } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/HasQualifierParameter.java b/src/java.base/share/classes/org/checkerframework/framework/qual/HasQualifierParameter.java index 9cc75018286..7f1cb3c6eed 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/HasQualifierParameter.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/HasQualifierParameter.java @@ -9,13 +9,15 @@ import java.lang.annotation.Target; /** - * This is a declaration annotation that applies to type declarations and packages. On a type, it - * means that the class conceptually takes a type qualifier parameter, though there is nowhere to - * write it because the class hard-codes a Java basetype rather than taking a type parameter. - * Writing {@code HasQualifierParameter} on a package is the same as writing it on each class in - * that package. + * This is a declaration annotation that applies to type declarations and packages. On a + * type, it means that the class conceptually takes a type qualifier parameter, though there + * is nowhere to write it because the class hard-codes a Java basetype rather than taking a type + * parameter. Writing {@code HasQualifierParameter} on a package is the same as writing it on + * each class in that package. * - *

    Writing {@code @HasQualifierParameter} on a type declaration has two effects. + *

    Written on a type declaration

    + * + *

    Writing {@code @HasQualifierParameter} on a type declaration has two effects. * *

      *
    1. Invariant subtyping is used for occurrences of the type: no two occurrences of the type @@ -55,12 +57,17 @@ * {@code @Untainted} MyStringBuffer * * - *

      When a class is {@code @HasQualifierParameter}, all its subclasses are as well. + *

      When a type is {@code @HasQualifierParameter}, all its subtypes are as well. That is, the + * {@code @HasQualifierParameter} annotation is inherited by subtypes. + * + *

      Written on a package

      * *

      When {@code @HasQualifierParameter} is written on a package, it is equivalent to writing that - * annotation on each class in the package or in a sub-package. It can be disabled on a specific - * class and its subclasses by writing {@code @NoQualifierParameter} on that class. This annotation - * may not be written on the same class as {@code NoQualifierParameter} for the same hierarchy. + * annotation on each class in the package or in a sub-package. Set the {@code applyToSubpackages} + * field to false to limit it to the package itself; doing so does not block an applicable + * {@code @HasQualifierParameter} on an enclosing package. It can be disabled on a specific class + * and its subclasses by writing {@code @NoQualifierParameter} on that class. This annotation may + * not be written on the same class as {@code @NoQualifierParameter} for the same hierarchy. * * @see NoQualifierParameter */ @@ -70,10 +77,17 @@ @Target({ElementType.TYPE, ElementType.PACKAGE}) public @interface HasQualifierParameter { - /** - * Class of the top qualifier for the hierarchy for which this class has a qualifier parameter. - * - * @return the value - */ - Class[] value(); + /** + * Class of the top qualifier for the hierarchy for which this class has a qualifier parameter. + * + * @return the value + */ + Class[] value(); + + /** + * When used on a package, whether this annotation should also apply to subpackages. + * + * @return whether this annotation should be inherited by subpackages + */ + boolean applyToSubpackages() default true; } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/InheritedAnnotation.java b/src/java.base/share/classes/org/checkerframework/framework/qual/InheritedAnnotation.java index cd1db57dc26..7f82c0176e0 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/InheritedAnnotation.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/InheritedAnnotation.java @@ -7,8 +7,13 @@ import java.lang.annotation.Target; /** - * A meta-annotation that specifies if a declaration annotation should be inherited. This should not - * be written on type annotations. + * A meta-annotation that specifies that a declaration annotation should be inherited. This should + * not be written on type annotations. Unlike {@link java.lang.annotation.Inherited}, this + * meta-annotation causes the declaration annotation to be inherited even if it is used to annotate + * something other than a class. + * + *

      If an annotation type is meta-annotation with {@link java.lang.annotation.Inherited}, that + * annotation will only be inherited when written on a class. */ @Documented @Retention(RetentionPolicy.RUNTIME) diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/InvisibleQualifier.java b/src/java.base/share/classes/org/checkerframework/framework/qual/InvisibleQualifier.java index 1925dc085d0..45b0f3684c8 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/InvisibleQualifier.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/InvisibleQualifier.java @@ -7,8 +7,24 @@ import java.lang.annotation.Target; /** - * A meta-annotation indicating that an annotation is a type qualifier that should not be visible in - * output. + * A meta-annotation indicating that an annotation is a type qualifier that should not be shown in + * output. {@code @InvisibleQualifier} should only be written on a qualifier that is also + * meta-annotated with {@code @}{@link DefaultQualifierInHierarchy}. + * + *

      By default, the Checker Framework's error messages show every annotation, including inferred + * and default ones (which far outnumber the ones explicitly written by the programmer). Being + * explicit helps users understand the effective annotations, which the Checker Framework operates + * upon. However, the output can be verbose, and it can show annotations that a user should not + * write. For example, a Compiler Message Key Checker warning message might contain + * "{@code @UnknownCompilerMessageKey Map<@CompilerMessageKey String, @UnknownCompilerMessageKey + * String>}". + * + *

      When an annotation is meta-annotated with {@code @InvisibleQualifier}, then the Checker + * Framework does not print the given qualifier when printing types. For the above example, the + * Compiler Message Key Checker prints "{@code Map<@CompilerMessageKey String, String>}". + * + *

      If a user runs the Checker Framework with command-line argument {@code -AprintAllQualifiers}, + * then invisible qualifiers are output. */ @Documented @Retention(RetentionPolicy.RUNTIME) diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/LiteralKind.java b/src/java.base/share/classes/org/checkerframework/framework/qual/LiteralKind.java index 7b3b291007b..e027ae6153f 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/LiteralKind.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/LiteralKind.java @@ -13,48 +13,50 @@ */ // https://docs.oracle.com/javase/8/docs/technotes/tools/findingclasses.html#bootclass public enum LiteralKind { - /** Corresponds to {@link com.sun.source.tree.Tree.Kind#NULL_LITERAL} trees. */ - NULL, - /** Corresponds to {@link com.sun.source.tree.Tree.Kind#INT_LITERAL} trees. */ - INT, - /** Corresponds to {@link com.sun.source.tree.Tree.Kind#LONG_LITERAL} trees. */ - LONG, - /** Corresponds to {@link com.sun.source.tree.Tree.Kind#FLOAT_LITERAL} trees. */ - FLOAT, - /** Corresponds to {@link com.sun.source.tree.Tree.Kind#DOUBLE_LITERAL} trees. */ - DOUBLE, - /** Corresponds to {@link com.sun.source.tree.Tree.Kind#BOOLEAN_LITERAL} trees. */ - BOOLEAN, - /** Corresponds to {@link com.sun.source.tree.Tree.Kind#CHAR_LITERAL} trees. */ - CHAR, - /** Corresponds to {@link com.sun.source.tree.Tree.Kind#STRING_LITERAL} trees. */ - STRING, - /** Shorthand for all other LiteralKind constants, other than PRIMITIVE. */ - ALL, - /** Shorthand for all primitive LiteralKind constants: INT, LONG, FLOAT, DOUBLE, BOOLEAN, CHAR. */ - PRIMITIVE; + /** Corresponds to {@link com.sun.source.tree.Tree.Kind#NULL_LITERAL} trees. */ + NULL, + /** Corresponds to {@link com.sun.source.tree.Tree.Kind#INT_LITERAL} trees. */ + INT, + /** Corresponds to {@link com.sun.source.tree.Tree.Kind#LONG_LITERAL} trees. */ + LONG, + /** Corresponds to {@link com.sun.source.tree.Tree.Kind#FLOAT_LITERAL} trees. */ + FLOAT, + /** Corresponds to {@link com.sun.source.tree.Tree.Kind#DOUBLE_LITERAL} trees. */ + DOUBLE, + /** Corresponds to {@link com.sun.source.tree.Tree.Kind#BOOLEAN_LITERAL} trees. */ + BOOLEAN, + /** Corresponds to {@link com.sun.source.tree.Tree.Kind#CHAR_LITERAL} trees. */ + CHAR, + /** Corresponds to {@link com.sun.source.tree.Tree.Kind#STRING_LITERAL} trees. */ + STRING, + /** Shorthand for all other LiteralKind constants, other than PRIMITIVE. */ + ALL, + /** + * Shorthand for all primitive LiteralKind constants: INT, LONG, FLOAT, DOUBLE, BOOLEAN, CHAR. + */ + PRIMITIVE; - /** - * Returns all LiteralKinds except for ALL and PRIMITIVE (which are shorthands for groups of other - * LiteralKinds). - * - * @return list of LiteralKinds except for ALL and PRIMITIVE - */ - public static List allLiteralKinds() { - List list = new ArrayList<>(Arrays.asList(values())); - list.remove(ALL); - list.remove(PRIMITIVE); - return list; - } + /** + * Returns all LiteralKinds except for ALL and PRIMITIVE (which are shorthands for groups of + * other LiteralKinds). + * + * @return list of LiteralKinds except for ALL and PRIMITIVE + */ + public static List allLiteralKinds() { + List list = new ArrayList<>(Arrays.asList(values())); + list.remove(ALL); + list.remove(PRIMITIVE); + return list; + } - /** - * Returns the primitive {@code LiteralKind}s: INT, LONG, FLOAT, DOUBLE, BOOLEAN, CHAR. This is - * all LiteralKinds except for NULL, STRING, and ones that are shorthands for groups of other - * LiteralKinds. - * - * @return list of LiteralKinds except for NULL and STRING - */ - public static List primitiveLiteralKinds() { - return Arrays.asList(INT, LONG, FLOAT, DOUBLE, BOOLEAN, CHAR); - } + /** + * Returns the primitive {@code LiteralKind}s: INT, LONG, FLOAT, DOUBLE, BOOLEAN, CHAR. This is + * all LiteralKinds except for NULL, STRING, and ones that are shorthands for groups of other + * LiteralKinds. + * + * @return list of LiteralKinds except for NULL and STRING + */ + public static List primitiveLiteralKinds() { + return Arrays.asList(INT, LONG, FLOAT, DOUBLE, BOOLEAN, CHAR); + } } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/MonotonicQualifier.java b/src/java.base/share/classes/org/checkerframework/framework/qual/MonotonicQualifier.java index 73b2fde809a..25232ebf100 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/MonotonicQualifier.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/MonotonicQualifier.java @@ -39,5 +39,5 @@ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.ANNOTATION_TYPE}) public @interface MonotonicQualifier { - Class value(); + Class value(); } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/NoDefaultQualifierForUse.java b/src/java.base/share/classes/org/checkerframework/framework/qual/NoDefaultQualifierForUse.java index d1d1c76658d..c82472cd159 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/NoDefaultQualifierForUse.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/NoDefaultQualifierForUse.java @@ -18,6 +18,6 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface NoDefaultQualifierForUse { - /** Top qualifier in hierarchies for which no default annotation for use should be applied. */ - Class[] value() default {}; + /** Top qualifier in hierarchies for which no default annotation for use should be applied. */ + Class[] value() default {}; } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/NoQualifierParameter.java b/src/java.base/share/classes/org/checkerframework/framework/qual/NoQualifierParameter.java index 4dd970b9c73..b61b15aa44e 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/NoQualifierParameter.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/NoQualifierParameter.java @@ -32,10 +32,10 @@ @Inherited public @interface NoQualifierParameter { - /** - * Class of the top qualifier for the hierarchy for which this class has no qualifier parameter. - * - * @return the value - */ - Class[] value(); + /** + * Class of the top qualifier for the hierarchy for which this class has no qualifier parameter. + * + * @return the value + */ + Class[] value(); } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/ParametricTypeVariableUseQualifier.java b/src/java.base/share/classes/org/checkerframework/framework/qual/ParametricTypeVariableUseQualifier.java new file mode 100644 index 00000000000..b0a5b392031 --- /dev/null +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/ParametricTypeVariableUseQualifier.java @@ -0,0 +1,39 @@ +package org.checkerframework.framework.qual; + +import java.lang.annotation.Annotation; +import 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 meta-annotation that indicates that an annotation can be used on a type variable use to + * explicitly indicate that the type variable is parametric in that type hierarchy. + * + *

      This is useful in combination with defaults for {@link TypeUseLocation#TYPE_VARIABLE_USE}, as + * it provides a way to have a default qualifier that expresses parametricity, which is usually + * expressed by the absence of an annotation on the type variable use. + * + *

      An annotation meta-annotated with {@code ParametricTypeVariableUseQualifier} will usually not + * be written explicitly in source code. + * + *

      This annotation is currently only for documentation, but will in the future also be used for + * automatic support for parametric type variable use qualifiers. + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.ANNOTATION_TYPE}) +public @interface ParametricTypeVariableUseQualifier { + /** + * Indicates which type system this annotation refers to (optional, and usually unnecessary). + * When multiple type hierarchies are supported by a single type system, then each parametric + * qualifier needs to indicate which sub-hierarchy it belongs to. Do so by passing the top + * qualifier from the given hierarchy. + * + * @return the top qualifier in the hierarchy of this qualifier + */ + // We use the meaningless Annotation.class as default value and + // then ensure there is a single top qualifier to use. + Class value() default Annotation.class; +} diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/PolymorphicQualifier.java b/src/java.base/share/classes/org/checkerframework/framework/qual/PolymorphicQualifier.java index 4e229d59e34..e3c2573dc20 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/PolymorphicQualifier.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/PolymorphicQualifier.java @@ -19,17 +19,16 @@ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.ANNOTATION_TYPE}) -@AnnotatedFor({"initialization", "nullness"}) public @interface PolymorphicQualifier { - /** - * Indicates which type system this annotation refers to (optional, and usually unnecessary). When - * multiple type hierarchies are supported by a single type system, then each polymorphic - * qualifier needs to indicate which sub-hierarchy it belongs to. Do so by passing the top - * qualifier from the given hierarchy. - * - * @return the top qualifier in the hierarchy of this qualifier - */ - // We use the meaningless Annotation.class as default value and - // then ensure there is a single top qualifier to use. - Class value() default Annotation.class; + /** + * Indicates which type system this annotation refers to (optional, and usually unnecessary). + * When multiple type hierarchies are supported by a single type system, then each polymorphic + * qualifier needs to indicate which sub-hierarchy it belongs to. Do so by passing the top + * qualifier from the given hierarchy. + * + * @return the top qualifier in the hierarchy of this qualifier + */ + // We use the meaningless Annotation.class as default value and + // then ensure there is a single top qualifier to use. + Class value() default Annotation.class; } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/PostconditionAnnotation.java b/src/java.base/share/classes/org/checkerframework/framework/qual/PostconditionAnnotation.java index 67bb434e848..1678614c67c 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/PostconditionAnnotation.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/PostconditionAnnotation.java @@ -60,10 +60,10 @@ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.ANNOTATION_TYPE}) public @interface PostconditionAnnotation { - /** - * The qualifier that will be established as a postcondition. - * - *

      This element is analogous to {@link EnsuresQualifier#qualifier()}. - */ - Class qualifier(); + /** + * The qualifier that will be established as a postcondition. + * + *

      This element is analogous to {@link EnsuresQualifier#qualifier()}. + */ + Class qualifier(); } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/PreconditionAnnotation.java b/src/java.base/share/classes/org/checkerframework/framework/qual/PreconditionAnnotation.java index 95af23ec376..542b1fa13b4 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/PreconditionAnnotation.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/PreconditionAnnotation.java @@ -56,6 +56,6 @@ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.ANNOTATION_TYPE}) public @interface PreconditionAnnotation { - /** The qualifier that must be established as a precondition. */ - Class qualifier(); + /** The qualifier that must be established as a precondition. */ + Class qualifier(); } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/ProgrammaticDefaultLocations.java b/src/java.base/share/classes/org/checkerframework/framework/qual/ProgrammaticDefaultLocations.java new file mode 100644 index 00000000000..6b7df111f5a --- /dev/null +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/ProgrammaticDefaultLocations.java @@ -0,0 +1,36 @@ +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; + +/** + * A meta-annotation that specifies the type-use locations where a type qualifier is permitted to be + * used as a programmatic default (e.g. by {@link + * org.checkerframework.framework.util.defaults.QualifierDefaults#addCheckedCodeDefault}, {@link + * org.checkerframework.framework.util.defaults.QualifierDefaults#addUncheckedCodeDefault}, or + * {@link org.checkerframework.framework.util.defaults.QualifierDefaults#addElementDefault}), even + * if the qualifier's {@link TargetLocations} meta-annotation prohibits explicit use by programmers + * at those locations. + * + *

      If used as a marker annotation without arguments (the default), the qualifier is permitted as + * a programmatic default at all type-use locations ({@link TypeUseLocation#ALL}). + * + *

      If a qualifier has no {@code @ProgrammaticDefaultLocations} annotation, top and bottom + * qualifiers in a qualifier hierarchy are permitted as programmatic defaults at all locations by + * default. Other qualifiers are permitted only at the locations allowed by their {@link + * TargetLocations} meta-annotation (or all locations if {@link TargetLocations} is also omitted). + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.ANNOTATION_TYPE) +public @interface ProgrammaticDefaultLocations { + /** + * Type-use locations at which the qualifier is permitted as a programmatic default. + * + * @return type-use locations + */ + TypeUseLocation[] value() default {TypeUseLocation.ALL}; +} diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/QualifierArgument.java b/src/java.base/share/classes/org/checkerframework/framework/qual/QualifierArgument.java index e56a2800ccc..0a6810569aa 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/QualifierArgument.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/QualifierArgument.java @@ -37,10 +37,10 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface QualifierArgument { - /** - * Specifies the name of the argument of the qualifier, that is passed the values held in the - * annotated element. If the value is omitted or is empty, then the name of the annotated element - * is used as the argument name. - */ - String value() default ""; + /** + * Specifies the name of the argument of the qualifier, that is passed the values held in the + * annotated element. If the value is omitted or is empty, then the name of the annotated + * element is used as the argument name. + */ + String value() default ""; } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/QualifierForLiterals.java b/src/java.base/share/classes/org/checkerframework/framework/qual/QualifierForLiterals.java index 72cf42edf45..6c75761f602 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/QualifierForLiterals.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/QualifierForLiterals.java @@ -15,21 +15,21 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface QualifierForLiterals { - /** - * The kinds of literals whose types have this qualifier. For example, if {@code @MyAnno} is - * meta-annotated with {@code @QualifierForLiterals(LiteralKind.STRING)}, then a literal {@code - * String} constant such as {@code "hello world"} has type {@code @MyAnno String}, but occurrences - * of {@code String} in the source code are not affected. - * - *

      For String literals, also see the {@link #stringPatterns} annotation element/field. - */ - LiteralKind[] value() default {}; + /** + * The kinds of literals whose types have this qualifier. For example, if {@code @MyAnno} is + * meta-annotated with {@code @QualifierForLiterals(LiteralKind.STRING)}, then a literal {@code + * String} constant such as {@code "hello world"} has type {@code @MyAnno String}, but + * occurrences of {@code String} in the source code are not affected. + * + *

      For String literals, also see the {@link #stringPatterns} annotation element/field. + */ + LiteralKind[] value() default {}; - /** - * A string literal that matches any of these patterns has this qualifier. - * - *

      If patterns for multiple qualifiers match, then the string literal is given the greatest - * lower bound of all the matches. - */ - String[] stringPatterns() default {}; + /** + * A string literal that matches any of these patterns has this qualifier. + * + *

      If patterns for multiple qualifiers match, then the string literal is given the greatest + * lower bound of all the matches. + */ + String[] stringPatterns() default {}; } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/RelevantJavaTypes.java b/src/java.base/share/classes/org/checkerframework/framework/qual/RelevantJavaTypes.java index 667f408627e..656fd6d5a18 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/RelevantJavaTypes.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/RelevantJavaTypes.java @@ -13,6 +13,12 @@ * their subtypes. If a checker is not annotated with this annotation, then the checker's qualifiers * may appear on any type. * + *

      In order for this annotation to have an effect, it must be placed on the declaration of a + * class that extends {@code org.checkerframework.framework.source.SourceChecker}. {@code + * org.checkerframework.framework.source.SourceChecker#getRelevantJavaTypes} collects these + * annotations from the checker's class hierarchy, so a subclass inherits and combines the relevant + * Java types of its superclasses. + * *

      This restriction is coarse-grained in that it applies to all type annotations for a given * checker. To have different restrictions for different Java types, override {@code * org.checkerframework.common.basetype.BaseTypeVisitor#visitAnnotatedType(List, Tree)}. @@ -27,17 +33,17 @@ @Target(ElementType.TYPE) @Inherited public @interface RelevantJavaTypes { - /** - * Classes where a type annotation supported by this checker may be written. - * - *

      {@code Object[].class} means that the checker processes all array types. No distinction - * among array types is currently made, and no other array class should be supplied to - * {@code @RelevantJavaTypes}. - * - *

      If a checker processes both primitive and boxed types, both must be specified separately, - * for example as {@code int.class} and {@code Integer.class}. - * - * @return classes where a type annotation supported by this checker may be written - */ - Class[] value(); + /** + * Classes where a type annotation supported by this checker may be written. + * + *

      {@code Object[].class} means that the checker processes all array types. No distinction + * among array types is currently made, and no other array class should be supplied to + * {@code @RelevantJavaTypes}. + * + *

      If a checker processes both primitive and boxed types, both must be specified separately, + * for example as {@code int.class} and {@code Integer.class}. + * + * @return classes where a type annotation supported by this checker may be written + */ + Class[] value(); } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/RequiresQualifier.java b/src/java.base/share/classes/org/checkerframework/framework/qual/RequiresQualifier.java index 5b6bbab7662..2092c396e1a 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/RequiresQualifier.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/RequiresQualifier.java @@ -21,36 +21,36 @@ @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) @Repeatable(RequiresQualifier.List.class) public @interface RequiresQualifier { - /** - * Returns the Java expressions for which the annotation need to be present. - * - * @return the Java expressions for which the annotation need to be present - * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions - */ - String[] expression(); + /** + * Returns the Java expressions for which the annotation need to be present. + * + * @return the Java expressions for which the annotation need to be present + * @checker_framework.manual #java-expressions-as-arguments Syntax of Java expressions + */ + String[] expression(); - /** - * Returns the qualifier that is required. - * - * @return the qualifier that is required - */ - Class qualifier(); + /** + * Returns the qualifier that is required. + * + * @return the qualifier that is required + */ + Class qualifier(); - /** - * A wrapper annotation that makes the {@link RequiresQualifier} annotation repeatable. - * - *

      Programmers generally do not need to write this. It is created by Java when a programmer - * writes more than one {@link RequiresQualifier} annotation at the same location. - */ - @Documented - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) - public static @interface List { /** - * Returns the repeatable annotations. + * A wrapper annotation that makes the {@link RequiresQualifier} annotation repeatable. * - * @return the repeatable annotations + *

      Programmers generally do not need to write this. It is created by Java when a programmer + * writes more than one {@link RequiresQualifier} annotation at the same location. */ - RequiresQualifier[] value(); - } + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) + public static @interface List { + /** + * Returns the repeatable annotations. + * + * @return the repeatable annotations + */ + RequiresQualifier[] value(); + } } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/StubFiles.java b/src/java.base/share/classes/org/checkerframework/framework/qual/StubFiles.java index 25d74cbda4a..18f3309d3b2 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/StubFiles.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/StubFiles.java @@ -11,9 +11,9 @@ * addition to {@code jdk.astub}. This allows larger compound checkers to separate the annotations * into multiple files, or to provide annotations for non-JDK classes. * - *

      This annotation is not inherited. That means that if a checker with this annotation is - * subclassed, then this annotation must be copied to the subclass and the stub file must also be - * copied to the directory that contains the subclass. + *

      A checker inherits the stub files of the nearest superclass that declares this annotation, + * unless it declares its own {@code @StubFiles} annotation. Furthermore, stub files are shared + * bidirectionally between compound checkers and their subcheckers. * * @checker_framework.manual #creating-a-checker-annotated-jdk Annotated JDK */ @@ -21,9 +21,11 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface StubFiles { - /** - * Stub file names. These are basenames: they include the extension (usually ".astub"), but no - * directory component. - */ - String[] value(); + /** + * Stub file names. These are basenames: they include the extension (usually ".astub"), but no + * directory component. + * + * @return the stub file names + */ + String[] value(); } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/SubtypeOf.java b/src/java.base/share/classes/org/checkerframework/framework/qual/SubtypeOf.java index 5dcb5dc3980..27db9070889 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/SubtypeOf.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/SubtypeOf.java @@ -38,8 +38,7 @@ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) -@AnnotatedFor({"initialization", "nullness"}) public @interface SubtypeOf { - /** An array of the supertype qualifiers of the annotated qualifier. */ - Class[] value(); + /** An array of the supertype qualifiers of the annotated qualifier. */ + Class[] value(); } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/TargetLocations.java b/src/java.base/share/classes/org/checkerframework/framework/qual/TargetLocations.java index 704566ab8ce..d1f544e7017 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/TargetLocations.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/TargetLocations.java @@ -7,31 +7,37 @@ import java.lang.annotation.Target; /** - * NOTE: This meta-annotation is not currently - * enforced. - * - *

      A meta-annotation that restricts the type-use locations where a type qualifier may be written. + * A meta-annotation that restricts the type-use locations where a type qualifier may be applied. * When written together with {@code @Target({ElementType.TYPE_USE})}, the given type qualifier may - * be written only at locations listed in the {@code @TargetLocations(...)} meta-annotation. + * be applied only at locations listed in the {@code @TargetLocations(...)} meta-annotation. * {@code @Target({ElementType.TYPE_USE})} together with no {@code @TargetLocations(...)} means that - * the qualifier can be written on any type use. + * the qualifier can be applied to any type use. {@code @TargetLocations({})} means that the + * qualifier should not be used in source code. The same goal can be achieved by writing + * {@code @Target({})}, which is enforced by javac itself. {@code @TargetLocations({...})} is + * enforced by the checker. The resulting errors from the checker can either be suppressed using + * {@code @SuppressWarnings("type.invalid.annotations.on.location")} or can be ignored by providing + * the {@code -AignoreTargetLocations} option. * - *

      This enables a type system designer to permit a qualifier to be written only in certain + *

      This enables a type system designer to permit a qualifier to be applied only in certain * locations. For example, some type systems' top and bottom qualifier (such as {@link - * org.checkerframework.checker.nullness.qual.KeyForBottom}) should only be written on an explicit + * org.checkerframework.checker.regex.qual.RegexBottom}) should only be written on an explicit * wildcard upper or lower bound. This meta-annotation is a declarative, coarse-grained approach to * enable that. For finer-grained control, override {@code visit*} methods that visit trees in * BaseTypeVisitor. * - *

      This annotation does not prevent the type system from defaulting, inferring, or computing the - * given type annotation at the given location. It only prevents users from writing an explicit - * annotation at the given location. + *

      {@code @TargetLocations} are used for all appearances of qualifiers regardless of whether they + * are provided explicitly or implicitly (inferred or computed). Therefore, only use type-use + * locations {@code LOWER_BOUND/UPPER_BOUND} instead of the {@code IMPLICIT_XX/EXPLICIT_XX} + * alternatives. */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface TargetLocations { - /** Type uses at which the qualifier is permitted to be written in source code. */ - TypeUseLocation[] value(); + /** + * Type uses at which the qualifier is permitted to be applied in source code. + * + * @return type-use locations declared in this meta-annotation + */ + TypeUseLocation[] value(); } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/TypeKind.java b/src/java.base/share/classes/org/checkerframework/framework/qual/TypeKind.java index 9adef287c7c..e80c6fd573b 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/TypeKind.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/TypeKind.java @@ -10,66 +10,66 @@ * annotations */ public enum TypeKind { - /** Corresponds to {@link javax.lang.model.type.TypeKind#BOOLEAN} types. */ - BOOLEAN, + /** Corresponds to {@link javax.lang.model.type.TypeKind#BOOLEAN} types. */ + BOOLEAN, - /** Corresponds to {@link javax.lang.model.type.TypeKind#BYTE} types. */ - BYTE, + /** Corresponds to {@link javax.lang.model.type.TypeKind#BYTE} types. */ + BYTE, - /** Corresponds to {@link javax.lang.model.type.TypeKind#SHORT} types. */ - SHORT, + /** Corresponds to {@link javax.lang.model.type.TypeKind#SHORT} types. */ + SHORT, - /** Corresponds to {@link javax.lang.model.type.TypeKind#INT} types. */ - INT, + /** Corresponds to {@link javax.lang.model.type.TypeKind#INT} types. */ + INT, - /** Corresponds to {@link javax.lang.model.type.TypeKind#LONG} types. */ - LONG, + /** Corresponds to {@link javax.lang.model.type.TypeKind#LONG} types. */ + LONG, - /** Corresponds to {@link javax.lang.model.type.TypeKind#CHAR} types. */ - CHAR, + /** Corresponds to {@link javax.lang.model.type.TypeKind#CHAR} types. */ + CHAR, - /** Corresponds to {@link javax.lang.model.type.TypeKind#FLOAT} types. */ - FLOAT, + /** Corresponds to {@link javax.lang.model.type.TypeKind#FLOAT} types. */ + FLOAT, - /** Corresponds to {@link javax.lang.model.type.TypeKind#DOUBLE} types. */ - DOUBLE, + /** Corresponds to {@link javax.lang.model.type.TypeKind#DOUBLE} types. */ + DOUBLE, - /** Corresponds to {@link javax.lang.model.type.TypeKind#VOID} types. */ - VOID, + /** Corresponds to {@link javax.lang.model.type.TypeKind#VOID} types. */ + VOID, - /** Corresponds to {@link javax.lang.model.type.TypeKind#NONE} types. */ - NONE, + /** Corresponds to {@link javax.lang.model.type.TypeKind#NONE} types. */ + NONE, - /** Corresponds to {@link javax.lang.model.type.TypeKind#NULL} types. */ - NULL, + /** Corresponds to {@link javax.lang.model.type.TypeKind#NULL} types. */ + NULL, - /** Corresponds to {@link javax.lang.model.type.TypeKind#ARRAY} types. */ - ARRAY, + /** Corresponds to {@link javax.lang.model.type.TypeKind#ARRAY} types. */ + ARRAY, - /** Corresponds to {@link javax.lang.model.type.TypeKind#DECLARED} types. */ - DECLARED, + /** Corresponds to {@link javax.lang.model.type.TypeKind#DECLARED} types. */ + DECLARED, - /** Corresponds to {@link javax.lang.model.type.TypeKind#ERROR} types. */ - ERROR, + /** Corresponds to {@link javax.lang.model.type.TypeKind#ERROR} types. */ + ERROR, - /** Corresponds to {@link javax.lang.model.type.TypeKind#TYPEVAR} types. */ - TYPEVAR, + /** Corresponds to {@link javax.lang.model.type.TypeKind#TYPEVAR} types. */ + TYPEVAR, - /** Corresponds to {@link javax.lang.model.type.TypeKind#WILDCARD} types. */ - WILDCARD, + /** Corresponds to {@link javax.lang.model.type.TypeKind#WILDCARD} types. */ + WILDCARD, - /** Corresponds to {@link javax.lang.model.type.TypeKind#PACKAGE} types. */ - PACKAGE, + /** Corresponds to {@link javax.lang.model.type.TypeKind#PACKAGE} types. */ + PACKAGE, - /** Corresponds to {@link javax.lang.model.type.TypeKind#EXECUTABLE} types. */ - EXECUTABLE, + /** Corresponds to {@link javax.lang.model.type.TypeKind#EXECUTABLE} types. */ + EXECUTABLE, - /** Corresponds to {@link javax.lang.model.type.TypeKind#OTHER} types. */ - OTHER, + /** Corresponds to {@link javax.lang.model.type.TypeKind#OTHER} types. */ + OTHER, - /** Corresponds to {@link javax.lang.model.type.TypeKind#UNION} types. */ - UNION, + /** Corresponds to {@link javax.lang.model.type.TypeKind#UNION} types. */ + UNION, - /** Corresponds to {@link javax.lang.model.type.TypeKind#INTERSECTION} types. */ - INTERSECTION; + /** Corresponds to {@link javax.lang.model.type.TypeKind#INTERSECTION} types. */ + INTERSECTION; } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/TypeUseLocation.java b/src/java.base/share/classes/org/checkerframework/framework/qual/TypeUseLocation.java index 53039f19960..22809919f57 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/TypeUseLocation.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/TypeUseLocation.java @@ -6,83 +6,151 @@ *

      The order of enums is important. Defaults are applied in this order. In particular, this means * that OTHERWISE and ALL should be last. * + *

      For an annotation on a variable which has element kind ENUM_CONSTANT, the annotation's + * type-use location is either {@code TypeUseLocation.FIELD} or {@code + * TypeUseLocation.CONSTRUCTOR_RESULT}. + * + *

      Note: The use locations listed here are not complete, for more details see EISOP Issue #340 + * * @see DefaultQualifier * @see javax.lang.model.element.ElementKind */ public enum TypeUseLocation { - /** Apply default annotations to all unannotated raw types of fields. */ - FIELD, - - /** - * Apply default annotations to all unannotated raw types of local variables, casts, and - * instanceof. - */ - LOCAL_VARIABLE, - - /** Apply default annotations to all unannotated raw types of resource variables. */ - RESOURCE_VARIABLE, - - /** Apply default annotations to all unannotated raw types of exception parameters. */ - EXCEPTION_PARAMETER, - - /** Apply default annotations to all unannotated raw types of receiver types. */ - RECEIVER, - - /** - * Apply default annotations to all unannotated raw types of formal parameter types, excluding the - * receiver. - */ - PARAMETER, - - /** Apply default annotations to all unannotated raw types of return types. */ - RETURN, - - /** Apply default annotations to all unannotated raw types of constructor result types. */ - CONSTRUCTOR_RESULT, - - /** - * Apply default annotations to unannotated lower bounds for type variables and wildcards both - * explicit ones in {@code extends} clauses, and implicit upper bounds when no explicit {@code - * extends} or {@code super} clause is present. - */ - LOWER_BOUND, - - /** - * Apply default annotations to unannotated, but explicit lower bounds: {@code } - */ - EXPLICIT_LOWER_BOUND, - - /** - * Apply default annotations to unannotated, but implicit lower bounds: {@code } {@code }. - */ - IMPLICIT_LOWER_BOUND, - - /** - * Apply default annotations to unannotated upper bounds: both explicit ones in {@code extends} - * clauses, and implicit upper bounds when no explicit {@code extends} or {@code super} clause is - * present. - * - *

      Especially useful for parametrized classes that provide a lot of static methods with the - * same generic parameters as the class. - */ - UPPER_BOUND, - - /** - * Apply default annotations to unannotated, but explicit upper bounds: {@code }. - */ - EXPLICIT_UPPER_BOUND, - - /** Apply default annotations to unannotated type variables: {@code }. */ - IMPLICIT_UPPER_BOUND, - - /** Apply if nothing more concrete is provided. TODO: clarify relation to ALL. */ - OTHERWISE, - - /** - * Apply default annotations to all type uses other than uses of type parameters. Does not allow - * any of the other constants. Usually you want OTHERWISE. - */ - ALL; + /** Apply default annotations to unannotated top-level types of fields. */ + FIELD, + + /** + * Apply default annotations to unannotated top-level types of local variables, casts, and + * instanceof. + */ + LOCAL_VARIABLE, + + /** Apply default annotations to unannotated top-level types of resource variables. */ + RESOURCE_VARIABLE, + + /** Apply default annotations to unannotated top-level types of exception parameters. */ + EXCEPTION_PARAMETER, + + /** Apply default annotations to unannotated top-level types of receiver types. */ + RECEIVER, + + /** + * Apply default annotations to unannotated top-level types of formal parameter types, excluding + * the receiver. + */ + PARAMETER, + + /** Apply default annotations to unannotated top-level types of return types. */ + RETURN, + + /** Apply default annotations to unannotated top-level types of constructor result types. */ + CONSTRUCTOR_RESULT, + + /** + * Apply default annotations to unannotated top-level lower bounds of type parameters and + * wildcards, both explicit ones in {@code super} clauses, and implicit lower bounds when no + * explicit {@code extends} or {@code super} clause is present. + */ + LOWER_BOUND, + + /** + * Apply default annotations to unannotated top-level explicit lower bounds of wildcards: {@code + * }. Type parameters have no syntax for explicit lower bound types. + */ + EXPLICIT_LOWER_BOUND, + + /** + * Apply default annotations to unannotated implicit lower bounds of type parameters and + * wildcards: {@code } and {@code }, possibly with explicit upper bounds. + */ + // Note: no distinction between implicit lower bound when upper bound is explicit or not, in + // contrast to what we do for upper bounds. We can add that if a type system needs it. + IMPLICIT_LOWER_BOUND, + + /** + * Apply default annotations to unannotated top-level upper bounds of type parameters and + * wildcards: both explicit ones in {@code extends} clauses, and implicit upper bounds when no + * explicit {@code extends} or {@code super} clause is present. + * + *

      Especially useful for parametrized classes that provide a lot of static methods with the + * same generic parameters as the class. + */ + UPPER_BOUND, + + /** + * Apply default annotations to unannotated top-level explicit type parameter and wildcard upper + * bounds: {@code } and {@code }. + */ + EXPLICIT_UPPER_BOUND, + + /** + * Apply default annotations to unannotated top-level explicit type parameter upper bounds: + * {@code }. + */ + EXPLICIT_TYPE_PARAMETER_UPPER_BOUND, + + /** + * Apply default annotations to unannotated top-level explicit wildcard upper bounds: {@code }. + */ + EXPLICIT_WILDCARD_UPPER_BOUND, + + /** + * Apply default annotations to unannotated upper bounds of type parameters and wildcards + * without explicit upper bounds: {@code }, {@code }, and {@code }. + */ + IMPLICIT_UPPER_BOUND, + + /** + * Apply default annotations to unannotated upper bounds of type parameters without explicit + * upper bounds: {@code }. + */ + IMPLICIT_TYPE_PARAMETER_UPPER_BOUND, + + /** + * Apply default annotations to unannotated upper bounds of wildcards without a super bound: + * {@code }. + */ + IMPLICIT_WILDCARD_UPPER_BOUND_NO_SUPER, + + /** + * Apply default annotations to unannotated upper bounds of wildcards with a super bound: {@code + * }. + */ + IMPLICIT_WILDCARD_UPPER_BOUND_SUPER, + + /** + * Apply default annotations to unannotated upper bounds of wildcards with or without a super + * bound: {@code } or {@code }. + */ + IMPLICIT_WILDCARD_UPPER_BOUND, + + /** + * Apply default annotations to unannotated type variable uses that are not top-level local + * variables: {@code T field} or {@code List local}. + * + *

      Such uses of type variables are not flow-sensitively refined and are therefore usually + * parametric. + * + *

      To get parametric polymorphism: add a qualifier that is meta-annotated with {@link + * ParametricTypeVariableUseQualifier} to your type system and use it as default for {@code + * TYPE_VARIABLE_USE}, which is treated like no annotation on the type variable use. + * + *

      We could name this constant {@code TYPE_VARIABLE_USE_NOT_TOP_LEVEL_LOCAL_VARIABLE} and + * introduce a separate constant {@code TYPE_VARIABLE_USE_TOP_LEVEL_LOCAL_VARIABLE}. At the + * moment we use the {@code LOCAL_VARIABLE} default for unannotated top-level type variable uses + * of local variables: {@code T local}. + */ + TYPE_VARIABLE_USE, + + /** Apply if nothing more concrete is provided. TODO: clarify relation to ALL. */ + OTHERWISE, + + /** + * Apply default annotations to all type uses other than uses of type parameters. Does not allow + * any of the other constants. Usually you want OTHERWISE. + */ + ALL; } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/UnannotatedFor.java b/src/java.base/share/classes/org/checkerframework/framework/qual/UnannotatedFor.java new file mode 100644 index 00000000000..5280ce8d266 --- /dev/null +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/UnannotatedFor.java @@ -0,0 +1,89 @@ +package org.checkerframework.framework.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; + +/** + * Indicates that this package, class, method, or constructor has not been annotated for the given + * type system, even though an enclosing element is annotated for it. For example, if a package is + * {@code @AnnotatedFor("nullness")} but one of its classes has not been annotated with + * {@code @Nullable} and friends, mark that class {@code @UnannotatedFor("nullness")}. The argument + * to {@code UnannotatedFor} is not an annotation name, but a checker name. + * + *

      This annotation has no effect unless the {@code + * -AuseConservativeDefaultsForUncheckedCode=source} or the {@code -AonlyAnnotatedFor} command-line + * argument is supplied. It only subtracts from the scope of an enclosing {@link AnnotatedFor}: an + * element in its scope is treated as if no enclosing {@code @AnnotatedFor} were present, so its + * warnings are suppressed, and under {@code -AuseConservativeDefaultsForUncheckedCode=source} it is + * also defaulted using conservative defaults. ({@code -AonlyAnnotatedFor} suppresses warnings + * without changing defaults, the same as for {@link AnnotatedFor}.) An {@code @AnnotatedFor} on a + * nested element takes effect again for that element. Writing both an {@code @AnnotatedFor} and an + * {@code @UnannotatedFor} that name the same checker on one declaration is a warning ({@code + * conflicting.annotatedfor}), because the two contradict each other; if that warning is suppressed, + * the {@code @AnnotatedFor} wins, since {@code @UnannotatedFor} only subtracts from an + * enclosing scope. + * + *

      Like {@link AnnotatedFor}, this annotation is stored in class files and is available via + * reflection at run time. + * + *

      An {@code @UnannotatedFor} on a package also applies to subpackages, unless the {@code + * applyToSubpackages} field is set to false. The innermost package annotation wins: an + * {@code @UnannotatedFor} on a package excludes its subpackages from an {@code @AnnotatedFor} on an + * enclosing package, and vice versa. + * + *

      You may write multiple {@code @UnannotatedFor} annotations at the same location, for example + * to give two type systems different {@code applyToSubpackages} settings on one package: + * + *

      + *   {@literal @}UnannotatedFor(value = "nullness", applyToSubpackages = false)
      + *   {@literal @}UnannotatedFor(value = "index", applyToSubpackages = true)
      + *   package mypackage;
      + * 
      + * + * @checker_framework.manual #compiling-libraries Compiling partially-annotated libraries + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PACKAGE}) +@Repeatable(UnannotatedFor.List.class) +public @interface UnannotatedFor { + /** + * Returns the type systems for which the annotated element has not 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 @UnannotatedFor({})}, has no effect. + * + * @return the type systems for which the annotated element has not been annotated + * @checker_framework.manual #shorthand-for-checkers Short names for built-in checkers + */ + String[] value(); + + /** + * When used on a package, whether this annotation should also apply to subpackages. + * + * @return whether this annotation should be inherited by subpackages + */ + boolean applyToSubpackages() default true; + + /** + * A wrapper annotation that makes the {@link UnannotatedFor} annotation repeatable. + * + *

      Programmers generally do not need to write this. It is created by Java when a programmer + * writes more than one {@link UnannotatedFor} annotation at the same location. + */ + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PACKAGE}) + public static @interface List { + /** + * Returns the repeatable annotations. + * + * @return the repeatable annotations + */ + UnannotatedFor[] value(); + } +} diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/Unused.java b/src/java.base/share/classes/org/checkerframework/framework/qual/Unused.java index e431e76dc32..f0d00d15217 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/Unused.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/Unused.java @@ -39,9 +39,9 @@ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) public @interface Unused { - /** - * The field that is annotated with @Unused may not be accessed via a receiver that is annotated - * with the "when" annotation. - */ - Class when(); + /** + * The field that is annotated with @Unused may not be accessed via a receiver that is annotated + * with the "when" annotation. + */ + Class when(); } diff --git a/src/java.base/share/classes/org/checkerframework/framework/qual/UpperBoundFor.java b/src/java.base/share/classes/org/checkerframework/framework/qual/UpperBoundFor.java index f1f334242e7..75d24027f27 100644 --- a/src/java.base/share/classes/org/checkerframework/framework/qual/UpperBoundFor.java +++ b/src/java.base/share/classes/org/checkerframework/framework/qual/UpperBoundFor.java @@ -18,7 +18,7 @@ * An example is the declaration * *

      
      - * {@literal @}DefaultFor(classes=String.class)
      + * {@literal @}UpperBoundFor(types=String.class)
        * {@literal @}interface MyAnno {}
        * 
      * @@ -31,19 +31,19 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface UpperBoundFor { - /** - * Returns {@link TypeKind}s of types that get an upper bound. The meta-annotated annotation is - * the upper bound. - * - * @return {@link TypeKind}s of types that get an upper bound - */ - TypeKind[] typeKinds() default {}; + /** + * Returns {@link TypeKind}s of types that get an upper bound. The meta-annotated annotation is + * the upper bound. + * + * @return {@link TypeKind}s of types that get an upper bound + */ + TypeKind[] typeKinds() default {}; - /** - * Returns {@link Class}es that should get an upper bound. The meta-annotated annotation is the - * upper bound. - * - * @return {@link Class}es that get an upper bound - */ - Class[] types() default {}; + /** + * Returns {@link Class}es that should get an upper bound. The meta-annotated annotation is the + * upper bound. + * + * @return {@link Class}es that get an upper bound + */ + Class[] types() default {}; } diff --git a/src/java.base/share/classes/sun/net/www/HeaderParser.java b/src/java.base/share/classes/sun/net/www/HeaderParser.java index ec69c47f035..a41ffb02116 100644 --- a/src/java.base/share/classes/sun/net/www/HeaderParser.java +++ b/src/java.base/share/classes/sun/net/www/HeaderParser.java @@ -26,7 +26,6 @@ package sun.net.www; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.util.Iterator; import java.util.Locale; @@ -208,7 +207,6 @@ class ParserIterator implements Iterator { public boolean hasNext () { return index next() { return new Map.Entry() { String k = i.next(); diff --git a/src/java.base/share/classes/sun/util/locale/StringTokenIterator.java b/src/java.base/share/classes/sun/util/locale/StringTokenIterator.java index 7d0ab209641..5a5edc2823f 100644 --- a/src/java.base/share/classes/sun/util/locale/StringTokenIterator.java +++ b/src/java.base/share/classes/sun/util/locale/StringTokenIterator.java @@ -31,7 +31,6 @@ package sun.util.locale; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; public class StringTokenIterator { private String text; @@ -74,7 +73,6 @@ public boolean isDone() { return done; } - @SideEffectsOnly("this") public String next() { if (hasNext()) { start = end + 1; diff --git a/src/java.base/share/classes/sun/util/resources/ParallelListResourceBundle.java b/src/java.base/share/classes/sun/util/resources/ParallelListResourceBundle.java index e372d57d222..1200d1ce217 100644 --- a/src/java.base/share/classes/sun/util/resources/ParallelListResourceBundle.java +++ b/src/java.base/share/classes/sun/util/resources/ParallelListResourceBundle.java @@ -28,7 +28,6 @@ import org.checkerframework.checker.lock.qual.GuardSatisfied; import org.checkerframework.checker.signedness.qual.UnknownSignedness; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.util.AbstractSet; import java.util.Collections; @@ -240,7 +239,6 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") public String next() { if (hasNext()) { return itr.next(); diff --git a/src/java.base/unix/classes/java/lang/ProcessEnvironment.java b/src/java.base/unix/classes/java/lang/ProcessEnvironment.java index c91fca356b5..c030f652db2 100644 --- a/src/java.base/unix/classes/java/lang/ProcessEnvironment.java +++ b/src/java.base/unix/classes/java/lang/ProcessEnvironment.java @@ -55,7 +55,6 @@ package java.lang; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.util.*; @@ -338,7 +337,6 @@ public Iterator> iterator() { Iterator> i = s.iterator(); @Pure public boolean hasNext() {return i.hasNext();} - @SideEffectsOnly("this") public Map.Entry next() { return new StringEntry(i.next()); } @@ -385,7 +383,6 @@ public Iterator iterator() { Iterator i = c.iterator(); @Pure public boolean hasNext() {return i.hasNext();} - @SideEffectsOnly("this") public String next() {return i.next().toString();} public void remove() {i.remove();} }; @@ -416,7 +413,6 @@ public Iterator iterator() { Iterator i = s.iterator(); @Pure public boolean hasNext() {return i.hasNext();} - @SideEffectsOnly("this") public String next() {return i.next().toString();} public void remove() { i.remove();} }; diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixDirectoryStream.java b/src/java.base/unix/classes/sun/nio/fs/UnixDirectoryStream.java index 4ef0d19fc3c..68ad84da8aa 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixDirectoryStream.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixDirectoryStream.java @@ -26,7 +26,6 @@ package sun.nio.fs; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.nio.file.*; import java.util.Iterator; @@ -204,7 +203,6 @@ public synchronized boolean hasNext() { } @Override - @SideEffectsOnly("this") public synchronized Path next() { Path result; if (nextEntry == null && !atEof) { diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java index 6ddc73690aa..a4192da3b8a 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java @@ -26,7 +26,6 @@ package sun.nio.fs; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.nio.ByteBuffer; import java.nio.file.AtomicMoveNotSupportedException; @@ -259,7 +258,6 @@ public synchronized boolean hasNext() { } @Override - @SideEffectsOnly("this") public synchronized FileStore next() { if (next == null) next = readNext(); diff --git a/src/java.base/windows/classes/java/lang/ProcessEnvironment.java b/src/java.base/windows/classes/java/lang/ProcessEnvironment.java index 8f0feb7519a..aba74f57fcd 100644 --- a/src/java.base/windows/classes/java/lang/ProcessEnvironment.java +++ b/src/java.base/windows/classes/java/lang/ProcessEnvironment.java @@ -64,7 +64,6 @@ package java.lang; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.util.*; @@ -145,7 +144,6 @@ public Iterator> iterator() { Iterator> i = s.iterator(); @Pure public boolean hasNext() { return i.hasNext();} - @SideEffectsOnly("this") public Map.Entry next() { return new CheckedEntry(i.next()); } diff --git a/src/java.base/windows/classes/sun/nio/ch/DefaultPollerProvider.java b/src/java.base/windows/classes/sun/nio/ch/DefaultPollerProvider.java index 67625352baf..f3147cf08c9 100644 --- a/src/java.base/windows/classes/sun/nio/ch/DefaultPollerProvider.java +++ b/src/java.base/windows/classes/sun/nio/ch/DefaultPollerProvider.java @@ -26,6 +26,12 @@ import java.io.IOException; +import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.qual.Pure; +import org.checkerframework.dataflow.qual.SideEffectFree; + /** * Default PollerProvider for Windows based on wepoll. */ diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsDirectoryStream.java b/src/java.base/windows/classes/sun/nio/fs/WindowsDirectoryStream.java index 0916f458799..bb9b70e136a 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsDirectoryStream.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsDirectoryStream.java @@ -26,7 +26,6 @@ package sun.nio.fs; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; @@ -215,7 +214,6 @@ public synchronized boolean hasNext() { } @Override - @SideEffectsOnly("this") public synchronized Path next() { Path result = null; if (nextEntry == null && !atEof) { diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystem.java b/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystem.java index faf07b454b9..1d3eb09a0b8 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystem.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystem.java @@ -26,7 +26,6 @@ package sun.nio.fs; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.nio.file.*; import java.nio.file.attribute.*; @@ -170,7 +169,6 @@ public synchronized boolean hasNext() { } @Override - @SideEffectsOnly("this") public synchronized FileStore next() { if (next == null) next = readNext(); diff --git a/src/java.compiler/share/classes/javax/lang/model/util/Types.java b/src/java.compiler/share/classes/javax/lang/model/util/Types.java index 5e8fc2f3ea9..96204e56053 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/Types.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/Types.java @@ -28,6 +28,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.framework.qual.AnnotatedFor; + import java.lang.annotation.Annotation; import java.lang.annotation.AnnotationTypeMismatchException; import java.lang.annotation.IncompleteAnnotationException; diff --git a/src/java.desktop/share/classes/java/awt/ModalEventFilter.java b/src/java.desktop/share/classes/java/awt/ModalEventFilter.java index f9f3945c005..24e4b68243f 100644 --- a/src/java.desktop/share/classes/java/awt/ModalEventFilter.java +++ b/src/java.desktop/share/classes/java/awt/ModalEventFilter.java @@ -32,7 +32,7 @@ import sun.awt.AppContext; @AnnotatedFor({"interning"}) -public abstract @UsesObjectEquals class ModalEventFilter implements EventFilter { +abstract @UsesObjectEquals class ModalEventFilter implements EventFilter { protected Dialog modalDialog; protected boolean disabled; diff --git a/src/java.desktop/share/classes/javax/imageio/stream/ImageOutputStreamImpl.java b/src/java.desktop/share/classes/javax/imageio/stream/ImageOutputStreamImpl.java index 1ef28b53dca..07e2003720d 100644 --- a/src/java.desktop/share/classes/javax/imageio/stream/ImageOutputStreamImpl.java +++ b/src/java.desktop/share/classes/javax/imageio/stream/ImageOutputStreamImpl.java @@ -31,6 +31,8 @@ import jdk.internal.util.ByteArray; import jdk.internal.util.ByteArrayLittleEndian; +import jdk.internal.util.ByteArray; +import jdk.internal.util.ByteArrayLittleEndian; import java.io.IOException; import java.io.UTFDataFormatException; import java.nio.ByteOrder; diff --git a/src/java.desktop/share/classes/javax/swing/DefaultListCellRenderer.java b/src/java.desktop/share/classes/javax/swing/DefaultListCellRenderer.java index ea8f94f99af..e8fcbf4ae95 100644 --- a/src/java.desktop/share/classes/javax/swing/DefaultListCellRenderer.java +++ b/src/java.desktop/share/classes/javax/swing/DefaultListCellRenderer.java @@ -26,8 +26,8 @@ package javax.swing; import org.checkerframework.checker.interning.qual.Interned; -import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; import java.awt.Color; import java.awt.Component; diff --git a/src/java.desktop/share/classes/javax/swing/JOptionPane.java b/src/java.desktop/share/classes/javax/swing/JOptionPane.java index 32f20f7424c..5cc0e4ee11f 100644 --- a/src/java.desktop/share/classes/javax/swing/JOptionPane.java +++ b/src/java.desktop/share/classes/javax/swing/JOptionPane.java @@ -26,8 +26,8 @@ package javax.swing; import org.checkerframework.checker.interning.qual.Interned; -import org.checkerframework.framework.qual.AnnotatedFor; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; import java.awt.BorderLayout; import java.awt.Component; @@ -1192,8 +1192,8 @@ public static int showInternalConfirmDialog(@Nullable Component parentComponent, * @return an integer indicating the option selected by the user */ public static int showInternalConfirmDialog(@Nullable Component parentComponent, - @Nullable Object message, - @Nullable String title, int optionType, + @Nullable Object message, + @Nullable String title, int optionType, int messageType) { return showInternalConfirmDialog(parentComponent, message, title, optionType, messageType, null); @@ -1404,7 +1404,7 @@ public static String showInternalInputDialog(@Nullable Component parentComponent * @return user's input */ public static String showInternalInputDialog(@Nullable Component parentComponent, - @Nullable Object message, @Nullable String title, int messageType) { + @Nullable Object message, @Nullable String title, int messageType) { return (String)showInternalInputDialog(parentComponent, message, title, messageType, null, null, null); } @@ -1517,7 +1517,7 @@ public static Object showInternalInputDialog(@Nullable Component parentComponent * not have a valid parent */ public JInternalFrame createInternalFrame(@Nullable Component parentComponent, - @Nullable String title) { + @Nullable String title) { Container parent = JOptionPane.getDesktopPaneForComponent(parentComponent); diff --git a/src/java.management/share/classes/sun/management/counter/perf/PerfInstrumentation.java b/src/java.management/share/classes/sun/management/counter/perf/PerfInstrumentation.java index 9091b6aa347..47ba3c62317 100644 --- a/src/java.management/share/classes/sun/management/counter/perf/PerfInstrumentation.java +++ b/src/java.management/share/classes/sun/management/counter/perf/PerfInstrumentation.java @@ -26,7 +26,6 @@ package sun.management.counter.perf; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import sun.management.counter.*; @@ -85,7 +84,6 @@ boolean hasNext() { return (nextEntry < prologue.getUsed()); } - @SideEffectsOnly("this") Counter getNextCounter() { if (! hasNext()) { return null; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HeaderParser.java b/src/java.net.http/share/classes/jdk/internal/net/http/HeaderParser.java index 099f323266d..8559a5467b8 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HeaderParser.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HeaderParser.java @@ -26,7 +26,6 @@ package jdk.internal.net.http; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.util.Iterator; import java.util.Locale; @@ -208,7 +207,6 @@ public boolean hasNext () { return index= nkeys) { throw new NoSuchElementException(); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/RequestPublishers.java b/src/java.net.http/share/classes/jdk/internal/net/http/RequestPublishers.java index 2fc75039a23..728db54ce5c 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/RequestPublishers.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/RequestPublishers.java @@ -26,7 +26,6 @@ package jdk.internal.net.http; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -140,7 +139,6 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") public ByteBuffer next() { ByteBuffer buffer = buffers.poll(); while (buffer == null) { @@ -471,7 +469,6 @@ private boolean hasNext0() { } @Override - @SideEffectsOnly("this") public ByteBuffer next() { stateLock.lock(); try { diff --git a/src/java.sql/share/classes/java/sql/Connection.java b/src/java.sql/share/classes/java/sql/Connection.java index 3347d4144f7..fc5dfebd4ca 100644 --- a/src/java.sql/share/classes/java/sql/Connection.java +++ b/src/java.sql/share/classes/java/sql/Connection.java @@ -26,6 +26,7 @@ package java.sql; import org.checkerframework.checker.mustcall.qual.InheritableMustCall; +import org.checkerframework.checker.sqlquotes.qual.SqlEvenQuotes; import org.checkerframework.framework.qual.AnnotatedFor; import java.util.Properties; @@ -141,7 +142,7 @@ public interface Connection extends Wrapper, AutoCloseable { * @throws SQLException if a database access error occurs * or this method is called on a closed connection */ - PreparedStatement prepareStatement(String sql) + PreparedStatement prepareStatement(@SqlEvenQuotes String sql) throws SQLException; /** @@ -174,7 +175,7 @@ PreparedStatement prepareStatement(String sql) * @throws SQLException if a database access error occurs * or this method is called on a closed connection */ - CallableStatement prepareCall(String sql) throws SQLException; + CallableStatement prepareCall(@SqlEvenQuotes String sql) throws SQLException; /** * Converts the given SQL statement into the system's native SQL grammar. @@ -188,7 +189,7 @@ PreparedStatement prepareStatement(String sql) * @throws SQLException if a database access error occurs * or this method is called on a closed connection */ - String nativeSQL(String sql) throws SQLException; + String nativeSQL(@SqlEvenQuotes String sql) throws SQLException; /** * Sets this connection's auto-commit mode to the given state. @@ -569,7 +570,7 @@ Statement createStatement(int resultSetType, int resultSetConcurrency) * set type and result set concurrency. * @since 1.2 */ - PreparedStatement prepareStatement(String sql, int resultSetType, + PreparedStatement prepareStatement(@SqlEvenQuotes String sql, int resultSetType, int resultSetConcurrency) throws SQLException; @@ -603,7 +604,7 @@ PreparedStatement prepareStatement(String sql, int resultSetType, * set type and result set concurrency. * @since 1.2 */ - CallableStatement prepareCall(String sql, int resultSetType, + CallableStatement prepareCall(@SqlEvenQuotes String sql, int resultSetType, int resultSetConcurrency) throws SQLException; /** @@ -855,7 +856,7 @@ Statement createStatement(int resultSetType, int resultSetConcurrency, * @see ResultSet * @since 1.4 */ - PreparedStatement prepareStatement(String sql, int resultSetType, + PreparedStatement prepareStatement(@SqlEvenQuotes String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException; @@ -895,7 +896,7 @@ PreparedStatement prepareStatement(String sql, int resultSetType, * @see ResultSet * @since 1.4 */ - CallableStatement prepareCall(String sql, int resultSetType, + CallableStatement prepareCall(@SqlEvenQuotes String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException; @@ -942,7 +943,7 @@ CallableStatement prepareCall(String sql, int resultSetType, * this method with a constant of Statement.RETURN_GENERATED_KEYS * @since 1.4 */ - PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) + PreparedStatement prepareStatement(@SqlEvenQuotes String sql, int autoGeneratedKeys) throws SQLException; /** @@ -990,7 +991,7 @@ PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) * * @since 1.4 */ - PreparedStatement prepareStatement(String sql, int columnIndexes[]) + PreparedStatement prepareStatement(@SqlEvenQuotes String sql, int columnIndexes[]) throws SQLException; /** @@ -1038,7 +1039,7 @@ PreparedStatement prepareStatement(String sql, int columnIndexes[]) * * @since 1.4 */ - PreparedStatement prepareStatement(String sql, String columnNames[]) + PreparedStatement prepareStatement(@SqlEvenQuotes String sql, String columnNames[]) throws SQLException; /** diff --git a/src/java.sql/share/classes/java/sql/DriverManager.java b/src/java.sql/share/classes/java/sql/DriverManager.java index b20b2a0e8e6..dee7caae815 100644 --- a/src/java.sql/share/classes/java/sql/DriverManager.java +++ b/src/java.sql/share/classes/java/sql/DriverManager.java @@ -89,7 +89,7 @@ * @see Connection * @since 1.1 */ -@AnnotatedFor({"interning"}) +@AnnotatedFor({"initialization", "nullness", "interning"}) public @UsesObjectEquals class DriverManager { @@ -227,7 +227,7 @@ public static Connection getConnection(String url, */ @CallerSensitive public static Connection getConnection(String url, - String user, String password) throws SQLException { + @Nullable String user, @Nullable String password) throws SQLException { java.util.Properties info = new java.util.Properties(); if (user != null) { @@ -387,7 +387,7 @@ public static void registerDriver(java.sql.Driver driver, * @see SecurityManager#checkPermission */ @CallerSensitive - public static void deregisterDriver(Driver driver) throws SQLException { + public static void deregisterDriver(@Nullable Driver driver) throws SQLException { if (driver == null) { return; } @@ -508,7 +508,7 @@ public static int getLoginTimeout() { * @see #getLogStream */ @Deprecated(since="1.2") - public static void setLogStream(java.io.PrintStream out) { + public static void setLogStream(java.io.@Nullable PrintStream out) { @SuppressWarnings("removal") SecurityManager sec = System.getSecurityManager(); @@ -556,12 +556,13 @@ public static void println(String message) { // Indicates whether the class object that would be created if the code calling // DriverManager is accessible. - private static boolean isDriverAllowed(Driver driver, Class caller) { + private static boolean isDriverAllowed(Driver driver, @Nullable Class caller) { ClassLoader callerCL = caller != null ? caller.getClassLoader() : null; return isDriverAllowed(driver, callerCL); } - private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) { + private static boolean isDriverAllowed(@Nullable Driver driver, + @Nullable ClassLoader classLoader) { boolean result = false; if (driver != null) { Class aClass = null; @@ -660,7 +661,7 @@ public Void run() { // Worker method called by the public getConnection() methods. @CallerSensitiveAdapter private static Connection getConnection( - String url, java.util.Properties info, Class caller) throws SQLException { + String url, java.util.Properties info, @Nullable Class caller) throws SQLException { /* * When callerCl is null, we should check the application's * (which is invoking this class indirectly) @@ -726,6 +727,7 @@ private static Connection getConnection( * to avoid the capture of the Driver it being compared to as it might not * normally have access. */ +@AnnotatedFor({"initialization", "nullness"}) class DriverInfo { final Driver driver; diff --git a/src/java.sql/share/classes/java/sql/SQLException.java b/src/java.sql/share/classes/java/sql/SQLException.java index 1142b6c9f1e..f77ab4ffbd9 100644 --- a/src/java.sql/share/classes/java/sql/SQLException.java +++ b/src/java.sql/share/classes/java/sql/SQLException.java @@ -27,7 +27,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.util.Iterator; import java.util.NoSuchElementException; @@ -332,7 +331,6 @@ public boolean hasNext() { return false; } - @SideEffectsOnly("this") public Throwable next() { Throwable throwable = null; if(firstException != null){ diff --git a/src/java.sql/share/classes/java/sql/Statement.java b/src/java.sql/share/classes/java/sql/Statement.java index 7ef793aa274..f62a6ef5450 100644 --- a/src/java.sql/share/classes/java/sql/Statement.java +++ b/src/java.sql/share/classes/java/sql/Statement.java @@ -25,6 +25,7 @@ package java.sql; +import org.checkerframework.checker.sqlquotes.qual.SqlEvenQuotes; import org.checkerframework.checker.tainting.qual.Untainted; import java.util.regex.Pattern; @@ -68,7 +69,7 @@ public interface Statement extends Wrapper, AutoCloseable { * method has been exceeded and has at least attempted to cancel * the currently running {@code Statement} */ - ResultSet executeQuery(@Untainted String sql) throws SQLException; + ResultSet executeQuery(@Untainted @SqlEvenQuotes String sql) throws SQLException; /** * Executes the given SQL statement, which may be an {@code INSERT}, @@ -93,7 +94,7 @@ public interface Statement extends Wrapper, AutoCloseable { * method has been exceeded and has at least attempted to cancel * the currently running {@code Statement} */ - int executeUpdate(@Untainted String sql) throws SQLException; + int executeUpdate(@Untainted @SqlEvenQuotes String sql) throws SQLException; /** * Releases this {@code Statement} object's database @@ -357,7 +358,7 @@ public interface Statement extends Wrapper, AutoCloseable { * @see #getUpdateCount * @see #getMoreResults */ - boolean execute(@Untainted String sql) throws SQLException; + boolean execute(@Untainted @SqlEvenQuotes String sql) throws SQLException; /** * Retrieves the current result as a {@code ResultSet} object. @@ -523,7 +524,7 @@ public interface Statement extends Wrapper, AutoCloseable { * @see DatabaseMetaData#supportsBatchUpdates * @since 1.2 */ - void addBatch( @Untainted String sql ) throws SQLException; + void addBatch( @Untainted @SqlEvenQuotes String sql ) throws SQLException; /** * Empties this {@code Statement} object's current list of @@ -757,7 +758,7 @@ public interface Statement extends Wrapper, AutoCloseable { * the currently running {@code Statement} * @since 1.4 */ - int executeUpdate(@Untainted String sql, int autoGeneratedKeys) throws SQLException; + int executeUpdate(@Untainted @SqlEvenQuotes String sql, int autoGeneratedKeys) throws SQLException; /** * Executes the given SQL statement and signals the driver that the @@ -792,7 +793,7 @@ public interface Statement extends Wrapper, AutoCloseable { * the currently running {@code Statement} * @since 1.4 */ - int executeUpdate(@Untainted String sql, int columnIndexes[]) throws SQLException; + int executeUpdate(@Untainted @SqlEvenQuotes String sql, int columnIndexes[]) throws SQLException; /** * Executes the given SQL statement and signals the driver that the @@ -826,7 +827,7 @@ public interface Statement extends Wrapper, AutoCloseable { * the currently running {@code Statement} * @since 1.4 */ - int executeUpdate(@Untainted String sql, String columnNames[]) throws SQLException; + int executeUpdate(@Untainted @SqlEvenQuotes String sql, String columnNames[]) throws SQLException; /** * Executes the given SQL statement, which may return multiple results, @@ -879,7 +880,7 @@ public interface Statement extends Wrapper, AutoCloseable { * * @since 1.4 */ - boolean execute(@Untainted String sql, int autoGeneratedKeys) throws SQLException; + boolean execute(@Untainted @SqlEvenQuotes String sql, int autoGeneratedKeys) throws SQLException; /** * Executes the given SQL statement, which may return multiple results, @@ -928,7 +929,7 @@ public interface Statement extends Wrapper, AutoCloseable { * * @since 1.4 */ - boolean execute(@Untainted String sql, int columnIndexes[]) throws SQLException; + boolean execute(@Untainted @SqlEvenQuotes String sql, int columnIndexes[]) throws SQLException; /** * Executes the given SQL statement, which may return multiple results, @@ -978,7 +979,7 @@ public interface Statement extends Wrapper, AutoCloseable { * * @since 1.4 */ - boolean execute(@Untainted String sql, String columnNames[]) throws SQLException; + boolean execute(@Untainted @SqlEvenQuotes String sql, String columnNames[]) throws SQLException; /** * Retrieves the result set holdability for {@code ResultSet} objects @@ -1234,7 +1235,7 @@ default long[] executeLargeBatch() throws SQLException { * the currently running {@code Statement} * @since 1.8 */ - default long executeLargeUpdate(@Untainted String sql) throws SQLException { + default long executeLargeUpdate(@Untainted @SqlEvenQuotes String sql) throws SQLException { throw new UnsupportedOperationException("executeLargeUpdate not implemented"); } @@ -1281,7 +1282,7 @@ default long executeLargeUpdate(@Untainted String sql) throws SQLException { * the currently running {@code Statement} * @since 1.8 */ - default long executeLargeUpdate(@Untainted String sql, int autoGeneratedKeys) + default long executeLargeUpdate(@Untainted @SqlEvenQuotes String sql, int autoGeneratedKeys) throws SQLException { throw new SQLFeatureNotSupportedException("executeLargeUpdate not implemented"); } @@ -1326,7 +1327,7 @@ default long executeLargeUpdate(@Untainted String sql, int autoGeneratedKeys) * the currently running {@code Statement} * @since 1.8 */ - default long executeLargeUpdate(@Untainted String sql, int columnIndexes[]) throws SQLException { + default long executeLargeUpdate(@Untainted @SqlEvenQuotes String sql, int columnIndexes[]) throws SQLException { throw new SQLFeatureNotSupportedException("executeLargeUpdate not implemented"); } @@ -1369,7 +1370,7 @@ default long executeLargeUpdate(@Untainted String sql, int columnIndexes[]) thro * the currently running {@code Statement} * @since 1.8 */ - default long executeLargeUpdate(@Untainted String sql, String columnNames[]) + default long executeLargeUpdate(@Untainted @SqlEvenQuotes String sql, String columnNames[]) throws SQLException { throw new SQLFeatureNotSupportedException("executeLargeUpdate not implemented"); } diff --git a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolver.java b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolver.java index 3bdae38d075..b5d20e04bc3 100644 --- a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolver.java +++ b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolver.java @@ -32,7 +32,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -302,7 +301,6 @@ public boolean hasNext() { return it.hasNext(); } - @SideEffectsOnly("this") public KeyResolverSpi next() { KeyResolverSpi resolver = it.next(); if (resolver == null) { diff --git a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolver.java b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolver.java index 18230035d56..15924ca239b 100644 --- a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolver.java +++ b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/StorageResolver.java @@ -23,7 +23,6 @@ package com.sun.org.apache.xml.internal.security.keys.storage; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.security.KeyStore; import java.security.cert.Certificate; @@ -151,7 +150,6 @@ public boolean hasNext() { } /** {@inheritDoc} */ - @SideEffectsOnly("this") public Certificate next() { if (hasNext()) { return currentResolver.next(); diff --git a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/KeyStoreResolver.java b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/KeyStoreResolver.java index 98984652a7c..4f0b44d9dc5 100644 --- a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/KeyStoreResolver.java +++ b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/KeyStoreResolver.java @@ -23,7 +23,6 @@ package com.sun.org.apache.xml.internal.security.keys.storage.implementations; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.security.KeyStore; import java.security.KeyStoreException; @@ -112,7 +111,6 @@ public boolean hasNext() { } /** {@inheritDoc} */ - @SideEffectsOnly("this") public Certificate next() { if (hasNext()) { return this.certs.get(this.i++); diff --git a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/SingleCertificateResolver.java b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/SingleCertificateResolver.java index 40c1e22c689..d2c727bbe36 100644 --- a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/SingleCertificateResolver.java +++ b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/storage/implementations/SingleCertificateResolver.java @@ -23,7 +23,6 @@ package com.sun.org.apache.xml.internal.security.keys.storage.implementations; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.security.cert.Certificate; import java.security.cert.X509Certificate; @@ -76,12 +75,10 @@ public InternalIterator(X509Certificate x509cert) { /** {@inheritDoc} */ @Pure public boolean hasNext() { - return !this.alreadyReturned; } /** {@inheritDoc} */ - @SideEffectsOnly("this") public Certificate next() { if (this.alreadyReturned) { throw new NoSuchElementException(); diff --git a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/Reference.java b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/Reference.java index 211b5168238..dc4bbbaf960 100644 --- a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/Reference.java +++ b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/Reference.java @@ -53,7 +53,6 @@ import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverContext; import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -626,7 +625,6 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") public Node next() { return sIterator.next(); } diff --git a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/reference/ReferenceSubTreeData.java b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/reference/ReferenceSubTreeData.java index c4ccc6336db..9d5ed1baa47 100644 --- a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/reference/ReferenceSubTreeData.java +++ b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/reference/ReferenceSubTreeData.java @@ -31,7 +31,6 @@ import java.util.ListIterator; import java.util.NoSuchElementException; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -89,7 +88,6 @@ public boolean hasNext() { return li.hasNext(); } - @SideEffectsOnly("this") public Node next() { if (nodeSet == null) { nodeSet = dereferenceSameDocumentURI(root); diff --git a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMSubTreeData.java b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMSubTreeData.java index 78a03652f44..b893445c75c 100644 --- a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMSubTreeData.java +++ b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMSubTreeData.java @@ -32,7 +32,6 @@ import java.util.ListIterator; import java.util.NoSuchElementException; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -90,7 +89,6 @@ public boolean hasNext() { return li.hasNext(); } - @SideEffectsOnly("this") public Node next() { if (nodeSet == null) { nodeSet = dereferenceSameDocumentURI(root); diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/BranchInstruction.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/BranchInstruction.java index 12e4071158b..6eda0ccfb7c 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/BranchInstruction.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/BranchInstruction.java @@ -184,6 +184,7 @@ protected void setIndex(final int index) { * @param position the position to set * @since 6.0 */ + @Pure protected void setPosition(final int position) { this.position = position; } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionList.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionList.java index 3f95a0f5d3f..72857b35472 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionList.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionList.java @@ -20,7 +20,6 @@ package com.sun.org.apache.bcel.internal.generic; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; @@ -405,6 +404,7 @@ public boolean contains(final InstructionHandle i) { return false; } + @Pure /** * @return complete, i.e., deep copy of this list */ diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableGen.java index 7b2546a5612..223f6ddd632 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LocalVariableGen.java @@ -111,6 +111,7 @@ void dispose() { * We consider to local variables to be equal, if the use the same index and are valid in the same range. */ @Override + @Pure public boolean equals(final Object o) { if (!(o instanceof LocalVariableGen)) { return false; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLStreamFilterImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLStreamFilterImpl.java index 6e7b4359056..7a36189f1ab 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLStreamFilterImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLStreamFilterImpl.java @@ -26,7 +26,6 @@ package com.sun.org.apache.xerces.internal.impl; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.StreamFilter; @@ -97,7 +96,6 @@ protected void setStreamFilter(StreamFilter sf){ * @return * @throws XMLStreamException */ - @SideEffectsOnly("this") public int next() throws XMLStreamException { if (fStreamAdvancedByHasNext && fEventAccepted) { fStreamAdvancedByHasNext = false; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLStreamReaderImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLStreamReaderImpl.java index efd888ab9d7..3dea188ad9b 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLStreamReaderImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLStreamReaderImpl.java @@ -26,7 +26,6 @@ package com.sun.org.apache.xerces.internal.impl; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import com.sun.org.apache.xerces.internal.util.NamespaceContextWrapper; import com.sun.org.apache.xerces.internal.util.NamespaceSupport; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XSModelImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XSModelImpl.java index e328cd63ba0..afaafc6a7cd 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XSModelImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XSModelImpl.java @@ -21,7 +21,6 @@ package com.sun.org.apache.xerces.internal.impl.xs; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import com.sun.org.apache.xerces.internal.impl.Constants; import com.sun.org.apache.xerces.internal.impl.xs.util.StringListImpl; @@ -819,7 +818,6 @@ public XSNamespaceItemListIterator(int index) { public boolean hasNext() { return (index < fGrammarCount); } - @SideEffectsOnly("this") public XSNamespaceItem next() { if (index < fGrammarCount) { return fGrammarList[index++]; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/util/XSNamedMapImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/util/XSNamedMapImpl.java index 4fc5b349dc0..29c51a220a2 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/util/XSNamedMapImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/util/XSNamedMapImpl.java @@ -21,7 +21,6 @@ package com.sun.org.apache.xerces.internal.impl.xs.util; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import com.sun.org.apache.xerces.internal.util.SymbolHash; import com.sun.org.apache.xerces.internal.xs.XSNamedMap; import com.sun.org.apache.xerces.internal.xs.XSObject; @@ -242,7 +241,6 @@ public Iterator> iterator() { public boolean hasNext() { return (index < length); } - @SideEffectsOnly("this") public Map.Entry next() { if (index < length) { return entries[index++]; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/util/XSObjectListImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/util/XSObjectListImpl.java index 1b618554f28..04f8751cfc0 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/util/XSObjectListImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/util/XSObjectListImpl.java @@ -21,7 +21,6 @@ package com.sun.org.apache.xerces.internal.impl.xs.util; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import com.sun.org.apache.xerces.internal.xs.XSObject; import com.sun.org.apache.xerces.internal.xs.XSObjectList; import java.lang.reflect.Array; @@ -52,7 +51,6 @@ static class EmptyIterator implements ListIterator { public boolean hasNext() { return false; } - @SideEffectsOnly("this") public XSObject next() { throw new NoSuchElementException(); } @@ -238,7 +236,6 @@ public XSObjectListIterator(int index) { public boolean hasNext() { return (index < fLength); } - @SideEffectsOnly("this") public XSObject next() { if (index < fLength) { return fArray[index++]; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/NamespaceSupport.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/NamespaceSupport.java index 5ca84d15b1c..b6045f03eb7 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/NamespaceSupport.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/NamespaceSupport.java @@ -21,7 +21,6 @@ package com.sun.org.apache.xerces.internal.util; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import com.sun.org.apache.xerces.internal.xni.NamespaceContext; import java.util.ArrayList; import java.util.Enumeration; @@ -380,7 +379,6 @@ public boolean hasNext() { /** * @see java.util.Enumeration#nextElement() */ - @SideEffectsOnly("this") public String next() { if (counter< size){ return fPrefixes[counter++]; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/XMLAttributesIteratorImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/XMLAttributesIteratorImpl.java index 9d04ba7cc86..e33d7cd3b85 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/XMLAttributesIteratorImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/XMLAttributesIteratorImpl.java @@ -26,7 +26,6 @@ package com.sun.org.apache.xerces.internal.util; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.util.Iterator; import java.util.NoSuchElementException; @@ -63,7 +62,6 @@ public boolean hasNext() { return fCurrent < getLength() ? true : false ; }//hasNext() - @SideEffectsOnly("this") public XMLAttributesImpl.Attribute next() { if(hasNext()){ // should this be of type javax.xml.stream.Attribute ? diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathNodesImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathNodesImpl.java index d48abf0d23b..37bbf74b5be 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathNodesImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathNodesImpl.java @@ -30,7 +30,6 @@ import javax.xml.xpath.XPathNodes; import javax.xml.xpath.XPathEvaluationResult.XPathResultType; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -67,7 +66,6 @@ public boolean hasNext() { return false; } - @SideEffectsOnly("this") public E next() { if (nodeList != null && nodeList.getLength() > 0) { return elementType.cast(nodeList.item(currentIndex++)); diff --git a/src/java.xml/share/classes/com/sun/xml/internal/stream/EventFilterSupport.java b/src/java.xml/share/classes/com/sun/xml/internal/stream/EventFilterSupport.java index c02d2ed2d1d..5b90d7fff0d 100644 --- a/src/java.xml/share/classes/com/sun/xml/internal/stream/EventFilterSupport.java +++ b/src/java.xml/share/classes/com/sun/xml/internal/stream/EventFilterSupport.java @@ -26,7 +26,6 @@ package com.sun.xml.internal.stream; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.util.NoSuchElementException; import javax.xml.stream.EventFilter; @@ -50,7 +49,6 @@ public EventFilterSupport(XMLEventReader eventReader, EventFilter eventFilter) { fEventFilter = eventFilter; } - @SideEffectsOnly("this") public Object next(){ try{ return nextEvent(); diff --git a/src/java.xml/share/classes/com/sun/xml/internal/stream/XMLEventReaderImpl.java b/src/java.xml/share/classes/com/sun/xml/internal/stream/XMLEventReaderImpl.java index d73cf911a9b..67d88d7c098 100644 --- a/src/java.xml/share/classes/com/sun/xml/internal/stream/XMLEventReaderImpl.java +++ b/src/java.xml/share/classes/com/sun/xml/internal/stream/XMLEventReaderImpl.java @@ -26,7 +26,6 @@ package com.sun.xml.internal.stream; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import com.sun.xml.internal.stream.events.XMLEventAllocatorImpl; import java.util.NoSuchElementException; @@ -75,7 +74,6 @@ public boolean hasNext() { } - @SideEffectsOnly("this") public XMLEvent nextEvent() throws XMLStreamException { //if application peeked return the peeked event if(fPeekedEvent != null){ diff --git a/src/java.xml/share/classes/com/sun/xml/internal/stream/util/ReadOnlyIterator.java b/src/java.xml/share/classes/com/sun/xml/internal/stream/util/ReadOnlyIterator.java index aa1fc45aacf..dabe06ae9ab 100644 --- a/src/java.xml/share/classes/com/sun/xml/internal/stream/util/ReadOnlyIterator.java +++ b/src/java.xml/share/classes/com/sun/xml/internal/stream/util/ReadOnlyIterator.java @@ -30,7 +30,6 @@ */ import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.util.Iterator; @@ -54,7 +53,6 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") public T next() { if(iterator != null) return iterator.next(); diff --git a/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java b/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java index 29642e67dea..81c43c989d4 100644 --- a/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java +++ b/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java @@ -45,7 +45,6 @@ import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import org.xml.sax.SAXException; /** @@ -350,7 +349,6 @@ public boolean hasNext() { } @Override - @SideEffectsOnly("this") public Catalog next() { if (nextCatalog != null || hasNext()) { Catalog catalog = nextCatalog; diff --git a/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java b/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java index 3a951d9e3e4..f255d860246 100644 --- a/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java +++ b/src/java.xml/share/classes/javax/xml/stream/XMLEventReader.java @@ -26,7 +26,6 @@ package javax.xml.stream; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import javax.xml.stream.events.XMLEvent; @@ -54,7 +53,6 @@ public interface XMLEventReader extends Iterator { * @throws XMLStreamException if there is an error with the underlying XML. * @throws java.util.NoSuchElementException iteration has no more elements. */ - @SideEffectsOnly("this") public XMLEvent nextEvent() throws XMLStreamException; /** diff --git a/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java b/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java index c9282b654e4..0214657df59 100644 --- a/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java +++ b/src/java.xml/share/classes/javax/xml/stream/XMLStreamReader.java @@ -26,7 +26,6 @@ package javax.xml.stream; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; @@ -301,7 +300,6 @@ public interface XMLStreamReader extends XMLStreamConstants { * START_ELEMENT or END_ELEMENT * @throws java.util.NoSuchElementException if this is called when hasNext() returns false */ - @SideEffectsOnly("this") public int nextTag() throws XMLStreamException; /** diff --git a/src/java.xml/share/classes/javax/xml/stream/util/EventReaderDelegate.java b/src/java.xml/share/classes/javax/xml/stream/util/EventReaderDelegate.java index f83aa47c7a2..3e3a2afe05d 100644 --- a/src/java.xml/share/classes/javax/xml/stream/util/EventReaderDelegate.java +++ b/src/java.xml/share/classes/javax/xml/stream/util/EventReaderDelegate.java @@ -26,7 +26,6 @@ package javax.xml.stream.util; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import javax.xml.stream.XMLEventReader; import javax.xml.stream.events.XMLEvent; @@ -86,7 +85,6 @@ public XMLEvent nextEvent() return reader.nextEvent(); } - @SideEffectsOnly("this") public Object next() { return reader.next(); } diff --git a/src/java.xml/share/classes/javax/xml/stream/util/StreamReaderDelegate.java b/src/java.xml/share/classes/javax/xml/stream/util/StreamReaderDelegate.java index 0865afaf040..64e332d8988 100644 --- a/src/java.xml/share/classes/javax/xml/stream/util/StreamReaderDelegate.java +++ b/src/java.xml/share/classes/javax/xml/stream/util/StreamReaderDelegate.java @@ -26,7 +26,6 @@ package javax.xml.stream.util; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import javax.xml.namespace.QName; import javax.xml.namespace.NamespaceContext; diff --git a/src/jdk.charsets/share/classes/sun/nio/cs/ext/AbstractCharsetProvider.java b/src/jdk.charsets/share/classes/sun/nio/cs/ext/AbstractCharsetProvider.java index 32f67ad38ca..dd2d2ba47f0 100644 --- a/src/jdk.charsets/share/classes/sun/nio/cs/ext/AbstractCharsetProvider.java +++ b/src/jdk.charsets/share/classes/sun/nio/cs/ext/AbstractCharsetProvider.java @@ -26,7 +26,6 @@ package sun.nio.cs.ext; import org.checkerframework.dataflow.qual.Pure; -import org.checkerframework.dataflow.qual.SideEffectsOnly; import java.lang.ref.SoftReference; @@ -179,7 +178,6 @@ public boolean hasNext() { return i.hasNext(); } - @SideEffectsOnly("this") public Charset next() { String csn = i.next(); synchronized (AbstractCharsetProvider.this) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/ClientCodeWrapper.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/ClientCodeWrapper.java index 7a37fccca13..e737f56b362 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/ClientCodeWrapper.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/ClientCodeWrapper.java @@ -340,9 +340,7 @@ public FileObject getFileForOutputForOriginatingFiles(Location location, String } } - @Override @DefinedBy(Api.COMPILER) - @Pure - public boolean contains(Location location, FileObject file) throws IOException { + @Override @DefinedBy(Api.COMPILER) public boolean contains(Location location, FileObject file) throws IOException { try { return clientJavaFileManager.contains(location, unwrap(file)); } catch (ClientCodeException e) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java index e31a9ebe391..2621ce2c659 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java @@ -25,10 +25,11 @@ package com.sun.tools.javac.code; -import org.checkerframework.checker.signature.qual.BinaryName; -import org.checkerframework.checker.signature.qual.CanonicalName; import org.checkerframework.checker.interning.qual.InternedDistinct; import org.checkerframework.checker.interning.qual.UsesObjectEquals; +import org.checkerframework.checker.signature.qual.BinaryName; +import org.checkerframework.checker.signature.qual.CanonicalName; +import org.checkerframework.checker.signature.qual.Identifier; import java.lang.annotation.Annotation; import java.lang.annotation.Inherited; @@ -1379,7 +1380,7 @@ public String className() { } @Override @DefinedBy(Api.LANGUAGE_MODEL) - public @CanonicalName Name getSimpleName() { + public @Identifier Name getSimpleName() { return name; } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java index c410755ae31..ab628abb1d3 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java @@ -113,6 +113,7 @@ public String getTagName(DocTree dtree) { }; } + @Pure public String getParameterName(ParamTree p) { return p.getName().getName().toString(); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/UncheckedDocletException.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/UncheckedDocletException.java index 71da76efec4..92ddf1908ca 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/UncheckedDocletException.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/UncheckedDocletException.java @@ -41,6 +41,7 @@ public UncheckedDocletException(DocletException de) { super(de); } + @Override public Throwable initCause(Throwable cause) { throw new UnsupportedOperationException(); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java index 8a3250cfd55..0d375cbbfd8 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java @@ -2127,6 +2127,7 @@ public String getModuleName(ModuleElement mdle) { private final CommentHelperCache commentHelperCache = new CommentHelperCache(this); + @Pure public CommentHelper getCommentHelper(Element element) { return commentHelperCache.computeIfAbsent(element); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java index 710b6887aab..62fbc48af4f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java @@ -647,6 +647,7 @@ private void computeVisibleMethods(LocalMemberTable lmt) { } } + @Pure private static boolean putAllIsNonReplacing(Map dst, Map src) { for (var e : src.entrySet()) { if (dst.containsKey(e.getKey()) diff --git a/src/utils/IdealGraphVisualizer/Filter/src/main/java/com/sun/hotspot/igv/filter/RemoveEmptySlotsFilter.java b/src/utils/IdealGraphVisualizer/Filter/src/main/java/com/sun/hotspot/igv/filter/RemoveEmptySlotsFilter.java index 3db8b2a3444..d1f4e6dbb7a 100644 --- a/src/utils/IdealGraphVisualizer/Filter/src/main/java/com/sun/hotspot/igv/filter/RemoveEmptySlotsFilter.java +++ b/src/utils/IdealGraphVisualizer/Filter/src/main/java/com/sun/hotspot/igv/filter/RemoveEmptySlotsFilter.java @@ -23,6 +23,8 @@ */ package com.sun.hotspot.igv.filter; +import org.checkerframework.dataflow.qual.Pure; + import com.sun.hotspot.igv.graph.*; import java.util.ArrayList; import java.util.List; diff --git a/test/jdk/java/util/logging/CustomLogManager.java b/test/jdk/java/util/logging/CustomLogManager.java index 66ef6bd82eb..9cec2b2d7c7 100644 --- a/test/jdk/java/util/logging/CustomLogManager.java +++ b/test/jdk/java/util/logging/CustomLogManager.java @@ -1,5 +1,3 @@ -import org.checkerframework.checker.signature.qual.BinaryName; - /* * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -23,6 +21,8 @@ * questions. */ +import org.checkerframework.checker.signature.qual.BinaryName; + import java.io.*; import java.util.*; import java.util.logging.*; diff --git a/test/jdk/java/util/logging/Level/CustomLevel.java b/test/jdk/java/util/logging/Level/CustomLevel.java index f320327ab8f..6e7d56afb37 100644 --- a/test/jdk/java/util/logging/Level/CustomLevel.java +++ b/test/jdk/java/util/logging/Level/CustomLevel.java @@ -1,5 +1,3 @@ -import org.checkerframework.checker.signature.qual.BinaryName; - /* * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -23,6 +21,8 @@ * questions. */ +import org.checkerframework.checker.signature.qual.BinaryName; + import java.io.*; import java.lang.management.ManagementFactory; import java.lang.management.PlatformLoggingMXBean; diff --git a/test/jdk/java/util/logging/LogManager/TestLoggerNames.java b/test/jdk/java/util/logging/LogManager/TestLoggerNames.java index 8c1ca11831f..90c023ba65c 100644 --- a/test/jdk/java/util/logging/LogManager/TestLoggerNames.java +++ b/test/jdk/java/util/logging/LogManager/TestLoggerNames.java @@ -1,5 +1,3 @@ -import org.checkerframework.checker.signature.qual.BinaryName; - /* * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -22,6 +20,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + +import org.checkerframework.checker.signature.qual.BinaryName; + import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; diff --git a/test/jdk/java/util/logging/TestLoggerBundleSync.java b/test/jdk/java/util/logging/TestLoggerBundleSync.java index e43ea4d1076..057aedf5c41 100644 --- a/test/jdk/java/util/logging/TestLoggerBundleSync.java +++ b/test/jdk/java/util/logging/TestLoggerBundleSync.java @@ -1,5 +1,3 @@ -import org.checkerframework.checker.signature.qual.BinaryName; - /* * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -23,6 +21,8 @@ * questions. */ +import org.checkerframework.checker.signature.qual.BinaryName; + import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.security.Permission;