diff --git a/.gitignore b/.gitignore index 3fbae8bb6a..bb31d475e0 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ checker/jdk/jdk*.jar checker/jdk/**/*.class *.pyc checker/build-temp +checker/bin/.do-like-javac checker/bin-devel/.plume-scripts checker/bin-devel/.run-google-java-format checker/bin-devel/dockerdir @@ -128,8 +129,10 @@ checker/jtreg/multipleexecutions/Main.class checker-qual/src checker-qual-android/src -framework/tests/whole-program-inference/annotated/ -/framework/tests/returnsreceiverdelomboked/ +# Some tests produce output into the tests/ directory instead of the build/ directory. +checker/tests/wpi-testchecker/annotated/ +checker/tests/wpi-testchecker/inference-output/ +framework/tests/returnsreceiverdelomboked/ docs/tutorial/src/personalblog-demo/bin/net/eyde/personalblog/service/PersonalBlogService.class docs/tutorial/src/personalblog-demo/bin/net/eyde/personalblog/struts/action/ReadAction.class diff --git a/LICENSE.txt b/LICENSE.txt index 70d6a70fe2..0e641883be 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -16,8 +16,9 @@ the parts that you might want to include with your own program. I18nFormatUtil.java, NullnessUtil.java, Opt.java, PurityUnqualified.java, RegexUtil.java, SignednessUtil.java, SignednessUtilExtra.java, and UnitsTools.java. It also applies to the cleanroom implementations of - third-party annotations (in checker/src/testannotations/ and in - framework/src/main/java/org/jmlspecs/). + third-party annotations (in checker/src/testannotations/, + framework/src/main/java/org/jmlspecs/, and + framework/src/main/java/com/google/). The Checker Framework includes annotations for some libraries. Those in .astub files use the MIT License. Those in https://github.com/typetools/jdk diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e85c2e7205..f93104d976 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -131,8 +131,8 @@ jobs: - nonjunit_tests_jdk11 - misc_jdk11 - typecheck_jdk11 -## Reduce latency due to the "daikon_jdk11 -> daikon_jdk8" critical path. -# - daikon_jdk11 + ## Reduce latency due to the "daikon_jdk11 -> daikon_jdk8" critical path. + # - daikon_jdk11 pool: vmImage: 'ubuntu-latest' container: mdernst/cf-ubuntu-jdk8:latest diff --git a/build.gradle b/build.gradle index 660dea884f..1508948346 100644 --- a/build.gradle +++ b/build.gradle @@ -102,7 +102,7 @@ allprojects { // * any new checkers have been added, // * the patch level is 9 (keep the patch level as a single digit), or // * backward-incompatible changes have been made to APIs or elsewhere. - version '3.8.0-SNAPSHOT' + version '3.9.0' repositories { mavenCentral() @@ -211,8 +211,10 @@ allprojects { options.compilerArgs += [ '-g', '-Werror', - // To not get a warning about missing bootstrap classpath for Java 8 (once we use Java 9). - "-Xlint:-options", + // -options: To not get a warning about missing bootstrap classpath for Java 8 (once we use Java 9). + // -fallthrough: Don't check fallthroughs. Instead, use Error Prone. Its + // are suppressible warns with a "// fall through" comment. + "-Xlint:-options,-fallthrough", "-Xlint", ] @@ -428,7 +430,7 @@ configurations { requireJavadoc } dependencies { - requireJavadoc "org.plumelib:require-javadoc:1.0.0" + requireJavadoc "org.plumelib:require-javadoc:1.0.1" } task requireJavadoc(type: JavaExec) { description = 'Ensures that Javadoc documentation exists.' @@ -544,8 +546,8 @@ task getPlumeScripts() { } task pythonIsInstalled(type: Exec) { - description "Check that the python executable is installed." - executable = "python" + description "Check that the python3 executable is installed." + executable = "python3" args "--version" } @@ -581,7 +583,7 @@ subprojects { description 'Check whether the source code is properly formatted' // checker-qual* projects have no source, so skip onlyIf {!project.name.startsWith('checker-qual') } - executable 'python' + executable 'python3' doFirst { args += "${formatScriptsHome}/check-google-java-format.py" @@ -600,7 +602,7 @@ subprojects { description 'Format the Java source code' // checker-qual* projects have no source, so skip onlyIf { !project.name.startsWith('checker-qual') } - executable 'python' + executable 'python3' doFirst { args += "${formatScriptsHome}/run-google-java-format.py" args += "--aosp" // 4 space indentation @@ -818,15 +820,19 @@ subprojects { // Create a nonJunitTests task per project tasks.create(name: 'nonJunitTests', group: 'Verification') { description 'Run all Checker Framework tests except for the Junit tests.' + if (project.name.is('framework') || project.name.is('checker')) { + dependsOn('jtregTests') + } if (project.name.is('framework')) { - dependsOn('wholeProgramInferenceTests', 'loaderTests') + dependsOn('loaderTests') } if (project.name.is('checker')) { if (!isJava8) { dependsOn('jtregJdk11Tests') } - dependsOn('nullnessExtraTests', 'commandLineTests', 'tutorialTests') + dependsOn('nullnessExtraTests', 'commandLineTests', 'tutorialTests', + 'wholeProgramInferenceTests', 'wpiScriptsTests') } if (project.name.is('dataflow')) { @@ -841,13 +847,10 @@ subprojects { description 'Run the Checker Framework on itself' dependsOn('checkInterning', 'checkPurity', 'checkSignature') if (project.name.is('framework') || project.name.is('checker')) { - dependsOn('checkNullnessOnlyAnnotatedFor') + dependsOn('checkNullnessOnlyAnnotatedFor', 'checkCompilerMessages') } else { dependsOn('checkNullness') } - if (project.name.is('framework') || project.name.is('checker')) { - dependsOn('checkCompilerMessages', 'jtregTests') - } } // Create an allTests task per project. @@ -910,6 +913,7 @@ task checkBasicStyle(group: 'Format') { 'manual.html', 'manual.html-e', 'junit.*.properties', + 'securerandom.*', 'checker/dist/META-INF/maven/org.apache.bcel/bcel/pom.xml', 'checker/dist/META-INF/maven/org.apache.commons/commons-text/pom.xml', 'framework/src/main/resources/git.properties'] diff --git a/changelog.txt b/changelog.txt index 7fb391efbe..0f156589d0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,19 +1,64 @@ +Version 3.9.0, December 21, 2020 + +New scripts checker/bin/wpi.sh and checker/bin/wpi-many.sh run whole-program +inference, without modifying the source code of the target program(s). + +The Called Methods Checker supports the -AdisableReturnsReceiver command-line option. + +The Format String Checker recognizes Error Prone's `@FormatMethod` annotation. + +Implementation details: + +Class renamings: + * `StubParser` => `AnnotationFileParser` + * `Receiver` => `JavaExpression` + * also related class and method renamings + * In the Dataflow Framework: + * `ThisLiteralNode` => `ThisNode` + * `ExplicitThisLiteralNode` => `ExplicitThisNode` + * `ImplicitThisLiteralNode` => `ImplicitThisNode` + +Method deprecations: + * Deprecated `AnnotatedTypeFactory.addAliasedAnnotation`; use `addAliasedTypeAnnotation` + +Closed issues: +#765, #2452, #2953, #3287, #3294, #3377, #3390, #3496, #3499, #3681, #3826, +#3839, #3850, #3851, #3862, #3871, #3884, #3888, #3908, #3929, #3932, +#3935, #3956, #3971, #3974, #3994, #4004, #4005, #4018. + +--------------------------------------------------------------------------- + Version 3.8.0, December 1, 2020 +The Initialized Fields Checker warns when a field is not initialized by a +constructor. This is more general than the Initialization Checker, which +only checks that `@NonNull` fields are initialized. + The manual describes how to modify an sbt build file to run the Checker Framework. The -AwarnUnneededSuppressions command-line option warns only about suppression strings that contain a checker name. +The -AwarnUnneededSuppressionsExceptions=REGEX command-line option +partially disables -AwarnUnneededSuppressions. Most users don't need this. + Implementation details: Added classes `SubtypeIsSubsetQualifierHierarchy` and `SubtypeIsSupersetQualifierHierarchy`. +Moved the `contractsUtils` field from the visitor to the type factory. + +Class renamings: + * `ContractsUtils` => `ContractsFromMethod` + Method renamings: - ElementUtils.getVerboseName => ElementUtils.getQualifiedName - ElementUtils.getSimpleName => ElementUtils.getSimpleSignature + * `ElementUtils.getVerboseName` => `ElementUtils.getQualifiedName` + * `ElementUtils.getSimpleName` => `ElementUtils.getSimpleSignature` + +Field renamings: + * `AnnotatedTypeMirror.actualType` => `AnnotatedTypeMirror.underlyingType` Added a formal parameter to methods in `MostlyNoElementQualifierHierarchy`: * `leastUpperBoundWithElements` @@ -23,6 +68,15 @@ Removed a formal parameter from methods in `BaseTypeVisitor`: * `checkPostcondition` * `checkConditionalPostcondition` +In `Analysis.runAnalysisFor()`, changed `boolean` parameter to enum `BeforeOrAfter`. + +Removed `org.checkerframework.framework.util.AnnotatedTypes#getIteratedType`; use +`AnnotatedTypeFactory#getIterableElementType(ExpressionTree)` instead. + +Closed issues: +#3287, #3390, #3681, #3839, #3850, #3851, #3862, #3871, #3884, #3888, #3908, +#3929, #3932, #3935. + --------------------------------------------------------------------------- Version 3.7.1, November 2, 2020 diff --git a/checker/bin-devel/Dockerfile-ubuntu-jdk11 b/checker/bin-devel/Dockerfile-ubuntu-jdk11 index 33d7c3237e..891a6e80b5 100644 --- a/checker/bin-devel/Dockerfile-ubuntu-jdk11 +++ b/checker/bin-devel/Dockerfile-ubuntu-jdk11 @@ -31,17 +31,6 @@ RUN export DEBIAN_FRONTEND=noninteractive \ unzip \ wget -# Ubuntu 18.04 has Maven 3.6.0, but 3.6.1 apparently has better retry -# behavior to work around network problems. -RUN export DEBIAN_FRONTEND=noninteractive \ -&& VER=3.6.3 \ -&& mkdir -p $HOME/bin/install \ -&& cd $HOME/bin/install \ -&& wget http://apache.mirrors.pair.com/maven/maven-3/${VER}/binaries/apache-maven-${VER}-bin.tar.gz \ -&& tar xzf apache-maven-${VER}-bin.tar.gz \ -&& (cd /usr/local/bin && ln -sf $HOME/bin/install/apache-maven-${VER}/bin/* .) \ -&& hash -r - RUN export DEBIAN_FRONTEND=noninteractive \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* diff --git a/checker/bin-devel/Dockerfile-ubuntu-jdk11-plus b/checker/bin-devel/Dockerfile-ubuntu-jdk11-plus index e52038bbac..94a04758dc 100644 --- a/checker/bin-devel/Dockerfile-ubuntu-jdk11-plus +++ b/checker/bin-devel/Dockerfile-ubuntu-jdk11-plus @@ -34,17 +34,6 @@ RUN export DEBIAN_FRONTEND=noninteractive \ unzip \ wget -# Ubuntu 18.04 has Maven 3.6.0, but 3.6.1 apparently has better retry -# behavior to work around network problems. -RUN export DEBIAN_FRONTEND=noninteractive \ -&& VER=3.6.3 \ -&& mkdir -p $HOME/bin/install \ -&& cd $HOME/bin/install \ -&& wget http://apache.mirrors.pair.com/maven/maven-3/${VER}/binaries/apache-maven-${VER}-bin.tar.gz \ -&& tar xzf apache-maven-${VER}-bin.tar.gz \ -&& (cd /usr/local/bin && ln -sf $HOME/bin/install/apache-maven-${VER}/bin/* .) \ -&& hash -r - RUN export DEBIAN_FRONTEND=noninteractive \ && apt-get -qqy update \ && apt-get -qqy install \ diff --git a/checker/bin-devel/Dockerfile-ubuntu-jdk8 b/checker/bin-devel/Dockerfile-ubuntu-jdk8 index 33d8ece9f5..31192e4f95 100644 --- a/checker/bin-devel/Dockerfile-ubuntu-jdk8 +++ b/checker/bin-devel/Dockerfile-ubuntu-jdk8 @@ -32,17 +32,6 @@ RUN export DEBIAN_FRONTEND=noninteractive \ unzip \ wget -# Ubuntu 18.04 has Maven 3.6.0, but 3.6.1 apparently has better retry -# behavior to work around network problems. -RUN export DEBIAN_FRONTEND=noninteractive \ -&& VER=3.6.3 \ -&& mkdir -p $HOME/bin/install \ -&& cd $HOME/bin/install \ -&& wget http://apache.mirrors.pair.com/maven/maven-3/${VER}/binaries/apache-maven-${VER}-bin.tar.gz \ -&& tar xzf apache-maven-${VER}-bin.tar.gz \ -&& (cd /usr/local/bin && ln -sf $HOME/bin/install/apache-maven-${VER}/bin/* .) \ -&& hash -r - RUN export DEBIAN_FRONTEND=noninteractive \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* diff --git a/checker/bin-devel/Dockerfile-ubuntu-jdk8-plus b/checker/bin-devel/Dockerfile-ubuntu-jdk8-plus index 3fef18379c..8e5673a7d8 100644 --- a/checker/bin-devel/Dockerfile-ubuntu-jdk8-plus +++ b/checker/bin-devel/Dockerfile-ubuntu-jdk8-plus @@ -32,17 +32,6 @@ RUN export DEBIAN_FRONTEND=noninteractive \ unzip \ wget -# Ubuntu 18.04 has Maven 3.6.0, but 3.6.1 apparently has better retry -# behavior to work around network problems. -RUN export DEBIAN_FRONTEND=noninteractive \ -&& VER=3.6.3 \ -&& mkdir -p $HOME/bin/install \ -&& cd $HOME/bin/install \ -&& wget http://apache.mirrors.pair.com/maven/maven-3/${VER}/binaries/apache-maven-${VER}-bin.tar.gz \ -&& tar xzf apache-maven-${VER}-bin.tar.gz \ -&& (cd /usr/local/bin && ln -sf $HOME/bin/install/apache-maven-${VER}/bin/* .) \ -&& hash -r - RUN export DEBIAN_FRONTEND=noninteractive \ && apt-get -qqy update \ && apt-get -qqy install \ diff --git a/checker/bin-devel/Makefile b/checker/bin-devel/Makefile new file mode 100644 index 0000000000..47f5ac93ed --- /dev/null +++ b/checker/bin-devel/Makefile @@ -0,0 +1,19 @@ +remove-annotations.sh: + \rm -f remove-annotations.sh + echo "#!/bin/sh" >> remove-annotations.sh + echo "# Remove Checker Framework annotations (except ones that the checker trusts" >> remove-annotations.sh + echo "# rather than verifies) from all files under the current directory." >> remove-annotations.sh + echo "" >> remove-annotations.sh + echo 'PREPLACE="$$(dirname "$$(readlink -f "$$0")")"/.plume-scripts/preplace' >> remove-annotations.sh + echo "" >> remove-annotations.sh +# Only remove imports for annotations that are removed. + echo '"$$PREPLACE"'" '^import org.checkerframework(?!.*InternedDistinct).*\\\n' ''" >> remove-annotations.sh +# Remove declaration annotations that appear on their own line. + echo '"$$PREPLACE"'" '^ *\@(Deterministic|EnsuresNonNull|FormatMethod|Pure|RequiresNonNull|SideEffectFree)(\([^()]*\))?\\\n' ''" >> remove-annotations.sh +# The `grep -v` removes trusted annotations. This list of trusted annotations was generated by hand. +# TODO: Maybe have two variants of the script, with and without special treatment of trusted annotations. +# TODO: Don't remove annotations that are within the scope of @SuppressWarnings. (That requires a real parser rather than this script that uses regexes.) + grep '^ "[^"]*",' .run-google-java-format/fixup-google-java-format.py | grep -v InternedDistinct | sed 's/^ "\(.*\)",/"$$PREPLACE" '"'"'\\@\1(\\([^()"]*("[^"]*"[^()"]*)*\\))? '"'"' '"''"'/' >> remove-annotations.sh + echo '"$$PREPLACE"'" '\([ \\\n]*[A-Za-z][A-Za-z0-9_]*(<[^<>]*>)? this\)' '()'" >> remove-annotations.sh + echo '"$$PREPLACE"'" '\([ \\\n]*[A-Za-z][A-Za-z0-9_]*(<[^<>]*>)? this,[ \\\t]*' '('" >> remove-annotations.sh + chmod +x remove-annotations.sh diff --git a/checker/bin-devel/git.pre-commit b/checker/bin-devel/git.pre-commit index b2d1f81505..1c26a3b45f 100755 --- a/checker/bin-devel/git.pre-commit +++ b/checker/bin-devel/git.pre-commit @@ -20,7 +20,7 @@ if [ -n "$CHANGED_JAVA_FILES" ]; then # echo "CHANGED_JAVA_FILES: ${CHANGED_JAVA_FILES}" # shellcheck disable=SC2086 - python checker/bin-devel/.run-google-java-format/check-google-java-format.py --aosp ${CHANGED_JAVA_FILES} || (echo "Problem in pre-commit. Try running: ./gradlew reformat" && /bin/false) + python3 checker/bin-devel/.run-google-java-format/check-google-java-format.py --aosp ${CHANGED_JAVA_FILES} || (echo "Problem in pre-commit. Try running: ./gradlew reformat" && /bin/false) BRANCH=$(git rev-parse --abbrev-ref HEAD) if [ "$BRANCH" = "master" ]; then diff --git a/checker/bin-devel/remove-annotations.sh b/checker/bin-devel/remove-annotations.sh new file mode 100755 index 0000000000..e1e2a7c799 --- /dev/null +++ b/checker/bin-devel/remove-annotations.sh @@ -0,0 +1,311 @@ +#!/bin/sh +# Remove Checker Framework annotations (except trusted ones) from all files under the current directory. + +PREPLACE="$(dirname "$(readlink -f "$0")")"/.plume-scripts/preplace + +"$PREPLACE" '^import org.checkerframework(?!.*InternedDistinct).*\n' '' +"$PREPLACE" '^ *\@(Deterministic|EnsuresNonNull|FormatMethod|Pure|RequiresNonNull|SideEffectFree)(\([^()]*\))?\n' '' +"$PREPLACE" '\@A(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@ACCBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Acceleration(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@ACCTop(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@AlwaysSafe(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Angle(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@AnnoWithStringArg(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Area(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@ArrayLen(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@ArrayLenRange(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@ArrayWithoutPackage(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@AwtAlphaCompositingRule(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@AwtColorSpace(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@AwtCursorType(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@AwtFlowLayout(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@B(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@BinaryName(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@BinaryNameInUnnamedPackage(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@BinaryNameOrPrimitiveType(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@BinaryNameWithoutPackage(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@BoolVal(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Bottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@BottomQualifier(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@BottomThis(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@BottomVal(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@C(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@CalledMethods(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@CalledMethodsBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@CalledMethodsPredicate(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@CalledMethodsTop(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@CanonicalName(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@CanonicalNameOrEmpty(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@CCBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@CCTop(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@cd(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@ClassBound(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@ClassGetName(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@ClassGetSimpleName(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@ClassVal(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@ClassValBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@CompilerMessageKey(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@CompilerMessageKeyBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Constant(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Critical(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Current(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@D(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@DefaultType(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@degrees(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Det(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@DotSeparatedIdentifiers(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@DotSeparatedIdentifiersOrPrimitiveType(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@DoubleVal(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@E(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Encrypted(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@EnumVal(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Even(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@F(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@FBCBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@FEBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@FEBot(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Fenum(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@FenumBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@FenumTop(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@FETop(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@FieldDescriptor(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@FieldDescriptorForPrimitive(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@FieldDescriptorForPrimitiveOrArrayInUnnamedPackage(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@FieldDescriptorWithoutPackage(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@FlowExp(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Format(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@FormatBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@FqBinaryName(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Frequency(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@FullyQualifiedName(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@g(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@GTENegativeOne(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@GuardedBy(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@GuardedByBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@GuardedByUnknown(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@GuardSatisfied(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@h(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@H1Bot(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@H1Invalid(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@H1Poly(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@H1S1(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@H1S2(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@H1Top(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@H2Bot(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@H2Poly(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@H2S1(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@H2S2(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@H2Top(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Hz(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@I18nFormat(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@I18nFormatBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@I18nFormatFor(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@I18nInvalidFormat(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@I18nUnknownFormat(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Identifier(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@IdentifierOrArray(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@IdentifierOrPrimitiveType(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@ImplicitAnno(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@IndexFor(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@IndexOrHigh(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@IndexOrLow(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Initialized(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@InitializedFields(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@InitializedFieldsBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@InitializedFieldsPredicate(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@InternalForm(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Interned(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@IntRange(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@IntVal(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@InvalidFormat(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@K(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@KeyFor(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@KeyForBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@KeyForType(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@kg(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@kHz(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@km(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@km2(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@kmPERh(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@LbTop(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@LB_TOP(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@LeakedToResult(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Length(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@LengthOf(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@LessThan(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@LessThanBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@LessThanUnknown(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@LocalizableKey(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@LocalizableKeyBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Localized(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@LowerBoundBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@LowerBoundUnknown(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@LTEqLengthOf(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@LTLengthOf(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@LTOMLengthOf(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Luminance(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@m(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@m2(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Mass(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@MatchesRegex(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@MaybeAliased(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@MaybeDerivedFromConstant(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@MaybePresent(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@MaybeThis(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@MethodDescriptor(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@MethodVal(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@MethodValBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@min(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@MinLen(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@mm(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@mm2(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@mol(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@MonotonicNonNull(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@MonotonicNonNullType(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@MonotonicOdd(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@mPERs(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@mPERs2(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@NegativeIndexFor(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@NonConstant(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@NonDet(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@NonLeaked(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@NonNegative(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@NonNull(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@NonNullType(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@NonRaw(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@NotCalledMethods(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@NotNull(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@NotQualifier(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@NTDBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@NTDMiddle(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@NTDSide(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@NTDTop(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Nullable(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@NullableType(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Odd(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@OrderNonDet(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Parent(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PatternA(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PatternAB(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PatternAC(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PatternB(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PatternBC(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PatternBottomFull(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PatternBottomPartial(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PatternC(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PatternUnknown(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Poly(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyAll(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyConstant(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyDet(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyEncrypted(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyFenum(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyIndex(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyInitializedFields(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyInterned(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyKeyFor(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyLength(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyLowerBound(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyNull(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyNullType(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyPresent(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyRaw(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyReflection(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyRegex(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolySameLen(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolySignature(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolySigned(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyTainted(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyTestAccumulation(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyTypeDeclDefault(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyUI(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyUnit(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyUpperBound(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PolyValue(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Positive(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Present(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PrimitiveType(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PropertyKey(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PropertyKeyBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@PurityUnqualified(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Qualifier(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@radians(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Raw(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@ReflectBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Regex(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@RegexBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@ReportUnqualified(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@s(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SameLen(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SameLenBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SameLenUnknown(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SearchIndexBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SearchIndexFor(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SearchIndexUnknown(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Sibling1(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Sibling2(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SiblingWithFields(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SignatureBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Signed(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SignednessBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SignednessGlb(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SignedPositive(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SignedPositiveFromUnsigned(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Speed(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@StringVal(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SubQual(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Substance(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SubstringIndexBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SubstringIndexFor(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SubstringIndexUnknown(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SuperQual(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SwingBoxOrientation(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SwingCompassDirection(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SwingElementOrientation(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SwingHorizontalOrientation(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SwingSplitPaneOrientation(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SwingTextOrientation(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SwingTitleJustification(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SwingTitlePosition(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@SwingVerticalOrientation(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Tainted(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Temperature(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@TestAccumulation(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@TestAccumulationBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@TestAccumulationPredicate(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@This(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Time(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Top(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@TypeDeclDefaultBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@TypeDeclDefaultMiddle(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@TypeDeclDefaultTop(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UbTop(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UB_TOP(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UI(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UnderInitialization(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Unique(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UnitsBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UnknownClass(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UnknownCompilerMessageKey(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UnknownFormat(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UnknownInitialization(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UnknownInterned(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UnknownKeyFor(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UnknownLocalizableKey(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UnknownLocalized(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UnknownMethod(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UnknownPropertyKey(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UnknownRegex(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UnknownSignedness(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UnknownThis(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UnknownUnits(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UnknownVal(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Unsigned(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Untainted(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UpperBoundBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@UpperBoundUnknown(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@Value(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\@WholeProgramInferenceBottom(\([^()"]*("[^"]*"[^()"]*)*\))? ' '' +"$PREPLACE" '\([ \n]*[A-Za-z][A-Za-z0-9_]*(<[^<>]*>)? this\)' '()' +"$PREPLACE" '\([ \n]*[A-Za-z][A-Za-z0-9_]*(<[^<>]*>)? this,[ \t]*' '(' diff --git a/checker/bin-devel/test-misc.sh b/checker/bin-devel/test-misc.sh index c0ecc585f8..898dafe3c7 100755 --- a/checker/bin-devel/test-misc.sh +++ b/checker/bin-devel/test-misc.sh @@ -16,6 +16,8 @@ source "$SCRIPTDIR"/build.sh "/tmp/$USER/plume-scripts/git-clone-related" typetools checker-framework.demos ./gradlew :checker:demosTests --console=plain --warning-mode=all --no-daemon +status=0 + # Code style and formatting ./gradlew checkBasicStyle checkFormat --console=plain --warning-mode=all --no-daemon @@ -23,11 +25,10 @@ source "$SCRIPTDIR"/build.sh ./gradlew htmlValidate --console=plain --warning-mode=all --no-daemon # Javadoc documentation -status=0 ./gradlew javadoc --console=plain --warning-mode=all --no-daemon || status=1 ./gradlew javadocPrivate --console=plain --warning-mode=all --no-daemon || status=1 # For refactorings that touch a lot of code that you don't understand, create -# top-level file SKIP-REQUIRE-JAVADOC. Delete it when the pull request is merged. +# top-level file SKIP-REQUIRE-JAVADOC. Delete it after the pull request is merged. if [ ! -f SKIP-REQUIRE-JAVADOC ]; then (./gradlew requireJavadoc --console=plain --warning-mode=all --no-daemon > /tmp/warnings-rjp.txt 2>&1) || true /tmp/"$USER"/plume-scripts/ci-lint-diff /tmp/warnings-rjp.txt || status=1 diff --git a/checker/bin/Makefile b/checker/bin/Makefile new file mode 100644 index 0000000000..40e3ecec6a --- /dev/null +++ b/checker/bin/Makefile @@ -0,0 +1,10 @@ +SH_SCRIPTS = $(shell grep -r -l '^\#! \?\(/bin/\|/usr/bin/env \)sh' * | grep -v .git | grep -v "~") +BASH_SCRIPTS = $(shell grep -r -l '^\#! \?\(/bin/\|/usr/bin/env \)bash' * | grep -v .git | grep -v "~") + +shell-script-style: + shellcheck --format=gcc ${SH_SCRIPTS} ${BASH_SCRIPTS} + checkbashisms ${SH_SCRIPTS} + +showvars: + @echo "SH_SCRIPTS=${SH_SCRIPTS}" + @echo "BASH_SCRIPTS=${BASH_SCRIPTS}" diff --git a/checker/bin/README b/checker/bin/README index db90ef4630..fc6ab16511 100644 --- a/checker/bin/README +++ b/checker/bin/README @@ -1,24 +1,15 @@ This directory, "checker/bin", contains scripts to run the Checker Framework. +Before using them, you must run `./gradlew assemble` in the parent directory. -javac - Is a shell script that runs the Checker Framework in *nix systems -including Mac OS X. Its invocation is equivalent to -"java -jar checker.jar ". -This script is a drop-in replacement for the script javac provided by the -OpenJDK. +javac - Is a shell script that runs the Checker Framework in Unix systems +including Mac OS X. This script is a drop-in replacement for the script +javac provided by the OpenJDK. javac.bat - Is the equivalent of the javac script for Windows systems. - -The directory "checker/dist/" houses all jars built for the binary distribution. -To build these jars, run "./gradlew assemble" from the "checker-framework" directory. -Afterward, the directory will contain all jars needed to run the -Checker Framework. - -checker-qual.jar - Contains the annotations used by the checkers built into the -Checker Framework - -checker.jar - Contains all the Checker Framework classes including the framework -itself, all built-in checkers, and the annotations found in checker-qual.jar. - -javac.jar - Contains the Type Annotations Compiler -(see https://checkerframework.org/README-jsr308.html) +The other scripts are used for whole-program inference: +infer-and-annotate.sh +query-github.sh +wpi.sh +wpi-many.sh +wpi-summary.sh diff --git a/checker/bin/infer-and-annotate.sh b/checker/bin/infer-and-annotate.sh index 53d5108f93..6d3f737122 100755 --- a/checker/bin/infer-and-annotate.sh +++ b/checker/bin/infer-and-annotate.sh @@ -133,7 +133,7 @@ infer_and_annotate() { # Runs CF's javac command="$CHECKERBIN/javac -d $TEMP_DIR/ -cp $cp -processor $processor -Ainfer=jaifs -Awarns -Xmaxwarns 10000 ${extra_args[*]} ${java_files[*]}" echo "About to run: ${command}" - if [ $interactive ]; then + if [ "$interactive" ]; then echo "Press any key to run command... " IFS="" read -r _ fi @@ -158,7 +158,7 @@ infer_and_annotate() { # in its header. To avoid this problem, we add the "|| true" below. DIFF_JAIF="$(diff -qr $PREV_ITERATION_DIR $WHOLE_PROGRAM_INFERENCE_DIR || true)" done - if [ ! $debug ]; then + if [ ! "$debug" ]; then clean fi } diff --git a/checker/bin/javac b/checker/bin/javac index a05275f513..2a4005c390 100755 --- a/checker/bin/javac +++ b/checker/bin/javac @@ -24,10 +24,12 @@ nl=' ' for i in "$@" ; do IFS= + # shellcheck disable=SC2027 args=$args$nl"'"$i"'" IFS="$saveIFS" done +# shellcheck disable=SC2086 eval "java" \ "-jar" "${mydir}"/../dist/checker.jar \ ${args} diff --git a/checker/bin/query-github.sh b/checker/bin/query-github.sh new file mode 100755 index 0000000000..92038138d4 --- /dev/null +++ b/checker/bin/query-github.sh @@ -0,0 +1,109 @@ +#!/bin/sh + +# This script collects a list of projects that match a query from GitHub. + +# inputs: +# +# The file git-personal-access-token must exist in the directory from which +# this script is run, and must be a valid github OAuth token. +# +# $1 is the query file, which should contain the literal string to use +# as the github search. REQUIRED, no default +# +# $2 is the number of pages to search. default 1 + +query_file=$1 +# Number of times to retry a GitHub search query. +query_tries=5 + +if [ -z "${query_file}" ]; then + echo "you must provide a query file as the first argument" + exit 2 +fi + +if [ -z "$2" ]; then + page_count=1 +else + page_count=$2 +fi + +query=$(tr ' ' '+' < "${query_file}") + +mkdir -p "/tmp/$USER" + +## for storing the results before sorting and uniqing them +rm -f "/tmp/$USER/github-query-results-*.txt" +tempfile=$(mktemp "/tmp/$USER/github-query-results-XXX.txt") +#trap "rm -f ${tempfile}" 0 2 3 15 + +rm -f "/tmp/$USER/github-hash-results-*.txt" +hashfile=$(mktemp "/tmp/$USER/github-hash-results-XXX.txt") +#trap "rm -f ${hashfile}" 0 2 3 15 + +rm -rf "/tmp/$USER/curl-output-*.txt" +curl_output_file=$(mktemp "/tmp/$USER/curl-output-XXX.txt") + +# find the repos +for i in $(seq "${page_count}"); do + # GitHub only allows 30 searches per minute, so add a delay to each request. + if [ "${i}" -gt 1 ]; then + sleep 5 + fi + + full_query='https://api.github.com/search/code?q='${query}'&page='${i} + for tries in $(seq ${query_tries}); do + status_code=$(curl -s \ + -H "Authorization: token $(cat git-personal-access-token)" \ + -H "Accept: application/vnd.github.v3+json" \ + -w "%{http_code}" \ + -o "${curl_output_file}" \ + "${full_query}") + + if [ "${status_code}" -eq 200 ] || [ "${status_code}" -eq 422 ]; then + # Don't retry. + # 200 is success. 422 means too many GitHub requests. + break + elif [ "${tries}" -lt $((query_tries - 1)) ]; then + # Retry. + # Other status codes are failures. Failures are usually due to + # triggering the abuse detection mechanism for sending too many + # requests, so we add a delay when this happens. + sleep 20 + fi + done + + # GitHub only returns the first 1000 results. Requests past this limit + # return 422, so stop making requests. + if [ "${status_code}" -eq 422 ]; then + break; + elif [ "${status_code}" -ne 200 ]; then + echo "GitHub query failed, last response:" + cat "${curl_output_file}" + rm -f "${curl_output_file}" + exit 1 + fi + + grep " \"html_url" < "${curl_output_file}" \ + | grep -v " " \ + | sort -u \ + | cut -d \" -f 4 >> "${tempfile}" +done + +rm -f "${curl_output_file}" + +# Each loop iteration was sorted and unique; this does it for the full result. +sort -u -o "${tempfile}" "${tempfile}" + +while IFS= read -r line +do + repo=$(echo "${line}" | cut -d / -f 5) + owner=$(echo "${line}" | cut -d / -f 4) + hash_query='https://api.github.com/repos/'${owner}'/'${repo}'/commits?per_page=1' + curl -sH "Authorization: token $(cat git-personal-access-token)" \ + "Accept: application/vnd.github.v3+json" \ + "${hash_query}" \ + | grep '^ "sha":' \ + | cut -d \" -f 4 >> "${hashfile}" +done < "${tempfile}" + +paste "${tempfile}" "${hashfile}" diff --git a/checker/bin/wpi-many.sh b/checker/bin/wpi-many.sh new file mode 100755 index 0000000000..d5eaf73804 --- /dev/null +++ b/checker/bin/wpi-many.sh @@ -0,0 +1,224 @@ +#!/bin/bash + +# This script runs the Checker Framework's whole-program inference on each of a list of projects. + +# For usage and requirements, see the "Whole-program inference" +# section of the Checker Framework manual: +# https://checkerframework.org/manual/#whole-program-inference + +while getopts "o:i:u:t:g:" opt; do + case $opt in + o) OUTDIR="$OPTARG" + ;; + i) INLIST="$OPTARG" + ;; + u) GITHUB_USER="$OPTARG" + ;; + t) TIMEOUT="$OPTARG" + ;; + g) GRADLECACHEDIR="$OPTARG" + ;; + \?) # the remainder of the arguments will be passed to DLJC directly + ;; + esac +done + +# Make $@ be the arguments that should be passed to dljc. +shift $(( OPTIND - 1 )) + +echo "Starting wpi-many.sh. The output of this script is purely informational." + +# check required arguments and environment variables: + +if [ "x${JAVA_HOME}" = "x" ]; then + has_java_home="no" +else + has_java_home="yes" +fi + +# testing for JAVA8_HOME, not an unintentional reference to JAVA_HOME +# shellcheck disable=SC2153 +if [ "x${JAVA8_HOME}" = "x" ]; then + has_java8="no" +else + has_java8="yes" +fi + +# testing for JAVA11_HOME, not an unintentional reference to JAVA_HOME +# shellcheck disable=SC2153 +if [ "x${JAVA11_HOME}" = "x" ]; then + has_java11="no" +else + has_java11="yes" +fi + +if [ "${has_java_home}" = "yes" ]; then + java_version=$("${JAVA_HOME}"/bin/java -version 2>&1 | head -1 | cut -d'"' -f2 | sed '/^1\./s///' | cut -d'.' -f1) + if [ "${has_java8}" = "no" ] && [ "${java_version}" = 8 ]; then + export JAVA8_HOME="${JAVA_HOME}" + has_java8="yes" + fi + if [ "${has_java11}" = "no" ] && [ "${java_version}" = 11 ]; then + export JAVA11_HOME="${JAVA_HOME}" + has_java11="yes" + fi +fi + +if [ "${has_java8}" = "yes" ] && [ ! -d "${JAVA8_HOME}" ]; then + echo "JAVA8_HOME is set to a non-existent directory ${JAVA8_HOME}" + exit 1 +fi + +if [ "${has_java11}" = "yes" ] && [ ! -d "${JAVA11_HOME}" ]; then + echo "JAVA11_HOME is set to a non-existent directory ${JAVA11_HOME}" + exit 1 +fi + +if [ "${has_java8}" = "no" ] && [ "${has_java11}" = "no" ]; then + echo "No Java 8 or 11 JDKs found. At least one of JAVA_HOME, JAVA8_HOME, or JAVA11_HOME must be set." + exit 1 +fi + +if [ "x${CHECKERFRAMEWORK}" = "x" ]; then + echo "CHECKERFRAMEWORK is not set; it must be set to a locally-built Checker Framework. Please clone and build github.com/typetools/checker-framework" + exit 2 +fi + +if [ ! -d "${CHECKERFRAMEWORK}" ]; then + echo "CHECKERFRAMEWORK is set to a non-existent directory ${CHECKERFRAMEWORK}" + exit 2 +fi + +if [ "x${OUTDIR}" = "x" ]; then + echo "You must specify an output directory using the -o argument." + exit 3 +fi + +if [ "x${INLIST}" = "x" ]; then + echo "You must specify an input file using the -i argument." + exit 4 +fi + +if [ "x${GITHUB_USER}" = "x" ]; then + GITHUB_USER="${USER}" +fi + +if [ "x${GRADLECACHEDIR}" = "x" ]; then + GRADLECACHEDIR=".gradle" +fi + +JAVA_HOME_BACKUP="${JAVA_HOME}" +export JAVA_HOME="${JAVA11_HOME}" + +### Script + +echo "Finished configuring wpi-many.sh. Results will be placed in ${OUTDIR}-results/." + +SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +export PATH="${JAVA_HOME}/bin:${PATH}" + +mkdir -p "${OUTDIR}" +mkdir -p "${OUTDIR}-results" + +cd "${OUTDIR}" || exit 5 + +while IFS='' read -r line || [ "$line" ] +do + REPOHASH=${line} + + REPO=$(echo "${REPOHASH}" | awk '{print $1}') + HASH=$(echo "${REPOHASH}" | awk '{print $2}') + + REPO_NAME=$(echo "${REPO}" | cut -d / -f 5) + REPO_NAME_HASH="${REPO_NAME}-${HASH}" + + # Use repo name and hash, but not owner. We want + # repos that are different but have the same name to be treated + # as different repos, but forks with the same content to be skipped. + # TODO: consider just using hash, to skip hard forks? + mkdir -p "${REPO_NAME_HASH}" + + cd "${REPO_NAME_HASH}" || exit 5 + + if [ ! -d "${REPO_NAME}" ]; then + # The "GIT_TERMINAL_PROMPT=0" setting prevents git from prompting for + # username/password if the repository no longer exists. + GIT_TERMINAL_PROMPT=0 git clone "${REPO}" + # Skip the rest of the loop and move on to the next project + # if cloning isn't successful. + if [ ! -d "${REPO_NAME}" ]; then + continue + fi + else + rm -rf "${REPO_NAME}/dljc-out" + fi + + cd "${REPO_NAME}" || exit 5 + + git checkout "${HASH}" + + OWNER=$(echo "${REPO}" | cut -d / -f 4) + + if [ "${OWNER}" = "${GITHUB_USER}" ]; then + ORIGIN=$(echo "${REPOHASH}" | awk '{print $3}') + git remote add unannotated "${ORIGIN}" + fi + + REPO_FULLPATH=$(pwd) + + cd "${OUTDIR}/${REPO_NAME_HASH}" || exit 5 + + RESULT_LOG="${OUTDIR}-results/${REPO_NAME_HASH}-wpi.log" + touch "${RESULT_LOG}" + + /bin/bash -x "${SCRIPTDIR}/wpi.sh" -d "${REPO_FULLPATH}" -t "${TIMEOUT}" -g "${GRADLECACHEDIR}" -- "$@" &> "${RESULT_LOG}" &> "${OUTDIR}-results/wpi-out" || cat "${OUTDIR}-results/wpi-out" + rm -f "${OUTDIR}-result/wpi-out" + + cd "${OUTDIR}" || exit 5 + + # If the result is unusable (i.e. wpi cannot run), + # we don't need it for data analysis and we can + # delete it right away. + if [ -f "${REPO_FULLPATH}/.cannot-run-wpi" ]; then + echo "Deleting ${REPO_NAME_HASH} because WPI could not be run." + rm -rf "${REPO_NAME_HASH}" + else + cat "${REPO_FULLPATH}/dljc-out/wpi.log" >> "${RESULT_LOG}" + fi + + cd "${OUTDIR}" || exit 5 + +done <"${INLIST}" + +## This section is here rather than in wpi-summary.sh because counting lines can be moderately expensive. +## wpi-summary.sh is intended to be run while a human waits (unlike this script), so this script +## precomputes as much as it can, to make wpi-summary.sh faster. + +results_available=$(grep -Zvl -e "no build file found for" \ + -e "dljc could not run the Checker Framework" \ + -e "dljc could not run the build successfully" \ + -e "dljc timed out for" \ + "${OUTDIR}-results/"*.log) + +echo "${results_available}" > "${OUTDIR}-results/results_available.txt" + +if [ -n "${results_available}" ]; then + listpath=$(mktemp /tmp/cloc-file-list-XXX.txt) + # Compute lines of non-comment, non-blank Java code in the projects whose + # results can be inspected by hand (that is, those that WPI succeeded on). + grep -oh "\S*\.java" "${results_available}" | sort | uniq > "${listpath}" + + cd "${SCRIPTDIR}/.do-like-javac" || exit 5 + wget -nc "https://github.com/boyter/scc/releases/download/v2.13.0/scc-2.13.0-i386-unknown-linux.zip" + unzip -o "scc-2.13.0-i386-unknown-linux.zip" + + "${SCRIPTDIR}/.do-like-javac/scc" --output "${OUTDIR}-results/loc.txt" \ + "$(< "${listpath}")" + + rm -f "${listpath}" +fi + +export JAVA_HOME="${JAVA_HOME_BACKUP}" + +echo "Exiting wpi-many.sh. The output of this script was purely informational. Results were placed in ${OUTDIR}-results/." diff --git a/checker/bin/wpi-summary.sh b/checker/bin/wpi-summary.sh new file mode 100755 index 0000000000..1e329046b8 --- /dev/null +++ b/checker/bin/wpi-summary.sh @@ -0,0 +1,57 @@ +#!/bin/sh + +# This script takes a directory of .log files as input, and produces a summary of the results. +# Use its output to guide your analysis of the results of running ./wpi-many.sh. +# +# This script categorizes projects as: +# * does not have a maven or gradle build file +# * failed to build +# * WPI timed out +# * WPI produced results (reported as "results available"). This +# script makes no attempt to categorize these projects: a human +# should inspect these log files/projects to see the results. + +targetdir=$1 + +number_of_projects=$(find "${targetdir}" -name "*.log" | wc -l) + +no_build_file=$(grep -cl "no build file found for" "${targetdir}/"*.log) +no_build_file_percent=$(((no_build_file*100)/number_of_projects)) + +# "old" and "new" in the below refer to the two different messages that +# dljc's wpi tool can emit for this kind of failure. At some point while +# running an early set of these experiments, I realized that the original +# message wasn't correct, and fixed it. But, for backwards compatibility, +# this script looks for both messages and combines the counts. +build_failed_old=$(grep -cl "dljc could not run the Checker Framework" "${targetdir}/"*.log) +build_failed_new=$(grep -cl "dljc could not run the build successfully" "${targetdir}/"*.log) +build_failed=$((build_failed_old+build_failed_new)) +build_failed_percent=$(((build_failed*100)/number_of_projects)) + +timed_out=$(grep -cl "dljc timed out for" "${targetdir}/"*.log) +timed_out_percent=$(((timed_out*100)/number_of_projects)) + +echo "number of projects: ${number_of_projects} (100%)" +echo "no maven or gradle build file: ${no_build_file} (~${no_build_file_percent}%)" +echo "build failed: ${build_failed} (~${build_failed_percent}%)" +echo "timed out: ${timed_out} (~${timed_out_percent}%)" +echo "" +echo "timeouts:" +echo "" +grep -l "dljc timed out for" "${targetdir}/"*.log +echo "" + +results_available=$(cat "${targetdir}/results_available.txt") + +echo "results are available for these projects: " +echo "" +echo "${results_available}" | tr ' ' '\n' +echo "" + +if [ -f "${targetdir}/loc.txt" ]; then + echo "LoC of projects with available results:" + + cat "${targetdir}/loc.txt" +else + echo "No LoC count found for projects with available results" +fi diff --git a/checker/bin/wpi.sh b/checker/bin/wpi.sh new file mode 100755 index 0000000000..45bae0647e --- /dev/null +++ b/checker/bin/wpi.sh @@ -0,0 +1,247 @@ +#!/bin/bash + +# This script performs whole-program inference on a project directory. + +# For usage and requirements, see the "Whole-program inference" +# section of the Checker Framework manual: +# https://checkerframework.org/manual/#whole-program-inference + + +while getopts "d:t:b:g:" opt; do + case $opt in + d) DIR="$OPTARG" + ;; + t) TIMEOUT="$OPTARG" + ;; + b) EXTRA_BUILD_ARGS="$OPTARG" + ;; + g) GRADLECACHEDIR="$OPTARG" + ;; + \?) # echo "Invalid option -$OPTARG" >&2 + ;; + esac +done + +# Make $@ be the arguments that should be passed to dljc. +shift $(( OPTIND - 1 )) + +echo "Starting wpi.sh. The output of this script is purely informational." + +# check required arguments and environment variables: + +if [ "x${JAVA_HOME}" = "x" ]; then + has_java_home="no" +else + has_java_home="yes" +fi + +# testing for JAVA8_HOME, not an unintentional reference to JAVA_HOME +# shellcheck disable=SC2153 +if [ "x${JAVA8_HOME}" = "x" ]; then + has_java8="no" +else + has_java8="yes" +fi + +# testing for JAVA11_HOME, not an unintentional reference to JAVA_HOME +# shellcheck disable=SC2153 +if [ "x${JAVA11_HOME}" = "x" ]; then + has_java11="no" +else + has_java11="yes" +fi + +if [ "${has_java_home}" = "yes" ]; then + java_version=$("${JAVA_HOME}"/bin/java -version 2>&1 | head -1 | cut -d'"' -f2 | sed '/^1\./s///' | cut -d'.' -f1) + if [ "${has_java8}" = "no" ] && [ "${java_version}" = 8 ]; then + export JAVA8_HOME="${JAVA_HOME}" + has_java8="yes" + fi + if [ "${has_java11}" = "no" ] && [ "${java_version}" = 11 ]; then + export JAVA11_HOME="${JAVA_HOME}" + has_java11="yes" + fi +fi + +if [ "${has_java8}" = "yes" ] && [ ! -d "${JAVA8_HOME}" ]; then + echo "JAVA8_HOME is set to a non-existent directory ${JAVA8_HOME}" + exit 6 +fi + +if [ "${has_java11}" = "yes" ] && [ ! -d "${JAVA11_HOME}" ]; then + echo "JAVA11_HOME is set to a non-existent directory ${JAVA11_HOME}" + exit 7 +fi + +if [ "${has_java8}" = "no" ] && [ "${has_java11}" = "no" ]; then + echo "No Java 8 or 11 JDKs found. At least one of JAVA_HOME, JAVA8_HOME, or JAVA11_HOME must be set." + exit 8 +fi + +if [ "x${CHECKERFRAMEWORK}" = "x" ]; then + echo "CHECKERFRAMEWORK is not set; it must be set to a locally-built Checker Framework. Please clone and build github.com/typetools/checker-framework" + exit 2 +fi + +if [ ! -d "${CHECKERFRAMEWORK}" ]; then + echo "CHECKERFRAMEWORK is set to a non-existent directory ${CHECKERFRAMEWORK}" + exit 9 +fi + +if [ "x${DIR}" = "x" ]; then + # echo "wpi.sh: no -d argument supplied, using the current directory." + DIR=$(pwd) +fi + +if [ ! -d "${DIR}" ]; then + echo "wpi.sh's -d argument was not a directory: ${DIR}" + exit 4 +fi + +if [ "x${EXTRA_BUILD_ARGS}" = "x" ]; then + EXTRA_BUILD_ARGS="" +fi + +if [ "x${GRADLECACHEDIR}" = "x" ]; then + GRADLECACHEDIR=".gradle" +fi + +function configure_and_exec_dljc { + + if [ -f build.gradle ]; then + if [ -f gradlew ]; then + chmod +x gradlew + GRADLE_EXEC="./gradlew" + else + GRADLE_EXEC="gradle" + fi + if [ ! -d "${GRADLECACHEDIR}" ]; then + mkdir "${GRADLECACHEDIR}" + fi + CLEAN_CMD="${GRADLE_EXEC} clean -g ${GRADLECACHEDIR} -Dorg.gradle.java.home=${JAVA_HOME} ${EXTRA_BUILD_ARGS}" + BUILD_CMD="${GRADLE_EXEC} clean compileJava -g ${GRADLECACHEDIR} -Dorg.gradle.java.home=${JAVA_HOME} ${EXTRA_BUILD_ARGS}" + elif [ -f pom.xml ]; then + if [ -f mvnw ]; then + chmod +x mvnw + MVN_EXEC="./mvnw" + else + MVN_EXEC="mvn" + fi + # if running on java 8, need /jre at the end of this Maven command + if [ "${JAVA_HOME}" = "${JAVA8_HOME}" ]; then + CLEAN_CMD="${MVN_EXEC} clean -Djava.home=${JAVA_HOME}/jre ${EXTRA_BUILD_ARGS}" + BUILD_CMD="${MVN_EXEC} clean compile -Djava.home=${JAVA_HOME}/jre ${EXTRA_BUILD_ARGS}" + else + CLEAN_CMD="${MVN_EXEC} clean -Djava.home=${JAVA_HOME} ${EXTRA_BUILD_ARGS}" + BUILD_CMD="${MVN_EXEC} clean compile -Djava.home=${JAVA_HOME} ${EXTRA_BUILD_ARGS}" + fi + elif [ -f build.xml ]; then + # TODO: test these more thoroughly + CLEAN_CMD="ant clean ${EXTRA_BUILD_ARGS}" + BUILD_CMD="ant clean compile ${EXTRA_BUILD_ARGS}" + else + echo "no build file found for ${REPO_NAME}; not calling DLJC" + WPI_RESULTS_AVAILABLE="no" + return + fi + + # This command also includes "clean"; I'm not sure why it is necessary. + DLJC_CMD="${DLJC} -t wpi $* -- ${BUILD_CMD}" + + if [ ! "x${TIMEOUT}" = "x" ]; then + TMP="${DLJC_CMD}" + DLJC_CMD="timeout ${TIMEOUT} ${TMP}" + fi + + # Remove old DLJC output. + rm -rf dljc-out + + # ensure the project is clean before invoking DLJC + eval "${CLEAN_CMD}" < /dev/null > /dev/null 2>&1 + + mkdir -p "${DIR}/dljc-out/" + dljc_stdout=$(mktemp "${DIR}/dljc-out/dljc-stdout.XXXXXX") + + PATH_BACKUP="${PATH}" + export PATH="${JAVA_HOME}/bin:${PATH}" + + # use simpler syntax because this line was crashing mysteriously in CI, to get better debugging output + # shellcheck disable=SC2129 + echo "JAVA_HOME: ${JAVA_HOME}" >> "$dljc_stdout" + echo "PATH: ${PATH}" >> "$dljc_stdout" + echo "DLJC_CMD: ${DLJC_CMD}" >> "$dljc_stdout" + eval "${DLJC_CMD}" < /dev/null >> "$dljc_stdout" 2>&1 + DLJC_STATUS=$? + + export PATH="${PATH_BACKUP}" + + echo "=== DLJC standard out/err follows: ===" + cat "${dljc_stdout}" + echo "=== End of DLJC standard out/err. ===" + + if [[ $DLJC_STATUS -eq 124 ]]; then + echo "dljc timed out for ${DIR}" + WPI_RESULTS_AVAILABLE="no" + return + fi + + if [ -f dljc-out/wpi.log ]; then + echo "dljc output is available in ${DIR}/dljc-out/; stdout is in $dljc_stdout" + WPI_RESULTS_AVAILABLE="yes" + else + echo "dljc output is not available in ${DIR}/dljc-out/; stdout is in $dljc_stdout" + WPI_RESULTS_AVAILABLE="no" + fi +} + +#### Check and setup dependencies + +SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +# clone or update DLJC +if [ -d "${SCRIPTDIR}/.do-like-javac" ]; then + git -C "${SCRIPTDIR}/.do-like-javac" pull --quiet +else + git -C "${SCRIPTDIR}" clone https://github.com/kelloggm/do-like-javac --depth 1 --quiet .do-like-javac || (echo "Cannot clone do-like-javac" && exit 1) +fi + +DLJC="${SCRIPTDIR}/.do-like-javac/dljc" + +#### Main script + +echo "Finished configuring wpi.sh." + +rm -f "${DIR}/.cannot-run-wpi" + +cd "${DIR}" || exit 5 + +JAVA_HOME_BACKUP="${JAVA_HOME}" +if [ "${has_java11}" = "yes" ]; then + export JAVA_HOME="${JAVA11_HOME}" + configure_and_exec_dljc "$@" +elif [ "${has_java8}" = "yes" ]; then + export JAVA_HOME="${JAVA8_HOME}" + configure_and_exec_dljc "$@" +fi + +if [ "${has_java11}" = "yes" ] && [ "${WPI_RESULTS_AVAILABLE}" = "no" ]; then + # if running under Java 11 fails, try to run + # under Java 8 instead + if [ "${has_java8}" = "yes" ]; then + export JAVA_HOME="${JAVA8_HOME}" + echo "couldn't build using Java 11; trying Java 8" + configure_and_exec_dljc "$@" + fi +fi + +# support wpi-many.sh's ability to delete projects without usable results +# automatically +if [ "${WPI_RESULTS_AVAILABLE}" = "no" ]; then + echo "dljc could not run the build successfully." + echo "Check the log files in ${DIR}/dljc-out/ for diagnostics." + touch "${DIR}/.cannot-run-wpi" +fi + +export JAVA_HOME="${JAVA_HOME_BACKUP}" + +echo "Exiting wpi.sh." diff --git a/checker/build.gradle b/checker/build.gradle index 894f00439f..0ed5976d35 100644 --- a/checker/build.gradle +++ b/checker/build.gradle @@ -18,15 +18,20 @@ sourceSets { } dependencies { - implementation project(':framework') - implementation project(':dataflow') implementation project(':javacutil') + implementation project(':dataflow') + implementation project(':framework') + // AFU is an "includedBuild" imported in checker-framework/settings.gradle, so the version number doesn't matter. + // https://docs.gradle.org/current/userguide/composite_builds.html#settings_defined_composite + implementation('org.checkerframework:annotation-file-utilities:*') { + exclude group: 'com.google.errorprone', module: 'javac' + } implementation project(':checker-qual') - // As of 2019/12/16, the version of reflection-util in the Annotation + // As of 2019-12-16, the version of reflection-util in the Annotation // File Utilities takes priority over this version, in the fat jar // file. :-( So update it and re-build it locally when updating this. implementation 'org.plumelib:reflection-util:1.0.2' - implementation 'org.plumelib:plume-util:1.1.7' + implementation 'org.plumelib:plume-util:1.3.0' // Called Methods Checker AutoValue + Lombok support testImplementation "com.google.auto.value:auto-value-annotations:1.7.4" @@ -47,7 +52,7 @@ dependencies { // The AWS SDK is used for testing the Called Methods Checker. dependencyManagement { imports { - mavenBom "com.amazonaws:aws-java-sdk-bom:1.11.873" + mavenBom "com.amazonaws:aws-java-sdk-bom:1.11.923" } } @@ -128,6 +133,8 @@ artifacts { clean { delete "${projectDir}/dist" delete "tests/calledmethods-delomboked" + delete("tests/wpi-testchecker/annotated") + delete("tests/wpi-testchecker/inference-output") } // Add non-junit tests @@ -220,7 +227,7 @@ task jtregJdk11Tests(dependsOn: ':downloadJtreg', group: 'Verification') { String jtregOutput = "${buildDir}/jtregJdk11" String name = 'all' doLast { - if(isJava8) { + if (isJava8) { println "This test is only run with JDK 11." return; } @@ -291,3 +298,235 @@ task delombok { } tasks.test.dependsOn("delombok") + +/// +/// Whole-program inference tests +/// + +test { + useJUnit { + // These are run in task wholeProgramInferenceTests. + excludeCategories 'org.checkerframework.checker.test.junit.wpirunners.WholeProgramInferenceTestCheckerJaifsTest' + excludeCategories 'org.checkerframework.checker.test.junit.wpirunners.WholeProgramInferenceTestCheckerStubsTest' + } +} + +task testWpiTestCheckerStubs(type: Test) { + description 'Internal task to run the wpi-testchecker tests with -Ainfer=stubs to generate stub files' + + dependsOn(compileTestJava) + doFirst { + delete("tests/wpi-testchecker/annotated") + delete("${buildDir}/wpi-testchecker/") + } + outputs.upToDateWhen { false } + include '**/WholeProgramInferenceTestCheckerStubsTest.class' + testLogging { + // Always run the tests + outputs.upToDateWhen { false } + + // Show the found unexpected diagnostics and the expected diagnostics not found. + exceptionFormat "full" + events "passed", "skipped", "failed" + } + + doLast { + copyNonannotatedToAnnotatedDirectory("wpi-testchecker") + // The stub file format doesn't support annotations on anonymous inner classes, so + // this test also expects errors on UsesAnonymous.java. + delete('tests/wpi-testchecker/annotated/UsesAnonymous.java') + copy { + from file('tests/wpi-testchecker/non-annotated/UsesAnonymous.java') + into file('tests/wpi-testchecker/annotated') + } + } +} + +task testWpiTestCheckerStubsValidate(type: Test) { + description 'Internal task to re-run the wpi-testchecker tests using the stub files generated by testWpiTestCheckerStubs' + + dependsOn(testWpiTestCheckerStubs) + outputs.upToDateWhen { false } + include '**/WholeProgramInferenceTestCheckerStubsValidationTest.class' + testLogging { + // Always run the tests + outputs.upToDateWhen { false } + + // Show the found unexpected diagnostics and the expected diagnostics not found. + exceptionFormat "full" + events "passed", "skipped", "failed" + } +} + +// Copies directories as needed by WPI tests. +// Formal parameter testdir is, for example, "wpi-testchecker". +// Does work in directory "tests/${testdir}/". +// 1. Copies whole-program inference test source code from the non-annotated/ to the annotated/ directory. +// 2. Copies WPI output, such as .jaif or .stub files, to the inferference-output/ directory. +void copyNonannotatedToAnnotatedDirectory(String testdir) { + // Copying all test files to another directory, removing all expected errors that should not + // occur after inserting inferred annotations from .jaif files. + copy { + from files("tests/${testdir}/non-annotated") + into file("tests/${testdir}/annotated") + filter { String line -> + line.contains('// :: error:') ? null : line + } + } + // The only file for which expected errors are maintained is ExpectedErrors.java, so we copy it over. + delete("tests/${testdir}/annotated/ExpectedErrors.java") + copy { + from file("tests/${testdir}/non-annotated/ExpectedErrors.java") + into file("tests/${testdir}/annotated") + } + + delete("tests/${testdir}/inference-output") + file("build/whole-program-inference").renameTo(file("tests/${testdir}/inference-output")) +} + +// This task is similar to the wholeProgramInferenceTestCheckerJaifTests task below, but it doesn't +// run the insert-annotations-to-source tool. Instead, it tests the -Ainfer=stubs feature +// and the -AmergeStubsWithSource feature to do WPI using stub files. +task wholeProgramInferenceTestCheckerStubTests(dependsOn: 'shadowJar', group: 'Verification') { + description 'Run tests for whole-program inference using stub files' + dependsOn(testWpiTestCheckerStubsValidate) + outputs.upToDateWhen { false } +} + +task testWpiTestCheckerJaifs(type: Test) { + description 'Internal task to run the wpi-testchecker tests with -Ainfer=jaifs to generate .jaif files' + + dependsOn(compileTestJava) + doFirst { + delete("tests/wpi-testchecker/annotated") + } + outputs.upToDateWhen { false } + include '**/WholeProgramInferenceTestCheckerJaifsTest.class' + testLogging { + // Always run the tests + outputs.upToDateWhen { false } + + // Show the found unexpected diagnostics and expected diagnostics not found. + exceptionFormat "full" + events "passed", "skipped", "failed" + } + + doLast { + copyNonannotatedToAnnotatedDirectory("wpi-testchecker") + + // JAIF-based WPI fails these tests, which was added for stub-based WPI. + // See issue here: https://github.com/typetools/checker-framework/issues/3009 + delete('tests/wpi-testchecker/annotated/ConflictingAnnotationsTest.java') + delete('tests/wpi-testchecker/annotated/MultiDimensionalArrays.java') + + // Inserting annotations from .jaif files in-place. + String jaifsDir = "tests/wpi-testchecker/inference-output"; + List jaifs = fileTree(jaifsDir).matching { + include '*.jaif' + }.asList() + if (jaifs.isEmpty()) { + throw new GradleException("no .jaif files found in ${jaifsDir}") + } + String javasDir = "tests/wpi-testchecker/annotated/"; + List javas = fileTree(javasDir).matching { + include '*.java' + }.asList() + if (javas.isEmpty()) { + throw new GradleException("no .java files found in ${javasDir}") + } + exec { + executable "${afu}/scripts/insert-annotations-to-source" + args = ['-i'] + for (File jaif : jaifs) { + args += [jaif.toString()] + } + for (File javaFile : javas) { + args += [javaFile.toString()] + } + } + } +} + +task testWpiTestCheckerJaifsValidate(type: Test) { + description 'Internal task to re-run the wpi-testchecker tests using the .jaif files generated by testWpiTestCheckerJaifs' + + dependsOn(testWpiTestCheckerJaifs) + outputs.upToDateWhen { false } + include '**/WholeProgramInferenceTestCheckerJaifsValidationTest.class' + testLogging { + // Always run the tests + outputs.upToDateWhen { false } + + // Show the found unexpected diagnostics and expected diagnostics not found. + exceptionFormat "full" + events "passed", "skipped", "failed" + } +} + +task wholeProgramInferenceTestCheckerJaifTests(dependsOn: 'shadowJar', group: 'Verification') { + description 'Run tests for whole-program inference using .jaif files' + dependsOn(testWpiTestCheckerJaifsValidate) + outputs.upToDateWhen { false } +} + +// Empty task that just runs both the jaif and stub WPI tests. +// It is run as part of the nonJunitTests task. +task wholeProgramInferenceTests() { + description "Run tests for all whole program inference modes." + dependsOn('wholeProgramInferenceTestCheckerJaifTests') + dependsOn('wholeProgramInferenceTestCheckerStubTests') +} + +// This is run as part of the nonJunitTests task. +task wpiScriptsTests(group: "Verification") { + description 'Tests the wpi-many.sh script (and indirectly the wpi.sh script). Requires an Internet connection.' + + // This test must always be re-run when requested. + outputs.upToDateWhen { false } + + doFirst { + delete("${project.projectDir}/build/wpi-many-tests-results/") + } + + doLast { + // Run wpi-many.sh + exec { + commandLine 'bin/wpi-many.sh', + '-i', "${project.projectDir}/tests/wpi-many/testin.txt", + '-o', "${project.projectDir}/build/wpi-many-tests", + '--', '--checker', 'nullness,interning,lock,regex,signature' + } + // collect the logs from running WPI + def logFiles = fileTree("${project.projectDir}/build/wpi-many-tests-results/").matching { + include "**/*.log" + } + if (logFiles.size() == 0) { + throw new GradleException("Failure: WPI scripts did not produce any log files.") + } + + // check that WPI causes the expected builds to succeed + logFiles.visit { FileVisitDetails details -> + def content = details.getFile().readLines() + // TODO: why does the call to get() below throw an exception if the log files + // are empty if this check isn't present? + if (content.size() - 1 < 0) { + throw new GradleException("Failure: WPI produced empty log files.") + } else { + // iterate backwards and look for errors in the last WPI loop, + // and set success to false if any are found + for (int i = content.size() - 1; i--; i >= 0) { + def line = content.get(i) + // DLJC prints this string before each command that it runs. + if (line.startsWith("Running ")) { + break + } + if (line.toLowerCase().contains("error")) { + throw new GradleException("Failure: WPI scripts produced at least one error. " + + "See ${project.projectDir}/build/wpi-many-tests-results/" + details.getName() + ". " + + "Failing line is the following: " + line) + } + } + } + } + } +} diff --git a/checker/jtreg/index/ValueStubDriver.java b/checker/jtreg/index/ValueStubDriver.java index b279289165..2af0c02273 100644 --- a/checker/jtreg/index/ValueStubDriver.java +++ b/checker/jtreg/index/ValueStubDriver.java @@ -6,4 +6,4 @@ * @compile -XDrawDiagnostics -processor org.checkerframework.checker.index.IndexChecker valuestub/UseTest.java */ -class ValueStubDriver {} +public class ValueStubDriver {} diff --git a/checker/jtreg/issue1133/Main.java b/checker/jtreg/issue1133/Main.java index af7217768e..a7cd9e491e 100644 --- a/checker/jtreg/issue1133/Main.java +++ b/checker/jtreg/issue1133/Main.java @@ -6,4 +6,4 @@ * @compile/fail/ref=error.out -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker ClassA.java ClassB.java * @compile/fail/ref=error.out -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker ClassB.java ClassA.java */ -class Main {} +public class Main {} diff --git a/checker/jtreg/issue469/Main.java b/checker/jtreg/issue469/Main.java index 1b3e720314..763d08facc 100644 --- a/checker/jtreg/issue469/Main.java +++ b/checker/jtreg/issue469/Main.java @@ -12,4 +12,4 @@ * @compile -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker advancedcrash/LetItCrash.java advancedcrash/CrashyInterface.java advancedcrash/SomeInterface.java * @compile -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker advancedcrash/LetItCrash.java advancedcrash/SomeInterface.java advancedcrash/CrashyInterface.java */ -class Main {} +public class Main {} diff --git a/checker/jtreg/issue469/advancedcrash/LetItCrash.java b/checker/jtreg/issue469/advancedcrash/LetItCrash.java index 6a95256b90..14cebb2e3e 100644 --- a/checker/jtreg/issue469/advancedcrash/LetItCrash.java +++ b/checker/jtreg/issue469/advancedcrash/LetItCrash.java @@ -1,6 +1,6 @@ package advancedcrash; -class LetItCrash implements SomeInterface { +public class LetItCrash implements SomeInterface { Integer longer = 0; diff --git a/checker/jtreg/issue469/simplecrash/LetItCrash.java b/checker/jtreg/issue469/simplecrash/LetItCrash.java index f090eaac3f..6ef150ad5d 100644 --- a/checker/jtreg/issue469/simplecrash/LetItCrash.java +++ b/checker/jtreg/issue469/simplecrash/LetItCrash.java @@ -1,6 +1,6 @@ package simplecrash; -class LetItCrash implements CrashyInterface { +public class LetItCrash implements CrashyInterface { private Long longer = 0L; @Override diff --git a/checker/jtreg/issue469/simplecrash/SomeRandomClass.java b/checker/jtreg/issue469/simplecrash/SomeRandomClass.java index a949061c5e..a28dbf5bbd 100644 --- a/checker/jtreg/issue469/simplecrash/SomeRandomClass.java +++ b/checker/jtreg/issue469/simplecrash/SomeRandomClass.java @@ -1,6 +1,6 @@ package simplecrash; -class SomeRandomClass { +public class SomeRandomClass { void randomStuff(LetItCrash letItCrash) { letItCrash.makeItLongerAndCrash(); } diff --git a/checker/jtreg/multiplecheckers/NullnessInterning.java b/checker/jtreg/multiplecheckers/NullnessInterning.java index 50621cb228..faf6529c90 100644 --- a/checker/jtreg/multiplecheckers/NullnessInterning.java +++ b/checker/jtreg/multiplecheckers/NullnessInterning.java @@ -15,7 +15,7 @@ * @compile/ref=NullnessInterning4.out -XDrawDiagnostics -Anomsgtext -processor org.checkerframework.checker.nullness.NullnessChecker,org.checkerframework.checker.interning.InterningChecker NullnessInterning.java -Awarns -Aorg.checkerframework.common.basetype.BaseTypeChecker_skipDefs=NullnessInterning */ -class NullnessInterning { +public class NullnessInterning { Object f = null; void m(Object p) { diff --git a/checker/jtreg/nullness/Issue347.java b/checker/jtreg/nullness/Issue347.java index 0e77c70c24..f5319e00a2 100644 --- a/checker/jtreg/nullness/Issue347.java +++ b/checker/jtreg/nullness/Issue347.java @@ -9,7 +9,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; -class Issue347 { +public class Issue347 { @MonotonicNonNull String mono; diff --git a/checker/jtreg/nullness/Issue373.java b/checker/jtreg/nullness/Issue373.java index e2034bc3f5..a11a6697de 100644 --- a/checker/jtreg/nullness/Issue373.java +++ b/checker/jtreg/nullness/Issue373.java @@ -11,7 +11,7 @@ import java.util.Map; import java.util.Set; -class Issue373 extends AbstractMap { +public class Issue373 extends AbstractMap { @Override public Set> entrySet() { return Collections.emptySet(); diff --git a/checker/jtreg/nullness/annotationsOnExtends/Other.java b/checker/jtreg/nullness/annotationsOnExtends/Other.java index cca0222e13..f0cc1b6694 100644 --- a/checker/jtreg/nullness/annotationsOnExtends/Other.java +++ b/checker/jtreg/nullness/annotationsOnExtends/Other.java @@ -6,7 +6,7 @@ * @compile -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker Other.java Test.java Test2.java */ -class Other { +public class Other { void foo() { Test other = null; Test2 other2 = null; diff --git a/checker/jtreg/nullness/annotationsOnExtends/Test.java b/checker/jtreg/nullness/annotationsOnExtends/Test.java index 6c52b6ff38..6fd8099f69 100644 --- a/checker/jtreg/nullness/annotationsOnExtends/Test.java +++ b/checker/jtreg/nullness/annotationsOnExtends/Test.java @@ -1,3 +1,3 @@ import java.io.Serializable; -class Test implements Serializable {} +public class Test implements Serializable {} diff --git a/checker/jtreg/nullness/annotationsOnExtends/Test2.java b/checker/jtreg/nullness/annotationsOnExtends/Test2.java index ede2457b46..68e0782c52 100644 --- a/checker/jtreg/nullness/annotationsOnExtends/Test2.java +++ b/checker/jtreg/nullness/annotationsOnExtends/Test2.java @@ -1 +1 @@ -class Test2 extends Object {} +public class Test2 extends Object {} diff --git a/checker/jtreg/nullness/constructor-initialization/NonDefaultConstructor.java b/checker/jtreg/nullness/constructor-initialization/NonDefaultConstructor.java index 248a33ad6f..43023cae6b 100644 --- a/checker/jtreg/nullness/constructor-initialization/NonDefaultConstructor.java +++ b/checker/jtreg/nullness/constructor-initialization/NonDefaultConstructor.java @@ -6,7 +6,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -class NonDefaultConstructor { +public class NonDefaultConstructor { Object nonNull = 4; Object nullObject; @MonotonicNonNull Object lazyField; diff --git a/checker/jtreg/nullness/inheritDeclAnnoPersist/Super.java b/checker/jtreg/nullness/inheritDeclAnnoPersist/Super.java index 7acb37b8cc..2ab7a324c5 100644 --- a/checker/jtreg/nullness/inheritDeclAnnoPersist/Super.java +++ b/checker/jtreg/nullness/inheritDeclAnnoPersist/Super.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNull; import org.checkerframework.dataflow.qual.SideEffectFree; -class Super { +public class Super { Object f; Object g; Object h; diff --git a/checker/jtreg/nullness/issue12/BinaryDefaultTest.java b/checker/jtreg/nullness/issue12/BinaryDefaultTest.java index 25d0a305f4..42408204f7 100644 --- a/checker/jtreg/nullness/issue12/BinaryDefaultTest.java +++ b/checker/jtreg/nullness/issue12/BinaryDefaultTest.java @@ -10,7 +10,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -class BinaryDefaultTest { +public class BinaryDefaultTest { void test1(@NonNull BinaryDefaultTestInterface bar, @Nullable BinaryDefaultTestInterface bar2) { @Nullable BinaryDefaultTestBinary foo = BinaryDefaultTestBinary.foo(bar); @Nullable BinaryDefaultTestBinary baz = BinaryDefaultTestBinary.foo(bar2); diff --git a/checker/jtreg/nullness/issue12/BinaryDefaultTestWithStub.java b/checker/jtreg/nullness/issue12/BinaryDefaultTestWithStub.java index 0eee2c843a..9bf213bc4d 100644 --- a/checker/jtreg/nullness/issue12/BinaryDefaultTestWithStub.java +++ b/checker/jtreg/nullness/issue12/BinaryDefaultTestWithStub.java @@ -12,7 +12,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -class BinaryDefaultTestWithStub { +public class BinaryDefaultTestWithStub { void test1(@NonNull BinaryDefaultTestInterface bar, @Nullable BinaryDefaultTestInterface bar2) { @Nullable BinaryDefaultTestBinary foo = BinaryDefaultTestBinary.foo(bar); @Nullable BinaryDefaultTestBinary baz = BinaryDefaultTestBinary.foo(bar2); diff --git a/checker/jtreg/nullness/issue141/CharStreams.java b/checker/jtreg/nullness/issue141/CharStreams.java index 6dafa32eee..75a7c761ef 100644 --- a/checker/jtreg/nullness/issue141/CharStreams.java +++ b/checker/jtreg/nullness/issue141/CharStreams.java @@ -1,4 +1,4 @@ -class CharStreams { +public class CharStreams { static void copy( InputSupplier from, OutputSupplier to) {} } diff --git a/checker/jtreg/nullness/issue141/Driver.java b/checker/jtreg/nullness/issue141/Driver.java index 91db31d3bd..e1bf7ecdf5 100644 --- a/checker/jtreg/nullness/issue141/Driver.java +++ b/checker/jtreg/nullness/issue141/Driver.java @@ -9,4 +9,4 @@ * @compile -XDrawDiagnostics -processor org.checkerframework.checker.regex.RegexChecker Files.java * */ -class Driver {} +public class Driver {} diff --git a/checker/jtreg/nullness/issue1929/Issue1929-notrust.out b/checker/jtreg/nullness/issue1929/Issue1929-notrust.out index a868da756a..f40e15da3b 100644 --- a/checker/jtreg/nullness/issue1929/Issue1929-notrust.out +++ b/checker/jtreg/nullness/issue1929/Issue1929-notrust.out @@ -1,10 +1,10 @@ Issue1929.java:21:25: compiler.err.proc.messager: [return.type.incompatible] incompatible types in return. type of expression: @Initialized @Nullable String @Initialized @NonNull [] method return type: @Initialized @NonNull String @Initialized @NonNull [] -Issue1929.java:21:25: compiler.warn.proc.messager: [toArray.nullable.elements.not.newarray] call of toArray on collection of non-null elements yields an array of possibly-null elements; omit the argument to toArray or make it an explicit array constructor +Issue1929.java:21:25: compiler.warn.proc.messager: [toarray.nullable.elements.not.newarray] call of toArray on collection of non-null elements yields an array of possibly-null elements; omit the argument to toArray or make it an explicit array constructor Issue1929.java:29:25: compiler.err.proc.messager: [return.type.incompatible] incompatible types in return. type of expression: @Initialized @Nullable String @Initialized @NonNull [] method return type: @Initialized @NonNull String @Initialized @NonNull [] -Issue1929.java:29:25: compiler.warn.proc.messager: [toArray.nullable.elements.not.newarray] call of toArray on collection of non-null elements yields an array of possibly-null elements; omit the argument to toArray or make it an explicit array constructor +Issue1929.java:29:25: compiler.warn.proc.messager: [toarray.nullable.elements.not.newarray] call of toArray on collection of non-null elements yields an array of possibly-null elements; omit the argument to toArray or make it an explicit array constructor 2 errors 2 warnings diff --git a/checker/jtreg/nullness/issue1929/Issue1929-trust.out b/checker/jtreg/nullness/issue1929/Issue1929-trust.out index ccb85c6838..5494e2647f 100644 --- a/checker/jtreg/nullness/issue1929/Issue1929-trust.out +++ b/checker/jtreg/nullness/issue1929/Issue1929-trust.out @@ -1,6 +1,6 @@ Issue1929.java:29:25: compiler.err.proc.messager: [return.type.incompatible] incompatible types in return. type of expression: @Initialized @Nullable String @Initialized @NonNull [] method return type: @Initialized @NonNull String @Initialized @NonNull [] -Issue1929.java:29:25: compiler.warn.proc.messager: [toArray.nullable.elements.not.newarray] call of toArray on collection of non-null elements yields an array of possibly-null elements; omit the argument to toArray or make it an explicit array constructor +Issue1929.java:29:25: compiler.warn.proc.messager: [toarray.nullable.elements.not.newarray] call of toArray on collection of non-null elements yields an array of possibly-null elements; omit the argument to toArray or make it an explicit array constructor 1 error 1 warning diff --git a/checker/jtreg/nullness/issue257/ClientBuilder.java b/checker/jtreg/nullness/issue257/ClientBuilder.java index 528115bf45..829d324ceb 100644 --- a/checker/jtreg/nullness/issue257/ClientBuilder.java +++ b/checker/jtreg/nullness/issue257/ClientBuilder.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.NonNull; -class ClientBuilder> { +public class ClientBuilder> { static @NonNull ClientBuilder newBuilder() { return new BuilderImpl(); diff --git a/checker/jtreg/nullness/issue257/Module.java b/checker/jtreg/nullness/issue257/Module.java index 4a27ad52a5..400c94390a 100644 --- a/checker/jtreg/nullness/issue257/Module.java +++ b/checker/jtreg/nullness/issue257/Module.java @@ -8,7 +8,7 @@ * * @compile -XDrawDiagnostics ClientBuilder.java */ -class Module { +public class Module { void buildClient() { ClientBuilder builder = ClientBuilder.newBuilder().setThing().setThing(); } diff --git a/checker/jtreg/nullness/issue257/Small.java b/checker/jtreg/nullness/issue257/Small.java index 6ca932042c..cd4b6bea48 100644 --- a/checker/jtreg/nullness/issue257/Small.java +++ b/checker/jtreg/nullness/issue257/Small.java @@ -7,7 +7,7 @@ class Gen> { } } -class Small { +public class Small { void buildGen() { Gen> builder = Gen.newBuilder(); } diff --git a/checker/jtreg/nullness/issue3700/Client.out b/checker/jtreg/nullness/issue3700/Client.out index 4547baa764..f0d8acb757 100644 --- a/checker/jtreg/nullness/issue3700/Client.out +++ b/checker/jtreg/nullness/issue3700/Client.out @@ -1,2 +1,2 @@ -warning: StubParser: TimeUnitRange is an enum, but stub file declared it as class TimeUnitRange {... +warning: TimeUnitRange.astub:(line 3,col 1): TimeUnitRange is an enum, but stub file declared it as class TimeUnitRange {... 1 warning diff --git a/checker/jtreg/nullness/issue3700/TimeUnitRange.java b/checker/jtreg/nullness/issue3700/TimeUnitRange.java index 864f07ac32..cc4e5f0f9a 100644 --- a/checker/jtreg/nullness/issue3700/TimeUnitRange.java +++ b/checker/jtreg/nullness/issue3700/TimeUnitRange.java @@ -2,7 +2,7 @@ * @test * @summary Test case for Issue #3700 https://github.com/typetools/checker-framework/issues/3700 * @compile -XDrawDiagnostics -Xlint:unchecked TimeUnitRange.java - * @compile/ref=Client.out -processor org.checkerframework.checker.nullness.NullnessChecker Client.java -Astubs=TimeUnitRange.astub -implicit:none + * @compile/ref=Client.out -processor org.checkerframework.checker.nullness.NullnessChecker Client.java -Astubs=TimeUnitRange.astub -implicit:none -Anomsgtext */ public enum TimeUnitRange { diff --git a/checker/jtreg/nullness/issue380/DA.java b/checker/jtreg/nullness/issue380/DA.java index 809f777d98..8676c10dbc 100644 --- a/checker/jtreg/nullness/issue380/DA.java +++ b/checker/jtreg/nullness/issue380/DA.java @@ -1,4 +1,4 @@ -class DA { +public class DA { @Decl(flag = true) void foo() {} } diff --git a/checker/jtreg/nullness/issue380/DB.java b/checker/jtreg/nullness/issue380/DB.java index 393d184150..98b982598b 100644 --- a/checker/jtreg/nullness/issue380/DB.java +++ b/checker/jtreg/nullness/issue380/DB.java @@ -1,3 +1,3 @@ -class DB extends DA { +public class DB extends DA { void foo() {} } diff --git a/checker/jtreg/nullness/issue380/Driver.java b/checker/jtreg/nullness/issue380/Driver.java index 60c4ef06c5..7cb884db38 100644 --- a/checker/jtreg/nullness/issue380/Driver.java +++ b/checker/jtreg/nullness/issue380/Driver.java @@ -7,4 +7,4 @@ * * */ -class Driver {} +public class Driver {} diff --git a/checker/jtreg/nullness/issue820/AnonymousClass.java b/checker/jtreg/nullness/issue820/AnonymousClass.java index 8d6acb61be..cafe4c2bb5 100644 --- a/checker/jtreg/nullness/issue820/AnonymousClass.java +++ b/checker/jtreg/nullness/issue820/AnonymousClass.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.NonNull; -class AnonymousClass { +public class AnonymousClass { @NonNull Object error = null; void method() { diff --git a/checker/jtreg/nullness/issue820/Error.java b/checker/jtreg/nullness/issue820/Error.java index f9a21d5c93..05c981269a 100644 --- a/checker/jtreg/nullness/issue820/Error.java +++ b/checker/jtreg/nullness/issue820/Error.java @@ -9,6 +9,6 @@ * */ -class Error { +public class Error { @NonNull Object o = null; } diff --git a/checker/jtreg/nullness/issue824lib/First.java b/checker/jtreg/nullness/issue824lib/First.java index ecf80eca45..c92b9a2413 100644 --- a/checker/jtreg/nullness/issue824lib/First.java +++ b/checker/jtreg/nullness/issue824lib/First.java @@ -1,4 +1,4 @@ -class First { +public class First { public interface Supplier {} public interface Callable {} diff --git a/checker/jtreg/nullness/stub-warnings/Binary.java b/checker/jtreg/nullness/stub-warnings/Binary.java index 0b1d01071e..9f650332f9 100644 --- a/checker/jtreg/nullness/stub-warnings/Binary.java +++ b/checker/jtreg/nullness/stub-warnings/Binary.java @@ -4,7 +4,7 @@ import javax.annotation.Nullable; import org.checkerframework.checker.nullness.qual.NonNull; -class Binary { +public class Binary { @Nullable Object foo() { return null; } diff --git a/checker/jtreg/nullness/stub-warnings/StubWarnings.out b/checker/jtreg/nullness/stub-warnings/StubWarnings.out index d6823b0b94..72d0f4747e 100644 --- a/checker/jtreg/nullness/stub-warnings/StubWarnings.out +++ b/checker/jtreg/nullness/stub-warnings/StubWarnings.out @@ -1,5 +1,5 @@ -- compiler.warn.proc.messager: StubParser: in file binary.astub at line 6: redundant stub file specification for: Binary.foo() -- compiler.warn.proc.messager: StubParser: in file binary.astub at line 8: redundant stub file specification for: Binary.bar(java.lang.Object) +- compiler.warn.proc.messager: binary.astub:(line 6,col 5): redundant stub file specification for Binary.foo() +- compiler.warn.proc.messager: binary.astub:(line 8,col 5): redundant stub file specification for Binary.bar(java.lang.Object) - compiler.err.warnings.and.werror 1 error 2 warnings diff --git a/checker/jtreg/rawtypes/RawTypeFail.java b/checker/jtreg/rawtypes/RawTypeFail.java index 68f80a35c9..ba9aecc53c 100644 --- a/checker/jtreg/rawtypes/RawTypeFail.java +++ b/checker/jtreg/rawtypes/RawTypeFail.java @@ -10,7 +10,7 @@ import java.util.HashMap; import java.util.Map; -class RawTypeFail { +public class RawTypeFail { Map mr = new HashMap(); Map mc = mr; Map mc2 = new HashMap(); diff --git a/checker/jtreg/sortwarnings/Main.java b/checker/jtreg/sortwarnings/Main.java index 7a192198bd..42f9a81921 100644 --- a/checker/jtreg/sortwarnings/Main.java +++ b/checker/jtreg/sortwarnings/Main.java @@ -10,4 +10,4 @@ * @compile/fail/ref=OrderOfCheckers.out -XDrawDiagnostics -processor org.checkerframework.checker.index.IndexChecker OrderOfCheckers.java -AshowSuppressWarningsStrings */ -class Main {} +public class Main {} diff --git a/checker/jtreg/stubs/annotatedFor/Test.astub b/checker/jtreg/stubs/annotatedFor/Test.astub new file mode 100644 index 0000000000..f0fd607a2d --- /dev/null +++ b/checker/jtreg/stubs/annotatedFor/Test.astub @@ -0,0 +1,11 @@ +package annotatedforlib; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + +public class Test { + @AnnotatedFor("tainting") + public void method1(@Nullable T t){} + @AnnotatedFor("nullness") + public void method2(T t){} +} diff --git a/checker/jtreg/stubs/annotatedFor/UseTest.java b/checker/jtreg/stubs/annotatedFor/UseTest.java new file mode 100644 index 0000000000..0167452e5d --- /dev/null +++ b/checker/jtreg/stubs/annotatedFor/UseTest.java @@ -0,0 +1,18 @@ +/* + * @test + * @summary Test AnnotatedFor in stub files + * @compile -XDrawDiagnostics -Xlint:unchecked ../annotatedForLib/Test.java + * @compile/fail/ref=WithStub.out -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker -Anomsgtext UseTest.java -Astubs=Test.astub -AstubWarnIfNotFound -Werror + * @compile/fail/ref=WithoutStub.out -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker -Anomsgtext UseTest.java -AstubWarnIfNotFound -Werror + */ + +package annotatedfor; + +import annotatedforlib.Test; + +public class UseTest { + void test(Test test) { + test.method1(null); + test.method2(null); + } +} diff --git a/checker/jtreg/stubs/annotatedFor/WithStub.out b/checker/jtreg/stubs/annotatedFor/WithStub.out new file mode 100644 index 0000000000..4e9eaefd80 --- /dev/null +++ b/checker/jtreg/stubs/annotatedFor/WithStub.out @@ -0,0 +1,3 @@ +UseTest.java:15:22: compiler.err.proc.messager: (argument.type.incompatible) +UseTest.java:16:22: compiler.err.proc.messager: (argument.type.incompatible) +2 errors diff --git a/checker/jtreg/stubs/annotatedFor/WithoutStub.out b/checker/jtreg/stubs/annotatedFor/WithoutStub.out new file mode 100644 index 0000000000..112c0a532c --- /dev/null +++ b/checker/jtreg/stubs/annotatedFor/WithoutStub.out @@ -0,0 +1,2 @@ +UseTest.java:15:22: compiler.err.proc.messager: (argument.type.incompatible) +1 error diff --git a/checker/jtreg/stubs/annotatedForLib/Test.java b/checker/jtreg/stubs/annotatedForLib/Test.java new file mode 100644 index 0000000000..8b1b43b402 --- /dev/null +++ b/checker/jtreg/stubs/annotatedForLib/Test.java @@ -0,0 +1,9 @@ +package annotatedforlib; + +import org.checkerframework.checker.nullness.qual.Nullable; + +public class Test { + public void method1(T t) {} + + public void method2(@Nullable T t) {} +} diff --git a/checker/jtreg/stubs/defaultqualinstub/Main.java b/checker/jtreg/stubs/defaultqualinstub/Main.java index 67d792e393..7720f4f894 100644 --- a/checker/jtreg/stubs/defaultqualinstub/Main.java +++ b/checker/jtreg/stubs/defaultqualinstub/Main.java @@ -5,4 +5,4 @@ * @compile -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker -Astubs=defaults.astub pck/Defaults.java -AstubWarnIfNotFound -Werror */ -class Main {} +public class Main {} diff --git a/checker/jtreg/stubs/defaultqualinstub/pck/Defaults.java b/checker/jtreg/stubs/defaultqualinstub/pck/Defaults.java index 442574d66a..32e338c728 100644 --- a/checker/jtreg/stubs/defaultqualinstub/pck/Defaults.java +++ b/checker/jtreg/stubs/defaultqualinstub/pck/Defaults.java @@ -1,6 +1,6 @@ package pck; -class Defaults { +public class Defaults { Object o; void test() { diff --git a/checker/jtreg/stubs/general/Driver.java b/checker/jtreg/stubs/general/Driver.java index ebf512d9f4..f5335fcf47 100644 --- a/checker/jtreg/stubs/general/Driver.java +++ b/checker/jtreg/stubs/general/Driver.java @@ -5,7 +5,7 @@ * @compile -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker -Astubs=MyStub.astub Driver.java -AstubWarnIfNotFound -Werror */ -class Driver { +public class Driver { void test() { Object o = null; String v = String.valueOf(o); diff --git a/checker/jtreg/stubs/general/Driver2.java b/checker/jtreg/stubs/general/Driver2.java new file mode 100644 index 0000000000..0379fd2169 --- /dev/null +++ b/checker/jtreg/stubs/general/Driver2.java @@ -0,0 +1,9 @@ +/* + * @test + * @summary Test that a stub file can have no package, but have an annotation on the class. + * @compile -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker -Astubs=NoPackage.astub Driver2.java -Werror + */ + +public class Driver2 { + void test() {} +} diff --git a/checker/jtreg/stubs/general/NoPackage.astub b/checker/jtreg/stubs/general/NoPackage.astub new file mode 100644 index 0000000000..daf1391c3b --- /dev/null +++ b/checker/jtreg/stubs/general/NoPackage.astub @@ -0,0 +1,3 @@ +// No package statement. +@SuppressWarnings("") // Any annotation. +class Test {} diff --git a/checker/jtreg/stubs/issue1356/Main.java b/checker/jtreg/stubs/issue1356/Main.java index 37ecab1871..551a004929 100644 --- a/checker/jtreg/stubs/issue1356/Main.java +++ b/checker/jtreg/stubs/issue1356/Main.java @@ -7,4 +7,4 @@ * @compile -XDrawDiagnostics -processor org.checkerframework.checker.regex.RegexChecker mypackage/UseMyClass.java */ -class Main {} +public class Main {} diff --git a/checker/jtreg/stubs/issue1496/ClassAnnotation.astub b/checker/jtreg/stubs/issue1496/ClassAnnotation.astub index a4c77f2266..65bb657f5d 100644 --- a/checker/jtreg/stubs/issue1496/ClassAnnotation.astub +++ b/checker/jtreg/stubs/issue1496/ClassAnnotation.astub @@ -1,10 +1,10 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.DefaultQualifier; -// This checks that fully-qualified class literals in annotations are properly handled by the StubParser. +// This checks that fully-qualified class literals in annotations are properly handled by the AnnotationFileParser. @DefaultQualifier(org.checkerframework.checker.nullness.qual.NonNull.class) package java.lang; -// This checks that simply-named class literals in annotations are properly handled by the StubParser. +// This checks that simply-named class literals in annotations are properly handled by the AnnotationFileParser. @DefaultQualifier(Nullable.class) package java.util; diff --git a/checker/jtreg/stubs/issue1542/UsesIntRange.java b/checker/jtreg/stubs/issue1542/UsesIntRange.java index f5a2536314..d5bfaa0152 100644 --- a/checker/jtreg/stubs/issue1542/UsesIntRange.java +++ b/checker/jtreg/stubs/issue1542/UsesIntRange.java @@ -2,7 +2,7 @@ import org.checkerframework.common.value.qual.IntRange; -class UsesIntRange { +public class UsesIntRange { void do_things() { @IntRange(from = 3, to = 20000) int x = NeedsIntRange.range(true); @IntRange(from = 3L, to = 20000) int y = NeedsIntRange.range(true); diff --git a/checker/jtreg/stubs/issue1585/Main.java b/checker/jtreg/stubs/issue1585/Main.java index be8db878f8..3e4c7086ff 100644 --- a/checker/jtreg/stubs/issue1585/Main.java +++ b/checker/jtreg/stubs/issue1585/Main.java @@ -5,8 +5,8 @@ * * ParseError.out and UnknownField.out contain expected warnings. * - * @compile -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker -Astubs=UnknownField.astub Main.java - * @compile -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker -Astubs=ParseError.astub Main.java + * @compile/ref=UnknownField.out -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker -Astubs=UnknownField.astub -Anomsgtext Main.java + * @compile/ref=ParseError.out -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker -Astubs=ParseError.astub -Anomsgtext Main.java */ package issue1585; diff --git a/checker/jtreg/stubs/issue1585/ParseError.out b/checker/jtreg/stubs/issue1585/ParseError.out index 30d3fed09b..fd6157b14a 100644 --- a/checker/jtreg/stubs/issue1585/ParseError.out +++ b/checker/jtreg/stubs/issue1585/ParseError.out @@ -1,9 +1,2 @@ -warning: StubParser: exception from StubParser.parse for file checker/jtreg/stubs/issue1585/ParseErrors.astub. Encountered problems: Encountered unexpected token: "{" "{" - at line 3, column 17. - - Was expecting one of: - - "," - ">" - "extends" +- compiler.warn.proc.messager: ParseError.astub: (line 3,col 12) Parse error. Found "{", expected one of "," ">" "extends" 1 warning diff --git a/checker/jtreg/stubs/issue1585/UnknownField.out b/checker/jtreg/stubs/issue1585/UnknownField.out index 8df7a68a9f..684359c694 100644 --- a/checker/jtreg/stubs/issue1585/UnknownField.out +++ b/checker/jtreg/stubs/issue1585/UnknownField.out @@ -1,3 +1,3 @@ -warning: StubParser: Field not found: NonNull -warning: StubParser: Annotation expression, NonNull, could not be processed for annotation: @DefaultQualifier(NonNull). +- compiler.warn.proc.messager: UnknownField.astub:(line 5,col 19): Field NonNull [class com.github.javaparser.ast.expr.NameExpr] not found in getValueOfExpressionInAnnotation(value, NonNull [class com.github.javaparser.ast.expr.NameExpr], DECLARED) +- compiler.warn.proc.messager: UnknownField.astub:(line 5,col 19): For annotation @DefaultQualifier(NonNull), could not add value NonNull because null expression for name=value expr=NonNull, valueKind=DECLARED 2 warnings diff --git a/checker/jtreg/stubs/issue2059/AnnoNotFound.out b/checker/jtreg/stubs/issue2059/AnnoNotFound.out index 1dbde8e859..51cc8d8c9e 100644 --- a/checker/jtreg/stubs/issue2059/AnnoNotFound.out +++ b/checker/jtreg/stubs/issue2059/AnnoNotFound.out @@ -1,2 +1,2 @@ -- compiler.warn.proc.messager: StubParser: Unknown annotation: @Nullable +- compiler.warn.proc.messager: AnnoNotFound.astub:(line 8,col 3): Unknown annotation @Nullable 1 warning diff --git a/checker/jtreg/stubs/issue2059/Main.java b/checker/jtreg/stubs/issue2059/Main.java index f82487eb30..acda5b2abf 100644 --- a/checker/jtreg/stubs/issue2059/Main.java +++ b/checker/jtreg/stubs/issue2059/Main.java @@ -2,7 +2,7 @@ * @test * @summary Test case for Issue 2059 https://github.com/typetools/checker-framework/issues/2059 * - * @compile/ref=AnnoNotFound.out -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker -AstubWarnIfNotFound -Astubs=AnnoNotFound.astub Main.java + * @compile/ref=AnnoNotFound.out -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker -AstubWarnIfNotFound -Astubs=AnnoNotFound.astub -Anomsgtext Main.java */ package issue2059; diff --git a/checker/jtreg/stubs/issue2147/EnumStubTest.java b/checker/jtreg/stubs/issue2147/EnumStubTest.java index ac02044609..79c6974beb 100644 --- a/checker/jtreg/stubs/issue2147/EnumStubTest.java +++ b/checker/jtreg/stubs/issue2147/EnumStubTest.java @@ -10,7 +10,7 @@ import org.checkerframework.checker.tainting.qual.*; -class EnumStubTest { +public class EnumStubTest { void test() { requireEnum(SampleEnum.FIRST); requireEnum(SampleEnum.SECOND); diff --git a/checker/jtreg/stubs/sample/Sample.java b/checker/jtreg/stubs/sample/Sample.java index 82fb9d6028..d0254b68c5 100644 --- a/checker/jtreg/stubs/sample/Sample.java +++ b/checker/jtreg/stubs/sample/Sample.java @@ -5,7 +5,7 @@ * @compile -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker -Astubs=sample.astub Sample.java -AstubWarnIfNotFound -Werror */ -class Sample { +public class Sample { void test() { Object o = null; String v = String.valueOf(o); diff --git a/checker/jtreg/stubs/wildcards/NonN.java b/checker/jtreg/stubs/wildcards/NonN.java index 92ad4f14f3..3da7420ea4 100644 --- a/checker/jtreg/stubs/wildcards/NonN.java +++ b/checker/jtreg/stubs/wildcards/NonN.java @@ -1 +1 @@ -class NonN {} +public class NonN {} diff --git a/checker/jtreg/stubs/wildcards/Wildcards.java b/checker/jtreg/stubs/wildcards/Wildcards.java index a87cb169f4..e02d17869d 100644 --- a/checker/jtreg/stubs/wildcards/Wildcards.java +++ b/checker/jtreg/stubs/wildcards/Wildcards.java @@ -6,7 +6,7 @@ * @compile -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker -Astubs=NonN.astub Wildcards.java -AstubWarnIfNotFound -Werror */ -class Wildcards { +public class Wildcards { NonN f = new NonN(); class LocalNonN {} diff --git a/checker/jtreg/unboundedWildcards/issue1275/Crash.java b/checker/jtreg/unboundedWildcards/issue1275/Crash.java index 22c4742ce3..2f3fddf281 100644 --- a/checker/jtreg/unboundedWildcards/issue1275/Crash.java +++ b/checker/jtreg/unboundedWildcards/issue1275/Crash.java @@ -6,7 +6,7 @@ * @compile -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker -Anomsgtext Lib.java * @compile -XDrawDiagnostics -processor org.checkerframework.checker.nullness.NullnessChecker -Anomsgtext Crash.java */ -class Crash { +public class Crash { void crash(Sub o) { Sub.SubInner x = o.a().b().b(); o.a().b().b().c(); diff --git a/checker/jtreg/unboundedWildcards/issue1427/T.java b/checker/jtreg/unboundedWildcards/issue1427/T.java index e084bcbef8..5fcad3ecdc 100644 --- a/checker/jtreg/unboundedWildcards/issue1427/T.java +++ b/checker/jtreg/unboundedWildcards/issue1427/T.java @@ -6,7 +6,7 @@ * @compile B.java * @compile -XDrawDiagnostics -processor org.checkerframework.checker.tainting.TaintingChecker T.java */ -class Test { +public class T { { Three.c().g().f().build(); } diff --git a/checker/jtreg/unboundedWildcards/issue1428/T.java b/checker/jtreg/unboundedWildcards/issue1428/T.java index d29421ab7e..e85b0e55fb 100644 --- a/checker/jtreg/unboundedWildcards/issue1428/T.java +++ b/checker/jtreg/unboundedWildcards/issue1428/T.java @@ -10,7 +10,7 @@ import java.util.Collections; import java.util.List; -class T { +public class T { public List> f(B b) { return true ? Collections.>emptyList() : b.getItems(); } diff --git a/checker/jtregJdk11/Jdk11Release8.java b/checker/jtregJdk11/Jdk11Release8.java index ef05dc68fe..ec5d530abd 100644 --- a/checker/jtregJdk11/Jdk11Release8.java +++ b/checker/jtregJdk11/Jdk11Release8.java @@ -5,4 +5,4 @@ * @compile -XDrawDiagnostics -processor org.checkerframework.checker.interning.InterningChecker Jdk11Release8.java --release 8 */ -class Jdk11Release8 {} +public class Jdk11Release8 {} diff --git a/checker/src/main/java/org/checkerframework/checker/calledmethods/CalledMethodsAnnotatedTypeFactory.java b/checker/src/main/java/org/checkerframework/checker/calledmethods/CalledMethodsAnnotatedTypeFactory.java index 09e7727856..60ab33394f 100644 --- a/checker/src/main/java/org/checkerframework/checker/calledmethods/CalledMethodsAnnotatedTypeFactory.java +++ b/checker/src/main/java/org/checkerframework/checker/calledmethods/CalledMethodsAnnotatedTypeFactory.java @@ -83,13 +83,13 @@ public CalledMethodsAnnotatedTypeFactory(BaseTypeChecker checker) { "java.util.Collections", "singletonList", 1, getProcessingEnv()); // Lombok generates @CalledMethods annotations using an old package name, // so we maintain it as an alias. - addAliasedAnnotation( + addAliasedTypeAnnotation( "org.checkerframework.checker.builder.qual.CalledMethods", CalledMethods.class, true); // Lombok also generates an @NotCalledMethods annotation, which we have no support for. We // therefore treat it as top. - addAliasedAnnotation( + addAliasedTypeAnnotation( "org.checkerframework.checker.builder.qual.NotCalledMethods", this.top); this.postInit(); } @@ -100,7 +100,7 @@ public CalledMethodsAnnotatedTypeFactory(BaseTypeChecker checker) { * arguments. Throws a UserError if the user included an unsupported framework in the list of * frameworks to be disabled. * - * @param disabledFrameworks the disabled builder frameworks. + * @param disabledFrameworks the disabled builder frameworks */ private void enableFrameworks(String[] disabledFrameworks) { boolean enableAutoValueSupport = true; diff --git a/checker/src/main/java/org/checkerframework/checker/calledmethods/CalledMethodsChecker.java b/checker/src/main/java/org/checkerframework/checker/calledmethods/CalledMethodsChecker.java index 64d0286688..7633c1381b 100644 --- a/checker/src/main/java/org/checkerframework/checker/calledmethods/CalledMethodsChecker.java +++ b/checker/src/main/java/org/checkerframework/checker/calledmethods/CalledMethodsChecker.java @@ -1,6 +1,7 @@ package org.checkerframework.checker.calledmethods; import java.util.LinkedHashSet; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.common.accumulation.AccumulationChecker; import org.checkerframework.common.basetype.BaseTypeChecker; import org.checkerframework.common.returnsreceiver.ReturnsReceiverChecker; @@ -50,20 +51,53 @@ public class CalledMethodsChecker extends AccumulationChecker { */ public static final String USE_VALUE_CHECKER = "useValueChecker"; + /** + * Some use cases for the Called Methods Checker do not involve checking fluent APIs, and in + * those cases disabling the Returns Receiver Checker using this flag will make the Called + * Methods Checker run much faster. + */ + public static final String DISABLE_RETURNS_RECEIVER = "disableReturnsReceiver"; + /** * The number of calls to build frameworks supported by this invocation. Incremented only if the * {@link #COUNT_FRAMEWORK_BUILD_CALLS} option was supplied. */ int numBuildCalls = 0; + /** Never access this boolean directly. Call {@link #isReturnsReceiverDisabled()} instead. */ + private @MonotonicNonNull Boolean returnsReceiverDisabled = null; + + /** + * Was the Returns Receiver Checker disabled on the command line? + * + * @return whether the -AdisableReturnsReceiver option was specified on the command line + */ + private boolean isReturnsReceiverDisabled() { + if (returnsReceiverDisabled == null) { + // BaseTypeChecker#hasOption calls getImmediateSubcheckerClasses (so that all + // subcheckers' options are considered), so the processingEnvironment must be checked + // for options directly, because this method is called from there. + returnsReceiverDisabled = + this.processingEnv.getOptions().containsKey(DISABLE_RETURNS_RECEIVER) + || this.processingEnv + .getOptions() + .containsKey( + this.getClass().getSimpleName() + + "_" + + DISABLE_RETURNS_RECEIVER); + } + return returnsReceiverDisabled; + } + @Override protected LinkedHashSet> getImmediateSubcheckerClasses() { LinkedHashSet> checkers = super.getImmediateSubcheckerClasses(); - checkers.add(ReturnsReceiverChecker.class); - + if (!isReturnsReceiverDisabled()) { + checkers.add(ReturnsReceiverChecker.class); + } // BaseTypeChecker#hasOption calls this method (so that all subcheckers' options are - // considered), so the processingEnvironment must be checked for the option directly. + // considered), so the processingEnvironment must be checked for options directly. if (this.processingEnv.getOptions().containsKey(USE_VALUE_CHECKER) || this.processingEnv .getOptions() @@ -73,6 +107,20 @@ protected LinkedHashSet> getImmediateSubchecker return checkers; } + /** + * Check whether the given alias analysis is enabled by this particular accumulation checker. + * + * @param aliasAnalysis the analysis to check + * @return true iff the analysis is enabled + */ + @Override + public boolean isEnabled(AliasAnalysis aliasAnalysis) { + if (aliasAnalysis == AliasAnalysis.RETURNS_RECEIVER) { + return !isReturnsReceiverDisabled(); + } + return super.isEnabled(aliasAnalysis); + } + @Override public void typeProcessingOver() { if (getBooleanOption(COUNT_FRAMEWORK_BUILD_CALLS)) { diff --git a/checker/src/main/java/org/checkerframework/checker/calledmethods/builder/AutoValueSupport.java b/checker/src/main/java/org/checkerframework/checker/calledmethods/builder/AutoValueSupport.java index 304abaac24..6a6a87a5ed 100644 --- a/checker/src/main/java/org/checkerframework/checker/calledmethods/builder/AutoValueSupport.java +++ b/checker/src/main/java/org/checkerframework/checker/calledmethods/builder/AutoValueSupport.java @@ -1,9 +1,6 @@ package org.checkerframework.checker.calledmethods.builder; import com.sun.source.tree.NewClassTree; -import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.code.Types; -import com.sun.tools.javac.processing.JavacProcessingEnvironment; import java.beans.Introspector; import java.util.ArrayList; import java.util.HashSet; @@ -403,7 +400,8 @@ private boolean isAutoValueBuilderSetter(ExecutableElement method, TypeElement b * @return list of all abstract methods */ public List getAllAbstractMethods(TypeElement classElement) { - List supertypes = getAllSupertypes((Symbol) classElement); + List supertypes = + ElementUtils.getAllSupertypes(classElement, atypeFactory.getProcessingEnv()); List abstractMethods = new ArrayList<>(); Set overriddenMethods = new HashSet<>(); for (Element t : supertypes) { @@ -416,7 +414,7 @@ public List getAllAbstractMethods(TypeElement classElement) { continue; } if (modifiers.contains(Modifier.ABSTRACT)) { - // Make sure it's not overridden. This only works because #getAllSupertypes + // Make sure it's not overridden. This only works because ElementUtils#closure // returns results in a particular order. if (!overriddenMethods.contains(member)) { abstractMethods.add((ExecutableElement) member); @@ -446,19 +444,4 @@ private String getAutoValuePackageName() { String com = "com"; return com + "." + "google.auto.value"; } - - /** - * Get all the supertypes of a given class, including that class. - * - * @param symbol symbol for a class - * @return list including the class and all its supertypes, with a guarantee that supertypes - * (i.e. those that appear in extends clauses) appear before indirect supertypes - */ - private List getAllSupertypes(Symbol symbol) { - Types types = - Types.instance( - ((JavacProcessingEnvironment) atypeFactory.getProcessingEnv()) - .getContext()); - return types.closure(symbol.type).stream().map(t -> t.tsym).collect(Collectors.toList()); - } } diff --git a/checker/src/main/java/org/checkerframework/checker/fenum/FenumAnnotatedTypeFactory.java b/checker/src/main/java/org/checkerframework/checker/fenum/FenumAnnotatedTypeFactory.java index 30b1a9a7a4..f7cf8f5846 100644 --- a/checker/src/main/java/org/checkerframework/checker/fenum/FenumAnnotatedTypeFactory.java +++ b/checker/src/main/java/org/checkerframework/checker/fenum/FenumAnnotatedTypeFactory.java @@ -98,7 +98,7 @@ public QualifierHierarchy createQualifierHierarchy() { return new FenumQualifierHierarchy(getSupportedTypeQualifiers(), elements); } - /** Fenum qualifier hierarchy */ + /** Fenum qualifier hierarchy. */ protected class FenumQualifierHierarchy extends MostlyNoElementQualifierHierarchy { /** QualifierKind for {@link Fenum} qualifier. */ diff --git a/checker/src/main/java/org/checkerframework/checker/formatter/FormatUtil.java b/checker/src/main/java/org/checkerframework/checker/formatter/FormatUtil.java index 4102ef10fc..608e07b551 100644 --- a/checker/src/main/java/org/checkerframework/checker/formatter/FormatUtil.java +++ b/checker/src/main/java/org/checkerframework/checker/formatter/FormatUtil.java @@ -95,7 +95,8 @@ public static void tryFormatSatisfiability(String format) throws IllegalFormatEx @SuppressWarnings({ "unused", // called for side effect, to see if it throws an exception "nullness:argument.type.incompatible" // it's not documented, but String.format permits - // a null array, which it treats as matching any format string + // a null array, which it treats as matching any format string (null is supplied to each + // format specifier). }) String unused = String.format(format, (Object[]) null); } diff --git a/checker/src/main/java/org/checkerframework/checker/formatter/FormatterAnnotatedTypeFactory.java b/checker/src/main/java/org/checkerframework/checker/formatter/FormatterAnnotatedTypeFactory.java index d2d35862a3..e6665abb01 100644 --- a/checker/src/main/java/org/checkerframework/checker/formatter/FormatterAnnotatedTypeFactory.java +++ b/checker/src/main/java/org/checkerframework/checker/formatter/FormatterAnnotatedTypeFactory.java @@ -3,6 +3,7 @@ import com.sun.source.tree.LiteralTree; import com.sun.source.tree.Tree; import java.util.IllegalFormatException; +import java.util.Set; import javax.lang.model.element.AnnotationMirror; import org.checkerframework.checker.formatter.qual.ConversionCategory; import org.checkerframework.checker.formatter.qual.Format; @@ -13,6 +14,8 @@ import org.checkerframework.checker.signature.qual.CanonicalName; import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.common.basetype.BaseTypeChecker; +import org.checkerframework.common.wholeprograminference.WholeProgramInference; +import org.checkerframework.common.wholeprograminference.WholeProgramInferenceScenes; import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.MostlyNoElementQualifierHierarchy; @@ -23,6 +26,9 @@ import org.checkerframework.javacutil.AnnotationBuilder; import org.checkerframework.javacutil.AnnotationUtils; import org.checkerframework.javacutil.BugInCF; +import scenelib.annotations.Annotation; +import scenelib.annotations.el.AField; +import scenelib.annotations.el.AMethod; /** * Adds {@link Format} to the type of tree, if it is a {@code String} or {@code char} literal that @@ -56,6 +62,11 @@ public class FormatterAnnotatedTypeFactory extends BaseAnnotatedTypeFactory { public FormatterAnnotatedTypeFactory(BaseTypeChecker checker) { super(checker); + addAliasedDeclAnnotation( + com.google.errorprone.annotations.FormatMethod.class, + FormatMethod.class, + FORMATMETHOD); + this.postInit(); } @@ -69,7 +80,18 @@ protected TreeAnnotator createTreeAnnotator() { return new ListTreeAnnotator(super.createTreeAnnotator(), new FormatterTreeAnnotator(this)); } + @Override + protected WholeProgramInference createWholeProgramInference() { + return new FormatterWholeProgramInferenceScenes(this); + } + + /** The tree annotator for the Format String Checker. */ private class FormatterTreeAnnotator extends TreeAnnotator { + /** + * Create the tree annotator for the Format String Checker. + * + * @param atypeFactory the Format String Checker type factory + */ public FormatterTreeAnnotator(AnnotatedTypeFactory atypeFactory) { super(atypeFactory); } @@ -253,4 +275,54 @@ protected AnnotationMirror greatestLowerBoundWithElements( return FORMATBOTTOM; } } + + /** A WholeProgramInferenceScenes customized for the Format String Checker. */ + public static class FormatterWholeProgramInferenceScenes extends WholeProgramInferenceScenes { + + /** + * Create a FormatterWholeProgramInferenceScenes. + * + * @param atypeFactory the associated type factory + */ + public FormatterWholeProgramInferenceScenes(AnnotatedTypeFactory atypeFactory) { + super(atypeFactory); + } + + /** + * {@inheritDoc} + * + *

If a method is annotated with {@code @FormatMethod}, remove any {@code @Format} + * annotation from its first argument. + */ + @Override + public void prepareMethodForWriting(AMethod method) { + if (hasFormatMethodAnno(method)) { + AField param = method.parameters.get(0); + if (param != null) { + Set paramTypeAnnos = param.type.tlAnnotationsHere; + paramTypeAnnos.removeIf( + a -> + a.def.name.equals( + "org.checkerframework.checker.formatter.qual.Format")); + } + } + } + + /** + * Returns true if the method has a {@code @FormatMethod} annotation. + * + * @param method a method + * @return true if the method has a {@code @FormatMethod} annotation. + */ + private boolean hasFormatMethodAnno(AMethod method) { + for (Annotation anno : method.tlAnnotationsHere) { + String annoName = anno.def.name; + if (annoName.equals("org.checkerframework.checker.formatter.qual.FormatMethod") + || anno.def.name.equals("com.google.errorprone.annotations.FormatMethod")) { + return true; + } + } + return false; + } + } } diff --git a/checker/src/main/java/org/checkerframework/checker/formatter/FormatterTreeUtil.java b/checker/src/main/java/org/checkerframework/checker/formatter/FormatterTreeUtil.java index 67ee5407fe..841976370f 100644 --- a/checker/src/main/java/org/checkerframework/checker/formatter/FormatterTreeUtil.java +++ b/checker/src/main/java/org/checkerframework/checker/formatter/FormatterTreeUtil.java @@ -11,14 +11,10 @@ import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; import javax.lang.model.type.ArrayType; -import javax.lang.model.type.DeclaredType; import javax.lang.model.type.NullType; -import javax.lang.model.type.PrimitiveType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.SimpleElementVisitor8; import javax.lang.model.util.SimpleTypeVisitor7; import org.checkerframework.checker.compilermsgs.qual.CompilerMessageKey; import org.checkerframework.checker.formatter.qual.ConversionCategory; @@ -26,7 +22,6 @@ import org.checkerframework.checker.formatter.qual.FormatMethod; import org.checkerframework.checker.formatter.qual.InvalidFormat; import org.checkerframework.checker.formatter.qual.ReturnsFormat; -import org.checkerframework.checker.signature.qual.ClassGetName; import org.checkerframework.common.basetype.BaseTypeChecker; import org.checkerframework.dataflow.cfg.node.ArrayCreationNode; import org.checkerframework.dataflow.cfg.node.FieldAccessNode; @@ -37,6 +32,7 @@ import org.checkerframework.javacutil.AnnotationBuilder; import org.checkerframework.javacutil.AnnotationUtils; import org.checkerframework.javacutil.TreeUtils; +import org.checkerframework.javacutil.TypesUtils; /** * This class provides a collection of utilities to ease working with syntax trees that have @@ -62,7 +58,7 @@ public FormatterTreeUtil(BaseTypeChecker checker) { } /** Describes the ways a format method may be invoked. */ - public enum InvocationType { + public static enum InvocationType { /** * The parameters are passed as varargs. For example: * @@ -131,25 +127,24 @@ public boolean isAsFormatCall(MethodInvocationNode node, AnnotatedTypeFactory at private ConversionCategory[] asFormatCallCategoriesLowLevel(MethodInvocationNode node) { Node vararg = node.getArgument(1); - if (vararg instanceof ArrayCreationNode) { - List convs = ((ArrayCreationNode) vararg).getInitializers(); - ConversionCategory[] res = new ConversionCategory[convs.size()]; - for (int i = 0; i < convs.size(); ++i) { - Node conv = convs.get(i); - if (conv instanceof FieldAccessNode) { - Class clazz = - typeMirrorToClass(((FieldAccessNode) conv).getType()); - if (clazz == ConversionCategory.class) { - res[i] = - ConversionCategory.valueOf(((FieldAccessNode) conv).getFieldName()); - continue; /* avoid returning null */ - } + if (!(vararg instanceof ArrayCreationNode)) { + return null; + } + List convs = ((ArrayCreationNode) vararg).getInitializers(); + ConversionCategory[] res = new ConversionCategory[convs.size()]; + for (int i = 0; i < convs.size(); ++i) { + Node conv = convs.get(i); + if (conv instanceof FieldAccessNode) { + Class clazz = + TypesUtils.getClassFromType(((FieldAccessNode) conv).getType()); + if (clazz == ConversionCategory.class) { + res[i] = ConversionCategory.valueOf(((FieldAccessNode) conv).getFieldName()); + continue; /* avoid returning null */ } - return null; } - return res; + return null; } - return null; + return res; } public Result asFormatCallCategories(MethodInvocationNode node) { @@ -164,9 +159,15 @@ public boolean isFormatCall(MethodInvocationTree node, AnnotatedTypeFactory atyp return anno != null; } - /** Returns true if the given ExpressionTree has type java.util.Locale. */ + /** + * Returns true if the given ExpressionTree has type java.util.Locale. + * + * @param e an expression + * @param atypeFactory the type factory + * @return true if the given ExpressionTree has type java.util.Locale + */ public static boolean isLocale(ExpressionTree e, AnnotatedTypeFactory atypeFactory) { - return (typeMirrorToClass(atypeFactory.getAnnotatedType(e).getUnderlyingType()) + return (TypesUtils.getClassFromType(atypeFactory.getAnnotatedType(e).getUnderlyingType()) == Locale.class); } @@ -293,45 +294,53 @@ public final ConversionCategory[] getFormatCategories() { } /** - * Returns the type of the function's parameters. Use {@link - * #isValidParameter(ConversionCategory, TypeMirror) isValidParameter} and {@link - * #isParameterNull(TypeMirror) isParameterNull} to work with the result. + * Returns the types of the arguments to the call. Use {@link #isValidArgument} and {@link + * #isArgumentNull} to work with the result. + * + * @return the types of the arguments to the call */ - public final Result[] getParamTypes() { + public final Result[] getArgTypes() { // One to suppress warning in javac, the other to suppress warning in Eclipse... @SuppressWarnings({"rawtypes", "unchecked"}) Result[] res = new Result[args.size()]; for (int i = 0; i < res.length; ++i) { ExpressionTree arg = args.get(i); - TypeMirror argType = atypeFactory.getAnnotatedType(arg).getUnderlyingType(); + TypeMirror argType; + if (TreeUtils.isNullExpression(arg)) { + argType = atypeFactory.getProcessingEnv().getTypeUtils().getNullType(); + } else { + argType = atypeFactory.getAnnotatedType(arg).getUnderlyingType(); + } res[i] = new Result<>(argType, arg); } return res; } /** - * Checks if the type of a parameter returned from {@link #getParamTypes()} is valid for the + * Checks if the type of an argument returned from {@link #getArgTypes()} is valid for the * passed ConversionCategory. + * + * @param formatCat a format specifier + * @param argType an argument type + * @return true if the argument can be passed to the format specifier */ - public final boolean isValidParameter(ConversionCategory formatCat, TypeMirror paramType) { - Class type = typeMirrorToClass(paramType); - if (type == null) { - // we did not recognize the parameter type - return false; - } - for (Class c : formatCat.types) { - if (c.isAssignableFrom(type)) { - return true; - } + public final boolean isValidArgument(ConversionCategory formatCat, TypeMirror argType) { + if (argType.getKind() == TypeKind.NULL || isArgumentNull(argType)) { + return true; } - return false; + Class type = TypesUtils.getClassFromType(argType); + return formatCat.isAssignableFrom(type); } /** - * Checks if the parameter returned from {@link #getParamTypes()} is a {@code null} - * expression. + * Checks if the argument returned from {@link #getArgTypes()} is a {@code null} expression. + * + * @param type a type + * @return true if the argument is a {@code null} expression */ - public final boolean isParameterNull(TypeMirror type) { + public final boolean isArgumentNull(TypeMirror type) { + // TODO: Just check whether it is the VOID TypeMirror. + // is it the null literal return type.accept( new SimpleTypeVisitor7>() { @@ -385,13 +394,14 @@ public AnnotationMirror exceptionToInvalidFormatAnnotation(IllegalFormatExceptio } /** - * Takes an invalid formatter string and, returns a syntax trees element that represents a - * {@link InvalidFormat} annotation with the invalid formatter string as value. + * Creates an {@link InvalidFormat} annotation with the given string as its value. + * + * @param invalidFormatString an invalid formatter string + * @return an {@link InvalidFormat} annotation with the given string as its value */ // package-private AnnotationMirror stringToInvalidFormatAnnotation(String invalidFormatString) { - AnnotationBuilder builder = - new AnnotationBuilder(processingEnv, InvalidFormat.class.getCanonicalName()); + AnnotationBuilder builder = new AnnotationBuilder(processingEnv, InvalidFormat.class); builder.setValue("value", invalidFormatString); return builder.build(); } @@ -405,12 +415,13 @@ public String invalidFormatAnnotationToErrorMessage(AnnotationMirror anno) { } /** - * Takes a list of ConversionCategory elements, and returns a syntax tree element that - * represents a {@link Format} annotation with the list as value. + * Creates a {@code @}{@link Format} annotation with the given list as its value. + * + * @param args conversion categories for the {@code @Format} annotation + * @return a {@code @}{@link Format} annotation with the given list as its value */ public AnnotationMirror categoriesToFormatAnnotation(ConversionCategory[] args) { - AnnotationBuilder builder = - new AnnotationBuilder(processingEnv, Format.class.getCanonicalName()); + AnnotationBuilder builder = new AnnotationBuilder(processingEnv, Format.class); builder.setValue("value", args); return builder.build(); } @@ -425,71 +436,4 @@ public ConversionCategory[] formatAnnotationToCategories(AnnotationMirror anno) anno, "value", ConversionCategory.class, false); return list.toArray(new ConversionCategory[] {}); } - - /** Converts a TypeMirror to a Class. */ - private static class TypeMirrorToClassVisitor - extends SimpleTypeVisitor7, Class> { - @Override - public Class visitPrimitive(PrimitiveType t, Class v) { - switch (t.getKind()) { - case BOOLEAN: - return Boolean.class; - case BYTE: - return Byte.class; - case CHAR: - return Character.class; - case SHORT: - return Short.class; - case INT: - return Integer.class; - case LONG: - return Long.class; - case FLOAT: - return Float.class; - case DOUBLE: - return Double.class; - default: - return null; - } - } - - @Override - public Class visitDeclared(DeclaredType dt, Class v) { - return dt.asElement() - .accept( - new SimpleElementVisitor8, Class>() { - @Override - public Class visitType( - TypeElement e, Class v) { - try { - @SuppressWarnings( - "signature" // BUG: need to compute a @ClassGetName, - // but this code computes a @CanonicalNameOrEmpty. They are - // different for inner classes. - ) - @ClassGetName String cname = e.getQualifiedName().toString(); - return Class.forName(cname); - } catch (ClassNotFoundException e1) { - return null; // the lookup should work for all - // the classes we care about - } - } - }, - Void.TYPE); - } - } - - /** The singleton instance of TypeMirrorToClassVisitor. */ - private static TypeMirrorToClassVisitor typeMirrorToClassVisitor = - new TypeMirrorToClassVisitor(); - - /** - * Converts a TypeMirror to a Class. - * - * @param type a TypeMirror - * @return the class corresponding to the argument - */ - private static final Class typeMirrorToClass(final TypeMirror type) { - return type.accept(typeMirrorToClassVisitor, Void.TYPE); - } } diff --git a/checker/src/main/java/org/checkerframework/checker/formatter/FormatterVisitor.java b/checker/src/main/java/org/checkerframework/checker/formatter/FormatterVisitor.java index 13148a7160..eac70eb853 100644 --- a/checker/src/main/java/org/checkerframework/checker/formatter/FormatterVisitor.java +++ b/checker/src/main/java/org/checkerframework/checker/formatter/FormatterVisitor.java @@ -10,6 +10,7 @@ import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import org.checkerframework.checker.compilermsgs.qual.CompilerMessageKey; import org.checkerframework.checker.formatter.FormatterTreeUtil.FormatCall; @@ -60,48 +61,52 @@ public Void visitMethodInvocation(MethodInvocationTree node, Void p) { ConversionCategory[] formatCats = fc.getFormatCategories(); switch (invc.value()) { case VARARG: - Result[] paramTypes = fc.getParamTypes(); - int paraml = paramTypes.length; + Result[] argTypes = fc.getArgTypes(); + int argl = argTypes.length; int formatl = formatCats.length; - if (paraml < formatl) { + if (argl < formatl) { // For assignments, format.missing.arguments is issued // from commonAssignmentCheck. // II.1 - tu.failure(invc, "format.missing.arguments", formatl, paraml); + tu.failure(invc, "format.missing.arguments", formatl, argl); } else { - if (paraml > formatl) { + if (argl > formatl) { // II.2 - tu.warning(invc, "format.excess.arguments", formatl, paraml); + tu.warning(invc, "format.excess.arguments", formatl, argl); } for (int i = 0; i < formatl; ++i) { ConversionCategory formatCat = formatCats[i]; - Result param = paramTypes[i]; - TypeMirror paramType = param.value(); + Result arg = argTypes[i]; + TypeMirror argType = arg.value(); switch (formatCat) { case UNUSED: // I.2 - tu.warning(param, "format.argument.unused", " " + (1 + i)); + tu.warning(arg, "format.argument.unused", " " + (1 + i)); break; case NULL: // I.3 - tu.failure(param, "format.specifier.null", " " + (1 + i)); + if (argType.getKind() == TypeKind.NULL) { + tu.warning(arg, "format.specifier.null", " " + (1 + i)); + } else { + tu.failure(arg, "format.specifier.null", " " + (1 + i)); + } break; case GENERAL: break; default: - if (!fc.isValidParameter(formatCat, paramType)) { + if (!fc.isValidArgument(formatCat, argType)) { // II.3 ExecutableElement method = TreeUtils.elementFromUse(node); CharSequence methodName = ElementUtils.getSimpleNameOrDescription(method); tu.failure( - param, + arg, "argument.type.incompatible", - "", // parameter name is not useful + "in varargs position", methodName, - paramType, + argType, formatCat); } break; @@ -109,21 +114,30 @@ public Void visitMethodInvocation(MethodInvocationTree node, Void p) { } } break; - case NULLARRAY: - /* continue */ case ARRAY: + // III + if (!isWrappedFormatCall(fc, enclosingMethod)) { + tu.warning(invc, "format.indirect.arguments"); + } + // TODO: If it is explict array construction, such as "new Object[] { + // ... }", then we could treat it like the VARARGS case, analyzing each + // argument. "new array" is probably rare, in the varargs position. + // fall through + case NULLARRAY: for (ConversionCategory cat : formatCats) { if (cat == ConversionCategory.NULL) { // I.3 - tu.failure(invc, "format.specifier.null", ""); + if (invc.value() == FormatterTreeUtil.InvocationType.NULLARRAY) { + tu.warning(invc, "format.specifier.null", ""); + } else { + tu.failure(invc, "format.specifier.null", ""); + } } if (cat == ConversionCategory.UNUSED) { // I.2 tu.warning(invc, "format.argument.unused", ""); } } - // III - tu.warning(invc, "format.indirect.arguments"); break; } } diff --git a/checker/src/main/java/org/checkerframework/checker/formatter/qual/ConversionCategory.java b/checker/src/main/java/org/checkerframework/checker/formatter/qual/ConversionCategory.java index bf9ee8ce94..59ac145bf6 100644 --- a/checker/src/main/java/org/checkerframework/checker/formatter/qual/ConversionCategory.java +++ b/checker/src/main/java/org/checkerframework/checker/formatter/qual/ConversionCategory.java @@ -2,10 +2,12 @@ import java.math.BigDecimal; import java.math.BigInteger; +import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.StringJoiner; import org.checkerframework.checker.nullness.qual.Nullable; @@ -18,8 +20,8 @@ * *

* - *
{@literal @}Format({ConversionCategory.GENERAL, ConversionCategory.INT})
- * String f = "String '%s' has length %d";
+ * 
{@literal @}Format({GENERAL, INT}) String f = "String '%s' has length %d";
+ *
  * String.format(f, "Example", 7);
* *
@@ -31,42 +33,43 @@ * @see Format * @checker_framework.manual #formatter-checker Format String Checker */ +@SuppressWarnings("unchecked") // ".class" expressions in varargs position @AnnotatedFor("nullness") public enum ConversionCategory { /** Use if the parameter can be of any type. Applicable for conversions b, B, h, H, s, S. */ - GENERAL(null /* everything */, "bBhHsS"), + GENERAL("bBhHsS", (Class[]) null /* everything */), /** * Use if the parameter is of a basic types which represent Unicode characters: char, Character, * byte, Byte, short, and Short. This conversion may also be applied to the types int and * Integer when Character.isValidCodePoint(int) returns true. Applicable for conversions c, C. */ - CHAR(new Class[] {Character.class, Byte.class, Short.class, Integer.class}, "cC"), + CHAR("cC", Character.class, Byte.class, Short.class, Integer.class), /** * Use if the parameter is an integral type: byte, Byte, short, Short, int and Integer, long, * Long, and BigInteger. Applicable for conversions d, o, x, X. */ - INT( - new Class[] {Byte.class, Short.class, Integer.class, Long.class, BigInteger.class}, - "doxX"), + INT("doxX", Byte.class, Short.class, Integer.class, Long.class, BigInteger.class), /** * Use if the parameter is a floating-point type: float, Float, double, Double, and BigDecimal. * Applicable for conversions e, E, f, g, G, a, A. */ - FLOAT(new Class[] {Float.class, Double.class, BigDecimal.class}, "eEfgGaA"), + FLOAT("eEfgGaA", Float.class, Double.class, BigDecimal.class), /** * Use if the parameter is a type which is capable of encoding a date or time: long, Long, * Calendar, and Date. Applicable for conversions t, T. */ @SuppressWarnings("JdkObsolete") - TIME(new Class[] {Long.class, Calendar.class, Date.class}, "tT"), + TIME("tT", Long.class, Calendar.class, Date.class), /** - * In a format string, multiple conversions may be applied to the same parameter. This is - * seldomly needed, but the following is an example of such use: + * Use if the parameter is both a char and an int. + * + *

In a format string, multiple conversions may be applied to the same parameter. This is + * seldom needed, but the following is an example of such use: * *

      *   format("Test %1$c %1$d", (int)42);
@@ -82,9 +85,14 @@ public enum ConversionCategory {
      * 

All other intersection either lead to an already existing type, or NULL, in which case it * is illegal to pass object's of any type as parameter. */ - CHAR_AND_INT(new Class[] {Byte.class, Short.class, Integer.class}, null), + CHAR_AND_INT(null, Byte.class, Short.class, Integer.class), - INT_AND_TIME(new Class[] {Long.class}, null), + /** + * Use if the parameter is both an int and a time. + * + * @see #CHAR_AND_INT + */ + INT_AND_TIME(null, Long.class), /** * Use if no object of any type can be passed as parameter. In this case, the only legal value @@ -96,7 +104,7 @@ public enum ConversionCategory { * * Only null can be legally passed, passing a value such as 4 or 4.2 would lead to an exception. */ - NULL(new Class[0], null), + NULL(null), /** * Use if a parameter is not used by the formatter. This is seldomly needed, and indicates an @@ -109,21 +117,73 @@ public enum ConversionCategory { * Only the first "a" and third "b" parameters are used, the second "unused" parameter is * ignored. */ - UNUSED(null /* everything */, null); + UNUSED(null, (Class[]) null /* everything */); - /** Create a new conversion category. */ - ConversionCategory(Class @Nullable [] types, @Nullable String chars) { - this.types = types; - this.chars = chars; - } - - /** The format types. */ + /** The argument types. Null means every type. */ @SuppressWarnings("ImmutableEnumChecker") // TODO: clean this up! public final Class @Nullable [] types; - /** The format characters. */ + /** The format specifier characters. Null means users cannot specify it directly. */ public final @Nullable String chars; + /** + * Create a new conversion category. + * + * @param chars the format specifier characters. Null means users cannot specify it directly. + * @param types the argument types. Null means every type. + */ + ConversionCategory(@Nullable String chars, Class @Nullable ... types) { + this.chars = chars; + if (types == null) { + this.types = types; + } else { + List> typesWithPrimitives = new ArrayList<>(); + for (Class type : types) { + typesWithPrimitives.add(type); + Class unwrapped = unwrapPrimitive(type); + if (unwrapped != null) { + typesWithPrimitives.add(unwrapped); + } + } + this.types = typesWithPrimitives.toArray(new Class[typesWithPrimitives.size()]); + } + } + + /** + * If the given class is a primitive wrapper, return the corresponding primitive class. + * Otherwise return null. + * + * @param c a class + * @return the unwrapped primitive, or null + */ + private static @Nullable Class unwrapPrimitive(Class c) { + if (c == Byte.class) { + return byte.class; + } + if (c == Character.class) { + return char.class; + } + if (c == Short.class) { + return short.class; + } + if (c == Integer.class) { + return int.class; + } + if (c == Long.class) { + return long.class; + } + if (c == Float.class) { + return float.class; + } + if (c == Double.class) { + return double.class; + } + if (c == Boolean.class) { + return boolean.class; + } + return null; + } + /** * Converts a conversion character to a category. For example: * @@ -259,49 +319,46 @@ public static ConversionCategory union(ConversionCategory a, ConversionCategory return GENERAL; } - private String className(Class cls) { - if (cls == Boolean.class) { - return "boolean"; - } - if (cls == Character.class) { - return "char"; - } - if (cls == Byte.class) { - return "byte"; - } - if (cls == Short.class) { - return "short"; - } - if (cls == Integer.class) { - return "int"; - } - if (cls == Long.class) { - return "long"; + /** + * Returns true if {@code argType} can be an argument used by this format specifier. + * + * @param argType an argument type + * @return true if {@code argType} can be an argument used by this format specifier + */ + public boolean isAssignableFrom(Class argType) { + if (types == null) { + return true; } - if (cls == Float.class) { - return "float"; + if (argType == void.class) { + return true; } - if (cls == Double.class) { - return "double"; + for (Class c : types) { + if (c.isAssignableFrom(argType)) { + return true; + } } - return cls.getSimpleName(); + return false; } /** Returns a pretty printed {@link ConversionCategory}. */ - @SuppressWarnings( - "nullness:iterating.over.nullable") // `types` field is null only for UNUSED and - // GENERAL @Pure @Override public String toString() { - StringBuilder sb = new StringBuilder(this.name()); - if (this != UNUSED && this != GENERAL) { - StringJoiner sj = new StringJoiner(", ", " conversion category (one of: ", ")"); - for (Class cls : this.types) { - sj.add(className(cls)); - } - sb.append(sj); + StringBuilder sb = new StringBuilder(); + sb.append(name()); + sb.append(" conversion category"); + + if (types == null || types.length == 0) { + return sb.toString(); } + + StringJoiner sj = new StringJoiner(", ", "(one of: ", ")"); + for (Class cls : types) { + sj.add(cls.getSimpleName()); + } + sb.append(" "); + sb.append(sj); + return sb.toString(); } } diff --git a/checker/src/main/java/org/checkerframework/checker/formatter/qual/Format.java b/checker/src/main/java/org/checkerframework/checker/formatter/qual/Format.java index b513d84cfc..df0e73406a 100644 --- a/checker/src/main/java/org/checkerframework/checker/formatter/qual/Format.java +++ b/checker/src/main/java/org/checkerframework/checker/formatter/qual/Format.java @@ -17,8 +17,8 @@ *

* *
- * {@literal @}Format({ConversionCategory.GENERAL, ConversionCategory.INT})
- *  String f = "String '%s' has length %d";
+ * {@literal @}Format({GENERAL, INT}) String f = "String '%s' has length %d";
+ *
  *  String.format(f, "Example", 7);
  * 
* @@ -26,7 +26,8 @@ * * The annotation indicates that the format string requires any Object as the first parameter * ({@link ConversionCategory#GENERAL}) and an integer as the second parameter ({@link - * ConversionCategory#INT}). + * ConversionCategory#INT}). The format string accepts any values as additional parameters (because + * it ignores them). * * @see ConversionCategory * @checker_framework.manual #formatter-checker Format String Checker diff --git a/checker/src/main/java/org/checkerframework/checker/i18nformatter/I18nFormatterAnnotatedTypeFactory.java b/checker/src/main/java/org/checkerframework/checker/i18nformatter/I18nFormatterAnnotatedTypeFactory.java index 6b135641c7..f773139c09 100644 --- a/checker/src/main/java/org/checkerframework/checker/i18nformatter/I18nFormatterAnnotatedTypeFactory.java +++ b/checker/src/main/java/org/checkerframework/checker/i18nformatter/I18nFormatterAnnotatedTypeFactory.java @@ -217,7 +217,7 @@ public Void visitLiteral(LiteralTree tree, AnnotatedTypeMirror type) { } } - /** I18nFormatterQualifierHierarchy */ + /** I18nFormatterQualifierHierarchy. */ class I18nFormatterQualifierHierarchy extends MostlyNoElementQualifierHierarchy { /** Qualifier kind for the @{@link I18nFormat} annotation. */ diff --git a/checker/src/main/java/org/checkerframework/checker/i18nformatter/I18nFormatterTransfer.java b/checker/src/main/java/org/checkerframework/checker/i18nformatter/I18nFormatterTransfer.java index 756dc5c451..233fe2e983 100644 --- a/checker/src/main/java/org/checkerframework/checker/i18nformatter/I18nFormatterTransfer.java +++ b/checker/src/main/java/org/checkerframework/checker/i18nformatter/I18nFormatterTransfer.java @@ -9,8 +9,7 @@ import org.checkerframework.dataflow.analysis.TransferInput; import org.checkerframework.dataflow.analysis.TransferResult; import org.checkerframework.dataflow.cfg.node.MethodInvocationNode; -import org.checkerframework.dataflow.expression.FlowExpressions; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.framework.flow.CFAnalysis; import org.checkerframework.framework.flow.CFStore; import org.checkerframework.framework.flow.CFTransfer; @@ -46,8 +45,8 @@ public TransferResult visitMethodInvocation( if (cats.value() == null) { tu.failure(cats, "i18nformat.indirect.arguments"); } else { - Receiver firstParam = - FlowExpressions.internalReprOf(atypeFactory, node.getArgument(0)); + JavaExpression firstParam = + JavaExpression.fromNode(atypeFactory, node.getArgument(0)); AnnotationMirror anno = atypeFactory.treeUtil.categoriesToFormatAnnotation(cats.value()); thenStore.insertValue(firstParam, anno); @@ -61,10 +60,9 @@ public TransferResult visitMethodInvocation( CFStore elseStore = thenStore.copy(); ConditionalTransferResult newResult = new ConditionalTransferResult<>(result.getResultValue(), thenStore, elseStore); - Receiver firstParam = FlowExpressions.internalReprOf(atypeFactory, node.getArgument(0)); + JavaExpression firstParam = JavaExpression.fromNode(atypeFactory, node.getArgument(0)); AnnotationBuilder builder = - new AnnotationBuilder( - tu.processingEnv, I18nInvalidFormat.class.getCanonicalName()); + new AnnotationBuilder(tu.processingEnv, I18nInvalidFormat.class); // No need to set a value of @I18nInvalidFormat builder.setValue("value", ""); elseStore.insertValue(firstParam, builder.build()); diff --git a/checker/src/main/java/org/checkerframework/checker/i18nformatter/I18nFormatterTreeUtil.java b/checker/src/main/java/org/checkerframework/checker/i18nformatter/I18nFormatterTreeUtil.java index ab773de1f9..da10681d1f 100644 --- a/checker/src/main/java/org/checkerframework/checker/i18nformatter/I18nFormatterTreeUtil.java +++ b/checker/src/main/java/org/checkerframework/checker/i18nformatter/I18nFormatterTreeUtil.java @@ -37,13 +37,13 @@ import org.checkerframework.dataflow.cfg.node.MethodInvocationNode; import org.checkerframework.dataflow.cfg.node.Node; import org.checkerframework.dataflow.cfg.node.StringLiteralNode; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType; -import org.checkerframework.framework.util.FlowExpressionParseUtil; -import org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionContext; -import org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionParseException; +import org.checkerframework.framework.util.JavaExpressionParseUtil; +import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionContext; +import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionParseException; import org.checkerframework.javacutil.AnnotationBuilder; import org.checkerframework.javacutil.AnnotationUtils; import org.checkerframework.javacutil.TreeUtils; @@ -80,13 +80,14 @@ public AnnotationMirror exceptionToInvalidFormatAnnotation(IllegalArgumentExcept } /** - * Takes an invalid formatter string and returns a syntax trees element that represents a {@link - * I18nInvalidFormat} annotation with the invalid formatter string as value. + * Creates an {@link I18nInvalidFormat} annotation with the given string as its value. + * + * @param invalidFormatString an invalid formatter string + * @return an {@link I18nInvalidFormat} annotation with the given string as its value */ // package-private AnnotationMirror stringToInvalidFormatAnnotation(String invalidFormatString) { - AnnotationBuilder builder = - new AnnotationBuilder(processingEnv, I18nInvalidFormat.class.getCanonicalName()); + AnnotationBuilder builder = new AnnotationBuilder(processingEnv, I18nInvalidFormat.class); builder.setValue("value", invalidFormatString); return builder.build(); } @@ -100,12 +101,13 @@ public String invalidFormatAnnotationToErrorMessage(AnnotationMirror anno) { } /** - * Takes a list of ConversionCategory elements, and returns a syntax tree element that - * represents a {@link I18nFormat} annotation with the list as value. + * Creates a {@code @}{@link I18nFormat} annotation with the given list as its value. + * + * @param args conversion categories for the {@code @Format} annotation + * @return a {@code @}{@link I18nFormat} annotation with the given list as its value */ public AnnotationMirror categoriesToFormatAnnotation(I18nConversionCategory[] args) { - AnnotationBuilder builder = - new AnnotationBuilder(processingEnv, I18nFormat.class.getCanonicalName()); + AnnotationBuilder builder = new AnnotationBuilder(processingEnv, I18nFormat.class); builder.setValue("value", args); return builder.build(); } @@ -290,7 +292,7 @@ private void initialCheck( MethodInvocationNode node, AnnotatedExecutableType methodAnno) { int paramIndex = -1; - Receiver paramArg = null; + JavaExpression paramArg = null; int i = 0; for (AnnotatedTypeMirror paramType : methodAnno.getParameterTypes()) { if (paramType.getAnnotation(I18nFormatFor.class) != null) { @@ -301,8 +303,8 @@ private void initialCheck( // Invalid FormatFor invocation return; } - FlowExpressionContext flowExprContext = - FlowExpressionContext.buildContextForMethodUse( + JavaExpressionContext flowExprContext = + JavaExpressionContext.buildContextForMethodUse( node, checker.getContext()); String formatforArg = AnnotationUtils.getElementValue( @@ -313,13 +315,13 @@ private void initialCheck( if (flowExprContext != null) { try { paramArg = - FlowExpressionParseUtil.parse( + JavaExpressionParseUtil.parse( formatforArg, flowExprContext, atypeFactory.getPath(tree), true); paramIndex = flowExprContext.arguments.indexOf(paramArg); - } catch (FlowExpressionParseException e) { + } catch (JavaExpressionParseException e) { // report errors here checker.reportError(tree, "i18nformat.invalid.formatfor"); } @@ -473,12 +475,7 @@ public boolean isValidParameter(I18nConversionCategory formatCat, TypeMirror par // we did not recognize the parameter type return false; } - for (Class c : formatCat.types) { - if (c.isAssignableFrom(type)) { - return true; - } - } - return false; + return formatCat.isAssignableFrom(type); } } diff --git a/checker/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nConversionCategory.java b/checker/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nConversionCategory.java index 0078d96a22..05ad0338b1 100644 --- a/checker/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nConversionCategory.java +++ b/checker/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nConversionCategory.java @@ -25,13 +25,13 @@ public enum I18nConversionCategory { /** - * Use if a parameter is not used by the formatter. + * Use if a parameter is not used by the formatter. For example, in * *
      * MessageFormat.format("{1}", a, b);
      * 
* - * Only the second argument ("b") is used. The first argument ("a") is ignored + * only the second argument ("b") is used. The first argument ("a") is ignored. */ UNUSED(null /* everything */, null), @@ -169,6 +169,27 @@ public static I18nConversionCategory union(I18nConversionCategory a, I18nConvers return NUMBER; } + /** + * Returns true if {@code argType} can be an argument used by this format specifier. + * + * @param argType an argument type + * @return true if {@code argType} can be an argument used by this format specifier + */ + public boolean isAssignableFrom(Class argType) { + if (types == null) { + return true; + } + if (argType == void.class) { + return true; + } + for (Class c : types) { + if (c.isAssignableFrom(argType)) { + return true; + } + } + return false; + } + /** Returns a pretty printed {@link I18nConversionCategory}. */ @Override public String toString() { diff --git a/checker/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nFormat.java b/checker/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nFormat.java index 63968bc7fa..dc5ebbb49d 100644 --- a/checker/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nFormat.java +++ b/checker/src/main/java/org/checkerframework/checker/i18nformatter/qual/I18nFormat.java @@ -14,10 +14,11 @@ *

The annotation's value represents the valid arguments that may be passed to the format method. * For example: * - *

{@literal @}I18nFormat({I18nConversionCategory.GENERAL, I18nConversionCategory.NUMBER})
- * String f = "{0}{1, number}"; // valid
- * String f = "{0} {1} {2}"; // error, the format string is stronger (more restrictive) than the specifiers.
- * String f = "{0, number} {1, number}"; // error, the format string is stronger (NUMBER is a subtype of GENERAL).
+ * 
{@literal @}I18nFormat({GENERAL, NUMBER}) String f;
+ *
+ * f = "{0}{1, number}"; // valid
+ * f = "{0} {1} {2}"; // error, the format string is stronger (more restrictive) than the specifiers.
+ * f = "{0, number} {1, number}"; // error, the format string is stronger (NUMBER is a subtype of GENERAL).
  * 
* * The annotation indicates that the format string requires any object as the first parameter diff --git a/checker/src/main/java/org/checkerframework/checker/index/OffsetDependentTypesHelper.java b/checker/src/main/java/org/checkerframework/checker/index/OffsetDependentTypesHelper.java index 2a44622f9e..7c813f0d4b 100644 --- a/checker/src/main/java/org/checkerframework/checker/index/OffsetDependentTypesHelper.java +++ b/checker/src/main/java/org/checkerframework/checker/index/OffsetDependentTypesHelper.java @@ -4,12 +4,12 @@ import com.sun.source.util.TreePath; import org.checkerframework.checker.index.upperbound.OffsetEquation; import org.checkerframework.dataflow.expression.FieldAccess; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.treeannotator.TreeAnnotator; -import org.checkerframework.framework.util.FlowExpressionParseUtil; -import org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionContext; +import org.checkerframework.framework.util.JavaExpressionParseUtil; +import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionContext; import org.checkerframework.framework.util.dependenttypes.DependentTypesError; import org.checkerframework.framework.util.dependenttypes.DependentTypesHelper; import org.checkerframework.framework.util.dependenttypes.DependentTypesTreeAnnotator; @@ -27,7 +27,7 @@ public OffsetDependentTypesHelper(AnnotatedTypeFactory factory) { @Override protected String standardizeString( final String expression, - FlowExpressionContext context, + JavaExpressionContext context, TreePath localScope, boolean useLocalScope) { if (DependentTypesError.isExpressionError(expression)) { @@ -35,12 +35,12 @@ protected String standardizeString( } if (expression.indexOf('-') == -1 && expression.indexOf('+') == -1) { // The expression contains no "-" or "+", so it can be standardized directly. - Receiver result; + JavaExpression result; try { result = - FlowExpressionParseUtil.parse( + JavaExpressionParseUtil.parse( expression, context, localScope, useLocalScope); - } catch (FlowExpressionParseUtil.FlowExpressionParseException e) { + } catch (JavaExpressionParseUtil.JavaExpressionParseException e) { return new DependentTypesError(expression, e).toString(); } if (result == null) { @@ -65,7 +65,7 @@ protected String standardizeString( // Standardize individual terms of the expression. equation.standardizeAndViewpointAdaptExpressions( context, localScope, useLocalScope, factory); - } catch (FlowExpressionParseUtil.FlowExpressionParseException e) { + } catch (JavaExpressionParseUtil.JavaExpressionParseException e) { return new DependentTypesError(expression, e).toString(); } diff --git a/checker/src/main/java/org/checkerframework/checker/index/Subsequence.java b/checker/src/main/java/org/checkerframework/checker/index/Subsequence.java index 253267718f..556102fee3 100644 --- a/checker/src/main/java/org/checkerframework/checker/index/Subsequence.java +++ b/checker/src/main/java/org/checkerframework/checker/index/Subsequence.java @@ -6,12 +6,12 @@ import javax.lang.model.element.Element; import org.checkerframework.checker.index.qual.HasSubsequence; import org.checkerframework.dataflow.expression.FieldAccess; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.util.BaseContext; -import org.checkerframework.framework.util.FlowExpressionParseUtil; -import org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionContext; -import org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionParseException; +import org.checkerframework.framework.util.JavaExpressionParseUtil; +import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionContext; +import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionParseException; import org.checkerframework.javacutil.AnnotationUtils; import org.checkerframework.javacutil.TreeUtils; @@ -60,7 +60,7 @@ public static Subsequence getSubsequenceFromTree(Tree varTree, AnnotatedTypeFact * @return a new Subsequence object representing {@code hasSub} or null */ private static Subsequence createSubsequence( - AnnotationMirror hasSub, TreePath currentPath, FlowExpressionContext context) { + AnnotationMirror hasSub, TreePath currentPath, JavaExpressionContext context) { if (hasSub == null) { return null; } @@ -81,24 +81,24 @@ private static Subsequence createSubsequence( * Returns a Subsequence representing the {@link HasSubsequence} annotation on the declaration * of {@code rec} or null if there is not such annotation. * - * @param rec some tree + * @param expr some tree * @param factory an AnnotatedTypeFactory * @param currentPath the path at which to viewpoint adapt the subsequence * @param context the context in which to viewpoint adapt the subsequence * @return null or a new Subsequence from the declaration of {@code varTree} */ public static Subsequence getSubsequenceFromReceiver( - Receiver rec, + JavaExpression expr, AnnotatedTypeFactory factory, TreePath currentPath, - FlowExpressionContext context) { - if (rec == null) { + JavaExpressionContext context) { + if (expr == null) { return null; } Element element; - if (rec instanceof FieldAccess) { - element = ((FieldAccess) rec).getField(); + if (expr instanceof FieldAccess) { + element = ((FieldAccess) expr).getField(); } else { return null; } @@ -108,31 +108,32 @@ public static Subsequence getSubsequenceFromReceiver( /* * Helper function to standardize and viewpoint adapt a String given a path and a context. - * Wraps FlowExpressionParseUtil#parse. If a parse exception is encountered, this returns + * Wraps JavaExpressionParseUtil#parse. If a parse exception is encountered, this returns * its argument. */ private static String standardizeAndViewpointAdapt( - String s, TreePath currentPath, FlowExpressionContext context) { + String s, TreePath currentPath, JavaExpressionContext context) { try { - return FlowExpressionParseUtil.parse(s, context, currentPath, false).toString(); - } catch (FlowExpressionParseException e) { + return JavaExpressionParseUtil.parse(s, context, currentPath, false).toString(); + } catch (JavaExpressionParseException e) { return s; } } /** - * If the passed receiver is a FieldAccess, returns the context associated with it. Otherwise + * If the passed expression is a FieldAccess, returns the context associated with it. Otherwise * returns null. * *

Used to standardize and viewpoint adapt arguments to HasSubsequence annotations. */ - public static FlowExpressionContext getContextFromReceiver(Receiver rec, BaseContext checker) { - if (rec == null) { + public static JavaExpressionContext getContextFromJavaExpression( + JavaExpression expr, BaseContext checker) { + if (expr == null) { return null; } - if (rec instanceof FieldAccess) { - FieldAccess fa = (FieldAccess) rec; - return new FlowExpressionParseUtil.FlowExpressionContext( + if (expr instanceof FieldAccess) { + FieldAccess fa = (FieldAccess) expr; + return new JavaExpressionParseUtil.JavaExpressionContext( fa.getReceiver(), null, checker); } else { @@ -143,14 +144,14 @@ public static FlowExpressionContext getContextFromReceiver(Receiver rec, BaseCon /** * Returns the additive inverse of the given String. That is, if the result of this method is * some String s', then s + s' == 0 will evaluate to true. Note that this relies on the fact - * that the Flow Expression Parser cannot parse multiplication, so it naively just changes '-' - * to '+' and vice-versa. + * that the JavaExpression parser cannot parse multiplication, so it naively just changes '-' to + * '+' and vice-versa. * *

The passed String is standardized and viewpoint adapted before this transformation is * applied. */ public static String negateString( - String s, TreePath currentPath, FlowExpressionContext context) { + String s, TreePath currentPath, JavaExpressionContext context) { String original = standardizeAndViewpointAdapt(s, currentPath, context); String result = ""; if (!original.startsWith("-")) { diff --git a/checker/src/main/java/org/checkerframework/checker/index/inequality/LessThanAnnotatedTypeFactory.java b/checker/src/main/java/org/checkerframework/checker/index/inequality/LessThanAnnotatedTypeFactory.java index c9fe4b6c6a..df2e0643cf 100644 --- a/checker/src/main/java/org/checkerframework/checker/index/inequality/LessThanAnnotatedTypeFactory.java +++ b/checker/src/main/java/org/checkerframework/checker/index/inequality/LessThanAnnotatedTypeFactory.java @@ -28,11 +28,11 @@ import org.checkerframework.common.value.qual.IntRange; import org.checkerframework.common.value.qual.IntVal; import org.checkerframework.dataflow.expression.FieldAccess; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.ElementQualifierHierarchy; import org.checkerframework.framework.type.QualifierHierarchy; -import org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionParseException; +import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionParseException; import org.checkerframework.framework.util.dependenttypes.DependentTypesHelper; import org.checkerframework.javacutil.AnnotationBuilder; import org.checkerframework.javacutil.AnnotationUtils; @@ -77,7 +77,7 @@ protected QualifierHierarchy createQualifierHierarchy() { return new LessThanQualifierHierarchy(this.getSupportedTypeQualifiers(), elements); } - /** LessThanQualifierHierarchy */ + /** LessThanQualifierHierarchy. */ class LessThanQualifierHierarchy extends ElementQualifierHierarchy { /** @@ -202,43 +202,43 @@ public boolean isLessThanByValue(Tree smaller, String bigger, TreePath path) { * @param path the path to {@code tree} */ private long getMinValueFromString(String expression, Tree tree, TreePath path) { - Receiver expressionRec; + JavaExpression expressionJe; try { - expressionRec = - getValueAnnotatedTypeFactory() - .getReceiverFromJavaExpressionString(expression, path); - } catch (FlowExpressionParseException e) { + expressionJe = + getValueAnnotatedTypeFactory().parseJavaExpressionString(expression, path); + } catch (JavaExpressionParseException e) { return Long.MIN_VALUE; } AnnotationMirror intRange = getValueAnnotatedTypeFactory() - .getAnnotationFromReceiver(expressionRec, tree, IntRange.class); + .getAnnotationFromJavaExpression(expressionJe, tree, IntRange.class); if (intRange != null) { return ValueAnnotatedTypeFactory.getRange(intRange).from; } AnnotationMirror intValue = getValueAnnotatedTypeFactory() - .getAnnotationFromReceiver(expressionRec, tree, IntVal.class); + .getAnnotationFromJavaExpression(expressionJe, tree, IntVal.class); if (intValue != null) { List possibleValues = ValueAnnotatedTypeFactory.getIntValues(intValue); return Collections.min(possibleValues); } - if (expressionRec instanceof FieldAccess) { - FieldAccess fieldAccess = ((FieldAccess) expressionRec); + if (expressionJe instanceof FieldAccess) { + FieldAccess fieldAccess = ((FieldAccess) expressionJe); if (fieldAccess.getReceiver().getType().getKind() == TypeKind.ARRAY) { // array.length might not be in the store, so check for the length of the array. AnnotationMirror arrayRange = getValueAnnotatedTypeFactory() - .getAnnotationFromReceiver( + .getAnnotationFromJavaExpression( fieldAccess.getReceiver(), tree, ArrayLenRange.class); if (arrayRange != null) { return ValueAnnotatedTypeFactory.getRange(arrayRange).from; } AnnotationMirror arrayLen = getValueAnnotatedTypeFactory() - .getAnnotationFromReceiver(expressionRec, tree, ArrayLen.class); + .getAnnotationFromJavaExpression( + expressionJe, tree, ArrayLen.class); if (arrayLen != null) { List possibleValues = ValueAnnotatedTypeFactory.getArrayLength(arrayLen); diff --git a/checker/src/main/java/org/checkerframework/checker/index/inequality/LessThanTransfer.java b/checker/src/main/java/org/checkerframework/checker/index/inequality/LessThanTransfer.java index d9a606756a..37fdf1d9f3 100644 --- a/checker/src/main/java/org/checkerframework/checker/index/inequality/LessThanTransfer.java +++ b/checker/src/main/java/org/checkerframework/checker/index/inequality/LessThanTransfer.java @@ -14,13 +14,12 @@ import org.checkerframework.dataflow.analysis.TransferResult; import org.checkerframework.dataflow.cfg.node.Node; import org.checkerframework.dataflow.cfg.node.NumericalSubtractionNode; -import org.checkerframework.dataflow.expression.FlowExpressions; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.dataflow.expression.ValueLiteral; import org.checkerframework.framework.flow.CFAnalysis; import org.checkerframework.framework.flow.CFStore; import org.checkerframework.framework.flow.CFValue; -import org.checkerframework.framework.util.FlowExpressionParseUtil; +import org.checkerframework.framework.util.JavaExpressionParseUtil; /** * Implements 3 refinement rules: @@ -52,19 +51,19 @@ protected void refineGT( (LessThanAnnotatedTypeFactory) analysis.getTypeFactory(); // left > right so right < left // Refine right to @LessThan("left") - Receiver leftRec = FlowExpressions.internalReprOf(factory, left); - if (leftRec != null && leftRec.isUnassignableByOtherCode()) { + JavaExpression leftJe = JavaExpression.fromNode(factory, left); + if (leftJe != null && leftJe.isUnassignableByOtherCode()) { List lessThanExpressions = LessThanAnnotatedTypeFactory.getLessThanExpressions(rightAnno); if (lessThanExpressions == null) { // right is already bottom, nothing to refine. return; } - if (!isDoubleOrFloatLiteral(leftRec)) { - lessThanExpressions.add(leftRec.toString()); + if (!isDoubleOrFloatLiteral(leftJe)) { + lessThanExpressions.add(leftJe.toString()); } - Receiver rightRec = FlowExpressions.internalReprOf(analysis.getTypeFactory(), right); - store.insertValue(rightRec, factory.createLessThanQualifier(lessThanExpressions)); + JavaExpression rightJe = JavaExpression.fromNode(analysis.getTypeFactory(), right); + store.insertValue(rightJe, factory.createLessThanQualifier(lessThanExpressions)); } } @@ -84,19 +83,19 @@ protected void refineGTE( (LessThanAnnotatedTypeFactory) analysis.getTypeFactory(); // left > right so right is less than left // Refine right to @LessThan("left") - Receiver leftRec = FlowExpressions.internalReprOf(factory, left); - if (leftRec != null && leftRec.isUnassignableByOtherCode()) { + JavaExpression leftJe = JavaExpression.fromNode(factory, left); + if (leftJe != null && leftJe.isUnassignableByOtherCode()) { List lessThanExpressions = LessThanAnnotatedTypeFactory.getLessThanExpressions(rightAnno); if (lessThanExpressions == null) { // right is already bottom, nothing to refine. return; } - if (!isDoubleOrFloatLiteral(leftRec)) { - lessThanExpressions.add(leftRec.toString() + " + 1"); + if (!isDoubleOrFloatLiteral(leftJe)) { + lessThanExpressions.add(leftJe.toString() + " + 1"); } - Receiver rightRec = FlowExpressions.internalReprOf(analysis.getTypeFactory(), right); - store.insertValue(rightRec, factory.createLessThanQualifier(lessThanExpressions)); + JavaExpression rightJe = JavaExpression.fromNode(analysis.getTypeFactory(), right); + store.insertValue(rightJe, factory.createLessThanQualifier(lessThanExpressions)); } } @@ -106,8 +105,8 @@ public TransferResult visitNumericalSubtraction( NumericalSubtractionNode n, TransferInput in) { LessThanAnnotatedTypeFactory factory = (LessThanAnnotatedTypeFactory) analysis.getTypeFactory(); - Receiver leftRec = FlowExpressions.internalReprOf(factory, n.getLeftOperand()); - if (leftRec != null && leftRec.isUnassignableByOtherCode()) { + JavaExpression leftJe = JavaExpression.fromNode(factory, n.getLeftOperand()); + if (leftJe != null && leftJe.isUnassignableByOtherCode()) { ValueAnnotatedTypeFactory valueFactory = factory.getValueAnnotatedTypeFactory(); Long right = ValueCheckerUtils.getMinValue(n.getRightOperand().getTree(), valueFactory); if (right != null && 0 < right) { @@ -116,8 +115,8 @@ public TransferResult visitNumericalSubtraction( if (expressions == null) { expressions = new ArrayList<>(); } - if (!isDoubleOrFloatLiteral(leftRec)) { - expressions.add(leftRec.toString()); + if (!isDoubleOrFloatLiteral(leftJe)) { + expressions.add(leftJe.toString()); } AnnotationMirror refine = factory.createLessThanQualifier(expressions); CFValue value = analysis.createSingleAnnotationValue(refine, n.getType()); @@ -143,13 +142,13 @@ private List getLessThanExpressions(Node node) { } /** - * Return true if {@code receiver} is a double or float literal, which can't be parsed by {@link - * FlowExpressionParseUtil}. + * Return true if {@code expr} is a double or float literal, which can't be parsed by {@link + * JavaExpressionParseUtil}. */ - private boolean isDoubleOrFloatLiteral(Receiver receiver) { - if (receiver instanceof ValueLiteral) { - return receiver.getType().getKind() == TypeKind.DOUBLE - || receiver.getType().getKind() == TypeKind.FLOAT; + private boolean isDoubleOrFloatLiteral(JavaExpression expr) { + if (expr instanceof ValueLiteral) { + return expr.getType().getKind() == TypeKind.DOUBLE + || expr.getType().getKind() == TypeKind.FLOAT; } else { return false; } diff --git a/checker/src/main/java/org/checkerframework/checker/index/inequality/LessThanVisitor.java b/checker/src/main/java/org/checkerframework/checker/index/inequality/LessThanVisitor.java index 80e3782d16..1e022aa656 100644 --- a/checker/src/main/java/org/checkerframework/checker/index/inequality/LessThanVisitor.java +++ b/checker/src/main/java/org/checkerframework/checker/index/inequality/LessThanVisitor.java @@ -12,7 +12,7 @@ import org.checkerframework.common.basetype.BaseTypeChecker; import org.checkerframework.common.basetype.BaseTypeVisitor; import org.checkerframework.framework.type.AnnotatedTypeMirror; -import org.checkerframework.framework.util.FlowExpressionParseUtil; +import org.checkerframework.framework.util.JavaExpressionParseUtil; public class LessThanVisitor extends BaseTypeVisitor { @@ -39,7 +39,7 @@ protected void commonAssignmentCheck( anm = atypeFactory.getAnnotationMirrorFromJavaExpressionString( subSeq.from, varTree, getCurrentPath()); - } catch (FlowExpressionParseUtil.FlowExpressionParseException e) { + } catch (JavaExpressionParseUtil.JavaExpressionParseException e) { anm = null; } diff --git a/checker/src/main/java/org/checkerframework/checker/index/lowerbound/LowerBoundAnnotatedTypeFactory.java b/checker/src/main/java/org/checkerframework/checker/index/lowerbound/LowerBoundAnnotatedTypeFactory.java index dbcb799e31..9e830a465c 100644 --- a/checker/src/main/java/org/checkerframework/checker/index/lowerbound/LowerBoundAnnotatedTypeFactory.java +++ b/checker/src/main/java/org/checkerframework/checker/index/lowerbound/LowerBoundAnnotatedTypeFactory.java @@ -2,6 +2,7 @@ import com.sun.source.tree.BinaryTree; import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.LiteralTree; import com.sun.source.tree.MemberSelectTree; import com.sun.source.tree.MethodInvocationTree; import com.sun.source.tree.Tree; @@ -111,12 +112,12 @@ public LowerBoundAnnotatedTypeFactory(BaseTypeChecker checker) { // or @GTENegativeOne must also be aliased in the constructor of // ValueAnnotatedTypeFactory to the appropriate @IntRangeFrom* // annotation. - addAliasedAnnotation(IndexFor.class, NN); - addAliasedAnnotation(IndexOrLow.class, GTEN1); - addAliasedAnnotation(IndexOrHigh.class, NN); - addAliasedAnnotation(LengthOf.class, NN); - addAliasedAnnotation(PolyIndex.class, POLY); - addAliasedAnnotation(SubstringIndexFor.class, GTEN1); + addAliasedTypeAnnotation(IndexFor.class, NN); + addAliasedTypeAnnotation(IndexOrLow.class, GTEN1); + addAliasedTypeAnnotation(IndexOrHigh.class, NN); + addAliasedTypeAnnotation(LengthOf.class, NN); + addAliasedTypeAnnotation(PolyIndex.class, POLY); + addAliasedTypeAnnotation(SubstringIndexFor.class, GTEN1); imf = new IndexMethodIdentifier(this); @@ -175,7 +176,9 @@ public void addComputedTypeAnnotations(Tree tree, AnnotatedTypeMirror type, bool // If dataflow shouldn't be used to compute this type, then do not use the result from // the Value Checker, because dataflow is used to compute that type. (Without this, // "int i = 1; --i;" fails.) - if (iUseFlow && tree != null && TreeUtils.isExpressionTree(tree)) { + if (tree != null + && TreeUtils.isExpressionTree(tree) + && (iUseFlow || tree instanceof LiteralTree)) { AnnotatedTypeMirror valueType = getValueAnnotatedTypeFactory().getAnnotatedType(tree); addLowerBoundTypeFromValueType(valueType, type); } diff --git a/checker/src/main/java/org/checkerframework/checker/index/lowerbound/LowerBoundTransfer.java b/checker/src/main/java/org/checkerframework/checker/index/lowerbound/LowerBoundTransfer.java index 4ffe6b522b..3998491221 100644 --- a/checker/src/main/java/org/checkerframework/checker/index/lowerbound/LowerBoundTransfer.java +++ b/checker/src/main/java/org/checkerframework/checker/index/lowerbound/LowerBoundTransfer.java @@ -31,13 +31,12 @@ import org.checkerframework.dataflow.cfg.node.NumericalSubtractionNode; import org.checkerframework.dataflow.cfg.node.SignedRightShiftNode; import org.checkerframework.dataflow.cfg.node.UnsignedRightShiftNode; -import org.checkerframework.dataflow.expression.FlowExpressions; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.framework.flow.CFAnalysis; import org.checkerframework.framework.flow.CFStore; import org.checkerframework.framework.flow.CFValue; import org.checkerframework.framework.type.AnnotatedTypeFactory; -import org.checkerframework.framework.util.FlowExpressionParseUtil; +import org.checkerframework.framework.util.JavaExpressionParseUtil; import org.checkerframework.javacutil.AnnotationUtils; import org.checkerframework.javacutil.TreeUtils; @@ -207,16 +206,16 @@ private void notEqualToValue( if (aTypeFactory.areSameByClass(otherAnno, NonNegative.class)) { List internals = splitAssignments(otherNode); for (Node internal : internals) { - Receiver rec = FlowExpressions.internalReprOf(aTypeFactory, internal); - store.insertValue(rec, POS); + JavaExpression je = JavaExpression.fromNode(aTypeFactory, internal); + store.insertValue(je, POS); } } } else if (intLiteral == -1) { if (aTypeFactory.areSameByClass(otherAnno, GTENegativeOne.class)) { List internals = splitAssignments(otherNode); for (Node internal : internals) { - Receiver rec = FlowExpressions.internalReprOf(aTypeFactory, internal); - store.insertValue(rec, NN); + JavaExpression je = JavaExpression.fromNode(aTypeFactory, internal); + store.insertValue(je, NN); } } } @@ -267,11 +266,11 @@ private void notEqualsLessThan( if (!isNonNegative(leftAnno) || !isNonNegative(otherAnno)) { return; } - Receiver otherRec = FlowExpressions.internalReprOf(aTypeFactory, otherNode); + JavaExpression otherJe = JavaExpression.fromNode(aTypeFactory, otherNode); if (aTypeFactory .getLessThanAnnotatedTypeFactory() - .isLessThanOrEqual(leftNode.getTree(), otherRec.toString())) { - store.insertValue(otherRec, POS); + .isLessThanOrEqual(leftNode.getTree(), otherJe.toString())) { + store.insertValue(otherJe, POS); } } @@ -297,18 +296,18 @@ protected void refineGT( return; } - Receiver leftRec = FlowExpressions.internalReprOf(aTypeFactory, left); + JavaExpression leftJe = JavaExpression.fromNode(aTypeFactory, left); if (AnnotationUtils.areSame(rightAnno, GTEN1)) { - store.insertValue(leftRec, NN); + store.insertValue(leftJe, NN); return; } if (AnnotationUtils.areSame(rightAnno, NN)) { - store.insertValue(leftRec, POS); + store.insertValue(leftJe, POS); return; } if (AnnotationUtils.areSame(rightAnno, POS)) { - store.insertValue(leftRec, POS); + store.insertValue(leftJe, POS); return; } } @@ -334,12 +333,12 @@ protected void refineGTE( return; } - Receiver leftRec = FlowExpressions.internalReprOf(aTypeFactory, left); + JavaExpression leftJe = JavaExpression.fromNode(aTypeFactory, left); AnnotationMirror newLBType = aTypeFactory.getQualifierHierarchy().greatestLowerBound(rightAnno, leftAnno); - store.insertValue(leftRec, newLBType); + store.insertValue(leftJe, newLBType); } /** @@ -719,17 +718,15 @@ protected void addInformationFromPreconditions( for (VariableTree variableTree : paramTrees) { if (TreeUtils.typeOf(variableTree).getKind() == TypeKind.CHAR) { - Receiver rec = null; + JavaExpression je = null; try { - rec = - FlowExpressionParseUtil.internalReprOfVariable( - aTypeFactory, variableTree); - } catch (FlowExpressionParseUtil.FlowExpressionParseException e) { + je = JavaExpressionParseUtil.fromVariableTree(aTypeFactory, variableTree); + } catch (JavaExpressionParseUtil.JavaExpressionParseException e) { // do nothing } - if (rec != null) { - info.insertValue(rec, aTypeFactory.NN); + if (je != null) { + info.insertValue(je, aTypeFactory.NN); } } } diff --git a/checker/src/main/java/org/checkerframework/checker/index/lowerbound/LowerBoundVisitor.java b/checker/src/main/java/org/checkerframework/checker/index/lowerbound/LowerBoundVisitor.java index 3cecd0ad5f..8fcac9f1df 100644 --- a/checker/src/main/java/org/checkerframework/checker/index/lowerbound/LowerBoundVisitor.java +++ b/checker/src/main/java/org/checkerframework/checker/index/lowerbound/LowerBoundVisitor.java @@ -12,7 +12,7 @@ import org.checkerframework.common.basetype.BaseTypeChecker; import org.checkerframework.common.basetype.BaseTypeVisitor; import org.checkerframework.framework.type.AnnotatedTypeMirror; -import org.checkerframework.framework.util.FlowExpressionParseUtil; +import org.checkerframework.framework.util.JavaExpressionParseUtil; /** * Implements the actual checks to make sure that array accesses aren't too low. Will issue a @@ -77,7 +77,7 @@ protected void commonAssignmentCheck( anm = atypeFactory.getAnnotationMirrorFromJavaExpressionString( subSeq.from, varTree, getCurrentPath()); - } catch (FlowExpressionParseUtil.FlowExpressionParseException e) { + } catch (JavaExpressionParseUtil.JavaExpressionParseException e) { anm = null; } if (anm == null diff --git a/checker/src/main/java/org/checkerframework/checker/index/samelen/SameLenAnnotatedTypeFactory.java b/checker/src/main/java/org/checkerframework/checker/index/samelen/SameLenAnnotatedTypeFactory.java index b64d8b9bd4..2c2cf9a06d 100644 --- a/checker/src/main/java/org/checkerframework/checker/index/samelen/SameLenAnnotatedTypeFactory.java +++ b/checker/src/main/java/org/checkerframework/checker/index/samelen/SameLenAnnotatedTypeFactory.java @@ -28,15 +28,14 @@ import org.checkerframework.common.value.ValueCheckerUtils; import org.checkerframework.dataflow.expression.ArrayCreation; import org.checkerframework.dataflow.expression.ClassName; -import org.checkerframework.dataflow.expression.FlowExpressions; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.ElementQualifierHierarchy; import org.checkerframework.framework.type.QualifierHierarchy; import org.checkerframework.framework.type.treeannotator.ListTreeAnnotator; import org.checkerframework.framework.type.treeannotator.TreeAnnotator; -import org.checkerframework.framework.util.FlowExpressionParseUtil; -import org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionParseException; +import org.checkerframework.framework.util.JavaExpressionParseUtil; +import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionParseException; import org.checkerframework.javacutil.AnnotationBuilder; import org.checkerframework.javacutil.AnnotationUtils; @@ -85,7 +84,7 @@ public class SameLenAnnotatedTypeFactory extends BaseAnnotatedTypeFactory { public SameLenAnnotatedTypeFactory(BaseTypeChecker checker) { super(checker); - addAliasedAnnotation(PolyLength.class, POLY); + addAliasedTypeAnnotation(PolyLength.class, POLY); this.postInit(); } @@ -120,15 +119,15 @@ public AnnotatedTypeMirror getAnnotatedTypeLhs(Tree tree) { AnnotationMirror anm = atm.getAnnotation(SameLen.class); if (anm != null) { - Receiver r; + JavaExpression je; try { - r = FlowExpressionParseUtil.internalReprOfVariable(this, (VariableTree) tree); - } catch (FlowExpressionParseException ex) { - r = null; + je = JavaExpressionParseUtil.fromVariableTree(this, (VariableTree) tree); + } catch (JavaExpressionParseException ex) { + je = null; } - if (r != null) { - String varName = r.toString(); + if (je != null) { + String varName = je.toString(); List exprs = ValueCheckerUtils.getValueOfAnnotationWithStringArgument(anm); @@ -148,13 +147,13 @@ public AnnotatedTypeMirror getAnnotatedTypeLhs(Tree tree) { } /** Returns true if the given expression may appear in a @SameLen annotation. */ - public static boolean mayAppearInSameLen(Receiver receiver) { - return !receiver.containsUnknown() - && !(receiver instanceof ArrayCreation) - && !(receiver instanceof ClassName) - // Big expressions cause a stack overflow in FlowExpressionParseUtil. + public static boolean mayAppearInSameLen(JavaExpression expr) { + return !expr.containsUnknown() + && !(expr instanceof ArrayCreation) + && !(expr instanceof ClassName) + // Big expressions cause a stack overflow in JavaExpressionParseUtil. // So limit them to an arbitrary length of 999. - && receiver.toString().length() < 1000; + && expr.toString().length() < 1000; } /** @@ -303,9 +302,10 @@ public Void visitNewArray(NewArrayTree node, AnnotatedTypeMirror type) { AnnotationMirror sequenceAnno = getAnnotatedType(sequenceTree).getAnnotationInHierarchy(UNKNOWN); - Receiver rec = FlowExpressions.internalReprOf(this.atypeFactory, sequenceTree); - if (mayAppearInSameLen(rec)) { - String recString = rec.toString(); + JavaExpression sequenceExpr = + JavaExpression.fromTree(this.atypeFactory, sequenceTree); + if (mayAppearInSameLen(sequenceExpr)) { + String recString = sequenceExpr.toString(); if (areSameByClass(sequenceAnno, SameLenUnknown.class)) { sequenceAnno = createSameLen(Collections.singletonList(recString)); } else if (areSameByClass(sequenceAnno, SameLen.class)) { @@ -338,7 +338,7 @@ public List getSameLensFromString( sameLenAnno = getAnnotationFromJavaExpressionString( sequenceExpression, tree, currentPath, SameLen.class); - } catch (FlowExpressionParseUtil.FlowExpressionParseException e) { + } catch (JavaExpressionParseUtil.JavaExpressionParseException e) { // ignore parse errors sameLenAnno = null; } @@ -370,39 +370,39 @@ public AnnotationMirror createSameLen(Collection exprs) { * #createCombinedSameLen(List, List)}. */ public AnnotationMirror createCombinedSameLen( - Receiver rec1, Receiver rec2, AnnotationMirror a1, AnnotationMirror a2) { - List receivers = new ArrayList<>(); - receivers.add(rec1); - receivers.add(rec2); + JavaExpression expr1, JavaExpression expr2, AnnotationMirror a1, AnnotationMirror a2) { + List exprs = new ArrayList<>(); + exprs.add(expr1); + exprs.add(expr2); List annos = new ArrayList<>(); annos.add(a1); annos.add(a2); - return createCombinedSameLen(receivers, annos); + return createCombinedSameLen(exprs, annos); } /** - * Generates a SameLen that includes each receiver, as well as everything in the annotations2, + * Generates a SameLen that includes each expression, as well as everything in the annotations2, * if they are SameLen annotations. * - * @param receivers a list of receivers representing arrays to be included in the combined + * @param exprs a list of expressions representing arrays to be included in the combined * annotation * @param annos a list of annotations * @return a combined SameLen annotation */ public AnnotationMirror createCombinedSameLen( - List receivers, List annos) { + List exprs, List annos) { - Set exprs = new TreeSet<>(); - for (Receiver rec : receivers) { - if (mayAppearInSameLen(rec)) { - exprs.add(rec.toString()); + Set strings = new TreeSet<>(); + for (JavaExpression expr : exprs) { + if (mayAppearInSameLen(expr)) { + strings.add(expr.toString()); } } for (AnnotationMirror anno : annos) { if (areSameByClass(anno, SameLen.class)) { - exprs.addAll(ValueCheckerUtils.getValueOfAnnotationWithStringArgument(anno)); + strings.addAll(ValueCheckerUtils.getValueOfAnnotationWithStringArgument(anno)); } } - return createSameLen(exprs); + return createSameLen(strings); } } diff --git a/checker/src/main/java/org/checkerframework/checker/index/samelen/SameLenTransfer.java b/checker/src/main/java/org/checkerframework/checker/index/samelen/SameLenTransfer.java index 4fe03c438b..0723443e03 100644 --- a/checker/src/main/java/org/checkerframework/checker/index/samelen/SameLenTransfer.java +++ b/checker/src/main/java/org/checkerframework/checker/index/samelen/SameLenTransfer.java @@ -21,15 +21,14 @@ import org.checkerframework.dataflow.cfg.node.FieldAccessNode; import org.checkerframework.dataflow.cfg.node.MethodInvocationNode; import org.checkerframework.dataflow.cfg.node.Node; -import org.checkerframework.dataflow.expression.FlowExpressions; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.framework.flow.CFAnalysis; import org.checkerframework.framework.flow.CFStore; import org.checkerframework.framework.flow.CFTransfer; import org.checkerframework.framework.flow.CFValue; import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; -import org.checkerframework.framework.util.FlowExpressionParseUtil; +import org.checkerframework.framework.util.JavaExpressionParseUtil; /** * The transfer function for the SameLen checker. Contains three cases: @@ -91,12 +90,10 @@ public TransferResult visitAssignment( // "lengthNodeReceiver.length()" // targetRec is the receiver for the left hand side of the assignment. - Receiver targetRec = - FlowExpressions.internalReprOf( - analysis.getTypeFactory(), node.getTarget()); - Receiver otherRec = - FlowExpressions.internalReprOf( - analysis.getTypeFactory(), lengthNodeReceiver); + JavaExpression targetRec = + JavaExpression.fromNode(analysis.getTypeFactory(), node.getTarget()); + JavaExpression otherRec = + JavaExpression.fromNode(analysis.getTypeFactory(), lengthNodeReceiver); AnnotationMirror lengthNodeAnnotation = aTypeFactory @@ -124,11 +121,11 @@ public TransferResult visitAssignment( // If the left side of the assignment is an array or a string, then have both the right and // left side be SameLen of each other. - Receiver targetRec = - FlowExpressions.internalReprOf(analysis.getTypeFactory(), node.getTarget()); + JavaExpression targetRec = + JavaExpression.fromNode(analysis.getTypeFactory(), node.getTarget()); - Receiver exprRec = - FlowExpressions.internalReprOf(analysis.getTypeFactory(), node.getExpression()); + JavaExpression exprRec = + JavaExpression.fromNode(analysis.getTypeFactory(), node.getExpression()); if (IndexUtil.isSequenceType(node.getTarget().getType()) || (rightAnno != null && aTypeFactory.areSameByClass(rightAnno, SameLen.class))) { @@ -161,15 +158,16 @@ private void propagateCombinedSameLen(AnnotationMirror sameLenAnno, Node node, C if (currentPath == null) { return; } - for (String expr : ValueCheckerUtils.getValueOfAnnotationWithStringArgument(sameLenAnno)) { - Receiver recS; + for (String exprString : + ValueCheckerUtils.getValueOfAnnotationWithStringArgument(sameLenAnno)) { + JavaExpression je; try { - recS = aTypeFactory.getReceiverFromJavaExpressionString(expr, currentPath); - } catch (FlowExpressionParseUtil.FlowExpressionParseException e) { + je = aTypeFactory.parseJavaExpressionString(exprString, currentPath); + } catch (JavaExpressionParseUtil.JavaExpressionParseException e) { continue; } - store.clearValue(recS); - store.insertValue(recS, sameLenAnno); + store.clearValue(je); + store.insertValue(je, sameLenAnno); } } @@ -185,18 +183,18 @@ private boolean isArrayLengthAccess(Node node) { * evaluates to true. The method gives a and b SameLen of each other in the store. */ private void refineEq(Node left, Node right, CFStore store) { - List receivers = new ArrayList<>(); + List exprs = new ArrayList<>(); List annos = new ArrayList<>(); for (Node internal : splitAssignments(left)) { - receivers.add(FlowExpressions.internalReprOf(analysis.getTypeFactory(), internal)); + exprs.add(JavaExpression.fromNode(analysis.getTypeFactory(), internal)); annos.add(getAnno(internal)); } for (Node internal : splitAssignments(right)) { - receivers.add(FlowExpressions.internalReprOf(analysis.getTypeFactory(), internal)); + exprs.add(JavaExpression.fromNode(analysis.getTypeFactory(), internal)); annos.add(getAnno(internal)); } - AnnotationMirror combinedSameLen = aTypeFactory.createCombinedSameLen(receivers, annos); + AnnotationMirror combinedSameLen = aTypeFactory.createCombinedSameLen(exprs, annos); propagateCombinedSameLen(combinedSameLen, left, store); } @@ -298,12 +296,12 @@ protected void addInformationFromPreconditions( AnnotationMirror newSameLen = aTypeFactory.createSameLen( Collections.singletonList(paramNames.get(index))); - Receiver otherParamRec = null; + JavaExpression otherParamRec = null; try { otherParamRec = - FlowExpressionParseUtil.internalReprOfVariable( + JavaExpressionParseUtil.fromVariableTree( aTypeFactory, paramTrees.get(otherParamIndex)); - } catch (FlowExpressionParseUtil.FlowExpressionParseException e) { + } catch (JavaExpressionParseUtil.JavaExpressionParseException e) { // do nothing } if (otherParamRec != null) { diff --git a/checker/src/main/java/org/checkerframework/checker/index/samelen/SameLenVisitor.java b/checker/src/main/java/org/checkerframework/checker/index/samelen/SameLenVisitor.java index b9d3065b5a..55dd926233 100644 --- a/checker/src/main/java/org/checkerframework/checker/index/samelen/SameLenVisitor.java +++ b/checker/src/main/java/org/checkerframework/checker/index/samelen/SameLenVisitor.java @@ -13,8 +13,7 @@ import org.checkerframework.common.basetype.BaseTypeChecker; import org.checkerframework.common.basetype.BaseTypeVisitor; import org.checkerframework.common.value.ValueCheckerUtils; -import org.checkerframework.dataflow.expression.FlowExpressions; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.javacutil.TreeUtils; @@ -41,7 +40,7 @@ protected void commonAssignmentCheck( && !(valueType.hasAnnotation(PolySameLen.class) && varType.hasAnnotation(PolySameLen.class))) { - Receiver rhs = FlowExpressions.internalReprOf(atypeFactory, (ExpressionTree) valueTree); + JavaExpression rhs = JavaExpression.fromTree(atypeFactory, (ExpressionTree) valueTree); if (rhs != null && SameLenAnnotatedTypeFactory.mayAppearInSameLen(rhs)) { String rhsExpr = rhs.toString(); AnnotationMirror am = valueType.getAnnotation(SameLen.class); diff --git a/checker/src/main/java/org/checkerframework/checker/index/searchindex/SearchIndexAnnotatedTypeFactory.java b/checker/src/main/java/org/checkerframework/checker/index/searchindex/SearchIndexAnnotatedTypeFactory.java index e961ebf4e0..fad2894285 100644 --- a/checker/src/main/java/org/checkerframework/checker/index/searchindex/SearchIndexAnnotatedTypeFactory.java +++ b/checker/src/main/java/org/checkerframework/checker/index/searchindex/SearchIndexAnnotatedTypeFactory.java @@ -67,7 +67,7 @@ protected QualifierHierarchy createQualifierHierarchy() { return new SearchIndexQualifierHierarchy(this.getSupportedTypeQualifiers(), elements); } - /** SearchIndexQualifierHierarchy */ + /** SearchIndexQualifierHierarchy. */ private final class SearchIndexQualifierHierarchy extends ElementQualifierHierarchy { /** diff --git a/checker/src/main/java/org/checkerframework/checker/index/searchindex/SearchIndexTransfer.java b/checker/src/main/java/org/checkerframework/checker/index/searchindex/SearchIndexTransfer.java index fd36c476a4..2fd02619e5 100644 --- a/checker/src/main/java/org/checkerframework/checker/index/searchindex/SearchIndexTransfer.java +++ b/checker/src/main/java/org/checkerframework/checker/index/searchindex/SearchIndexTransfer.java @@ -8,7 +8,7 @@ import org.checkerframework.common.value.ValueCheckerUtils; import org.checkerframework.dataflow.analysis.TransferInput; import org.checkerframework.dataflow.cfg.node.Node; -import org.checkerframework.dataflow.expression.FlowExpressions; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.framework.flow.CFAnalysis; import org.checkerframework.framework.flow.CFStore; import org.checkerframework.framework.flow.CFValue; @@ -65,8 +65,7 @@ private void refineSearchIndexToNegativeIndexFor( List arrays = ValueCheckerUtils.getValueOfAnnotationWithStringArgument(rightSI); AnnotationMirror nif = aTypeFactory.createNegativeIndexFor(arrays); - store.insertValue( - FlowExpressions.internalReprOf(analysis.getTypeFactory(), right), nif); + store.insertValue(JavaExpression.fromNode(analysis.getTypeFactory(), right), nif); } } } diff --git a/checker/src/main/java/org/checkerframework/checker/index/upperbound/OffsetEquation.java b/checker/src/main/java/org/checkerframework/checker/index/upperbound/OffsetEquation.java index e31d68fd0a..374330aa64 100644 --- a/checker/src/main/java/org/checkerframework/checker/index/upperbound/OffsetEquation.java +++ b/checker/src/main/java/org/checkerframework/checker/index/upperbound/OffsetEquation.java @@ -15,16 +15,15 @@ import org.checkerframework.dataflow.cfg.node.Node; import org.checkerframework.dataflow.cfg.node.NumericalAdditionNode; import org.checkerframework.dataflow.cfg.node.NumericalSubtractionNode; -import org.checkerframework.dataflow.expression.FlowExpressions; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.dataflow.expression.LocalVariable; import org.checkerframework.dataflow.expression.MethodCall; -import org.checkerframework.dataflow.expression.Receiver; import org.checkerframework.dataflow.expression.Unknown; import org.checkerframework.dataflow.expression.ValueLiteral; import org.checkerframework.framework.type.AnnotatedTypeFactory; -import org.checkerframework.framework.util.FlowExpressionParseUtil; -import org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionContext; -import org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionParseException; +import org.checkerframework.framework.util.JavaExpressionParseUtil; +import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionContext; +import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionParseException; import org.checkerframework.framework.util.dependenttypes.DependentTypesError; import org.checkerframework.javacutil.AnnotationProvider; import org.checkerframework.javacutil.TreeUtils; @@ -256,19 +255,19 @@ public boolean isNegativeOrZero() { * * @param factory the AnnotatedTypeFactory used to access elements annotations. It can be null. */ - private Integer evalConstantTerm(Receiver termReceiver, BaseAnnotatedTypeFactory factory) { - if (termReceiver instanceof ValueLiteral) { + private Integer evalConstantTerm(JavaExpression termExpr, BaseAnnotatedTypeFactory factory) { + if (termExpr instanceof ValueLiteral) { // Integer literal - Object value = ((ValueLiteral) termReceiver).getValue(); + Object value = ((ValueLiteral) termExpr).getValue(); if (value instanceof Integer) { return (Integer) value; } - } else if (termReceiver instanceof MethodCall) { + } else if (termExpr instanceof MethodCall) { // TODO: generalize // Length of string literal - MethodCall call = (MethodCall) termReceiver; + MethodCall call = (MethodCall) termExpr; if (call.getElement().getSimpleName().toString().equals("length")) { - Receiver callReceiver = call.getReceiver(); + JavaExpression callReceiver = call.getReceiver(); if (callReceiver instanceof ValueLiteral) { Object value = ((ValueLiteral) callReceiver).getValue(); if (value instanceof String) { @@ -276,8 +275,8 @@ private Integer evalConstantTerm(Receiver termReceiver, BaseAnnotatedTypeFactory } } } - } else if (factory != null && termReceiver instanceof LocalVariable) { - Element element = ((LocalVariable) termReceiver).getElement(); + } else if (factory != null && termExpr instanceof LocalVariable) { + Element element = ((LocalVariable) termExpr).getElement(); Long exactValue = ValueCheckerUtils.getExactValue( element, factory.getTypeFactoryOfSubchecker(ValueChecker.class)); @@ -300,19 +299,20 @@ private Integer evalConstantTerm(Receiver termReceiver, BaseAnnotatedTypeFactory private void standardizeAndViewpointAdaptExpressions( List terms, boolean subtract, - FlowExpressionContext context, + JavaExpressionContext context, TreePath scope, boolean useLocalScope, AnnotatedTypeFactory factory) - throws FlowExpressionParseException { + throws JavaExpressionParseException { // Standardize all terms and remove constants int length = terms.size(), j = 0; for (int i = 0; i < length; ++i) { String term = terms.get(i); - Receiver receiver = FlowExpressionParseUtil.parse(term, context, scope, useLocalScope); - Integer termConstant = evalConstantTerm(receiver, (BaseAnnotatedTypeFactory) factory); + JavaExpression termExpr = + JavaExpressionParseUtil.parse(term, context, scope, useLocalScope); + Integer termConstant = evalConstantTerm(termExpr, (BaseAnnotatedTypeFactory) factory); if (termConstant == null) { - terms.set(j, receiver.toString()); + terms.set(j, termExpr.toString()); ++j; } else if (subtract) { intValue -= termConstant; @@ -327,19 +327,19 @@ private void standardizeAndViewpointAdaptExpressions( /** * Standardizes and viewpoint-adapts the string terms based us the supplied context. * - * @param context a FlowExpressionContext + * @param context a JavaExpressionContext * @param scope local scope * @param useLocalScope whether or not local scope is used * @param factory an AnnotatedTypeFactory used for annotation accessing. It can be null. - * @throws FlowExpressionParseException if any term isn't able to be parsed this exception is + * @throws JavaExpressionParseException if any term isn't able to be parsed this exception is * thrown. If this happens, no string terms are changed. */ public void standardizeAndViewpointAdaptExpressions( - FlowExpressionContext context, + JavaExpressionContext context, TreePath scope, boolean useLocalScope, AnnotatedTypeFactory factory) - throws FlowExpressionParseException { + throws JavaExpressionParseException { standardizeAndViewpointAdaptExpressions( addedTerms, false, context, scope, useLocalScope, factory); @@ -350,15 +350,15 @@ public void standardizeAndViewpointAdaptExpressions( /** * Standardizes and viewpoint-adapts the string terms based us the supplied context. * - * @param context a FlowExpressionContext + * @param context a JavaExpressionContext * @param scope local scope * @param useLocalScope whether or not local scope is used - * @throws FlowExpressionParseException if any term isn't able to be parsed this exception is + * @throws JavaExpressionParseException if any term isn't able to be parsed this exception is * thrown. If this happens, no string terms are changed. */ public void standardizeAndViewpointAdaptExpressions( - FlowExpressionContext context, TreePath scope, boolean useLocalScope) - throws FlowExpressionParseException { + JavaExpressionContext context, TreePath scope, boolean useLocalScope) + throws JavaExpressionParseException { standardizeAndViewpointAdaptExpressions(context, scope, useLocalScope, null); } @@ -535,8 +535,8 @@ public static OffsetEquation createOffsetFromNodesValue( * on the value of op. * *

Otherwise the return equation is created by converting the node to a {@link - * org.checkerframework.dataflow.expression.Receiver} and then added as a term to the returned - * equation. If op is '-' then it is a subtracted term. + * org.checkerframework.dataflow.expression.JavaExpression} and then added as a term to the + * returned equation. If op is '-' then it is a subtracted term. * * @param node the Node from which to create an offset equation * @param factory an AnnotationTypeFactory @@ -553,8 +553,8 @@ public static OffsetEquation createOffsetFromNode( private static void createOffsetFromNode( Node node, AnnotationProvider factory, OffsetEquation eq, char op) { - Receiver r = FlowExpressions.internalReprOf(factory, node); - if (r instanceof Unknown || r == null) { + JavaExpression je = JavaExpression.fromNode(factory, node); + if (je instanceof Unknown || je == null) { if (node instanceof NumericalAdditionNode) { createOffsetFromNode( ((NumericalAdditionNode) node).getLeftOperand(), factory, eq, op); @@ -570,7 +570,7 @@ private static void createOffsetFromNode( eq.error = node.toString(); } } else { - eq.addTerm(op, r.toString()); + eq.addTerm(op, je.toString()); } } } diff --git a/checker/src/main/java/org/checkerframework/checker/index/upperbound/UpperBoundAnnotatedTypeFactory.java b/checker/src/main/java/org/checkerframework/checker/index/upperbound/UpperBoundAnnotatedTypeFactory.java index 3d447f1e66..8907991f2c 100644 --- a/checker/src/main/java/org/checkerframework/checker/index/upperbound/UpperBoundAnnotatedTypeFactory.java +++ b/checker/src/main/java/org/checkerframework/checker/index/upperbound/UpperBoundAnnotatedTypeFactory.java @@ -55,7 +55,7 @@ import org.checkerframework.common.value.ValueCheckerUtils; import org.checkerframework.common.value.qual.BottomVal; import org.checkerframework.dataflow.cfg.node.Node; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.framework.flow.CFAbstractStore; import org.checkerframework.framework.flow.CFStore; import org.checkerframework.framework.flow.CFValue; @@ -67,7 +67,7 @@ import org.checkerframework.framework.type.treeannotator.TreeAnnotator; import org.checkerframework.framework.type.typeannotator.ListTypeAnnotator; import org.checkerframework.framework.type.typeannotator.TypeAnnotator; -import org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionParseException; +import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionParseException; import org.checkerframework.framework.util.dependenttypes.DependentTypesHelper; import org.checkerframework.javacutil.AnnotationBuilder; import org.checkerframework.javacutil.AnnotationUtils; @@ -118,13 +118,13 @@ public class UpperBoundAnnotatedTypeFactory extends BaseAnnotatedTypeFactory { public UpperBoundAnnotatedTypeFactory(BaseTypeChecker checker) { super(checker); - addAliasedAnnotation(IndexFor.class, LTLengthOf.class, true); - addAliasedAnnotation(IndexOrLow.class, LTLengthOf.class, true); - addAliasedAnnotation(IndexOrHigh.class, LTEqLengthOf.class, true); - addAliasedAnnotation(SearchIndexFor.class, LTLengthOf.class, true); - addAliasedAnnotation(NegativeIndexFor.class, LTLengthOf.class, true); - addAliasedAnnotation(LengthOf.class, LTEqLengthOf.class, true); - addAliasedAnnotation(PolyIndex.class, POLY); + addAliasedTypeAnnotation(IndexFor.class, LTLengthOf.class, true); + addAliasedTypeAnnotation(IndexOrLow.class, LTLengthOf.class, true); + addAliasedTypeAnnotation(IndexOrHigh.class, LTEqLengthOf.class, true); + addAliasedTypeAnnotation(SearchIndexFor.class, LTLengthOf.class, true); + addAliasedTypeAnnotation(NegativeIndexFor.class, LTLengthOf.class, true); + addAliasedTypeAnnotation(LengthOf.class, LTEqLengthOf.class, true); + addAliasedTypeAnnotation(PolyIndex.class, POLY); imf = new IndexMethodIdentifier(this); @@ -796,24 +796,24 @@ private UBQualifier fromLessThanOrEqual( Tree tree, TreePath treePath, List lessThanExpressions) { UBQualifier ubQualifier = null; for (String expression : lessThanExpressions) { - Pair receiverAndOffset; + Pair exprAndOffset; try { - receiverAndOffset = - getReceiverAndOffsetFromJavaExpressionString(expression, treePath); - } catch (FlowExpressionParseException e) { - receiverAndOffset = null; + exprAndOffset = + getExpressionAndOffsetFromJavaExpressionString(expression, treePath); + } catch (JavaExpressionParseException e) { + exprAndOffset = null; } - if (receiverAndOffset == null) { + if (exprAndOffset == null) { continue; } - Receiver receiver = receiverAndOffset.first; - String offset = receiverAndOffset.second; + JavaExpression je = exprAndOffset.first; + String offset = exprAndOffset.second; - if (!CFAbstractStore.canInsertReceiver(receiver)) { + if (!CFAbstractStore.canInsertJavaExpression(je)) { continue; } CFStore store = getStoreBefore(tree); - CFValue value = store.getValue(receiver); + CFValue value = store.getValue(je); if (value != null && value.getAnnotations().size() == 1) { UBQualifier newUBQ = UBQualifier.createUBQualifier( diff --git a/checker/src/main/java/org/checkerframework/checker/index/upperbound/UpperBoundTransfer.java b/checker/src/main/java/org/checkerframework/checker/index/upperbound/UpperBoundTransfer.java index 773009ebad..0d3d6d9ae2 100644 --- a/checker/src/main/java/org/checkerframework/checker/index/upperbound/UpperBoundTransfer.java +++ b/checker/src/main/java/org/checkerframework/checker/index/upperbound/UpperBoundTransfer.java @@ -32,9 +32,8 @@ import org.checkerframework.dataflow.cfg.node.NumericalSubtractionNode; import org.checkerframework.dataflow.cfg.node.TypeCastNode; import org.checkerframework.dataflow.expression.FieldAccess; -import org.checkerframework.dataflow.expression.FlowExpressions; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.dataflow.expression.MethodCall; -import org.checkerframework.dataflow.expression.Receiver; import org.checkerframework.dataflow.util.NodeUtils; import org.checkerframework.framework.flow.CFAbstractStore; import org.checkerframework.framework.flow.CFAnalysis; @@ -42,7 +41,7 @@ import org.checkerframework.framework.flow.CFValue; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.QualifierHierarchy; -import org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionContext; +import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionContext; /** * Contains the transfer functions for the upper bound type system, a part of the Index Checker. @@ -141,16 +140,16 @@ public TransferResult visitAssignment( Node dim = acNode.getDimension(0); UBQualifier previousQualifier = getUBQualifier(dim, in); - Receiver arrayRec = - FlowExpressions.internalReprOf(analysis.getTypeFactory(), node.getTarget()); - String arrayString = arrayRec.toString(); + JavaExpression arrayExpr = + JavaExpression.fromNode(analysis.getTypeFactory(), node.getTarget()); + String arrayString = arrayExpr.toString(); LessThanLengthOf newInfo = (LessThanLengthOf) UBQualifier.createUBQualifier(arrayString, "-1"); UBQualifier combined = previousQualifier.glb(newInfo); AnnotationMirror newAnno = atypeFactory.convertUBQualifierToAnnotation(combined); - Receiver dimRec = FlowExpressions.internalReprOf(analysis.getTypeFactory(), dim); - result.getRegularStore().insertValue(dimRec, newAnno); + JavaExpression dimExpr = JavaExpression.fromNode(analysis.getTypeFactory(), dim); + result.getRegularStore().insertValue(dimExpr, newAnno); propagateToOperands(newInfo, dim, in, result.getRegularStore()); } return result; @@ -209,8 +208,8 @@ private void propagateToMultiplicationOperand( } UBQualifier qual = getUBQualifier(node, in); UBQualifier newQual = qual.glb(typeOfMultiplication); - Receiver rec = FlowExpressions.internalReprOf(atypeFactory, node); - store.insertValue(rec, atypeFactory.convertUBQualifierToAnnotation(newQual)); + JavaExpression je = JavaExpression.fromNode(atypeFactory, node); + store.insertValue(je, atypeFactory.convertUBQualifierToAnnotation(newQual)); } } @@ -238,8 +237,8 @@ private void propagateToSubtractionOperands( UBQualifier newInfo = typeOfSubtraction.minusOffset(node.getRightOperand(), atypeFactory); UBQualifier newLeft = left.glb(newInfo); - Receiver leftRec = FlowExpressions.internalReprOf(atypeFactory, node.getLeftOperand()); - store.insertValue(leftRec, atypeFactory.convertUBQualifierToAnnotation(newLeft)); + JavaExpression leftJe = JavaExpression.fromNode(atypeFactory, node.getLeftOperand()); + store.insertValue(leftJe, atypeFactory.convertUBQualifierToAnnotation(newLeft)); } /** @@ -269,8 +268,8 @@ private void propagateToAdditionOperand( } else if (atypeFactory.hasLowerBoundTypeByClass(other, NonNegative.class)) { newQual = newQual.glb(typeOfAddition); } - Receiver operandRec = FlowExpressions.internalReprOf(atypeFactory, operand); - store.insertValue(operandRec, atypeFactory.convertUBQualifierToAnnotation(newQual)); + JavaExpression operandJe = JavaExpression.fromNode(atypeFactory, operand); + store.insertValue(operandJe, atypeFactory.convertUBQualifierToAnnotation(newQual)); } /** @@ -298,8 +297,8 @@ protected void refineGT( refineSubtrahendWithOffset(larger, smaller, true, in, store); - Receiver rightRec = FlowExpressions.internalReprOf(analysis.getTypeFactory(), smaller); - store.insertValue(rightRec, atypeFactory.convertUBQualifierToAnnotation(refinedRight)); + JavaExpression rightJe = JavaExpression.fromNode(analysis.getTypeFactory(), smaller); + store.insertValue(rightJe, atypeFactory.convertUBQualifierToAnnotation(refinedRight)); } /** @@ -324,8 +323,8 @@ protected void refineGTE( refineSubtrahendWithOffset(left, right, false, in, store); - Receiver rightRec = FlowExpressions.internalReprOf(analysis.getTypeFactory(), right); - store.insertValue(rightRec, atypeFactory.convertUBQualifierToAnnotation(refinedRight)); + JavaExpression rightJe = JavaExpression.fromNode(analysis.getTypeFactory(), right); + store.insertValue(rightJe, atypeFactory.convertUBQualifierToAnnotation(refinedRight)); } /** @@ -363,8 +362,8 @@ private void refineSubtrahendWithOffset( minuendQual .plusOffset(offsetNode, atypeFactory) .plusOffset(offsetAddOne ? 1 : 0)); - Receiver subtrahendRec = FlowExpressions.internalReprOf(atypeFactory, subtrahend); - store.insertValue(subtrahendRec, atypeFactory.convertUBQualifierToAnnotation(newQual)); + JavaExpression subtrahendJe = JavaExpression.fromNode(atypeFactory, subtrahend); + store.insertValue(subtrahendJe, atypeFactory.convertUBQualifierToAnnotation(newQual)); } } @@ -409,14 +408,14 @@ private void refineEq( List internalsRight = splitAssignments(right); for (Node internal : internalsRight) { - Receiver rightRec = FlowExpressions.internalReprOf(analysis.getTypeFactory(), internal); - store.insertValue(rightRec, glbAnno); + JavaExpression rightJe = JavaExpression.fromNode(analysis.getTypeFactory(), internal); + store.insertValue(rightJe, glbAnno); } List internalsLeft = splitAssignments(left); for (Node internal : internalsLeft) { - Receiver leftRec = FlowExpressions.internalReprOf(analysis.getTypeFactory(), internal); - store.insertValue(leftRec, glbAnno); + JavaExpression leftJe = JavaExpression.fromNode(analysis.getTypeFactory(), internal); + store.insertValue(leftJe, glbAnno); } } @@ -429,9 +428,8 @@ private void refineEq( private void refineNeqSequenceLength( Node lengthAccess, Node otherNode, AnnotationMirror otherNodeAnno, CFStore store) { - Receiver receiver = null; - // If lengthAccess is "receiver.length - c" where c is an integer constant, stores c - // into lengthOffset + // If lengthAccess is "receiver.length - c" where c is an integer constant, + // then lengthOffset is "c". int lengthOffset = 0; if (lengthAccess instanceof NumericalSubtractionNode) { NumericalSubtractionNode subtraction = (NumericalSubtractionNode) lengthAccess; @@ -450,14 +448,15 @@ private void refineNeqSequenceLength( } } + JavaExpression receiver = null; if (NodeUtils.isArrayLengthFieldAccess(lengthAccess)) { FieldAccess fa = - FlowExpressions.internalReprOfFieldAccess( + JavaExpression.fromNodeFieldAccess( atypeFactory, (FieldAccessNode) lengthAccess); receiver = fa.getReceiver(); } else if (atypeFactory.getMethodIdentifier().isLengthOfMethodInvocation(lengthAccess)) { - Receiver ma = FlowExpressions.internalReprOf(atypeFactory, lengthAccess); + JavaExpression ma = JavaExpression.fromNode(atypeFactory, lengthAccess); if (ma instanceof MethodCall) { receiver = ((MethodCall) ma).getReceiver(); } @@ -473,10 +472,10 @@ private void refineNeqSequenceLength( UBQualifier.createUBQualifier(sequence, Integer.toString(lengthOffset)); otherQualifier = otherQualifier.glb(newQualifier); for (Node internal : splitAssignments(otherNode)) { - Receiver leftRec = - FlowExpressions.internalReprOf(analysis.getTypeFactory(), internal); + JavaExpression leftJe = + JavaExpression.fromNode(analysis.getTypeFactory(), internal); store.insertValue( - leftRec, atypeFactory.convertUBQualifierToAnnotation(otherQualifier)); + leftJe, atypeFactory.convertUBQualifierToAnnotation(otherQualifier)); } } } @@ -595,10 +594,10 @@ public TransferResult visitNumericalSubtraction( || subtractionResult.hasSequenceWithOffset(b, 0)) { TreePath currentPath = this.atypeFactory.getPath(n.getTree()); - Receiver rec; + JavaExpression je; try { - rec = - UpperBoundVisitor.getReceiverFromJavaExpressionString( + je = + UpperBoundVisitor.parseJavaExpressionString( b, atypeFactory, currentPath); } catch (NullPointerException npe) { // I have no idea why this seems to happen only on a few JDK classes. @@ -611,22 +610,22 @@ public TransferResult visitNumericalSubtraction( return createTransferResult(n, in, leftWithOffset); } - FlowExpressionContext context = - Subsequence.getContextFromReceiver(rec, atypeFactory.getContext()); + JavaExpressionContext context = + Subsequence.getContextFromJavaExpression(je, atypeFactory.getContext()); Subsequence subsequence = Subsequence.getSubsequenceFromReceiver( - rec, atypeFactory, currentPath, context); + je, atypeFactory, currentPath, context); if (subsequence != null) { String from = subsequence.from; String to = subsequence.to; String a = subsequence.array; - Receiver leftOp = - FlowExpressions.internalReprOf(atypeFactory, n.getLeftOperand()); - Receiver rightOp = - FlowExpressions.internalReprOf(atypeFactory, n.getRightOperand()); + JavaExpression leftOp = + JavaExpression.fromNode(atypeFactory, n.getLeftOperand()); + JavaExpression rightOp = + JavaExpression.fromNode(atypeFactory, n.getRightOperand()); if (rightOp.toString().equals(from)) { AnnotationMirror lessThanType = @@ -662,7 +661,10 @@ public TransferResult visitNumericalSubtraction( * @param n sequence length access node */ private TransferResult visitLengthAccess( - Node n, TransferInput in, Receiver sequenceRec, Tree sequenceTree) { + Node n, + TransferInput in, + JavaExpression sequenceJe, + Tree sequenceTree) { if (sequenceTree == null) { return null; } @@ -673,8 +675,8 @@ private TransferResult visitLengthAccess( ? new ArrayList<>() : ValueCheckerUtils.getValueOfAnnotationWithStringArgument(sameLenAnno); - if (!sameLenSequences.contains(sequenceRec.toString())) { - sameLenSequences.add(sequenceRec.toString()); + if (!sameLenSequences.contains(sequenceJe.toString())) { + sameLenSequences.add(sequenceJe.toString()); } ArrayList offsets = new ArrayList<>(sameLenSequences.size()); @@ -682,7 +684,7 @@ private TransferResult visitLengthAccess( offsets.add("-1"); } - if (CFAbstractStore.canInsertReceiver(sequenceRec)) { + if (CFAbstractStore.canInsertJavaExpression(sequenceJe)) { UBQualifier qualifier = UBQualifier.createUBQualifier(sameLenSequences, offsets); UBQualifier previous = getUBQualifier(n, in); return createTransferResult(n, in, qualifier.glb(previous)); @@ -699,10 +701,10 @@ private TransferResult visitLengthAccess( public TransferResult visitFieldAccess( FieldAccessNode n, TransferInput in) { if (NodeUtils.isArrayLengthFieldAccess(n)) { - FieldAccess arrayLength = FlowExpressions.internalReprOfFieldAccess(atypeFactory, n); - Receiver arrayRec = arrayLength.getReceiver(); + FieldAccess arrayLength = JavaExpression.fromNodeFieldAccess(atypeFactory, n); + JavaExpression arrayJe = arrayLength.getReceiver(); Tree arrayTree = n.getReceiver().getTree(); - TransferResult result = visitLengthAccess(n, in, arrayRec, arrayTree); + TransferResult result = visitLengthAccess(n, in, arrayJe, arrayTree); if (result != null) { return result; } @@ -719,14 +721,14 @@ public TransferResult visitMethodInvocation( MethodInvocationNode n, TransferInput in) { if (atypeFactory.getMethodIdentifier().isLengthOfMethodInvocation(n)) { - Receiver stringLength = FlowExpressions.internalReprOf(atypeFactory, n); + JavaExpression stringLength = JavaExpression.fromNode(atypeFactory, n); if (stringLength instanceof MethodCall) { - Receiver receiverRec = ((MethodCall) stringLength).getReceiver(); + JavaExpression receiverJe = ((MethodCall) stringLength).getReceiver(); Tree receiverTree = n.getTarget().getReceiver().getTree(); // receiverTree is null when the receiver is implicit "this". if (receiverTree != null) { TransferResult result = - visitLengthAccess(n, in, receiverRec, receiverTree); + visitLengthAccess(n, in, receiverJe, receiverTree); if (result != null) { return result; } @@ -783,10 +785,10 @@ private UBQualifier getUBQualifierForAddition(Node n, TransferInput in) { QualifierHierarchy hierarchy = analysis.getTypeFactory().getQualifierHierarchy(); - Receiver rec = FlowExpressions.internalReprOf(atypeFactory, n); + JavaExpression je = JavaExpression.fromNode(atypeFactory, n); CFValue value = null; - if (CFAbstractStore.canInsertReceiver(rec)) { - value = in.getRegularStore().getValue(rec); + if (CFAbstractStore.canInsertJavaExpression(je)) { + value = in.getRegularStore().getValue(je); } if (value == null) { value = analysis.getValue(n); diff --git a/checker/src/main/java/org/checkerframework/checker/index/upperbound/UpperBoundVisitor.java b/checker/src/main/java/org/checkerframework/checker/index/upperbound/UpperBoundVisitor.java index 4c0c772695..025b3e4498 100644 --- a/checker/src/main/java/org/checkerframework/checker/index/upperbound/UpperBoundVisitor.java +++ b/checker/src/main/java/org/checkerframework/checker/index/upperbound/UpperBoundVisitor.java @@ -23,17 +23,16 @@ import org.checkerframework.common.value.ValueAnnotatedTypeFactory; import org.checkerframework.common.value.ValueCheckerUtils; import org.checkerframework.dataflow.expression.FieldAccess; -import org.checkerframework.dataflow.expression.FlowExpressions; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.dataflow.expression.LocalVariable; -import org.checkerframework.dataflow.expression.Receiver; import org.checkerframework.dataflow.expression.ThisReference; import org.checkerframework.dataflow.expression.ValueLiteral; import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType; -import org.checkerframework.framework.util.FlowExpressionParseUtil; -import org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionContext; -import org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionParseException; +import org.checkerframework.framework.util.JavaExpressionParseUtil; +import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionContext; +import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionParseException; import org.checkerframework.javacutil.AnnotationUtils; import org.checkerframework.javacutil.ElementUtils; import org.checkerframework.javacutil.Pair; @@ -95,7 +94,7 @@ public Void visitAnnotation(AnnotationTree node, Void p) { } } } else if (atypeFactory.areSameByClass(anno, HasSubsequence.class)) { - // Check that the arguments to a HasSubsequence annotation are valid flow expressions, + // Check that the arguments to a HasSubsequence annotation are valid JavaExpressions, // and issue an error if one of them is not. String seq = AnnotationUtils.getElementValue(anno, "subsequence", String.class, true); @@ -104,8 +103,8 @@ public Void visitAnnotation(AnnotationTree node, Void p) { // check that each expression is parseable in this context ClassTree enclosingClass = TreeUtils.enclosingClass(getCurrentPath()); - FlowExpressionContext context = - FlowExpressionContext.buildContextForClassDeclaration(enclosingClass, checker); + JavaExpressionContext context = + JavaExpressionContext.buildContextForClassDeclaration(enclosingClass, checker); checkEffectivelyFinalAndParsable(seq, context, node); checkEffectivelyFinalAndParsable(from, context, node); checkEffectivelyFinalAndParsable(to, context, node); @@ -114,28 +113,32 @@ public Void visitAnnotation(AnnotationTree node, Void p) { } /** - * Determines if the Java expression named by s is effectively final at the current program - * location. + * Reports an error if the Java expression named by s is not effectively final at the current + * program location. + * + * @param s a Java expression + * @param context the JavaExpression context + * @param tree the tree at which to possibly report an error */ private void checkEffectivelyFinalAndParsable( - String s, FlowExpressionContext context, Tree error) { - Receiver rec; + String s, JavaExpressionContext context, Tree tree) { + JavaExpression je; try { - rec = FlowExpressionParseUtil.parse(s, context, getCurrentPath(), false); - } catch (FlowExpressionParseException e) { - checker.report(error, e.getDiagMessage()); + je = JavaExpressionParseUtil.parse(s, context, getCurrentPath(), false); + } catch (JavaExpressionParseException e) { + checker.report(tree, e.getDiagMessage()); return; } Element element = null; - if (rec instanceof LocalVariable) { - element = ((LocalVariable) rec).getElement(); - } else if (rec instanceof FieldAccess) { - element = ((FieldAccess) rec).getField(); - } else if (rec instanceof ThisReference || rec instanceof ValueLiteral) { + if (je instanceof LocalVariable) { + element = ((LocalVariable) je).getElement(); + } else if (je instanceof FieldAccess) { + element = ((FieldAccess) je).getField(); + } else if (je instanceof ThisReference || je instanceof ValueLiteral) { return; } if (element == null || !ElementUtils.isEffectivelyFinal(element)) { - checker.reportError(error, NOT_FINAL, rec); + checker.reportError(tree, NOT_FINAL, je); } } @@ -146,7 +149,7 @@ private void checkEffectivelyFinalAndParsable( */ private void visitAccess(ExpressionTree indexTree, ExpressionTree arrTree) { - String arrName = FlowExpressions.internalReprOf(this.atypeFactory, arrTree).toString(); + String arrName = JavaExpression.fromTree(this.atypeFactory, arrTree).toString(); LessThanLengthOf lhsQual = (LessThanLengthOf) UBQualifier.createUBQualifier(arrName, "0"); if (relaxedCommonAssignmentCheck(lhsQual, indexTree) || checkMinLen(indexTree, arrTree)) { return; @@ -205,7 +208,7 @@ protected void commonAssignmentCheck( anm = atypeFactory.getAnnotationMirrorFromJavaExpressionString( subSeq.to, varTree, getCurrentPath()); - } catch (FlowExpressionParseException e) { + } catch (JavaExpressionParseException e) { anm = null; } @@ -321,48 +324,46 @@ private boolean relaxedCommonAssignment(AnnotatedTypeMirror varType, ExpressionT /** * Fetches a receiver and an offset from a String using the passed type factory. Returns null if - * there is a parse exception. This wraps - * GenericAnnotatedTypeFactory#getReceiverFromJavaExpressionString. + * there is a parse exception. This wraps GenericAnnotatedTypeFactory#parseJavaExpressionString. * - *

This is useful for expressions like "n+1", for which {@link - * #getReceiverFromJavaExpressionString} returns null because the whole expression is not a - * receiver. + *

This is useful for expressions like "n+1", for which {@link #parseJavaExpressionString} + * returns null because the whole expression is not a receiver. */ - static Pair getReceiverAndOffsetFromJavaExpressionString( + static Pair getExpressionAndOffsetFromJavaExpressionString( String s, UpperBoundAnnotatedTypeFactory atypeFactory, TreePath currentPath) { Pair p = AnnotatedTypeFactory.getExpressionAndOffset(s); - Receiver rec = getReceiverFromJavaExpressionString(p.first, atypeFactory, currentPath); - if (rec == null) { + JavaExpression je = parseJavaExpressionString(p.first, atypeFactory, currentPath); + if (je == null) { return null; } - return Pair.of(rec, p.second); + return Pair.of(je, p.second); } /** * Fetches a receiver from a String using the passed type factory. Returns null if there is a - * parse exception -- that is, if the string does not represent an expression for a Receiver. - * For example, the expression "n+1" does not represent a Receiver. + * parse exception -- that is, if the string does not represent an expression for a + * JavaExpression. For example, the expression "n+1" does not represent a JavaExpression. * - *

This wraps GenericAnnotatedTypeFactory#getReceiverFromJavaExpressionString. + *

This wraps GenericAnnotatedTypeFactory#parseJavaExpressionString. */ - static Receiver getReceiverFromJavaExpressionString( + static JavaExpression parseJavaExpressionString( String s, UpperBoundAnnotatedTypeFactory atypeFactory, TreePath currentPath) { - Receiver rec; + JavaExpression result; try { - rec = atypeFactory.getReceiverFromJavaExpressionString(s, currentPath); - } catch (FlowExpressionParseException e) { - rec = null; + result = atypeFactory.parseJavaExpressionString(s, currentPath); + } catch (JavaExpressionParseException e) { + result = null; } - return rec; + return result; } /** * Given a Java expression, returns the additive inverse, as a String. Assumes that - * FlowExpressions do not contain multiplication. + * JavaExpressions do not contain multiplication. */ - private String negateString(String s, FlowExpressionContext context) { + private String negateString(String s, JavaExpressionContext context) { return Subsequence.negateString(s, getCurrentPath(), context); } @@ -471,12 +472,13 @@ private UBQualifier processSubsequenceForLHS(LessThanLengthOf varLtlQual, UBQual // check is lhsSeq is an actual LTL if (varLtlQual.hasSequenceWithOffset(lhsSeq, 0)) { - Receiver rec = - getReceiverFromJavaExpressionString(lhsSeq, atypeFactory, getCurrentPath()); - FlowExpressionContext context = Subsequence.getContextFromReceiver(rec, checker); + JavaExpression lhsSeqExpr = + parseJavaExpressionString(lhsSeq, atypeFactory, getCurrentPath()); + JavaExpressionContext context = + Subsequence.getContextFromJavaExpression(lhsSeqExpr, checker); Subsequence subSeq = Subsequence.getSubsequenceFromReceiver( - rec, atypeFactory, getCurrentPath(), context); + lhsSeqExpr, atypeFactory, getCurrentPath(), context); if (subSeq != null) { String from = subSeq.from; diff --git a/checker/src/main/java/org/checkerframework/checker/initialization/InitializationAnnotatedTypeFactory.java b/checker/src/main/java/org/checkerframework/checker/initialization/InitializationAnnotatedTypeFactory.java index 8b48be40a3..adb5c313df 100644 --- a/checker/src/main/java/org/checkerframework/checker/initialization/InitializationAnnotatedTypeFactory.java +++ b/checker/src/main/java/org/checkerframework/checker/initialization/InitializationAnnotatedTypeFactory.java @@ -56,6 +56,7 @@ import org.checkerframework.javacutil.AnnotationBuilder; import org.checkerframework.javacutil.AnnotationUtils; import org.checkerframework.javacutil.ElementUtils; +import org.checkerframework.javacutil.Pair; import org.checkerframework.javacutil.TreeUtils; import org.checkerframework.javacutil.TypesUtils; @@ -534,38 +535,74 @@ protected AnnotationMirror getUnderInitializationAnnotationOfSuperType(TypeMirro } /** - * Returns the (non-static) fields that have the invariant annotation and are not yet - * initialized in a given store. + * Returns the fields that are not yet initialized in a given store. The result is a pair of + * lists: + * + *

    + *
  • fields that are not yet initialized and have the invariant annotation + *
  • fields that are not yet initialized and do not have the invariant annotation + *
+ * + * @param store a store + * @param path the current path, used to determine the current class + * @param isStatic whether to report static fields or instance fields + * @param receiverAnnotations the annotations on the receiver + * @return the fields that are not yet initialized in a given store (a pair of lists) */ - public List getUninitializedInvariantFields( + public Pair, List> getUninitializedFields( Store store, TreePath path, boolean isStatic, List receiverAnnotations) { ClassTree currentClass = TreeUtils.enclosingClass(path); List fields = InitializationChecker.getAllFields(currentClass); - List violatingFields = new ArrayList<>(); + List uninitWithInvariantAnno = new ArrayList<>(); + List uninitWithoutInvariantAnno = new ArrayList<>(); for (VariableTree field : fields) { if (isUnused(field, receiverAnnotations)) { continue; // don't consider unused fields } VariableElement fieldElem = TreeUtils.elementFromDeclaration(field); if (ElementUtils.isStatic(fieldElem) == isStatic) { - // Does this field need to satisfy the invariant? - if (hasFieldInvariantAnnotation(field)) { - // Has the field been initialized? - if (!store.isFieldInitialized(fieldElem)) { - violatingFields.add(field); + // Has the field been initialized? + if (!store.isFieldInitialized(fieldElem)) { + // Does this field need to satisfy the invariant? + if (hasFieldInvariantAnnotation(field)) { + uninitWithInvariantAnno.add(field); + } else { + uninitWithoutInvariantAnno.add(field); } } } } - return violatingFields; + return Pair.of(uninitWithInvariantAnno, uninitWithoutInvariantAnno); } /** - * Returns the (non-static) fields that have the invariant annotation and are initialized in a - * given store. + * Returns the fields that have the invariant annotation and are not yet initialized in a given + * store. + * + * @param store a store + * @param path the current path, used to determine the current class + * @param isStatic whether to report static fields or instance fields + * @param receiverAnnotations the annotations on the receiver + * @return the fields that have the invariant annotation and are not yet initialized in a given + * store (a pair of lists) + */ + public final List getUninitializedInvariantFields( + Store store, + TreePath path, + boolean isStatic, + List receiverAnnotations) { + return getUninitializedFields(store, path, isStatic, receiverAnnotations).first; + } + + /** + * Returns the fields that have the invariant annotation and are initialized in a given store. + * + * @param store a store + * @param path the current path; used to compute the current class + * @return the fields that have the invariant annotation and are initialized in a given store */ public List getInitializedInvariantFields(Store store, TreePath path) { // TODO: Instead of passing the TreePath around, can we use diff --git a/checker/src/main/java/org/checkerframework/checker/initialization/InitializationStore.java b/checker/src/main/java/org/checkerframework/checker/initialization/InitializationStore.java index 0b0f692716..0d12c921f9 100644 --- a/checker/src/main/java/org/checkerframework/checker/initialization/InitializationStore.java +++ b/checker/src/main/java/org/checkerframework/checker/initialization/InitializationStore.java @@ -2,8 +2,10 @@ import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; import javax.lang.model.element.VariableElement; @@ -11,7 +13,7 @@ import org.checkerframework.dataflow.cfg.visualize.CFGVisualizer; import org.checkerframework.dataflow.expression.ClassName; import org.checkerframework.dataflow.expression.FieldAccess; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.dataflow.expression.ThisReference; import org.checkerframework.framework.flow.CFAbstractAnalysis; import org.checkerframework.framework.flow.CFAbstractStore; @@ -19,6 +21,7 @@ import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.QualifierHierarchy; import org.checkerframework.javacutil.AnnotationUtils; +import org.plumelib.util.ToStringComparator; /** * A store that extends {@code CFAbstractStore} and additionally tracks which fields of the 'self' @@ -47,7 +50,7 @@ public InitializationStore(CFAbstractAnalysis analysis, boolean sequent * initialized. */ @Override - public void insertValue(Receiver r, V value) { + public void insertValue(JavaExpression je, V value) { if (value == null) { // No need to insert a null abstract value because it represents // top and top is also the default value. @@ -60,27 +63,27 @@ public void insertValue(Receiver r, V value) { AnnotationMirror invariantAnno = atypeFactory.getFieldInvariantAnnotation(); // Remember fields that have the 'invariant' annotation in the store. - if (r instanceof FieldAccess) { - FieldAccess fieldAccess = (FieldAccess) r; - if (!fieldValues.containsKey(r)) { + if (je instanceof FieldAccess) { + FieldAccess fieldAccess = (FieldAccess) je; + if (!fieldValues.containsKey(je)) { Set declaredAnnos = atypeFactory.getAnnotatedType(fieldAccess.getField()).getAnnotations(); if (AnnotationUtils.containsSame(declaredAnnos, invariantAnno)) { if (!invariantFields.containsKey(fieldAccess)) { invariantFields.put( fieldAccess, - analysis.createSingleAnnotationValue(invariantAnno, r.getType())); + analysis.createSingleAnnotationValue(invariantAnno, je.getType())); } } } } - super.insertValue(r, value); + super.insertValue(je, value); for (AnnotationMirror a : value.getAnnotations()) { if (qualifierHierarchy.isSubtype(a, invariantAnno)) { - if (r instanceof FieldAccess) { - FieldAccess fa = (FieldAccess) r; + if (je instanceof FieldAccess) { + FieldAccess fa = (FieldAccess) je; if (fa.getReceiver() instanceof ThisReference || fa.getReceiver() instanceof ClassName) { addInitializedField(fa.getField()); @@ -222,24 +225,30 @@ public S leastUpperBound(S other) { @Override protected String internalVisualize(CFGVisualizer viz) { String superVisualize = super.internalVisualize(viz); + String initializedVisualize = + viz.visualizeStoreKeyVal( + "initialized fields", ToStringComparator.sorted(initializedFields)); + List invariantVars = + invariantFields.keySet().stream() + .map(FieldAccess::getField) + .collect(Collectors.toList()); + String invariantVisualize = + viz.visualizeStoreKeyVal( + "invariant fields", ToStringComparator.sorted(invariantVars)); + if (superVisualize.isEmpty()) { - return String.join( - viz.getSeparator(), - viz.visualizeStoreKeyVal("initialized fields", initializedFields), - viz.visualizeStoreKeyVal("invariant fields", invariantFields)); + return String.join(viz.getSeparator(), initializedVisualize, invariantVisualize); } else { return String.join( - viz.getSeparator(), - super.internalVisualize(viz), - viz.visualizeStoreKeyVal("initialized fields", initializedFields), - viz.visualizeStoreKeyVal("invariant fields", invariantFields)); + viz.getSeparator(), superVisualize, initializedVisualize, invariantVisualize); } } - public Map getFieldValues() { - return fieldValues; - } - + /** + * Returns the analysis associated with this store. + * + * @return the analysis associated with this store + */ public CFAbstractAnalysis getAnalysis() { return analysis; } diff --git a/checker/src/main/java/org/checkerframework/checker/initialization/InitializationTransfer.java b/checker/src/main/java/org/checkerframework/checker/initialization/InitializationTransfer.java index a9348e0d93..e278eb8bd4 100644 --- a/checker/src/main/java/org/checkerframework/checker/initialization/InitializationTransfer.java +++ b/checker/src/main/java/org/checkerframework/checker/initialization/InitializationTransfer.java @@ -20,10 +20,9 @@ import org.checkerframework.dataflow.cfg.node.FieldAccessNode; import org.checkerframework.dataflow.cfg.node.MethodInvocationNode; import org.checkerframework.dataflow.cfg.node.Node; -import org.checkerframework.dataflow.cfg.node.ThisLiteralNode; +import org.checkerframework.dataflow.cfg.node.ThisNode; import org.checkerframework.dataflow.expression.FieldAccess; -import org.checkerframework.dataflow.expression.FlowExpressions; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.framework.flow.CFAbstractAnalysis; import org.checkerframework.framework.flow.CFAbstractTransfer; import org.checkerframework.framework.flow.CFAbstractValue; @@ -43,9 +42,9 @@ * can safely be considered initialized. *
  • After a method call with a postcondition that ensures a field to be non-null, that field * can safely be considered initialized (this is done in {@link - * InitializationStore#insertValue(Receiver, CFAbstractValue)}). + * InitializationStore#insertValue(JavaExpression, CFAbstractValue)}). *
  • All non-null fields with an initializer can be considered initialized (this is done in - * {@link InitializationStore#insertValue(Receiver, CFAbstractValue)}). + * {@link InitializationStore#insertValue(JavaExpression, CFAbstractValue)}). *
  • After the call to a super constructor ("super()" call), all non-null fields of the super * class can safely be considered initialized. * @@ -100,7 +99,7 @@ protected List initializedFieldsAfterCall(MethodInvocationNode // Case 1: After a call to the constructor of the same class, all // invariant fields are guaranteed to be initialized. - if (isConstructor && receiver instanceof ThisLiteralNode && methodString.equals("this")) { + if (isConstructor && receiver instanceof ThisNode && methodString.equals("this")) { ClassTree clazz = TreeUtils.enclosingClass(analysis.getTypeFactory().getPath(tree)); TypeElement clazzElem = TreeUtils.elementFromDeclaration(clazz); markInvariantFieldsAsInitialized(result, clazzElem); @@ -108,7 +107,7 @@ protected List initializedFieldsAfterCall(MethodInvocationNode // Case 4: After a call to the constructor of the super class, all // invariant fields of any super class are guaranteed to be initialized. - if (isConstructor && receiver instanceof ThisLiteralNode && methodString.equals("super")) { + if (isConstructor && receiver instanceof ThisNode && methodString.equals("super")) { ClassTree clazz = TreeUtils.enclosingClass(analysis.getTypeFactory().getPath(tree)); TypeElement clazzElem = TreeUtils.elementFromDeclaration(clazz); TypeMirror superClass = clazzElem.getSuperclass(); @@ -150,7 +149,7 @@ protected void markInvariantFieldsAsInitialized( public TransferResult visitAssignment(AssignmentNode n, TransferInput in) { TransferResult result = super.visitAssignment(n, in); assert result instanceof RegularTransferResult; - Receiver expr = FlowExpressions.internalReprOf(analysis.getTypeFactory(), n.getTarget()); + JavaExpression expr = JavaExpression.fromNode(analysis.getTypeFactory(), n.getTarget()); // If this is an assignment to a field of 'this', then mark the field as // initialized. @@ -173,8 +172,7 @@ public TransferResult visitFieldAccess(FieldAccessNode n, TransferInput result = super.visitFieldAccess(n, p); assert !result.containsTwoStores(); S store = result.getRegularStore(); - if (store.isFieldInitialized(n.getElement()) - && n.getReceiver() instanceof ThisLiteralNode) { + if (store.isFieldInitialized(n.getElement()) && n.getReceiver() instanceof ThisNode) { AnnotatedTypeMirror fieldAnno = analysis.getTypeFactory().getAnnotatedType(n.getElement()); // Only if the field has the type system's invariant annotation, diff --git a/checker/src/main/java/org/checkerframework/checker/initialization/InitializationVisitor.java b/checker/src/main/java/org/checkerframework/checker/initialization/InitializationVisitor.java index 99be6a0b0e..c990a0a59a 100644 --- a/checker/src/main/java/org/checkerframework/checker/initialization/InitializationVisitor.java +++ b/checker/src/main/java/org/checkerframework/checker/initialization/InitializationVisitor.java @@ -15,7 +15,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.StringJoiner; @@ -29,8 +28,8 @@ import org.checkerframework.common.basetype.BaseTypeVisitor; import org.checkerframework.dataflow.expression.ClassName; import org.checkerframework.dataflow.expression.FieldAccess; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.dataflow.expression.LocalVariable; -import org.checkerframework.dataflow.expression.Receiver; import org.checkerframework.dataflow.expression.ThisReference; import org.checkerframework.framework.flow.CFAbstractStore; import org.checkerframework.framework.flow.CFAbstractValue; @@ -172,7 +171,7 @@ public Void visitVariable(VariableTree node, Void p) { @Override protected boolean checkContract( - Receiver expr, + JavaExpression expr, AnnotationMirror necessaryAnnotation, AnnotationMirror inferredAnnotation, CFAbstractStore store) { @@ -183,6 +182,9 @@ protected boolean checkContract( || !(expr instanceof FieldAccess)) { return super.checkContract(expr, necessaryAnnotation, inferredAnnotation, store); } + if (expr.containsUnknown()) { + return false; + } FieldAccess fa = (FieldAccess) expr; if (fa.getReceiver() instanceof ThisReference || fa.getReceiver() instanceof ClassName) { @@ -196,32 +198,32 @@ protected boolean checkContract( } } } else { - Set recvAnnoSet; @SuppressWarnings("unchecked") Value value = (Value) store.getValue(fa.getReceiver()); + Set receiverAnnoSet; if (value != null) { - recvAnnoSet = value.getAnnotations(); + receiverAnnoSet = value.getAnnotations(); } else if (fa.getReceiver() instanceof LocalVariable) { Element elem = ((LocalVariable) fa.getReceiver()).getElement(); - AnnotatedTypeMirror recvType = atypeFactory.getAnnotatedType(elem); - recvAnnoSet = recvType.getAnnotations(); + AnnotatedTypeMirror receiverType = atypeFactory.getAnnotatedType(elem); + receiverAnnoSet = receiverType.getAnnotations(); } else { // Is there anything better we could do? return false; } - boolean isRecvInitialized = false; - for (AnnotationMirror anno : recvAnnoSet) { + boolean isReceiverInitialized = false; + for (AnnotationMirror anno : receiverAnnoSet) { if (atypeFactory.isInitialized(anno)) { - isRecvInitialized = true; + isReceiverInitialized = true; } } AnnotatedTypeMirror fieldType = atypeFactory.getAnnotatedType(fa.getField()); // The receiver is fully initialized and the field type // has the invariant type. - if (isRecvInitialized + if (isReceiverInitialized && AnnotationUtils.containsSame(fieldType.getAnnotations(), invariantAnno)) { return true; } @@ -382,9 +384,10 @@ protected void checkFieldsInitialized( ? COMMITMENT_STATIC_FIELDS_UNINITIALIZED : COMMITMENT_FIELDS_UNINITIALIZED); - List violatingFields = - atypeFactory.getUninitializedInvariantFields( + Pair, List> uninitializedFields = + atypeFactory.getUninitializedFields( store, getCurrentPath(), staticFields, receiverAnnotations); + List violatingFields = uninitializedFields.first; if (staticFields) { // TODO: Why is nothing done for static fields? @@ -397,14 +400,10 @@ protected void checkFieldsInitialized( } // Remove fields with a relevant @SuppressWarnings annotation. - Iterator itor = violatingFields.iterator(); - while (itor.hasNext()) { - VariableTree f = itor.next(); - Element e = TreeUtils.elementFromTree(f); - if (checker.shouldSuppressWarnings(e, COMMITMENT_FIELDS_UNINITIALIZED_KEY)) { - itor.remove(); - } - } + violatingFields.removeIf( + f -> + checker.shouldSuppressWarnings( + TreeUtils.elementFromTree(f), COMMITMENT_FIELDS_UNINITIALIZED_KEY)); if (!violatingFields.isEmpty()) { StringJoiner fieldsString = new StringJoiner(", "); diff --git a/checker/src/main/java/org/checkerframework/checker/interning/InterningAnnotatedTypeFactory.java b/checker/src/main/java/org/checkerframework/checker/interning/InterningAnnotatedTypeFactory.java index c19e3ce762..e64b70d43e 100644 --- a/checker/src/main/java/org/checkerframework/checker/interning/InterningAnnotatedTypeFactory.java +++ b/checker/src/main/java/org/checkerframework/checker/interning/InterningAnnotatedTypeFactory.java @@ -82,7 +82,7 @@ public InterningAnnotatedTypeFactory(BaseTypeChecker checker) { super(checker); // If you update the following, also update ../../../../../docs/manual/interning-checker.tex - addAliasedAnnotation("com.sun.istack.internal.Interned", INTERNED); + addAliasedTypeAnnotation("com.sun.istack.internal.Interned", INTERNED); this.postInit(); } diff --git a/checker/src/main/java/org/checkerframework/checker/interning/InterningVisitor.java b/checker/src/main/java/org/checkerframework/checker/interning/InterningVisitor.java index b52aa4993a..6d3b8109f9 100644 --- a/checker/src/main/java/org/checkerframework/checker/interning/InterningVisitor.java +++ b/checker/src/main/java/org/checkerframework/checker/interning/InterningVisitor.java @@ -205,11 +205,11 @@ public Void visitBinary(BinaryTree node, Void p) { @Override public Void visitMethodInvocation(MethodInvocationTree node, Void p) { if (isInvocationOfEquals(node)) { - AnnotatedTypeMirror recv = atypeFactory.getReceiverType(node); + AnnotatedTypeMirror receiverType = atypeFactory.getReceiverType(node); AnnotatedTypeMirror comp = atypeFactory.getAnnotatedType(node.getArguments().get(0)); if (this.checker.getLintOption("dotequals", true) - && recv.hasEffectiveAnnotation(INTERNED) + && receiverType.hasEffectiveAnnotation(INTERNED) && comp.hasEffectiveAnnotation(INTERNED)) { checker.reportWarning(node, "unnecessary.equals"); } diff --git a/checker/src/main/java/org/checkerframework/checker/lock/LockAnnotatedTypeFactory.java b/checker/src/main/java/org/checkerframework/checker/lock/LockAnnotatedTypeFactory.java index 1e2cd2cf40..8434fc1218 100644 --- a/checker/src/main/java/org/checkerframework/checker/lock/LockAnnotatedTypeFactory.java +++ b/checker/src/main/java/org/checkerframework/checker/lock/LockAnnotatedTypeFactory.java @@ -35,9 +35,9 @@ import org.checkerframework.common.basetype.BaseTypeChecker; import org.checkerframework.dataflow.expression.ClassName; import org.checkerframework.dataflow.expression.FieldAccess; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.dataflow.expression.LocalVariable; import org.checkerframework.dataflow.expression.MethodCall; -import org.checkerframework.dataflow.expression.Receiver; import org.checkerframework.dataflow.expression.ThisReference; import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.SideEffectFree; @@ -52,8 +52,8 @@ import org.checkerframework.framework.type.treeannotator.ListTreeAnnotator; import org.checkerframework.framework.type.treeannotator.TreeAnnotator; import org.checkerframework.framework.util.AnnotatedTypes; -import org.checkerframework.framework.util.FlowExpressionParseUtil; -import org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionContext; +import org.checkerframework.framework.util.JavaExpressionParseUtil; +import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionContext; import org.checkerframework.framework.util.QualifierKind; import org.checkerframework.framework.util.dependenttypes.DependentTypesError; import org.checkerframework.framework.util.dependenttypes.DependentTypesHelper; @@ -168,7 +168,7 @@ protected void reportErrors(Tree errorTree, List errors) { @Override protected String standardizeString( String expression, - FlowExpressionContext context, + JavaExpressionContext context, TreePath localScope, boolean useLocalScope) { if (DependentTypesError.isExpressionError(expression)) { @@ -181,8 +181,8 @@ protected String standardizeString( } try { - Receiver result = - FlowExpressionParseUtil.parse( + JavaExpression result = + JavaExpressionParseUtil.parse( expression, context, localScope, useLocalScope); if (result == null) { return new DependentTypesError(expression, " ").toString(); @@ -194,7 +194,7 @@ protected String standardizeString( .toString(); } return result.toString(); - } catch (FlowExpressionParseUtil.FlowExpressionParseException e) { + } catch (JavaExpressionParseUtil.JavaExpressionParseException e) { return new DependentTypesError(expression, e).toString(); } } @@ -219,17 +219,17 @@ protected String standardizeString( * @param expr expression * @return whether or not the expression is effectively final */ - boolean isExpressionEffectivelyFinal(Receiver expr) { + boolean isExpressionEffectivelyFinal(JavaExpression expr) { if (expr instanceof FieldAccess) { FieldAccess fieldAccess = (FieldAccess) expr; - Receiver recv = fieldAccess.getReceiver(); + JavaExpression receiver = fieldAccess.getReceiver(); // Don't call fieldAccess - return fieldAccess.isFinal() && isExpressionEffectivelyFinal(recv); + return fieldAccess.isFinal() && isExpressionEffectivelyFinal(receiver); } else if (expr instanceof LocalVariable) { return ElementUtils.isEffectivelyFinal(((LocalVariable) expr).getElement()); } else if (expr instanceof MethodCall) { MethodCall methodCall = (MethodCall) expr; - for (Receiver param : methodCall.getParameters()) { + for (JavaExpression param : methodCall.getParameters()) { if (!isExpressionEffectivelyFinal(param)) { return false; } @@ -273,7 +273,7 @@ public LockTransfer createFlowTransferFunction( return new LockTransfer((LockAnalysis) analysis, (LockChecker) this.checker); } - /** LockQualifierHierarchy */ + /** LockQualifierHierarchy. */ class LockQualifierHierarchy extends MostlyNoElementQualifierHierarchy { /** Qualifier kind for the @{@link GuardedBy} annotation. */ diff --git a/checker/src/main/java/org/checkerframework/checker/lock/LockStore.java b/checker/src/main/java/org/checkerframework/checker/lock/LockStore.java index 528810a4f0..3c473afa2b 100644 --- a/checker/src/main/java/org/checkerframework/checker/lock/LockStore.java +++ b/checker/src/main/java/org/checkerframework/checker/lock/LockStore.java @@ -11,9 +11,9 @@ import org.checkerframework.dataflow.expression.ArrayAccess; import org.checkerframework.dataflow.expression.ClassName; import org.checkerframework.dataflow.expression.FieldAccess; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.dataflow.expression.LocalVariable; import org.checkerframework.dataflow.expression.MethodCall; -import org.checkerframework.dataflow.expression.Receiver; import org.checkerframework.dataflow.expression.ThisReference; import org.checkerframework.framework.flow.CFAbstractStore; import org.checkerframework.framework.flow.CFValue; @@ -66,45 +66,45 @@ public LockStore leastUpperBound(LockStore other) { * Insert an annotation exactly, without regard to whether an annotation was already present. * This is only done for @LockPossiblyHeld. This is not sound for other type qualifiers. */ - public void insertLockPossiblyHeld(Receiver r) { - if (r.containsUnknown()) { + public void insertLockPossiblyHeld(JavaExpression je) { + if (je.containsUnknown()) { // Expressions containing unknown expressions are not stored. return; } - if (r instanceof LocalVariable) { - LocalVariable localVar = (LocalVariable) r; + if (je instanceof LocalVariable) { + LocalVariable localVar = (LocalVariable) je; CFValue current = localVariableValues.get(localVar); - CFValue value = changeLockAnnoToTop(r, current); + CFValue value = changeLockAnnoToTop(je, current); if (value != null) { localVariableValues.put(localVar, value); } - } else if (r instanceof FieldAccess) { - FieldAccess fieldAcc = (FieldAccess) r; + } else if (je instanceof FieldAccess) { + FieldAccess fieldAcc = (FieldAccess) je; CFValue current = fieldValues.get(fieldAcc); - CFValue value = changeLockAnnoToTop(r, current); + CFValue value = changeLockAnnoToTop(je, current); if (value != null) { fieldValues.put(fieldAcc, value); } - } else if (r instanceof MethodCall) { - MethodCall method = (MethodCall) r; + } else if (je instanceof MethodCall) { + MethodCall method = (MethodCall) je; CFValue current = methodValues.get(method); - CFValue value = changeLockAnnoToTop(r, current); + CFValue value = changeLockAnnoToTop(je, current); if (value != null) { methodValues.put(method, value); } - } else if (r instanceof ArrayAccess) { - ArrayAccess arrayAccess = (ArrayAccess) r; + } else if (je instanceof ArrayAccess) { + ArrayAccess arrayAccess = (ArrayAccess) je; CFValue current = arrayValues.get(arrayAccess); - CFValue value = changeLockAnnoToTop(r, current); + CFValue value = changeLockAnnoToTop(je, current); if (value != null) { arrayValues.put(arrayAccess, value); } - } else if (r instanceof ThisReference) { - thisValue = changeLockAnnoToTop(r, thisValue); - } else if (r instanceof ClassName) { - ClassName className = (ClassName) r; + } else if (je instanceof ThisReference) { + thisValue = changeLockAnnoToTop(je, thisValue); + } else if (je instanceof ClassName) { + ClassName className = (ClassName) je; CFValue current = classValues.get(className); - CFValue value = changeLockAnnoToTop(r, current); + CFValue value = changeLockAnnoToTop(je, current); if (value != null) { classValues.put(className, value); } @@ -118,12 +118,12 @@ public void insertLockPossiblyHeld(Receiver r) { * the LockPossiblyHeld hierarchy is set to LockPossiblyHeld. If currentValue is null, then a * new value is created where the annotation set is LockPossiblyHeld and GuardedByUnknown */ - private CFValue changeLockAnnoToTop(Receiver r, CFValue currentValue) { + private CFValue changeLockAnnoToTop(JavaExpression je, CFValue currentValue) { if (currentValue == null) { Set set = AnnotationUtils.createAnnotationSet(); set.add(atypeFactory.GUARDEDBYUNKNOWN); set.add(atypeFactory.LOCKPOSSIBLYHELD); - return analysis.createAbstractValue(set, r.getType()); + return analysis.createAbstractValue(set, je.getType()); } QualifierHierarchy hierarchy = atypeFactory.getQualifierHierarchy(); @@ -143,7 +143,7 @@ public void setInConstructorOrInitializer() { } @Override - public @Nullable CFValue getValue(Receiver expr) { + public @Nullable CFValue getValue(JavaExpression expr) { if (inConstructorOrInitializer) { // 'this' is automatically considered as being held in a constructor or initializer. @@ -226,7 +226,7 @@ boolean hasLockPossiblyHeld(CFValue value) { } @Override - public void insertValue(Receiver r, @Nullable CFValue value) { + public void insertValue(JavaExpression je, @Nullable CFValue value) { if (value == null) { // No need to insert a null abstract value because it represents // top and top is also the default value. @@ -238,15 +238,15 @@ public void insertValue(Receiver r, @Nullable CFValue value) { // -Locks are assumed to be effectively final, hence another thread will not // side effect the lock expression that has value @LockHeld. if (hasLockHeld(value)) { - if (r instanceof FieldAccess) { - FieldAccess fieldAcc = (FieldAccess) r; + if (je instanceof FieldAccess) { + FieldAccess fieldAcc = (FieldAccess) je; CFValue oldValue = fieldValues.get(fieldAcc); CFValue newValue = value.mostSpecific(oldValue, null); if (newValue != null) { fieldValues.put(fieldAcc, newValue); } - } else if (r instanceof MethodCall) { - MethodCall method = (MethodCall) r; + } else if (je instanceof MethodCall) { + MethodCall method = (MethodCall) je; CFValue oldValue = methodValues.get(method); CFValue newValue = value.mostSpecific(oldValue, null); if (newValue != null) { @@ -255,6 +255,6 @@ public void insertValue(Receiver r, @Nullable CFValue value) { } } - super.insertValue(r, value); + super.insertValue(je, value); } } diff --git a/checker/src/main/java/org/checkerframework/checker/lock/LockTransfer.java b/checker/src/main/java/org/checkerframework/checker/lock/LockTransfer.java index 468af60f0a..ab28cdccbb 100644 --- a/checker/src/main/java/org/checkerframework/checker/lock/LockTransfer.java +++ b/checker/src/main/java/org/checkerframework/checker/lock/LockTransfer.java @@ -16,8 +16,7 @@ import org.checkerframework.dataflow.cfg.node.Node; import org.checkerframework.dataflow.cfg.node.SynchronizedNode; import org.checkerframework.dataflow.expression.ClassName; -import org.checkerframework.dataflow.expression.FlowExpressions; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.framework.flow.CFAbstractTransfer; import org.checkerframework.framework.flow.CFValue; import org.checkerframework.javacutil.TreeUtils; @@ -43,13 +42,13 @@ public LockTransfer(LockAnalysis analysis, LockChecker checker) { /** Sets a given {@link Node} to @LockHeld in the given {@code store}. */ protected void makeLockHeld(LockStore store, Node node) { - Receiver internalRepr = FlowExpressions.internalReprOf(atypeFactory, node); + JavaExpression internalRepr = JavaExpression.fromNode(atypeFactory, node); store.insertValue(internalRepr, atypeFactory.LOCKHELD); } /** Sets a given {@link Node} to @LockPossiblyHeld in the given {@code store}. */ protected void makeLockPossiblyHeld(LockStore store, Node node) { - Receiver internalRepr = FlowExpressions.internalReprOf(atypeFactory, node); + JavaExpression internalRepr = JavaExpression.fromNode(atypeFactory, node); // insertValue cannot change an annotation to a less // specific type (e.g. LockHeld to LockPossiblyHeld), diff --git a/checker/src/main/java/org/checkerframework/checker/lock/LockVisitor.java b/checker/src/main/java/org/checkerframework/checker/lock/LockVisitor.java index b07e2dc2c2..97a76ca4ec 100644 --- a/checker/src/main/java/org/checkerframework/checker/lock/LockVisitor.java +++ b/checker/src/main/java/org/checkerframework/checker/lock/LockVisitor.java @@ -43,8 +43,7 @@ import org.checkerframework.checker.lock.qual.LockHeld; import org.checkerframework.common.basetype.BaseTypeChecker; import org.checkerframework.common.basetype.BaseTypeVisitor; -import org.checkerframework.dataflow.expression.FlowExpressions; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.dataflow.expression.Unknown; import org.checkerframework.dataflow.qual.Deterministic; import org.checkerframework.dataflow.qual.Pure; @@ -55,9 +54,9 @@ import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType; import org.checkerframework.framework.type.QualifierHierarchy; import org.checkerframework.framework.util.AnnotatedTypes; -import org.checkerframework.framework.util.FlowExpressionParseUtil; -import org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionContext; -import org.checkerframework.framework.util.FlowExpressionParseUtil.FlowExpressionParseException; +import org.checkerframework.framework.util.JavaExpressionParseUtil; +import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionContext; +import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionParseException; import org.checkerframework.framework.util.dependenttypes.DependentTypesError; import org.checkerframework.javacutil.AnnotationUtils; import org.checkerframework.javacutil.BugInCF; @@ -585,8 +584,8 @@ public Void visitMethodInvocation(MethodInvocationTree node, Void p) { node, "method.guarantee.violated", seaOfContainingMethod.getNameOfSideEffectAnnotation(), - enclosingMethodElement.toString(), - methodElement.toString(), + enclosingMethodElement.getSimpleName(), + methodElement.getSimpleName(), seaOfInvokedMethod.getNameOfSideEffectAnnotation()); } } @@ -594,9 +593,9 @@ public Void visitMethodInvocation(MethodInvocationTree node, Void p) { if (methodElement != null) { // Handle releasing of explicit locks. Verify that the lock expression is effectively // final. - ExpressionTree recvTree = TreeUtils.getReceiverTree(node); + ExpressionTree receiverTree = TreeUtils.getReceiverTree(node); - ensureReceiverOfExplicitUnlockCallIsEffectivelyFinal(methodElement, recvTree); + ensureReceiverOfExplicitUnlockCallIsEffectivelyFinal(methodElement, receiverTree); // Handle acquiring of explicit locks. Verify that the lock expression is effectively // final. @@ -628,10 +627,11 @@ public Void visitMethodInvocation(MethodInvocationTree node, Void p) { for (String expr : expressions) { if (expr.equals("this")) { - // recvTree will be null for implicit this, or class name receivers. But they + // receiverTree will be null for implicit this, or class name receivers. But + // they // are also final. So nothing to be checked for them. - if (recvTree != null) { - ensureExpressionIsEffectivelyFinal(recvTree); + if (receiverTree != null) { + ensureExpressionIsEffectivelyFinal(receiverTree); } } else if (expr.equals("#1")) { ExpressionTree firstParameter = node.getArguments().get(0); @@ -929,7 +929,7 @@ private void ensureExpressionIsEffectivelyFinal(final ExpressionTree lockExpress } private void ensureExpressionIsEffectivelyFinal( - final Receiver lockExpr, + final JavaExpression lockExpr, String expressionForErrorReporting, Tree treeForErrorReporting) { if (!atypeFactory.isExpressionEffectivelyFinal(lockExpr)) { @@ -1009,7 +1009,7 @@ private void issueErrorIfGuardSatisfiedAnnotationInUnsupportedLocation( } /** - * The flow expression parser requires a path for retrieving the scope that will be used to + * The JavaExpression parser requires a path for retrieving the scope that will be used to * resolve local variables. One would expect that simply providing the path to an AnnotationTree * would work, since the compiler (as called by the org.checkerframework.javacutil.Resolver * class) could walk up the path from the AnnotationTree to determine the scope. Unfortunately @@ -1207,11 +1207,11 @@ private void checkLockOfThisOrTree(Tree tree, boolean implicitThis, AnnotationMi } } - private boolean isLockHeld(Receiver lock, LockStore store) { + private boolean isLockHeld(JavaExpression lockExpr, LockStore store) { if (store == null) { return false; } - CFAbstractValue value = store.getValue(lock); + CFAbstractValue value = store.getValue(lockExpr); if (value == null) { return false; } @@ -1233,19 +1233,19 @@ private List getLockExpressions( } TreePath currentPath = getCurrentPath(); - List params = - FlowExpressions.getParametersOfEnclosingMethod(atypeFactory, currentPath); + List params = + JavaExpression.getParametersOfEnclosingMethod(atypeFactory, currentPath); TypeMirror enclosingType = TreeUtils.typeOf(TreeUtils.enclosingClass(currentPath)); - Receiver pseudoReceiver = - FlowExpressions.internalReprOfPseudoReceiver(currentPath, enclosingType); - FlowExpressionContext exprContext = - new FlowExpressionContext(pseudoReceiver, params, atypeFactory.getContext()); - Receiver self; + JavaExpression pseudoReceiver = + JavaExpression.getPseudoReceiver(currentPath, enclosingType); + JavaExpressionContext exprContext = + new JavaExpressionContext(pseudoReceiver, params, atypeFactory.getContext()); + JavaExpression self; if (implicitThis) { self = pseudoReceiver; } else if (TreeUtils.isExpressionTree(tree)) { - self = FlowExpressions.internalReprOf(atypeFactory, (ExpressionTree) tree); + self = JavaExpression.fromTree(atypeFactory, (ExpressionTree) tree); } else { self = new Unknown(TreeUtils.typeOf(tree)); } @@ -1259,9 +1259,9 @@ private List getLockExpressions( private LockExpression parseExpressionString( String expression, - FlowExpressionContext flowExprContext, + JavaExpressionContext flowExprContext, TreePath path, - Receiver itself) { + JavaExpression itself) { LockExpression lockExpression = new LockExpression(expression); if (DependentTypesError.isExpressionError(expression)) { @@ -1285,17 +1285,17 @@ private LockExpression parseExpressionString( } else { // TODO: The proper way to do this is to call // flowExprContext.copyChangeToParsingMemberOfReceiver to set the receiver to - // the expression, and then call FlowExpressionParseUtil.parse on the - // remaining expression string with the new flow expression context. However, - // this currently results in a Receiver that has a different - // hash code than if the following flow expression is parsed directly, which + // the expression, and then call JavaExpressionParseUtil.parse on the + // remaining expression string with the new JavaExpressionContext. However, + // this currently results in a JavaExpression that has a different + // hash code than if the following JavaExpression is parsed directly, which // results in our inability to check that a lock expression is held as it does // not match anything in the store due to the hash code mismatch. For now, // convert the "" portion to the node's string representation, and parse // the entire string: lockExpression.lockExpression = - FlowExpressionParseUtil.parse( + JavaExpressionParseUtil.parse( itself.toString() + "." + remainingExpression, flowExprContext, path, @@ -1310,10 +1310,10 @@ private LockExpression parseExpressionString( } } else { lockExpression.lockExpression = - FlowExpressionParseUtil.parse(expression, flowExprContext, path, true); + JavaExpressionParseUtil.parse(expression, flowExprContext, path, true); return lockExpression; } - } catch (FlowExpressionParseException ex) { + } catch (JavaExpressionParseException ex) { lockExpression.error = new DependentTypesError(expression, ex); return lockExpression; } @@ -1321,7 +1321,7 @@ private LockExpression parseExpressionString( private static class LockExpression { final String expressionString; - Receiver lockExpression = null; + JavaExpression lockExpression = null; DependentTypesError error = null; LockExpression(String expression) { diff --git a/checker/src/main/java/org/checkerframework/checker/nullness/CollectionToArrayHeuristics.java b/checker/src/main/java/org/checkerframework/checker/nullness/CollectionToArrayHeuristics.java index e3a8298a0c..2228f56309 100644 --- a/checker/src/main/java/org/checkerframework/checker/nullness/CollectionToArrayHeuristics.java +++ b/checker/src/main/java/org/checkerframework/checker/nullness/CollectionToArrayHeuristics.java @@ -104,9 +104,9 @@ public void handle(MethodInvocationTree tree, AnnotatedExecutableType method) { if (receiverIsNonNull && !argIsHandled) { if (argument.getKind() != Tree.Kind.NEW_ARRAY) { - checker.reportWarning(tree, "toArray.nullable.elements.not.newarray"); + checker.reportWarning(tree, "toarray.nullable.elements.not.newarray"); } else { - checker.reportWarning(tree, "toArray.nullable.elements.mismatched.size"); + checker.reportWarning(tree, "toarray.nullable.elements.mismatched.size"); } } } diff --git a/checker/src/main/java/org/checkerframework/checker/nullness/KeyForAnnotatedTypeFactory.java b/checker/src/main/java/org/checkerframework/checker/nullness/KeyForAnnotatedTypeFactory.java index 5efc36563a..d5afc9f356 100644 --- a/checker/src/main/java/org/checkerframework/checker/nullness/KeyForAnnotatedTypeFactory.java +++ b/checker/src/main/java/org/checkerframework/checker/nullness/KeyForAnnotatedTypeFactory.java @@ -66,9 +66,9 @@ public KeyForAnnotatedTypeFactory(BaseTypeChecker checker) { super(checker, true); // Add compatibility annotations: - addAliasedAnnotation( + addAliasedTypeAnnotation( "org.checkerframework.checker.nullness.compatqual.KeyForDecl", KeyFor.class, true); - addAliasedAnnotation( + addAliasedTypeAnnotation( "org.checkerframework.checker.nullness.compatqual.KeyForType", KeyFor.class, true); // While strictly required for soundness, this leads to too many false positives. Printing diff --git a/checker/src/main/java/org/checkerframework/checker/nullness/KeyForTransfer.java b/checker/src/main/java/org/checkerframework/checker/nullness/KeyForTransfer.java index aa7f6e9f77..67cd0bf8ca 100644 --- a/checker/src/main/java/org/checkerframework/checker/nullness/KeyForTransfer.java +++ b/checker/src/main/java/org/checkerframework/checker/nullness/KeyForTransfer.java @@ -8,8 +8,7 @@ import org.checkerframework.dataflow.analysis.TransferResult; import org.checkerframework.dataflow.cfg.node.MethodInvocationNode; import org.checkerframework.dataflow.cfg.node.Node; -import org.checkerframework.dataflow.expression.FlowExpressions; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.framework.flow.CFAbstractTransfer; import org.checkerframework.javacutil.AnnotationUtils; @@ -39,9 +38,9 @@ public TransferResult visitMethodInvocation( if (factory.isMapContainsKey(node) || factory.isMapPut(node)) { Node receiver = node.getTarget().getReceiver(); - Receiver internalReceiver = FlowExpressions.internalReprOf(factory, receiver); - String mapName = internalReceiver.toString(); - Receiver keyReceiver = FlowExpressions.internalReprOf(factory, node.getArgument(0)); + JavaExpression receiverJe = JavaExpression.fromNode(factory, receiver); + String mapName = receiverJe.toString(); + JavaExpression keyExpr = JavaExpression.fromNode(factory, node.getArgument(0)); LinkedHashSet keyForMaps = new LinkedHashSet<>(); keyForMaps.add(mapName); @@ -58,10 +57,10 @@ public TransferResult visitMethodInvocation( AnnotationMirror am = factory.createKeyForAnnotationMirrorWithValue(keyForMaps); if (factory.isMapContainsKey(node)) { - result.getThenStore().insertValue(keyReceiver, am); + result.getThenStore().insertValue(keyExpr, am); } else { // method is Map.put - result.getThenStore().insertValue(keyReceiver, am); - result.getElseStore().insertValue(keyReceiver, am); + result.getThenStore().insertValue(keyExpr, am); + result.getElseStore().insertValue(keyExpr, am); } } diff --git a/checker/src/main/java/org/checkerframework/checker/nullness/NullnessAnnotatedTypeFactory.java b/checker/src/main/java/org/checkerframework/checker/nullness/NullnessAnnotatedTypeFactory.java index c35a53a070..16d3b0fd82 100644 --- a/checker/src/main/java/org/checkerframework/checker/nullness/NullnessAnnotatedTypeFactory.java +++ b/checker/src/main/java/org/checkerframework/checker/nullness/NullnessAnnotatedTypeFactory.java @@ -17,7 +17,6 @@ import com.sun.source.tree.VariableTree; import com.sun.source.util.TreePath; import java.lang.annotation.Annotation; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; @@ -29,6 +28,7 @@ import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; import org.checkerframework.checker.initialization.InitializationAnnotatedTypeFactory; import org.checkerframework.checker.initialization.qual.FBCBottom; import org.checkerframework.checker.initialization.qual.Initialized; @@ -40,6 +40,7 @@ import org.checkerframework.checker.nullness.qual.PolyNull; import org.checkerframework.checker.signature.qual.FullyQualifiedName; import org.checkerframework.common.basetype.BaseTypeChecker; +import org.checkerframework.common.wholeprograminference.WholeProgramInference; import org.checkerframework.framework.flow.CFAbstractAnalysis; import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeFormatter; @@ -210,18 +211,18 @@ public NullnessAnnotatedTypeFactory(BaseTypeChecker checker) { tempNullnessAnnos.add(PolyNull.class); nullnessAnnos = Collections.unmodifiableSet(tempNullnessAnnos); - NONNULL_ALIASES.forEach(annotation -> addAliasedAnnotation(annotation, NONNULL)); - NULLABLE_ALIASES.forEach(annotation -> addAliasedAnnotation(annotation, NULLABLE)); + NONNULL_ALIASES.forEach(annotation -> addAliasedTypeAnnotation(annotation, NONNULL)); + NULLABLE_ALIASES.forEach(annotation -> addAliasedTypeAnnotation(annotation, NULLABLE)); // Add compatibility annotations: - addAliasedAnnotation( + addAliasedTypeAnnotation( "org.checkerframework.checker.nullness.compatqual.PolyNullDecl", POLYNULL); - addAliasedAnnotation( + addAliasedTypeAnnotation( "org.checkerframework.checker.nullness.compatqual.MonotonicNonNullDecl", MONOTONIC_NONNULL); - addAliasedAnnotation( + addAliasedTypeAnnotation( "org.checkerframework.checker.nullness.compatqual.PolyNullType", POLYNULL); - addAliasedAnnotation( + addAliasedTypeAnnotation( "org.checkerframework.checker.nullness.compatqual.MonotonicNonNullType", MONOTONIC_NONNULL); @@ -291,22 +292,19 @@ protected void replacePolyQualifier(AnnotatedTypeMirror lhsType, Tree context) { } @Override - public List getUninitializedInvariantFields( + public Pair, List> getUninitializedFields( NullnessStore store, TreePath path, boolean isStatic, List receiverAnnotations) { - List candidates = - super.getUninitializedInvariantFields(store, path, isStatic, receiverAnnotations); - List result = new ArrayList<>(); - for (VariableTree c : candidates) { - AnnotatedTypeMirror type = getAnnotatedType(c); - boolean isPrimitive = TypesUtils.isPrimitive(type.getUnderlyingType()); - if (!isPrimitive) { - // primitives do not need to be initialized - result.add(c); - } - } + Pair, List> result = + super.getUninitializedFields(store, path, isStatic, receiverAnnotations); + // Filter out primitives. They have the @NonNull annotation, but this checker issues no + // warning when they are not initialized. + result.first.removeIf( + vt -> TypesUtils.isPrimitive(getAnnotatedType(vt).getUnderlyingType())); + result.second.removeIf( + vt -> TypesUtils.isPrimitive(getAnnotatedType(vt).getUnderlyingType())); return result; } @@ -598,7 +596,7 @@ public QualifierHierarchy createQualifierHierarchy() { return new NullnessQualifierHierarchy(); } - /** NullnessQualifierHierarchy */ + /** NullnessQualifierHierarchy. */ protected class NullnessQualifierHierarchy extends InitializationQualifierHierarchy { /** Qualifier kind for the @{@link Nullable} annotation. */ @@ -659,6 +657,9 @@ protected AnnotationMirror greatestLowerBoundWithElements( * Returns true if some annotation in the given list is a nullness annotation such * as @NonNull, @Nullable, @MonotonicNonNull, etc. * + *

    This method ignores aliases of nullness annotations that are declaration annotations, + * because they may apply to inner types. + * * @param annoTrees a list of annotations on a variable/method declaration; null if this type is * not from such a location * @param typeTree the type whose annotations to test @@ -671,7 +672,7 @@ protected boolean containsNullnessAnnotation( for (AnnotationTree annoTree : annos) { AnnotationMirror am = TreeUtils.annotationFromAnnotationTree(annoTree); - if (isNullnessAnnotation(am)) { + if (isNullnessAnnotation(am) && !AnnotationUtils.isDeclarationAnnotation(am)) { return true; } } @@ -719,4 +720,18 @@ protected boolean isNullableOrAlias(AnnotationMirror am) { } return AnnotationUtils.areSameByName(am, NULLABLE); } + + @Override + public AnnotatedTypeMirror getDefaultValueAnnotatedType(TypeMirror typeMirror) { + AnnotatedTypeMirror result = super.getDefaultValueAnnotatedType(typeMirror); + if (getAnnotationByClass(result.getAnnotations(), Nullable.class) != null) { + result.replaceAnnotation(MONOTONIC_NONNULL); + } + return result; + } + + @Override + public WholeProgramInference createWholeProgramInference() { + return new NullnessWholeProgramInferenceScenes(this); + } } diff --git a/checker/src/main/java/org/checkerframework/checker/nullness/NullnessStore.java b/checker/src/main/java/org/checkerframework/checker/nullness/NullnessStore.java index ab3b852792..3aa3831303 100644 --- a/checker/src/main/java/org/checkerframework/checker/nullness/NullnessStore.java +++ b/checker/src/main/java/org/checkerframework/checker/nullness/NullnessStore.java @@ -30,7 +30,7 @@ public class NullnessStore extends InitializationStore strengthenAnnotationOfEqu List secondParts = splitAssignments(secondNode); for (Node secondPart : secondParts) { - Receiver secondInternal = - FlowExpressions.internalReprOf(nullnessTypeFactory, secondPart); - if (CFAbstractStore.canInsertReceiver(secondInternal)) { + JavaExpression secondInternal = + JavaExpression.fromNode(nullnessTypeFactory, secondPart); + if (CFAbstractStore.canInsertJavaExpression(secondInternal)) { thenStore = thenStore == null ? res.getThenStore() : thenStore; elseStore = elseStore == null ? res.getElseStore() : elseStore; if (notEqualTo) { @@ -369,8 +368,7 @@ public TransferResult visitMethodInvocation( // Refine result to @NonNull if n is an invocation of Map.get, the argument is a key for // the map, and the map's value type is not @Nullable. if (keyForTypeFactory != null && keyForTypeFactory.isMapGet(n)) { - String mapName = - FlowExpressions.internalReprOf(nullnessTypeFactory, receiver).toString(); + String mapName = JavaExpression.fromNode(nullnessTypeFactory, receiver).toString(); AnnotatedTypeMirror receiverType = nullnessTypeFactory.getReceiverType(n.getTree()); if (keyForTypeFactory.isKeyForMap(mapName, methodArgs.get(0)) diff --git a/checker/src/main/java/org/checkerframework/checker/nullness/NullnessVisitor.java b/checker/src/main/java/org/checkerframework/checker/nullness/NullnessVisitor.java index 50bb2ee658..86e583c5ba 100644 --- a/checker/src/main/java/org/checkerframework/checker/nullness/NullnessVisitor.java +++ b/checker/src/main/java/org/checkerframework/checker/nullness/NullnessVisitor.java @@ -556,7 +556,8 @@ protected void checkMethodInvocability( method.getReceiverType() != null) { // TODO: should all or some constructors be excluded? // method.getElement().getKind() != ElementKind.CONSTRUCTOR) { - Set recvAnnos = atypeFactory.getReceiverType(node).getAnnotations(); + Set receiverAnnos = + atypeFactory.getReceiverType(node).getAnnotations(); AnnotatedTypeMirror methodReceiver = method.getReceiverType().getErased(); AnnotatedTypeMirror treeReceiver = methodReceiver.shallowCopy(false); AnnotatedTypeMirror rcv = atypeFactory.getReceiverType(node); @@ -564,7 +565,7 @@ protected void checkMethodInvocability( // If receiver is Nullable, then we don't want to issue a warning // about method invocability (we'd rather have only the // "dereference.of.nullable" message). - if (treeReceiver.hasAnnotation(NULLABLE) || recvAnnos.contains(MONOTONIC_NONNULL)) { + if (treeReceiver.hasAnnotation(NULLABLE) || receiverAnnos.contains(MONOTONIC_NONNULL)) { return; } } diff --git a/checker/src/main/java/org/checkerframework/checker/nullness/NullnessWholeProgramInferenceScenes.java b/checker/src/main/java/org/checkerframework/checker/nullness/NullnessWholeProgramInferenceScenes.java new file mode 100644 index 0000000000..db6c93cb85 --- /dev/null +++ b/checker/src/main/java/org/checkerframework/checker/nullness/NullnessWholeProgramInferenceScenes.java @@ -0,0 +1,18 @@ +package org.checkerframework.checker.nullness; + +import org.checkerframework.common.wholeprograminference.WholeProgramInferenceScenes; +import org.checkerframework.framework.type.AnnotatedTypeFactory; + +/** A WholeProgramInferenceScenes customized for the Nullness Checker. */ +public class NullnessWholeProgramInferenceScenes extends WholeProgramInferenceScenes { + + /** + * Create a NullnessWholeProgramInferenceScenes. + * + * @param atypeFactory the associated type factory + */ + public NullnessWholeProgramInferenceScenes(AnnotatedTypeFactory atypeFactory) { + // "false" argument means don't ignore null assignments. + super(atypeFactory, false); + } +} diff --git a/checker/src/main/java/org/checkerframework/checker/nullness/messages.properties b/checker/src/main/java/org/checkerframework/checker/nullness/messages.properties index 1b0f132f1c..f3886c1dbe 100644 --- a/checker/src/main/java/org/checkerframework/checker/nullness/messages.properties +++ b/checker/src/main/java/org/checkerframework/checker/nullness/messages.properties @@ -13,8 +13,8 @@ class.not.found.nullness.parse.error=class not found for field "%s" field.not.found.nullness.parse.error=field "%s" not found new.array.type.invalid=annotations %s may not be applied as component type for array "%s" new.class.type.invalid=the annotations %s do not need be applied in object creations -toArray.nullable.elements.not.newarray=call of toArray on collection of non-null elements yields an array of possibly-null elements; omit the argument to toArray or make it an explicit array constructor -toArray.nullable.elements.mismatched.size=call of toArray on collection of non-null elements yields an array of possibly-null elements; cannot determine that the argument array has the same size as the receiver collection +toarray.nullable.elements.not.newarray=call of toArray on collection of non-null elements yields an array of possibly-null elements; omit the argument to toArray or make it an explicit array constructor +toarray.nullable.elements.mismatched.size=call of toArray on collection of non-null elements yields an array of possibly-null elements; cannot determine that the argument array has the same size as the receiver collection clear.system.property=call might clear a predefined system property; pass -Alint=permitClearProperty to permit it instanceof.nullable=instanceof is only true for a non-null expression instanceof.nonnull.redundant=redundant @NonNull annotation on instanceof diff --git a/checker/src/main/java/org/checkerframework/checker/nullness/qual/PolyNull.java b/checker/src/main/java/org/checkerframework/checker/nullness/qual/PolyNull.java index 1ae6b204c8..35b10a0b18 100644 --- a/checker/src/main/java/org/checkerframework/checker/nullness/qual/PolyNull.java +++ b/checker/src/main/java/org/checkerframework/checker/nullness/qual/PolyNull.java @@ -11,9 +11,8 @@ * A polymorphic qualifier for the non-null type system. * *

    Any method written using {@link PolyNull} conceptually has two versions: one in which every - * instance of {@link PolyNull} has been replaced by {@link - * org.checkerframework.checker.nullness.qual.NonNull}, and one in which every instance of {@link - * PolyNull} has been replaced by {@link org.checkerframework.checker.nullness.qual.Nullable}. + * instance of {@link PolyNull} has been replaced by {@link NonNull}, and one in which every + * instance of {@link PolyNull} has been replaced by {@link Nullable}. * * @checker_framework.manual #nullness-checker Nullness Checker * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism diff --git a/checker/src/main/java/org/checkerframework/checker/optional/OptionalVisitor.java b/checker/src/main/java/org/checkerframework/checker/optional/OptionalVisitor.java index a1b876b3e4..5406abe6d8 100644 --- a/checker/src/main/java/org/checkerframework/checker/optional/OptionalVisitor.java +++ b/checker/src/main/java/org/checkerframework/checker/optional/OptionalVisitor.java @@ -6,9 +6,11 @@ import com.sun.source.tree.ExpressionTree; import com.sun.source.tree.IfTree; import com.sun.source.tree.MethodInvocationTree; +import com.sun.source.tree.ParenthesizedTree; import com.sun.source.tree.StatementTree; import com.sun.source.tree.Tree; import com.sun.source.tree.Tree.Kind; +import com.sun.source.tree.UnaryTree; import com.sun.source.tree.VariableTree; import java.util.Collection; import java.util.List; @@ -19,14 +21,15 @@ import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.common.basetype.BaseTypeChecker; import org.checkerframework.common.basetype.BaseTypeValidator; import org.checkerframework.common.basetype.BaseTypeVisitor; -import org.checkerframework.dataflow.expression.FlowExpressions; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.framework.type.AnnotatedTypeFactory; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType; +import org.checkerframework.javacutil.Pair; import org.checkerframework.javacutil.TreeUtils; import org.checkerframework.javacutil.TypesUtils; @@ -45,6 +48,8 @@ public class OptionalVisitor private final ExecutableElement optionalGet; /** The element for java.util.Optional.isPresent(). */ private final ExecutableElement optionalIsPresent; + /** The element for java.util.Optional.isEmpty(), or null if running under JDK 8. */ + private final @Nullable ExecutableElement optionalIsEmpty; /** The element for java.util.Optional.of(). */ private final ExecutableElement optionalOf; /** The element for java.util.Optional.ofNullable(). */ @@ -54,7 +59,9 @@ public class OptionalVisitor /** The element for java.util.Optional.orElseGet(). */ private final ExecutableElement optionalOrElseGet; /** The element for java.util.Optional.orElseThrow(). */ - private final ExecutableElement optionalOrElseThrow; + private final @Nullable ExecutableElement optionalOrElseThrow; + /** The element for java.util.Optional.orElseThrow(Supplier), or null if running under JDK 8. */ + private final ExecutableElement optionalOrElseThrowSupplier; /** Create an OptionalVisitor. */ public OptionalVisitor(BaseTypeChecker checker) { @@ -64,11 +71,15 @@ public OptionalVisitor(BaseTypeChecker checker) { ProcessingEnvironment env = checker.getProcessingEnvironment(); optionalGet = TreeUtils.getMethod("java.util.Optional", "get", 0, env); optionalIsPresent = TreeUtils.getMethod("java.util.Optional", "isPresent", 0, env); + optionalIsEmpty = TreeUtils.getMethodOrNull("java.util.Optional", "isEmpty", 0, env); optionalOf = TreeUtils.getMethod("java.util.Optional", "of", 1, env); optionalOfNullable = TreeUtils.getMethod("java.util.Optional", "ofNullable", 1, env); optionalOrElse = TreeUtils.getMethod("java.util.Optional", "orElse", 1, env); optionalOrElseGet = TreeUtils.getMethod("java.util.Optional", "orElseGet", 1, env); - optionalOrElseThrow = TreeUtils.getMethod("java.util.Optional", "orElseThrow", 1, env); + optionalOrElseThrow = + TreeUtils.getMethodOrNull("java.util.Optional", "orElseThrow", 0, env); + optionalOrElseThrowSupplier = + TreeUtils.getMethod("java.util.Optional", "orElseThrow", 1, env); } @Override @@ -82,10 +93,42 @@ private boolean isCallToGet(ExpressionTree expression) { return TreeUtils.isMethodInvocation(expression, optionalGet, env); } - /** @return true iff expression is a call to java.util.Optional.isPresent */ - private boolean isCallToIsPresent(ExpressionTree expression) { + /** + * Is the expression a call to {@code isPresent} or {@code isEmpty}? If not, returns null. If + * so, returns a pair of (boolean, receiver expression). The boolean is true if the given + * expression is a call to {@code isPresent} and is false if the given expression is a call to + * {@code isEmpty}. + * + * @param expression an expression + * @return a pair of a boolean (indicating whether the expression is a call to {@code + * Optional.isPresent} or to {@code Optional.isEmpty}) and its receiver; or null if not a + * call to either of the methods + */ + private @Nullable Pair isCallToIsPresent(ExpressionTree expression) { ProcessingEnvironment env = checker.getProcessingEnvironment(); - return TreeUtils.isMethodInvocation(expression, optionalIsPresent, env); + boolean negate = false; + while (true) { + switch (expression.getKind()) { + case PARENTHESIZED: + expression = ((ParenthesizedTree) expression).getExpression(); + break; + case LOGICAL_COMPLEMENT: + expression = ((UnaryTree) expression).getExpression(); + negate = !negate; + break; + case METHOD_INVOCATION: + if (TreeUtils.isMethodInvocation(expression, optionalIsPresent, env)) { + return Pair.of(!negate, TreeUtils.getReceiverTree(expression)); + } else if (optionalIsEmpty != null + && TreeUtils.isMethodInvocation(expression, optionalIsEmpty, env)) { + return Pair.of(negate, TreeUtils.getReceiverTree(expression)); + } else { + return null; + } + default: + return null; + } + } } /** @return true iff expression is a call to Optional creation: of, ofNullable. */ @@ -104,7 +147,9 @@ private boolean isOptionalElimation(MethodInvocationTree methInvok) { return TreeUtils.isMethodInvocation(methInvok, optionalGet, env) || TreeUtils.isMethodInvocation(methInvok, optionalOrElse, env) || TreeUtils.isMethodInvocation(methInvok, optionalOrElseGet, env) - || TreeUtils.isMethodInvocation(methInvok, optionalOrElseThrow, env); + || (optionalIsEmpty != null + && TreeUtils.isMethodInvocation(methInvok, optionalOrElseThrow, env)) + || TreeUtils.isMethodInvocation(methInvok, optionalOrElseThrowSupplier, env); } @Override @@ -124,13 +169,17 @@ public Void visitConditionalExpression(ConditionalExpressionTree node, Void p) { public void handleTernaryIsPresentGet(ConditionalExpressionTree node) { ExpressionTree condExpr = TreeUtils.withoutParens(node.getCondition()); + Pair isPresentCall = isCallToIsPresent(condExpr); + if (isPresentCall == null) { + return; + } ExpressionTree trueExpr = TreeUtils.withoutParens(node.getTrueExpression()); ExpressionTree falseExpr = TreeUtils.withoutParens(node.getFalseExpression()); - - if (!isCallToIsPresent(condExpr)) { - return; + if (!isPresentCall.first) { + ExpressionTree tmp = trueExpr; + trueExpr = falseExpr; + falseExpr = tmp; } - ExpressionTree receiver = TreeUtils.getReceiverTree(condExpr); if (trueExpr.getKind() != Kind.METHOD_INVOCATION) { return; @@ -143,6 +192,7 @@ public void handleTernaryIsPresentGet(ConditionalExpressionTree node) { // What is a better way to do this than string comparison? // Use transfer functions and Store entries. + ExpressionTree receiver = isPresentCall.second; if (sameExpression(receiver, getReceiver)) { ExecutableElement ele = TreeUtils.elementFromUse((MethodInvocationTree) trueExpr); @@ -160,8 +210,8 @@ public void handleTernaryIsPresentGet(ConditionalExpressionTree node) { /** Return true if the two trees represent the same expression. */ private boolean sameExpression(ExpressionTree tree1, ExpressionTree tree2) { - Receiver r1 = FlowExpressions.internalReprOf(atypeFactory, tree1); - Receiver r2 = FlowExpressions.internalReprOf(atypeFactory, tree1); + JavaExpression r1 = JavaExpression.fromTree(atypeFactory, tree1); + JavaExpression r2 = JavaExpression.fromTree(atypeFactory, tree1); if (r1 != null && !r1.containsUnknown() && r2 != null && !r2.containsUnknown()) { return r1.equals(r2); } else { @@ -185,8 +235,18 @@ public Void visitIf(IfTree node, Void p) { public void handleConditionalStatementIsPresentGet(IfTree node) { ExpressionTree condExpr = TreeUtils.withoutParens(node.getCondition()); + Pair isPresentCall = isCallToIsPresent(condExpr); + if (isPresentCall == null) { + return; + } + StatementTree thenStmt = skipBlocks(node.getThenStatement()); StatementTree elseStmt = skipBlocks(node.getElseStatement()); + if (!isPresentCall.first) { + StatementTree tmp = thenStmt; + thenStmt = elseStmt; + elseStmt = tmp; + } if (!(elseStmt == null || (elseStmt.getKind() == Tree.Kind.BLOCK @@ -194,10 +254,7 @@ public void handleConditionalStatementIsPresentGet(IfTree node) { // else block is missing or is an empty block: "{}" return; } - if (!isCallToIsPresent(condExpr)) { - return; - } - ExpressionTree receiver = TreeUtils.getReceiverTree(condExpr); + if (thenStmt.getKind() != Kind.EXPRESSION_STATEMENT) { return; } @@ -214,6 +271,7 @@ public void handleConditionalStatementIsPresentGet(IfTree node) { if (!isCallToGet(arg)) { return; } + ExpressionTree receiver = isPresentCall.second; ExpressionTree getReceiver = TreeUtils.getReceiverTree(arg); if (!receiver.toString().equals(getReceiver.toString())) { return; diff --git a/checker/src/main/java/org/checkerframework/checker/regex/RegexTransfer.java b/checker/src/main/java/org/checkerframework/checker/regex/RegexTransfer.java index 1fd773d1c8..83366c690f 100644 --- a/checker/src/main/java/org/checkerframework/checker/regex/RegexTransfer.java +++ b/checker/src/main/java/org/checkerframework/checker/regex/RegexTransfer.java @@ -15,8 +15,7 @@ import org.checkerframework.dataflow.cfg.node.MethodAccessNode; import org.checkerframework.dataflow.cfg.node.MethodInvocationNode; import org.checkerframework.dataflow.cfg.node.Node; -import org.checkerframework.dataflow.expression.FlowExpressions; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.dataflow.util.NodeUtils; import org.checkerframework.framework.flow.CFAbstractAnalysis; import org.checkerframework.framework.flow.CFStore; @@ -86,8 +85,8 @@ private TransferResult handleRegexUtil( CFStore elseStore = thenStore.copy(); ConditionalTransferResult newResult = new ConditionalTransferResult<>(result.getResultValue(), thenStore, elseStore); - Receiver firstParam = - FlowExpressions.internalReprOf( + JavaExpression firstParam = + JavaExpression.fromNode( factory.getContext().getAnnotationProvider(), n.getArgument(0)); // add annotation with correct group count (if possible, @@ -197,8 +196,8 @@ private TransferResult handleMatcherGroupCount( MethodAccessNode methodAccessNode = ((MethodInvocationNode) possibleMatcher).getTarget(); Node receiver = methodAccessNode.getReceiver(); - Receiver matcherReceiver = - FlowExpressions.internalReprOf(analysis.getTypeFactory(), receiver); + JavaExpression matcherReceiver = + JavaExpression.fromNode(analysis.getTypeFactory(), receiver); IntegerLiteralNode iln = (IntegerLiteralNode) possibleConstant; int groupCount; diff --git a/checker/src/main/java/org/checkerframework/checker/regex/RegexUtil.java b/checker/src/main/java/org/checkerframework/checker/regex/RegexUtil.java index 45381b43e9..4709fadcc5 100644 --- a/checker/src/main/java/org/checkerframework/checker/regex/RegexUtil.java +++ b/checker/src/main/java/org/checkerframework/checker/regex/RegexUtil.java @@ -154,7 +154,7 @@ public static boolean isRegex(String s) { * @param groups number of groups expected * @return true iff s is a regular expression with {@code groups} groups */ - @SuppressWarnings({"regex", "all:deterministic"}) // RegexUtil; for purity, catches an exception + @SuppressWarnings("regex") // RegexUtil; for purity, catches an exception @Pure // @EnsuresQualifierIf annotation is extraneous because this method is special-cased // in RegexTransfer. @@ -176,9 +176,7 @@ public static boolean isRegex(String s, int groups) { * @return true iff c is a regular expression */ @SuppressWarnings({ - "regex", - "all:purity.not.deterministic.call", - "lock" + "regex", "lock" }) // RegexUtil; temp value used in pure method is equal up to equals but not up to == @Pure @EnsuresQualifierIf(result = true, expression = "#1", qualifier = Regex.class) @@ -327,7 +325,7 @@ private static String regexErrorMessage(String s, int expectedGroups, int actual * @param p pattern whose groups to count * @return the count of groups in the argument */ - @SuppressWarnings({"all:purity", "lock"}) // does not depend on object identity + @SuppressWarnings("lock") // does not depend on object identity @Pure private static int getGroupCount(Pattern p) { return p.matcher("").groupCount(); diff --git a/checker/src/main/java/org/checkerframework/checker/regex/RegexVisitor.java b/checker/src/main/java/org/checkerframework/checker/regex/RegexVisitor.java index e60415608b..e505baf462 100644 --- a/checker/src/main/java/org/checkerframework/checker/regex/RegexVisitor.java +++ b/checker/src/main/java/org/checkerframework/checker/regex/RegexVisitor.java @@ -44,7 +44,7 @@ public class RegexVisitor extends BaseTypeVisitor { /** * Create a RegexVisitor. * - * @param checker the associated RegexChecker. + * @param checker the associated RegexChecker */ public RegexVisitor(BaseTypeChecker checker) { super(checker); diff --git a/checker/src/main/java/org/checkerframework/checker/regex/qual/PolyRegex.java b/checker/src/main/java/org/checkerframework/checker/regex/qual/PolyRegex.java index 80e5bffdc5..ea81c50f2b 100644 --- a/checker/src/main/java/org/checkerframework/checker/regex/qual/PolyRegex.java +++ b/checker/src/main/java/org/checkerframework/checker/regex/qual/PolyRegex.java @@ -10,9 +10,9 @@ /** * A polymorphic qualifier for the Regex type system. * - *

    Any method written using {@code @PolyRegex} conceptually has two versions: one in which every - * instance of {@code @PolyRegex String} has been replaced by {@code @Regex String}, and one in - * which every instance of {@code @PolyRegex String} has been replaced by {@code String}. + *

    Any method written using {@link PolyRegex} conceptually has two versions: one in which every + * instance of {@link PolyRegex} has been replaced by {@link Regex}, and one in which every instance + * of {@link PolyRegex} has been replaced by {@link UnknownRegex}. * * @checker_framework.manual #regex-checker Regex Checker * @checker_framework.manual #qualifier-polymorphism Qualifier polymorphism diff --git a/checker/src/main/java/org/checkerframework/checker/signature/SignatureTransfer.java b/checker/src/main/java/org/checkerframework/checker/signature/SignatureTransfer.java index c6fbd4e48b..91e2c6d67e 100644 --- a/checker/src/main/java/org/checkerframework/checker/signature/SignatureTransfer.java +++ b/checker/src/main/java/org/checkerframework/checker/signature/SignatureTransfer.java @@ -8,8 +8,7 @@ import org.checkerframework.dataflow.cfg.node.MethodAccessNode; import org.checkerframework.dataflow.cfg.node.MethodInvocationNode; import org.checkerframework.dataflow.cfg.node.Node; -import org.checkerframework.dataflow.expression.FlowExpressions; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.framework.flow.CFAnalysis; import org.checkerframework.framework.flow.CFStore; import org.checkerframework.framework.flow.CFTransfer; @@ -54,8 +53,8 @@ public TransferResult visitMethodInvocation( new ConditionalTransferResult<>( superResult.getResultValue(), thenStore, elseStore); // The refined expression is the receive of the method call. - Receiver refinedExpr = - FlowExpressions.internalReprOf( + JavaExpression refinedExpr = + JavaExpression.fromNode( aTypeFactory.getContext().getAnnotationProvider(), receiver); elseStore.insertValue(refinedExpr, aTypeFactory.CANONICAL_NAME); diff --git a/checker/src/main/java/org/checkerframework/checker/signature/qual/DotSeparatedIdentifiers.java b/checker/src/main/java/org/checkerframework/checker/signature/qual/DotSeparatedIdentifiers.java index 79e63100fc..1f75bd0498 100644 --- a/checker/src/main/java/org/checkerframework/checker/signature/qual/DotSeparatedIdentifiers.java +++ b/checker/src/main/java/org/checkerframework/checker/signature/qual/DotSeparatedIdentifiers.java @@ -13,7 +13,7 @@ * {@linkplain org.checkerframework.checker.signature.qual.BinaryName binary name}. It represents a * non-array, non-inner class: dot-separated identifiers. * - *

    Examples: int, MyClass, java.lang.Integer + *

    Examples: int, MyClass, java.lang, java.lang.Integer * * @checker_framework.manual #signature-checker Signature Checker */ diff --git a/checker/src/main/java/org/checkerframework/checker/signedness/SignednessAnnotatedTypeFactory.java b/checker/src/main/java/org/checkerframework/checker/signedness/SignednessAnnotatedTypeFactory.java index 380a608e56..4a4e1acfe4 100644 --- a/checker/src/main/java/org/checkerframework/checker/signedness/SignednessAnnotatedTypeFactory.java +++ b/checker/src/main/java/org/checkerframework/checker/signedness/SignednessAnnotatedTypeFactory.java @@ -83,9 +83,9 @@ public class SignednessAnnotatedTypeFactory extends BaseAnnotatedTypeFactory { public SignednessAnnotatedTypeFactory(BaseTypeChecker checker) { super(checker); - addAliasedAnnotation(SignedPositive.class, SIGNEDNESS_GLB); + addAliasedTypeAnnotation(SignedPositive.class, SIGNEDNESS_GLB); - addAliasedAnnotation("jdk.jfr.Unsigned", UNSIGNED); + addAliasedTypeAnnotation("jdk.jfr.Unsigned", UNSIGNED); postInit(); } @@ -329,7 +329,7 @@ private boolean isMask(Tree node) { * Returns the type of a primitive cast, or null the argument is not a cast to a primitive. * * @param node a tree that might be a cast to a primitive - * @return type of a primitive cast, or null if not a cast to a primitive. + * @return type of a primitive cast, or null if not a cast to a primitive */ private PrimitiveTypeTree primitiveTypeCast(Tree node) { if (node.getKind() != Kind.TYPE_CAST) { @@ -354,7 +354,7 @@ private PrimitiveTypeTree primitiveTypeCast(Tree node) { } /** - * Returns true iff the given tree is a literal + * Returns true iff the given tree is a literal. * * @param expr a tree to test * @return true iff expr is a literal diff --git a/checker/src/main/java/org/checkerframework/checker/units/UnitsAnnotatedTypeFactory.java b/checker/src/main/java/org/checkerframework/checker/units/UnitsAnnotatedTypeFactory.java index bbcf4c1e10..3f276132aa 100644 --- a/checker/src/main/java/org/checkerframework/checker/units/UnitsAnnotatedTypeFactory.java +++ b/checker/src/main/java/org/checkerframework/checker/units/UnitsAnnotatedTypeFactory.java @@ -617,7 +617,7 @@ protected AnnotationMirror greatestLowerBoundWithElements( } } - /** UnitsQualifierKindHierarchy */ + /** UnitsQualifierKindHierarchy. */ @AnnotatedFor("nullness") protected static class UnitsQualifierKindHierarchy extends DefaultQualifierKindHierarchy { diff --git a/checker/src/main/java/org/checkerframework/checker/units/UnitsRelationsTools.java b/checker/src/main/java/org/checkerframework/checker/units/UnitsRelationsTools.java index a12577bfe4..f6c86f8f19 100644 --- a/checker/src/main/java/org/checkerframework/checker/units/UnitsRelationsTools.java +++ b/checker/src/main/java/org/checkerframework/checker/units/UnitsRelationsTools.java @@ -281,7 +281,7 @@ public static boolean hasSpecificUnitIgnoringPrefix( final ProcessingEnvironment env, final Class annoClass, final Prefix p) { - AnnotationBuilder builder = new AnnotationBuilder(env, annoClass.getCanonicalName()); + AnnotationBuilder builder = new AnnotationBuilder(env, annoClass); builder.setValue("value", p); return builder.build(); } diff --git a/checker/src/test/java/tests/CalledMethodsAutoValueTest.java b/checker/src/test/java/org/checkerframework/checker/test/junit/CalledMethodsAutoValueTest.java similarity index 96% rename from checker/src/test/java/tests/CalledMethodsAutoValueTest.java rename to checker/src/test/java/org/checkerframework/checker/test/junit/CalledMethodsAutoValueTest.java index 6880fa4f2c..3668fef99d 100644 --- a/checker/src/test/java/tests/CalledMethodsAutoValueTest.java +++ b/checker/src/test/java/org/checkerframework/checker/test/junit/CalledMethodsAutoValueTest.java @@ -1,4 +1,4 @@ -package tests; +package org.checkerframework.checker.test.junit; import java.io.File; import java.util.Arrays; diff --git a/checker/src/test/java/org/checkerframework/checker/test/junit/CalledMethodsDisableReturnsReceiverTest.java b/checker/src/test/java/org/checkerframework/checker/test/junit/CalledMethodsDisableReturnsReceiverTest.java new file mode 100644 index 0000000000..8996aae877 --- /dev/null +++ b/checker/src/test/java/org/checkerframework/checker/test/junit/CalledMethodsDisableReturnsReceiverTest.java @@ -0,0 +1,27 @@ +package org.checkerframework.checker.test.junit; + +import java.io.File; +import java.util.List; +import org.checkerframework.checker.calledmethods.CalledMethodsChecker; +import org.checkerframework.framework.test.CheckerFrameworkPerDirectoryTest; +import org.junit.runners.Parameterized.Parameters; + +/** Basic tests for the Called Methods Checker. */ +public class CalledMethodsDisableReturnsReceiverTest extends CheckerFrameworkPerDirectoryTest { + public CalledMethodsDisableReturnsReceiverTest(List testFiles) { + super( + testFiles, + CalledMethodsChecker.class, + "calledmethods-disablereturnsreceiver", + "-Anomsgtext", + "-AdisableReturnsReceiver", + "-nowarn", + "-encoding", + "UTF-8"); + } + + @Parameters + public static String[] getTestDirs() { + return new String[] {"calledmethods-disablereturnsreceiver"}; + } +} diff --git a/checker/src/test/java/tests/CalledMethodsDisableframeworksTest.java b/checker/src/test/java/org/checkerframework/checker/test/junit/CalledMethodsDisableframeworksTest.java similarity index 97% rename from checker/src/test/java/tests/CalledMethodsDisableframeworksTest.java rename to checker/src/test/java/org/checkerframework/checker/test/junit/CalledMethodsDisableframeworksTest.java index ca8d3fd88d..2f27aa4709 100644 --- a/checker/src/test/java/tests/CalledMethodsDisableframeworksTest.java +++ b/checker/src/test/java/org/checkerframework/checker/test/junit/CalledMethodsDisableframeworksTest.java @@ -1,4 +1,4 @@ -package tests; +package org.checkerframework.checker.test.junit; import java.io.File; import java.util.Arrays; diff --git a/checker/src/test/java/tests/CalledMethodsLombokTest.java b/checker/src/test/java/org/checkerframework/checker/test/junit/CalledMethodsLombokTest.java similarity index 94% rename from checker/src/test/java/tests/CalledMethodsLombokTest.java rename to checker/src/test/java/org/checkerframework/checker/test/junit/CalledMethodsLombokTest.java index bac1a58f27..429d0a2896 100644 --- a/checker/src/test/java/tests/CalledMethodsLombokTest.java +++ b/checker/src/test/java/org/checkerframework/checker/test/junit/CalledMethodsLombokTest.java @@ -1,4 +1,4 @@ -package tests; +package org.checkerframework.checker.test.junit; import java.io.File; import java.util.List; diff --git a/checker/src/test/java/tests/CalledMethodsTest.java b/checker/src/test/java/org/checkerframework/checker/test/junit/CalledMethodsTest.java similarity index 94% rename from checker/src/test/java/tests/CalledMethodsTest.java rename to checker/src/test/java/org/checkerframework/checker/test/junit/CalledMethodsTest.java index f3635add1c..a39f4768c4 100644 --- a/checker/src/test/java/tests/CalledMethodsTest.java +++ b/checker/src/test/java/org/checkerframework/checker/test/junit/CalledMethodsTest.java @@ -1,4 +1,4 @@ -package tests; +package org.checkerframework.checker.test.junit; import java.io.File; import java.util.List; diff --git a/checker/src/test/java/tests/CalledMethodsUseValueCheckerTest.java b/checker/src/test/java/org/checkerframework/checker/test/junit/CalledMethodsUseValueCheckerTest.java similarity index 94% rename from checker/src/test/java/tests/CalledMethodsUseValueCheckerTest.java rename to checker/src/test/java/org/checkerframework/checker/test/junit/CalledMethodsUseValueCheckerTest.java index febf01711c..f31c8ae3e8 100644 --- a/checker/src/test/java/tests/CalledMethodsUseValueCheckerTest.java +++ b/checker/src/test/java/org/checkerframework/checker/test/junit/CalledMethodsUseValueCheckerTest.java @@ -1,4 +1,4 @@ -package tests; +package org.checkerframework.checker.test.junit; import java.io.File; import java.util.List; diff --git a/framework/src/test/java/org/checkerframework/framework/test/junit/wpirunners/README.md b/checker/src/test/java/org/checkerframework/checker/test/junit/wpirunners/README.md similarity index 71% rename from framework/src/test/java/org/checkerframework/framework/test/junit/wpirunners/README.md rename to checker/src/test/java/org/checkerframework/checker/test/junit/wpirunners/README.md index 673d748f6b..6ad7a76231 100644 --- a/framework/src/test/java/org/checkerframework/framework/test/junit/wpirunners/README.md +++ b/checker/src/test/java/org/checkerframework/checker/test/junit/wpirunners/README.md @@ -1,4 +1,4 @@ This package contains the test runners for testing whole-program inference. They are in a separate package so that they don't run by default; they should only run when they're invoked directly by their corresponding build rules, which -are in framework/build.gradle (wholeProgramInferenceTest and wholeProgramInferenceStubsTest). +are in checker/build.gradle (wholeProgramInferenceTest and wholeProgramInferenceStubsTest). diff --git a/framework/src/test/java/org/checkerframework/framework/test/junit/wpirunners/WholeProgramInferenceJaifsTest.java b/checker/src/test/java/org/checkerframework/checker/test/junit/wpirunners/WholeProgramInferenceTestCheckerJaifsTest.java similarity index 61% rename from framework/src/test/java/org/checkerframework/framework/test/junit/wpirunners/WholeProgramInferenceJaifsTest.java rename to checker/src/test/java/org/checkerframework/checker/test/junit/wpirunners/WholeProgramInferenceTestCheckerJaifsTest.java index 5d7e6886ba..0c99c387a4 100644 --- a/framework/src/test/java/org/checkerframework/framework/test/junit/wpirunners/WholeProgramInferenceJaifsTest.java +++ b/checker/src/test/java/org/checkerframework/checker/test/junit/wpirunners/WholeProgramInferenceTestCheckerJaifsTest.java @@ -1,33 +1,33 @@ -package org.checkerframework.framework.test.junit.wpirunners; +package org.checkerframework.checker.test.junit.wpirunners; import java.io.File; import java.util.List; +import org.checkerframework.checker.testchecker.wholeprograminference.WholeProgramInferenceTestChecker; import org.checkerframework.framework.test.CheckerFrameworkPerDirectoryTest; -import org.checkerframework.framework.testchecker.wholeprograminference.WholeProgramInferenceTestChecker; import org.junit.experimental.categories.Category; import org.junit.runners.Parameterized.Parameters; /** * Runs whole-program inference and inserts annotations into source code. * - *

    IMPORTANT: The errors captured in the tests located in tests/whole-program-inference/ are not + *

    IMPORTANT: The errors captured in the tests located in tests/wpi-testchecker/ are not * relevant. The meaning of this test class is to test if the generated .jaif files are similar to * the expected ones. The errors on .java files must be ignored. */ -@Category(WholeProgramInferenceJaifsTest.class) -public class WholeProgramInferenceJaifsTest extends CheckerFrameworkPerDirectoryTest { +@Category(WholeProgramInferenceTestCheckerJaifsTest.class) +public class WholeProgramInferenceTestCheckerJaifsTest extends CheckerFrameworkPerDirectoryTest { /** @param testFiles the files containing test code, which will be type-checked */ - public WholeProgramInferenceJaifsTest(List testFiles) { + public WholeProgramInferenceTestCheckerJaifsTest(List testFiles) { super( testFiles, WholeProgramInferenceTestChecker.class, - "value", + "wpi-testchecker/non-annotated", "-Anomsgtext", "-Ainfer=jaifs"); } @Parameters public static String[] getTestDirs() { - return new String[] {"whole-program-inference/non-annotated"}; + return new String[] {"wpi-testchecker/non-annotated"}; } } diff --git a/checker/src/test/java/org/checkerframework/checker/test/junit/wpirunners/WholeProgramInferenceTestCheckerJaifsValidationTest.java b/checker/src/test/java/org/checkerframework/checker/test/junit/wpirunners/WholeProgramInferenceTestCheckerJaifsValidationTest.java new file mode 100644 index 0000000000..4fcc75f1d5 --- /dev/null +++ b/checker/src/test/java/org/checkerframework/checker/test/junit/wpirunners/WholeProgramInferenceTestCheckerJaifsValidationTest.java @@ -0,0 +1,42 @@ +package org.checkerframework.checker.test.junit.wpirunners; + +import java.io.File; +import java.util.List; +import org.checkerframework.checker.testchecker.wholeprograminference.WholeProgramInferenceTestChecker; +import org.checkerframework.framework.test.CheckerFrameworkPerDirectoryTest; +import org.junit.experimental.categories.Category; +import org.junit.runners.Parameterized.Parameters; + +/** + * Tests whole-program type inference with the aid of .jaif files. This test is the second pass, + * which ensures that with the annotations inserted, the errors are no longer issued. + */ +@Category(WholeProgramInferenceTestCheckerJaifsTest.class) +public class WholeProgramInferenceTestCheckerJaifsValidationTest + extends CheckerFrameworkPerDirectoryTest { + /** @param testFiles the files containing test code, which will be type-checked */ + public WholeProgramInferenceTestCheckerJaifsValidationTest(List testFiles) { + super( + testFiles, + WholeProgramInferenceTestChecker.class, + "wpi-testchecker/non-annotated", + "-Anomsgtext"); + } + + @Override + public void run() { + // Only run if annotated files have been created. + // See wholeProgramInferenceTests task. + if (!new File("tests/wpi-testchecker/annotated/").exists()) { + throw new RuntimeException( + WholeProgramInferenceTestCheckerJaifsTest.class + + " must be run before this test."); + } + super.run(); + } + + @Parameters + public static String[] getTestDirs() { + return new String[] {"wpi-testchecker/annotated/"}; + } +} diff --git a/framework/src/test/java/org/checkerframework/framework/test/junit/wpirunners/WholeProgramInferenceStubsTest.java b/checker/src/test/java/org/checkerframework/checker/test/junit/wpirunners/WholeProgramInferenceTestCheckerStubsTest.java similarity index 63% rename from framework/src/test/java/org/checkerframework/framework/test/junit/wpirunners/WholeProgramInferenceStubsTest.java rename to checker/src/test/java/org/checkerframework/checker/test/junit/wpirunners/WholeProgramInferenceTestCheckerStubsTest.java index 6e18c683d2..71354e0183 100644 --- a/framework/src/test/java/org/checkerframework/framework/test/junit/wpirunners/WholeProgramInferenceStubsTest.java +++ b/checker/src/test/java/org/checkerframework/checker/test/junit/wpirunners/WholeProgramInferenceTestCheckerStubsTest.java @@ -1,9 +1,9 @@ -package org.checkerframework.framework.test.junit.wpirunners; +package org.checkerframework.checker.test.junit.wpirunners; import java.io.File; import java.util.List; +import org.checkerframework.checker.testchecker.wholeprograminference.WholeProgramInferenceTestChecker; import org.checkerframework.framework.test.CheckerFrameworkPerDirectoryTest; -import org.checkerframework.framework.testchecker.wholeprograminference.WholeProgramInferenceTestChecker; import org.junit.experimental.categories.Category; import org.junit.runners.Parameterized.Parameters; @@ -11,25 +11,25 @@ * Tests whole-program inference with the aid of stub files. This test is the first pass on the test * data, which generates the stubs. * - *

    IMPORTANT: The errors captured in the tests located in tests/whole-program-inference/ are not + *

    IMPORTANT: The errors captured in the tests located in tests/wpi-testchecker/ are not * relevant. The meaning of this test class is to test if the generated stub files are similar to * the expected ones. The errors on .java files must be ignored. */ -@Category(WholeProgramInferenceStubsTest.class) -public class WholeProgramInferenceStubsTest extends CheckerFrameworkPerDirectoryTest { +@Category(WholeProgramInferenceTestCheckerStubsTest.class) +public class WholeProgramInferenceTestCheckerStubsTest extends CheckerFrameworkPerDirectoryTest { /** @param testFiles the files containing test code, which will be type-checked */ - public WholeProgramInferenceStubsTest(List testFiles) { + public WholeProgramInferenceTestCheckerStubsTest(List testFiles) { super( testFiles, WholeProgramInferenceTestChecker.class, - "whole-program-inference/non-annotated", + "wpi-testchecker/non-annotated", "-Anomsgtext", "-Ainfer=stubs"); } @Parameters public static String[] getTestDirs() { - return new String[] {"whole-program-inference/non-annotated"}; + return new String[] {"wpi-testchecker/non-annotated"}; } } diff --git a/framework/src/test/java/org/checkerframework/framework/test/junit/wpirunners/WholeProgramInferenceStubsValidationTest.java b/checker/src/test/java/org/checkerframework/checker/test/junit/wpirunners/WholeProgramInferenceTestCheckerStubsValidationTest.java similarity index 55% rename from framework/src/test/java/org/checkerframework/framework/test/junit/wpirunners/WholeProgramInferenceStubsValidationTest.java rename to checker/src/test/java/org/checkerframework/checker/test/junit/wpirunners/WholeProgramInferenceTestCheckerStubsValidationTest.java index a620da10ab..3276999215 100644 --- a/framework/src/test/java/org/checkerframework/framework/test/junit/wpirunners/WholeProgramInferenceStubsValidationTest.java +++ b/checker/src/test/java/org/checkerframework/checker/test/junit/wpirunners/WholeProgramInferenceTestCheckerStubsValidationTest.java @@ -1,9 +1,9 @@ -package org.checkerframework.framework.test.junit.wpirunners; +package org.checkerframework.checker.test.junit.wpirunners; import java.io.File; import java.util.List; +import org.checkerframework.checker.testchecker.wholeprograminference.WholeProgramInferenceTestChecker; import org.checkerframework.framework.test.CheckerFrameworkPerDirectoryTest; -import org.checkerframework.framework.testchecker.wholeprograminference.WholeProgramInferenceTestChecker; import org.junit.experimental.categories.Category; import org.junit.runners.Parameterized.Parameters; @@ -11,17 +11,18 @@ * Tests whole-program type inference with stub files. This test is the second pass, which ensures * that with the stubs in place, the errors that those annotations remove are no longer issued. */ -@Category(WholeProgramInferenceStubsTest.class) -public class WholeProgramInferenceStubsValidationTest extends CheckerFrameworkPerDirectoryTest { +@Category(WholeProgramInferenceTestCheckerStubsTest.class) +public class WholeProgramInferenceTestCheckerStubsValidationTest + extends CheckerFrameworkPerDirectoryTest { /** @param testFiles the files containing test code, which will be type-checked */ - public WholeProgramInferenceStubsValidationTest(List testFiles) { + public WholeProgramInferenceTestCheckerStubsValidationTest(List testFiles) { super( testFiles, WholeProgramInferenceTestChecker.class, - "whole-program-inference/annotated", + "wpi-testchecker/annotated", "-Anomsgtext", - "-Astubs=build/whole-program-inference", + "-Astubs=tests/wpi-testchecker/inference-output", // "-AstubDebug", "-AmergeStubsWithSource"); } @@ -30,15 +31,16 @@ public WholeProgramInferenceStubsValidationTest(List testFiles) { public void run() { // Only run if annotated files have been created. // See wholeProgramInferenceTests task. - if (!new File("tests/whole-program-inference/annotated/").exists()) { + if (!new File("tests/wpi-testchecker/annotated/").exists()) { throw new RuntimeException( - WholeProgramInferenceStubsTest.class + " must be run before this test."); + WholeProgramInferenceTestCheckerStubsTest.class + + " must be run before this test."); } super.run(); } @Parameters public static String[] getTestDirs() { - return new String[] {"whole-program-inference/annotated/"}; + return new String[] {"wpi-testchecker/annotated/"}; } } diff --git a/checker/src/test/java/org/checkerframework/checker/testchecker/lubglb/FormatterLubGlbChecker.java b/checker/src/test/java/org/checkerframework/checker/testchecker/lubglb/FormatterLubGlbChecker.java index f3d6c59903..51346ce9dc 100644 --- a/checker/src/test/java/org/checkerframework/checker/testchecker/lubglb/FormatterLubGlbChecker.java +++ b/checker/src/test/java/org/checkerframework/checker/testchecker/lubglb/FormatterLubGlbChecker.java @@ -86,20 +86,19 @@ public void initChecker() { AnnotationBuilder.elementNamesValues("value", "dummy")); AnnotationMirror FORMATBOTTOM = AnnotationBuilder.fromClass(elements, FormatBottom.class); - AnnotationBuilder builder = - new AnnotationBuilder(processingEnv, InvalidFormat.class.getCanonicalName()); + AnnotationBuilder builder = new AnnotationBuilder(processingEnv, InvalidFormat.class); builder.setValue("value", "Message"); AnnotationMirror invalidFormatWithMessage = builder.build(); - builder = new AnnotationBuilder(processingEnv, InvalidFormat.class.getCanonicalName()); + builder = new AnnotationBuilder(processingEnv, InvalidFormat.class); builder.setValue("value", "Message2"); AnnotationMirror invalidFormatWithMessage2 = builder.build(); - builder = new AnnotationBuilder(processingEnv, InvalidFormat.class.getCanonicalName()); + builder = new AnnotationBuilder(processingEnv, InvalidFormat.class); builder.setValue("value", "(\"Message\" or \"Message2\")"); AnnotationMirror invalidFormatWithMessagesOred = builder.build(); - builder = new AnnotationBuilder(processingEnv, InvalidFormat.class.getCanonicalName()); + builder = new AnnotationBuilder(processingEnv, InvalidFormat.class); builder.setValue("value", "(\"Message\" and \"Message2\")"); AnnotationMirror invalidFormatWithMessagesAnded = builder.build(); diff --git a/checker/src/test/java/org/checkerframework/checker/testchecker/lubglb/I18nFormatterLubGlbChecker.java b/checker/src/test/java/org/checkerframework/checker/testchecker/lubglb/I18nFormatterLubGlbChecker.java index d7087040f0..58bef3d25b 100644 --- a/checker/src/test/java/org/checkerframework/checker/testchecker/lubglb/I18nFormatterLubGlbChecker.java +++ b/checker/src/test/java/org/checkerframework/checker/testchecker/lubglb/I18nFormatterLubGlbChecker.java @@ -97,28 +97,27 @@ public void initChecker() { AnnotationMirror I18NFORMATBOTTOM = AnnotationBuilder.fromClass(elements, I18nFormatBottom.class); - AnnotationBuilder builder = - new AnnotationBuilder(processingEnv, I18nInvalidFormat.class.getCanonicalName()); + AnnotationBuilder builder = new AnnotationBuilder(processingEnv, I18nInvalidFormat.class); builder.setValue("value", "Message"); AnnotationMirror i18nInvalidFormatWithMessage = builder.build(); - builder = new AnnotationBuilder(processingEnv, I18nInvalidFormat.class.getCanonicalName()); + builder = new AnnotationBuilder(processingEnv, I18nInvalidFormat.class); builder.setValue("value", "Message2"); AnnotationMirror i18nInvalidFormatWithMessage2 = builder.build(); - builder = new AnnotationBuilder(processingEnv, I18nInvalidFormat.class.getCanonicalName()); + builder = new AnnotationBuilder(processingEnv, I18nInvalidFormat.class); builder.setValue("value", "(\"Message\" or \"Message2\")"); AnnotationMirror i18nInvalidFormatWithMessagesOred = builder.build(); - builder = new AnnotationBuilder(processingEnv, I18nInvalidFormat.class.getCanonicalName()); + builder = new AnnotationBuilder(processingEnv, I18nInvalidFormat.class); builder.setValue("value", "(\"Message\" and \"Message2\")"); AnnotationMirror i18nInvalidFormatWithMessagesAnded = builder.build(); - builder = new AnnotationBuilder(processingEnv, I18nFormatFor.class.getCanonicalName()); + builder = new AnnotationBuilder(processingEnv, I18nFormatFor.class); builder.setValue("value", "#1"); AnnotationMirror i18nFormatForWithValue1 = builder.build(); - builder = new AnnotationBuilder(processingEnv, I18nFormatFor.class.getCanonicalName()); + builder = new AnnotationBuilder(processingEnv, I18nFormatFor.class); builder.setValue("value", "#2"); AnnotationMirror i18nFormatForWithValue2 = builder.build(); diff --git a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/WholeProgramInferenceTestAnnotatedTypeFactory.java b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/WholeProgramInferenceTestAnnotatedTypeFactory.java similarity index 89% rename from framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/WholeProgramInferenceTestAnnotatedTypeFactory.java rename to checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/WholeProgramInferenceTestAnnotatedTypeFactory.java index d35265035f..4cad9db728 100644 --- a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/WholeProgramInferenceTestAnnotatedTypeFactory.java +++ b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/WholeProgramInferenceTestAnnotatedTypeFactory.java @@ -1,4 +1,4 @@ -package org.checkerframework.framework.testchecker.wholeprograminference; +package org.checkerframework.checker.testchecker.wholeprograminference; import java.lang.annotation.Annotation; import java.util.Arrays; @@ -9,17 +9,17 @@ import java.util.Set; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.util.Elements; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.DefaultType; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.ImplicitAnno; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Parent; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling2; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.SiblingWithFields; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Top; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.WholeProgramInferenceBottom; import org.checkerframework.common.basetype.BaseAnnotatedTypeFactory; import org.checkerframework.common.basetype.BaseTypeChecker; import org.checkerframework.framework.qual.LiteralKind; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.DefaultType; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.ImplicitAnno; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Parent; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling2; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.SiblingWithFields; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Top; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.WholeProgramInferenceBottom; import org.checkerframework.framework.type.MostlyNoElementQualifierHierarchy; import org.checkerframework.framework.type.QualifierHierarchy; import org.checkerframework.framework.type.treeannotator.ListTreeAnnotator; diff --git a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/WholeProgramInferenceTestChecker.java b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/WholeProgramInferenceTestChecker.java similarity index 93% rename from framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/WholeProgramInferenceTestChecker.java rename to checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/WholeProgramInferenceTestChecker.java index a7b43cc9c1..555ddce61d 100644 --- a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/WholeProgramInferenceTestChecker.java +++ b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/WholeProgramInferenceTestChecker.java @@ -1,4 +1,4 @@ -package org.checkerframework.framework.testchecker.wholeprograminference; +package org.checkerframework.checker.testchecker.wholeprograminference; import java.util.LinkedHashSet; import org.checkerframework.common.basetype.BaseTypeChecker; diff --git a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/WholeProgramInferenceTestVisitor.java b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/WholeProgramInferenceTestVisitor.java similarity index 90% rename from framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/WholeProgramInferenceTestVisitor.java rename to checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/WholeProgramInferenceTestVisitor.java index d14ece66d4..e870c23e2e 100644 --- a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/WholeProgramInferenceTestVisitor.java +++ b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/WholeProgramInferenceTestVisitor.java @@ -1,13 +1,13 @@ -package org.checkerframework.framework.testchecker.wholeprograminference; +package org.checkerframework.checker.testchecker.wholeprograminference; import com.sun.source.tree.AnnotationTree; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.TreeInfo; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.DefaultType; import org.checkerframework.common.basetype.BaseTypeChecker; import org.checkerframework.common.basetype.BaseTypeVisitor; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.DefaultType; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType; /** Visitor for a simple type system to test whole-program inference using .jaif files. */ diff --git a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/DefaultType.java b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/DefaultType.java similarity index 87% rename from framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/DefaultType.java rename to checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/DefaultType.java index f0f84d57f4..4afcb9144e 100644 --- a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/DefaultType.java +++ b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/DefaultType.java @@ -1,4 +1,4 @@ -package org.checkerframework.framework.testchecker.wholeprograminference.qual; +package org.checkerframework.checker.testchecker.wholeprograminference.qual; import java.lang.annotation.ElementType; import java.lang.annotation.Target; diff --git a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/ImplicitAnno.java b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/ImplicitAnno.java similarity index 88% rename from framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/ImplicitAnno.java rename to checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/ImplicitAnno.java index cbbd46c51c..2d9281ee0e 100644 --- a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/ImplicitAnno.java +++ b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/ImplicitAnno.java @@ -1,4 +1,4 @@ -package org.checkerframework.framework.testchecker.wholeprograminference.qual; +package org.checkerframework.checker.testchecker.wholeprograminference.qual; import java.lang.annotation.ElementType; import java.lang.annotation.Target; diff --git a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/Parent.java b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/Parent.java similarity index 81% rename from framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/Parent.java rename to checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/Parent.java index 65e28e9079..092deef9b7 100644 --- a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/Parent.java +++ b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/Parent.java @@ -1,4 +1,4 @@ -package org.checkerframework.framework.testchecker.wholeprograminference.qual; +package org.checkerframework.checker.testchecker.wholeprograminference.qual; import java.lang.annotation.ElementType; import java.lang.annotation.Target; diff --git a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/Sibling1.java b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/Sibling1.java similarity index 81% rename from framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/Sibling1.java rename to checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/Sibling1.java index 9f7cb0c127..72c31363b9 100644 --- a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/Sibling1.java +++ b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/Sibling1.java @@ -1,4 +1,4 @@ -package org.checkerframework.framework.testchecker.wholeprograminference.qual; +package org.checkerframework.checker.testchecker.wholeprograminference.qual; import java.lang.annotation.ElementType; import java.lang.annotation.Target; diff --git a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/Sibling2.java b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/Sibling2.java similarity index 81% rename from framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/Sibling2.java rename to checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/Sibling2.java index e4b89fe8d5..b1168fe196 100644 --- a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/Sibling2.java +++ b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/Sibling2.java @@ -1,4 +1,4 @@ -package org.checkerframework.framework.testchecker.wholeprograminference.qual; +package org.checkerframework.checker.testchecker.wholeprograminference.qual; import java.lang.annotation.ElementType; import java.lang.annotation.Target; diff --git a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/SiblingWithFields.java b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/SiblingWithFields.java similarity index 84% rename from framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/SiblingWithFields.java rename to checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/SiblingWithFields.java index 547a68dd52..069d1afb52 100644 --- a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/SiblingWithFields.java +++ b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/SiblingWithFields.java @@ -1,4 +1,4 @@ -package org.checkerframework.framework.testchecker.wholeprograminference.qual; +package org.checkerframework.checker.testchecker.wholeprograminference.qual; import java.lang.annotation.ElementType; import java.lang.annotation.Target; diff --git a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/ToIgnore.java b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/ToIgnore.java similarity index 74% rename from framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/ToIgnore.java rename to checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/ToIgnore.java index 7ca4d133c9..945075fb2f 100644 --- a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/ToIgnore.java +++ b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/ToIgnore.java @@ -1,4 +1,4 @@ -package org.checkerframework.framework.testchecker.wholeprograminference.qual; +package org.checkerframework.checker.testchecker.wholeprograminference.qual; import org.checkerframework.framework.qual.IgnoreInWholeProgramInference; diff --git a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/Top.java b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/Top.java similarity index 80% rename from framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/Top.java rename to checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/Top.java index 181b504eb9..0ca9c89a78 100644 --- a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/Top.java +++ b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/Top.java @@ -1,4 +1,4 @@ -package org.checkerframework.framework.testchecker.wholeprograminference.qual; +package org.checkerframework.checker.testchecker.wholeprograminference.qual; import java.lang.annotation.ElementType; import java.lang.annotation.Target; diff --git a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/WholeProgramInferenceBottom.java b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/WholeProgramInferenceBottom.java similarity index 89% rename from framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/WholeProgramInferenceBottom.java rename to checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/WholeProgramInferenceBottom.java index 38c1eb148a..9d6ad1254a 100644 --- a/framework/src/test/java/org/checkerframework/framework/testchecker/wholeprograminference/qual/WholeProgramInferenceBottom.java +++ b/checker/src/test/java/org/checkerframework/checker/testchecker/wholeprograminference/qual/WholeProgramInferenceBottom.java @@ -1,4 +1,4 @@ -package org.checkerframework.framework.testchecker.wholeprograminference.qual; +package org.checkerframework.checker.testchecker.wholeprograminference.qual; import java.lang.annotation.ElementType; import java.lang.annotation.Target; diff --git a/checker/tests/README b/checker/tests/README index fb7bf18a4a..24aff07191 100644 --- a/checker/tests/README +++ b/checker/tests/README @@ -85,7 +85,7 @@ error messages. Suppose that you want to test the Nullness Checker's behavior when type-checking the following Java class: -class MyNullnessTest { +public class MyNullnessTest { void method() { Object nullable = null; nullable.toString(); // should emit error @@ -104,7 +104,7 @@ directly preceding the expected error line. If a warning rather than an error is expected, insert the line // :: warning: () If a stub parser warning is expected, insert the line - //warning: StubParser: + //warning: AnnotationFileParser: If multiple errors are expected on a single line, duplicate everthing except the "//" comment characters, as in // :: error: () :: error: () @@ -115,7 +115,7 @@ a line, to indicate a warning on the line immediately after the "{". So the final test case would be: -class MyNullnessTest { +public class MyNullnessTest { void method() { Object nullable = null; // :: error: (dereference.of.nullable) diff --git a/checker/tests/aggregate/NullnessAndRegex.java b/checker/tests/aggregate/NullnessAndRegex.java index f1c1107217..43f77b9608 100644 --- a/checker/tests/aggregate/NullnessAndRegex.java +++ b/checker/tests/aggregate/NullnessAndRegex.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.i18n.qual.Localized; import org.checkerframework.checker.regex.qual.Regex; -class NullnessAndRegex { +public class NullnessAndRegex { // :: error: (assignment.type.incompatible) @Regex String s1 = "De(mo"; // :: error: (assignment.type.incompatible) diff --git a/checker/tests/aggregate/Placeholder.java b/checker/tests/aggregate/Placeholder.java index 79887ccf82..fa7714a7e8 100644 --- a/checker/tests/aggregate/Placeholder.java +++ b/checker/tests/aggregate/Placeholder.java @@ -2,4 +2,4 @@ // We should add more files to test // aggregate checker functionality. -class Placeholder {} +public class Placeholder {} diff --git a/checker/tests/calledmethods-autovalue/Inheritance.java b/checker/tests/calledmethods-autovalue/Inheritance.java index 32041b3aa3..f3450779cd 100644 --- a/checker/tests/calledmethods-autovalue/Inheritance.java +++ b/checker/tests/calledmethods-autovalue/Inheritance.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.calledmethods.qual.*; import org.checkerframework.common.returnsreceiver.qual.This; -class Inheritance { +public class Inheritance { static interface Props { String name(); diff --git a/checker/tests/calledmethods-disableframeworks/LombokBuilderExample.java b/checker/tests/calledmethods-disableframeworks/LombokBuilderExample.java index 4844df87ba..926d12ecdc 100644 --- a/checker/tests/calledmethods-disableframeworks/LombokBuilderExample.java +++ b/checker/tests/calledmethods-disableframeworks/LombokBuilderExample.java @@ -1,6 +1,6 @@ // Generated by delombok at Wed Aug 14 15:57:15 PDT 2019 // A test for support for the builder() method in Lombok builders. -class LombokBuilderExample { +public class LombokBuilderExample { @lombok.NonNull Object foo; @lombok.NonNull Object bar; diff --git a/checker/tests/calledmethods-disablereturnsreceiver/SimpleFluentInference.java b/checker/tests/calledmethods-disablereturnsreceiver/SimpleFluentInference.java new file mode 100644 index 0000000000..20fbf9605a --- /dev/null +++ b/checker/tests/calledmethods-disablereturnsreceiver/SimpleFluentInference.java @@ -0,0 +1,76 @@ +// This is a copy of SimpleFluentInference.java in the main calledmethods +// test directory. The only difference is that the expected errors have been +// modified to account for the Returns Receiver checker having been disabled. + +import org.checkerframework.checker.calledmethods.qual.*; +import org.checkerframework.common.returnsreceiver.qual.*; + +/* Simple inference of a fluent builder */ +public class SimpleFluentInference { + SimpleFluentInference build(@CalledMethods({"a", "b"}) SimpleFluentInference this) { + return this; + } + + SimpleFluentInference weakbuild(@CalledMethods({"a"}) SimpleFluentInference this) { + return this; + } + + @This SimpleFluentInference a() { + return this; + } + + @This SimpleFluentInference b() { + return this; + } + + // intentionally does not have an @This annotation + SimpleFluentInference c() { + return new SimpleFluentInference(); + } + + static void doStuffCorrect() { + SimpleFluentInference s = + new SimpleFluentInference() + .a() + .b() + // :: error: finalizer.invocation.invalid + .build(); + } + + static void doStuffWrong() { + SimpleFluentInference s = + new SimpleFluentInference() + .a() + // :: error: finalizer.invocation.invalid + .build(); + } + + static void doStuffRightWeak() { + SimpleFluentInference s = + new SimpleFluentInference() + .a() + // :: error: finalizer.invocation.invalid + .weakbuild(); + } + + static void noReturnsReceiverAnno() { + SimpleFluentInference s = + new SimpleFluentInference() + .a() + .b() + .c() + // :: error: finalizer.invocation.invalid + .build(); + } + + static void fluentLoop() { + SimpleFluentInference s = new SimpleFluentInference().a(); + int i = 10; + while (i > 0) { + // :: error: finalizer.invocation.invalid + s.b().build(); + i--; + s = new SimpleFluentInference(); + } + } +} diff --git a/checker/tests/calledmethods-lombok/CheckerFrameworkBuilder.java b/checker/tests/calledmethods-lombok/CheckerFrameworkBuilder.java index 121bffbf5c..d6f2fc0499 100644 --- a/checker/tests/calledmethods-lombok/CheckerFrameworkBuilder.java +++ b/checker/tests/calledmethods-lombok/CheckerFrameworkBuilder.java @@ -1,7 +1,7 @@ // skip-idempotent import java.util.List; -class CheckerFrameworkBuilder { +public class CheckerFrameworkBuilder { /** * Most of this test was copied from diff --git a/checker/tests/calledmethods-lombok/DefaultedName.java b/checker/tests/calledmethods-lombok/DefaultedName.java index 72ffce3d91..b9974aef1e 100644 --- a/checker/tests/calledmethods-lombok/DefaultedName.java +++ b/checker/tests/calledmethods-lombok/DefaultedName.java @@ -1,7 +1,7 @@ import lombok.Builder; @Builder -class DefaultedName { +public class DefaultedName { @Builder.Default @lombok.NonNull String name = "Martin"; static void test1() { diff --git a/checker/tests/calledmethods-lombok/LombokBuilderExample.java b/checker/tests/calledmethods-lombok/LombokBuilderExample.java index 91c8c84e09..9a8ca6843e 100644 --- a/checker/tests/calledmethods-lombok/LombokBuilderExample.java +++ b/checker/tests/calledmethods-lombok/LombokBuilderExample.java @@ -3,7 +3,7 @@ import lombok.Builder; @Builder -class LombokBuilderExample { +public class LombokBuilderExample { @lombok.NonNull Object foo; @lombok.NonNull Object bar; diff --git a/checker/tests/calledmethods-lombok/LombokToBuilderExample.java b/checker/tests/calledmethods-lombok/LombokToBuilderExample.java index a4e6bf7ad9..c1cbdb8e56 100644 --- a/checker/tests/calledmethods-lombok/LombokToBuilderExample.java +++ b/checker/tests/calledmethods-lombok/LombokToBuilderExample.java @@ -3,7 +3,7 @@ import lombok.Builder; @Builder(toBuilder = true) -class LombokToBuilderExample { +public class LombokToBuilderExample { @lombok.NonNull String req; static void test(LombokToBuilderExample foo) { diff --git a/checker/tests/calledmethods-lombok/OldInherited.java b/checker/tests/calledmethods-lombok/OldInherited.java index 4df6277ac8..d163c1b13c 100644 --- a/checker/tests/calledmethods-lombok/OldInherited.java +++ b/checker/tests/calledmethods-lombok/OldInherited.java @@ -4,7 +4,7 @@ import org.checkerframework.checker.builder.qual.ReturnsReceiver; import org.checkerframework.checker.calledmethods.qual.*; -class OldInherited { +public class OldInherited { @ReturnsReceiver OldInherited getThis() { return this; diff --git a/checker/tests/calledmethods-usevaluechecker/GenerateDataKeyRequestExamples.java b/checker/tests/calledmethods-usevaluechecker/GenerateDataKeyRequestExamples.java index f120b1ec61..dbfa7a1e7b 100644 --- a/checker/tests/calledmethods-usevaluechecker/GenerateDataKeyRequestExamples.java +++ b/checker/tests/calledmethods-usevaluechecker/GenerateDataKeyRequestExamples.java @@ -5,7 +5,7 @@ import com.amazonaws.services.kms.model.GenerateDataKeyRequest; import org.checkerframework.checker.calledmethods.qual.*; -class GenerateDataKeyRequestExamples { +public class GenerateDataKeyRequestExamples { void correctWithKeySpec(AWSKMS client) { GenerateDataKeyRequest request = new GenerateDataKeyRequest(); diff --git a/checker/tests/calledmethods-usevaluechecker/MorePreciseFilters.java b/checker/tests/calledmethods-usevaluechecker/MorePreciseFilters.java index 0289d688e6..19365a74dc 100644 --- a/checker/tests/calledmethods-usevaluechecker/MorePreciseFilters.java +++ b/checker/tests/calledmethods-usevaluechecker/MorePreciseFilters.java @@ -5,7 +5,7 @@ import java.util.Arrays; import java.util.Collections; -class MorePreciseFilters { +public class MorePreciseFilters { /* TODO: handle lists void ownerAliasList(AmazonEC2 ec2Client) { diff --git a/checker/tests/calledmethods-usevaluechecker/OnlyOwnersFalsePositive.java b/checker/tests/calledmethods-usevaluechecker/OnlyOwnersFalsePositive.java index 7af461a2f5..42ceca2322 100644 --- a/checker/tests/calledmethods-usevaluechecker/OnlyOwnersFalsePositive.java +++ b/checker/tests/calledmethods-usevaluechecker/OnlyOwnersFalsePositive.java @@ -6,7 +6,7 @@ // Tests that just setting with/setOwners is permitted, since there are legitimate reasons to do // that. // Originally, we required with/setFilters && with/setOwners. -class OnlyOwnersFalsePositive { +public class OnlyOwnersFalsePositive { void test(AmazonEC2 ec2Client) { DescribeImagesRequest describeImagesRequest = new DescribeImagesRequest(); describeImagesRequest.setOwners(Collections.singleton("self")); diff --git a/checker/tests/calledmethods-usevaluechecker/RequestCreatedInCall.java b/checker/tests/calledmethods-usevaluechecker/RequestCreatedInCall.java index 8c3235870d..0d09303e10 100644 --- a/checker/tests/calledmethods-usevaluechecker/RequestCreatedInCall.java +++ b/checker/tests/calledmethods-usevaluechecker/RequestCreatedInCall.java @@ -5,7 +5,7 @@ import java.util.*; // A test to ensure that requests that are created in the call to describeImages work correctly. -class RequestCreatedInCall { +public class RequestCreatedInCall { void test(AmazonEC2 ec2) { List filters = new ArrayList<>(); filters.add(new Filter().withName("foo").withValues("bar")); diff --git a/checker/tests/calledmethods-usevaluechecker/SimpleFalsePositive.java b/checker/tests/calledmethods-usevaluechecker/SimpleFalsePositive.java index a69d9ebeaf..83f7c016d9 100644 --- a/checker/tests/calledmethods-usevaluechecker/SimpleFalsePositive.java +++ b/checker/tests/calledmethods-usevaluechecker/SimpleFalsePositive.java @@ -5,7 +5,7 @@ import java.util.*; // A simple (potential) false positive case with mutliple filters. -class SimpleFalsePositive { +public class SimpleFalsePositive { void test(AmazonEC2 ec2Client, String namePrefix) { DescribeImagesRequest request = new DescribeImagesRequest() diff --git a/checker/tests/calledmethods-usevaluechecker/SpecialNames.java b/checker/tests/calledmethods-usevaluechecker/SpecialNames.java index 1ec0a4a3a3..a8bfb5d6ae 100644 --- a/checker/tests/calledmethods-usevaluechecker/SpecialNames.java +++ b/checker/tests/calledmethods-usevaluechecker/SpecialNames.java @@ -5,7 +5,7 @@ import org.checkerframework.checker.calledmethods.qual.*; import org.checkerframework.common.returnsreceiver.qual.*; -class SpecialNames { +public class SpecialNames { @This SpecialNames withFilters() { return this; } diff --git a/checker/tests/calledmethods/CmPredicate.java b/checker/tests/calledmethods/CmPredicate.java index ffb792f043..427b5d3829 100644 --- a/checker/tests/calledmethods/CmPredicate.java +++ b/checker/tests/calledmethods/CmPredicate.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.calledmethods.qual.*; -class CmPredicate { +public class CmPredicate { void testOr1() { MyClass m1 = new MyClass(); diff --git a/checker/tests/calledmethods/Generics.java b/checker/tests/calledmethods/Generics.java index b2b441ea40..741d810f18 100644 --- a/checker/tests/calledmethods/Generics.java +++ b/checker/tests/calledmethods/Generics.java @@ -5,7 +5,7 @@ import org.checkerframework.checker.calledmethods.qual.*; import org.checkerframework.common.returnsreceiver.qual.*; -class Generics { +public class Generics { static interface Symbol { diff --git a/checker/tests/calledmethods/Not.java b/checker/tests/calledmethods/Not.java index f53874e008..9d91fbdd8f 100644 --- a/checker/tests/calledmethods/Not.java +++ b/checker/tests/calledmethods/Not.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.calledmethods.qual.*; -class Not { +public class Not { class Foo { void a() {} diff --git a/checker/tests/calledmethods/Postconditions.java b/checker/tests/calledmethods/Postconditions.java index c0cfc106c5..0589f56d97 100644 --- a/checker/tests/calledmethods/Postconditions.java +++ b/checker/tests/calledmethods/Postconditions.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.calledmethods.qual.*; -/** Test for postcondition support via @EnsureCalledMethods */ -class Postconditions { +/** Test for postcondition support via @EnsureCalledMethods. */ +public class Postconditions { void build(@CalledMethods({"a", "b", "c"}) Postconditions this) {} void a() {} diff --git a/checker/tests/calledmethods/SimpleFluentInference.java b/checker/tests/calledmethods/SimpleFluentInference.java index 020432d21e..ae17946aec 100644 --- a/checker/tests/calledmethods/SimpleFluentInference.java +++ b/checker/tests/calledmethods/SimpleFluentInference.java @@ -2,7 +2,7 @@ import org.checkerframework.common.returnsreceiver.qual.*; /* Simple inference of a fluent builder */ -class SimpleFluentInference { +public class SimpleFluentInference { SimpleFluentInference build(@CalledMethods({"a", "b"}) SimpleFluentInference this) { return this; } diff --git a/checker/tests/calledmethods/SimpleInference.java b/checker/tests/calledmethods/SimpleInference.java index 9d3fb27f70..0f86b96de5 100644 --- a/checker/tests/calledmethods/SimpleInference.java +++ b/checker/tests/calledmethods/SimpleInference.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.calledmethods.qual.*; /* The simplest inference test case Martin could think of */ -class SimpleInference { +public class SimpleInference { void build(@CalledMethods({"a"}) SimpleInference this) {} void a() {} diff --git a/checker/tests/calledmethods/SimpleInferenceMerge.java b/checker/tests/calledmethods/SimpleInferenceMerge.java index b7af4ae5ec..601e34572f 100644 --- a/checker/tests/calledmethods/SimpleInferenceMerge.java +++ b/checker/tests/calledmethods/SimpleInferenceMerge.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.calledmethods.qual.*; /* The simplest inference test case Martin could think of */ -class SimpleInferenceMerge { +public class SimpleInferenceMerge { void build(@CalledMethods({"a", "b"}) SimpleInferenceMerge this) {} void a() {} diff --git a/checker/tests/calledmethods/Subtyping.java b/checker/tests/calledmethods/Subtyping.java index 01a7e73123..4d53e30f63 100644 --- a/checker/tests/calledmethods/Subtyping.java +++ b/checker/tests/calledmethods/Subtyping.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.calledmethods.qual.*; // basic subtyping checks -class Subtyping { +public class Subtyping { @CalledMethods({}) Object top_top(@CalledMethods({}) Object o) { return o; } diff --git a/checker/tests/calledmethods/UnparseablePredicate.java b/checker/tests/calledmethods/UnparseablePredicate.java index 3785e468dd..c2cddad5de 100644 --- a/checker/tests/calledmethods/UnparseablePredicate.java +++ b/checker/tests/calledmethods/UnparseablePredicate.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.calledmethods.qual.*; -class UnparseablePredicate { +public class UnparseablePredicate { // :: error: predicate.invalid void unclosedOpen(@CalledMethodsPredicate("(foo && bar") Object x) {} diff --git a/checker/tests/calledmethods/Xor.java b/checker/tests/calledmethods/Xor.java index e81181ea56..a128d0b0ee 100644 --- a/checker/tests/calledmethods/Xor.java +++ b/checker/tests/calledmethods/Xor.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.calledmethods.qual.*; -class Xor { +public class Xor { class Foo { void a() {} diff --git a/checker/tests/compilermsg/Basic.java b/checker/tests/compilermsg/Basic.java index 99286d665c..fb503bc5a8 100644 --- a/checker/tests/compilermsg/Basic.java +++ b/checker/tests/compilermsg/Basic.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.compilermsgs.qual.CompilerMessageKey; -class Basic { +public class Basic { void required(@CompilerMessageKey String in) {} diff --git a/checker/tests/fenum/CastsFenum.java b/checker/tests/fenum/CastsFenum.java index e0664990c3..a3be27f799 100644 --- a/checker/tests/fenum/CastsFenum.java +++ b/checker/tests/fenum/CastsFenum.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.fenum.qual.Fenum; -class CastsFenum { +public class CastsFenum { @Fenum("A") Object fa; void m(Object p, @Fenum("A") Object a) { diff --git a/checker/tests/fenum/CatchFenumUnqualified.java b/checker/tests/fenum/CatchFenumUnqualified.java index cd4c6780e6..cb54ce747c 100644 --- a/checker/tests/fenum/CatchFenumUnqualified.java +++ b/checker/tests/fenum/CatchFenumUnqualified.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.fenum.qual.Fenum; -class CatchFenumUnqualfied { +public class CatchFenumUnqualified { void method() { try { } catch ( diff --git a/checker/tests/fenum/TestSwitch.java b/checker/tests/fenum/TestSwitch.java index d9851ac29c..22fdd4de49 100644 --- a/checker/tests/fenum/TestSwitch.java +++ b/checker/tests/fenum/TestSwitch.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.fenum.qual.Fenum; -class TestSwitch { +public class TestSwitch { void m() { @SuppressWarnings("fenum:assignment.type.incompatible") @Fenum("TEST") final int annotated = 3; diff --git a/checker/tests/formatter-lubglb/Placeholder.java b/checker/tests/formatter-lubglb/Placeholder.java index 7cb44dbe34..5ee2ef079a 100644 --- a/checker/tests/formatter-lubglb/Placeholder.java +++ b/checker/tests/formatter-lubglb/Placeholder.java @@ -1,3 +1,3 @@ // We need a file to start the checker. -class Placeholder {} +public class Placeholder {} diff --git a/checker/tests/formatter/ConversionNull.java b/checker/tests/formatter/ConversionNull.java index bc5ccf4c49..8ac77b13dd 100644 --- a/checker/tests/formatter/ConversionNull.java +++ b/checker/tests/formatter/ConversionNull.java @@ -8,28 +8,20 @@ public static void main(String... p) { f.format("%d %s", 0, null); f.format("%s", (Object) null); - // :: error: (argument.type.incompatible) f.format("%d %c", 0, null); f.format("%c", (Character) null); - // :: error: (argument.type.incompatible) f.format("%c", (Object) null); - // :: error: (argument.type.incompatible) f.format("%d %d", 0, null); f.format("%d", (Integer) null); - // :: error: (argument.type.incompatible) f.format("%d", (Object) null); - // :: error: (argument.type.incompatible) f.format("%d %f", 0, null); f.format("%f", (Float) null); - // :: error: (argument.type.incompatible) f.format("%f", (Object) null); - // :: error: (argument.type.incompatible) f.format("%d %tD", 0, null); f.format("%tD", (Date) null); - // :: error: (argument.type.incompatible) f.format("%tD", (Object) null); System.out.println(f.toString()); diff --git a/checker/tests/formatter/ConversionNull2.java b/checker/tests/formatter/ConversionNull2.java index 064725bc8f..3b926ba4e2 100644 --- a/checker/tests/formatter/ConversionNull2.java +++ b/checker/tests/formatter/ConversionNull2.java @@ -3,9 +3,7 @@ public class ConversionNull2 { void foo(Formatter f1, MyFormatter f2) { - // :: error: (argument.type.incompatible) f1.format("%d %c", 0, null); - // :: error: (argument.type.incompatible) f2.format("%d %c", 0, null); } } diff --git a/checker/tests/formatter/FormatIndexing.java b/checker/tests/formatter/FormatIndexing.java index 048a9f4d78..74ca247028 100644 --- a/checker/tests/formatter/FormatIndexing.java +++ b/checker/tests/formatter/FormatIndexing.java @@ -43,13 +43,13 @@ public static void main(String... p) { @Format({ConversionCategory.NULL, ConversionCategory.INT}) String tf = "%TT % { +public class ArrayIntroWithCast { void test(String[] a, String[] b) { Object result = new Object[a.length + b.length]; diff --git a/checker/tests/index/ArrayLength.java b/checker/tests/index/ArrayLength.java index 7647d3e91d..b646fb2de1 100644 --- a/checker/tests/index/ArrayLength.java +++ b/checker/tests/index/ArrayLength.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.index.qual.LTEqLengthOf; -class ArrayLength { +public class ArrayLength { void test() { int[] arr = {1, 2, 3}; @LTEqLengthOf({"arr"}) int a = arr.length; diff --git a/checker/tests/index/ArrayLengthEquality.java b/checker/tests/index/ArrayLengthEquality.java index 571252d73b..13e09dada3 100644 --- a/checker/tests/index/ArrayLengthEquality.java +++ b/checker/tests/index/ArrayLengthEquality.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.index.qual.SameLen; -class ArrayLengthEquality { +public class ArrayLengthEquality { void test(int[] a, int[] b) { if (a.length == b.length) { int @SameLen({"a", "b"}) [] c = a; diff --git a/checker/tests/index/ArraysSort.java b/checker/tests/index/ArraysSort.java index 3dba567e27..e092cc6ded 100644 --- a/checker/tests/index/ArraysSort.java +++ b/checker/tests/index/ArraysSort.java @@ -1,7 +1,7 @@ import java.util.Arrays; import org.checkerframework.common.value.qual.MinLen; -class ArraysSort { +public class ArraysSort { void sortInt(int @MinLen(10) [] nums) { // Checks the correct handling of the toIndex parameter diff --git a/checker/tests/index/BasicSubsequence.java b/checker/tests/index/BasicSubsequence.java index 3df75870b9..e021f25df1 100644 --- a/checker/tests/index/BasicSubsequence.java +++ b/checker/tests/index/BasicSubsequence.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.index.qual.*; -class BasicSubsequence { +public class BasicSubsequence { // :: error: not.final @HasSubsequence(subsequence = "this", from = "this.x", to = "this.y") int[] b; diff --git a/checker/tests/index/BasicSubsequence2.java b/checker/tests/index/BasicSubsequence2.java index 1d3b6d74e2..2b572221c9 100644 --- a/checker/tests/index/BasicSubsequence2.java +++ b/checker/tests/index/BasicSubsequence2.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.index.qual.IndexFor; import org.checkerframework.checker.index.qual.IndexOrHigh; -class BasicSubsequence2 { +public class BasicSubsequence2 { @HasSubsequence(subsequence = "this", from = "this.start", to = "this.end") int[] array; diff --git a/checker/tests/index/BasicSubsequence3.java b/checker/tests/index/BasicSubsequence3.java index d233862167..bb25d8058c 100644 --- a/checker/tests/index/BasicSubsequence3.java +++ b/checker/tests/index/BasicSubsequence3.java @@ -4,7 +4,7 @@ import org.checkerframework.checker.index.qual.LessThan; @SuppressWarnings("lowerbound") -class BasicSubsequence3 { +public class BasicSubsequence3 { @HasSubsequence(subsequence = "this", from = "this.start", to = "this.end") int[] array; diff --git a/checker/tests/index/BigBinaryExpr.java b/checker/tests/index/BigBinaryExpr.java index 2b6ae87ea9..318cdb9cd8 100644 --- a/checker/tests/index/BigBinaryExpr.java +++ b/checker/tests/index/BigBinaryExpr.java @@ -1,4 +1,4 @@ -class BigBinaryExpr { +public class BigBinaryExpr { void test() { int i0 = 163; int i1 = 153; diff --git a/checker/tests/index/BinomialTest.java b/checker/tests/index/BinomialTest.java index 97650379c5..121fb7f17c 100644 --- a/checker/tests/index/BinomialTest.java +++ b/checker/tests/index/BinomialTest.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.*; import org.checkerframework.common.value.qual.*; -class BinomialTest { +public class BinomialTest { static final long @MinLen(1) [] factorials = {1L, 1L, 1L * 2}; diff --git a/checker/tests/index/BottomValTest.java b/checker/tests/index/BottomValTest.java index acb9c9d33c..51bbd36a9f 100644 --- a/checker/tests/index/BottomValTest.java +++ b/checker/tests/index/BottomValTest.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.*; import org.checkerframework.common.value.qual.*; -class BottomValTest { +public class BottomValTest { @NonNegative int foo(@BottomVal int bottom) { return bottom; } diff --git a/checker/tests/index/CastArray.java b/checker/tests/index/CastArray.java index 8f4d44a8c1..0ffb750b22 100644 --- a/checker/tests/index/CastArray.java +++ b/checker/tests/index/CastArray.java @@ -1,4 +1,4 @@ -class CastArray { +public class CastArray { void test(Object a) { int[] b = (int[]) a; } diff --git a/checker/tests/index/CheckAgainstNegativeOne.java b/checker/tests/index/CheckAgainstNegativeOne.java index 4f39ad77d8..6c61942bfa 100644 --- a/checker/tests/index/CheckAgainstNegativeOne.java +++ b/checker/tests/index/CheckAgainstNegativeOne.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.index.qual.IndexOrHigh; -class CheckAgainstNegativeOne { +public class CheckAgainstNegativeOne { public static String replaceString(String target, String oldStr, String newStr) { if (oldStr.equals("")) { diff --git a/checker/tests/index/CheckNotNull1.java b/checker/tests/index/CheckNotNull1.java index 029a234f24..afd2b7c418 100644 --- a/checker/tests/index/CheckNotNull1.java +++ b/checker/tests/index/CheckNotNull1.java @@ -1,4 +1,4 @@ -class CheckNotNull1 { +public class CheckNotNull1 { T checkNotNull(T ref) { return ref; } diff --git a/checker/tests/index/CheckNotNull2.java b/checker/tests/index/CheckNotNull2.java index 5d8c8acdab..8304f27758 100644 --- a/checker/tests/index/CheckNotNull2.java +++ b/checker/tests/index/CheckNotNull2.java @@ -1,4 +1,4 @@ -class CheckNotNull2 { +public class CheckNotNull2 { T checkNotNull(T ref) { return ref; } diff --git a/checker/tests/index/CombineFacts.java b/checker/tests/index/CombineFacts.java index aa375dbabb..70a88ccc56 100644 --- a/checker/tests/index/CombineFacts.java +++ b/checker/tests/index/CombineFacts.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.LTLengthOf; @SuppressWarnings("lowerbound") -class CombineFacts { +public class CombineFacts { void test(int[] a1) { @LTLengthOf("a1") int len = a1.length - 1; int[] a2 = new int[len]; diff --git a/checker/tests/index/CompareBySubtraction.java b/checker/tests/index/CompareBySubtraction.java index 9a282494a9..20912bad22 100644 --- a/checker/tests/index/CompareBySubtraction.java +++ b/checker/tests/index/CompareBySubtraction.java @@ -1,6 +1,6 @@ // @skip-test until fixed. -class CompareBySubtraction { +public class CompareBySubtraction { public int compare(int[] a1, int[] a2) { if (a1 == a2) { return 0; diff --git a/checker/tests/index/CompoundAssignmentCheck.java b/checker/tests/index/CompoundAssignmentCheck.java index 853ce64bd6..7518d9c466 100644 --- a/checker/tests/index/CompoundAssignmentCheck.java +++ b/checker/tests/index/CompoundAssignmentCheck.java @@ -1,4 +1,4 @@ -class CompoundAssignmentCheck { +public class CompoundAssignmentCheck { void test() { int a = 9; a += 5; diff --git a/checker/tests/index/ConstantArrays.java b/checker/tests/index/ConstantArrays.java index 5c082d8a1b..c6a56da5ca 100644 --- a/checker/tests/index/ConstantArrays.java +++ b/checker/tests/index/ConstantArrays.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.index.qual.*; -class ConstantArrays { +public class ConstantArrays { void basic_test() { int[] b = new int[4]; @LTLengthOf("b") int[] a = {0, 1, 2, 3}; diff --git a/checker/tests/index/ConstantsIndex.java b/checker/tests/index/ConstantsIndex.java index 9e53627e60..672b15332b 100644 --- a/checker/tests/index/ConstantsIndex.java +++ b/checker/tests/index/ConstantsIndex.java @@ -1,6 +1,6 @@ import org.checkerframework.common.value.qual.MinLen; -class ConstantsIndex { +public class ConstantsIndex { void test() { int @MinLen(3) [] arr = {1, 2, 3}; diff --git a/checker/tests/index/EnumValues.java b/checker/tests/index/EnumValues.java index 8e300a0a01..49452b3fae 100644 --- a/checker/tests/index/EnumValues.java +++ b/checker/tests/index/EnumValues.java @@ -1,6 +1,6 @@ import org.checkerframework.common.value.qual.*; -class EnumValues { +public class EnumValues { public static enum Direction { NORTH, diff --git a/checker/tests/index/EqualToIndex.java b/checker/tests/index/EqualToIndex.java index 6a2ef1325e..33aae4b82b 100644 --- a/checker/tests/index/EqualToIndex.java +++ b/checker/tests/index/EqualToIndex.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.LTEqLengthOf; import org.checkerframework.checker.index.qual.LTLengthOf; -class EqualToIndex { +public class EqualToIndex { static int[] a = {0}; public static void equalToUpper(@LTLengthOf("a") int m, @LTEqLengthOf("a") int r) { diff --git a/checker/tests/index/EqualToTransfer.java b/checker/tests/index/EqualToTransfer.java index 7841a3e7b5..54d622b321 100644 --- a/checker/tests/index/EqualToTransfer.java +++ b/checker/tests/index/EqualToTransfer.java @@ -1,6 +1,6 @@ import org.checkerframework.common.value.qual.MinLen; -class EqualToTransfer { +public class EqualToTransfer { void eq_check(int[] a) { if (1 == a.length) { int @MinLen(1) [] b = a; diff --git a/checker/tests/index/GreaterThanOrEqualTransfer.java b/checker/tests/index/GreaterThanOrEqualTransfer.java index af60fd1ce4..09deb96fbd 100644 --- a/checker/tests/index/GreaterThanOrEqualTransfer.java +++ b/checker/tests/index/GreaterThanOrEqualTransfer.java @@ -1,6 +1,6 @@ import org.checkerframework.common.value.qual.MinLen; -class GreaterThanOrEqualTransfer { +public class GreaterThanOrEqualTransfer { void gte_check(int[] a) { if (a.length >= 1) { int @MinLen(1) [] b = a; diff --git a/checker/tests/index/GreaterThanTransfer.java b/checker/tests/index/GreaterThanTransfer.java index 04a9628dbf..dbacd8374e 100644 --- a/checker/tests/index/GreaterThanTransfer.java +++ b/checker/tests/index/GreaterThanTransfer.java @@ -1,6 +1,6 @@ import org.checkerframework.common.value.qual.MinLen; -class GreaterThanTransfer { +public class GreaterThanTransfer { void gt_check(int[] a) { if (a.length > 0) { int @MinLen(1) [] b = a; diff --git a/checker/tests/index/IndexConditionalReport.java b/checker/tests/index/IndexConditionalReport.java index b2447654ae..ef59017053 100644 --- a/checker/tests/index/IndexConditionalReport.java +++ b/checker/tests/index/IndexConditionalReport.java @@ -1,6 +1,6 @@ // test case for https://github.com/typetools/checker-framework/issues/2345 -class IndexConditionalReport { +public class IndexConditionalReport { public int getI(int len) { for (int i = 0; i < len; i++) { diff --git a/checker/tests/index/IndexForTwoArrays.java b/checker/tests/index/IndexForTwoArrays.java index 1e3a7fff5d..1afe76eb19 100644 --- a/checker/tests/index/IndexForTwoArrays.java +++ b/checker/tests/index/IndexForTwoArrays.java @@ -1,4 +1,4 @@ -class IndexForTwoArrays { +public class IndexForTwoArrays { public int compare(double[] a1, double[] a2) { if (a1 == a2) { diff --git a/checker/tests/index/IndexForTwoArrays2.java b/checker/tests/index/IndexForTwoArrays2.java index 40de32d0f2..b1f2d940cc 100644 --- a/checker/tests/index/IndexForTwoArrays2.java +++ b/checker/tests/index/IndexForTwoArrays2.java @@ -1,6 +1,6 @@ // Test case for issue #34: https://github.com/kelloggm/checker-framework/issues/34 -class IndexForTwoArrays2 { +public class IndexForTwoArrays2 { public boolean equals(int[] da1, int[] da2) { if (da1.length != da2.length) { diff --git a/checker/tests/index/IntroAnd.java b/checker/tests/index/IntroAnd.java index 2219a2b37c..340da58b8a 100644 --- a/checker/tests/index/IntroAnd.java +++ b/checker/tests/index/IntroAnd.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.index.qual.*; -class IntroAnd { +public class IntroAnd { void test() { @NonNegative int a = 1 & 0; @NonNegative int b = a & 5; diff --git a/checker/tests/index/IntroShift.java b/checker/tests/index/IntroShift.java index b6e1006609..dff7b471fe 100644 --- a/checker/tests/index/IntroShift.java +++ b/checker/tests/index/IntroShift.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.index.qual.NonNegative; -class IntroShift { +public class IntroShift { void test() { @NonNegative int a = 1 >> 1; // :: error: (assignment.type.incompatible) diff --git a/checker/tests/index/InvalidSubsequence.java b/checker/tests/index/InvalidSubsequence.java index 290635d2ef..f15b85d8a1 100644 --- a/checker/tests/index/InvalidSubsequence.java +++ b/checker/tests/index/InvalidSubsequence.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.index.qual.IndexOrHigh; import org.checkerframework.checker.index.qual.LessThan; -class InvalidSubsequence { +public class InvalidSubsequence { // :: error: flowexpr.parse.error :: error: not.final @HasSubsequence(subsequence = "banana", from = "this.from", to = "this.to") int[] a; diff --git a/checker/tests/index/Issue20.java b/checker/tests/index/Issue20.java index aa0dd9b571..f2dc36f942 100644 --- a/checker/tests/index/Issue20.java +++ b/checker/tests/index/Issue20.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.LTEqLengthOf; import org.checkerframework.checker.index.qual.LTLengthOf; -class Issue20 { +public class Issue20 { // An issue with LUB that results in losing information when unifying. int[] a, b; diff --git a/checker/tests/index/Issue21.java b/checker/tests/index/Issue21.java index 7f651c1d99..f474d7893f 100644 --- a/checker/tests/index/Issue21.java +++ b/checker/tests/index/Issue21.java @@ -1,4 +1,4 @@ -class Issue21 { +public class Issue21 { void test(int[] arr, int[] arr2) { for (int i = 0; i < arr2.length && i < arr.length; i++) { diff --git a/checker/tests/index/Issue2334.java b/checker/tests/index/Issue2334.java index 5eb86d9c18..c81a8b8115 100644 --- a/checker/tests/index/Issue2334.java +++ b/checker/tests/index/Issue2334.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.index.qual.NonNegative; -class Issue2334 { +public class Issue2334 { void hasSideEffect() {} diff --git a/checker/tests/index/Issue2420.java b/checker/tests/index/Issue2420.java index 64f2512443..7ed8cc7dd8 100644 --- a/checker/tests/index/Issue2420.java +++ b/checker/tests/index/Issue2420.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.*; import org.checkerframework.common.value.qual.*; -class Issue2420 { +public class Issue2420 { static void str(String argStr) { if (argStr.isEmpty()) { return; diff --git a/checker/tests/index/Issue2452.java b/checker/tests/index/Issue2452.java new file mode 100644 index 0000000000..6f15b506c6 --- /dev/null +++ b/checker/tests/index/Issue2452.java @@ -0,0 +1,39 @@ +// Test case for https://github.com/typetools/checker-framework/issues/2452 + +import java.lang.reflect.Array; +import org.checkerframework.checker.index.qual.IndexFor; +import org.checkerframework.checker.index.qual.IndexOrHigh; +import org.checkerframework.checker.index.qual.LTEqLengthOf; +import org.checkerframework.checker.index.qual.NonNegative; +import org.checkerframework.checker.index.qual.Positive; +import org.checkerframework.common.value.qual.MinLen; + +class Issue2452 { + Object m1(Object[] a1) { + if (Array.getLength(a1) > 0) { + return Array.get(a1, 0); + } else { + return null; + } + } + + void m2() { + int[] arr = {1, 2, 3}; + @LTEqLengthOf({"arr"}) int a = Array.getLength(arr); + } + + void testMinLenSubtractPositive(String @MinLen(10) [] s) { + @Positive int i1 = s.length - 9; + @NonNegative int i0 = Array.getLength(s) - 10; + // :: error: (assignment.type.incompatible) + @NonNegative int im1 = Array.getLength(s) - 11; + } + + void testLessThanLength(String[] s, @IndexOrHigh("#1") int i, @IndexOrHigh("#1") int j) { + if (i < Array.getLength(s)) { + @IndexFor("s") int in = i; + // :: error: (assignment.type.incompatible) + @IndexFor("s") int jn = j; + } + } +} diff --git a/checker/tests/index/Issue2493.java b/checker/tests/index/Issue2493.java index bbd5abb74e..c32138cb01 100644 --- a/checker/tests/index/Issue2493.java +++ b/checker/tests/index/Issue2493.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.index.qual.*; -class Issue2493 { +public class Issue2493 { public static void test(int a[], int @SameLen("#1") [] b) { for (@IndexOrHigh("b") int i = 0; i < a.length; i++) ; } diff --git a/checker/tests/index/Issue2505.java b/checker/tests/index/Issue2505.java index 90db74096d..e20533009a 100644 --- a/checker/tests/index/Issue2505.java +++ b/checker/tests/index/Issue2505.java @@ -1,6 +1,6 @@ import org.checkerframework.common.value.qual.MinLen; -class Issue2505 { +public class Issue2505 { public static void warningIfStatement(int @MinLen(1) [] a) { int i = a.length; if (--i >= 0) { diff --git a/checker/tests/index/Issue2613.java b/checker/tests/index/Issue2613.java index 16f5b0a450..ac47cc6bb5 100644 --- a/checker/tests/index/Issue2613.java +++ b/checker/tests/index/Issue2613.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.LTLengthOf; import org.checkerframework.checker.index.qual.LessThan; -class Issue2613 { +public class Issue2613 { private static final String STRING_CONSTANT = "Hello"; diff --git a/checker/tests/index/Issue2629.java b/checker/tests/index/Issue2629.java index 466c37c8a2..ea16381a0c 100644 --- a/checker/tests/index/Issue2629.java +++ b/checker/tests/index/Issue2629.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.index.qual.LessThan; -class Issue2629 { +public class Issue2629 { @LessThan("#1 + 1") int test(int a) { return a; } diff --git a/checker/tests/index/Issue58Minimization.java b/checker/tests/index/Issue58Minimization.java index 5569ba5918..1f8fcb9834 100644 --- a/checker/tests/index/Issue58Minimization.java +++ b/checker/tests/index/Issue58Minimization.java @@ -6,7 +6,7 @@ import org.checkerframework.checker.index.qual.SameLen; import org.checkerframework.common.value.qual.MinLen; -class Issue58Minimization { +public class Issue58Minimization { void test(@GTENegativeOne int x) { int z; diff --git a/checker/tests/index/Issue60.java b/checker/tests/index/Issue60.java index 4b0255cf0c..eddfb9dc23 100644 --- a/checker/tests/index/Issue60.java +++ b/checker/tests/index/Issue60.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.index.qual.IndexFor; -class Issue60 { +public class Issue60 { public static int[] fn_compose(@IndexFor("#2") int[] a, int[] b) { int[] result = new int[a.length]; diff --git a/checker/tests/index/Kelloggm225.java b/checker/tests/index/Kelloggm225.java index 002456056b..0bc334b6a5 100644 --- a/checker/tests/index/Kelloggm225.java +++ b/checker/tests/index/Kelloggm225.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.*; import org.checkerframework.common.value.qual.*; -class Kelloggm225 { +public class Kelloggm225 { void method(int @MinLen(1) [] bar) { foo(bar, 0, bar.length); } diff --git a/checker/tests/index/LBCSubtyping.java b/checker/tests/index/LBCSubtyping.java index 8abda9d315..3ef5a1df2d 100644 --- a/checker/tests/index/LBCSubtyping.java +++ b/checker/tests/index/LBCSubtyping.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.index.qual.NonNegative; import org.checkerframework.checker.index.qual.Positive; -class LBCSubtyping { +public class LBCSubtyping { void foo() { diff --git a/checker/tests/index/LTLDivide.java b/checker/tests/index/LTLDivide.java index 8d16cd6bdd..631c24cfa9 100644 --- a/checker/tests/index/LTLDivide.java +++ b/checker/tests/index/LTLDivide.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.LTEqLengthOf; import org.checkerframework.checker.index.qual.LTLengthOf; -class LTLDivide { +public class LTLDivide { int[] test(int[] array) { // @LTLengthOf("array") int len = array.length / 2; int len = array.length / 2; diff --git a/checker/tests/index/LTLengthOfPostcondition.java b/checker/tests/index/LTLengthOfPostcondition.java index b89289ea8a..d34e834dbb 100644 --- a/checker/tests/index/LTLengthOfPostcondition.java +++ b/checker/tests/index/LTLengthOfPostcondition.java @@ -4,7 +4,7 @@ import org.checkerframework.checker.index.qual.LTEqLengthOf; import org.checkerframework.checker.index.qual.NonNegative; -class LTLengthOfPostcondition { +public class LTLengthOfPostcondition { Object[] array; diff --git a/checker/tests/index/LengthOfArrayMinusOne.java b/checker/tests/index/LengthOfArrayMinusOne.java index bfb71120f8..e575024e4d 100644 --- a/checker/tests/index/LengthOfArrayMinusOne.java +++ b/checker/tests/index/LengthOfArrayMinusOne.java @@ -1,4 +1,4 @@ -class LengthOfArrayMinusOne { +public class LengthOfArrayMinusOne { void test(int[] arr) { // :: error: (array.access.unsafe.low) int i = arr[arr.length - 1]; diff --git a/checker/tests/index/LengthOfTest.java b/checker/tests/index/LengthOfTest.java index 7a3c998072..68f79675ac 100644 --- a/checker/tests/index/LengthOfTest.java +++ b/checker/tests/index/LengthOfTest.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.index.qual.*; -class LengthOfTest { +public class LengthOfTest { void foo(int[] a, @LengthOf("#1") int x) { @IndexOrHigh("a") int y = x; // :: error: (assignment.type.incompatible) diff --git a/checker/tests/index/LengthTransfer.java b/checker/tests/index/LengthTransfer.java index 3970c07207..c7e5bbf638 100644 --- a/checker/tests/index/LengthTransfer.java +++ b/checker/tests/index/LengthTransfer.java @@ -1,4 +1,4 @@ -class LengthTransfer { +public class LengthTransfer { void exceptional_control_flow(int[] a) { if (a.length == 0) { throw new IllegalArgumentException(); diff --git a/checker/tests/index/LengthTransfer2.java b/checker/tests/index/LengthTransfer2.java index af90aecac7..b4b9ef91fe 100644 --- a/checker/tests/index/LengthTransfer2.java +++ b/checker/tests/index/LengthTransfer2.java @@ -2,7 +2,7 @@ import org.checkerframework.common.value.qual.*; -class LengthTransfer2 { +public class LengthTransfer2 { public static void main(String[] args) { if (args.length != 2) { System.err.println("Needs 2 arguments, got " + args.length); diff --git a/checker/tests/index/LengthTransferForMinLen.java b/checker/tests/index/LengthTransferForMinLen.java index 4acc4cd276..21d9879f76 100644 --- a/checker/tests/index/LengthTransferForMinLen.java +++ b/checker/tests/index/LengthTransferForMinLen.java @@ -1,6 +1,6 @@ import org.checkerframework.common.value.qual.MinLen; -class LengthTransferForMinLen { +public class LengthTransferForMinLen { void exceptional_control_flow(int[] a) { if (a.length == 0) { throw new IllegalArgumentException(); diff --git a/checker/tests/index/LessThanOrEqualTransfer.java b/checker/tests/index/LessThanOrEqualTransfer.java index ff912850fa..cfc7efb01d 100644 --- a/checker/tests/index/LessThanOrEqualTransfer.java +++ b/checker/tests/index/LessThanOrEqualTransfer.java @@ -1,6 +1,6 @@ import org.checkerframework.common.value.qual.MinLen; -class LessThanOrEqualTransfer { +public class LessThanOrEqualTransfer { void lte_check(int[] a) { if (1 <= a.length) { int @MinLen(1) [] b = a; diff --git a/checker/tests/index/LessThanTransfer.java b/checker/tests/index/LessThanTransfer.java index f1da12adc8..2013556e75 100644 --- a/checker/tests/index/LessThanTransfer.java +++ b/checker/tests/index/LessThanTransfer.java @@ -1,6 +1,6 @@ import org.checkerframework.common.value.qual.MinLen; -class LessThanTransfer { +public class LessThanTransfer { void lt_check(int[] a) { if (0 < a.length) { int @MinLen(1) [] b = a; diff --git a/checker/tests/index/LessThanZeroArrayLength.java b/checker/tests/index/LessThanZeroArrayLength.java index a61f70113d..ea0ccd2e11 100644 --- a/checker/tests/index/LessThanZeroArrayLength.java +++ b/checker/tests/index/LessThanZeroArrayLength.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.index.qual.LessThan; -class LessThanZeroArrayLength { +public class LessThanZeroArrayLength { void test(int[] a) { foo(0, a.length); } diff --git a/checker/tests/index/ListAdd.java b/checker/tests/index/ListAdd.java index b251239e46..51a75b6330 100644 --- a/checker/tests/index/ListAdd.java +++ b/checker/tests/index/ListAdd.java @@ -5,7 +5,7 @@ // @skip-test until we bring list support back -class ListAdd { +public class ListAdd { List listField; diff --git a/checker/tests/index/ListAddAll.java b/checker/tests/index/ListAddAll.java index 2e76d7c575..8fed1ddf4d 100644 --- a/checker/tests/index/ListAddAll.java +++ b/checker/tests/index/ListAddAll.java @@ -4,7 +4,7 @@ // @skip-test until we bring list support back -class ListAddAll { +public class ListAddAll { List listField; List coll; diff --git a/checker/tests/index/ListAddInfiniteLoop.java b/checker/tests/index/ListAddInfiniteLoop.java index 0f7a686f48..6c9fbd7ceb 100644 --- a/checker/tests/index/ListAddInfiniteLoop.java +++ b/checker/tests/index/ListAddInfiniteLoop.java @@ -1,6 +1,6 @@ // @skip-test until we bring list support back -class ListAddInfiniteLoop { +public class ListAddInfiniteLoop { void ListLoop(List list) { while (true) { diff --git a/checker/tests/index/ListGet.java b/checker/tests/index/ListGet.java index 178d461e3f..e60cea1aef 100644 --- a/checker/tests/index/ListGet.java +++ b/checker/tests/index/ListGet.java @@ -4,7 +4,7 @@ // @skip-test until we bring list support back -class ListGet { +public class ListGet { List listField; int[] arr = {0}; diff --git a/checker/tests/index/ListIterator.java b/checker/tests/index/ListIterator.java index 23ab03b738..e2d85d6941 100644 --- a/checker/tests/index/ListIterator.java +++ b/checker/tests/index/ListIterator.java @@ -4,7 +4,7 @@ // @skip-test until we bring list support back -class ListIterator { +public class ListIterator { List listField; diff --git a/checker/tests/index/ListRemove.java b/checker/tests/index/ListRemove.java index 80750727a7..2253d6fa76 100644 --- a/checker/tests/index/ListRemove.java +++ b/checker/tests/index/ListRemove.java @@ -5,7 +5,7 @@ // @skip-test until we bring list support back // @skip-test can't handle until TreeUtils.getMethod has a way to precisly handle method overloading -class ListRemove { +public class ListRemove { List listField; diff --git a/checker/tests/index/ListSet.java b/checker/tests/index/ListSet.java index aba477b57a..943caac69e 100644 --- a/checker/tests/index/ListSet.java +++ b/checker/tests/index/ListSet.java @@ -4,7 +4,7 @@ // @skip-test until we bring list support back -class ListSet { +public class ListSet { List listField; diff --git a/checker/tests/index/ListSupport.java b/checker/tests/index/ListSupport.java index 7d8f7cc7e9..de94282ddf 100644 --- a/checker/tests/index/ListSupport.java +++ b/checker/tests/index/ListSupport.java @@ -4,7 +4,7 @@ // @skip-test until we bring list support back -class ListSupport { +public class ListSupport { void indexOf(List list) { int index = list.indexOf(0); diff --git a/checker/tests/index/ListSupportLBC.java b/checker/tests/index/ListSupportLBC.java index 666b742cac..fe4d303451 100644 --- a/checker/tests/index/ListSupportLBC.java +++ b/checker/tests/index/ListSupportLBC.java @@ -5,7 +5,7 @@ // @skip-test until we bring list support back -class ListSupportLBC { +public class ListSupportLBC { void testGet() { diff --git a/checker/tests/index/ListSupportML.java b/checker/tests/index/ListSupportML.java index 83fc71428f..2d5f375ffd 100644 --- a/checker/tests/index/ListSupportML.java +++ b/checker/tests/index/ListSupportML.java @@ -3,7 +3,7 @@ // @skip-test until we bring list support back -class ListSupportML { +public class ListSupportML { void newListMinLen() { List list = new ArrayList<>(); diff --git a/checker/tests/index/MLEqualTo.java b/checker/tests/index/MLEqualTo.java index 27aa9c9dd2..642ebbe830 100644 --- a/checker/tests/index/MLEqualTo.java +++ b/checker/tests/index/MLEqualTo.java @@ -1,6 +1,6 @@ import org.checkerframework.common.value.qual.MinLen; -class MLEqualTo { +public class MLEqualTo { public static void equalToMinLen(int @MinLen(2) [] m, int @MinLen(0) [] r) { if (r == m) { diff --git a/checker/tests/index/MinLenFromPositive.java b/checker/tests/index/MinLenFromPositive.java index 8eaece1b8c..7f0cb27af3 100644 --- a/checker/tests/index/MinLenFromPositive.java +++ b/checker/tests/index/MinLenFromPositive.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.Positive; import org.checkerframework.common.value.qual.*; -class MinLenFromPositive { +public class MinLenFromPositive { void test(@Positive int x) { int @MinLen(1) [] y = new int[x]; diff --git a/checker/tests/index/MinLenSameLenInteraction.java b/checker/tests/index/MinLenSameLenInteraction.java index d8db871ccf..3c2b3dfe5c 100644 --- a/checker/tests/index/MinLenSameLenInteraction.java +++ b/checker/tests/index/MinLenSameLenInteraction.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.index.qual.*; -class MinLenSameLenInteraction { +public class MinLenSameLenInteraction { void test(int @SameLen("#2") [] a, int @SameLen("#1") [] b) { if (a.length == 1) { int x = b[0]; diff --git a/checker/tests/index/MinMax.java b/checker/tests/index/MinMax.java index c34472c261..8357a70b74 100644 --- a/checker/tests/index/MinMax.java +++ b/checker/tests/index/MinMax.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.GTENegativeOne; import org.checkerframework.checker.index.qual.Positive; -class MinMax { +public class MinMax { // They call me a power gamer. I stole the test cases from issue 26. void mathmax() { @Positive int i = Math.max(-15, 2); diff --git a/checker/tests/index/MinMaxIndex.java b/checker/tests/index/MinMaxIndex.java index 722d84d2d3..3190ba16b6 100644 --- a/checker/tests/index/MinMaxIndex.java +++ b/checker/tests/index/MinMaxIndex.java @@ -5,7 +5,7 @@ import org.checkerframework.checker.index.qual.IndexFor; import org.checkerframework.checker.index.qual.IndexOrHigh; -class MinMaxIndex { +public class MinMaxIndex { // Both min and max preserve IndexFor void indexFor(char[] array, @IndexFor("#1") int i1, @IndexFor("#1") int i2) { char c = array[Math.max(i1, i2)]; diff --git a/checker/tests/index/NonNegativeCharValue.java b/checker/tests/index/NonNegativeCharValue.java index c5cf600f88..2c6e65ae05 100644 --- a/checker/tests/index/NonNegativeCharValue.java +++ b/checker/tests/index/NonNegativeCharValue.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.index.qual.NonNegative; -class NonNegativeCharValue { +public class NonNegativeCharValue { public static String toString(final @NonNegative Character ch) { return toString(ch.charValue()); } diff --git a/checker/tests/index/NotEqualTransfer.java b/checker/tests/index/NotEqualTransfer.java index ee523a16cc..24a21afae8 100644 --- a/checker/tests/index/NotEqualTransfer.java +++ b/checker/tests/index/NotEqualTransfer.java @@ -1,6 +1,6 @@ import org.checkerframework.common.value.qual.MinLen; -class NotEqualTransfer { +public class NotEqualTransfer { void neq_check(int[] a) { if (1 != a.length) { int x = 1; // do nothing. diff --git a/checker/tests/index/ObjectClone.java b/checker/tests/index/ObjectClone.java index 64656257a2..6f61f031d3 100644 --- a/checker/tests/index/ObjectClone.java +++ b/checker/tests/index/ObjectClone.java @@ -3,7 +3,7 @@ import java.util.Arrays; import org.checkerframework.checker.index.qual.*; -class ObjectClone { +public class ObjectClone { void test(int[] a, int @SameLen("#1") [] b) { int @SameLen("a") [] c = b.clone(); diff --git a/checker/tests/index/OneLTL.java b/checker/tests/index/OneLTL.java index 66a4191e15..a47bc8fbe8 100644 --- a/checker/tests/index/OneLTL.java +++ b/checker/tests/index/OneLTL.java @@ -1,4 +1,4 @@ -class OneLTL { +public class OneLTL { public static boolean sorted(int[] a) { for (int i = 0; i < a.length - 1; i++) { if (a[i + 1] < a[i]) { diff --git a/checker/tests/index/OneOrTwo.java b/checker/tests/index/OneOrTwo.java index 13a5224c91..8adb3f5a2a 100644 --- a/checker/tests/index/OneOrTwo.java +++ b/checker/tests/index/OneOrTwo.java @@ -1,6 +1,6 @@ import org.checkerframework.common.value.qual.*; -class OneOrTwo { +public class OneOrTwo { @IntVal({1, 2}) int getOneOrTwo() { return 1; } diff --git a/checker/tests/index/OnlyCheckSubsequenceWhenAssigningToArray.java b/checker/tests/index/OnlyCheckSubsequenceWhenAssigningToArray.java index 0edb268b1a..2ec214612e 100644 --- a/checker/tests/index/OnlyCheckSubsequenceWhenAssigningToArray.java +++ b/checker/tests/index/OnlyCheckSubsequenceWhenAssigningToArray.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.index.qual.IndexFor; import org.checkerframework.checker.index.qual.IndexOrHigh; -class OnlyCheckSubsequenceWhenAssigningToArray { +public class OnlyCheckSubsequenceWhenAssigningToArray { @HasSubsequence(subsequence = "this", from = "this.start", to = "this.end") int[] array; diff --git a/checker/tests/index/ParsingBug.java b/checker/tests/index/ParsingBug.java index 953ac98811..d597ed2143 100644 --- a/checker/tests/index/ParsingBug.java +++ b/checker/tests/index/ParsingBug.java @@ -1,4 +1,4 @@ -class ParsingBug { +public class ParsingBug { void test() { String[] saOrig = new String[] {"foo", "bar"}; Object o1 = do_things((Object) saOrig); diff --git a/checker/tests/index/Pilot2HalfLength.java b/checker/tests/index/Pilot2HalfLength.java index 71c4ea1b6d..601a7d5a56 100644 --- a/checker/tests/index/Pilot2HalfLength.java +++ b/checker/tests/index/Pilot2HalfLength.java @@ -2,7 +2,7 @@ // @skip-test until fixed -class Pilot2HalfLength { +public class Pilot2HalfLength { private static int[] getFirstHalf(int[] array) { int[] firstHalf = new int[array.length / 2]; for (int i = 0; i < firstHalf.length; i++) { diff --git a/checker/tests/index/Pilot3ArrayCreation.java b/checker/tests/index/Pilot3ArrayCreation.java index adf6ac09a2..493b6c36c3 100644 --- a/checker/tests/index/Pilot3ArrayCreation.java +++ b/checker/tests/index/Pilot3ArrayCreation.java @@ -1,6 +1,6 @@ // This test case is for issue 44: https://github.com/kelloggm/checker-framework/issues/44 -class Pilot3ArrayCreation { +public class Pilot3ArrayCreation { void test(int[] firstArray, int[] secondArray[]) { int[] newArray = new int[firstArray.length + secondArray.length]; for (int i = 0; i < firstArray.length; i++) { diff --git a/checker/tests/index/Pilot4Subtraction.java b/checker/tests/index/Pilot4Subtraction.java index 46a34cd9a3..534fe0ab60 100644 --- a/checker/tests/index/Pilot4Subtraction.java +++ b/checker/tests/index/Pilot4Subtraction.java @@ -2,7 +2,7 @@ // @skip-test until bug is fixed -class Pilot4Subtraction { +public class Pilot4Subtraction { private static int[] getSecondHalf(int[] array) { int len = array.length / 2; diff --git a/checker/tests/index/PolyLengthTest.java b/checker/tests/index/PolyLengthTest.java index 7bf980fe1c..379bd367d4 100644 --- a/checker/tests/index/PolyLengthTest.java +++ b/checker/tests/index/PolyLengthTest.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.*; import org.checkerframework.common.value.qual.*; -class PolyLengthTest { +public class PolyLengthTest { int @PolyLength [] id(int @PolyLength [] a) { return a; } diff --git a/checker/tests/index/Polymorphic.java b/checker/tests/index/Polymorphic.java index 645509f579..31f07063b0 100644 --- a/checker/tests/index/Polymorphic.java +++ b/checker/tests/index/Polymorphic.java @@ -8,7 +8,7 @@ import org.checkerframework.checker.index.qual.Positive; import org.checkerframework.checker.index.qual.SameLen; -class Polymorphic { +public class Polymorphic { // Identity functions diff --git a/checker/tests/index/Polymorphic2.java b/checker/tests/index/Polymorphic2.java index 686f25b6e8..308b2825b0 100644 --- a/checker/tests/index/Polymorphic2.java +++ b/checker/tests/index/Polymorphic2.java @@ -7,7 +7,7 @@ import org.checkerframework.checker.index.qual.Positive; import org.checkerframework.checker.index.qual.SameLen; -class Polymorphic2 { +public class Polymorphic2 { public static boolean flag = false; int @PolySameLen [] mergeSameLen(int @PolySameLen [] a, int @PolySameLen [] b) { diff --git a/checker/tests/index/Polymorphic3.java b/checker/tests/index/Polymorphic3.java index 8efa1a7c8e..5c29323b1c 100644 --- a/checker/tests/index/Polymorphic3.java +++ b/checker/tests/index/Polymorphic3.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.index.qual.*; -class Polymorphic3 { +public class Polymorphic3 { // Identity functions diff --git a/checker/tests/index/Polymorphic4.java b/checker/tests/index/Polymorphic4.java index c2dedbcb20..c1b2fcc41e 100644 --- a/checker/tests/index/Polymorphic4.java +++ b/checker/tests/index/Polymorphic4.java @@ -2,7 +2,7 @@ // @skip-test until #153 is resolved. -class Polymorphic4 { +public class Polymorphic4 { public static String @PolyValue [] quantify(String @PolyValue [] vars) { diff --git a/checker/tests/index/PredecrementTest.java b/checker/tests/index/PredecrementTest.java index 4713833f9a..a52ca2cf13 100644 --- a/checker/tests/index/PredecrementTest.java +++ b/checker/tests/index/PredecrementTest.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.*; import org.checkerframework.common.value.qual.*; -class PredecrementTest { +public class PredecrementTest { public static void warningForLoop(int @MinLen(1) [] a) { for (int i = a.length; --i >= 0; ) { diff --git a/checker/tests/index/PrimitiveWrappers.java b/checker/tests/index/PrimitiveWrappers.java index 27dd7442f3..c07fb338ce 100644 --- a/checker/tests/index/PrimitiveWrappers.java +++ b/checker/tests/index/PrimitiveWrappers.java @@ -5,7 +5,7 @@ // This test ensures that the checker functions on primitive wrappers in // addition to literal primitives. Primarily it focuses on Integer/int. -class PrimitiveWrappers { +public class PrimitiveWrappers { void int_Integer_access_equivalent(@IndexFor("#3") Integer i, @IndexFor("#3") int j, int[] a) { a[i] = a[j]; diff --git a/checker/tests/index/RangeIndex.java b/checker/tests/index/RangeIndex.java index 333de53985..eb705b2db1 100644 --- a/checker/tests/index/RangeIndex.java +++ b/checker/tests/index/RangeIndex.java @@ -1,6 +1,6 @@ import org.checkerframework.common.value.qual.*; -class RangeIndex { +public class RangeIndex { void foo(@IntRange(from = 0, to = 11) int x, int @MinLen(10) [] a) { // :: error: (array.access.unsafe.high.range) int y = a[x]; diff --git a/checker/tests/index/Reassignment.java b/checker/tests/index/Reassignment.java index 22bef7d1df..ce07c5b1f6 100644 --- a/checker/tests/index/Reassignment.java +++ b/checker/tests/index/Reassignment.java @@ -3,7 +3,7 @@ // problem but still permits some unsoundness is worse than no solution and // an obvious issue. -class Reassignment { +public class Reassignment { void test(int[] arr, int i) { if (i > 0 && i < arr.length) { arr = new int[0]; diff --git a/checker/tests/index/RefineEq.java b/checker/tests/index/RefineEq.java index 08ad1e05c9..d7f59ddc74 100644 --- a/checker/tests/index/RefineEq.java +++ b/checker/tests/index/RefineEq.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.LTEqLengthOf; import org.checkerframework.checker.index.qual.LTLengthOf; -class RefineEq { +public class RefineEq { int[] arr = {1}; void testLTL(@LTLengthOf("arr") int test) { diff --git a/checker/tests/index/RefineGT.java b/checker/tests/index/RefineGT.java index 1847452449..a73613c6d7 100644 --- a/checker/tests/index/RefineGT.java +++ b/checker/tests/index/RefineGT.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.LTEqLengthOf; import org.checkerframework.checker.index.qual.LTLengthOf; -class RefineGT { +public class RefineGT { int[] arr = {1}; void testLTL(@LTLengthOf("arr") int test) { diff --git a/checker/tests/index/RefineGTE.java b/checker/tests/index/RefineGTE.java index df7bb1ff50..766d11562e 100644 --- a/checker/tests/index/RefineGTE.java +++ b/checker/tests/index/RefineGTE.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.LTEqLengthOf; import org.checkerframework.checker.index.qual.LTLengthOf; -class RefineGTE { +public class RefineGTE { int[] arr = {1}; void testLTL(@LTLengthOf("arr") int test) { diff --git a/checker/tests/index/RefineLT.java b/checker/tests/index/RefineLT.java index d010001a81..8412cd7fbf 100644 --- a/checker/tests/index/RefineLT.java +++ b/checker/tests/index/RefineLT.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.LTEqLengthOf; import org.checkerframework.checker.index.qual.LTLengthOf; -class RefineLT { +public class RefineLT { int[] arr = {1}; void testLTL(@LTLengthOf("arr") int test, @LTLengthOf("arr") int a, @LTLengthOf("arr") int a3) { diff --git a/checker/tests/index/RefineLTE.java b/checker/tests/index/RefineLTE.java index 0100320c49..bc0056aa3c 100644 --- a/checker/tests/index/RefineLTE.java +++ b/checker/tests/index/RefineLTE.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.LTEqLengthOf; import org.checkerframework.checker.index.qual.LTLengthOf; -class RefineLTE { +public class RefineLTE { int[] arr = {1}; void testLTL(@LTLengthOf("arr") int test) { diff --git a/checker/tests/index/RefineNeq.java b/checker/tests/index/RefineNeq.java index cf8e7fd29f..d5c2c72c68 100644 --- a/checker/tests/index/RefineNeq.java +++ b/checker/tests/index/RefineNeq.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.LTEqLengthOf; import org.checkerframework.checker.index.qual.LTLengthOf; -class RefineNeq { +public class RefineNeq { int[] arr = {1}; void testLTL(@LTLengthOf("arr") int test) { diff --git a/checker/tests/index/RefineNeqLength.java b/checker/tests/index/RefineNeqLength.java index 46be6b6595..d11d3ce2b8 100644 --- a/checker/tests/index/RefineNeqLength.java +++ b/checker/tests/index/RefineNeqLength.java @@ -8,7 +8,7 @@ import org.checkerframework.checker.index.qual.NonNegative; import org.checkerframework.common.value.qual.IntVal; -class RefineNeqLength { +public class RefineNeqLength { void refineNeqLength(int[] array, @IndexOrHigh("#1") int i) { // Refines i <= array.length to i < array.length if (i != array.length) { diff --git a/checker/tests/index/ReflectArray.java b/checker/tests/index/ReflectArray.java index b3d25c9ad6..33f31de95c 100644 --- a/checker/tests/index/ReflectArray.java +++ b/checker/tests/index/ReflectArray.java @@ -1,7 +1,7 @@ import java.lang.reflect.Array; import org.checkerframework.common.value.qual.MinLen; -class ReflectArray { +public class ReflectArray { void testNewInstance(int i) { // :: error: (argument.type.incompatible) diff --git a/checker/tests/index/RepeatLTLengthOf.java b/checker/tests/index/RepeatLTLengthOf.java index 73db3328c7..14565c7403 100644 --- a/checker/tests/index/RepeatLTLengthOf.java +++ b/checker/tests/index/RepeatLTLengthOf.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.EnsuresLTLengthOf; import org.checkerframework.checker.index.qual.EnsuresLTLengthOfIf; -class RepeatLTLengthOf { +public class RepeatLTLengthOf { protected String value1; protected String value2; diff --git a/checker/tests/index/RepeatLTLengthOfWithError.java b/checker/tests/index/RepeatLTLengthOfWithError.java index c6e5978765..fd8b63a79a 100644 --- a/checker/tests/index/RepeatLTLengthOfWithError.java +++ b/checker/tests/index/RepeatLTLengthOfWithError.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.EnsuresLTLengthOf; import org.checkerframework.checker.index.qual.EnsuresLTLengthOfIf; -class RepeatLTLengthOfWithError { +public class RepeatLTLengthOfWithError { protected String value1; protected String value2; diff --git a/checker/tests/index/Return.java b/checker/tests/index/Return.java index 2310f4708e..008776c851 100644 --- a/checker/tests/index/Return.java +++ b/checker/tests/index/Return.java @@ -1,4 +1,4 @@ -class Return { +public class Return { int[] test() { return null; } diff --git a/checker/tests/index/SLSubtyping.java b/checker/tests/index/SLSubtyping.java index 2a3d291a50..c99695bd77 100644 --- a/checker/tests/index/SLSubtyping.java +++ b/checker/tests/index/SLSubtyping.java @@ -2,7 +2,7 @@ // This test checks whether the SameLen type system works as expected. -class SLSubtyping { +public class SLSubtyping { int[] f = {1}; void subtype(int @SameLen("#2") [] a, int[] b) { diff --git a/checker/tests/index/SameLenAssignmentTransfer.java b/checker/tests/index/SameLenAssignmentTransfer.java index ef8db0bcc6..f1fe52fccb 100644 --- a/checker/tests/index/SameLenAssignmentTransfer.java +++ b/checker/tests/index/SameLenAssignmentTransfer.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.index.qual.*; -class SameLenAssignmentTransfer { +public class SameLenAssignmentTransfer { void transfer5(int @SameLen("#2") [] a, int[] b) { int[] c = a; for (int i = 0; i < c.length; i++) { // i's type is @LTL("c") diff --git a/checker/tests/index/SameLenEqualsRefinement.java b/checker/tests/index/SameLenEqualsRefinement.java index 0eb6e88416..6af7a52c52 100644 --- a/checker/tests/index/SameLenEqualsRefinement.java +++ b/checker/tests/index/SameLenEqualsRefinement.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.*; import org.checkerframework.dataflow.qual.Pure; -class SameLenEqualsRefinement { +public class SameLenEqualsRefinement { void transfer3(int @SameLen("#2") [] a, int[] b, int[] c) { if (a == c) { for (int i = 0; i < c.length; i++) { // i's type is @LTL("c") diff --git a/checker/tests/index/SameLenManyArrays.java b/checker/tests/index/SameLenManyArrays.java index f32844c7c3..0e0c519c36 100644 --- a/checker/tests/index/SameLenManyArrays.java +++ b/checker/tests/index/SameLenManyArrays.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.*; import org.checkerframework.dataflow.qual.Pure; -class SameLenManyArrays { +public class SameLenManyArrays { void transfer1(int @SameLen("#2") [] a, int[] b) { int[] c = new int[a.length]; for (int i = 0; i < c.length; i++) { // i's type is @LTL("c") diff --git a/checker/tests/index/SameLenNewArrayWithSameLength.java b/checker/tests/index/SameLenNewArrayWithSameLength.java index f2007c617f..e4bd965474 100644 --- a/checker/tests/index/SameLenNewArrayWithSameLength.java +++ b/checker/tests/index/SameLenNewArrayWithSameLength.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.index.qual.*; -class SameLenNewArrayWithSameLength { +public class SameLenNewArrayWithSameLength { public void m1(int[] a) { int @SameLen("a") [] b = new int[a.length]; } diff --git a/checker/tests/index/SameLenOnFormalParameter.java b/checker/tests/index/SameLenOnFormalParameter.java index 194cb839f5..b8bb360cdf 100644 --- a/checker/tests/index/SameLenOnFormalParameter.java +++ b/checker/tests/index/SameLenOnFormalParameter.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.index.qual.*; -class SameLenOnFormalParameter { +public class SameLenOnFormalParameter { public void requiresSameLen1(String x1, @SameLen("#1") String y1) {} public void requiresSameLen2(@SameLen("#2") String x2, String y2) {} diff --git a/checker/tests/index/SameLenOnFormalParameterSimple.java b/checker/tests/index/SameLenOnFormalParameterSimple.java index aa5495380f..53e11cd1ae 100644 --- a/checker/tests/index/SameLenOnFormalParameterSimple.java +++ b/checker/tests/index/SameLenOnFormalParameterSimple.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.index.qual.SameLen; -class SameLenOnFormalParameterSimple { +public class SameLenOnFormalParameterSimple { public void requiresSameLen1(String x1, @SameLen("#1") String y1) {} public void m1(@SameLen("#2") String a1, String b1) { diff --git a/checker/tests/index/SameLenSelf.java b/checker/tests/index/SameLenSelf.java index f3aaa557a0..f4740b26d3 100644 --- a/checker/tests/index/SameLenSelf.java +++ b/checker/tests/index/SameLenSelf.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.index.qual.*; -class SameLenSelf { +public class SameLenSelf { int @SameLen("this.field") [] field = new int[10]; int @SameLen("field2") [] field2 = new int[10]; int @SameLen("field3") [] field3 = field2; diff --git a/checker/tests/index/SameLenSimpleCase.java b/checker/tests/index/SameLenSimpleCase.java index 812b593a04..dceaf6dc16 100644 --- a/checker/tests/index/SameLenSimpleCase.java +++ b/checker/tests/index/SameLenSimpleCase.java @@ -1,4 +1,4 @@ -class SameLenSimpleCase { +public class SameLenSimpleCase { public int compare(int[] a1, int[] a2) { if (a1.length != a2.length) { return a1.length - a2.length; diff --git a/checker/tests/index/SameLenWithObjects.java b/checker/tests/index/SameLenWithObjects.java index b21f6fabab..60165d4cd9 100644 --- a/checker/tests/index/SameLenWithObjects.java +++ b/checker/tests/index/SameLenWithObjects.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.index.qual.*; -class SameLenWithObjects { +public class SameLenWithObjects { class SimpleCollection { Object[] var_infos; diff --git a/checker/tests/index/SearchIndexTests.java b/checker/tests/index/SearchIndexTests.java index bba7cff5df..74b21c9f3f 100644 --- a/checker/tests/index/SearchIndexTests.java +++ b/checker/tests/index/SearchIndexTests.java @@ -1,7 +1,7 @@ import java.util.Arrays; import org.checkerframework.checker.index.qual.*; -class SearchIndexTests { +public class SearchIndexTests { public void test(short[] a, short instant) { int i = Arrays.binarySearch(a, instant); @SearchIndexFor("a") int z = i; diff --git a/checker/tests/index/SimpleCollection.java b/checker/tests/index/SimpleCollection.java index f81da44678..24a2da1d8a 100644 --- a/checker/tests/index/SimpleCollection.java +++ b/checker/tests/index/SimpleCollection.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.index.qual.*; -class SimpleCollection { +public class SimpleCollection { private int[] values; @IndexOrHigh("values") int size() { diff --git a/checker/tests/index/SimpleTransferAdd.java b/checker/tests/index/SimpleTransferAdd.java index 5dc6965929..38b5a33018 100644 --- a/checker/tests/index/SimpleTransferAdd.java +++ b/checker/tests/index/SimpleTransferAdd.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.index.qual.NonNegative; import org.checkerframework.checker.index.qual.Positive; -class SimpleTransferAdd { +public class SimpleTransferAdd { void test() { int bs = -1; // :: error: (assignment.type.incompatible) diff --git a/checker/tests/index/SimpleTransferSub.java b/checker/tests/index/SimpleTransferSub.java index bb4d9b3777..cea610ba44 100644 --- a/checker/tests/index/SimpleTransferSub.java +++ b/checker/tests/index/SimpleTransferSub.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.index.qual.Positive; -class SimpleTransferSub { +public class SimpleTransferSub { void test() { // shows a bug in the checker framework. I don't think we can get around this bit... int bs = 0; diff --git a/checker/tests/index/SizeVsLength.java b/checker/tests/index/SizeVsLength.java index b5dcb81514..00208a61d3 100644 --- a/checker/tests/index/SizeVsLength.java +++ b/checker/tests/index/SizeVsLength.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.index.qual.*; -class SizeVsLength { +public class SizeVsLength { public int[] getArray(@NonNegative int size) { int[] values = new int[size]; diff --git a/checker/tests/index/SpecialTransfersForEquality.java b/checker/tests/index/SpecialTransfersForEquality.java index 203b7aa847..2a399df823 100644 --- a/checker/tests/index/SpecialTransfersForEquality.java +++ b/checker/tests/index/SpecialTransfersForEquality.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.index.qual.NonNegative; import org.checkerframework.checker.index.qual.Positive; -class SpecialTransfersForEquality { +public class SpecialTransfersForEquality { void gteN1Test(@GTENegativeOne int y) { int[] arr = new int[10]; diff --git a/checker/tests/index/StartsEndsWith.java b/checker/tests/index/StartsEndsWith.java index d3fc5aef8d..9078068567 100644 --- a/checker/tests/index/StartsEndsWith.java +++ b/checker/tests/index/StartsEndsWith.java @@ -3,7 +3,7 @@ import org.checkerframework.common.value.qual.MinLen; -class StartsEndsWith { +public class StartsEndsWith { // This particular test is here rather than in the framework tests because it depends on purity // annotations for these particular JDK methods. diff --git a/checker/tests/index/StringIndexOf.java b/checker/tests/index/StringIndexOf.java index d262cef470..003aea18b3 100644 --- a/checker/tests/index/StringIndexOf.java +++ b/checker/tests/index/StringIndexOf.java @@ -1,6 +1,6 @@ // Tests using the index returned from String.indexOf -class StringIndexOf { +public class StringIndexOf { public static String remove(String l, String s) { int i = l.indexOf(s); diff --git a/checker/tests/index/StringLenRefinement.java b/checker/tests/index/StringLenRefinement.java index a590f61e2e..d7556bfa4e 100644 --- a/checker/tests/index/StringLenRefinement.java +++ b/checker/tests/index/StringLenRefinement.java @@ -2,7 +2,7 @@ import org.checkerframework.common.value.qual.ArrayLenRange; import org.checkerframework.common.value.qual.StringVal; -class StringLenRefinement { +public class StringLenRefinement { void refineLenRange( @ArrayLenRange(from = 3, to = 10) String range, diff --git a/checker/tests/index/StringLength.java b/checker/tests/index/StringLength.java index b4f491475c..aa2de13fda 100644 --- a/checker/tests/index/StringLength.java +++ b/checker/tests/index/StringLength.java @@ -9,7 +9,7 @@ import org.checkerframework.checker.index.qual.SameLen; import org.checkerframework.common.value.qual.MinLen; -class StringLength { +public class StringLength { void testMinLenSubtractPositive(@MinLen(10) String s) { @Positive int i1 = s.length() - 9; @NonNegative int i0 = s.length() - 10; diff --git a/checker/tests/index/StringMethods.java b/checker/tests/index/StringMethods.java index 266374acb2..0c3368d591 100644 --- a/checker/tests/index/StringMethods.java +++ b/checker/tests/index/StringMethods.java @@ -1,6 +1,6 @@ // Tests for index annotations on string methods in the annotated JDK -class StringMethods { +public class StringMethods { void testCharAt(String s, int i) { // :: error: (argument.type.incompatible) diff --git a/checker/tests/index/StringSameLen.java b/checker/tests/index/StringSameLen.java index 5313e1b271..1286990355 100644 --- a/checker/tests/index/StringSameLen.java +++ b/checker/tests/index/StringSameLen.java @@ -1,4 +1,4 @@ -class StringSameLen { +public class StringSameLen { public void m(String s) { String t = s; diff --git a/checker/tests/index/StringTokenizerMinLen.java b/checker/tests/index/StringTokenizerMinLen.java index 67934ce786..d91c481387 100644 --- a/checker/tests/index/StringTokenizerMinLen.java +++ b/checker/tests/index/StringTokenizerMinLen.java @@ -3,7 +3,7 @@ import java.util.StringTokenizer; -class StringTokenizerMinLen { +public class StringTokenizerMinLen { void test(String str, String delim, boolean returnDelims) { StringTokenizer st = new StringTokenizer(str, delim, returnDelims); while (st.hasMoreTokens()) { diff --git a/checker/tests/index/TransferMod.java b/checker/tests/index/TransferMod.java index 1e86954152..a98d62cd76 100644 --- a/checker/tests/index/TransferMod.java +++ b/checker/tests/index/TransferMod.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.index.qual.NonNegative; import org.checkerframework.checker.index.qual.Positive; -class TransferMod { +public class TransferMod { void test() { int aa = -100; diff --git a/checker/tests/index/TypeArrayLengthWithSameLen.java b/checker/tests/index/TypeArrayLengthWithSameLen.java index 21a1571fad..a35bed6799 100644 --- a/checker/tests/index/TypeArrayLengthWithSameLen.java +++ b/checker/tests/index/TypeArrayLengthWithSameLen.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.index.qual.*; -class TypeArrayLengthWithSameLen { +public class TypeArrayLengthWithSameLen { void test(int @SameLen("#2") [] a, int @SameLen("#1") [] b, int[] c) { if (a.length == c.length) { @LTEqLengthOf({"a", "b", "c"}) int x = b.length; diff --git a/checker/tests/index/ViewpointAdaptTest.java b/checker/tests/index/ViewpointAdaptTest.java index 048bfedfdf..a15114fa2d 100644 --- a/checker/tests/index/ViewpointAdaptTest.java +++ b/checker/tests/index/ViewpointAdaptTest.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.index.qual.LTEqLengthOf; import org.checkerframework.checker.index.qual.LTLengthOf; -class ViewpointAdaptTest { +public class ViewpointAdaptTest { void ListGet( @LTLengthOf("list") int index, @LTEqLengthOf("list") int notIndex, List list) { diff --git a/checker/tests/index/divisionTest.java b/checker/tests/index/divisionTest.java index d0aae78d8a..64067842a4 100644 --- a/checker/tests/index/divisionTest.java +++ b/checker/tests/index/divisionTest.java @@ -1,6 +1,6 @@ import java.util.*; -class divisionTest { +public class divisionTest { public static void division() { System.out.println(1 / (2.0)); diff --git a/checker/tests/initialization/CastInit.java b/checker/tests/initialization/CastInit.java index 14f7666fae..6d775f9c9d 100644 --- a/checker/tests/initialization/CastInit.java +++ b/checker/tests/initialization/CastInit.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.initialization.qual.Initialized; import org.checkerframework.checker.initialization.qual.UnknownInitialization; -class CastInit { +public class CastInit { public CastInit() { @UnknownInitialization CastInit t1 = (@UnknownInitialization CastInit) this; diff --git a/checker/tests/initialization/List.java b/checker/tests/initialization/FBCList.java similarity index 64% rename from checker/tests/initialization/List.java rename to checker/tests/initialization/FBCList.java index 26464b116d..14f1f5beb7 100644 --- a/checker/tests/initialization/List.java +++ b/checker/tests/initialization/FBCList.java @@ -4,11 +4,11 @@ // This example is taken from the FBC paper, figure 1 (and has some additional code in main below). // We made the list generic. -public class List { - @NotOnlyInitialized Node sentinel; +public class FBCList { + @NotOnlyInitialized FBCNode sentinel; - public List() { - this.sentinel = new Node<>(this); + public FBCList() { + this.sentinel = new FBCNode<>(this); } void insert(@Nullable T data) { @@ -16,30 +16,30 @@ void insert(@Nullable T data) { } public static void main() { - List l = new List<>(); + FBCList l = new FBCList<>(); l.insert(1); l.insert(2); } } -class Node { - @NotOnlyInitialized Node prev; +class FBCNode { + @NotOnlyInitialized FBCNode prev; - @NotOnlyInitialized Node next; + @NotOnlyInitialized FBCNode next; - @NotOnlyInitialized List parent; + @NotOnlyInitialized FBCList parent; @Nullable T data; // for sentinel construction - Node(@UnderInitialization List parent) { + FBCNode(@UnderInitialization FBCList parent) { this.parent = parent; this.prev = this; this.next = this; } // for data node construction - Node(Node prev, Node next, @Nullable T data) { + FBCNode(FBCNode prev, FBCNode next, @Nullable T data) { this.parent = prev.parent; this.prev = prev; this.next = next; @@ -47,7 +47,7 @@ class Node { } void insertAfter(@Nullable T data) { - Node n = new Node<>(this, this.next, data); + FBCNode n = new FBCNode<>(this, this.next, data); this.next.prev = n; this.next = n; } diff --git a/checker/tests/initialization/Issue574.java b/checker/tests/initialization/Issue574.java index 55845637bc..5489e5fa46 100644 --- a/checker/tests/initialization/Issue574.java +++ b/checker/tests/initialization/Issue574.java @@ -10,7 +10,7 @@ // However, for the purposes of this test, fields must be annotated with @UnderInitialization. "initialization.invalid.field.type" }) -class Issue574 { +public class Issue574 { @UnderInitialization(Object.class) Object o1; @UnderInitialization(String.class) Object o2; diff --git a/checker/tests/initialization/Issue813.java b/checker/tests/initialization/Issue813.java index 647fc62637..30689628c1 100644 --- a/checker/tests/initialization/Issue813.java +++ b/checker/tests/initialization/Issue813.java @@ -5,7 +5,7 @@ import org.checkerframework.checker.initialization.qual.NotOnlyInitialized; import org.checkerframework.checker.initialization.qual.UnderInitialization; -class Issue813 { +public class Issue813 { static interface MyInterface {} static class MyClass { diff --git a/checker/tests/initialization/ReceiverSuperInvocation.java b/checker/tests/initialization/ReceiverSuperInvocation.java index 914b7716c9..6ec0be1e7c 100644 --- a/checker/tests/initialization/ReceiverSuperInvocation.java +++ b/checker/tests/initialization/ReceiverSuperInvocation.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.initialization.qual.UnderInitialization; -class ReceiverSuperInvocation { +public class ReceiverSuperInvocation { void foo(@UnderInitialization(ReceiverSuperInvocation.class) ReceiverSuperInvocation this) {} } diff --git a/checker/tests/initialization/TryFinallyBreak.java b/checker/tests/initialization/TryFinallyBreak.java index f98dca6793..c78d8fd7b7 100644 --- a/checker/tests/initialization/TryFinallyBreak.java +++ b/checker/tests/initialization/TryFinallyBreak.java @@ -1,7 +1,7 @@ // Test case for Issue 548: // https://github.com/typetools/checker-framework/issues/548 -class TryFinallyBreak { +public class TryFinallyBreak { String testWhile1() { String ans = "x"; while (this.hashCode() > 10000) { diff --git a/checker/tests/initialization/TryFinallyContinue.java b/checker/tests/initialization/TryFinallyContinue.java index 67eb4ce470..6b22d5bcb0 100644 --- a/checker/tests/initialization/TryFinallyContinue.java +++ b/checker/tests/initialization/TryFinallyContinue.java @@ -1,7 +1,7 @@ // Test case for Issue 548: // https://github.com/typetools/checker-framework/issues/548 -class TryFinallyContinue { +public class TryFinallyContinue { String testWhile1() { String ans = "x"; while (true) { diff --git a/checker/tests/interning/ArrayInitializers.java b/checker/tests/interning/ArrayInitializers.java index 8ca4147794..cb24dfc018 100644 --- a/checker/tests/interning/ArrayInitializers.java +++ b/checker/tests/interning/ArrayInitializers.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.interning.qual.Interned; -class ArrayInitializers { +public class ArrayInitializers { public static final String STATIC_FIELD = "m"; public static final @Interned String OTHER_FIELD = "n"; diff --git a/checker/tests/interning/Autoboxing.java b/checker/tests/interning/Autoboxing.java index 320354c94e..cc53021822 100644 --- a/checker/tests/interning/Autoboxing.java +++ b/checker/tests/interning/Autoboxing.java @@ -1,4 +1,4 @@ -class Autoboxing { +public class Autoboxing { Byte b; Short s; Short sInterned; diff --git a/checker/tests/interning/ClassDefaults.java b/checker/tests/interning/ClassDefaults.java index 41d9a091ae..60f057be36 100644 --- a/checker/tests/interning/ClassDefaults.java +++ b/checker/tests/interning/ClassDefaults.java @@ -6,7 +6,7 @@ * and method type argument inference. * A previously existing Unqualified annotation wasn't correctly removed. */ -class ClassDefaults { +public class ClassDefaults { @Interned class Test {} public static interface Visitor {} diff --git a/checker/tests/interning/CompileTimeConstants2.java b/checker/tests/interning/CompileTimeConstants2.java index 2a93198513..f4c725db44 100644 --- a/checker/tests/interning/CompileTimeConstants2.java +++ b/checker/tests/interning/CompileTimeConstants2.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.interning.qual.Interned; -class CompileTimeConstants2 { +public class CompileTimeConstants2 { @Interned String s1 = "" + ("" + 1); @Interned String s2 = (("" + ("" + 1))); diff --git a/checker/tests/interning/ConditionalInterning.java b/checker/tests/interning/ConditionalInterning.java index 2462609628..342cd77e98 100644 --- a/checker/tests/interning/ConditionalInterning.java +++ b/checker/tests/interning/ConditionalInterning.java @@ -1,4 +1,4 @@ -class ConditionalInterning { +public class ConditionalInterning { int a, b, c; boolean cmp() { diff --git a/checker/tests/interning/FieldsImplicits.java b/checker/tests/interning/FieldsImplicits.java index 2b034910e6..149e953682 100644 --- a/checker/tests/interning/FieldsImplicits.java +++ b/checker/tests/interning/FieldsImplicits.java @@ -1,5 +1,5 @@ /** Tests that a final field annotation is inferred. */ -class FieldsImplicits { +public class FieldsImplicits { final String finalField = "asdf"; static final String finalStaticField = "asdf"; String nonFinalField = "asdf"; diff --git a/checker/tests/interning/Issue2809.java b/checker/tests/interning/Issue2809.java index 788be873ec..64a3713529 100644 --- a/checker/tests/interning/Issue2809.java +++ b/checker/tests/interning/Issue2809.java @@ -4,7 +4,7 @@ import org.checkerframework.checker.interning.qual.Interned; import org.checkerframework.checker.interning.qual.UnknownInterned; -class Issue2809 { +public class Issue2809 { void new1(MyType t, int @Interned [] non) { t.self(new MyType<>(non)); diff --git a/checker/tests/interning/Issue3594.java b/checker/tests/interning/Issue3594.java index 76ca6426e3..4d231c0616 100644 --- a/checker/tests/interning/Issue3594.java +++ b/checker/tests/interning/Issue3594.java @@ -1,4 +1,4 @@ -class Issue3594 { +public class Issue3594 { // Throwable is annotated with @UsesObjectEquals, which is an inherited annotation. // So, MyThrowable should be treated as @UsesObjectEquals, too. diff --git a/checker/tests/interning/Options.java b/checker/tests/interning/Options.java index cef3f08fe7..496b7791ca 100644 --- a/checker/tests/interning/Options.java +++ b/checker/tests/interning/Options.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.interning.qual.*; // Test case lifted from plume.Options -class Options { +public class Options { public void minimal(String s) { String arg = ""; // interned here diff --git a/checker/tests/interning/OverrideInterned.java b/checker/tests/interning/OverrideInterned.java index 3da93058ba..7e94814679 100644 --- a/checker/tests/interning/OverrideInterned.java +++ b/checker/tests/interning/OverrideInterned.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.interning.qual.Interned; -class OverrideInterned { +public class OverrideInterned { // This code is extracted from FreePastry diff --git a/checker/tests/interning/Raw3.java b/checker/tests/interning/Raw3.java index 076ee491ab..f332f7f0e9 100644 --- a/checker/tests/interning/Raw3.java +++ b/checker/tests/interning/Raw3.java @@ -9,7 +9,7 @@ * List<@Interned String> sl = new ArrayList(); * and then the assignment fails. */ -class Raw3 { +public class Raw3 { // We would like behavior that is as similar as possible between the // versions with no raw types and those with raw types. diff --git a/checker/tests/lock/ChapterExamples.java b/checker/tests/lock/ChapterExamples.java index cdd316541f..f492d61a29 100644 --- a/checker/tests/lock/ChapterExamples.java +++ b/checker/tests/lock/ChapterExamples.java @@ -19,7 +19,7 @@ import org.checkerframework.checker.lock.qual.ReleasesNoLocks; import org.checkerframework.checker.nullness.qual.NonNull; -class ChapterExamples { +public class ChapterExamples { // This code crashed when there was a bug before issue 524 was fixed. // An attempt to take the LUB between 'val' in the store with type 'long' // and 'val' in another store with type 'none' resulted in a crash. diff --git a/checker/tests/lock/ClassLiterals.java b/checker/tests/lock/ClassLiterals.java index 5122300405..04564529af 100644 --- a/checker/tests/lock/ClassLiterals.java +++ b/checker/tests/lock/ClassLiterals.java @@ -2,13 +2,13 @@ import org.checkerframework.checker.lock.qual.Holding; -class ClassLiterals { +public class ClassLiterals { @Holding("ClassLiterals.class") static Object method1() { return new Object(); } - // a class literal may not terminate a flow expression string + // a class literal may not terminate a JavaExpression string @Holding("ClassLiterals") // :: error: (flowexpr.parse.error) static void method2() {} @@ -19,7 +19,7 @@ static void method3() {} @Holding("testpackage.ClassLiterals.class") static void method4() {} - // a class literal may not terminate a flow expression string + // a class literal may not terminate a JavaExpression string @Holding("testpackage.ClassLiterals") // :: error: (flowexpr.parse.error) static void method5() {} diff --git a/checker/tests/lock/FlowExpressionsTest.java b/checker/tests/lock/FlowExpressionsTest.java index 822158630e..5d2747b7cd 100644 --- a/checker/tests/lock/FlowExpressionsTest.java +++ b/checker/tests/lock/FlowExpressionsTest.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.lock.qual.*; import org.checkerframework.dataflow.qual.Pure; -class FlowExpressionsTest { +public class FlowExpressionsTest { class MyClass { public Object field; } diff --git a/checker/tests/lock/GuardedByLocalVariable.java b/checker/tests/lock/GuardedByLocalVariable.java index 4775b71f39..e9cd572357 100644 --- a/checker/tests/lock/GuardedByLocalVariable.java +++ b/checker/tests/lock/GuardedByLocalVariable.java @@ -5,7 +5,7 @@ import java.util.Map; import org.checkerframework.checker.lock.qual.*; -class GuardedByLocalVariable { +public class GuardedByLocalVariable { public static void localVariableShadowing() { // :: error: (expression.unparsable.type.invalid) diff --git a/checker/tests/lock/Issue2163Lock.java b/checker/tests/lock/Issue2163Lock.java index 86f8ef0d16..0b73b90922 100644 --- a/checker/tests/lock/Issue2163Lock.java +++ b/checker/tests/lock/Issue2163Lock.java @@ -1,10 +1,10 @@ import org.checkerframework.checker.lock.qual.*; -class Issue2163 { - @GuardedBy Issue2163() {} +public class Issue2163Lock { + @GuardedBy Issue2163Lock() {} void test() { // :: error: (constructor.invocation.invalid) :: error: (guardsatisfied.location.disallowed) - new @GuardSatisfied Issue2163(); + new @GuardSatisfied Issue2163Lock(); } } diff --git a/checker/tests/lock/Issue523.java b/checker/tests/lock/Issue523.java index 06ccbec3ff..1a29887ddb 100644 --- a/checker/tests/lock/Issue523.java +++ b/checker/tests/lock/Issue523.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.lock.qual.*; -class Issue523 { +public class Issue523 { static class MyClass { Object field; } diff --git a/checker/tests/lock/Issue524.java b/checker/tests/lock/Issue524.java index c9f54bb13d..8f2a5ebada 100644 --- a/checker/tests/lock/Issue524.java +++ b/checker/tests/lock/Issue524.java @@ -16,7 +16,7 @@ // However even without a fix for issue 524 in place, the test sometimes type checks. // Unfortunately a test case that always fails to typecheck using a Checker Framework build // prior to the fix for issue 524 has not been found. -class Issue524 { +public class Issue524 { class MyClass { public Object field; } diff --git a/checker/tests/lock/Issue805.java b/checker/tests/lock/Issue805.java index 772cb32e0c..6a721e772c 100644 --- a/checker/tests/lock/Issue805.java +++ b/checker/tests/lock/Issue805.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.lock.qual.Holding; -class Issue805 { +public class Issue805 { @Holding("this.Issue805.class") // :: error: (flowexpr.parse.error) void method() {} diff --git a/checker/tests/lock/ItselfExpressionCases.java b/checker/tests/lock/ItselfExpressionCases.java index 753a792e83..f01d3a94e1 100644 --- a/checker/tests/lock/ItselfExpressionCases.java +++ b/checker/tests/lock/ItselfExpressionCases.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.nullness.qual.*; import org.checkerframework.dataflow.qual.*; -class ItselfExpressionCases { +public class ItselfExpressionCases { final Object somelock = new Object(); private final @GuardedBy({""}) MyClass m = new MyClass(); diff --git a/checker/tests/lock/LockInterfaceTest.java b/checker/tests/lock/LockInterfaceTest.java index db5a331698..595de5a3d8 100644 --- a/checker/tests/lock/LockInterfaceTest.java +++ b/checker/tests/lock/LockInterfaceTest.java @@ -7,7 +7,7 @@ import org.checkerframework.checker.lock.qual.MayReleaseLocks; import org.checkerframework.checker.lock.qual.ReleasesNoLocks; -class LockInterfaceTest { +public class LockInterfaceTest { static final Lock myStaticLock = new ReentrantLock(true); diff --git a/checker/tests/lock/PrimitivesLocking.java b/checker/tests/lock/PrimitivesLocking.java index 5e102157db..2149feb8f2 100644 --- a/checker/tests/lock/PrimitivesLocking.java +++ b/checker/tests/lock/PrimitivesLocking.java @@ -4,7 +4,7 @@ // Note that testing of the immutable.type.guardedby error message is done in TestTreeKinds.java -class PrimitivesLocking { +public class PrimitivesLocking { // @GuardedByName("lock") int primitive = 1; diff --git a/checker/tests/lock/TestAnon.java b/checker/tests/lock/TestAnon.java index 5750b06620..0966c61c64 100644 --- a/checker/tests/lock/TestAnon.java +++ b/checker/tests/lock/TestAnon.java @@ -1,4 +1,4 @@ -class TestAnon { +public class TestAnon { public void foo() { String s = ""; new Object() { diff --git a/checker/tests/lock/TestConcurrentSemantics1.java b/checker/tests/lock/TestConcurrentSemantics1.java index 6c1511cd65..cdd430708f 100644 --- a/checker/tests/lock/TestConcurrentSemantics1.java +++ b/checker/tests/lock/TestConcurrentSemantics1.java @@ -4,7 +4,7 @@ import org.checkerframework.checker.lock.qual.GuardedBy; import org.checkerframework.checker.lock.qual.GuardedByUnknown; -class TestConcurrentSemantics1 { +public class TestConcurrentSemantics1 { /* This class tests the following critical scenario. * * Suppose the following lines from method1 are executed on thread A. diff --git a/checker/tests/lock/TestConcurrentSemantics2.java b/checker/tests/lock/TestConcurrentSemantics2.java index db30b7240b..3f25def0cc 100644 --- a/checker/tests/lock/TestConcurrentSemantics2.java +++ b/checker/tests/lock/TestConcurrentSemantics2.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.lock.qual.GuardedBy; -class TestConcurrentSemantics2 { +public class TestConcurrentSemantics2 { final Object a = new Object(); final Object b = new Object(); diff --git a/checker/tests/lock/ThisPostCondition.java b/checker/tests/lock/ThisPostCondition.java index 448932937e..0e31d1ea5e 100644 --- a/checker/tests/lock/ThisPostCondition.java +++ b/checker/tests/lock/ThisPostCondition.java @@ -32,7 +32,7 @@ boolean tryLock() { } } -class ThisPostCondition { +public class ThisPostCondition { final MyReentrantLock myLock = new MyReentrantLock(); @GuardedBy("myLock") Bar bar = new Bar(); diff --git a/checker/tests/lock/TypeVarNull.java b/checker/tests/lock/TypeVarNull.java index 555f100af6..a4713a7d84 100644 --- a/checker/tests/lock/TypeVarNull.java +++ b/checker/tests/lock/TypeVarNull.java @@ -1,3 +1,3 @@ -class TypeVarNull { +public class TypeVarNull { T t = null; } diff --git a/checker/tests/lock/Update.java b/checker/tests/lock/Update.java index 882baa2b12..66bd10f95d 100644 --- a/checker/tests/lock/Update.java +++ b/checker/tests/lock/Update.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.lock.qual.GuardedBy; -class Update { +public class Update { void test() { Object o1 = new Object(); diff --git a/checker/tests/nullness-asserts/TestAssumeAssertionsAreEnabled.java b/checker/tests/nullness-asserts/TestAssumeAssertionsAreEnabled.java index 003f3a52ca..3d639182b4 100644 --- a/checker/tests/nullness-asserts/TestAssumeAssertionsAreEnabled.java +++ b/checker/tests/nullness-asserts/TestAssumeAssertionsAreEnabled.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; -class TestAssumeAssertionsAreEnabled { +public class TestAssumeAssertionsAreEnabled { void foo(@Nullable String s1, @Nullable String s2) { // :: error: (dereference.of.nullable) diff --git a/checker/tests/nullness-assumeassertions/TestAssumeAssertionsAreDisabled.java b/checker/tests/nullness-assumeassertions/TestAssumeAssertionsAreDisabled.java index ae15c04e9b..37b2fb419d 100644 --- a/checker/tests/nullness-assumeassertions/TestAssumeAssertionsAreDisabled.java +++ b/checker/tests/nullness-assumeassertions/TestAssumeAssertionsAreDisabled.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; -class TestAssumeAssertionsAreDisabled { +public class TestAssumeAssertionsAreDisabled { void foo(@Nullable String s1, @Nullable String s2) { diff --git a/checker/tests/nullness-extra/Bug109_B.java b/checker/tests/nullness-extra/Bug109_B.java index 3bb75bda3c..b4beca9692 100644 --- a/checker/tests/nullness-extra/Bug109_B.java +++ b/checker/tests/nullness-extra/Bug109_B.java @@ -1,4 +1,4 @@ -class Bug109_B extends Bug109_A { +public class Bug109_B extends Bug109_A { public Bug109_B() { // Accessing field one causes NPE // at org.checkerframework.checker.nullness.MapGetHeuristics.handle diff --git a/checker/tests/nullness-extra/issue265/Delta.java b/checker/tests/nullness-extra/issue265/Delta.java index b62a66c0f1..f8b67139c7 100644 --- a/checker/tests/nullness-extra/issue265/Delta.java +++ b/checker/tests/nullness-extra/issue265/Delta.java @@ -1,6 +1,6 @@ import java.util.List; -class Delta { +public class Delta { List field; Delta(List field) { diff --git a/checker/tests/nullness-extra/issue309/Issue309.java b/checker/tests/nullness-extra/issue309/Issue309.java index 9975d15d16..2c3a1029d3 100644 --- a/checker/tests/nullness-extra/issue309/Issue309.java +++ b/checker/tests/nullness-extra/issue309/Issue309.java @@ -1,6 +1,6 @@ import lib.Lib; -class Issue309 { +public class Issue309 { void bar() { Lib.foo(); } diff --git a/checker/tests/nullness-extra/issue348/Issue348.java b/checker/tests/nullness-extra/issue348/Issue348.java index 4969b63d1d..f7dd6b8282 100644 --- a/checker/tests/nullness-extra/issue348/Issue348.java +++ b/checker/tests/nullness-extra/issue348/Issue348.java @@ -1,6 +1,6 @@ import lib.Lib; -class Issue348 { +public class Issue348 { void test() { Lib lib = new Lib(); diff --git a/checker/tests/nullness-extra/issue3597/testpkg/Issue3597A.java b/checker/tests/nullness-extra/issue3597/testpkg/Issue3597A.java index 9a03aed0d4..0a9be45d12 100644 --- a/checker/tests/nullness-extra/issue3597/testpkg/Issue3597A.java +++ b/checker/tests/nullness-extra/issue3597/testpkg/Issue3597A.java @@ -1,6 +1,6 @@ package testpkg; -class Issue3597A { +public class Issue3597A { void f() { System.err.println(new Issue3597B().f().toString()); } diff --git a/checker/tests/nullness-extra/issue3597/testpkg/Issue3597B.java b/checker/tests/nullness-extra/issue3597/testpkg/Issue3597B.java index f8661b7bcf..b365430b09 100644 --- a/checker/tests/nullness-extra/issue3597/testpkg/Issue3597B.java +++ b/checker/tests/nullness-extra/issue3597/testpkg/Issue3597B.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; -class Issue3597B { +public class Issue3597B { @Nullable Object f() { return new Object(); } diff --git a/checker/tests/nullness-extra/issue502/Issue502.java b/checker/tests/nullness-extra/issue502/Issue502.java index 21576cc30f..a39f3ff374 100644 --- a/checker/tests/nullness-extra/issue502/Issue502.java +++ b/checker/tests/nullness-extra/issue502/Issue502.java @@ -1,7 +1,7 @@ // Test case for Issue 502: // https://github.com/typetools/checker-framework/issues/502 -class Issue502 { +public class Issue502 { @Override public String toString() { return ""; diff --git a/checker/tests/nullness-extra/issue559/Expected.txt b/checker/tests/nullness-extra/issue559/Expected.txt index 59bbf4f8b8..ef808e0e01 100644 --- a/checker/tests/nullness-extra/issue559/Expected.txt +++ b/checker/tests/nullness-extra/issue559/Expected.txt @@ -1,4 +1,4 @@ -warning: StubParser: in file myjdk.astub at line 6 ignored existing annotations on type: T[ extends @Initialized @Nullable Object super @Initialized @Nullable Void] +warning: AnnotationFileParser: in file myjdk.astub at line 6 ignored existing annotations on type: T[ extends @Initialized @Nullable Object super @Initialized @Nullable Void] Issue559.java:10: error: [argument.type.incompatible] incompatible types in argument. o.orElse(null); ^ diff --git a/checker/tests/nullness-extra/issue559/Issue559.java b/checker/tests/nullness-extra/issue559/Issue559.java index 848d799db7..158dc6fa38 100644 --- a/checker/tests/nullness-extra/issue559/Issue559.java +++ b/checker/tests/nullness-extra/issue559/Issue559.java @@ -3,7 +3,7 @@ import java.util.Optional; -class Issue559 { +public class Issue559 { void bar(Optional o) { // With myjdk.astub the following should fail with an // argument.type.incompatible error. diff --git a/checker/tests/nullness-extra/issue607/Issue607.java b/checker/tests/nullness-extra/issue607/Issue607.java index 3be6545a1b..c441fc5784 100644 --- a/checker/tests/nullness-extra/issue607/Issue607.java +++ b/checker/tests/nullness-extra/issue607/Issue607.java @@ -1,4 +1,4 @@ -class Issue607 extends Issue607SuperClass { +public class Issue607 extends Issue607SuperClass { static String simpleString = "a"; Issue607() { diff --git a/checker/tests/nullness-extra/package-anno/test/PackageAnnotationTest.java b/checker/tests/nullness-extra/package-anno/test/PackageAnnotationTest.java index 0e56069550..87991eae4f 100644 --- a/checker/tests/nullness-extra/package-anno/test/PackageAnnotationTest.java +++ b/checker/tests/nullness-extra/package-anno/test/PackageAnnotationTest.java @@ -1,6 +1,6 @@ package test; -class PackageAnnotationTest { +public class PackageAnnotationTest { // Allowed because of package annotation. Object f = null; } diff --git a/checker/tests/nullness-extra/shorthand/NullnessRegexWithErrors.java b/checker/tests/nullness-extra/shorthand/NullnessRegexWithErrors.java index 7a151c7984..d9bc93ab5a 100644 --- a/checker/tests/nullness-extra/shorthand/NullnessRegexWithErrors.java +++ b/checker/tests/nullness-extra/shorthand/NullnessRegexWithErrors.java @@ -2,7 +2,7 @@ import java.util.regex.Pattern; -class NullnessRegexWithErrors { +public class NullnessRegexWithErrors { String str = "(str"; void context() { diff --git a/checker/tests/nullness-genericwildcardlib/GwiParent.java b/checker/tests/nullness-genericwildcardlib/GwiParent.java index e469bc2a89..6fde1b3e7c 100644 --- a/checker/tests/nullness-genericwildcardlib/GwiParent.java +++ b/checker/tests/nullness-genericwildcardlib/GwiParent.java @@ -1,6 +1,6 @@ // Library for issue #511: https://github.com/typetools/checker-framework/issues/511 -abstract class GwiParent { +public abstract class GwiParent { abstract void syntaxError(Recognizer recognizer); } diff --git a/checker/tests/nullness-javac-errors/BadCast1.java b/checker/tests/nullness-javac-errors/BadCast1.java index 06f503646d..2d9cf3c1bb 100644 --- a/checker/tests/nullness-javac-errors/BadCast1.java +++ b/checker/tests/nullness-javac-errors/BadCast1.java @@ -1,4 +1,4 @@ -class BadCast1 { +public class BadCast1 { public void m() { // :: error: illegal start of type :: error: not a statement (@NonNull) ""; diff --git a/checker/tests/nullness-javac-errors/BadCast2.java b/checker/tests/nullness-javac-errors/BadCast2.java index fdded88f7a..174f85cd78 100644 --- a/checker/tests/nullness-javac-errors/BadCast2.java +++ b/checker/tests/nullness-javac-errors/BadCast2.java @@ -1,4 +1,4 @@ -class BadCast2 { +public class BadCast2 { public static void main(String[] args) { // :: error: illegal start of type String example = (@NonNull) ""; diff --git a/checker/tests/nullness-reflection/VoidTest.java b/checker/tests/nullness-reflection/VoidTest.java index ec85c01278..a6d88928b0 100644 --- a/checker/tests/nullness-reflection/VoidTest.java +++ b/checker/tests/nullness-reflection/VoidTest.java @@ -1,4 +1,4 @@ -class VoidTest { +public class VoidTest { Class test() { return void.class; diff --git a/checker/tests/nullness-safedefaultsbytecode/BytecodeDefaultsTest.java b/checker/tests/nullness-safedefaultsbytecode/BytecodeDefaultsTest.java index d27a28057d..b2265edc9a 100644 --- a/checker/tests/nullness-safedefaultsbytecode/BytecodeDefaultsTest.java +++ b/checker/tests/nullness-safedefaultsbytecode/BytecodeDefaultsTest.java @@ -3,7 +3,7 @@ // Tests that the unchecked bytecode defaults option does not // affect defaulting nor suppress errors in source code. -class BytecodeDefaultsTest { +public class BytecodeDefaultsTest { void f() { g(""); } diff --git a/checker/tests/nullness-safedefaultssourcecode/BasicSafeDefaultsTest.java b/checker/tests/nullness-safedefaultssourcecode/BasicSafeDefaultsTest.java index af53460173..a12e7ebc23 100644 --- a/checker/tests/nullness-safedefaultssourcecode/BasicSafeDefaultsTest.java +++ b/checker/tests/nullness-safedefaultssourcecode/BasicSafeDefaultsTest.java @@ -5,7 +5,7 @@ // -AuseConservativeDefaultsForUncheckedCode=source is supplied. @AnnotatedFor("nullness") -class BasicSafeDefaultsTest { +public class BasicSafeDefaultsTest { void m1() { @NonNull Object x1 = SdfuscLib.unannotated(); diff --git a/checker/tests/nullness-safedefaultssourcecode/PrimitiveClassLiteral.java b/checker/tests/nullness-safedefaultssourcecode/PrimitiveClassLiteral.java new file mode 100644 index 0000000000..1d70bcd18c --- /dev/null +++ b/checker/tests/nullness-safedefaultssourcecode/PrimitiveClassLiteral.java @@ -0,0 +1,33 @@ +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.AnnotatedFor; + +@AnnotatedFor("nullness") +public class PrimitiveClassLiteral { + private static @Nullable Class unwrapPrimitive(Class c) { + if (c == Byte.class) { + return byte.class; + } + if (c == Character.class) { + return char.class; + } + if (c == Short.class) { + return short.class; + } + if (c == Integer.class) { + return int.class; + } + if (c == Long.class) { + return long.class; + } + if (c == Float.class) { + return float.class; + } + if (c == Double.class) { + return double.class; + } + if (c == Boolean.class) { + return boolean.class; + } + return c; + } +} diff --git a/checker/tests/nullness-stubfile/NullnessStubfileMerge.java b/checker/tests/nullness-stubfile/NullnessStubfileMerge.java index fc26d492c8..979dce316d 100644 --- a/checker/tests/nullness-stubfile/NullnessStubfileMerge.java +++ b/checker/tests/nullness-stubfile/NullnessStubfileMerge.java @@ -1,6 +1,7 @@ -// warning: StubParser: Package-private method notReal(String) not found in type java.lang.String -// warning: StubParser: Type not found: java.lang.NotARealClass -// warning: StubParser: Type not found: not.real.NotARealClassInNotRealPackage +// warning: stubfile1.astub:(line 16,col 6): Package-private method notReal(String) not found in +// type java.lang.String +// warning: stubfile1.astub:(line 19,col 1): Type not found: java.lang.NotARealClass +// warning: stubfile1.astub:(line 21,col 1): Type not found: not.real.NotARealClassInNotRealPackage import org.checkerframework.checker.nullness.qual.*; diff --git a/checker/tests/nullness/AnnotatedJdkEqualsTest.java b/checker/tests/nullness/AnnotatedJdkEqualsTest.java index 47376c0f5c..87975920dc 100644 --- a/checker/tests/nullness/AnnotatedJdkEqualsTest.java +++ b/checker/tests/nullness/AnnotatedJdkEqualsTest.java @@ -4,7 +4,7 @@ import java.net.URL; -class AnnotatedJdkEqualsTest { +public class AnnotatedJdkEqualsTest { void foo(URL u) { // As of this writing, the annotated JDK does not contain a URL.java file // for the java.net.URL class. diff --git a/checker/tests/nullness/AnnotatedJdkTest.java b/checker/tests/nullness/AnnotatedJdkTest.java index d914f7a772..a8669b0d49 100644 --- a/checker/tests/nullness/AnnotatedJdkTest.java +++ b/checker/tests/nullness/AnnotatedJdkTest.java @@ -4,7 +4,7 @@ import java.util.List; import org.checkerframework.checker.nullness.qual.Nullable; -class AnnotatedJdkTest { +public class AnnotatedJdkTest { // This code should type-check because of the annotated JDK, which contains: // class Arrays { // public static List asList(T... a); diff --git a/checker/tests/nullness/ArrayIndex.java b/checker/tests/nullness/ArrayIndex.java index b25bf6769d..6be82600be 100644 --- a/checker/tests/nullness/ArrayIndex.java +++ b/checker/tests/nullness/ArrayIndex.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; -class ArrayIndex { +public class ArrayIndex { void foo(@Nullable Object[] a, int i) { if (a[i] != null) { a[i].hashCode(); diff --git a/checker/tests/nullness/ArrayInitBug.java b/checker/tests/nullness/ArrayInitBug.java index 1bae579a57..19fbb8d7fe 100644 --- a/checker/tests/nullness/ArrayInitBug.java +++ b/checker/tests/nullness/ArrayInitBug.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class ArrayInitBug { +public class ArrayInitBug { @Nullable Object @Nullable [] aa; diff --git a/checker/tests/nullness/ArrayLazyNN.java b/checker/tests/nullness/ArrayLazyNN.java index e25fd6fc28..8054f1d23a 100644 --- a/checker/tests/nullness/ArrayLazyNN.java +++ b/checker/tests/nullness/ArrayLazyNN.java @@ -5,7 +5,7 @@ * we can be sure that all elements are non-null. * TODO: support for (i=0; i < a.length.... and change component type to non-null. */ -class ArrayLazyNN { +public class ArrayLazyNN { void test1() { @MonotonicNonNull Object[] o1 = new @MonotonicNonNull Object[10]; o1[0] = new Object(); diff --git a/checker/tests/nullness/ArrayNew.java b/checker/tests/nullness/ArrayNew.java index 6a7232ebb5..284bda743e 100644 --- a/checker/tests/nullness/ArrayNew.java +++ b/checker/tests/nullness/ArrayNew.java @@ -1,7 +1,7 @@ import java.util.Collection; import org.checkerframework.checker.nullness.qual.*; -class ArrayNew { +public class ArrayNew { void m(Collection seq1) { Integer[] seq1_array = new @NonNull Integer[] {5}; Integer[] seq2_array = seq1.toArray(new @NonNull Integer[0]); diff --git a/checker/tests/nullness/BinaryOp.java b/checker/tests/nullness/BinaryOp.java index 5f3eda7a0d..64a96590dc 100644 --- a/checker/tests/nullness/BinaryOp.java +++ b/checker/tests/nullness/BinaryOp.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.initialization.qual.*; import org.checkerframework.checker.nullness.qual.*; -class BinaryOp { +public class BinaryOp { void test(@UnknownInitialization Object obj) { throw new Error("" + obj); } diff --git a/checker/tests/nullness/BinarySearch.java b/checker/tests/nullness/BinarySearch.java index 4aa04ab31c..44ba2f7aec 100644 --- a/checker/tests/nullness/BinarySearch.java +++ b/checker/tests/nullness/BinarySearch.java @@ -2,7 +2,7 @@ // Allow searching through nullable arrays components // and for nullable keys. -class BinarySearch { +public class BinarySearch { @Nullable Object @NonNull [] arr = {"a", "b", null}; void search(@Nullable Object key) { diff --git a/checker/tests/nullness/ChainAssignment.java b/checker/tests/nullness/ChainAssignment.java index 891ac587df..45557c6c4a 100644 --- a/checker/tests/nullness/ChainAssignment.java +++ b/checker/tests/nullness/ChainAssignment.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; -class ChainAssignment { +public class ChainAssignment { @Nullable Object a; @Nullable Object b; Object x = new Object(); diff --git a/checker/tests/nullness/CompoundAssign.java b/checker/tests/nullness/CompoundAssign.java index b8ce8d273a..e9cf4075d0 100644 --- a/checker/tests/nullness/CompoundAssign.java +++ b/checker/tests/nullness/CompoundAssign.java @@ -1,4 +1,4 @@ -class CompoundAssign { +public class CompoundAssign { void m(String args) { String arg = ""; for (int ii = 0; ii < args.length(); ii++) { diff --git a/checker/tests/nullness/DefaultInterface.java b/checker/tests/nullness/DefaultInterface.java index 22c765be88..d5751902de 100644 --- a/checker/tests/nullness/DefaultInterface.java +++ b/checker/tests/nullness/DefaultInterface.java @@ -7,7 +7,7 @@ interface Foo { } @DefaultQualifier(org.checkerframework.checker.nullness.qual.NonNull.class) -class DefaultInterface { +public class DefaultInterface { public void test() { diff --git a/checker/tests/nullness/DotClass.java b/checker/tests/nullness/DotClass.java index a1cac7b9f3..cdf9beed0c 100644 --- a/checker/tests/nullness/DotClass.java +++ b/checker/tests/nullness/DotClass.java @@ -1,7 +1,7 @@ import java.lang.annotation.Annotation; import org.checkerframework.checker.nullness.qual.NonNull; -class DotClass { +public class DotClass { void test() { doStuff(NonNull.class); diff --git a/checker/tests/nullness/EmptyConstructor.java b/checker/tests/nullness/EmptyConstructor.java index 4db946bb2d..f623ebe215 100644 --- a/checker/tests/nullness/EmptyConstructor.java +++ b/checker/tests/nullness/EmptyConstructor.java @@ -3,7 +3,7 @@ import org.checkerframework.dataflow.qual.*; -class SuperClass { +public class SuperClass { static int count = 0; public SuperClass() { diff --git a/checker/tests/nullness/EnsuresNonNullIfTest.java b/checker/tests/nullness/EnsuresNonNullIfTest.java index 16fdd513dd..a7b88dd079 100644 --- a/checker/tests/nullness/EnsuresNonNullIfTest.java +++ b/checker/tests/nullness/EnsuresNonNullIfTest.java @@ -30,7 +30,7 @@ public static void fromDirNeg(File1 dbdir) { // TODO: Have a way of saying the property holds no matter what value is used in a given expression. -class File1 { +public class File1 { @EnsuresNonNullIf( result = true, expression = { diff --git a/checker/tests/nullness/EnumStaticBlock.java b/checker/tests/nullness/EnumStaticBlock.java index c203092df5..dc056ffd9c 100644 --- a/checker/tests/nullness/EnumStaticBlock.java +++ b/checker/tests/nullness/EnumStaticBlock.java @@ -1,7 +1,7 @@ import java.util.ArrayList; import java.util.List; -class EnumStaticBlock { +public class EnumStaticBlock { public enum Section { ME, OTHER; diff --git a/checker/tests/nullness/ExceptionParam.java b/checker/tests/nullness/ExceptionParam.java index 00e495dc74..f6b78a54eb 100644 --- a/checker/tests/nullness/ExceptionParam.java +++ b/checker/tests/nullness/ExceptionParam.java @@ -4,7 +4,7 @@ /** Exception parameters are non-null, even if the default is nullable. */ @DefaultQualifier(org.checkerframework.checker.nullness.qual.Nullable.class) -class ExceptionParam { +public class ExceptionParam { void exc1() { try { } catch (AssertionError e) { diff --git a/checker/tests/nullness/FinalFields.java b/checker/tests/nullness/FinalFields.java index e5e6645512..26d1c27369 100644 --- a/checker/tests/nullness/FinalFields.java +++ b/checker/tests/nullness/FinalFields.java @@ -13,7 +13,7 @@ void access() { } } -class FinalFields { +public class FinalFields { public void foo(Upper u) { // Error, because final field in different class is not refined // :: error: (dereference.of.nullable) diff --git a/checker/tests/nullness/FinalVar.java b/checker/tests/nullness/FinalVar.java index 7d23965b0e..1aba0708f9 100644 --- a/checker/tests/nullness/FinalVar.java +++ b/checker/tests/nullness/FinalVar.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.NonNull; -class FinalVar { +public class FinalVar { public Object pptIterator() { // Only test with (effectively) final variables; Java only permits final or diff --git a/checker/tests/nullness/FinalVar2.java b/checker/tests/nullness/FinalVar2.java index 66b186f3db..af05348ff8 100644 --- a/checker/tests/nullness/FinalVar2.java +++ b/checker/tests/nullness/FinalVar2.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.nullness.qual.*; -class FinalVar2 { +public class FinalVar2 { static Object method1(@Nullable Object arg) { final Object tmp = arg; diff --git a/checker/tests/nullness/FinalVar3.java b/checker/tests/nullness/FinalVar3.java index 47084b22f1..0a024047ec 100644 --- a/checker/tests/nullness/FinalVar3.java +++ b/checker/tests/nullness/FinalVar3.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class FinalVar3 { +public class FinalVar3 { static Object method1(@Nullable Object arg) { final Object tmp = arg; diff --git a/checker/tests/nullness/FlowCompound.java b/checker/tests/nullness/FlowCompound.java index 3a97aa6b48..6784610555 100644 --- a/checker/tests/nullness/FlowCompound.java +++ b/checker/tests/nullness/FlowCompound.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class FlowCompound { +public class FlowCompound { @org.checkerframework.dataflow.qual.Pure public boolean equals(@Nullable Object o) { diff --git a/checker/tests/nullness/FlowCompoundConcatenation.java b/checker/tests/nullness/FlowCompoundConcatenation.java index e81d0734cb..8ab7c81a7a 100644 --- a/checker/tests/nullness/FlowCompoundConcatenation.java +++ b/checker/tests/nullness/FlowCompoundConcatenation.java @@ -1,4 +1,4 @@ -class FlowCompoundConcatenation { +public class FlowCompoundConcatenation { static String getNonNullString() { return ""; } diff --git a/checker/tests/nullness/FlowConditions.java b/checker/tests/nullness/FlowConditions.java index d1ea8217ad..5dbfe6c2ee 100644 --- a/checker/tests/nullness/FlowConditions.java +++ b/checker/tests/nullness/FlowConditions.java @@ -4,7 +4,7 @@ import java.util.Set; import org.checkerframework.checker.nullness.qual.*; -class FlowConditions { +public class FlowConditions { void m(@Nullable Object x, @Nullable Object y) { if (x == null || y == null) { // :: error: (dereference.of.nullable) diff --git a/checker/tests/nullness/FlowExpressionParsingBug.java b/checker/tests/nullness/FlowExpressionParsingBug.java index deee2bf3f0..93b2c84c74 100644 --- a/checker/tests/nullness/FlowExpressionParsingBug.java +++ b/checker/tests/nullness/FlowExpressionParsingBug.java @@ -4,7 +4,7 @@ public abstract class FlowExpressionParsingBug { - //// Check that flow expressions with explicit and implicit 'this' work + //// Check that JavaExpressions with explicit and implicit 'this' work protected @Nullable JMenuBar menuBar = null; @@ -14,7 +14,7 @@ public void addFavorite() {} @RequiresNonNull("this.menuBar") public void addFavorite1() {} - //// Check flow expressions for static fields with different ways to access the field + //// Check JavaExpressions for static fields with different ways to access the field static @Nullable String i = null; diff --git a/checker/tests/nullness/FlowSelf.java b/checker/tests/nullness/FlowSelf.java index 55a7d1f5ea..bfde931ada 100644 --- a/checker/tests/nullness/FlowSelf.java +++ b/checker/tests/nullness/FlowSelf.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class FlowSelf { +public class FlowSelf { void test(@Nullable String s) { diff --git a/checker/tests/nullness/FullyQualifiedAnnotation.java b/checker/tests/nullness/FullyQualifiedAnnotation.java index 7b2f10ac62..438a9f2d6c 100644 --- a/checker/tests/nullness/FullyQualifiedAnnotation.java +++ b/checker/tests/nullness/FullyQualifiedAnnotation.java @@ -1,6 +1,6 @@ import java.util.Iterator; -class FullyQualifiedAnnotation { +public class FullyQualifiedAnnotation { void client1(Iterator i) { @SuppressWarnings("nullness") diff --git a/checker/tests/nullness/GetInterfacesPurity.java b/checker/tests/nullness/GetInterfacesPurity.java new file mode 100644 index 0000000000..ab32812be7 --- /dev/null +++ b/checker/tests/nullness/GetInterfacesPurity.java @@ -0,0 +1,11 @@ +import org.checkerframework.dataflow.qual.Pure; + +public class GetInterfacesPurity { + + @Pure + public static boolean isSubtype(Class sub, Class sup) { + // :: error: (purity.not.deterministic.call) + Class[] interfaces = sub.getInterfaces(); + return interfaces.length == 0; + } +} diff --git a/checker/tests/nullness/HierarchicalInit.java b/checker/tests/nullness/HierarchicalInit.java index 8b3f341b48..eb85da3927 100644 --- a/checker/tests/nullness/HierarchicalInit.java +++ b/checker/tests/nullness/HierarchicalInit.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class HierarchicalInit { +public class HierarchicalInit { String a; diff --git a/checker/tests/nullness/ImplementInterface.java b/checker/tests/nullness/ImplementInterface.java index 6fcebb1150..610c165307 100644 --- a/checker/tests/nullness/ImplementInterface.java +++ b/checker/tests/nullness/ImplementInterface.java @@ -4,7 +4,7 @@ interface TestInterface { public char @Nullable [] getChars(); } -class ImplementInterface implements TestInterface { +public class ImplementInterface implements TestInterface { @Override public char @Nullable [] getChars() { return null; diff --git a/checker/tests/nullness/InferListParam.java b/checker/tests/nullness/InferListParam.java index 8020d79657..981823e98d 100644 --- a/checker/tests/nullness/InferListParam.java +++ b/checker/tests/nullness/InferListParam.java @@ -1,7 +1,7 @@ import java.util.Collections; import java.util.List; -class InferListParam { +public class InferListParam { List fieldValues; InferListParam() { diff --git a/checker/tests/nullness/InferNullType.java b/checker/tests/nullness/InferNullType.java index c7be64e36d..8f9eacbab8 100644 --- a/checker/tests/nullness/InferNullType.java +++ b/checker/tests/nullness/InferNullType.java @@ -1,5 +1,5 @@ // Version of framework/tests/all-systems/InferNullType.java with expected Nullness Checker warnings -class InferNullType { +public class InferNullType { T toInfer(T input) { return input; diff --git a/checker/tests/nullness/InferTypeArgsCondtionalExpression.java b/checker/tests/nullness/InferTypeArgsConditionalExpression.java similarity index 93% rename from checker/tests/nullness/InferTypeArgsCondtionalExpression.java rename to checker/tests/nullness/InferTypeArgsConditionalExpression.java index 9dbd21d1ab..b0103be213 100644 --- a/checker/tests/nullness/InferTypeArgsCondtionalExpression.java +++ b/checker/tests/nullness/InferTypeArgsConditionalExpression.java @@ -6,7 +6,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; -class InferTypeArgsConditionalExpression { +public class InferTypeArgsConditionalExpression { public void foo(Generic real, Generic other, boolean flag) { // :: error: (type.argument.type.incompatible) diff --git a/checker/tests/nullness/Initializer.java b/checker/tests/nullness/Initializer.java index 7ee126f04b..c0b6323c43 100644 --- a/checker/tests/nullness/Initializer.java +++ b/checker/tests/nullness/Initializer.java @@ -3,7 +3,7 @@ import org.checkerframework.framework.qual.EnsuresQualifier; import org.checkerframework.framework.qual.EnsuresQualifierIf; -class Initializer { +public class Initializer { public String a; public String b = "abc"; diff --git a/checker/tests/nullness/Issue1027.java b/checker/tests/nullness/Issue1027.java index 61f33482fd..62e3da84cd 100644 --- a/checker/tests/nullness/Issue1027.java +++ b/checker/tests/nullness/Issue1027.java @@ -11,7 +11,7 @@ import java.util.stream.Stream; import org.checkerframework.checker.nullness.qual.KeyFor; -class Issue1027 { +public class Issue1027 { // Stand-alone reproduction diff --git a/checker/tests/nullness/Issue1059.java b/checker/tests/nullness/Issue1059.java index d1fd2dd505..df652f8720 100644 --- a/checker/tests/nullness/Issue1059.java +++ b/checker/tests/nullness/Issue1059.java @@ -4,7 +4,7 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNull; import org.checkerframework.checker.nullness.qual.Nullable; -class Issue1059 { +public class Issue1059 { @Nullable Object f; @EnsuresNonNull({"f"}) diff --git a/checker/tests/nullness/Issue1096.java b/checker/tests/nullness/Issue1096.java index 2c38a970b3..70b354fd65 100644 --- a/checker/tests/nullness/Issue1096.java +++ b/checker/tests/nullness/Issue1096.java @@ -32,13 +32,13 @@ void doNullable(@UnknownInitialization PreCond this) { } void foo(@UnknownInitialization PreCond this) { - // Receiver is not fully initialized, so raise error + // The receiver is not fully initialized, so raise an error. // :: error: (contracts.precondition.not.satisfied) early(); } void bar() { - // Receiver is initialized, so non-null field f is definitely non-null + // The receiver is initialized, so non-null field f is definitely non-null. early(); // Nullable fields stay nullable // :: error: (contracts.precondition.not.satisfied) @@ -48,13 +48,13 @@ void bar() { class User { void foo(@UnknownInitialization PreCond pc) { - // Receiver is not fully initialized, so raise error + // The receiver is not fully initialized, so raise an error. // :: error: (contracts.precondition.not.satisfied) pc.early(); } void bar(PreCond pc) { - // Receiver is initialized, so non-null field f is definitely non-null + // The receiver is initialized, so non-null field f is definitely non-null. pc.early(); // Nullable fields stay nullable // :: error: (contracts.precondition.not.satisfied) diff --git a/checker/tests/nullness/Issue1147.java b/checker/tests/nullness/Issue1147.java index c6ec600671..65ae001664 100644 --- a/checker/tests/nullness/Issue1147.java +++ b/checker/tests/nullness/Issue1147.java @@ -2,7 +2,7 @@ import java.util.StringJoiner; -class Issue1147 { +public class Issue1147 { public static void main(String[] args) { diff --git a/checker/tests/nullness/Issue1307.java b/checker/tests/nullness/Issue1307.java index c52fe0c04f..a5978de12d 100644 --- a/checker/tests/nullness/Issue1307.java +++ b/checker/tests/nullness/Issue1307.java @@ -6,7 +6,7 @@ @DefaultQualifier(value = Nullable.class, locations = TypeUseLocation.FIELD) @DefaultQualifier(value = Nullable.class, locations = TypeUseLocation.PARAMETER) -class Issue1307 { +public class Issue1307 { Object nullableField = null; void perl(Integer a) { diff --git a/checker/tests/nullness/Issue1522.java b/checker/tests/nullness/Issue1522.java index cf51eeb99d..9cfc74ed46 100644 --- a/checker/tests/nullness/Issue1522.java +++ b/checker/tests/nullness/Issue1522.java @@ -4,7 +4,7 @@ import java.util.Vector; import org.checkerframework.checker.nullness.qual.Nullable; -class Issue1522 { +public class Issue1522 { void copyInto(String p) {} void bar() { diff --git a/checker/tests/nullness/Issue1555.java b/checker/tests/nullness/Issue1555.java index 38352c2a2a..147b8ed650 100644 --- a/checker/tests/nullness/Issue1555.java +++ b/checker/tests/nullness/Issue1555.java @@ -4,7 +4,7 @@ import org.checkerframework.checker.nullness.NullnessUtil; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -class Issue1555 { +public class Issue1555 { private @MonotonicNonNull String x; diff --git a/checker/tests/nullness/Issue1628.java b/checker/tests/nullness/Issue1628.java index 1904ceade0..363571381c 100644 --- a/checker/tests/nullness/Issue1628.java +++ b/checker/tests/nullness/Issue1628.java @@ -4,7 +4,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; -class Issue1628> implements Issue1628R { +public class Issue1628> implements Issue1628R { public boolean isEmpty() { return false; diff --git a/checker/tests/nullness/Issue1797.java b/checker/tests/nullness/Issue1797.java index f611eb9fb8..f1bcf42dfe 100644 --- a/checker/tests/nullness/Issue1797.java +++ b/checker/tests/nullness/Issue1797.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; -class Issue1797 { +public class Issue1797 { void fooReturn(@Nullable Object o) { try { return; diff --git a/checker/tests/nullness/Issue1981.java b/checker/tests/nullness/Issue1981.java index 2f4d98fd6a..98dd8b9242 100644 --- a/checker/tests/nullness/Issue1981.java +++ b/checker/tests/nullness/Issue1981.java @@ -3,7 +3,7 @@ import java.util.List; -class Issue1981 { +public class Issue1981 { void test(List ids) { for (List l : func2(func1(ids))) {} diff --git a/checker/tests/nullness/Issue1983.java b/checker/tests/nullness/Issue1983.java index 20d963b477..11de271dd3 100644 --- a/checker/tests/nullness/Issue1983.java +++ b/checker/tests/nullness/Issue1983.java @@ -6,7 +6,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; @SuppressWarnings("initialization.fields.uninitialized") -class Issue1983 { +public class Issue1983 { Converter converter; diff --git a/checker/tests/nullness/Issue2048.java b/checker/tests/nullness/Issue2048.java index f7f09a4fed..03d85ff960 100644 --- a/checker/tests/nullness/Issue2048.java +++ b/checker/tests/nullness/Issue2048.java @@ -5,7 +5,7 @@ // framework/tests/all-systems // checker/tests/nullness -class Issue2048 { +public class Issue2048 { interface Foo {} interface Fooer {} diff --git a/checker/tests/nullness/Issue2407.java b/checker/tests/nullness/Issue2407.java index b0948f38cb..1510ccbd2f 100644 --- a/checker/tests/nullness/Issue2407.java +++ b/checker/tests/nullness/Issue2407.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; import org.checkerframework.checker.nullness.qual.RequiresNonNull; -class Issue2407 { +public class Issue2407 { @RequiresNonNull("#1") void setMessage(String message) {} diff --git a/checker/tests/nullness/Issue2432.java b/checker/tests/nullness/Issue2432.java index 35dca6e1c4..21568fa551 100644 --- a/checker/tests/nullness/Issue2432.java +++ b/checker/tests/nullness/Issue2432.java @@ -6,7 +6,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.PolyNull; -class Issue2432 { +public class Issue2432 { void jdkAnnotation(List<@PolyNull Object> nl, @Nullable Object no, @PolyNull Object po) { // :: error: (argument.type.incompatible) diff --git a/checker/tests/nullness/Issue2432b.java b/checker/tests/nullness/Issue2432b.java index 49d132b0de..4b54db5454 100644 --- a/checker/tests/nullness/Issue2432b.java +++ b/checker/tests/nullness/Issue2432b.java @@ -5,7 +5,7 @@ import java.util.List; import org.checkerframework.checker.nullness.qual.PolyNull; -class Issue2432b { +public class Issue2432b { void objectAsTypeArg() { List objs = new ArrayList<>(); // no error diff --git a/checker/tests/nullness/Issue261.java b/checker/tests/nullness/Issue261.java index 737a95df28..06756158a9 100644 --- a/checker/tests/nullness/Issue261.java +++ b/checker/tests/nullness/Issue261.java @@ -1,6 +1,6 @@ // Test case for Issue 261 // https://github.com/typetools/checker-framework/issues/261 -class Issue261 { +public class Issue261 { boolean b; // :: error: (initialization.fields.uninitialized) class Flag { diff --git a/checker/tests/nullness/Issue266.java b/checker/tests/nullness/Issue266.java index 5ab25c4b72..0b1df73bc9 100644 --- a/checker/tests/nullness/Issue266.java +++ b/checker/tests/nullness/Issue266.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.nullness.qual.*; -class Issue266 { +public class Issue266 { abstract static class Inner { abstract String getThing(); diff --git a/checker/tests/nullness/Issue266a.java b/checker/tests/nullness/Issue266a.java index 43488399f6..9919404293 100644 --- a/checker/tests/nullness/Issue266a.java +++ b/checker/tests/nullness/Issue266a.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.nullness.qual.*; -class Issue266a { +public class Issue266a { private final Object mBar; public Issue266a() { diff --git a/checker/tests/nullness/Issue2721.java b/checker/tests/nullness/Issue2721.java index 5ec429b278..089a982812 100644 --- a/checker/tests/nullness/Issue2721.java +++ b/checker/tests/nullness/Issue2721.java @@ -3,7 +3,7 @@ import java.util.List; @SuppressWarnings("all") // Just check for crashes. -class Issue2721 { +public class Issue2721 { void foo() { passThrough(asList(asList(1))).get(0).get(0).intValue(); } diff --git a/checker/tests/nullness/Issue273.java b/checker/tests/nullness/Issue273.java index c0210c00e3..8a9b2810ff 100644 --- a/checker/tests/nullness/Issue273.java +++ b/checker/tests/nullness/Issue273.java @@ -5,7 +5,7 @@ import java.util.Map; import org.checkerframework.checker.nullness.qual.*; -class Issue273 { +public class Issue273 { public static void main(String... p) { Map m0 = new HashMap<>(); Map m1 = new HashMap<>(); diff --git a/checker/tests/nullness/Issue2888.java b/checker/tests/nullness/Issue2888.java index 2795a14598..49be12b48a 100644 --- a/checker/tests/nullness/Issue2888.java +++ b/checker/tests/nullness/Issue2888.java @@ -1,6 +1,6 @@ import com.sun.istack.internal.Nullable; -class Issue2888 { +public class Issue2888 { @Nullable Object[] noa; void foo() { diff --git a/checker/tests/nullness/Issue289.java b/checker/tests/nullness/Issue289.java index 3834cf99c0..c3c6e678e4 100644 --- a/checker/tests/nullness/Issue289.java +++ b/checker/tests/nullness/Issue289.java @@ -5,7 +5,7 @@ import java.util.List; import org.checkerframework.checker.nullness.qual.*; -class Issue289 { +public class Issue289 { void simple() { List lo = new ArrayList<>(); List ls = new ArrayList<>(); diff --git a/checker/tests/nullness/Issue293.java b/checker/tests/nullness/Issue293.java index aafb3ccc85..c17ab75fe7 100644 --- a/checker/tests/nullness/Issue293.java +++ b/checker/tests/nullness/Issue293.java @@ -1,7 +1,7 @@ // Test for Issue 293: // https://github.com/typetools/checker-framework/issues/293 -class Issue293 { +public class Issue293 { void test1() { String s; try { diff --git a/checker/tests/nullness/Issue296.java b/checker/tests/nullness/Issue296.java index 507179c3c7..fbd960e825 100644 --- a/checker/tests/nullness/Issue296.java +++ b/checker/tests/nullness/Issue296.java @@ -6,7 +6,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; // Note that with -AinvariantArrays we would get additional errors. -class Issue296 { +public class Issue296 { public static void f1(T[] a) { @Nullable T[] r1 = Arrays.copyOf(a, a.length + 1); // :: error: (argument.type.incompatible) diff --git a/checker/tests/nullness/Issue3033.java b/checker/tests/nullness/Issue3033.java index 6f58f28f29..c636dbd9b8 100644 --- a/checker/tests/nullness/Issue3033.java +++ b/checker/tests/nullness/Issue3033.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -class Issue3033 { +public class Issue3033 { class Test { diff --git a/checker/tests/nullness/Issue306.java b/checker/tests/nullness/Issue306.java index 67bcf19704..b5919d0352 100644 --- a/checker/tests/nullness/Issue306.java +++ b/checker/tests/nullness/Issue306.java @@ -6,7 +6,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; -class Issue306 { +public class Issue306 { @MonotonicNonNull Object x; static T check(T var) { diff --git a/checker/tests/nullness/Issue308.java b/checker/tests/nullness/Issue308.java index 8deb220ab1..86d2a6f61d 100644 --- a/checker/tests/nullness/Issue308.java +++ b/checker/tests/nullness/Issue308.java @@ -4,7 +4,7 @@ // @skip-test The clean-room implementation of javax.validation.constraints.NotNull is not in this // repository because Oracle claims a license over its specification and is lawsuit-happy. -class Issue308 { +public class Issue308 { @NonNull Object nonnull = new Object(); @Nullable Object nullable; diff --git a/checker/tests/nullness/Issue3150.java b/checker/tests/nullness/Issue3150.java index 7b7f4ce984..24d2507cc9 100644 --- a/checker/tests/nullness/Issue3150.java +++ b/checker/tests/nullness/Issue3150.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -class Issue3150 { +public class Issue3150 { void foo(@Nullable Object nble, @NonNull Object nn) { // :: error: (type.argument.type.incompatible) requireNonNull1(null); diff --git a/checker/tests/nullness/Issue328.java b/checker/tests/nullness/Issue328.java index 11bb3d3128..8fff376a17 100644 --- a/checker/tests/nullness/Issue328.java +++ b/checker/tests/nullness/Issue328.java @@ -1,7 +1,7 @@ import java.util.Map; import org.checkerframework.checker.nullness.qual.*; -class Issue328 { +public class Issue328 { public static void m(Map a, Map b, Object ka, Object kb) { if (a.containsKey(ka)) { @NonNull Object i = a.get(ka); // OK diff --git a/checker/tests/nullness/Issue3349.java b/checker/tests/nullness/Issue3349.java index 78c0980119..7f76b1f015 100644 --- a/checker/tests/nullness/Issue3349.java +++ b/checker/tests/nullness/Issue3349.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.nullness.qual.*; // :: warning: (explicit.annotation.ignored) -class Issue3348 { +public class Issue3349 { void foo(T p1) { @NonNull Serializable s = p1; @NonNull Object o = p1; diff --git a/checker/tests/nullness/Issue338.java b/checker/tests/nullness/Issue338.java index 8e5934d8be..f2f1e66099 100644 --- a/checker/tests/nullness/Issue338.java +++ b/checker/tests/nullness/Issue338.java @@ -2,7 +2,7 @@ interface Foo338 { Class get(); } -class Issue338 { +public class Issue338 { static void m2(Foo338 foo) { Class clazz = foo.get(); } diff --git a/checker/tests/nullness/Issue3443.java b/checker/tests/nullness/Issue3443.java index d70d281fb3..34057774d1 100644 --- a/checker/tests/nullness/Issue3443.java +++ b/checker/tests/nullness/Issue3443.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; -class Issue3443 { +public class Issue3443 { static > Supplier3443 passThrough(T t) { // :: error: (return.type.incompatible) return t; diff --git a/checker/tests/nullness/Issue354.java b/checker/tests/nullness/Issue354.java index 2cf783b30b..f004769673 100644 --- a/checker/tests/nullness/Issue354.java +++ b/checker/tests/nullness/Issue354.java @@ -1,4 +1,4 @@ -class Issue354 { +public class Issue354 { String a; diff --git a/checker/tests/nullness/Issue355.java b/checker/tests/nullness/Issue355.java index 83e40cd0d9..1264159f7d 100644 --- a/checker/tests/nullness/Issue355.java +++ b/checker/tests/nullness/Issue355.java @@ -5,7 +5,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -class Issue355 { +public class Issue355 { static @NonNull T checkNotNull(@Nullable T sample) { throw new RuntimeException(); } diff --git a/checker/tests/nullness/Issue3631.java b/checker/tests/nullness/Issue3631.java new file mode 100644 index 0000000000..4704ec06e9 --- /dev/null +++ b/checker/tests/nullness/Issue3631.java @@ -0,0 +1,18 @@ +import org.checkerframework.checker.nullness.qual.RequiresNonNull; + +public class Issue3631 { + + void f(Object otherArg) { + // Casts aren't a supported JavaExpression. + // :: error: (contracts.precondition.not.satisfied) + ((Issue3631Helper) otherArg).m(); + } +} + +class Issue3631Helper { + + String type = "foo"; + + @RequiresNonNull("type") + void m() {} +} diff --git a/checker/tests/nullness/Issue3681.java b/checker/tests/nullness/Issue3681.java index a0ac0d68ee..6637dedb04 100644 --- a/checker/tests/nullness/Issue3681.java +++ b/checker/tests/nullness/Issue3681.java @@ -1,11 +1,8 @@ // Test case for isse #3681: https://tinyurl.com/cfissue/3681 -// @skip-test until the bug is fixed - +// @below-java11-jdk-skip-test package org.jro.tests.checkerfwk.utils; -import org.checkerframework.checker.nullness.qual.NonNull; - public class Issue3681 { interface PartialFunction { R apply(T t); @@ -19,32 +16,32 @@ interface Either { boolean isRight(); } - public static @NonNull PartialFunction, R> createKeepRight() { + public static PartialFunction, R> createKeepRight() { return new PartialFunction<>() { @Override - @NonNull public R apply(final @NonNull Either either) { + public R apply(final Either either) { return either.get(); } @Override - public boolean isDefinedAt(final @NonNull Either value) { + public boolean isDefinedAt(final Either value) { return value.isRight(); } }; } - public static @NonNull + public static PartialFunction, ? extends R> createRCovariantKeepRight() { return new PartialFunction<>() { @Override - @NonNull public R apply(final @NonNull Either either) { + public R apply(final Either either) { return either.get(); } @Override - public boolean isDefinedAt(final @NonNull Either value) { + public boolean isDefinedAt(final Either value) { return value.isRight(); } }; diff --git a/checker/tests/nullness/Issue370.java b/checker/tests/nullness/Issue370.java index 63d46365d8..293556fb5f 100644 --- a/checker/tests/nullness/Issue370.java +++ b/checker/tests/nullness/Issue370.java @@ -3,7 +3,7 @@ import java.util.Collections; -class Issue370 { +public class Issue370 { Iterable foo() { return Collections.emptyList(); diff --git a/checker/tests/nullness/Issue376.java b/checker/tests/nullness/Issue376.java index b8b725d822..34219f1d53 100644 --- a/checker/tests/nullness/Issue376.java +++ b/checker/tests/nullness/Issue376.java @@ -1,7 +1,7 @@ // Test case for Issue 376: // https://github.com/typetools/checker-framework/issues/376 -class Issue376Test { +public class Issue376 { interface I {} diff --git a/checker/tests/nullness/Issue3850.java b/checker/tests/nullness/Issue3850.java index d35bf53d41..056dbb9eb2 100644 --- a/checker/tests/nullness/Issue3850.java +++ b/checker/tests/nullness/Issue3850.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.PolyNull; -class Issue3850 { +public class Issue3850 { private static Iterable<@PolyNull String> toPos(Iterable nodes) { // :: error: (return.type.incompatible) diff --git a/checker/tests/nullness/Issue388.java b/checker/tests/nullness/Issue388.java index d6f00c3299..702eeb1901 100644 --- a/checker/tests/nullness/Issue388.java +++ b/checker/tests/nullness/Issue388.java @@ -3,7 +3,7 @@ import java.util.Map; -class MapKeyConstant { +public class Issue388 { static class Holder { static final String KEY = "key"; } diff --git a/checker/tests/nullness/Issue3888.java b/checker/tests/nullness/Issue3888.java new file mode 100644 index 0000000000..585d3438e5 --- /dev/null +++ b/checker/tests/nullness/Issue3888.java @@ -0,0 +1,18 @@ +import org.checkerframework.checker.nullness.qual.PolyNull; + +abstract class Issue3888 { + + interface L {} + + interface E {} + + public interface F { + Y a(V v); + } + + abstract void f(F f); + + void c(F o) { + f((E vm) -> o.a(vm) == null); + } +} diff --git a/checker/tests/nullness/Issue3929.java b/checker/tests/nullness/Issue3929.java new file mode 100644 index 0000000000..3487897807 --- /dev/null +++ b/checker/tests/nullness/Issue3929.java @@ -0,0 +1,33 @@ +import java.util.ArrayList; +import java.util.List; +import org.checkerframework.checker.nullness.qual.Nullable; + +public class Issue3929 { + + public void endElement(MyClass3929 arg) { + for (Object o : arg.getKeys()) { + o.toString(); + } + } + + public void endElement(NullableMyClass3929 arg) { + for (Object o : arg.getKeys()) { + // :: error: (dereference.of.nullable) + o.toString(); + } + } +} + +class MyClass3929> { + public List getKeys() { + return new ArrayList<>(); + } +} +// TODO: This is a false positive. +// See https://github.com/typetools/checker-framework/issues/2174 +// :: error: (type.argument.type.incompatible) +class NullableMyClass3929> { + public List getKeys() { + return new ArrayList<>(); + } +} diff --git a/checker/tests/nullness/Issue3935.java b/checker/tests/nullness/Issue3935.java new file mode 100644 index 0000000000..a180ae339b --- /dev/null +++ b/checker/tests/nullness/Issue3935.java @@ -0,0 +1,10 @@ +import android.annotation.Nullable; + +public class Issue3935 { + // Note: Nullable is a declaration annotation and applies to the array, not the array element. + private @Nullable byte[] data; + + // Declaration annotations on primitives are ignored, but this should issue + // a nullness.on.primitive error. + @Nullable byte b; +} diff --git a/checker/tests/nullness/Issue4007.java b/checker/tests/nullness/Issue4007.java new file mode 100644 index 0000000000..b8cdb8b118 --- /dev/null +++ b/checker/tests/nullness/Issue4007.java @@ -0,0 +1,34 @@ +// Test case for issue #4007: https://tinyurl.com/cfissue/4007 + +// @skip-test until the issue is fixed + +import java.util.List; +import java.util.Optional; +import org.checkerframework.checker.nullness.qual.NonNull; + +final class Issue4007 { + Optional m1(List list) { + return list.isEmpty() ? Optional.empty() : Optional.of(list.get(0)); + } + + Optional> m2(List list) { + return Optional.of(list.isEmpty() ? Optional.empty() : Optional.of(list.get(0))); + } + + Optional> m3(List list) { + return Optional.of( + list.isEmpty() ? Optional.<@NonNull String>empty() : Optional.of(list.get(0))); + } + + Optional> m4(List list) { + return Optional.of( + list.isEmpty() ? Optional.empty() : Optional.<@NonNull String>of(list.get(0))); + } + + Optional> m5(List list) { + return Optional.of( + list.isEmpty() + ? Optional.<@NonNull String>empty() + : Optional.<@NonNull String>of(list.get(0))); + } +} diff --git a/checker/tests/nullness/Issue408.java b/checker/tests/nullness/Issue408.java index c6d2f358dd..bec43dddbb 100644 --- a/checker/tests/nullness/Issue408.java +++ b/checker/tests/nullness/Issue408.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.initialization.qual.UnderInitialization; -class Issue408 { +public class Issue408 { static class Bar { Bar() { doIssue408(); diff --git a/checker/tests/nullness/Issue411.java b/checker/tests/nullness/Issue411.java index 00af90fe7b..6274162a79 100644 --- a/checker/tests/nullness/Issue411.java +++ b/checker/tests/nullness/Issue411.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.nullness.qual.*; -class Test { +public class Issue411 { @MonotonicNonNull Object field1 = null; final @Nullable Object field2 = null; diff --git a/checker/tests/nullness/Issue414.java b/checker/tests/nullness/Issue414.java index a1cc11e525..e81da888d3 100644 --- a/checker/tests/nullness/Issue414.java +++ b/checker/tests/nullness/Issue414.java @@ -7,7 +7,7 @@ import java.util.Map; import org.checkerframework.checker.nullness.qual.KeyFor; -class Issue414 { +public class Issue414 { void simple(String s) { Map mymap = new HashMap<>(); diff --git a/checker/tests/nullness/Issue419.java b/checker/tests/nullness/Issue419.java index c9b7103daf..46e787ee69 100644 --- a/checker/tests/nullness/Issue419.java +++ b/checker/tests/nullness/Issue419.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.nullness.qual.*; -class Issue419 { +public class Issue419 { @SuppressWarnings("nullness") @NonNull T verifyNotNull(@Nullable T o) { return o; diff --git a/checker/tests/nullness/Issue471.java b/checker/tests/nullness/Issue471.java index e15195662a..7026790f3c 100644 --- a/checker/tests/nullness/Issue471.java +++ b/checker/tests/nullness/Issue471.java @@ -4,7 +4,7 @@ import javax.annotation.Nullable; -class Issue471 { +public class Issue471 { @Nullable T t; Issue471(@Nullable T t) { diff --git a/checker/tests/nullness/Issue563.java b/checker/tests/nullness/Issue563.java index 21811d6d1e..ab48ea41f8 100644 --- a/checker/tests/nullness/Issue563.java +++ b/checker/tests/nullness/Issue563.java @@ -1,6 +1,6 @@ // Test case for Issue 563: // https://github.com/typetools/checker-framework/issues/563 -class Issue563 { +public class Issue563 { void bar() { Object x = null; if (Object.class.isInstance(x)) { diff --git a/checker/tests/nullness/Issue578.java b/checker/tests/nullness/Issue578.java index b4308bdf8d..a80d4af397 100644 --- a/checker/tests/nullness/Issue578.java +++ b/checker/tests/nullness/Issue578.java @@ -1,5 +1,5 @@ // Test case for issue #578: https://github.com/typetools/checker-framework/issues/578 -class Issue578 { +public class Issue578 { void eval(Helper helper, Interface anInterface) { Object o = new SomeGenericClass<>(helper.helperMethod(anInterface)); } diff --git a/checker/tests/nullness/Issue579Error.java b/checker/tests/nullness/Issue579Error.java index 93ce4f61ff..55f6e35b42 100644 --- a/checker/tests/nullness/Issue579Error.java +++ b/checker/tests/nullness/Issue579Error.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; -class Issue579Error { +public class Issue579Error { public void foo(Generic real, Generic other, boolean flag) { // :: error: (type.argument.type.incompatible) diff --git a/checker/tests/nullness/Issue602.java b/checker/tests/nullness/Issue602.java index 26f62cd3db..1e9fcffb35 100644 --- a/checker/tests/nullness/Issue602.java +++ b/checker/tests/nullness/Issue602.java @@ -4,7 +4,7 @@ // Test case for Issue 602 // https://github.com/typetools/checker-framework/issues/602 // @skip-test -class Issue602 { +public class Issue602 { @PolyNull String id(@PolyNull String o) { return o; } diff --git a/checker/tests/nullness/Issue653.java b/checker/tests/nullness/Issue653.java index c68ff7d76b..84ed2694ad 100644 --- a/checker/tests/nullness/Issue653.java +++ b/checker/tests/nullness/Issue653.java @@ -3,7 +3,7 @@ // @skip-test Commented out until the bug is fixed -class Issue653 { +public class Issue653 { public static @PolyNull String[] concat( @PolyNull String @Nullable [] a, @PolyNull String @Nullable [] b) { diff --git a/checker/tests/nullness/Issue67.java b/checker/tests/nullness/Issue67.java index 14f7fcb4a2..38f4e13c57 100644 --- a/checker/tests/nullness/Issue67.java +++ b/checker/tests/nullness/Issue67.java @@ -4,7 +4,7 @@ import java.util.HashMap; import java.util.Map; -class Issue67 { +public class Issue67 { private static final String KEY = "key"; private static final String KEY2 = "key2"; diff --git a/checker/tests/nullness/Issue752.java b/checker/tests/nullness/Issue752.java index e43ffaf5d6..c78cdb06ca 100644 --- a/checker/tests/nullness/Issue752.java +++ b/checker/tests/nullness/Issue752.java @@ -15,7 +15,7 @@ static Issue752 staticMethod() { return staticField; } - // A package name without a class name is not a valid flow expression string. + // A package name without a class name is not a valid JavaExpression string. @RequiresNonNull("java.lang") // :: error: (flowexpr.parse.error) void method1() {} @@ -23,7 +23,7 @@ void method1() {} @RequiresNonNull("java.lang.String.class") void method2() {} - // A package name without a class name is not a valid flow expression string. + // A package name without a class name is not a valid JavaExpression string. @RequiresNonNull("a.b.c") // :: error: (flowexpr.parse.error) void method3() {} diff --git a/checker/tests/nullness/Issue765.java b/checker/tests/nullness/Issue765.java index a4f119e4b4..ae47273e0c 100644 --- a/checker/tests/nullness/Issue765.java +++ b/checker/tests/nullness/Issue765.java @@ -1,6 +1,6 @@ // Test case for Issue 765 // https://github.com/typetools/checker-framework/issues/765 -class Issue765 { +public class Issue765 { Thread thread = new Thread() {}; void execute() { diff --git a/checker/tests/nullness/JPanelTest.java b/checker/tests/nullness/JPanelTest.java index b2af926203..1ffe2dbdde 100644 --- a/checker/tests/nullness/JPanelTest.java +++ b/checker/tests/nullness/JPanelTest.java @@ -1,3 +1,3 @@ // Minimal test case for Issue #244 // https://github.com/typetools/checker-framework/issues/244 -class JPanelTest extends javax.swing.JPanel {} +public class JPanelTest extends javax.swing.JPanel {} diff --git a/checker/tests/nullness/JavaCopExplosion.java b/checker/tests/nullness/JavaCopExplosion.java index 293b6d7306..0ce3563c0b 100644 --- a/checker/tests/nullness/JavaCopExplosion.java +++ b/checker/tests/nullness/JavaCopExplosion.java @@ -2,13 +2,13 @@ import org.checkerframework.checker.nullness.qual.*; @org.checkerframework.framework.qual.DefaultQualifier(Nullable.class) -class Explosion { +public class JavaCopExplosion { public static class ExplosiveException extends Exception {} @NonNull Integer m_nni = 1; final String m_astring; - Explosion() { + JavaCopExplosion() { // m_nni = 1;\ m_astring = "hi"; try { diff --git a/checker/tests/nullness/JavaCopFlow.java b/checker/tests/nullness/JavaCopFlow.java index 8a8f3c06f6..959848862e 100644 --- a/checker/tests/nullness/JavaCopFlow.java +++ b/checker/tests/nullness/JavaCopFlow.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.nullness.qual.*; @org.checkerframework.framework.qual.DefaultQualifier(Nullable.class) -class JavaCopFlow { +public class JavaCopFlow { public void testIf(String str) { diff --git a/checker/tests/nullness/JavaCopRandomTests.java b/checker/tests/nullness/JavaCopRandomTests.java index bb3ba313e2..8ecde2bdf5 100644 --- a/checker/tests/nullness/JavaCopRandomTests.java +++ b/checker/tests/nullness/JavaCopRandomTests.java @@ -1,16 +1,16 @@ import org.checkerframework.checker.nullness.qual.*; -class RandomTests { +public class JavaCopRandomTests { final int a; final int b = 1; final int c; - RandomTests() { + JavaCopRandomTests() { String s = null; a = 2; } - RandomTests(String s) throws Exception { + JavaCopRandomTests(String s) throws Exception { // this(); a = 2; if (a > 1) { diff --git a/checker/tests/nullness/KeyForIssue328.java b/checker/tests/nullness/KeyForIssue328.java index 0bbcfe1b9d..0ed3737400 100644 --- a/checker/tests/nullness/KeyForIssue328.java +++ b/checker/tests/nullness/KeyForIssue328.java @@ -4,7 +4,7 @@ import java.util.Map; import org.checkerframework.checker.nullness.qual.*; -class KeyForIssue328 { +public class KeyForIssue328 { public static void m(Map a, Map b, Object ka, Object kb) { if (a.containsKey(ka)) { @NonNull Object i = a.get(ka); // OK diff --git a/checker/tests/nullness/KeyForLocalVariable.java b/checker/tests/nullness/KeyForLocalVariable.java index 038324fc81..0340068615 100644 --- a/checker/tests/nullness/KeyForLocalVariable.java +++ b/checker/tests/nullness/KeyForLocalVariable.java @@ -5,7 +5,7 @@ import java.util.Map; import org.checkerframework.checker.nullness.qual.*; -class KeyForLocalVariable { +public class KeyForLocalVariable { public static void localVariableShadowing() { // :: error: (expression.unparsable.type.invalid) diff --git a/checker/tests/nullness/KeyForPolymorphism.java b/checker/tests/nullness/KeyForPolymorphism.java index 7a6bd52dcd..ab3a02f7fc 100644 --- a/checker/tests/nullness/KeyForPolymorphism.java +++ b/checker/tests/nullness/KeyForPolymorphism.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.nullness.qual.*; // test related to issue 429: https://github.com/typetools/checker-framework/issues/429 -class KeyForPolymorphism { +public class KeyForPolymorphism { Map m1 = new HashMap<>(); Map m2 = new HashMap<>(); diff --git a/checker/tests/nullness/KeyForPostcondition.java b/checker/tests/nullness/KeyForPostcondition.java index 3e39b9f091..5f258177ce 100644 --- a/checker/tests/nullness/KeyForPostcondition.java +++ b/checker/tests/nullness/KeyForPostcondition.java @@ -4,7 +4,7 @@ import org.checkerframework.checker.nullness.qual.EnsuresKeyForIf; import org.checkerframework.checker.nullness.qual.KeyFor; -class KeyForPostcondition { +public class KeyForPostcondition { public static Map m = new HashMap<>(); diff --git a/checker/tests/nullness/KeyForPropagation.java b/checker/tests/nullness/KeyForPropagation.java index 0c97ab5cc8..8b326f2208 100644 --- a/checker/tests/nullness/KeyForPropagation.java +++ b/checker/tests/nullness/KeyForPropagation.java @@ -13,7 +13,7 @@ // // class Source extends HashMap implements Inter2 {} -class KeyForPropagation { +public class KeyForPropagation { { List<@KeyFor("a") String> a = new ArrayList(); diff --git a/checker/tests/nullness/KeyForShadowing.java b/checker/tests/nullness/KeyForShadowing.java index 4850970f42..5233f7a300 100644 --- a/checker/tests/nullness/KeyForShadowing.java +++ b/checker/tests/nullness/KeyForShadowing.java @@ -5,7 +5,7 @@ import java.util.Map; import org.checkerframework.checker.nullness.qual.*; -class KeyForShadowing { +public class KeyForShadowing { public static void main(String... p) { Map m0 = new HashMap<>(); Map m1 = new HashMap<>(); diff --git a/checker/tests/nullness/KeyForStaticField.java b/checker/tests/nullness/KeyForStaticField.java index 3e52448545..5973fe7489 100644 --- a/checker/tests/nullness/KeyForStaticField.java +++ b/checker/tests/nullness/KeyForStaticField.java @@ -6,7 +6,7 @@ import java.util.Map; import org.checkerframework.checker.nullness.qual.*; -class KeyForStaticField { +public class KeyForStaticField { @SuppressWarnings("keyfor") public static final @KeyFor("this.map") String STATIC_KEY = "some text"; diff --git a/checker/tests/nullness/LogicOperations.java b/checker/tests/nullness/LogicOperations.java index 782255e637..3333958daf 100644 --- a/checker/tests/nullness/LogicOperations.java +++ b/checker/tests/nullness/LogicOperations.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.nullness.qual.*; import org.checkerframework.checker.nullness.qual.NonNull; -class LogicOperations { +public class LogicOperations { void andTrueClause(@Nullable Object a) { if (a != null && helper()) { a.toString(); diff --git a/checker/tests/nullness/LubTest.java b/checker/tests/nullness/LubTest.java index 9fc06cb4ac..b5e1ad2df9 100644 --- a/checker/tests/nullness/LubTest.java +++ b/checker/tests/nullness/LubTest.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class LubTest { +public class LubTest { @Nullable String str; diff --git a/checker/tests/nullness/MapMerge.java b/checker/tests/nullness/MapMerge.java index b23d9bc1aa..24922889f3 100644 --- a/checker/tests/nullness/MapMerge.java +++ b/checker/tests/nullness/MapMerge.java @@ -2,7 +2,7 @@ import java.util.Map; import java.util.function.BiFunction; -class MapMerge { +public class MapMerge { public static void main(String[] args) { Map map = new HashMap<>(); map.put("k", "v"); diff --git a/checker/tests/nullness/MethodInvocation.java b/checker/tests/nullness/MethodInvocation.java index edfaae535d..5625f95e9c 100644 --- a/checker/tests/nullness/MethodInvocation.java +++ b/checker/tests/nullness/MethodInvocation.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.initialization.qual.*; import org.checkerframework.checker.nullness.qual.*; -class MethodInvocation { +public class MethodInvocation { String s; diff --git a/checker/tests/nullness/MethodTypeVars4.java b/checker/tests/nullness/MethodTypeVars4.java index 1278cf2809..bc9e14d8e1 100644 --- a/checker/tests/nullness/MethodTypeVars4.java +++ b/checker/tests/nullness/MethodTypeVars4.java @@ -3,7 +3,7 @@ import org.checkerframework.framework.qual.DefaultQualifier; import org.checkerframework.framework.qual.TypeUseLocation; -class MethodTypeVars4 { +public class MethodTypeVars4 { @DefaultQualifier(value = NonNull.class, locations = TypeUseLocation.IMPLICIT_UPPER_BOUND) interface I { T doit(); diff --git a/checker/tests/nullness/MultiConstructorInit.java b/checker/tests/nullness/MultiConstructorInit.java index 512a4e1192..782a476533 100644 --- a/checker/tests/nullness/MultiConstructorInit.java +++ b/checker/tests/nullness/MultiConstructorInit.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.initialization.qual.*; import org.checkerframework.checker.nullness.qual.*; -class MultiConstructorInit { +public class MultiConstructorInit { String a; diff --git a/checker/tests/nullness/NNOEMoreTests.java b/checker/tests/nullness/NNOEMoreTests.java index 0a7e69062c..0e8cb3f7f8 100644 --- a/checker/tests/nullness/NNOEMoreTests.java +++ b/checker/tests/nullness/NNOEMoreTests.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.nullness.qual.*; import org.checkerframework.checker.nullness.qual.RequiresNonNull; -class NNOEMoreTests { +public class NNOEMoreTests { class NNOEMain { protected @Nullable String nullable = null; @Nullable String otherNullable = null; diff --git a/checker/tests/nullness/NNOEStaticFields.java b/checker/tests/nullness/NNOEStaticFields.java index f6625d5d30..d79b28c933 100644 --- a/checker/tests/nullness/NNOEStaticFields.java +++ b/checker/tests/nullness/NNOEStaticFields.java @@ -4,7 +4,7 @@ import org.checkerframework.checker.nullness.qual.*; import org.checkerframework.checker.nullness.qual.RequiresNonNull; -class NNOEStaticFields { +public class NNOEStaticFields { static @Nullable String nullable = null; static @Nullable String otherNullable = null; diff --git a/checker/tests/nullness/NegatingConditionalNullness.java b/checker/tests/nullness/NegatingConditionalNullness.java index a9450ec184..5bd46673d6 100644 --- a/checker/tests/nullness/NegatingConditionalNullness.java +++ b/checker/tests/nullness/NegatingConditionalNullness.java @@ -2,8 +2,7 @@ import org.checkerframework.checker.nullness.qual.*; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; -class PptTopLevel { - /** List of all of the splitters for this ppt. */ +public class NegatingConditionalNullness { public @MonotonicNonNull List splitters = null; @EnsuresNonNullIf(result = true, expression = "splitters") @@ -11,37 +10,37 @@ public boolean has_splitters() { return (splitters != null); } - static void testPptTopLevel(PptTopLevel ppt) { + static void test(NegatingConditionalNullness ppt) { if (!ppt.has_splitters()) { return; } @NonNull Object s2 = ppt.splitters; } - static void testPptTopLevelAssert(PptTopLevel ppt) { + static void testAssert(NegatingConditionalNullness ppt) { assert ppt.has_splitters() : "@AssumeAssertion(nullness)"; @NonNull Object s2 = ppt.splitters; } - static void testSimple(PptTopLevel ppt) { + static void testSimple(NegatingConditionalNullness ppt) { if (ppt.has_splitters()) { @NonNull Object s2 = ppt.splitters; } } // False tests - static void testFalse(PptTopLevel ppt) { + static void testFalse(NegatingConditionalNullness ppt) { // :: error: (dereference.of.nullable) ppt.splitters.toString(); // error } - static void testFalseNoAssertion(PptTopLevel ppt) { + static void testFalseNoAssertion(NegatingConditionalNullness ppt) { ppt.has_splitters(); // :: error: (dereference.of.nullable) ppt.splitters.toString(); // error } - static void testFalseIf(PptTopLevel ppt) { + static void testFalseIf(NegatingConditionalNullness ppt) { if (ppt.has_splitters()) { return; } @@ -49,7 +48,7 @@ static void testFalseIf(PptTopLevel ppt) { ppt.splitters.toString(); // error } - // static void testFalseIfBody(PptTopLevel ppt) { + // static void testFalseIfBody(NegatingConditionalNullness ppt) { // if (!ppt.has_splitters()) { // // :: error: (dereference.of.nullable) // ppt.splitters.toString(); // error diff --git a/checker/tests/nullness/NewNullable.java b/checker/tests/nullness/NewNullable.java index 9c8fc0f35e..860ed8ad8a 100644 --- a/checker/tests/nullness/NewNullable.java +++ b/checker/tests/nullness/NewNullable.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class NewNullable { +public class NewNullable { Object o = new Object(); Object nn = new @NonNull Object(); // :: warning: (new.class.type.invalid) diff --git a/checker/tests/nullness/NewObjectNonNull.java b/checker/tests/nullness/NewObjectNonNull.java index d31c7c062d..5f865bf81e 100644 --- a/checker/tests/nullness/NewObjectNonNull.java +++ b/checker/tests/nullness/NewObjectNonNull.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.nullness.qual.*; import org.checkerframework.framework.qual.DefaultQualifier; -class NewObjectNonNull { +public class NewObjectNonNull { @DefaultQualifier(Nullable.class) class A { A() {} diff --git a/checker/tests/nullness/NonNullIteratorNext.java b/checker/tests/nullness/NonNullIteratorNext.java index bdec6ec915..7930447d4d 100644 --- a/checker/tests/nullness/NonNullIteratorNext.java +++ b/checker/tests/nullness/NonNullIteratorNext.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.NonNull; -class NonNullIteratorNext { +public class NonNullIteratorNext { interface MyIterator extends java.util.Iterator { @NonNull E next(); } diff --git a/checker/tests/nullness/NullableArrays.java b/checker/tests/nullness/NullableArrays.java index 4eea1c0e10..5a9cc220d2 100644 --- a/checker/tests/nullness/NullableArrays.java +++ b/checker/tests/nullness/NullableArrays.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class NullableArrays { +public class NullableArrays { private byte @Nullable [] padding; public NullableArrays(byte @Nullable [] padding) { diff --git a/checker/tests/nullness/ObjectsRequireNonNull.java b/checker/tests/nullness/ObjectsRequireNonNull.java index 3d84d4b04d..b7448a7e42 100644 --- a/checker/tests/nullness/ObjectsRequireNonNull.java +++ b/checker/tests/nullness/ObjectsRequireNonNull.java @@ -4,7 +4,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -class ObjectsRequireNonNull { +public class ObjectsRequireNonNull { void foo(@Nullable Object nble, @NonNull Object nn) { // :: error: (argument.type.incompatible) Objects.requireNonNull(null); diff --git a/checker/tests/nullness/ObjectsRequireNonNullElse.java b/checker/tests/nullness/ObjectsRequireNonNullElse.java index cc3e652783..90d1c24c18 100644 --- a/checker/tests/nullness/ObjectsRequireNonNullElse.java +++ b/checker/tests/nullness/ObjectsRequireNonNullElse.java @@ -6,7 +6,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; -class ObjectsRequireNonNullElse { +public class ObjectsRequireNonNullElse { public static void main(String[] args) { @NonNull String value = requireNonNullElse(null, "Something"); System.err.println(requireNonNullElse(null, "Something")); diff --git a/checker/tests/nullness/OverrideANNA.java b/checker/tests/nullness/OverrideANNA.java index 1b40406d2a..1cc7cba6e5 100644 --- a/checker/tests/nullness/OverrideANNA.java +++ b/checker/tests/nullness/OverrideANNA.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.initialization.qual.*; import org.checkerframework.checker.nullness.qual.*; -class OverrideANNA { +public class OverrideANNA { static class Super { Object f; diff --git a/checker/tests/nullness/OverrideANNA2.java b/checker/tests/nullness/OverrideANNA2.java index ecdff3d503..90f3782358 100644 --- a/checker/tests/nullness/OverrideANNA2.java +++ b/checker/tests/nullness/OverrideANNA2.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.initialization.qual.*; import org.checkerframework.checker.nullness.qual.*; -class OverrideANNA2 { +public class OverrideANNA2 { static class Super { Object f; diff --git a/checker/tests/nullness/OverrideANNA3.java b/checker/tests/nullness/OverrideANNA3.java index 8b972c70e8..98f38ca0ea 100644 --- a/checker/tests/nullness/OverrideANNA3.java +++ b/checker/tests/nullness/OverrideANNA3.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.initialization.qual.UnknownInitialization; import org.checkerframework.checker.nullness.qual.EnsuresNonNull; -class OverrideANNA3 { +public class OverrideANNA3 { static class Super { Object f; Object g; diff --git a/checker/tests/nullness/OverrideNNOE.java b/checker/tests/nullness/OverrideNNOE.java index 82b878101c..dd96eea0cd 100644 --- a/checker/tests/nullness/OverrideNNOE.java +++ b/checker/tests/nullness/OverrideNNOE.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.nullness.qual.*; import org.checkerframework.checker.nullness.qual.RequiresNonNull; -class OverrideNNOE { +public class OverrideNNOE { static class Super { @Nullable Object f; diff --git a/checker/tests/nullness/OverrideNNOE2.java b/checker/tests/nullness/OverrideNNOE2.java index 6fdf67f6a9..7f98f00396 100644 --- a/checker/tests/nullness/OverrideNNOE2.java +++ b/checker/tests/nullness/OverrideNNOE2.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.nullness.qual.*; import org.checkerframework.checker.nullness.qual.RequiresNonNull; -class OverrideNNOE2 { +public class OverrideNNOE2 { static class Super { @Nullable Object f; diff --git a/checker/tests/nullness/PackageDecl.java b/checker/tests/nullness/PackageDecl.java index 532b010500..1e299befe5 100644 --- a/checker/tests/nullness/PackageDecl.java +++ b/checker/tests/nullness/PackageDecl.java @@ -2,4 +2,4 @@ import org.checkerframework.checker.nullness.qual.*; -class PackageDecl {} +public class PackageDecl {} diff --git a/checker/tests/nullness/PureTest.java b/checker/tests/nullness/PureTest.java index e9dead4f34..bcad3f3d37 100644 --- a/checker/tests/nullness/PureTest.java +++ b/checker/tests/nullness/PureTest.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.nullness.qual.*; import org.checkerframework.dataflow.qual.*; -class PureTest { +public class PureTest { @org.checkerframework.dataflow.qual.Pure @Nullable Object puremethod(@Nullable Object a) { return a; diff --git a/checker/tests/nullness/Raw2.java b/checker/tests/nullness/Raw2.java index 7c7fef3cfb..3210c84bf2 100644 --- a/checker/tests/nullness/Raw2.java +++ b/checker/tests/nullness/Raw2.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.initialization.qual.UnknownInitialization; import org.checkerframework.checker.nullness.qual.*; -class Raw2 { +public class Raw2 { private @NonNull Object field; // :: error: (initialization.fields.uninitialized) public Raw2(int i) { diff --git a/checker/tests/nullness/RawAndPrimitive.java b/checker/tests/nullness/RawAndPrimitive.java index 5377fd8e67..2d50290f8b 100644 --- a/checker/tests/nullness/RawAndPrimitive.java +++ b/checker/tests/nullness/RawAndPrimitive.java @@ -1,4 +1,4 @@ -class RawAndPrimitive { +public class RawAndPrimitive { public T foo(T startValue) { return startValue; } diff --git a/checker/tests/nullness/RawMethodInvocation.java b/checker/tests/nullness/RawMethodInvocation.java index cb0e5e7b32..761d16893d 100644 --- a/checker/tests/nullness/RawMethodInvocation.java +++ b/checker/tests/nullness/RawMethodInvocation.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNull; @org.checkerframework.framework.qual.DefaultQualifier(Nullable.class) -class RawMethodInvocation { +public class RawMethodInvocation { Object a; Object b; diff --git a/checker/tests/nullness/RawSuper.java b/checker/tests/nullness/RawSuper.java index 0c2bc3fac0..c4f0073422 100644 --- a/checker/tests/nullness/RawSuper.java +++ b/checker/tests/nullness/RawSuper.java @@ -3,7 +3,7 @@ // @skip-test // This test is broken as it uses multiple classes. Javac halts // when seeing the first error -class RawSuper { +public class RawSuper { class A { @NonNull Object afield; diff --git a/checker/tests/nullness/RawTypesBounded.java b/checker/tests/nullness/RawTypesBounded.java index af5e4793a4..1edb3c1f12 100644 --- a/checker/tests/nullness/RawTypesBounded.java +++ b/checker/tests/nullness/RawTypesBounded.java @@ -4,7 +4,7 @@ import org.checkerframework.checker.nullness.qual.*; @org.checkerframework.framework.qual.DefaultQualifier(Nullable.class) -class RawTypesBounded { +public class RawTypesBounded { class Bad { @NonNull String field; diff --git a/checker/tests/nullness/ReadyReadLine.java b/checker/tests/nullness/ReadyReadLine.java index cbb2f5e244..de26b07c23 100644 --- a/checker/tests/nullness/ReadyReadLine.java +++ b/checker/tests/nullness/ReadyReadLine.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; -class ReadyReadLine { +public class ReadyReadLine { void m(MyBufferedReader buf) throws Exception { if (buf.ready()) { diff --git a/checker/tests/nullness/RefineArray.java b/checker/tests/nullness/RefineArray.java index 9d302b2525..a9e34be7b1 100644 --- a/checker/tests/nullness/RefineArray.java +++ b/checker/tests/nullness/RefineArray.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.nullness.qual.*; // TODO: Add as test -class RefineArray { +public class RefineArray { public static T[] concat(T @Nullable [] a, T @Nullable [] b) { if (a == null) { if (b != null) { diff --git a/checker/tests/nullness/RequiresNonNullTest.java b/checker/tests/nullness/RequiresNonNullTest.java index bc49bda530..132ca4de8b 100644 --- a/checker/tests/nullness/RequiresNonNullTest.java +++ b/checker/tests/nullness/RequiresNonNullTest.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.nullness.qual.*; import org.checkerframework.dataflow.qual.Pure; -class RequiresNonNullTest { +public class RequiresNonNullTest { @Nullable Object field1; @Nullable Object field2; diff --git a/checker/tests/nullness/ScopingConstruct.java b/checker/tests/nullness/ScopingConstruct.java index a5978188bb..1b07f4e714 100644 --- a/checker/tests/nullness/ScopingConstruct.java +++ b/checker/tests/nullness/ScopingConstruct.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; @SuppressWarnings("initialization.fields.uninitialized") -class ScopingConstruct { +public class ScopingConstruct { // TODO: add nested classes within these two? static class StaticNested implements AutoCloseable { diff --git a/checker/tests/nullness/SelfAssignment.java b/checker/tests/nullness/SelfAssignment.java index 434115bb73..3fb4a63cee 100644 --- a/checker/tests/nullness/SelfAssignment.java +++ b/checker/tests/nullness/SelfAssignment.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNull; import org.checkerframework.checker.nullness.qual.Nullable; -class SelfAssignment { +public class SelfAssignment { void test(@Nullable String s) { assertNonNull(s); diff --git a/checker/tests/nullness/StaticInitializer.java b/checker/tests/nullness/StaticInitializer.java index f5b65f9555..95ea293902 100644 --- a/checker/tests/nullness/StaticInitializer.java +++ b/checker/tests/nullness/StaticInitializer.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.nullness.qual.*; // :: error: (initialization.static.fields.uninitialized) -class StaticInitializer { +public class StaticInitializer { public static String a; public static String b; diff --git a/checker/tests/nullness/StaticInitializer2.java b/checker/tests/nullness/StaticInitializer2.java index e123aa95a3..dfcf577ba6 100644 --- a/checker/tests/nullness/StaticInitializer2.java +++ b/checker/tests/nullness/StaticInitializer2.java @@ -8,7 +8,7 @@ import org.checkerframework.checker.initialization.qual.*; import org.checkerframework.checker.nullness.qual.*; -class StaticInitializer2 { +public class StaticInitializer2 { static String a; diff --git a/checker/tests/nullness/SuperConstructorInit.java b/checker/tests/nullness/SuperConstructorInit.java index 762d0a7489..50a97937b5 100644 --- a/checker/tests/nullness/SuperConstructorInit.java +++ b/checker/tests/nullness/SuperConstructorInit.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class SuperConstructorInit { +public class SuperConstructorInit { String a; diff --git a/checker/tests/nullness/SuppressDeprecation.java b/checker/tests/nullness/SuppressDeprecation.java index 6768981f16..97b88c300b 100644 --- a/checker/tests/nullness/SuppressDeprecation.java +++ b/checker/tests/nullness/SuppressDeprecation.java @@ -5,7 +5,7 @@ class SuppressDeprecationOther { void old() {} } -class SuppressDeprecation { +public class SuppressDeprecation { @MonotonicNonNull String tz1; diff --git a/checker/tests/nullness/SuppressWarningsTest.java b/checker/tests/nullness/SuppressWarningsTest.java index bde8b14494..8a64666a13 100644 --- a/checker/tests/nullness/SuppressWarningsTest.java +++ b/checker/tests/nullness/SuppressWarningsTest.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class SuppressWarningsTest { +public class SuppressWarningsTest { @SuppressWarnings("all") void test() { diff --git a/checker/tests/nullness/TernaryNested.java b/checker/tests/nullness/TernaryNested.java index 330a8601e9..b53d85a305 100644 --- a/checker/tests/nullness/TernaryNested.java +++ b/checker/tests/nullness/TernaryNested.java @@ -5,7 +5,7 @@ import org.checkerframework.checker.initialization.qual.*; import org.checkerframework.checker.nullness.qual.*; -class TernaryNested { +public class TernaryNested { Object foo(boolean b) { Object o = b ? "" : (b ? "" : ""); return o; diff --git a/checker/tests/nullness/TestInfer.java b/checker/tests/nullness/TestInfer.java index edbc9fb214..69284365b4 100644 --- a/checker/tests/nullness/TestInfer.java +++ b/checker/tests/nullness/TestInfer.java @@ -4,7 +4,7 @@ import java.util.List; import org.checkerframework.checker.nullness.qual.UnknownKeyFor; -class TestInfer { +public class TestInfer { T getValue(List l) { return l.get(0); } diff --git a/checker/tests/nullness/TestPolyNull.java b/checker/tests/nullness/TestPolyNull.java index 364fa78702..452205b026 100644 --- a/checker/tests/nullness/TestPolyNull.java +++ b/checker/tests/nullness/TestPolyNull.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class TestPolyNull { +public class TestPolyNull { @PolyNull String identity(@PolyNull String str) { return str; } diff --git a/checker/tests/nullness/TestValOf.java b/checker/tests/nullness/TestValOf.java index a0acb4b54c..31952742d6 100644 --- a/checker/tests/nullness/TestValOf.java +++ b/checker/tests/nullness/TestValOf.java @@ -1,6 +1,6 @@ // Test case for issue #243: https://github.com/typetools/checker-framework/issues/243 -class TestValOf> { +public class TestValOf> { private final Class enumClass; diff --git a/checker/tests/nullness/ThisIsNN.java b/checker/tests/nullness/ThisIsNN.java index 41e8147625..139e94ad59 100644 --- a/checker/tests/nullness/ThisIsNN.java +++ b/checker/tests/nullness/ThisIsNN.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class ThisIsNN { +public class ThisIsNN { Object out = new Object(); class Inner { diff --git a/checker/tests/nullness/ThisLiteralQualified.java b/checker/tests/nullness/ThisLiteralQualified.java deleted file mode 100644 index c2b39bb16e..0000000000 --- a/checker/tests/nullness/ThisLiteralQualified.java +++ /dev/null @@ -1,12 +0,0 @@ -// Test case for Issue #2208: -// https://github.com/typetools/checker-framework/issues/2208 - -import org.checkerframework.checker.initialization.qual.UnderInitialization; - -public class ThisLiteralQualified { - public ThisLiteralQualified() { - super(); - @UnderInitialization ThisLiteralQualified a = this; - @UnderInitialization ThisLiteralQualified b = ThisLiteralQualified.this; - } -} diff --git a/checker/tests/nullness/ThisLiteral.java b/checker/tests/nullness/ThisNodeTest.java similarity index 63% rename from checker/tests/nullness/ThisLiteral.java rename to checker/tests/nullness/ThisNodeTest.java index ac7140f7ca..1bb39b1397 100644 --- a/checker/tests/nullness/ThisLiteral.java +++ b/checker/tests/nullness/ThisNodeTest.java @@ -1,16 +1,16 @@ import org.checkerframework.checker.initialization.qual.*; import org.checkerframework.checker.nullness.qual.*; -public class ThisLiteral { - public ThisLiteral() { +public class ThisNodeTest { + public ThisNodeTest() { new Object() { void test() { - @UnderInitialization ThisLiteral l1 = ThisLiteral.this; + @UnderInitialization ThisNodeTest l1 = ThisNodeTest.this; // :: error: (assignment.type.incompatible) - @Initialized ThisLiteral l2 = ThisLiteral.this; + @Initialized ThisNodeTest l2 = ThisNodeTest.this; // :: error: (method.invocation.invalid) - ThisLiteral.this.foo(); + ThisNodeTest.this.foo(); // :: error: (method.invocation.invalid) foo(); } diff --git a/checker/tests/nullness/ThisQualified.java b/checker/tests/nullness/ThisQualified.java new file mode 100644 index 0000000000..87c8f07efd --- /dev/null +++ b/checker/tests/nullness/ThisQualified.java @@ -0,0 +1,12 @@ +// Test case for Issue #2208: +// https://github.com/typetools/checker-framework/issues/2208 + +import org.checkerframework.checker.initialization.qual.UnderInitialization; + +public class ThisQualified { + public ThisQualified() { + super(); + @UnderInitialization ThisQualified a = this; + @UnderInitialization ThisQualified b = ThisQualified.this; + } +} diff --git a/checker/tests/nullness/ThisTest.java b/checker/tests/nullness/ThisTest.java index db17807083..3c33ff0267 100644 --- a/checker/tests/nullness/ThisTest.java +++ b/checker/tests/nullness/ThisTest.java @@ -2,7 +2,7 @@ @org.checkerframework.framework.qual.DefaultQualifier( org.checkerframework.checker.nullness.qual.NonNull.class) -class ThisTest { +public class ThisTest { public String field; diff --git a/checker/tests/nullness/ToArrayDiagnostics.java b/checker/tests/nullness/ToArrayDiagnostics.java index c9d8de5758..174e51ee0e 100644 --- a/checker/tests/nullness/ToArrayDiagnostics.java +++ b/checker/tests/nullness/ToArrayDiagnostics.java @@ -17,14 +17,14 @@ String[] ok4(ArrayList list) { String[] warn1(ArrayList list) { // :: error: (new.array.type.invalid) String[] resultArray = new String[list.size()]; - // :: error: (return.type.incompatible) :: warning: (toArray.nullable.elements.not.newarray) + // :: error: (return.type.incompatible) :: warning: (toarray.nullable.elements.not.newarray) return list.toArray(resultArray); } String[] warn2(ArrayList list) { int size = list.size(); // :: error: (new.array.type.invalid) :: error: (return.type.incompatible) :: warning: - // (toArray.nullable.elements.mismatched.size) + // (toarray.nullable.elements.mismatched.size) return list.toArray(new String[size]); } } diff --git a/checker/tests/nullness/ToArrayNullness.java b/checker/tests/nullness/ToArrayNullness.java index 5f17d107df..9912ccc68e 100644 --- a/checker/tests/nullness/ToArrayNullness.java +++ b/checker/tests/nullness/ToArrayNullness.java @@ -72,36 +72,36 @@ void testHearusitics() { for (@Nullable String o : nonnullCol.toArray(new String[nonnullCol.size()])) ; for (@NonNull String o : nonnullCol.toArray(new String[nonnullCol.size()])) ; - // :: warning: (toArray.nullable.elements.mismatched.size) + // :: warning: (toarray.nullable.elements.mismatched.size) for (@Nullable String o : nonnullCol.toArray(new @Nullable String[] {null})) ; // :: error: (enhancedfor.type.incompatible) :: warning: - // (toArray.nullable.elements.mismatched.size) + // (toarray.nullable.elements.mismatched.size) for (@NonNull String o : nonnullCol.toArray(new @Nullable String[] {null})) ; // error // Size 1 is too big for an empty array. Complain. TODO: Could allow as result is Nullable. // :: error: (new.array.type.invalid) :: warning: - // (toArray.nullable.elements.mismatched.size) + // (toarray.nullable.elements.mismatched.size) for (@Nullable String o : nonnullCol.toArray(new String[1])) ; // :: error: (enhancedfor.type.incompatible) :: error: (new.array.type.invalid) :: warning: - // (toArray.nullable.elements.mismatched.size) + // (toarray.nullable.elements.mismatched.size) for (@NonNull String o : nonnullCol.toArray(new String[1])) ; // error // Array too big -> complain. TODO: Could allow as result is Nullable. // :: error: (new.array.type.invalid) :: warning: - // (toArray.nullable.elements.mismatched.size) + // (toarray.nullable.elements.mismatched.size) for (@Nullable String o : nonnullCol.toArray(new String[nonnullCol.size() + 1])) ; // Array too big -> complain. // :: error: (enhancedfor.type.incompatible) :: error: (new.array.type.invalid) :: warning: - // (toArray.nullable.elements.mismatched.size) + // (toarray.nullable.elements.mismatched.size) for (@NonNull String o : nonnullCol.toArray(new String[nonnullCol.size() + 1])) ; // error // cannot handle the following cases for now // new array not size 0 or .size -> complain about cration. TODO: Could allow as result is // Nullable. // :: error: (new.array.type.invalid) :: warning: - // (toArray.nullable.elements.mismatched.size) + // (toarray.nullable.elements.mismatched.size) for (@Nullable String o : nonnullCol.toArray(new String[nonnullCol.size() - 1])) ; // New array not size 0 or .size -> complain about creation. // :: error: (enhancedfor.type.incompatible) :: error: (new.array.type.invalid) :: warning: - // (toArray.nullable.elements.mismatched.size) + // (toarray.nullable.elements.mismatched.size) for (@NonNull String o : nonnullCol.toArray(new String[nonnullCol.size() - 1])) ; // error } } diff --git a/checker/tests/nullness/TryCatch.java b/checker/tests/nullness/TryCatch.java index edaae1ca18..20f0611c82 100644 --- a/checker/tests/nullness/TryCatch.java +++ b/checker/tests/nullness/TryCatch.java @@ -7,7 +7,7 @@ class EntryReader { public EntryReader() throws IOException {} } -class TryCatch { +public class TryCatch { void constructorException() throws IOException { List file_errors = new ArrayList<>(); try { diff --git a/checker/tests/nullness/TryWithResources.java b/checker/tests/nullness/TryWithResources.java index 7b755c1d5d..505d342fae 100644 --- a/checker/tests/nullness/TryWithResources.java +++ b/checker/tests/nullness/TryWithResources.java @@ -1,6 +1,8 @@ import java.io.*; +import java.util.zip.ZipFile; +import org.checkerframework.checker.nullness.qual.Nullable; -class TryWithResources { +public class TryWithResources { void m1(InputStream stream) { try (BufferedReader in = new BufferedReader(new InputStreamReader(stream))) { in.toString(); @@ -15,4 +17,29 @@ void m2() { } catch (Exception e) { } } + + // Check that catch blocks and code after try-catch are part of CFG (and flow-sensitive + // type-refinements work there). + boolean m3(@Nullable Object x) { + try (ZipFile f = openZipFile()) { + return true; + } catch (IOException e) { + if (x != null) { + // OK + x.toString(); + } + } + + if (x != null) { + // OK + return x.equals(x); + } + + return false; + } + + // Helper + private static ZipFile openZipFile() throws IOException { + throw new IOException("No zip-file for you!"); + } } diff --git a/checker/tests/nullness/TwoStaticInitBlocks.java b/checker/tests/nullness/TwoStaticInitBlocks.java index dd5d865fb3..1887384646 100644 --- a/checker/tests/nullness/TwoStaticInitBlocks.java +++ b/checker/tests/nullness/TwoStaticInitBlocks.java @@ -2,7 +2,7 @@ // this is a test-case for initialization that covers multiple initializer blocks, field // initializers and a few other things -class TwoStaticInitBlocks { +public class TwoStaticInitBlocks { String f2; String f1 = (f2 = ""); diff --git a/checker/tests/nullness/UnannoPrimitives.java b/checker/tests/nullness/UnannoPrimitives.java index 9500474b5e..4e70f9ae07 100644 --- a/checker/tests/nullness/UnannoPrimitives.java +++ b/checker/tests/nullness/UnannoPrimitives.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class UnannoPrimitives { +public class UnannoPrimitives { // :: error: (nullness.on.primitive) @Nullable int f; diff --git a/checker/tests/nullness/Unboxing.java b/checker/tests/nullness/Unboxing.java index e61161f109..3a8c762a04 100644 --- a/checker/tests/nullness/Unboxing.java +++ b/checker/tests/nullness/Unboxing.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class Unboxing { +public class Unboxing { @Nullable Integer f; diff --git a/checker/tests/nullness/ValidType.java b/checker/tests/nullness/ValidType.java index 9943cdaef9..f98a5efb3c 100644 --- a/checker/tests/nullness/ValidType.java +++ b/checker/tests/nullness/ValidType.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.initialization.qual.*; import org.checkerframework.checker.nullness.qual.*; -class ValidType { +public class ValidType { void t1() { // :: error: (type.invalid.conflicting.annos) diff --git a/checker/tests/nullness/WeakRef.java b/checker/tests/nullness/WeakRef.java index 67bf000317..104660d040 100644 --- a/checker/tests/nullness/WeakRef.java +++ b/checker/tests/nullness/WeakRef.java @@ -1,7 +1,7 @@ import java.lang.ref.WeakReference; import org.checkerframework.checker.nullness.qual.*; -class WeakRef { +public class WeakRef { @PolyNull Object @Nullable [] foo(WeakReference<@PolyNull Object[]> lookup) { return lookup.get(); } diff --git a/checker/tests/nullness/Wellformed.java b/checker/tests/nullness/Wellformed.java index 6c211de9c1..ae319acb3e 100644 --- a/checker/tests/nullness/Wellformed.java +++ b/checker/tests/nullness/Wellformed.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class Wellformed { +public class Wellformed { // :: error: (type.invalid.conflicting.annos) @NonNull @Nullable Object f = null; diff --git a/checker/tests/nullness/Widening.java b/checker/tests/nullness/Widening.java index d7b4878723..4da7df66ec 100644 --- a/checker/tests/nullness/Widening.java +++ b/checker/tests/nullness/Widening.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; -class Widening { +public class Widening { @Nullable Integer i; void inc(long amt) {} diff --git a/checker/tests/nullness/WildcardSubtype.java b/checker/tests/nullness/WildcardSubtype.java index 29536a4298..66fea84d5c 100644 --- a/checker/tests/nullness/WildcardSubtype.java +++ b/checker/tests/nullness/WildcardSubtype.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -class WildcardSubtype { +public class WildcardSubtype { class MyClass {} class Visitor { diff --git a/checker/tests/nullness/flow/Issue3267.java b/checker/tests/nullness/flow/Issue3267.java index 179d2a2688..57b392e9b8 100644 --- a/checker/tests/nullness/flow/Issue3267.java +++ b/checker/tests/nullness/flow/Issue3267.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; -class Issue3267 { +public class Issue3267 { void m1(@Nullable Object obj) { if (true) { // :: error: (dereference.of.nullable) diff --git a/checker/tests/nullness/flow/Issue3275.java b/checker/tests/nullness/flow/Issue3275.java index 88a58fac45..05b615b457 100644 --- a/checker/tests/nullness/flow/Issue3275.java +++ b/checker/tests/nullness/flow/Issue3275.java @@ -4,7 +4,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -class Issue3275 { +public class Issue3275 { public @NonNull Object f = new Object(); public boolean b = false; diff --git a/checker/tests/nullness/flow/Issue341.java b/checker/tests/nullness/flow/Issue341.java index c757f49184..a22df59fe9 100644 --- a/checker/tests/nullness/flow/Issue341.java +++ b/checker/tests/nullness/flow/Issue341.java @@ -1,7 +1,7 @@ // Test case for issue #341: // https://github.com/typetools/checker-framework/issues/341 -class Test { +public class Issue341 { static class Provider { public final Object get = new Object(); diff --git a/checker/tests/nullness/flow/Issue818.java b/checker/tests/nullness/flow/Issue818.java index a4e24918f5..7005fa925c 100644 --- a/checker/tests/nullness/flow/Issue818.java +++ b/checker/tests/nullness/flow/Issue818.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.nullness.qual.*; -class Issue818 { +public class Issue818 { public static @Nullable Object o = null; void method() { diff --git a/checker/tests/nullness/flow/MapGet.java b/checker/tests/nullness/flow/MapGet.java index 6c691eda98..5ccbd733f0 100644 --- a/checker/tests/nullness/flow/MapGet.java +++ b/checker/tests/nullness/flow/MapGet.java @@ -8,7 +8,7 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNull; import org.checkerframework.checker.nullness.qual.NonNull; -class MapGet { +public class MapGet { private final Map labels = new HashMap<>(); void foo1(String v) { diff --git a/checker/tests/nullness/flow/PureAndFlow.java b/checker/tests/nullness/flow/PureAndFlow.java index 02f759d65b..724e78a411 100644 --- a/checker/tests/nullness/flow/PureAndFlow.java +++ b/checker/tests/nullness/flow/PureAndFlow.java @@ -51,12 +51,12 @@ interface IFace { class Cons { @org.checkerframework.dataflow.qual.Pure // :: warning: (purity.deterministic.constructor) - // :: error: (purity.not.deterministic.not.sideeffectfree.call.method) + // :: error: (purity.not.deterministic.not.sideeffectfree.call) Cons(String s) {} @org.checkerframework.dataflow.qual.Deterministic // :: warning: (purity.deterministic.constructor) - // :: error: (purity.not.deterministic.call.method) + // :: error: (purity.not.deterministic.call) Cons(int i) {} } } diff --git a/checker/tests/nullness/flow/PurityError.java b/checker/tests/nullness/flow/PurityError.java index 188c106ebd..746dfbd631 100644 --- a/checker/tests/nullness/flow/PurityError.java +++ b/checker/tests/nullness/flow/PurityError.java @@ -7,7 +7,7 @@ void method() {} @Pure Object method2() { - // :: error: (purity.not.deterministic.call.method) + // :: error: (purity.not.deterministic.call) method(); return ""; } diff --git a/checker/tests/nullness/flow/TestNullnessUtil.java b/checker/tests/nullness/flow/TestNullnessUtil.java index 5cb3b589c6..c37567095f 100644 --- a/checker/tests/nullness/flow/TestNullnessUtil.java +++ b/checker/tests/nullness/flow/TestNullnessUtil.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.nullness.qual.*; /** Test class org.checkerframework.checker.nullness.NullnessUtil. */ -class TestNullnessUtil { +public class TestNullnessUtil { void testRef1(@Nullable Object o) { // one way to use as a cast: @NonNull Object l1 = NullnessUtil.castNonNull(o); diff --git a/checker/tests/nullness/flow/TestOpt.java b/checker/tests/nullness/flow/TestOpt.java index a48c9bff24..4af6697e69 100644 --- a/checker/tests/nullness/flow/TestOpt.java +++ b/checker/tests/nullness/flow/TestOpt.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.nullness.qual.*; /** Test class org.checkerframework.checker.nullness.Opt. */ -class TestOpt { +public class TestOpt { void foo1(@Nullable Object p) { if (Opt.isPresent(p)) { p.toString(); // Flow refinement diff --git a/checker/tests/nullness/generics/AnnotatedGenerics.java b/checker/tests/nullness/generics/AnnotatedGenerics.java index 06ad456477..c096f40d63 100644 --- a/checker/tests/nullness/generics/AnnotatedGenerics.java +++ b/checker/tests/nullness/generics/AnnotatedGenerics.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.nullness.qual.*; import org.checkerframework.dataflow.qual.*; -class AnnotatedGenerics { +public class AnnotatedGenerics { public static void testNullableTypeVariable() { // :: error: (initialization.fields.uninitialized) class Test { diff --git a/checker/tests/nullness/generics/AnnotatedGenerics2.java b/checker/tests/nullness/generics/AnnotatedGenerics2.java index 5c92da5668..cafe66bee4 100644 --- a/checker/tests/nullness/generics/AnnotatedGenerics2.java +++ b/checker/tests/nullness/generics/AnnotatedGenerics2.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class AnnotatedGenerics2 { +public class AnnotatedGenerics2 { // Top-level class to ensure that both classes are processed. // :: error: (initialization.fields.uninitialized) diff --git a/checker/tests/nullness/generics/AnnotatedGenerics3.java b/checker/tests/nullness/generics/AnnotatedGenerics3.java index 9f58aefa08..31490a8d7f 100644 --- a/checker/tests/nullness/generics/AnnotatedGenerics3.java +++ b/checker/tests/nullness/generics/AnnotatedGenerics3.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class AnnotatedGenerics3 { +public class AnnotatedGenerics3 { class Cell { T f; diff --git a/checker/tests/nullness/generics/AnnotatedTypeParams2.java b/checker/tests/nullness/generics/AnnotatedTypeParams2.java index d20598f236..99c89df3ba 100644 --- a/checker/tests/nullness/generics/AnnotatedTypeParams2.java +++ b/checker/tests/nullness/generics/AnnotatedTypeParams2.java @@ -6,7 +6,7 @@ T get() { } } -class AnnotatedTypeParams { +public class AnnotatedTypeParams2 { void testPositive() { SomeClass<@Nullable String> l = new SomeClass<>(); diff --git a/checker/tests/nullness/generics/AnnotatedTypeParams4.java b/checker/tests/nullness/generics/AnnotatedTypeParams4.java index a93faba91f..46e066a344 100644 --- a/checker/tests/nullness/generics/AnnotatedTypeParams4.java +++ b/checker/tests/nullness/generics/AnnotatedTypeParams4.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class Test { +public class AnnotatedTypeParams4 { class Test1 { CONTENT a; diff --git a/checker/tests/nullness/generics/AnnonymousClass.java b/checker/tests/nullness/generics/AnonymousClass.java similarity index 93% rename from checker/tests/nullness/generics/AnnonymousClass.java rename to checker/tests/nullness/generics/AnonymousClass.java index 9bde5f290d..9fd3545eda 100644 --- a/checker/tests/nullness/generics/AnnonymousClass.java +++ b/checker/tests/nullness/generics/AnonymousClass.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class AnonymousClass { +public class AnonymousClass { class Bound {} diff --git a/checker/tests/nullness/generics/BoundedWildcardTest.java b/checker/tests/nullness/generics/BoundedWildcardTest.java index 51eee182bb..26c64de260 100644 --- a/checker/tests/nullness/generics/BoundedWildcardTest.java +++ b/checker/tests/nullness/generics/BoundedWildcardTest.java @@ -6,7 +6,7 @@ class Styleable {} -class BoundedWildcardTest { +public class BoundedWildcardTest { private void locChildren(Styleable c) { // ... diff --git a/checker/tests/nullness/generics/BoxingGenerics.java b/checker/tests/nullness/generics/BoxingGenerics.java index 218ff3aeb8..13fb50f2bb 100644 --- a/checker/tests/nullness/generics/BoxingGenerics.java +++ b/checker/tests/nullness/generics/BoxingGenerics.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class BoxingGenerics { +public class BoxingGenerics { static class X { public static X foo(T x) { return new X<>(); diff --git a/checker/tests/nullness/generics/CollectionsAnnotationsMin.java b/checker/tests/nullness/generics/CollectionsAnnotationsMin.java index 34310d89bb..67120e3985 100644 --- a/checker/tests/nullness/generics/CollectionsAnnotationsMin.java +++ b/checker/tests/nullness/generics/CollectionsAnnotationsMin.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class CollectionsAnnotationsMin { +public class CollectionsAnnotationsMin { static class Collection1 { public void add(E elt) { // :: error: (dereference.of.nullable) diff --git a/checker/tests/nullness/generics/GenericArgs2.java b/checker/tests/nullness/generics/GenericArgs2.java index 3b7a6de848..59cde773d2 100644 --- a/checker/tests/nullness/generics/GenericArgs2.java +++ b/checker/tests/nullness/generics/GenericArgs2.java @@ -7,7 +7,7 @@ class Cell { void add(T arg) {} } -class GenericArgs2 { +public class GenericArgs2 { static void test1(Cell collection) { // :: error: (argument.type.incompatible) collection.add(null); // should fail diff --git a/checker/tests/nullness/generics/GenericBoundsExplicit.java b/checker/tests/nullness/generics/GenericBoundsExplicit.java index fa9b86f8ef..4461c75cdb 100644 --- a/checker/tests/nullness/generics/GenericBoundsExplicit.java +++ b/checker/tests/nullness/generics/GenericBoundsExplicit.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.nullness.qual.*; @SuppressWarnings("initialization.fields.uninitialized") -class GenericBoundsExplicit<@NonNull T extends @Nullable Object> { +public class GenericBoundsExplicit<@NonNull T extends @Nullable Object> { T t; diff --git a/checker/tests/nullness/generics/GenericTest11.java b/checker/tests/nullness/generics/GenericTest11.java index 12bf4c0668..560303c00b 100644 --- a/checker/tests/nullness/generics/GenericTest11.java +++ b/checker/tests/nullness/generics/GenericTest11.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.nullness.qual.*; -class GenericTest11 { +public class GenericTest11 { public void m(BeanManager beanManager) { Bean bean = beanManager.getBeans(GenericTest11.class).iterator().next(); CreationalContext context = beanManager.createCreationalContext(bean); diff --git a/checker/tests/nullness/generics/GenericsBounds4.java b/checker/tests/nullness/generics/GenericsBounds4.java index 5258cea3a1..6c87882a97 100644 --- a/checker/tests/nullness/generics/GenericsBounds4.java +++ b/checker/tests/nullness/generics/GenericsBounds4.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class GenericsBounds4 { +public class GenericsBounds4 { class Collection1 { public void add(E elt) { // :: error: (dereference.of.nullable) diff --git a/checker/tests/nullness/generics/GenericsBounds5.java b/checker/tests/nullness/generics/GenericsBounds5.java index 157ce94d5c..8a5a170af9 100644 --- a/checker/tests/nullness/generics/GenericsBounds5.java +++ b/checker/tests/nullness/generics/GenericsBounds5.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class GenericsBounds5 { +public class GenericsBounds5 { class Collection1 { public void add(E elt) { // This call is forbidden, because elt might be null. diff --git a/checker/tests/nullness/generics/GenericsExample.java b/checker/tests/nullness/generics/GenericsExample.java index 6ae072c39d..4b4ad2dd65 100644 --- a/checker/tests/nullness/generics/GenericsExample.java +++ b/checker/tests/nullness/generics/GenericsExample.java @@ -3,7 +3,7 @@ // This is the example from manual section: // "Generics (parametric polymorphism or type polymorphism)" // whose source code is ../../../docs/manual/advanced-features.tex -class GenericsExample { +public class GenericsExample { class MyList1<@Nullable T> { T t; diff --git a/checker/tests/nullness/generics/GenericsExampleMin.java b/checker/tests/nullness/generics/GenericsExampleMin.java index 22b31e04ce..56d7d52235 100644 --- a/checker/tests/nullness/generics/GenericsExampleMin.java +++ b/checker/tests/nullness/generics/GenericsExampleMin.java @@ -3,7 +3,7 @@ // This is the example from manual section: // "Generics (parametric polymorphism or type polymorphism)" // whose source code is ../../../docs/manual/advanced-features.tex -class GenericsExampleMin { +public class GenericsExampleMin { class MyList1<@Nullable T> { T t; diff --git a/checker/tests/nullness/generics/InferedPrimitive.java b/checker/tests/nullness/generics/InferredPrimitive.java similarity index 86% rename from checker/tests/nullness/generics/InferedPrimitive.java rename to checker/tests/nullness/generics/InferredPrimitive.java index 223fe031aa..68288facda 100644 --- a/checker/tests/nullness/generics/InferedPrimitive.java +++ b/checker/tests/nullness/generics/InferredPrimitive.java @@ -1,5 +1,5 @@ /** Test case for Issue 143: https://github.com/typetools/checker-framework/issues/143 */ -class InferredPrimitive { +public class InferredPrimitive { public static void main(String[] args) { java.util.Set s = java.util.Collections.singleton(123L); } diff --git a/checker/tests/nullness/generics/Issue1838.java b/checker/tests/nullness/generics/Issue1838.java index ef762e8368..def32f0502 100644 --- a/checker/tests/nullness/generics/Issue1838.java +++ b/checker/tests/nullness/generics/Issue1838.java @@ -5,7 +5,7 @@ import java.util.List; import org.checkerframework.checker.nullness.qual.Nullable; -class Issue1838 { +public class Issue1838 { public static void main(String[] args) { f(); } diff --git a/checker/tests/nullness/generics/Issue1838Min.java b/checker/tests/nullness/generics/Issue1838Min.java index 8111486d3f..b8dd24e6b4 100644 --- a/checker/tests/nullness/generics/Issue1838Min.java +++ b/checker/tests/nullness/generics/Issue1838Min.java @@ -5,7 +5,7 @@ import java.util.List; import org.checkerframework.checker.nullness.qual.Nullable; -class Issue1838Min { +public class Issue1838Min { List> llno = new ArrayList<>(); // :: error: (assignment.type.incompatible) List> lweo = llno; diff --git a/checker/tests/nullness/generics/Issue269.java b/checker/tests/nullness/generics/Issue269.java index 39500228c2..c65cce2662 100644 --- a/checker/tests/nullness/generics/Issue269.java +++ b/checker/tests/nullness/generics/Issue269.java @@ -1,6 +1,6 @@ // Test case for Issue 269 // https://github.com/typetools/checker-framework/issues/269 -class Repro { +class Issue269 { // Implicitly G has bound @Nullable Object interface Callback { public boolean handler(G arg); @@ -9,7 +9,7 @@ interface Callback { void method1(Callback callback) { // Allow this call. // :: warning: [unchecked] unchecked call to handler(G) as a member of the raw type - // Repro.Callback + // Issue269.Callback callback.handler(this); } @@ -23,7 +23,7 @@ void method2(CallbackNN callback) { // TODO: false negative. See #635. //// :: error: (argument.type.incompatible) // :: warning: [unchecked] unchecked call to handler(H) as a member of the raw type - // Repro.CallbackNN + // Issue269.CallbackNN callback.handler(null); } } diff --git a/checker/tests/nullness/generics/Issue270.java b/checker/tests/nullness/generics/Issue270.java index 6ce9a08904..500fcdc5d7 100644 --- a/checker/tests/nullness/generics/Issue270.java +++ b/checker/tests/nullness/generics/Issue270.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.nullness.qual.*; // ::error: (bound.type.incompatible) -class Issue270<@Nullable TypeParam extends @NonNull Object> { +public class Issue270<@Nullable TypeParam extends @NonNull Object> { public static void main() { // ::error: (type.argument.type.incompatible) diff --git a/checker/tests/nullness/generics/Issue282Min.java b/checker/tests/nullness/generics/Issue282Min.java index c82b790d72..ca454522c9 100644 --- a/checker/tests/nullness/generics/Issue282Min.java +++ b/checker/tests/nullness/generics/Issue282Min.java @@ -6,7 +6,7 @@ import java.util.Set; import org.checkerframework.checker.nullness.qual.*; -class Issue282Min { +public class Issue282Min { static Set copyOf(Comparator comparator, Collection elements) { // :: error: (return.type.incompatible) return null; diff --git a/checker/tests/nullness/generics/Issue312.java b/checker/tests/nullness/generics/Issue312.java index b04ba1b286..45b2b1b064 100644 --- a/checker/tests/nullness/generics/Issue312.java +++ b/checker/tests/nullness/generics/Issue312.java @@ -20,7 +20,7 @@ public List sortedCopy(Iterable elements) { } } -class Issue312 { +public class Issue312 { void test(List list) { Ordering312.natural().reverse().sortedCopy(list); } @@ -32,7 +32,7 @@ void test(List list) { import com.google.common.collect.Ordering312; import java.util.List; -class Issue312 { +public class Issue312 { void test() { List list = Lists.newArrayList(); Ordering.natural().reverse().sortedCopy(list); diff --git a/checker/tests/nullness/generics/Issue313.java b/checker/tests/nullness/generics/Issue313.java index 19c7a26f1e..fcaa819ffd 100644 --- a/checker/tests/nullness/generics/Issue313.java +++ b/checker/tests/nullness/generics/Issue313.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class Issue313 { +public class Issue313 { class A<@NonNull T extends @Nullable Object> {} <@NonNull X extends @Nullable Object> void m() { diff --git a/checker/tests/nullness/generics/Issue314.java b/checker/tests/nullness/generics/Issue314.java index 71c3a5b15d..5a0b528eda 100644 --- a/checker/tests/nullness/generics/Issue314.java +++ b/checker/tests/nullness/generics/Issue314.java @@ -5,7 +5,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -class Issue314 { +public class Issue314 { List m1(List<@NonNull T> l1) { return l1; } diff --git a/checker/tests/nullness/generics/Issue319.java b/checker/tests/nullness/generics/Issue319.java index b437fc8963..fadf581879 100644 --- a/checker/tests/nullness/generics/Issue319.java +++ b/checker/tests/nullness/generics/Issue319.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.nullness.qual.*; -class Issue319 { +public class Issue319 { class Foo { Foo(@Nullable T t) {} } diff --git a/checker/tests/nullness/generics/Issue326.java b/checker/tests/nullness/generics/Issue326.java index 97e0a802c2..ccba0aa9f3 100644 --- a/checker/tests/nullness/generics/Issue326.java +++ b/checker/tests/nullness/generics/Issue326.java @@ -2,7 +2,7 @@ import java.util.Set; import org.checkerframework.checker.nullness.qual.Nullable; -class Issue326 { +public class Issue326 { { Set<@Nullable String> local = new HashSet<>(); } diff --git a/checker/tests/nullness/generics/Issue335.java b/checker/tests/nullness/generics/Issue335.java index d2411c9b7a..78037ab5d7 100644 --- a/checker/tests/nullness/generics/Issue335.java +++ b/checker/tests/nullness/generics/Issue335.java @@ -15,7 +15,7 @@ static Optional of(T reference) { } } -class Issue335 { +public class Issue335 { Optional> m(String one, String two) { return Optional.of(Pair.of(one, two)); } diff --git a/checker/tests/nullness/generics/Issue339.java b/checker/tests/nullness/generics/Issue339.java index 0d5abb3d0c..34c67a9544 100644 --- a/checker/tests/nullness/generics/Issue339.java +++ b/checker/tests/nullness/generics/Issue339.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.nullness.qual.*; -class Issue339 { +public class Issue339 { static @NonNull T checkNotNull(T p) { throw new RuntimeException(); } diff --git a/checker/tests/nullness/generics/Issue421.java b/checker/tests/nullness/generics/Issue421.java index da8f6d976e..02f80b90b8 100644 --- a/checker/tests/nullness/generics/Issue421.java +++ b/checker/tests/nullness/generics/Issue421.java @@ -1,4 +1,4 @@ -class Issue421 { +public class Issue421 { abstract static class C { abstract X getX(); } diff --git a/checker/tests/nullness/generics/Issue428.java b/checker/tests/nullness/generics/Issue428.java index 1de5d8144c..c5bca87fe0 100644 --- a/checker/tests/nullness/generics/Issue428.java +++ b/checker/tests/nullness/generics/Issue428.java @@ -3,7 +3,7 @@ import java.util.List; -interface Issue428 {} +public interface Issue428 {} class Test428 { void m(List> is) { diff --git a/checker/tests/nullness/generics/Issue849.java b/checker/tests/nullness/generics/Issue849.java index caf8b19607..fc51a7ee45 100644 --- a/checker/tests/nullness/generics/Issue849.java +++ b/checker/tests/nullness/generics/Issue849.java @@ -4,7 +4,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -class Issue849 { +public class Issue849 { class Gen {} void nullness(Gen> genGenNonNull) { diff --git a/checker/tests/nullness/generics/KeyForPolyKeyFor.java b/checker/tests/nullness/generics/KeyForPolyKeyFor.java index b347d990b6..3b6f7ca2af 100644 --- a/checker/tests/nullness/generics/KeyForPolyKeyFor.java +++ b/checker/tests/nullness/generics/KeyForPolyKeyFor.java @@ -6,7 +6,7 @@ import org.checkerframework.checker.nullness.qual.*; // test related to issue 429: https://github.com/typetools/checker-framework/issues/429 -class KeyForPolyKeyFor { +public class KeyForPolyKeyFor { // TODO: Figure out why diamond operator does not work: // Map<@KeyFor("dict") String, String> dict = new HashMap<>(); Map<@KeyFor("dict") String, String> dict = new HashMap<@KeyFor("dict") String, String>(); diff --git a/checker/tests/nullness/generics/MapLoop.java b/checker/tests/nullness/generics/MapLoop.java index 2fa775a8d7..1241ab7176 100644 --- a/checker/tests/nullness/generics/MapLoop.java +++ b/checker/tests/nullness/generics/MapLoop.java @@ -1,7 +1,7 @@ import java.util.Map; import org.checkerframework.checker.nullness.qual.*; -class MapLoop { +public class MapLoop { void test1(Map map) { for (Map.Entry<@KeyFor("map") String, String> entry : map.entrySet()) {} } diff --git a/checker/tests/nullness/generics/MethodTypeVars3.java b/checker/tests/nullness/generics/MethodTypeVars3.java index fc801d4caa..2260cfcda9 100644 --- a/checker/tests/nullness/generics/MethodTypeVars3.java +++ b/checker/tests/nullness/generics/MethodTypeVars3.java @@ -6,7 +6,7 @@ import java.util.Set; import org.checkerframework.checker.nullness.qual.*; -class MethodTypeVars3 { +public class MethodTypeVars3 { public static <@KeyFor("#1") T extends @KeyFor("#1") Object> Map> dominators( Map> preds) { List nodes = new ArrayList<>(preds.keySet()); diff --git a/checker/tests/nullness/generics/MethodTypeVars5.java b/checker/tests/nullness/generics/MethodTypeVars5.java index 0bbe31f78a..13bbb31d15 100644 --- a/checker/tests/nullness/generics/MethodTypeVars5.java +++ b/checker/tests/nullness/generics/MethodTypeVars5.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class MethodTypeVars5 { +public class MethodTypeVars5 { class B { S t; diff --git a/checker/tests/nullness/generics/NullnessBound.java b/checker/tests/nullness/generics/NullnessBound.java index ced84afa3a..70911d72ed 100644 --- a/checker/tests/nullness/generics/NullnessBound.java +++ b/checker/tests/nullness/generics/NullnessBound.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class NullnessBound { +public class NullnessBound { public void test() { Gen1<@Nullable String> t1 = new Gen1<>(); diff --git a/checker/tests/nullness/generics/RawTypesGenerics.java b/checker/tests/nullness/generics/RawTypesGenerics.java index c9aeb28363..634f23fa1f 100644 --- a/checker/tests/nullness/generics/RawTypesGenerics.java +++ b/checker/tests/nullness/generics/RawTypesGenerics.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class RawTypesGenerics { +public class RawTypesGenerics { void m() throws ClassNotFoundException { Class c1 = Class.forName("bla"); Class c2 = Class.forName("bla"); diff --git a/checker/tests/nullness/generics/SuperRawness.java b/checker/tests/nullness/generics/SuperRawness.java index 9efc3960c6..d6f7e9f6e9 100644 --- a/checker/tests/nullness/generics/SuperRawness.java +++ b/checker/tests/nullness/generics/SuperRawness.java @@ -1,7 +1,7 @@ import java.util.Arrays; import java.util.Set; -class SuperRawness { +public class SuperRawness { // :: warning: [unchecked] Possible heap pollution from parameterized vararg type // java.util.Set static void test(Set... args) { diff --git a/checker/tests/nullness/generics/TernaryGenerics.java b/checker/tests/nullness/generics/TernaryGenerics.java index b384457205..dadbdc49b0 100644 --- a/checker/tests/nullness/generics/TernaryGenerics.java +++ b/checker/tests/nullness/generics/TernaryGenerics.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class TernaryGenerics { +public class TernaryGenerics { class Generic1 { void cond(boolean b, T p) { // :: error: (assignment.type.incompatible) diff --git a/checker/tests/nullness/generics/VarArgs.java b/checker/tests/nullness/generics/VarArgsTest.java similarity index 93% rename from checker/tests/nullness/generics/VarArgs.java rename to checker/tests/nullness/generics/VarArgsTest.java index 7e7dd10549..3c56330853 100644 --- a/checker/tests/nullness/generics/VarArgs.java +++ b/checker/tests/nullness/generics/VarArgsTest.java @@ -1,7 +1,7 @@ import java.util.Arrays; import java.util.Set; -class AaTest { +public class VarArgsTest { // :: warning: [unchecked] Possible heap pollution from parameterized vararg type // java.util.Set void test(Set... args) { diff --git a/checker/tests/nullness/generics/WellformedBounds.java b/checker/tests/nullness/generics/WellformedBounds.java index d4ebc11f28..80034b102e 100644 --- a/checker/tests/nullness/generics/WellformedBounds.java +++ b/checker/tests/nullness/generics/WellformedBounds.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -// Field f needs to be set, b/c the upper bound is @Initialized +// Field f needs to be set, because the upper bound is @Initialized // :: error: (initialization.fields.uninitialized) class Param { T f; diff --git a/checker/tests/nullness/generics/WildcardAnnos.java b/checker/tests/nullness/generics/WildcardAnnos.java index 81a42ba292..90ca14de75 100644 --- a/checker/tests/nullness/generics/WildcardAnnos.java +++ b/checker/tests/nullness/generics/WildcardAnnos.java @@ -1,7 +1,7 @@ import java.util.List; import org.checkerframework.checker.nullness.qual.*; -class WildcardAnnos { +public class WildcardAnnos { // :: error: (bound.type.incompatible) @Nullable List<@Nullable ? extends @NonNull Object> l1 = null; @Nullable List<@NonNull ? extends @Nullable Object> l2 = null; diff --git a/checker/tests/nullness/generics/WildcardBoundDefault.java b/checker/tests/nullness/generics/WildcardBoundDefault.java index 2cb4ca53e7..b922e8df12 100644 --- a/checker/tests/nullness/generics/WildcardBoundDefault.java +++ b/checker/tests/nullness/generics/WildcardBoundDefault.java @@ -5,7 +5,7 @@ class MyGenClass {} @DefaultQualifier(value = Nullable.class, locations = TypeUseLocation.UPPER_BOUND) -class Varargs { +public class WildcardBoundDefault { void test() { ignore(newInstance()); } diff --git a/checker/tests/nullness/generics/WildcardOverride.java b/checker/tests/nullness/generics/WildcardOverride.java index a21cf4cd8f..275f4cf208 100644 --- a/checker/tests/nullness/generics/WildcardOverride.java +++ b/checker/tests/nullness/generics/WildcardOverride.java @@ -11,7 +11,7 @@ interface ToOverride { public abstract int transform(List function); } -class WildcardOverride implements ToOverride { +public class WildcardOverride implements ToOverride { // invalid because the overriden method takes @Nullable args and this one doesn't @Override // :: error: (override.param.invalid) diff --git a/checker/tests/nullness/generics/WildcardSubtyping2.java b/checker/tests/nullness/generics/WildcardSubtyping2.java index 1198ee5944..8b01eeb591 100644 --- a/checker/tests/nullness/generics/WildcardSubtyping2.java +++ b/checker/tests/nullness/generics/WildcardSubtyping2.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.*; -class WildcardSubtyping2 { +public class WildcardSubtyping2 { class MyClass {} class MyCloneClass extends MyClass implements Cloneable {} diff --git a/checker/tests/nullness/generics/WildcardSubtypingTypeArray.java b/checker/tests/nullness/generics/WildcardSubtypingTypeArray.java index 19832c4b80..cd810cfe3b 100644 --- a/checker/tests/nullness/generics/WildcardSubtypingTypeArray.java +++ b/checker/tests/nullness/generics/WildcardSubtypingTypeArray.java @@ -1,7 +1,7 @@ import java.util.List; import org.checkerframework.checker.nullness.qual.*; -class WildcardSubtypingTypeArray { +public class WildcardSubtypingTypeArray { void test(List list) { test2(list.get(0)); } diff --git a/checker/tests/nullness/generics/WildcardSuper.java b/checker/tests/nullness/generics/WildcardSuper.java index 5fa6420c69..5e67c68919 100644 --- a/checker/tests/nullness/generics/WildcardSuper.java +++ b/checker/tests/nullness/generics/WildcardSuper.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.nullness.qual.*; import org.checkerframework.framework.qual.DefaultQualifier; -class WildcardSuper { +public class WildcardSuper { void testWithSuper(Cell cell) { // TODO: Address comments. Since ? is explicitly lower bounded, I have made a judgment that @@ -13,7 +13,7 @@ void testWithSuper(Cell cell) { // TODO: THIS SHOULD JUST ISSUE A WARNING, WHY WOULD PEOPLE WANT TO WRITE CONTRADICTING BOUNDS? void testWithContradiction(Cell cell) { - // This is actually valid, because it's a contradiction, b/c + // This is actually valid, because it's a contradiction, because // the implicit upper bound is NonNull. // We are free to do anything, as the method is not callable. // TODO: test whether all calls of method fail. diff --git a/checker/tests/nullness/init/AnonymousInit.java b/checker/tests/nullness/init/AnonymousInit.java index cb054b1d1d..74e44e6d98 100644 --- a/checker/tests/nullness/init/AnonymousInit.java +++ b/checker/tests/nullness/init/AnonymousInit.java @@ -1,6 +1,6 @@ // Ensure field initialization checks for anonymous // classes work. -class AnonymousInit { +public class AnonymousInit { Object o1 = // :: error: (initialization.fields.uninitialized) new Object() { diff --git a/checker/tests/nullness/init/FieldWithInit.java b/checker/tests/nullness/init/FieldWithInit.java index e47a8f00c3..b42ea03adc 100644 --- a/checker/tests/nullness/init/FieldWithInit.java +++ b/checker/tests/nullness/init/FieldWithInit.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.initialization.qual.UnknownInitialization; -class FieldWithInit { +public class FieldWithInit { Object f = foo(); Object foo(@UnknownInitialization FieldWithInit this) { diff --git a/checker/tests/nullness/init/GenericTest12b.java b/checker/tests/nullness/init/GenericTest12b.java index 41d915cfb4..6a0cc594a6 100644 --- a/checker/tests/nullness/init/GenericTest12b.java +++ b/checker/tests/nullness/init/GenericTest12b.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.initialization.qual.UnderInitialization; import org.checkerframework.checker.nullness.qual.Nullable; -class GenericTest12b { +public class GenericTest12b { class Cell {} class Node { diff --git a/checker/tests/nullness/init/InstanceOf.java b/checker/tests/nullness/init/InstanceOf.java index 459c65f123..6ced9d107e 100644 --- a/checker/tests/nullness/init/InstanceOf.java +++ b/checker/tests/nullness/init/InstanceOf.java @@ -13,7 +13,7 @@ Object method() { class OtherPpt extends Ppt {} } -class InstanceOf { +public class InstanceOf { void foo(PptTopLevel.@UnknownInitialization(PptTopLevel.class) Ppt ppt) { // :: error: (method.invocation.invalid) ppt.method(); diff --git a/checker/tests/nullness/init/Issue1347.java b/checker/tests/nullness/init/Issue1347.java index 7a46029c34..b0e2702e6b 100644 --- a/checker/tests/nullness/init/Issue1347.java +++ b/checker/tests/nullness/init/Issue1347.java @@ -1,7 +1,7 @@ // Test case for Issue 1347. // https://github.com/typetools/checker-framework/issues/1347 -class Issue1347 { +public class Issue1347 { T t; T t2; Object o; diff --git a/checker/tests/nullness/init/Issue3407.java b/checker/tests/nullness/init/Issue3407.java index 85d8111463..6bb7c3c1a6 100644 --- a/checker/tests/nullness/init/Issue3407.java +++ b/checker/tests/nullness/init/Issue3407.java @@ -1,17 +1,17 @@ // @below-java9-jdk-skip-test -class Issue3408 { +public class Issue3407 { final String foo; String getFoo() { return foo; } - Issue3408() { + Issue3407() { var anon = new Object() { String bar() { // :: error: (method.invocation.invalid) - return Issue3408.this.getFoo().substring(1); + return Issue3407.this.getFoo().substring(1); } }; anon.bar(); // / WHOOPS... NPE, `getFoo()` returns `foo` which is still null diff --git a/checker/tests/nullness/init/RawMethodInvocation.java b/checker/tests/nullness/init/RawMethodInvocation.java index 093bf24c1f..8aa9117238 100644 --- a/checker/tests/nullness/init/RawMethodInvocation.java +++ b/checker/tests/nullness/init/RawMethodInvocation.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNull; @org.checkerframework.framework.qual.DefaultQualifier(Nullable.class) -class RawMethodInvocation { +public class RawMethodInvocation { @NonNull String a; @NonNull String b; diff --git a/checker/tests/nullness/init/RawTypesInit.java b/checker/tests/nullness/init/RawTypesInit.java index fa7833af5f..57ff209e70 100644 --- a/checker/tests/nullness/init/RawTypesInit.java +++ b/checker/tests/nullness/init/RawTypesInit.java @@ -5,7 +5,7 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNull; import org.checkerframework.checker.nullness.qual.RequiresNonNull; -class RawTypesInit { +public class RawTypesInit { class Bad { @NonNull String field; diff --git a/checker/tests/nullness/init/StaticInit.java b/checker/tests/nullness/init/StaticInit.java index 5c309e178b..64f15adc39 100644 --- a/checker/tests/nullness/init/StaticInit.java +++ b/checker/tests/nullness/init/StaticInit.java @@ -2,7 +2,7 @@ // https://github.com/typetools/checker-framework/issues/353 // @skip-test -class StaticInit { +public class StaticInit { static String a; diff --git a/checker/tests/nullness/java8/Issue1000.java b/checker/tests/nullness/java8/Issue1000.java index d1674c5bed..143c32ab65 100644 --- a/checker/tests/nullness/java8/Issue1000.java +++ b/checker/tests/nullness/java8/Issue1000.java @@ -4,7 +4,7 @@ import java.util.Optional; import org.checkerframework.checker.nullness.qual.Nullable; -class Issue1000 { +public class Issue1000 { void illegalInstantiation(Optional<@Nullable String> arg) {} String orElseAppliedToNonNull(Optional opt) { diff --git a/checker/tests/nullness/java8/Issue1046Java8.java b/checker/tests/nullness/java8/Issue1046Java8.java index d81060ca54..c77f917919 100644 --- a/checker/tests/nullness/java8/Issue1046Java8.java +++ b/checker/tests/nullness/java8/Issue1046Java8.java @@ -6,7 +6,7 @@ import java.util.function.Function; import org.checkerframework.checker.nullness.qual.UnknownKeyFor; -class Issue1046Java8 { +public class Issue1046Java8 { interface EnumMarker {} enum MyEnum implements EnumMarker { diff --git a/checker/tests/nullness/java8/Issue1098.java b/checker/tests/nullness/java8/Issue1098.java index aa63d5d92f..f64568ee51 100644 --- a/checker/tests/nullness/java8/Issue1098.java +++ b/checker/tests/nullness/java8/Issue1098.java @@ -3,7 +3,7 @@ import java.util.Optional; -class Issue1098 { +public class Issue1098 { void opt(Optional p1, T p2) {} void cls(Class p1, T p2) {} diff --git a/checker/tests/nullness/java8/Issue1633.java b/checker/tests/nullness/java8/Issue1633.java index 48eb06f1e3..7c31c895af 100644 --- a/checker/tests/nullness/java8/Issue1633.java +++ b/checker/tests/nullness/java8/Issue1633.java @@ -7,7 +7,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.framework.qual.Covariant; -class Issue1633 { +public class Issue1633 { // supplyNullable is a supplier that may return null. // supplyNonNull is a supplier that does not return null. diff --git a/checker/tests/nullness/java8/Issue363.java b/checker/tests/nullness/java8/Issue363.java index 341138d94d..e20d6dc25e 100644 --- a/checker/tests/nullness/java8/Issue363.java +++ b/checker/tests/nullness/java8/Issue363.java @@ -1,7 +1,7 @@ // Test case for Issue 363: // https://github.com/typetools/checker-framework/issues/363 -class Issue363 { +public class Issue363 { void foo(java.util.OptionalInt value) { value.orElseThrow(() -> new Error()); } diff --git a/checker/tests/nullness/java8/Issue366.java b/checker/tests/nullness/java8/Issue366.java index 60eb7ec39e..0f1d9a2b40 100644 --- a/checker/tests/nullness/java8/Issue366.java +++ b/checker/tests/nullness/java8/Issue366.java @@ -7,7 +7,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -class Issue366 { +public class Issue366 { static Optional<@NonNull String> getPossiblyEmptyString() { return Optional.ofNullable(null); } diff --git a/checker/tests/nullness/java8/Issue448Ext.java b/checker/tests/nullness/java8/Issue448Ext.java index d4f9371bd6..866b1c08df 100644 --- a/checker/tests/nullness/java8/Issue448Ext.java +++ b/checker/tests/nullness/java8/Issue448Ext.java @@ -5,7 +5,7 @@ import java.util.function.IntPredicate; import java.util.stream.IntStream; -class Issue448Ext { +public class Issue448Ext { void getFor(int[] ia, int index) { Arrays.stream(ia).filter(x -> true); } diff --git a/checker/tests/nullness/java8/Issue496.java b/checker/tests/nullness/java8/Issue496.java index 66661d2870..00961e91ff 100644 --- a/checker/tests/nullness/java8/Issue496.java +++ b/checker/tests/nullness/java8/Issue496.java @@ -3,7 +3,7 @@ import java.util.Optional; -class Issue496 { +public class Issue496 { public static class Entity { public final T value; diff --git a/checker/tests/nullness/java8/Issue579.java b/checker/tests/nullness/java8/Issue579.java index 66482225f9..5e00311be7 100644 --- a/checker/tests/nullness/java8/Issue579.java +++ b/checker/tests/nullness/java8/Issue579.java @@ -3,11 +3,11 @@ import java.util.Comparator; -class Issue570 implements Comparator { +public class Issue579 implements Comparator { private final Comparator real; @SuppressWarnings("unchecked") - Issue570(Comparator real) { + Issue579(Comparator real) { this.real = (Comparator) real; } @@ -19,6 +19,6 @@ public int compare(T a, T b) { @Override public Comparator thenComparing(Comparator other) { // :: warning: (known.nonnull) - return new Issue570<>(real == null ? other : real.thenComparing(other)); + return new Issue579<>(real == null ? other : real.thenComparing(other)); } } diff --git a/checker/tests/nullness/java8/Issue596.java b/checker/tests/nullness/java8/Issue596.java index 7b6062641d..e1f190250d 100644 --- a/checker/tests/nullness/java8/Issue596.java +++ b/checker/tests/nullness/java8/Issue596.java @@ -4,7 +4,7 @@ import java.util.concurrent.atomic.AtomicReference; import org.checkerframework.checker.nullness.qual.*; -class Issue596 { +public class Issue596 { private static String getOrEmpty(AtomicReference ref) { return Optional596.fromNullable(ref.get()).or(""); diff --git a/checker/tests/nullness/java8/Issue720.java b/checker/tests/nullness/java8/Issue720.java index 36416e1b4f..d747160f51 100644 --- a/checker/tests/nullness/java8/Issue720.java +++ b/checker/tests/nullness/java8/Issue720.java @@ -3,7 +3,7 @@ import java.util.function.IntConsumer; -class Issue720 { +public class Issue720 { static IntConsumer consumer = Issue720::method; static int method(int x) { diff --git a/checker/tests/nullness/java8/lambda/Dataflow.java b/checker/tests/nullness/java8/lambda/Dataflow.java index c35f1edab1..0eae76bdbb 100644 --- a/checker/tests/nullness/java8/lambda/Dataflow.java +++ b/checker/tests/nullness/java8/lambda/Dataflow.java @@ -2,7 +2,7 @@ import org.checkerframework.checker.nullness.qual.*; -class Dataflow { +public class Dataflow { void context() { FunctionDF<@Nullable Object, Object> o = a -> { diff --git a/checker/tests/nullness/java8/lambda/Issue1864b.java b/checker/tests/nullness/java8/lambda/Issue1864b.java index d4ec4bcdc5..074488ffd7 100644 --- a/checker/tests/nullness/java8/lambda/Issue1864b.java +++ b/checker/tests/nullness/java8/lambda/Issue1864b.java @@ -1,7 +1,7 @@ // Test case for Issue 1864: // https://github.com/typetools/checker-framework/issues/1864 -class Issue1864b { +public class Issue1864b { interface Supplier { Object get(); } diff --git a/checker/tests/nullness/java8/lambda/Issue1897.java b/checker/tests/nullness/java8/lambda/Issue1897.java index 3118d224df..aba8e53138 100644 --- a/checker/tests/nullness/java8/lambda/Issue1897.java +++ b/checker/tests/nullness/java8/lambda/Issue1897.java @@ -3,7 +3,7 @@ import java.util.function.Function; -class Issue1897 { +public class Issue1897 { Issue1897() { final int length = 1; takesLambda(s -> length); diff --git a/checker/tests/nullness/java8/lambda/Issue367.java b/checker/tests/nullness/java8/lambda/Issue367.java index d80b883330..816cc13d6a 100644 --- a/checker/tests/nullness/java8/lambda/Issue367.java +++ b/checker/tests/nullness/java8/lambda/Issue367.java @@ -1,6 +1,6 @@ // Test case for Issue 367: // https://github.com/typetools/checker-framework/issues/367 -class Issue367 { +public class Issue367 { static void test(Iterable threads) { threads.forEach(thread -> System.out.println(thread)); } diff --git a/checker/tests/nullness/java8/lambda/Issue403.java b/checker/tests/nullness/java8/lambda/Issue403.java index b0251ed987..6bb0a82f8a 100644 --- a/checker/tests/nullness/java8/lambda/Issue403.java +++ b/checker/tests/nullness/java8/lambda/Issue403.java @@ -3,7 +3,7 @@ import java.util.Comparator; -class Issue403 { +public class Issue403 { Comparator COMPARATOR = Comparator.comparing(w -> w.value); String value; diff --git a/checker/tests/nullness/java8/lambda/Issue436.java b/checker/tests/nullness/java8/lambda/Issue436.java index bcc6c6ee05..5710d916e0 100644 --- a/checker/tests/nullness/java8/lambda/Issue436.java +++ b/checker/tests/nullness/java8/lambda/Issue436.java @@ -3,7 +3,7 @@ import java.util.List; import java.util.function.Supplier; -class Issue436 { +public class Issue436 { public void makeALongFormConditionalLambdaReturningGenerics(boolean makeAll) { // TypeArgInferenceUtil.assignedTo used to try to use the method return rather than the // lambda return for those return statements below diff --git a/checker/tests/nullness/java8/lambda/Issue572.java b/checker/tests/nullness/java8/lambda/Issue572.java index 06c91520b0..d83bde9460 100644 --- a/checker/tests/nullness/java8/lambda/Issue572.java +++ b/checker/tests/nullness/java8/lambda/Issue572.java @@ -4,7 +4,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -class ParenthesizedLambda { +public class Issue572 { static C biApply(BiFunction f, A a, B b) { return f.apply(a, b); } diff --git a/checker/tests/nullness/java8/lambda/Issue953bLambda.java b/checker/tests/nullness/java8/lambda/Issue953bLambda.java index 1c331c62f6..49a470c961 100644 --- a/checker/tests/nullness/java8/lambda/Issue953bLambda.java +++ b/checker/tests/nullness/java8/lambda/Issue953bLambda.java @@ -7,7 +7,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; @SuppressWarnings("all") -class Issue953bLambda { +public class Issue953bLambda { private static List> strs = new ArrayList<>(); public static List<@NonNull R> mapList( diff --git a/checker/tests/nullness/java8/lambda/Initialization.java b/checker/tests/nullness/java8/lambda/LambdaInit.java similarity index 99% rename from checker/tests/nullness/java8/lambda/Initialization.java rename to checker/tests/nullness/java8/lambda/LambdaInit.java index ac8ac9f166..72bb3e1260 100644 --- a/checker/tests/nullness/java8/lambda/Initialization.java +++ b/checker/tests/nullness/java8/lambda/LambdaInit.java @@ -16,7 +16,7 @@ interface Consumer { "initialization.fields.uninitialized", "initialization.static.fields.uninitialized" }) -class LambdaInit { +public class LambdaInit { String f1; String f2 = ""; @Nullable String f3 = ""; diff --git a/checker/tests/nullness/java8/lambda/LambdaNullness.java b/checker/tests/nullness/java8/lambda/LambdaNullness.java index 96510a7f66..74377dbd71 100644 --- a/checker/tests/nullness/java8/lambda/LambdaNullness.java +++ b/checker/tests/nullness/java8/lambda/LambdaNullness.java @@ -18,7 +18,7 @@ interface BiFunctionNull { R apply(T t, U u); } -class LambdaNullness { +public class LambdaNullness { // Annotations in lamba expressions, in static, instance of fields initializers are stored on // the last declared constructor. diff --git a/checker/tests/nullness/java8/lambda/ParametersInBodyGenerics.java b/checker/tests/nullness/java8/lambda/ParametersInBodyGenerics.java index 6cd3b3b659..2d9ca73aaa 100644 --- a/checker/tests/nullness/java8/lambda/ParametersInBodyGenerics.java +++ b/checker/tests/nullness/java8/lambda/ParametersInBodyGenerics.java @@ -3,7 +3,7 @@ import java.util.List; import org.checkerframework.checker.nullness.qual.*; -class ParametersInBodyGenerics { +public class ParametersInBodyGenerics { interface NullableConsumer { void method(List<@Nullable String> s); } diff --git a/checker/tests/nullness/java8/lambda/Shadowed.java b/checker/tests/nullness/java8/lambda/Shadowed.java index 4489d82032..ff706b5ba4 100644 --- a/checker/tests/nullness/java8/lambda/Shadowed.java +++ b/checker/tests/nullness/java8/lambda/Shadowed.java @@ -10,7 +10,7 @@ interface NNConsumerS { void take(String s); } -class Shadowed { +public class Shadowed { ConsumerS c = s -> { diff --git a/checker/tests/nullness/java8/methodref/AssignmentContext.java b/checker/tests/nullness/java8/methodref/AssignmentContext.java index 250505a0ef..6c9d916872 100644 --- a/checker/tests/nullness/java8/methodref/AssignmentContext.java +++ b/checker/tests/nullness/java8/methodref/AssignmentContext.java @@ -8,7 +8,7 @@ interface FunctionAC2 { String apply(@Nullable String s); } -class AssignmentContext { +public class AssignmentContext { // Test assign FunctionAC f1 = String::toString; // :: error: (methodref.receiver.invalid) diff --git a/checker/tests/nullness/java8/methodref/FromByteCode.java b/checker/tests/nullness/java8/methodref/FromByteCode.java index 1c9a50c85a..89cb561148 100644 --- a/checker/tests/nullness/java8/methodref/FromByteCode.java +++ b/checker/tests/nullness/java8/methodref/FromByteCode.java @@ -4,7 +4,7 @@ interface FunctionBC { R apply(T t); } -class FromByteCode { +public class FromByteCode { FunctionBC f1 = String::toString; diff --git a/checker/tests/nullness/java8/methodref/Postconditions.java b/checker/tests/nullness/java8/methodref/Postconditions.java index 44ffe9069c..5dd0d9f02f 100644 --- a/checker/tests/nullness/java8/methodref/Postconditions.java +++ b/checker/tests/nullness/java8/methodref/Postconditions.java @@ -15,7 +15,7 @@ interface AssertFunc2 { boolean testParam(final @Nullable Object param); } -class AssertionTest { +public class AssertionTest { @EnsuresNonNullIf(result = true, expression = "#1") static boolean override(final @Nullable Object param) { return param != null; diff --git a/checker/tests/nullness/java8inference/InLambda.java b/checker/tests/nullness/java8inference/InLambda.java index bc9256f12d..e7ff0430fd 100644 --- a/checker/tests/nullness/java8inference/InLambda.java +++ b/checker/tests/nullness/java8inference/InLambda.java @@ -1,4 +1,4 @@ -class InLambda { +public class InLambda { static class Mine { @SuppressWarnings("nullness") // just a utility static Mine some() { diff --git a/checker/tests/nullness/java8inference/InLambdaAnnotated.java b/checker/tests/nullness/java8inference/InLambdaAnnotated.java index 42250d6f6a..f15a3ca576 100644 --- a/checker/tests/nullness/java8inference/InLambdaAnnotated.java +++ b/checker/tests/nullness/java8inference/InLambdaAnnotated.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; -class InLambdaAnnotated { +public class InLambdaAnnotated { static class Mine { @SuppressWarnings("nullness") // just a utility static Mine some() { diff --git a/checker/tests/nullness/java8inference/Inference.java b/checker/tests/nullness/java8inference/Inference.java index eaf27ee77a..7152027ce8 100644 --- a/checker/tests/nullness/java8inference/Inference.java +++ b/checker/tests/nullness/java8inference/Inference.java @@ -10,7 +10,7 @@ R collect(MyCollector collector) { interface MyCollector {} -class Inference { +public class Inference { @SuppressWarnings("nullness") static MyCollector> toImmutableStream() { diff --git a/checker/tests/nullness/java8inference/InferenceSimpler.java b/checker/tests/nullness/java8inference/InferenceSimpler.java index f8538d1cdf..909e797c7a 100644 --- a/checker/tests/nullness/java8inference/InferenceSimpler.java +++ b/checker/tests/nullness/java8inference/InferenceSimpler.java @@ -14,7 +14,7 @@ static List empty() { } } -class InferenceSimpler { +public class InferenceSimpler { List> foo() { return ISOuter.wrap(ISOuter.empty()); } diff --git a/checker/tests/nullness/java8inference/Issue1032.java b/checker/tests/nullness/java8inference/Issue1032.java index 17573cfba8..9e59e3ed4e 100644 --- a/checker/tests/nullness/java8inference/Issue1032.java +++ b/checker/tests/nullness/java8inference/Issue1032.java @@ -4,7 +4,7 @@ import java.util.stream.Stream; import org.checkerframework.checker.nullness.qual.*; -class Issue1032 { +public class Issue1032 { @SuppressWarnings("nullness") static @NonNull String castStringToNonNull(@Nullable String arg) { diff --git a/checker/tests/nullness/java8inference/Issue1084.java b/checker/tests/nullness/java8inference/Issue1084.java index 5f8e7f65b2..2c31695f51 100644 --- a/checker/tests/nullness/java8inference/Issue1084.java +++ b/checker/tests/nullness/java8inference/Issue1084.java @@ -13,7 +13,7 @@ static MyOpt of(S p) { } } -class Issue1084 { +public class Issue1084 { MyOpt get() { return this.hashCode() > 0 ? MyOpt.of(5L) : MyOpt.empty(); } diff --git a/checker/tests/nullness/java8inference/Issue1630.java b/checker/tests/nullness/java8inference/Issue1630.java index 838dc7e4c9..82ae95d79e 100644 --- a/checker/tests/nullness/java8inference/Issue1630.java +++ b/checker/tests/nullness/java8inference/Issue1630.java @@ -4,7 +4,7 @@ import java.util.stream.Collectors; import org.checkerframework.checker.nullness.qual.Nullable; -class Issue1630 { +public class Issue1630 { static @Nullable String toString(Object o) { return null; } diff --git a/checker/tests/nullness/java8inference/Issue1818.java b/checker/tests/nullness/java8inference/Issue1818.java index e1dfa57499..5f07eebce8 100644 --- a/checker/tests/nullness/java8inference/Issue1818.java +++ b/checker/tests/nullness/java8inference/Issue1818.java @@ -2,7 +2,7 @@ import java.util.function.Consumer; import org.checkerframework.checker.nullness.qual.Nullable; -class Issue1818 { +public class Issue1818 { void f() { Consumer> c = values -> values.forEach(value -> g(value)); } diff --git a/checker/tests/nullness/java8inference/Issue4048.java b/checker/tests/nullness/java8inference/Issue4048.java new file mode 100644 index 0000000000..8c5f66dba3 --- /dev/null +++ b/checker/tests/nullness/java8inference/Issue4048.java @@ -0,0 +1,20 @@ +// Test case for issue #4048: https://tinyurl.com/cfissue/4048 + +// @skip-test until the issue is fixed + +import java.util.List; +import org.checkerframework.checker.nullness.qual.Nullable; + +abstract class Issue4048 { + @Nullable Number m1(List numbers) { + return getOnlyElement1(numbers); + } + + abstract @Nullable T getOnlyElement1(Iterable values); + + @Nullable Number m2(List numbers) { + return getOnlyElement2(numbers); + } + + abstract @Nullable T getOnlyElement2(Iterable values); +} diff --git a/checker/tests/nullness/java8inference/OneOf.java b/checker/tests/nullness/java8inference/OneOf.java index b6ca22099c..2a57e313fe 100644 --- a/checker/tests/nullness/java8inference/OneOf.java +++ b/checker/tests/nullness/java8inference/OneOf.java @@ -4,7 +4,7 @@ import java.util.List; @SuppressWarnings("nullness") // don't bother with implementations -class OneOf { +public class OneOf { static List alist; static V oneof(V v1, V v2) { diff --git a/checker/tests/nullness/jdkannotations/HashtableTest.java b/checker/tests/nullness/jdkannotations/HashtableTest.java index 30416b563d..4724737f1e 100644 --- a/checker/tests/nullness/jdkannotations/HashtableTest.java +++ b/checker/tests/nullness/jdkannotations/HashtableTest.java @@ -1,7 +1,7 @@ import java.util.Hashtable; import org.checkerframework.checker.nullness.qual.Nullable; -class HashtableTest { +public class HashtableTest { public static void main(String[] args) { diff --git a/checker/tests/nullness/jdkannotations/Issue1142.java b/checker/tests/nullness/jdkannotations/Issue1142.java index fce9a401d1..0e841b5e18 100644 --- a/checker/tests/nullness/jdkannotations/Issue1142.java +++ b/checker/tests/nullness/jdkannotations/Issue1142.java @@ -3,7 +3,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.checkerframework.checker.nullness.qual.Nullable; -class Issue1142 { +public class Issue1142 { void foo() { // :: error: (type.argument.type.incompatible) diff --git a/checker/tests/nullness/jdkannotations/TreeSetTest.java b/checker/tests/nullness/jdkannotations/TreeSetTest.java index 7134c829b3..d88591ebdc 100644 --- a/checker/tests/nullness/jdkannotations/TreeSetTest.java +++ b/checker/tests/nullness/jdkannotations/TreeSetTest.java @@ -6,7 +6,7 @@ import java.util.TreeSet; import org.checkerframework.checker.nullness.qual.Nullable; -class TreeSetTest { +public class TreeSetTest { public static void main(String[] args) { diff --git a/checker/tests/optional/JdkCheck.java b/checker/tests/optional/JdkCheck.java index aff34b1107..f5008318ce 100644 --- a/checker/tests/optional/JdkCheck.java +++ b/checker/tests/optional/JdkCheck.java @@ -25,6 +25,12 @@ String orElseThrowTest2(Optional mos, Supplier excepti return mos.orElseThrow(exceptionSupplier); } + String orElseThrowTestFlow(Optional mos, Supplier exceptionSupplier) { + // :: error: (method.invocation.invalid) + mos.orElseThrow(exceptionSupplier); + return mos.get(); + } + String getTest1(@Present Optional pos) { return pos.get(); } diff --git a/checker/tests/optional/JdkCheck11.java b/checker/tests/optional/JdkCheck11.java new file mode 100644 index 0000000000..d14b67ad3c --- /dev/null +++ b/checker/tests/optional/JdkCheck11.java @@ -0,0 +1,31 @@ +// @below-java11-jdk-skip-test + +import java.util.Optional; +import org.checkerframework.checker.optional.qual.Present; + +/** Test JDK annotations, for methods added after JDK 8. */ +@SuppressWarnings("optional.parameter") +public class JdkCheck11 { + + String isEmptyTest1(Optional pos, String fallback) { + if (pos.isEmpty()) { + return fallback; + } + return pos.get(); + } + + String orElseThrowTest1(@Present Optional pos) { + return pos.orElseThrow(); + } + + String orElseThrowTest2(Optional mos) { + // :: error: (method.invocation.invalid) + return mos.orElseThrow(); + } + + String orElseThrowTestFlow(Optional mos) { + // :: error: (method.invocation.invalid) + mos.orElseThrow(); + return mos.get(); + } +} diff --git a/checker/tests/optional/Marks3a.java b/checker/tests/optional/Marks3a.java index e5a7c89b29..293b3a8e5d 100644 --- a/checker/tests/optional/Marks3a.java +++ b/checker/tests/optional/Marks3a.java @@ -23,6 +23,13 @@ String customerNameByID_acceptable(List custList, int custID) { return opt.isPresent() ? opt.get().getName() : "UNKNOWN"; } + String customerNameByID_acceptable2(List custList, int custID) { + Optional opt = custList.stream().filter(c -> c.getID() == custID).findFirst(); + + // :: warning: (prefer.map.and.orelse) + return !opt.isPresent() ? "UNKNOWN" : opt.get().getName(); + } + String customerNameByID_better(List custList, int custID) { Optional opt = custList.stream().filter(c -> c.getID() == custID).findFirst(); diff --git a/checker/tests/optional/Marks3aJdk11.java b/checker/tests/optional/Marks3aJdk11.java new file mode 100644 index 0000000000..1114afdd94 --- /dev/null +++ b/checker/tests/optional/Marks3aJdk11.java @@ -0,0 +1,27 @@ +// @below-java11-jdk-skip-test + +import java.util.List; +import java.util.Optional; + +/** + * Test case for rule #3: "Prefer alternative APIs over Optional.isPresent() and Optional.get()." + */ +public class Marks3aJdk11 { + + class Customer { + int getID() { + return 42; + } + + String getName() { + return "Fozzy Bear"; + } + } + + String customerNameByID_acceptable3(List custList, int custID) { + Optional opt = custList.stream().filter(c -> c.getID() == custID).findFirst(); + + // :: warning: (prefer.map.and.orelse) + return opt.isEmpty() ? "UNKNOWN" : opt.get().getName(); + } +} diff --git a/checker/tests/optional/Marks3bJdk11.java b/checker/tests/optional/Marks3bJdk11.java new file mode 100644 index 0000000000..0e9209390e --- /dev/null +++ b/checker/tests/optional/Marks3bJdk11.java @@ -0,0 +1,33 @@ +// @below-java11-jdk-skip-test + +import java.util.Optional; + +/** + * Test case for rule #3: "Prefer alternative APIs over Optional.isPresent() and Optional.get()." + */ +@SuppressWarnings("optional.parameter") +public class Marks3bJdk11 { + + class Task {} + + class Executor { + void runTask(Task t) {} + } + + Executor executor = new Executor(); + + void bad2(Optional oTask) { + // :: warning: (prefer.ifpresent) + if (!oTask.isEmpty()) { + executor.runTask(oTask.get()); + } + } + + void bad3(Optional oTask) { + // :: warning: (prefer.ifpresent) + if (oTask.isEmpty()) { + } else { + executor.runTask(oTask.get()); + } + } +} diff --git a/checker/tests/regex/AllowedTypes.java b/checker/tests/regex/AllowedTypes.java index 5035e5e4df..60cfd2a4e3 100644 --- a/checker/tests/regex/AllowedTypes.java +++ b/checker/tests/regex/AllowedTypes.java @@ -6,7 +6,7 @@ import javax.swing.text.Segment; import org.checkerframework.checker.regex.qual.Regex; -class AllowedTypes { +public class AllowedTypes { @Regex CharSequence cs; @Regex String s11; @Regex StringBuilder sb; diff --git a/checker/tests/regex/AnnotatedTypeParams3.java b/checker/tests/regex/AnnotatedTypeParams3.java index 1a81942ae9..065492e65c 100644 --- a/checker/tests/regex/AnnotatedTypeParams3.java +++ b/checker/tests/regex/AnnotatedTypeParams3.java @@ -2,7 +2,7 @@ import java.lang.reflect.*; import org.checkerframework.checker.regex.qual.Regex; -class AnnotatedTypeParams3 { +public class AnnotatedTypeParams3 { private T safeGetAnnotation(Field f, Class annotationClass) { T annotation; try { diff --git a/checker/tests/regex/Annotation.java b/checker/tests/regex/Annotation.java index 1f0aca5535..a0b60517db 100644 --- a/checker/tests/regex/Annotation.java +++ b/checker/tests/regex/Annotation.java @@ -6,7 +6,7 @@ String[] value(); } -class Annotation { +public class Annotation { @A1({"a", "b"}) void m1() {} diff --git a/checker/tests/regex/Continue.java b/checker/tests/regex/Continue.java index db9201036a..680996ef42 100644 --- a/checker/tests/regex/Continue.java +++ b/checker/tests/regex/Continue.java @@ -1,7 +1,7 @@ import java.util.regex.Pattern; import org.checkerframework.checker.regex.RegexUtil; -class Continue { +public class Continue { void test1(String[] a) { for (String s : a) { diff --git a/checker/tests/regex/ForEach.java b/checker/tests/regex/ForEach.java index cd023eab82..e7c90c7873 100644 --- a/checker/tests/regex/ForEach.java +++ b/checker/tests/regex/ForEach.java @@ -1,4 +1,4 @@ -class ForEach { +public class ForEach { T iterate(T[] constants) { for (T constant : constants) { return constant; diff --git a/checker/tests/regex/Issue3267.java b/checker/tests/regex/Issue3267.java index cb754a5fec..116d80057d 100644 --- a/checker/tests/regex/Issue3267.java +++ b/checker/tests/regex/Issue3267.java @@ -4,7 +4,7 @@ import java.util.regex.Pattern; import org.checkerframework.checker.regex.RegexUtil; -class Issue3267 { +public class Issue3267 { void foo(String s) { if (RegexUtil.isRegex(s)) { } else { diff --git a/checker/tests/regex/Issue809.java b/checker/tests/regex/Issue809.java index 7b2321ae17..6ce471420f 100644 --- a/checker/tests/regex/Issue809.java +++ b/checker/tests/regex/Issue809.java @@ -1,7 +1,7 @@ // Test case for issue #809: // https://github.com/typetools/checker-framework/issues/809 -class Issue809> { +public class Issue809> { K[] array; int index = 0; diff --git a/checker/tests/regex/RawTypeTest.java b/checker/tests/regex/RawTypeTest.java index 8f628cb736..0c46de16fc 100644 --- a/checker/tests/regex/RawTypeTest.java +++ b/checker/tests/regex/RawTypeTest.java @@ -4,7 +4,7 @@ import java.util.List; import org.checkerframework.checker.regex.qual.*; -class RawTypeTest { +public class RawTypeTest { public void m1(Class c) { Class x = c.asSubclass(I2.class); diff --git a/checker/tests/regex/TestIsRegex.java b/checker/tests/regex/TestIsRegex.java index 457bb2df25..735868f126 100644 --- a/checker/tests/regex/TestIsRegex.java +++ b/checker/tests/regex/TestIsRegex.java @@ -3,7 +3,7 @@ import org.checkerframework.checker.regex.RegexUtil; import org.checkerframework.checker.regex.qual.*; -class TestIsRegex { +public class TestIsRegex { void test1(String str1) throws Exception { if (!RegexUtil.isRegex(str1)) { throw new Exception(); diff --git a/checker/tests/regex/TypeParamSubtype.java b/checker/tests/regex/TypeParamSubtype.java index 35ab3af6b2..9ea6172792 100644 --- a/checker/tests/regex/TypeParamSubtype.java +++ b/checker/tests/regex/TypeParamSubtype.java @@ -1,7 +1,7 @@ import java.util.Collection; import org.checkerframework.checker.regex.qual.Regex; -class TypeParamSubtype { +public class TypeParamSubtype { // These are legal because null has type @Regex String // void nullRegexSubtype(Collection col) { // // :: error: (argument.type.incompatible) diff --git a/checker/tests/regex/WildcardInvoke.java b/checker/tests/regex/WildcardInvoke.java index 4c4cde756a..de0135bb94 100644 --- a/checker/tests/regex/WildcardInvoke.java +++ b/checker/tests/regex/WildcardInvoke.java @@ -1,4 +1,4 @@ -class WildcardInvoke { +public class WildcardInvoke { class Demo { void call(T p) {} } diff --git a/checker/tests/signedness/Issue2482.java b/checker/tests/signedness/Issue2482.java index 78c1db2548..8872f3c91e 100644 --- a/checker/tests/signedness/Issue2482.java +++ b/checker/tests/signedness/Issue2482.java @@ -1,4 +1,4 @@ -class Issue2482 { +public class Issue2482 { void regularAssignment(byte[] b, int c) { int a = b.length; diff --git a/checker/tests/signedness/Issue2483.java b/checker/tests/signedness/Issue2483.java index 9217ca9c1a..a0abf1dbd2 100644 --- a/checker/tests/signedness/Issue2483.java +++ b/checker/tests/signedness/Issue2483.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.signedness.qual.*; -class Issue2483 { +public class Issue2483 { void foo(String a, byte[] b) { @Unsigned int len = a.length(); @Unsigned int len2 = b.length; diff --git a/checker/tests/signedness/Issue2534.java b/checker/tests/signedness/Issue2534.java index 732290bb91..742f7535bc 100644 --- a/checker/tests/signedness/Issue2534.java +++ b/checker/tests/signedness/Issue2534.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.signedness.qual.Unsigned; import org.checkerframework.common.value.qual.IntRange; -class Issue2534 { +public class Issue2534 { @IntRange(from = 0, to = Integer.MAX_VALUE) int field = 3; diff --git a/checker/tests/stubparser-nullness/VarargConstructorParameterAnnotationTest.java b/checker/tests/stubparser-nullness/VarargConstructorParameterAnnotationTest.java index 797c8f6a91..fc027aa256 100644 --- a/checker/tests/stubparser-nullness/VarargConstructorParameterAnnotationTest.java +++ b/checker/tests/stubparser-nullness/VarargConstructorParameterAnnotationTest.java @@ -3,7 +3,7 @@ /* * Tests parsing annotations on parameter represented by an array or vararg to the constructor. */ -class ProcessBuilding2 { +public class VarargConstructorParameterAnnotationTest { public void strArraysNonNull(@NonNull String[] parameter) { new ProcessBuilder(parameter); diff --git a/checker/tests/tainting/ExtendsAndAnnotation.java b/checker/tests/tainting/ExtendsAndAnnotation.java index 98fee6c61e..ca030b6769 100644 --- a/checker/tests/tainting/ExtendsAndAnnotation.java +++ b/checker/tests/tainting/ExtendsAndAnnotation.java @@ -5,7 +5,7 @@ import org.checkerframework.checker.tainting.qual.Untainted; import org.checkerframework.framework.qual.HasQualifierParameter; -class ExtendsAndAnnotation extends @Tainted Object { +public class ExtendsAndAnnotation extends @Tainted Object { void test(@Untainted ExtendsAndAnnotation c) { // :: warning: (cast.unsafe.constructor.invocation) Object o = new @Untainted ExtendsAndAnnotation(); diff --git a/checker/tests/tainting/Issue2156.java b/checker/tests/tainting/Issue2156.java index 2c7fdc07a5..d34e2f1550 100644 --- a/checker/tests/tainting/Issue2156.java +++ b/checker/tests/tainting/Issue2156.java @@ -11,7 +11,7 @@ enum SampleEnum { @Tainted SECOND; } -class Issue2156 { +public class Issue2156 { void test() { requireUntainted(SampleEnum.FIRST); // :: error: assignment.type.incompatible diff --git a/checker/tests/tainting/Issue3033.java b/checker/tests/tainting/Issue3033.java index 0121211c49..7abe60e7bd 100644 --- a/checker/tests/tainting/Issue3033.java +++ b/checker/tests/tainting/Issue3033.java @@ -1,7 +1,7 @@ import org.checkerframework.checker.tainting.qual.Tainted; import org.checkerframework.checker.tainting.qual.Untainted; -class Issue3033 { +public class Issue3033 { void main() { @Tainted String a = getTainted(); diff --git a/checker/tests/tainting/Issue352.java b/checker/tests/tainting/Issue352.java index e62c392711..73c42874f8 100644 --- a/checker/tests/tainting/Issue352.java +++ b/checker/tests/tainting/Issue352.java @@ -3,10 +3,10 @@ import org.checkerframework.checker.tainting.qual.Untainted; -class Outer { +public class Issue352 { class Nested { - @Untainted Outer context(@Untainted Outer.@Untainted Nested this) { - return Outer.this; + @Untainted Issue352 context(@Untainted Issue352.@Untainted Nested this) { + return Issue352.this; } } } diff --git a/checker/tests/tainting/NestedTypeConstructor.java b/checker/tests/tainting/NestedTypeConstructor.java index 27e3b5abae..ae6b50ba7c 100644 --- a/checker/tests/tainting/NestedTypeConstructor.java +++ b/checker/tests/tainting/NestedTypeConstructor.java @@ -3,7 +3,7 @@ // Test case for Issue 275 // https://github.com/typetools/checker-framework/issues/275 // Not tainting-specific, but a convenient location. -class NestedTypeConstructor { +public class NestedTypeConstructor { class Inner { @Tainted Inner() {} } diff --git a/checker/tests/tainting/SimplePrims.java b/checker/tests/tainting/SimplePrims.java index 787879accc..b784473601 100644 --- a/checker/tests/tainting/SimplePrims.java +++ b/checker/tests/tainting/SimplePrims.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.tainting.qual.Untainted; -class SimplePrims { +public class SimplePrims { void execute(@Untainted int s) {} diff --git a/checker/tests/tainting/SimpleTainting.java b/checker/tests/tainting/SimpleTainting.java index cf6fcdb986..498b9c1193 100644 --- a/checker/tests/tainting/SimpleTainting.java +++ b/checker/tests/tainting/SimpleTainting.java @@ -1,6 +1,6 @@ import org.checkerframework.checker.tainting.qual.Untainted; -class SimpleTainting { +public class SimpleTainting { void execute(@Untainted String s) {} diff --git a/checker/tests/tainting/SubClassHasQP.java b/checker/tests/tainting/SubClassHasQP.java index 8780451e61..8a7783c609 100644 --- a/checker/tests/tainting/SubClassHasQP.java +++ b/checker/tests/tainting/SubClassHasQP.java @@ -4,7 +4,7 @@ import org.checkerframework.framework.qual.HasQualifierParameter; // @skip-test https://github.com/typetools/checker-framework/issues/3400 -class SubClassHasQP { +public class SubClassHasQP { @HasQualifierParameter(Tainted.class) static class Buffer { void append(@PolyTainted Buffer this, @PolyTainted String s) {} diff --git a/checker/tests/tainting/TestFieldPolymorphism.java b/checker/tests/tainting/TestFieldPolymorphism.java index 7fc21f4772..78d6cdea92 100644 --- a/checker/tests/tainting/TestFieldPolymorphism.java +++ b/checker/tests/tainting/TestFieldPolymorphism.java @@ -4,7 +4,7 @@ import org.checkerframework.framework.qual.HasQualifierParameter; @HasQualifierParameter(Tainted.class) -class TestFieldPolymorphism { +public class TestFieldPolymorphism { @PolyTainted String field; @PolyTainted TestFieldPolymorphism(@PolyTainted String s) { diff --git a/checker/tests/value-index-interaction/MinLenFromPositive.java b/checker/tests/value-index-interaction/MinLenFromPositive.java index 4921607d96..f14a9d556e 100644 --- a/checker/tests/value-index-interaction/MinLenFromPositive.java +++ b/checker/tests/value-index-interaction/MinLenFromPositive.java @@ -3,7 +3,7 @@ import org.checkerframework.common.value.qual.IntRange; import org.checkerframework.common.value.qual.MinLen; -class MinLenFromPositive { +public class MinLenFromPositive { public @Positive int x = 0; diff --git a/checker/tests/wpi-many/README.md b/checker/tests/wpi-many/README.md new file mode 100644 index 0000000000..0e2619e0f5 --- /dev/null +++ b/checker/tests/wpi-many/README.md @@ -0,0 +1,29 @@ +The file `testin.txt` in this directory contains a list of github repositories that +are used to test the `wpi-many.sh` script (stored in `checker/bin`). Each entry is a +git URL and commit hash, separated by whitespace. + +The projects listed in `testin.txt` are derived from plume-lib projects; each is a hard fork. +These forks have had their (inferrable) annotations removed, and their typical checker +build infrastructure disabled. The `./gradlew testWpiScripts` task defined in `checker/build.gradle` +runs the `wpi-many.sh` script on these projects, and then checks that they typecheck afterwards. + +To add a new project (named `$PROJECT` below) to `testin.txt`, follow these steps: +1. Create a new GitHub repository under your own user name with the name "wpi-many-tests-$PROJECT". +Do not initialize it with any content. +2. Clone that repo and the project you intend to add locally. +3. Copy of the contents of the project you are adding to your new repo and commit the result. +4. Run `checker/bin/remove-annotations.sh` on your new repository. (Note that `remove-annotations.sh` +needs GNU `readlink`, so it will not work by default on a Mac without installing GNU coreutils.) +5. Edit the build file of the new project and disable the Checker Framework. This is usually done +by commenting out the checkerframework-gradle-plugin and checkerFramework lines for Gradle users. +In addition, you probably will need to add `org.checkerframework:checker-qual:$LATEST-CF-VERSION` as an +`implementation` dependency. Ensure that the build still succeeds (correcting any errors) and then commit. +6. Run `wpi.sh` on the project yourself and locate any annotations that cannot be inferred by WPI and/or +any false positives from the relevant typecheckers (see `checker/build.gradle` for the list of +checkers that the `testWpiScripts` task uses). You must add annotations or warning suppressions to your +project until running `wpi.sh` on the project with those checkers produces no errors in its final iteration. +When that is the case, commit the result and note the commit hash. +7. Push the state of your new repo to GitHub. +8. Add the HTTPS version of the GitHub URL (without the `.git`!) and the commit hash you noted in step 6 +to `testin.txt`. +9. Run `./gradlew testWpiScripts` to ensure that the tests still pass, and correct any errors. diff --git a/checker/tests/wpi-many/testin.txt b/checker/tests/wpi-many/testin.txt new file mode 100644 index 0000000000..9f85443c00 --- /dev/null +++ b/checker/tests/wpi-many/testin.txt @@ -0,0 +1,3 @@ +https://github.com/kelloggm/wpi-many-tests-bcel-util f15bc9cd3f6f62bbea459663be49137a64797611 +https://github.com/kelloggm/wpi-many-tests-bibtex-clean 409461c024a3b73d68af5eb7b5861cc047794eff +https://github.com/kelloggm/wpi-many-tests-html-pretty-print c1c12d7f296061ef4c8a180c2832b29a5461e5c5 diff --git a/framework/tests/whole-program-inference/README b/checker/tests/wpi-testchecker/README similarity index 82% rename from framework/tests/whole-program-inference/README rename to checker/tests/wpi-testchecker/README index ce565ffa3a..7da3412b65 100644 --- a/framework/tests/whole-program-inference/README +++ b/checker/tests/wpi-testchecker/README @@ -7,6 +7,7 @@ cases -- no other expected errors comments should be added. The task wholeProgramInferenceTests tests the whole-program inference in three steps: + 1. The WholeProgramInferenceTest Checker will type-check all files in the "non-annotated" folder, writing the inferred types of some elements into .jaif files. The inferred types are written into .jaif files, but are not @@ -24,7 +25,7 @@ the temporary "annotated" folder. The expected error comments were removed, but the inferred types that were inserted should remove their occurrence during the type-checking. -In order to test that an error will persist even after the whole-program inference, -this expected error must be added to the "non-annotated/ExpectedErrors.java" -file. This is the only file where the expected error comments are not removed -when copied to "annotated/ExpectedErrors.java". +If an error should persist even after the whole-program inference, add the test +to the "non-annotated/ExpectedErrors.java" file. This is the only file +where the expected error comments are not removed when copied to +"annotated/ExpectedErrors.java". diff --git a/framework/tests/whole-program-inference/non-annotated/AnnotationWithFieldTest.java b/checker/tests/wpi-testchecker/non-annotated/AnnotationWithFieldTest.java similarity index 93% rename from framework/tests/whole-program-inference/non-annotated/AnnotationWithFieldTest.java rename to checker/tests/wpi-testchecker/non-annotated/AnnotationWithFieldTest.java index b6ba3b9b64..19b914b2e5 100644 --- a/framework/tests/whole-program-inference/non-annotated/AnnotationWithFieldTest.java +++ b/checker/tests/wpi-testchecker/non-annotated/AnnotationWithFieldTest.java @@ -1,4 +1,4 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.SiblingWithFields; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.SiblingWithFields; public class AnnotationWithFieldTest { diff --git a/framework/tests/whole-program-inference/non-annotated/Anonymous.java b/checker/tests/wpi-testchecker/non-annotated/Anonymous.java similarity index 63% rename from framework/tests/whole-program-inference/non-annotated/Anonymous.java rename to checker/tests/wpi-testchecker/non-annotated/Anonymous.java index 52efaa8977..cf8b343a0c 100644 --- a/framework/tests/whole-program-inference/non-annotated/Anonymous.java +++ b/checker/tests/wpi-testchecker/non-annotated/Anonymous.java @@ -1,8 +1,8 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Parent; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling2; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Top; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.WholeProgramInferenceBottom; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Parent; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling2; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Top; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.WholeProgramInferenceBottom; public class Anonymous { public static int field1; // parent diff --git a/framework/tests/whole-program-inference/non-annotated/AnonymousClassField.java b/checker/tests/wpi-testchecker/non-annotated/AnonymousClassField.java similarity index 85% rename from framework/tests/whole-program-inference/non-annotated/AnonymousClassField.java rename to checker/tests/wpi-testchecker/non-annotated/AnonymousClassField.java index 591d693c9f..e97b9ff0d9 100644 --- a/framework/tests/whole-program-inference/non-annotated/AnonymousClassField.java +++ b/checker/tests/wpi-testchecker/non-annotated/AnonymousClassField.java @@ -3,6 +3,6 @@ import java.util.*; -class AnonymousClassField { +public class AnonymousClassField { public static final List foo = new ArrayList() {}; } diff --git a/framework/tests/whole-program-inference/non-annotated/CompoundTypeTest.java b/checker/tests/wpi-testchecker/non-annotated/CompoundTypeTest.java similarity index 76% rename from framework/tests/whole-program-inference/non-annotated/CompoundTypeTest.java rename to checker/tests/wpi-testchecker/non-annotated/CompoundTypeTest.java index 533d0830fa..cda70d2878 100644 --- a/framework/tests/whole-program-inference/non-annotated/CompoundTypeTest.java +++ b/checker/tests/wpi-testchecker/non-annotated/CompoundTypeTest.java @@ -1,5 +1,5 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling2; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling2; public class CompoundTypeTest { // The default type for fields is @DefaultType. diff --git a/framework/tests/whole-program-inference/non-annotated/CompoundTypeTest2.java b/checker/tests/wpi-testchecker/non-annotated/CompoundTypeTest2.java similarity index 74% rename from framework/tests/whole-program-inference/non-annotated/CompoundTypeTest2.java rename to checker/tests/wpi-testchecker/non-annotated/CompoundTypeTest2.java index cdd18c5f4c..91fb7315d3 100644 --- a/framework/tests/whole-program-inference/non-annotated/CompoundTypeTest2.java +++ b/checker/tests/wpi-testchecker/non-annotated/CompoundTypeTest2.java @@ -1,4 +1,4 @@ -class CompoundTypeTest2 { +public class CompoundTypeTest2 { private static int[] foo = new int[10]; private static String[] bar = new String[10]; } diff --git a/framework/tests/whole-program-inference/non-annotated/ConflictingAnnotationsTest.java b/checker/tests/wpi-testchecker/non-annotated/ConflictingAnnotationsTest.java similarity index 76% rename from framework/tests/whole-program-inference/non-annotated/ConflictingAnnotationsTest.java rename to checker/tests/wpi-testchecker/non-annotated/ConflictingAnnotationsTest.java index 5a440b9a60..bebb814b13 100644 --- a/framework/tests/whole-program-inference/non-annotated/ConflictingAnnotationsTest.java +++ b/checker/tests/wpi-testchecker/non-annotated/ConflictingAnnotationsTest.java @@ -5,7 +5,7 @@ // their fully-qualified names, making namespace collisions // impossible. -class ConflictingAnnotationsTest { +public class ConflictingAnnotationsTest { int getWPINamespaceSibling1() { return getSibling1(); @@ -23,10 +23,10 @@ void test() { expectsSibling1(getWPINamespaceSibling1()); } - @org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1 int getSibling1() { + @org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1 int getSibling1() { return 1; } void expectsSibling1( - @org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1 int i) {} + @org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1 int i) {} } diff --git a/framework/tests/whole-program-inference/non-annotated/ConstructorTest.java b/checker/tests/wpi-testchecker/non-annotated/ConstructorTest.java similarity index 72% rename from framework/tests/whole-program-inference/non-annotated/ConstructorTest.java rename to checker/tests/wpi-testchecker/non-annotated/ConstructorTest.java index 34ec3ff840..46e602f34c 100644 --- a/framework/tests/whole-program-inference/non-annotated/ConstructorTest.java +++ b/checker/tests/wpi-testchecker/non-annotated/ConstructorTest.java @@ -1,4 +1,4 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Top; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Top; public class ConstructorTest { diff --git a/framework/tests/whole-program-inference/non-annotated/DefaultsTest.java b/checker/tests/wpi-testchecker/non-annotated/DefaultsTest.java similarity index 83% rename from framework/tests/whole-program-inference/non-annotated/DefaultsTest.java rename to checker/tests/wpi-testchecker/non-annotated/DefaultsTest.java index f3cff4313a..f7bd7018aa 100644 --- a/framework/tests/whole-program-inference/non-annotated/DefaultsTest.java +++ b/checker/tests/wpi-testchecker/non-annotated/DefaultsTest.java @@ -1,5 +1,5 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.DefaultType; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.WholeProgramInferenceBottom; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.DefaultType; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.WholeProgramInferenceBottom; // The @DefaultType annotation, which is the default for every location, is forbidden // to be written anywhere. This class attempts to infer @DefaultType in several diff --git a/framework/tests/whole-program-inference/non-annotated/DeviceTypeTest.java b/checker/tests/wpi-testchecker/non-annotated/DeviceTypeTest.java similarity index 100% rename from framework/tests/whole-program-inference/non-annotated/DeviceTypeTest.java rename to checker/tests/wpi-testchecker/non-annotated/DeviceTypeTest.java diff --git a/framework/tests/whole-program-inference/non-annotated/DoubleGeneric.java b/checker/tests/wpi-testchecker/non-annotated/DoubleGeneric.java similarity index 89% rename from framework/tests/whole-program-inference/non-annotated/DoubleGeneric.java rename to checker/tests/wpi-testchecker/non-annotated/DoubleGeneric.java index 8ec1eefe62..6844994e7f 100644 --- a/framework/tests/whole-program-inference/non-annotated/DoubleGeneric.java +++ b/checker/tests/wpi-testchecker/non-annotated/DoubleGeneric.java @@ -3,6 +3,6 @@ import java.util.HashMap; import java.util.Map; -class DoubleGeneric { +public class DoubleGeneric { static Map> map10 = new HashMap>(); } diff --git a/framework/tests/whole-program-inference/non-annotated/EnumConstants.java b/checker/tests/wpi-testchecker/non-annotated/EnumConstants.java similarity index 81% rename from framework/tests/whole-program-inference/non-annotated/EnumConstants.java rename to checker/tests/wpi-testchecker/non-annotated/EnumConstants.java index 9cf72be9f6..fe2bca0184 100644 --- a/framework/tests/whole-program-inference/non-annotated/EnumConstants.java +++ b/checker/tests/wpi-testchecker/non-annotated/EnumConstants.java @@ -6,9 +6,9 @@ // from how they're used. They also cannot be assigned to, // so there's no way for WPI to learn their types. -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; -class EnumConstants { +public class EnumConstants { enum MyEnum { ONE, TWO; diff --git a/framework/tests/whole-program-inference/non-annotated/EnumTest.java b/checker/tests/wpi-testchecker/non-annotated/EnumTest.java similarity index 100% rename from framework/tests/whole-program-inference/non-annotated/EnumTest.java rename to checker/tests/wpi-testchecker/non-annotated/EnumTest.java diff --git a/framework/tests/whole-program-inference/non-annotated/EnumWithInnerClass.java b/checker/tests/wpi-testchecker/non-annotated/EnumWithInnerClass.java similarity index 85% rename from framework/tests/whole-program-inference/non-annotated/EnumWithInnerClass.java rename to checker/tests/wpi-testchecker/non-annotated/EnumWithInnerClass.java index aa3a8bce12..129783d1f1 100644 --- a/framework/tests/whole-program-inference/non-annotated/EnumWithInnerClass.java +++ b/checker/tests/wpi-testchecker/non-annotated/EnumWithInnerClass.java @@ -3,7 +3,7 @@ // which was a problem with an earlier version of stub-based // WPI. -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; enum EnumWithInnerClass { CONSTANT; diff --git a/framework/tests/whole-program-inference/non-annotated/ExpectedErrors.java b/checker/tests/wpi-testchecker/non-annotated/ExpectedErrors.java similarity index 93% rename from framework/tests/whole-program-inference/non-annotated/ExpectedErrors.java rename to checker/tests/wpi-testchecker/non-annotated/ExpectedErrors.java index b8f1e62ffa..6d501ee0a6 100644 --- a/framework/tests/whole-program-inference/non-annotated/ExpectedErrors.java +++ b/checker/tests/wpi-testchecker/non-annotated/ExpectedErrors.java @@ -1,11 +1,11 @@ import java.lang.reflect.Field; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Parent; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling2; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.ToIgnore; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Top; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.WholeProgramInferenceBottom; import org.checkerframework.framework.qual.IgnoreInWholeProgramInference; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Parent; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling2; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.ToIgnore; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Top; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.WholeProgramInferenceBottom; /** * This file contains expected errors that should exist even after the jaif type inference occurs. diff --git a/framework/tests/whole-program-inference/non-annotated/IgnoreMetaAnnotationTest1.java b/checker/tests/wpi-testchecker/non-annotated/IgnoreMetaAnnotationTest1.java similarity index 73% rename from framework/tests/whole-program-inference/non-annotated/IgnoreMetaAnnotationTest1.java rename to checker/tests/wpi-testchecker/non-annotated/IgnoreMetaAnnotationTest1.java index 779520c3d2..c76f4ea443 100644 --- a/framework/tests/whole-program-inference/non-annotated/IgnoreMetaAnnotationTest1.java +++ b/checker/tests/wpi-testchecker/non-annotated/IgnoreMetaAnnotationTest1.java @@ -1,7 +1,7 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; // See ExpectedErrors#IgnoreMetaAnnotationTest2 -class IgnoreMetaAnnotationTest1 { +public class IgnoreMetaAnnotationTest1 { int field2; diff --git a/framework/tests/whole-program-inference/non-annotated/ImplicitAnnosTest.java b/checker/tests/wpi-testchecker/non-annotated/ImplicitAnnosTest.java similarity index 100% rename from framework/tests/whole-program-inference/non-annotated/ImplicitAnnosTest.java rename to checker/tests/wpi-testchecker/non-annotated/ImplicitAnnosTest.java diff --git a/framework/tests/whole-program-inference/non-annotated/InheritanceTest.java b/checker/tests/wpi-testchecker/non-annotated/InheritanceTest.java similarity index 82% rename from framework/tests/whole-program-inference/non-annotated/InheritanceTest.java rename to checker/tests/wpi-testchecker/non-annotated/InheritanceTest.java index fa1dc9207c..ed4ed59115 100644 --- a/framework/tests/whole-program-inference/non-annotated/InheritanceTest.java +++ b/checker/tests/wpi-testchecker/non-annotated/InheritanceTest.java @@ -1,4 +1,4 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.WholeProgramInferenceBottom; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.WholeProgramInferenceBottom; class IParent { int field; diff --git a/framework/tests/whole-program-inference/non-annotated/InnerTypeTest.java b/checker/tests/wpi-testchecker/non-annotated/InnerTypeTest.java similarity index 93% rename from framework/tests/whole-program-inference/non-annotated/InnerTypeTest.java rename to checker/tests/wpi-testchecker/non-annotated/InnerTypeTest.java index 01e3631407..b713d30dfc 100644 --- a/framework/tests/whole-program-inference/non-annotated/InnerTypeTest.java +++ b/checker/tests/wpi-testchecker/non-annotated/InnerTypeTest.java @@ -1,4 +1,4 @@ -class InnerTypeTest { +public class InnerTypeTest { public static String toStringQuoted(Object[] a) { return toString(a, true); } diff --git a/framework/tests/whole-program-inference/non-annotated/InnerTypeTest2.java b/checker/tests/wpi-testchecker/non-annotated/InnerTypeTest2.java similarity index 88% rename from framework/tests/whole-program-inference/non-annotated/InnerTypeTest2.java rename to checker/tests/wpi-testchecker/non-annotated/InnerTypeTest2.java index c0ada6f6d2..52e8111d4e 100644 --- a/framework/tests/whole-program-inference/non-annotated/InnerTypeTest2.java +++ b/checker/tests/wpi-testchecker/non-annotated/InnerTypeTest2.java @@ -1,4 +1,4 @@ -class InnerTypeTest2 { +public class InnerTypeTest2 { public static int[] min_max(int[] a) { if (a.length == 0) { return null; diff --git a/framework/tests/whole-program-inference/non-annotated/InnerTypeTest3.java b/checker/tests/wpi-testchecker/non-annotated/InnerTypeTest3.java similarity index 87% rename from framework/tests/whole-program-inference/non-annotated/InnerTypeTest3.java rename to checker/tests/wpi-testchecker/non-annotated/InnerTypeTest3.java index 25afc0dbdc..eb3386cc5e 100644 --- a/framework/tests/whole-program-inference/non-annotated/InnerTypeTest3.java +++ b/checker/tests/wpi-testchecker/non-annotated/InnerTypeTest3.java @@ -1,4 +1,4 @@ -class InnerTypeTest3 { +public class InnerTypeTest3 { private int[] nums; private static byte[] buffer = new byte[4096]; diff --git a/framework/tests/whole-program-inference/non-annotated/InterfaceTest.java b/checker/tests/wpi-testchecker/non-annotated/InterfaceTest.java similarity index 83% rename from framework/tests/whole-program-inference/non-annotated/InterfaceTest.java rename to checker/tests/wpi-testchecker/non-annotated/InterfaceTest.java index dbfea0fa87..5580489a3c 100644 --- a/framework/tests/whole-program-inference/non-annotated/InterfaceTest.java +++ b/checker/tests/wpi-testchecker/non-annotated/InterfaceTest.java @@ -1,6 +1,6 @@ // checks that types can be inferred for constants defined in interfaces -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; @SuppressWarnings("cast.unsafe") interface InterfaceTest { diff --git a/framework/tests/whole-program-inference/non-annotated/LUBAssignmentTest.java b/checker/tests/wpi-testchecker/non-annotated/LUBAssignmentTest.java similarity index 82% rename from framework/tests/whole-program-inference/non-annotated/LUBAssignmentTest.java rename to checker/tests/wpi-testchecker/non-annotated/LUBAssignmentTest.java index dc85d6add5..a5f7dcba10 100644 --- a/framework/tests/whole-program-inference/non-annotated/LUBAssignmentTest.java +++ b/checker/tests/wpi-testchecker/non-annotated/LUBAssignmentTest.java @@ -1,6 +1,6 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Parent; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling2; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Parent; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling2; public class LUBAssignmentTest { // The default type for fields is @DefaultType. diff --git a/framework/tests/whole-program-inference/non-annotated/LambdaReturn.java b/checker/tests/wpi-testchecker/non-annotated/LambdaReturn.java similarity index 95% rename from framework/tests/whole-program-inference/non-annotated/LambdaReturn.java rename to checker/tests/wpi-testchecker/non-annotated/LambdaReturn.java index aef1e63cee..7b24565b17 100644 --- a/framework/tests/whole-program-inference/non-annotated/LambdaReturn.java +++ b/checker/tests/wpi-testchecker/non-annotated/LambdaReturn.java @@ -3,7 +3,7 @@ import java.io.FileFilter; -class LambdaReturn { +public class LambdaReturn { void test() { FileFilter docxFilter = pathname -> { diff --git a/framework/tests/whole-program-inference/non-annotated/LocalClassTest.java b/checker/tests/wpi-testchecker/non-annotated/LocalClassTest.java similarity index 71% rename from framework/tests/whole-program-inference/non-annotated/LocalClassTest.java rename to checker/tests/wpi-testchecker/non-annotated/LocalClassTest.java index b39d470956..1c75aeabc3 100644 --- a/framework/tests/whole-program-inference/non-annotated/LocalClassTest.java +++ b/checker/tests/wpi-testchecker/non-annotated/LocalClassTest.java @@ -1,6 +1,6 @@ // test case for https://github.com/typetools/checker-framework/issues/3461 -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; public class LocalClassTest { public void method() { diff --git a/framework/tests/whole-program-inference/non-annotated/MethodDefinedInSupertype.java b/checker/tests/wpi-testchecker/non-annotated/MethodDefinedInSupertype.java similarity index 74% rename from framework/tests/whole-program-inference/non-annotated/MethodDefinedInSupertype.java rename to checker/tests/wpi-testchecker/non-annotated/MethodDefinedInSupertype.java index 5f6896181d..969e520d03 100644 --- a/framework/tests/whole-program-inference/non-annotated/MethodDefinedInSupertype.java +++ b/checker/tests/wpi-testchecker/non-annotated/MethodDefinedInSupertype.java @@ -1,5 +1,5 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Parent; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Parent; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; abstract class MethodDefinedInSupertype { diff --git a/framework/tests/whole-program-inference/non-annotated/MethodOverrideInSubtype.java b/checker/tests/wpi-testchecker/non-annotated/MethodOverrideInSubtype.java similarity index 63% rename from framework/tests/whole-program-inference/non-annotated/MethodOverrideInSubtype.java rename to checker/tests/wpi-testchecker/non-annotated/MethodOverrideInSubtype.java index 28bb2e74ab..380c482926 100644 --- a/framework/tests/whole-program-inference/non-annotated/MethodOverrideInSubtype.java +++ b/checker/tests/wpi-testchecker/non-annotated/MethodOverrideInSubtype.java @@ -1,6 +1,6 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; -class MethodOverrideInSubtype extends MethodDefinedInSupertype { +public class MethodOverrideInSubtype extends MethodDefinedInSupertype { @java.lang.Override public int shouldReturnSibling1() { return getSibling1(); diff --git a/framework/tests/whole-program-inference/non-annotated/MethodOverrideInSubtype2.java b/checker/tests/wpi-testchecker/non-annotated/MethodOverrideInSubtype2.java similarity index 73% rename from framework/tests/whole-program-inference/non-annotated/MethodOverrideInSubtype2.java rename to checker/tests/wpi-testchecker/non-annotated/MethodOverrideInSubtype2.java index 9b5f3acee7..1a7956e6a4 100644 --- a/framework/tests/whole-program-inference/non-annotated/MethodOverrideInSubtype2.java +++ b/checker/tests/wpi-testchecker/non-annotated/MethodOverrideInSubtype2.java @@ -1,4 +1,4 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling2; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling2; abstract class MethodOverrideInSubtype2 extends MethodDefinedInSupertype { diff --git a/framework/tests/whole-program-inference/non-annotated/MethodParameterInferenceTest.java b/checker/tests/wpi-testchecker/non-annotated/MethodParameterInferenceTest.java similarity index 80% rename from framework/tests/whole-program-inference/non-annotated/MethodParameterInferenceTest.java rename to checker/tests/wpi-testchecker/non-annotated/MethodParameterInferenceTest.java index 0cdfab0a7e..41130d5716 100644 --- a/framework/tests/whole-program-inference/non-annotated/MethodParameterInferenceTest.java +++ b/checker/tests/wpi-testchecker/non-annotated/MethodParameterInferenceTest.java @@ -1,4 +1,4 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; // TODO: Like this one, some tests must verify that it contains the expected // output after performing the whole-program inference. diff --git a/framework/tests/whole-program-inference/non-annotated/MethodReturnTest.java b/checker/tests/wpi-testchecker/non-annotated/MethodReturnTest.java similarity index 80% rename from framework/tests/whole-program-inference/non-annotated/MethodReturnTest.java rename to checker/tests/wpi-testchecker/non-annotated/MethodReturnTest.java index ce03d42994..cb6ff40549 100644 --- a/framework/tests/whole-program-inference/non-annotated/MethodReturnTest.java +++ b/checker/tests/wpi-testchecker/non-annotated/MethodReturnTest.java @@ -1,6 +1,6 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Parent; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling2; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Parent; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling2; public class MethodReturnTest { diff --git a/framework/tests/whole-program-inference/non-annotated/MultiDimensionalArrays.java b/checker/tests/wpi-testchecker/non-annotated/MultiDimensionalArrays.java similarity index 95% rename from framework/tests/whole-program-inference/non-annotated/MultiDimensionalArrays.java rename to checker/tests/wpi-testchecker/non-annotated/MultiDimensionalArrays.java index 193415cb32..2c01288846 100644 --- a/framework/tests/whole-program-inference/non-annotated/MultiDimensionalArrays.java +++ b/checker/tests/wpi-testchecker/non-annotated/MultiDimensionalArrays.java @@ -2,14 +2,14 @@ // are printed correctly. import java.util.List; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling2; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.SiblingWithFields; import org.checkerframework.common.aliasing.qual.MaybeAliased; import org.checkerframework.common.aliasing.qual.NonLeaked; import org.checkerframework.common.aliasing.qual.Unique; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling2; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.SiblingWithFields; -class MultiDimensionalArrays { +public class MultiDimensionalArrays { // two dimensional arrays diff --git a/framework/tests/whole-program-inference/non-annotated/MultidimensionalAnnotatedArray.java b/checker/tests/wpi-testchecker/non-annotated/MultidimensionalAnnotatedArray.java similarity index 73% rename from framework/tests/whole-program-inference/non-annotated/MultidimensionalAnnotatedArray.java rename to checker/tests/wpi-testchecker/non-annotated/MultidimensionalAnnotatedArray.java index 443f9cbd12..6b31f8539d 100644 --- a/framework/tests/whole-program-inference/non-annotated/MultidimensionalAnnotatedArray.java +++ b/checker/tests/wpi-testchecker/non-annotated/MultidimensionalAnnotatedArray.java @@ -1,6 +1,6 @@ // test case for https://github.com/typetools/checker-framework/issues/3422 -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; public class MultidimensionalAnnotatedArray { boolean[][] field = getArray(); diff --git a/framework/tests/whole-program-inference/non-annotated/NamedInnerClassInAnonymous.java b/checker/tests/wpi-testchecker/non-annotated/NamedInnerClassInAnonymous.java similarity index 87% rename from framework/tests/whole-program-inference/non-annotated/NamedInnerClassInAnonymous.java rename to checker/tests/wpi-testchecker/non-annotated/NamedInnerClassInAnonymous.java index 6136b238a5..b5498bd3ea 100644 --- a/framework/tests/whole-program-inference/non-annotated/NamedInnerClassInAnonymous.java +++ b/checker/tests/wpi-testchecker/non-annotated/NamedInnerClassInAnonymous.java @@ -1,7 +1,7 @@ // Tests whether the stub writer correctly handles named inner classes // in anonymous classes. -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; public class NamedInnerClassInAnonymous { void test() { diff --git a/framework/tests/whole-program-inference/non-annotated/OtherAnnotations.java b/checker/tests/wpi-testchecker/non-annotated/OtherAnnotations.java similarity index 88% rename from framework/tests/whole-program-inference/non-annotated/OtherAnnotations.java rename to checker/tests/wpi-testchecker/non-annotated/OtherAnnotations.java index 281188b26b..026d730798 100644 --- a/framework/tests/whole-program-inference/non-annotated/OtherAnnotations.java +++ b/checker/tests/wpi-testchecker/non-annotated/OtherAnnotations.java @@ -1,9 +1,9 @@ // Test that having other, unrelated annotations on fields/methods/etc doesn't foul up inference. +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; import org.checkerframework.common.aliasing.qual.Unique; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; -class OtherAnnotations { +public class OtherAnnotations { void requireSibling1(@Sibling1 int a) {} diff --git a/framework/tests/whole-program-inference/non-annotated/OuterClassWithTypeParam.java b/checker/tests/wpi-testchecker/non-annotated/OuterClassWithTypeParam.java similarity index 69% rename from framework/tests/whole-program-inference/non-annotated/OuterClassWithTypeParam.java rename to checker/tests/wpi-testchecker/non-annotated/OuterClassWithTypeParam.java index cf976aee1b..459aeebb3f 100644 --- a/framework/tests/whole-program-inference/non-annotated/OuterClassWithTypeParam.java +++ b/checker/tests/wpi-testchecker/non-annotated/OuterClassWithTypeParam.java @@ -1,6 +1,6 @@ // test file for https://github.com/typetools/checker-framework/issues/3438 -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; public class OuterClassWithTypeParam { public class InnerClass { diff --git a/framework/tests/whole-program-inference/non-annotated/OverloadedMethodsTest.java b/checker/tests/wpi-testchecker/non-annotated/OverloadedMethodsTest.java similarity index 70% rename from framework/tests/whole-program-inference/non-annotated/OverloadedMethodsTest.java rename to checker/tests/wpi-testchecker/non-annotated/OverloadedMethodsTest.java index e2b3033623..909b49920c 100644 --- a/framework/tests/whole-program-inference/non-annotated/OverloadedMethodsTest.java +++ b/checker/tests/wpi-testchecker/non-annotated/OverloadedMethodsTest.java @@ -1,8 +1,8 @@ // This test ensures that overloaded methods with different return types aren't confused. -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; -class OverloadedMethodsTest { +public class OverloadedMethodsTest { String f; diff --git a/framework/tests/whole-program-inference/non-annotated/OverriddenMethodsTest.java b/checker/tests/wpi-testchecker/non-annotated/OverriddenMethodsTest.java similarity index 90% rename from framework/tests/whole-program-inference/non-annotated/OverriddenMethodsTest.java rename to checker/tests/wpi-testchecker/non-annotated/OverriddenMethodsTest.java index 149f2074e9..7adfefe392 100644 --- a/framework/tests/whole-program-inference/non-annotated/OverriddenMethodsTest.java +++ b/checker/tests/wpi-testchecker/non-annotated/OverriddenMethodsTest.java @@ -1,5 +1,5 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling2; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling2; class OverriddenMethodsTestParent { public void foo(@Sibling1 Object obj, @Sibling2 Object obj2) {} diff --git a/checker/tests/wpi-testchecker/non-annotated/OverriddenMethodsTestChildInAnotherCompilationUnit.java b/checker/tests/wpi-testchecker/non-annotated/OverriddenMethodsTestChildInAnotherCompilationUnit.java new file mode 100644 index 0000000000..6a9dbe942c --- /dev/null +++ b/checker/tests/wpi-testchecker/non-annotated/OverriddenMethodsTestChildInAnotherCompilationUnit.java @@ -0,0 +1,9 @@ +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling2; + +public class OverriddenMethodsTestChildInAnotherCompilationUnit + extends OverriddenMethodsTestParent { + public void callthud(@Sibling1 Object obj1, @Sibling2 Object obj2) { + thud(obj1, obj2); + } +} diff --git a/framework/tests/whole-program-inference/non-annotated/ParameterInferenceTest.java b/checker/tests/wpi-testchecker/non-annotated/ParameterInferenceTest.java similarity index 74% rename from framework/tests/whole-program-inference/non-annotated/ParameterInferenceTest.java rename to checker/tests/wpi-testchecker/non-annotated/ParameterInferenceTest.java index 247cc0276d..1e88f1952f 100644 --- a/framework/tests/whole-program-inference/non-annotated/ParameterInferenceTest.java +++ b/checker/tests/wpi-testchecker/non-annotated/ParameterInferenceTest.java @@ -1,5 +1,5 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Parent; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Top; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Parent; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Top; public class ParameterInferenceTest { diff --git a/framework/tests/whole-program-inference/non-annotated/Planet.java b/checker/tests/wpi-testchecker/non-annotated/Planet.java similarity index 93% rename from framework/tests/whole-program-inference/non-annotated/Planet.java rename to checker/tests/wpi-testchecker/non-annotated/Planet.java index f79a1b48f8..afe0de58a9 100644 --- a/framework/tests/whole-program-inference/non-annotated/Planet.java +++ b/checker/tests/wpi-testchecker/non-annotated/Planet.java @@ -1,6 +1,6 @@ // This test checks that enums with fields and methods are handled correctly -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; @SuppressWarnings( "value" // Do not generate Value Checker annotations, because IndexFileParser cannot handle diff --git a/framework/tests/whole-program-inference/non-annotated/PublicFieldTest.java b/checker/tests/wpi-testchecker/non-annotated/PublicFieldTest.java similarity index 75% rename from framework/tests/whole-program-inference/non-annotated/PublicFieldTest.java rename to checker/tests/wpi-testchecker/non-annotated/PublicFieldTest.java index 399748200e..b49f556bc2 100644 --- a/framework/tests/whole-program-inference/non-annotated/PublicFieldTest.java +++ b/checker/tests/wpi-testchecker/non-annotated/PublicFieldTest.java @@ -1,8 +1,8 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Parent; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling2; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Top; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.WholeProgramInferenceBottom; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Parent; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling2; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Top; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.WholeProgramInferenceBottom; public class PublicFieldTest { public static int field1; // parent diff --git a/framework/tests/whole-program-inference/non-annotated/Sibling1.java b/checker/tests/wpi-testchecker/non-annotated/Sibling1.java similarity index 100% rename from framework/tests/whole-program-inference/non-annotated/Sibling1.java rename to checker/tests/wpi-testchecker/non-annotated/Sibling1.java diff --git a/framework/tests/whole-program-inference/non-annotated/StringConcatenationTest.java b/checker/tests/wpi-testchecker/non-annotated/StringConcatenationTest.java similarity index 86% rename from framework/tests/whole-program-inference/non-annotated/StringConcatenationTest.java rename to checker/tests/wpi-testchecker/non-annotated/StringConcatenationTest.java index bc32cd5753..78ccebbeff 100644 --- a/framework/tests/whole-program-inference/non-annotated/StringConcatenationTest.java +++ b/checker/tests/wpi-testchecker/non-annotated/StringConcatenationTest.java @@ -1,4 +1,4 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; public class StringConcatenationTest { diff --git a/framework/tests/whole-program-inference/non-annotated/Tempvars.java b/checker/tests/wpi-testchecker/non-annotated/Tempvars.java similarity index 100% rename from framework/tests/whole-program-inference/non-annotated/Tempvars.java rename to checker/tests/wpi-testchecker/non-annotated/Tempvars.java diff --git a/framework/tests/whole-program-inference/non-annotated/TwoMethodsSameName.java b/checker/tests/wpi-testchecker/non-annotated/TwoMethodsSameName.java similarity index 72% rename from framework/tests/whole-program-inference/non-annotated/TwoMethodsSameName.java rename to checker/tests/wpi-testchecker/non-annotated/TwoMethodsSameName.java index f4eab691cf..650753f246 100644 --- a/framework/tests/whole-program-inference/non-annotated/TwoMethodsSameName.java +++ b/checker/tests/wpi-testchecker/non-annotated/TwoMethodsSameName.java @@ -1,10 +1,10 @@ // This test makes sure that if a class has two methods with the same name, // the parameters are inferred correctly and are not confused. -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling2; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling2; -class TwoMethodsSameName { +public class TwoMethodsSameName { void test(int x, int y) { // :: error: assignment.type.incompatible diff --git a/framework/tests/whole-program-inference/non-annotated/TypeVariablesTest.java b/checker/tests/wpi-testchecker/non-annotated/TypeVariablesTest.java similarity index 79% rename from framework/tests/whole-program-inference/non-annotated/TypeVariablesTest.java rename to checker/tests/wpi-testchecker/non-annotated/TypeVariablesTest.java index ed04222a68..ce946eaa40 100644 --- a/framework/tests/whole-program-inference/non-annotated/TypeVariablesTest.java +++ b/checker/tests/wpi-testchecker/non-annotated/TypeVariablesTest.java @@ -1,6 +1,6 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Parent; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling2; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Parent; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling2; public class TypeVariablesTest { diff --git a/framework/tests/whole-program-inference/non-annotated/TypeVariablesTest2.java b/checker/tests/wpi-testchecker/non-annotated/TypeVariablesTest2.java similarity index 100% rename from framework/tests/whole-program-inference/non-annotated/TypeVariablesTest2.java rename to checker/tests/wpi-testchecker/non-annotated/TypeVariablesTest2.java diff --git a/framework/tests/whole-program-inference/non-annotated/TypeVariablesTest3.java b/checker/tests/wpi-testchecker/non-annotated/TypeVariablesTest3.java similarity index 60% rename from framework/tests/whole-program-inference/non-annotated/TypeVariablesTest3.java rename to checker/tests/wpi-testchecker/non-annotated/TypeVariablesTest3.java index 5c242dbc2b..48328207e7 100644 --- a/framework/tests/whole-program-inference/non-annotated/TypeVariablesTest3.java +++ b/checker/tests/wpi-testchecker/non-annotated/TypeVariablesTest3.java @@ -1,7 +1,7 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling2; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling2; -class Generic<@Sibling1 T extends @Sibling1 Object> { +public class TypeVariablesTest3<@Sibling1 T extends @Sibling1 Object> { public @Sibling2 T sibling2; public @Sibling1 T sibling1; diff --git a/framework/tests/whole-program-inference/non-annotated/UsesAnonymous.java b/checker/tests/wpi-testchecker/non-annotated/UsesAnonymous.java similarity index 77% rename from framework/tests/whole-program-inference/non-annotated/UsesAnonymous.java rename to checker/tests/wpi-testchecker/non-annotated/UsesAnonymous.java index 354c158b57..0701a531c3 100644 --- a/framework/tests/whole-program-inference/non-annotated/UsesAnonymous.java +++ b/checker/tests/wpi-testchecker/non-annotated/UsesAnonymous.java @@ -1,8 +1,8 @@ -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling2; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Top; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.WholeProgramInferenceBottom; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling2; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Top; +import org.checkerframework.checker.testchecker.wholeprograminference.qual.WholeProgramInferenceBottom; -class UsesAnonymous { +public class UsesAnonymous { void method() { Anonymous a = new Anonymous() { diff --git a/framework/tests/whole-program-inference/non-annotated/ValueCheck.java b/checker/tests/wpi-testchecker/non-annotated/ValueCheck.java similarity index 86% rename from framework/tests/whole-program-inference/non-annotated/ValueCheck.java rename to checker/tests/wpi-testchecker/non-annotated/ValueCheck.java index 6cce8ce1d6..c2545d1cbc 100644 --- a/framework/tests/whole-program-inference/non-annotated/ValueCheck.java +++ b/checker/tests/wpi-testchecker/non-annotated/ValueCheck.java @@ -3,10 +3,10 @@ // present in the generated files, even when there is also // an annotation from the main checker. +import org.checkerframework.checker.testchecker.wholeprograminference.qual.Sibling1; import org.checkerframework.common.value.qual.IntVal; -import org.checkerframework.framework.testchecker.wholeprograminference.qual.Sibling1; -class ValueCheck { +public class ValueCheck { // return value should be @Sibling1 @IntVal(5) int int getSibling1withValue5() { diff --git a/framework/tests/whole-program-inference/non-annotated/WildcardReturn.java b/checker/tests/wpi-testchecker/non-annotated/WildcardReturn.java similarity index 94% rename from framework/tests/whole-program-inference/non-annotated/WildcardReturn.java rename to checker/tests/wpi-testchecker/non-annotated/WildcardReturn.java index baf731d9aa..122dc6e3af 100644 --- a/framework/tests/whole-program-inference/non-annotated/WildcardReturn.java +++ b/checker/tests/wpi-testchecker/non-annotated/WildcardReturn.java @@ -5,7 +5,7 @@ import java.util.Set; import java.util.stream.Collectors; -class WildcardReturn { +public class WildcardReturn { public Set getCredentialIdsForUsername(String username) { return getRegistrationsByUsername(username).stream() .map(registration -> registration.toString()) diff --git a/dataflow/build.gradle b/dataflow/build.gradle index 4aeda7bd1f..8d6dfa14a1 100644 --- a/dataflow/build.gradle +++ b/dataflow/build.gradle @@ -1,7 +1,7 @@ dependencies { implementation project(':javacutil') implementation project(':checker-qual') - implementation 'org.plumelib:plume-util:1.1.7' + implementation 'org.plumelib:plume-util:1.3.0' } shadowJar { diff --git a/dataflow/manual/content.tex b/dataflow/manual/content.tex index e743f9939b..3eb26be35e 100644 --- a/dataflow/manual/content.tex +++ b/dataflow/manual/content.tex @@ -223,22 +223,22 @@ \subsubsubsection{CFGVisualizeLauncher} class CFGVisualizeLauncher \end{verbatim} -\subsubsection{FlowExpressions} +\subsubsection{JavaExpressions} \label{sec:flow_expressions_class} The Dataflow Framework records the abstract values of certain -expressions, called FlowExpressions: local variables, field accesses, +expressions, called JavaExpressions: local variables, field accesses, array accesses, references to \code{this}, and pure method calls. -FlowExpressions are keys in the store of abstract values. +JavaExpressions are keys in the store of abstract values. \begin{verbatim} package org.checkerframework.dataflow.analysis; -class FlowExpressions +class JavaExpressions \end{verbatim} Java expressions that appear in method pre- and postconditions are -parsed into FlowExpressions using helper routines in -\code{org.checkerframework.framework.util.FlowExpressionParseUtil}. +parsed into JavaExpressions using helper routines in +\code{org.checkerframework.framework.util.JavaExpressionParseUtil}. \subsubsection{AbstractValue} @@ -284,7 +284,7 @@ \subsubsection{Store} \label{sec:store_classes} A Store is a set of dataflow facts computed by an analysis, so it is a -mapping from FlowExpressions to AbstractValues. As with +mapping from JavaExpressions to AbstractValues. As with AbstractValues, one can take the least upper bound of two Stores. \begin{verbatim} @@ -745,9 +745,9 @@ \subsection{Formal Definition of the Control-Flow Graph} \code{ArrayAccess} & & \code{args[i]} \\ \code{FieldAccess} & & \code{f}, \code{obj.f} \\ \code{MethodAccess} & & \code{obj.hashCode} \\ - \code{ThisLiteral} & Base class of references to \code{this} & \\ - \code{ExplicitThisLiteral} & Explicit use of \code{this} in an expression & \\ - \code{ImplicitThisLiteral} & Implicit use of \code{this} in an expression & \\ + \code{This} & Base class of references to \code{this} & \\ + \code{ExplicitThis} & Explicit use of \code{this} in an expression & \\ + \code{ImplicitThis} & Implicit use of \code{this} in an expression & \\ \code{Super} & Explicit use of \code{super} in expression. & \code{super(x, y)} \\ \code{LocalVariable} & Use of a local variable, either as l-value or r-value & \\ \midrule @@ -845,16 +845,11 @@ \subsection{Formal Definition of the Control-Flow Graph} \label{tab:nodes} \end{longtable} -\autoref{tab:nodesWithException} shows all node types that can possibly throw -an exception and the exception type to be thrown. -Java class name of nodes are simplified as with \autoref{tab:nodes}. -All exception types in \autoref{tab:nodesWithException} are in package \code{java.lang}. -Considering \code{Error} such as \code{OutOfMemoryError} or \code{NoSuchFieldError}, -an exceptional edge of \code{Error} is not created except for method or -constructor invocation, assertion statement or throw statement. Because -it's not recommended to catch it due to a critical situation which is not -to able to execute JVM and handle in an application. +In theory, nearly any statement can throw an \code{Error} such as +\code{OutOfMemoryError} or \code{NoSuchFieldError}. The Dataflow Framework +does not represent all that possible flow. It only creates the exceptional +edges shown in \autoref{tab:nodesWithException}. \begin{table} \begin{tabular}{ll} @@ -868,22 +863,20 @@ \subsection{Formal Definition of the Control-Flow Graph} \code{IntegerDivision} & \code{ArithmeticException} \\ \code{IntegerRemainder} & \code{ArithmeticException} \\ \code{ObjectCreation} & \code{Throwable}, types in throws clause of the signature \\ + \code{ArrayCreation} & \code{NegativeArraySizeException}, \code{OutOfMemoryError} \\ \code{TypeCast} & \code{ClassCastException} \\ \code{Throw} & Type of \code{e} when \code{throw e} \\ \code{AssertionError} & \code{AssertionError} \\ \hline \end{tabular} - \caption{All node types that could throw Exception, and the types to be thrown.} + \caption{All node types that could throw Exception, and the types + to be thrown. + Java class name of nodes are simplified as with \autoref{tab:nodes}. + All exception types are in package \code{java.lang}.} \label{tab:nodesWithException} \end{table} -\begin{workinprogress} -ThisLiteral shouldn't be considered a literal value node, because a use of -\code{this} is not a literal expression. I would change the name and group -it with accessor expressions. -\end{workinprogress} - \begin{workinprogress} Can \code{StringConversion} be implicit? I think so, but in any event discuss. \end{workinprogress} @@ -1391,7 +1384,7 @@ \subsection{Managing Intermediate Results of the Analysis} Conceptually, the dataflow analysis computes an abstract value for -every node and flow expression\footnote{Certain dataflow analysis +every node and flow expression\footnote{Certain dataflow analyses might choose not to produce an abstract value for every node. For instance, a constant propagation analysis would only be concerned with nodes of a numerical type, and could ignore other nodes.}. The @@ -1944,7 +1937,7 @@ \subsubsubsection{Alias Information} % LocalWords: SingleSuccessorBlock RegularBlock SingleSuccessorBlockImpl % LocalWords: ExceptionBlock SpecialBlock ConditionalBlock SpecialBlocks % LocalWords: ControlFlowGraph ControlFlowGraphs CFGBuilder ast CFValue -% LocalWords: FlowExpressions AbstractValue AbstractValues PolyNull Poly +% LocalWords: JavaExpressions AbstractValue AbstractValues PolyNull Poly % LocalWords: AnnotatedTypeMirrors CFAbstractValue NullnessValue CFStore % LocalWords: NullnessCheckers CFAbstractStore InitializationStore Regex % LocalWords: NullnessStore TransferInput TransferResult TransferInputs @@ -1959,8 +1952,8 @@ \subsubsubsection{Alias Information} % LocalWords: BaseAnnotatedTypeFactory CFGSimple ValueLiteral txt % LocalWords: BooleanLiteral CharacterLiteral DoubleLiteral FloatLiteral % LocalWords: IntegerLiteral LongLiteral NullLiteral ShortLiteral args -% LocalWords: StringLiteral Accessor ArrayAccess FieldAccess ThisLiteral -% LocalWords: MethodAccess ExplicitThisLiteral ImplicitThisLiteral java +% LocalWords: StringLiteral Accessor ArrayAccess FieldAccess This +% LocalWords: MethodAccess ExplicitThis ImplicitThis java % LocalWords: LocalVariable MethodInvocation BitwiseAnd BitwiseOr MyType % LocalWords: BitwiseComplement BitwiseXor ConditionalAnd ConditionalNot % LocalWords: ConditionalOr FloatingDivision FloatingRemainder LeftShift diff --git a/dataflow/manual/examples/CFGConditionalOr2.java b/dataflow/manual/examples/CFGConditionalOr2.java index dc9b285507..09c8161570 100644 --- a/dataflow/manual/examples/CFGConditionalOr2.java +++ b/dataflow/manual/examples/CFGConditionalOr2.java @@ -1,4 +1,4 @@ -class Test { +Test { void test(boolean b1, boolean b2, boolean b3) { int x = 0; boolean b = b1 || (b2 || b3); diff --git a/dataflow/manual/examples/LiveSimple.java b/dataflow/manual/examples/LiveSimple.java index 641ac2eb4f..74c1c2dfed 100644 --- a/dataflow/manual/examples/LiveSimple.java +++ b/dataflow/manual/examples/LiveSimple.java @@ -1,4 +1,4 @@ -public class Test { +class Test { public void test() { int a = 1, b = 2, c = 3; if (a > 0) { diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/analysis/AbstractAnalysis.java b/dataflow/src/main/java/org/checkerframework/dataflow/analysis/AbstractAnalysis.java index fb440395a5..5b88dc57f4 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/analysis/AbstractAnalysis.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/analysis/AbstractAnalysis.java @@ -73,7 +73,7 @@ public abstract class AbstractAnalysis< * invariant holds: * *
    -     *   !isRunning ==> (currentNode == null)
    +     *   !isRunning ⇒ (currentNode == null)
          * 
    */ protected @InternedDistinct @Nullable Node currentNode; @@ -184,10 +184,10 @@ public AnalysisResult getResult() { @Override public @Nullable V getValue(Node n) { if (isRunning) { + assert currentNode != null + : "@AssumeAssertion(nullness): currentNode is nonull if isRunning."; // we don't have a org.checkerframework.dataflow fact about the current node yet - if (currentNode == null - || currentNode == n - || (currentTree != null && currentTree == n.getTree())) { + if (currentNode == n || (currentTree != null && currentTree == n.getTree())) { return null; } // check that 'n' is a subnode of 'node'. Check immediate operands @@ -366,8 +366,8 @@ protected final void init(ControlFlowGraph cfg) { } /** - * Initialize class fields based on a given control flow graph. Sub-class may override this - * method to initialize customized fields. + * Initialize fields of this object based on a given control flow graph. Sub-class may override + * this method to initialize customized fields. * * @param cfg a given control flow graph */ diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/analysis/Analysis.java b/dataflow/src/main/java/org/checkerframework/dataflow/analysis/Analysis.java index ed45f121e3..87e39538f5 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/analysis/Analysis.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/analysis/Analysis.java @@ -29,6 +29,17 @@ enum Direction { BACKWARD } + /** + * In calls to {@code Analysis#runAnalysisFor}, whether to return the store before or after the + * given node. + */ + public static enum BeforeOrAfter { + /** Return the pre-store. */ + BEFORE, + /** Return the post-store. */ + AFTER + } + /** * Get the direction of this analysis. * @@ -68,9 +79,8 @@ enum Direction { * the nodes. * * @param node the node to analyze - * @param before the boolean value to indicate which store to return (if it is true, return the - * store immediately before {@code node}; otherwise, the store after {@code node} is - * returned) + * @param preOrPost indicates which store to return: the store immediately before {@code node} + * or the store after {@code node} * @param blockTransferInput the transfer input of the block of this node * @param nodeValues abstract values of nodes * @param analysisCaches caches of analysis results @@ -79,7 +89,7 @@ enum Direction { */ S runAnalysisFor( Node node, - boolean before, + Analysis.BeforeOrAfter preOrPost, TransferInput blockTransferInput, IdentityHashMap nodeValues, Map, IdentityHashMap>> analysisCaches); diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/analysis/AnalysisResult.java b/dataflow/src/main/java/org/checkerframework/dataflow/analysis/AnalysisResult.java index 95ea51d9c7..2892825426 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/analysis/AnalysisResult.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/analysis/AnalysisResult.java @@ -52,7 +52,7 @@ public class AnalysisResult, S extends Store> impl /** * Caches of the analysis results for each input for the block of the node and each node. * - * @see #runAnalysisFor(Node, boolean, TransferInput, IdentityHashMap, Map) + * @see #runAnalysisFor(Node, Analysis.BeforeOrAfter, TransferInput, IdentityHashMap, Map) */ protected final Map, IdentityHashMap>> analysisCaches; @@ -281,7 +281,7 @@ public AssignmentNode getAssignForUnaryTree(UnaryTree tree) { * @return the store immediately before a given {@link Node} */ public @Nullable S getStoreBefore(Node node) { - return runAnalysisFor(node, true); + return runAnalysisFor(node, Analysis.BeforeOrAfter.BEFORE); } /** @@ -315,7 +315,11 @@ public S getStoreBefore(Block block) { return transferInput.getRegularStore(); } return analysis.runAnalysisFor( - firstNode, true, transferInput, nodeValues, analysisCaches); + firstNode, + Analysis.BeforeOrAfter.BEFORE, + transferInput, + nodeValues, + analysisCaches); default: throw new BugInCF("Unknown direction: " + analysis.getDirection()); } @@ -340,7 +344,11 @@ public S getStoreAfter(Block block) { return transferInput.getRegularStore(); } return analysis.runAnalysisFor( - lastNode, false, transferInput, nodeValues, analysisCaches); + lastNode, + Analysis.BeforeOrAfter.AFTER, + transferInput, + nodeValues, + analysisCaches); case BACKWARD: return transferInput.getRegularStore(); default: @@ -378,7 +386,7 @@ public S getStoreAfter(Block block) { * @return the store immediately after a given {@link Node} */ public @Nullable S getStoreAfter(Node node) { - return runAnalysisFor(node, false); + return runAnalysisFor(node, Analysis.BeforeOrAfter.AFTER); } /** @@ -390,20 +398,19 @@ public S getStoreAfter(Block block) { * is returned. * * @param node the node to analyze - * @param before the boolean value to indicate which store to return (if it is true, return the - * store immediately before {@code node}; otherwise, the store after {@code node} is - * returned) + * @param preOrPost indicates which store to return: the store immediately before {@code node} + * or the store after {@code node} * @return the store before or after {@code node} (depends on the value of {@code before}) after * running the analysis */ - protected @Nullable S runAnalysisFor(Node node, boolean before) { + protected @Nullable S runAnalysisFor(Node node, Analysis.BeforeOrAfter preOrPost) { Block block = node.getBlock(); assert block != null : "@AssumeAssertion(nullness): invariant"; TransferInput transferInput = stores.get(block); if (transferInput == null) { return null; } - return runAnalysisFor(node, before, transferInput, nodeValues, analysisCaches); + return runAnalysisFor(node, preOrPost, transferInput, nodeValues, analysisCaches); } /** @@ -419,9 +426,8 @@ public S getStoreAfter(Block block) { * @param the abstract value type to be tracked by the analysis * @param the store type used in the analysis * @param node the node to analyze - * @param before the boolean value to indicate which store to return (if it is true, return the - * store immediately before {@code node}; otherwise, the store after {@code node} is - * returned) + * @param preOrPost indicates which store to return: the store immediately before {@code node} + * or the store after {@code node} * @param transferInput a transfer input * @param nodeValues {@link #nodeValues} * @param analysisCaches {@link #analysisCaches} @@ -430,7 +436,7 @@ public S getStoreAfter(Block block) { */ public static , S extends Store> S runAnalysisFor( Node node, - boolean before, + Analysis.BeforeOrAfter preOrPost, TransferInput transferInput, IdentityHashMap nodeValues, Map, IdentityHashMap>> analysisCaches) { @@ -438,7 +444,7 @@ public static , S extends Store> S runAnalysisFor( throw new BugInCF("Analysis in transferInput cannot be null."); } return transferInput.analysis.runAnalysisFor( - node, before, transferInput, nodeValues, analysisCaches); + node, preOrPost, transferInput, nodeValues, analysisCaches); } /** diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/analysis/BackwardAnalysisImpl.java b/dataflow/src/main/java/org/checkerframework/dataflow/analysis/BackwardAnalysisImpl.java index 1d77314aa9..7449957906 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/analysis/BackwardAnalysisImpl.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/analysis/BackwardAnalysisImpl.java @@ -316,7 +316,7 @@ protected void addStoreAfter(Block pred, @Nullable Node node, S s, boolean addBl @Override public S runAnalysisFor( @FindDistinct Node node, - boolean before, + Analysis.BeforeOrAfter preOrPost, TransferInput blockTransferInput, IdentityHashMap nodeValues, Map, IdentityHashMap>> analysisCaches) { @@ -341,7 +341,7 @@ public S runAnalysisFor( while (reverseIter.hasPrevious()) { Node n = reverseIter.previous(); setCurrentNode(n); - if (n == node && !before) { + if (n == node && preOrPost == Analysis.BeforeOrAfter.AFTER) { return store.getRegularStore(); } // Copy the store to avoid changing other blocks' transfer inputs in @@ -365,7 +365,7 @@ public S runAnalysisFor( + "\teb.getNode(): " + eb.getNode()); } - if (!before) { + if (preOrPost == Analysis.BeforeOrAfter.AFTER) { return blockTransferInput.getRegularStore(); } setCurrentNode(node); diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/analysis/ConditionalTransferResult.java b/dataflow/src/main/java/org/checkerframework/dataflow/analysis/ConditionalTransferResult.java index 61a7d12a56..bd85da0f59 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/analysis/ConditionalTransferResult.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/analysis/ConditionalTransferResult.java @@ -4,7 +4,7 @@ import java.util.StringJoiner; import javax.lang.model.type.TypeMirror; import org.checkerframework.checker.nullness.qual.Nullable; -import org.plumelib.util.UtilPlume; +import org.plumelib.util.StringsPlume; /** * Implementation of a {@link TransferResult} with two non-exceptional stores. The 'then' store @@ -142,9 +142,9 @@ public boolean containsTwoStores() { public String toString() { StringJoiner result = new StringJoiner(System.lineSeparator()); result.add("RegularTransferResult("); - result.add(" resultValue = " + UtilPlume.indentLinesExceptFirst(2, resultValue)); - result.add(" thenStore = " + UtilPlume.indentLinesExceptFirst(2, thenStore)); - result.add(" elseStore = " + UtilPlume.indentLinesExceptFirst(2, elseStore)); + result.add(" resultValue = " + StringsPlume.indentLinesExceptFirst(2, resultValue)); + result.add(" thenStore = " + StringsPlume.indentLinesExceptFirst(2, thenStore)); + result.add(" elseStore = " + StringsPlume.indentLinesExceptFirst(2, elseStore)); result.add(")"); return result.toString(); } diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/analysis/ForwardAnalysisImpl.java b/dataflow/src/main/java/org/checkerframework/dataflow/analysis/ForwardAnalysisImpl.java index 696f972113..425b509ea2 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/analysis/ForwardAnalysisImpl.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/analysis/ForwardAnalysisImpl.java @@ -238,7 +238,7 @@ public void performAnalysisBlock(Block b) { @Override public S runAnalysisFor( @FindDistinct Node node, - boolean before, + Analysis.BeforeOrAfter preOrPost, TransferInput blockTransferInput, IdentityHashMap nodeValues, Map, IdentityHashMap>> analysisCaches) { @@ -275,7 +275,7 @@ public S runAnalysisFor( TransferResult transferResult; for (Node n : rb.getNodes()) { setCurrentNode(n); - if (n == node && before) { + if (n == node && preOrPost == Analysis.BeforeOrAfter.BEFORE) { return store.getRegularStore(); } if (cache != null && cache.containsKey(n)) { @@ -306,7 +306,7 @@ public S runAnalysisFor( + "\teb.getNode(): " + eb.getNode()); } - if (before) { + if (preOrPost == Analysis.BeforeOrAfter.BEFORE) { return blockTransferInput.getRegularStore(); } setCurrentNode(node); diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/analysis/RegularTransferResult.java b/dataflow/src/main/java/org/checkerframework/dataflow/analysis/RegularTransferResult.java index 3b33c22e77..fbbfd371b5 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/analysis/RegularTransferResult.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/analysis/RegularTransferResult.java @@ -4,7 +4,7 @@ import java.util.StringJoiner; import javax.lang.model.type.TypeMirror; import org.checkerframework.checker.nullness.qual.Nullable; -import org.plumelib.util.UtilPlume; +import org.plumelib.util.StringsPlume; /** * Implementation of a {@link TransferResult} with just one non-exceptional store. The result of @@ -136,10 +136,12 @@ public boolean containsTwoStores() { public String toString() { StringJoiner result = new StringJoiner(System.lineSeparator()); result.add("RegularTransferResult("); - result.add(" resultValue = " + UtilPlume.indentLinesExceptFirst(2, resultValue)); + result.add(" resultValue = " + StringsPlume.indentLinesExceptFirst(2, resultValue)); // "toString().trim()" works around bug where toString ends with a newline. result.add( - " store = " + UtilPlume.indentLinesExceptFirst(2, store.toString().trim()) + ")"); + " store = " + + StringsPlume.indentLinesExceptFirst(2, store.toString().trim()) + + ")"); return result.toString(); } diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/analysis/Store.java b/dataflow/src/main/java/org/checkerframework/dataflow/analysis/Store.java index aae08b6492..656ced5dc9 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/analysis/Store.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/analysis/Store.java @@ -1,7 +1,7 @@ package org.checkerframework.dataflow.analysis; import org.checkerframework.dataflow.cfg.visualize.CFGVisualizer; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; /** * A store is used to keep track of the information that the org.checkerframework.dataflow analysis @@ -95,7 +95,7 @@ public static enum FlowRule { * Can the objects {@code a} and {@code b} be aliases? Returns a conservative answer (i.e., * returns {@code true} if not enough information is available to determine aliasing). */ - boolean canAlias(Receiver a, Receiver b); + boolean canAlias(JavaExpression a, JavaExpression b); /** * Delegate visualization responsibility to a visualizer. diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/analysis/TransferInput.java b/dataflow/src/main/java/org/checkerframework/dataflow/analysis/TransferInput.java index cc09e16e77..4c57c5c975 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/analysis/TransferInput.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/analysis/TransferInput.java @@ -5,8 +5,8 @@ import org.checkerframework.checker.initialization.qual.UnknownInitialization; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.cfg.node.Node; +import org.plumelib.util.StringsPlume; import org.plumelib.util.UniqueId; -import org.plumelib.util.UtilPlume; /** * {@code TransferInput} is used as the input type of the individual transfer functions of a {@link @@ -303,11 +303,11 @@ public int hashCode() { public String toString() { if (store == null) { return "[then=" - + UtilPlume.indentLinesExceptFirst(2, thenStore) + + StringsPlume.indentLinesExceptFirst(2, thenStore) + "," + System.lineSeparator() + " else=" - + UtilPlume.indentLinesExceptFirst(2, elseStore) + + StringsPlume.indentLinesExceptFirst(2, elseStore) + "]"; } else { return "[" + store + "]"; diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/UnderlyingAST.java b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/UnderlyingAST.java index f0071867c1..f55a29f2b6 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/UnderlyingAST.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/UnderlyingAST.java @@ -6,8 +6,8 @@ import com.sun.source.tree.Tree; import java.util.concurrent.atomic.AtomicLong; import org.checkerframework.checker.initialization.qual.UnknownInitialization; +import org.plumelib.util.StringsPlume; import org.plumelib.util.UniqueId; -import org.plumelib.util.UtilPlume; /** * Represents an abstract syntax tree of type {@link Tree} that underlies a given control flow @@ -83,7 +83,7 @@ public MethodTree getMethod() { } /** - * Returns the name of the method + * Returns the name of the method. * * @return the name of the method */ @@ -111,7 +111,7 @@ public String getSimpleClassName() { @Override public String toString() { - return UtilPlume.joinLines("CFGMethod(", method, ")"); + return StringsPlume.joinLines("CFGMethod(", method, ")"); } } @@ -193,7 +193,7 @@ public String getMethodName() { @Override public String toString() { - return UtilPlume.joinLines("CFGLambda(", lambda, ")"); + return StringsPlume.joinLines("CFGLambda(", lambda, ")"); } } @@ -231,7 +231,7 @@ public String getSimpleClassName() { @Override public String toString() { - return UtilPlume.joinLines("CFGStatement(", code, ")"); + return StringsPlume.joinLines("CFGStatement(", code, ")"); } } } diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/builder/CFGTranslationPhaseOne.java b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/builder/CFGTranslationPhaseOne.java index c7dd3b6c25..500940ff5d 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/builder/CFGTranslationPhaseOne.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/builder/CFGTranslationPhaseOne.java @@ -110,7 +110,7 @@ import org.checkerframework.dataflow.cfg.node.ConditionalOrNode; import org.checkerframework.dataflow.cfg.node.DoubleLiteralNode; import org.checkerframework.dataflow.cfg.node.EqualToNode; -import org.checkerframework.dataflow.cfg.node.ExplicitThisLiteralNode; +import org.checkerframework.dataflow.cfg.node.ExplicitThisNode; import org.checkerframework.dataflow.cfg.node.FieldAccessNode; import org.checkerframework.dataflow.cfg.node.FloatLiteralNode; import org.checkerframework.dataflow.cfg.node.FloatingDivisionNode; @@ -118,7 +118,7 @@ import org.checkerframework.dataflow.cfg.node.FunctionalInterfaceNode; import org.checkerframework.dataflow.cfg.node.GreaterThanNode; import org.checkerframework.dataflow.cfg.node.GreaterThanOrEqualNode; -import org.checkerframework.dataflow.cfg.node.ImplicitThisLiteralNode; +import org.checkerframework.dataflow.cfg.node.ImplicitThisNode; import org.checkerframework.dataflow.cfg.node.InstanceOfNode; import org.checkerframework.dataflow.cfg.node.IntegerDivisionNode; import org.checkerframework.dataflow.cfg.node.IntegerLiteralNode; @@ -155,7 +155,7 @@ import org.checkerframework.dataflow.cfg.node.SuperNode; import org.checkerframework.dataflow.cfg.node.SynchronizedNode; import org.checkerframework.dataflow.cfg.node.TernaryExpressionNode; -import org.checkerframework.dataflow.cfg.node.ThisLiteralNode; +import org.checkerframework.dataflow.cfg.node.ThisNode; import org.checkerframework.dataflow.cfg.node.ThrowNode; import org.checkerframework.dataflow.cfg.node.TypeCastNode; import org.checkerframework.dataflow.cfg.node.UnsignedRightShiftNode; @@ -297,21 +297,28 @@ public class CFGTranslationPhaseOne extends TreePathScanner { /** The ArithmeticException type. */ final TypeMirror arithmeticExceptionType; - /** The AssertionError type. */ - final TypeMirror assertionErrorType; - /** The ArrayIndexOutOfBoundsException type */ + /** The ArrayIndexOutOfBoundsException type. */ final TypeMirror arrayIndexOutOfBoundsExceptionType; + /** The AssertionError type. */ + final TypeMirror assertionErrorType; + /** The ClassCastException type . */ final TypeMirror classCastExceptionType; - /** The (erased) Iterable type . */ + /** The Iterable type (erased). */ final TypeMirror iterableType; + /** The NegativeArraySizeException type. */ + final TypeMirror negativeArraySizeExceptionType; + /** The NullPointerException type . */ final TypeMirror nullPointerExceptionType; + /** The OutOfMemoryError type. */ + final TypeMirror outOfMemoryErrorType; + /** The String type. */ final TypeMirror stringType; @@ -366,7 +373,9 @@ public CFGTranslationPhaseOne( assertionErrorType = getTypeMirror(AssertionError.class); classCastExceptionType = getTypeMirror(ClassCastException.class); iterableType = types.erasure(getTypeMirror(Iterable.class)); + negativeArraySizeExceptionType = getTypeMirror(NegativeArraySizeException.class); nullPointerExceptionType = getTypeMirror(NullPointerException.class); + outOfMemoryErrorType = getTypeMirror(OutOfMemoryError.class); stringType = getTypeMirror(String.class); throwableType = getTypeMirror(Throwable.class); } @@ -1272,7 +1281,7 @@ public MethodInvocationNode visitMethodInvocation(MethodInvocationTree tree, Voi MethodAccessNode target = new MethodAccessNode(methodSelect, receiver); ExecutableElement element = TreeUtils.elementFromUse(tree); - if (ElementUtils.isStatic(element) || receiver instanceof ThisLiteralNode) { + if (ElementUtils.isStatic(element) || receiver instanceof ThisNode) { // No NullPointerException can be thrown, use normal node extendWithNode(target); } else { @@ -1454,7 +1463,7 @@ public Node visitAssignment(AssignmentTree tree, Void p) { target.setLValue(); Element element = TreeUtils.elementFromUse(variable); - if (ElementUtils.isStatic(element) || receiver instanceof ThisLiteralNode) { + if (ElementUtils.isStatic(element) || receiver instanceof ThisNode) { // No NullPointerException can be thrown, use normal node extendWithNode(target); } else { @@ -1515,7 +1524,7 @@ private Node getReceiver(ExpressionTree tree) { extendWithNode(node); return node; } else { - Node node = new ImplicitThisLiteralNode(type); + Node node = new ImplicitThisNode(type); extendWithNode(node); return node; } @@ -2426,10 +2435,18 @@ public Node visitEnhancedForLoop(EnhancedForLoopTree tree, Void p) { MethodInvocationNode nextCallNode = new MethodInvocationNode( nextCall, nextAccessNode, Collections.emptyList(), getCurrentPath()); + // If the type of iteratorVariable is a capture, its type tree may be missing + // annotations, so save the expression in the node so that the full type can be found + // later. + nextCallNode.setIterableExpression(expression); nextCallNode.setInSource(false); extendWithNode(nextCallNode); - translateAssignment(variable, new LocalVariableNode(variable), nextCall); + AssignmentNode assignNode = + translateAssignment(variable, new LocalVariableNode(variable), nextCall); + // translateAssignment() scans variable and creates new nodes, so set the expression + // there, too. + ((MethodInvocationNode) assignNode.getExpression()).setIterableExpression(expression); assert statement != null; scan(statement, p); @@ -2669,7 +2686,7 @@ public Node visitIdentifier(IdentifierTree tree, Void p) { case FIELD: // Note that "this"/"super" is a field, but not a field access. if (element.getSimpleName().contentEquals("this")) { - node = new ExplicitThisLiteralNode(tree); + node = new ExplicitThisNode(tree); } else { node = new SuperNode(tree); } @@ -2837,7 +2854,14 @@ public Node visitNewArray(NewArrayTree tree, Void p) { } Node node = new ArrayCreationNode(tree, type, dimensionNodes, initializerNodes); - extendWithNode(node); + + Set thrownSet = new HashSet<>(); + // List of exceptions comes from JLS 15.10.1 "Run-Time Evaluation of Array Creation + // Expressions". + thrownSet.add(negativeArraySizeExceptionType); + thrownSet.add(outOfMemoryErrorType); + + extendWithNodeWithExceptions(node, thrownSet); return node; } @@ -2941,7 +2965,7 @@ public Node visitMemberSelect(MemberSelectTree tree, Void p) { if (!TreeUtils.isFieldAccess(tree)) { // Could be a selector of a class or package Element element = TreeUtils.elementFromUse(tree); - if (ElementUtils.isClassElement(element)) { + if (ElementUtils.isTypeElement(element)) { Node result = new ClassNameNode(tree, expr); extendWithNode(result); return result; @@ -2958,8 +2982,8 @@ public Node visitMemberSelect(MemberSelectTree tree, Void p) { Element element = TreeUtils.elementFromUse(tree); if (ElementUtils.isStatic(element) - || expr instanceof ImplicitThisLiteralNode - || expr instanceof ExplicitThisLiteralNode) { + || expr instanceof ImplicitThisNode + || expr instanceof ExplicitThisNode) { // No NullPointerException can be thrown, use normal node extendWithNode(node); } else { @@ -3016,13 +3040,6 @@ public Node visitTry(TryTree tree, Void p) { "start of try statement #" + TreeUtils.treeUids.get(tree), env.getTypeUtils())); - // TODO: Should we handle try-with-resources blocks by also generating code - // for automatically closing the resources? - List resources = tree.getResources(); - for (Tree resource : resources) { - scan(resource, p); - } - List> catchLabels = new ArrayList<>(); for (CatchTree c : catches) { TypeMirror type = TreeUtils.typeOf(c.getParameter().getType()); @@ -3059,6 +3076,15 @@ public Node visitTry(TryTree tree, Void p) { tryStack.pushFrame(new TryCatchFrame(types, catchLabels)); + // Must scan the resources *after* we push frame to tryStack. Otherwise we can + // lose catch blocks. + // TODO: Should we handle try-with-resources blocks by also generating code + // for automatically closing the resources? + List resources = tree.getResources(); + for (Tree resource : resources) { + scan(resource, p); + } + extendWithNode( new MarkerNode( tree, @@ -3527,7 +3553,7 @@ public Node visitVariable(VariableTree tree, Void p) { ClassTree enclosingClass = TreeUtils.enclosingClass(getCurrentPath()); TypeElement classElem = TreeUtils.elementFromDeclaration(enclosingClass); - Node receiver = new ImplicitThisLiteralNode(classElem.asType()); + Node receiver = new ImplicitThisNode(classElem.asType()); if (isField) { ExpressionTree initializer = tree.getInitializer(); diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/AbstractNodeVisitor.java b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/AbstractNodeVisitor.java index a4bde3e343..613ea62186 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/AbstractNodeVisitor.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/AbstractNodeVisitor.java @@ -246,18 +246,18 @@ public R visitArrayAccess(ArrayAccessNode n, P p) { return visitNode(n, p); } - public R visitThisLiteral(ThisLiteralNode n, P p) { + public R visitThis(ThisNode n, P p) { return visitNode(n, p); } @Override - public R visitImplicitThisLiteral(ImplicitThisLiteralNode n, P p) { - return visitThisLiteral(n, p); + public R visitImplicitThis(ImplicitThisNode n, P p) { + return visitThis(n, p); } @Override - public R visitExplicitThisLiteral(ExplicitThisLiteralNode n, P p) { - return visitThisLiteral(n, p); + public R visitExplicitThis(ExplicitThisNode n, P p) { + return visitThis(n, p); } @Override diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ArrayCreationNode.java b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ArrayCreationNode.java index f712b2b08c..9d6d37684d 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ArrayCreationNode.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ArrayCreationNode.java @@ -8,7 +8,7 @@ import java.util.Objects; import javax.lang.model.type.TypeMirror; import org.checkerframework.checker.nullness.qual.Nullable; -import org.plumelib.util.UtilPlume; +import org.plumelib.util.StringsPlume; /** * A node for new array creation. @@ -74,12 +74,12 @@ public String toString() { sb.append("new " + type); if (!dimensions.isEmpty()) { sb.append(" ("); - sb.append(UtilPlume.join(", ", dimensions)); + sb.append(StringsPlume.join(", ", dimensions)); sb.append(")"); } if (!initializers.isEmpty()) { sb.append(" = {"); - sb.append(UtilPlume.join(", ", initializers)); + sb.append(StringsPlume.join(", ", initializers)); sb.append("}"); } return sb.toString(); diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ExplicitThisLiteralNode.java b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ExplicitThisNode.java similarity index 80% rename from dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ExplicitThisLiteralNode.java rename to dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ExplicitThisNode.java index 6beb50d43b..b77399a1a1 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ExplicitThisLiteralNode.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ExplicitThisNode.java @@ -11,11 +11,11 @@ * this * */ -public class ExplicitThisLiteralNode extends ThisLiteralNode { +public class ExplicitThisNode extends ThisNode { protected final Tree tree; - public ExplicitThisLiteralNode(Tree t) { + public ExplicitThisNode(Tree t) { super(TreeUtils.typeOf(t)); assert t instanceof IdentifierTree && ((IdentifierTree) t).getName().contentEquals("this"); tree = t; @@ -28,7 +28,7 @@ public Tree getTree() { @Override public R accept(NodeVisitor visitor, P p) { - return visitor.visitExplicitThisLiteral(this, p); + return visitor.visitExplicitThis(this, p); } @Override diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ImplicitThisLiteralNode.java b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ImplicitThisNode.java similarity index 75% rename from dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ImplicitThisLiteralNode.java rename to dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ImplicitThisNode.java index 9f984fb5b4..efceb3194e 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ImplicitThisLiteralNode.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ImplicitThisNode.java @@ -5,9 +5,9 @@ import org.checkerframework.checker.nullness.qual.Nullable; /** A node to model the implicit {@code this}, e.g., in a field access. */ -public class ImplicitThisLiteralNode extends ThisLiteralNode { +public class ImplicitThisNode extends ThisNode { - public ImplicitThisLiteralNode(TypeMirror type) { + public ImplicitThisNode(TypeMirror type) { super(type); } @@ -18,7 +18,7 @@ public ImplicitThisLiteralNode(TypeMirror type) { @Override public R accept(NodeVisitor visitor, P p) { - return visitor.visitImplicitThisLiteral(this, p); + return visitor.visitImplicitThis(this, p); } @Override diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/MethodInvocationNode.java b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/MethodInvocationNode.java index cd50cabae3..39daa05ea2 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/MethodInvocationNode.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/MethodInvocationNode.java @@ -1,16 +1,18 @@ package org.checkerframework.dataflow.cfg.node; +import com.sun.source.tree.ExpressionTree; import com.sun.source.tree.MethodInvocationTree; import com.sun.source.tree.Tree; import com.sun.source.util.TreePath; import java.util.ArrayList; import java.util.Collection; +import java.util.Iterator; import java.util.List; import java.util.Objects; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.cfg.node.AssignmentContext.MethodParameterContext; import org.checkerframework.javacutil.TreeUtils; -import org.plumelib.util.UtilPlume; +import org.plumelib.util.StringsPlume; /** * A node for method invocation. @@ -26,17 +28,35 @@ public class MethodInvocationNode extends Node { /** The tree for the method invocation. */ protected final @Nullable MethodInvocationTree tree; + /** * The target of the method invocation -- that is, the receiver. For a static method, may be a * class name. */ protected final MethodAccessNode target; + /** The arguments of the method invocation. */ protected final List arguments; + /** The tree path to the method invocation. */ protected final TreePath treePath; - /** Create a MethodInvocationNode. */ + /** + * If this MethodInvocationNode is a node for an {@link Iterator#next()} desugared from an + * enhanced for loop, then the {@code iterExpression} field is the expression in the for loop, + * e.g., {@code iter} in {@code for(Object o: iter}. + */ + protected @Nullable ExpressionTree iterableExpression; + + /** + * Create a MethodInvocationNode. + * + * @param tree for the method invocation + * @param target of the method invocation -- that is, the receiver. For a static method, may be + * a class name. + * @param arguments arguments of the method invocation + * @param treePath path to the method invocation + */ public MethodInvocationNode( @Nullable MethodInvocationTree tree, MethodAccessNode target, @@ -76,6 +96,28 @@ public TreePath getTreePath() { return treePath; } + /** + * If this MethodInvocationNode is a node for an {@link Iterator#next()} desugared from an + * enhanced for loop, then return the expression in the for loop, e.g., {@code iter} in {@code + * for(Object o: iter}. Otherwise, return null. + * + * @return the iter expression, or null if this is not a {@link Iterator#next()} from an + * enhanced for loop + */ + public @Nullable ExpressionTree getIterableExpression() { + return iterableExpression; + } + + /** + * Set the iterable expression from a for loop. + * + * @param iterableExpression iterable expression + * @see #getIterableExpression() + */ + public void setIterableExpression(@Nullable ExpressionTree iterableExpression) { + this.iterableExpression = iterableExpression; + } + @Override public @Nullable MethodInvocationTree getTree() { return tree; @@ -88,7 +130,7 @@ public R accept(NodeVisitor visitor, P p) { @Override public String toString() { - return target + "(" + UtilPlume.join(", ", arguments) + ")"; + return target + "(" + StringsPlume.join(", ", arguments) + ")"; } @Override diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/Node.java b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/Node.java index dc7f219728..a6d06b0c71 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/Node.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/Node.java @@ -102,7 +102,7 @@ public void setBlock(Block b) { /** * Returns the {@link Tree} in the abstract syntax tree, or {@code null} if no corresponding - * tree exists. For instance, this is the case for an {@link ImplicitThisLiteralNode}. + * tree exists. For instance, this is the case for an {@link ImplicitThisNode}. * * @return the corresponding {@link Tree} or {@code null}. */ diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/NodeVisitor.java b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/NodeVisitor.java index c3d665938a..08c1c231c8 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/NodeVisitor.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/NodeVisitor.java @@ -103,9 +103,9 @@ public interface NodeVisitor { R visitArrayAccess(ArrayAccessNode n, P p); - R visitImplicitThisLiteral(ImplicitThisLiteralNode n, P p); + R visitImplicitThis(ImplicitThisNode n, P p); - R visitExplicitThisLiteral(ExplicitThisLiteralNode n, P p); + R visitExplicitThis(ExplicitThisNode n, P p); R visitSuper(SuperNode n, P p); diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ObjectCreationNode.java b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ObjectCreationNode.java index 1e525aff66..dae3edbacd 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ObjectCreationNode.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ObjectCreationNode.java @@ -5,9 +5,10 @@ import java.util.Collection; import java.util.List; import java.util.Objects; +import javax.lang.model.element.ExecutableElement; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.javacutil.TreeUtils; -import org.plumelib.util.UtilPlume; +import org.plumelib.util.StringsPlume; /** * A node for new object creation. @@ -35,6 +36,16 @@ public ObjectCreationNode( this.constructor = constructor; this.arguments = arguments; this.classbody = classbody; + + // set assignment contexts for parameters + int i = 0; + ExecutableElement elem = TreeUtils.elementFromUse(tree); + if (elem != null) { + for (Node arg : arguments) { + AssignmentContext ctx = new AssignmentContext.MethodParameterContext(elem, i++); + arg.setAssignmentContext(ctx); + } + } } public Node getConstructor() { @@ -67,7 +78,7 @@ public R accept(NodeVisitor visitor, P p) { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("new " + constructor + "("); - sb.append(UtilPlume.join(", ", arguments)); + sb.append(StringsPlume.join(", ", arguments)); sb.append(")"); if (classbody != null) { // TODO: maybe this can be done nicer... diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ThisLiteralNode.java b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ThisNode.java similarity index 82% rename from dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ThisLiteralNode.java rename to dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ThisNode.java index a6fc55fcff..be8280311e 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ThisLiteralNode.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/node/ThisNode.java @@ -13,9 +13,9 @@ * this * */ -public abstract class ThisLiteralNode extends Node { +public abstract class ThisNode extends Node { - protected ThisLiteralNode(TypeMirror type) { + protected ThisNode(TypeMirror type) { super(type); } @@ -25,7 +25,7 @@ public String getName() { @Override public boolean equals(@Nullable Object obj) { - return obj instanceof ThisLiteralNode; + return obj instanceof ThisNode; } @Override diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/visualize/AbstractCFGVisualizer.java b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/visualize/AbstractCFGVisualizer.java index 5a7b03d58a..daa36a0bea 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/cfg/visualize/AbstractCFGVisualizer.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/cfg/visualize/AbstractCFGVisualizer.java @@ -26,8 +26,8 @@ import org.checkerframework.dataflow.cfg.block.SpecialBlock; import org.checkerframework.dataflow.cfg.node.Node; import org.checkerframework.javacutil.BugInCF; +import org.plumelib.util.StringsPlume; import org.plumelib.util.UniqueId; -import org.plumelib.util.UtilPlume; /** * This abstract class makes implementing a {@link CFGVisualizer} easier. Some of the methods in @@ -456,7 +456,7 @@ protected abstract String visualizeNodes( * @return a String representation of the given process orders */ protected String getProcessOrderSimpleString(List order) { - return "Process order: " + UtilPlume.join(",", order); + return "Process order: " + StringsPlume.join(",", order); } /** diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationStore.java b/dataflow/src/main/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationStore.java index 8983c69099..8c4099e91b 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationStore.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/constantpropagation/ConstantPropagationStore.java @@ -8,7 +8,7 @@ import org.checkerframework.dataflow.cfg.node.LocalVariableNode; import org.checkerframework.dataflow.cfg.node.Node; import org.checkerframework.dataflow.cfg.visualize.CFGVisualizer; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; public class ConstantPropagationStore implements Store { @@ -152,7 +152,7 @@ public String toString() { } @Override - public boolean canAlias(Receiver a, Receiver b) { + public boolean canAlias(JavaExpression a, JavaExpression b) { return true; } diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/ArrayAccess.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/ArrayAccess.java index 68e9a98711..215ca78b7c 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/ArrayAccess.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/ArrayAccess.java @@ -6,19 +6,19 @@ import org.checkerframework.dataflow.analysis.Store; /** An array access. */ -public class ArrayAccess extends Receiver { +public class ArrayAccess extends JavaExpression { - protected final Receiver receiver; - protected final Receiver index; + protected final JavaExpression receiver; + protected final JavaExpression index; - public ArrayAccess(TypeMirror type, Receiver receiver, Receiver index) { + public ArrayAccess(TypeMirror type, JavaExpression receiver, JavaExpression index) { super(type); this.receiver = receiver; this.index = index; } @Override - public boolean containsOfClass(Class clazz) { + public boolean containsOfClass(Class clazz) { if (getClass() == clazz) { return true; } @@ -28,11 +28,11 @@ public boolean containsOfClass(Class clazz) { return index.containsOfClass(clazz); } - public Receiver getReceiver() { + public JavaExpression getReceiver() { return receiver; } - public Receiver getIndex() { + public JavaExpression getIndex() { return index; } @@ -47,14 +47,14 @@ public boolean isUnmodifiableByOtherCode() { } @Override - public boolean containsSyntacticEqualReceiver(Receiver other) { + public boolean containsSyntacticEqualJavaExpression(JavaExpression other) { return syntacticEquals(other) || receiver.syntacticEquals(other) || index.syntacticEquals(other); } @Override - public boolean syntacticEquals(Receiver other) { + public boolean syntacticEquals(JavaExpression other) { if (!(other instanceof ArrayAccess)) { return false; } @@ -66,7 +66,7 @@ public boolean syntacticEquals(Receiver other) { } @Override - public boolean containsModifiableAliasOf(Store store, Receiver other) { + public boolean containsModifiableAliasOf(Store store, JavaExpression other) { if (receiver.containsModifiableAliasOf(store, other)) { return true; } diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/ArrayCreation.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/ArrayCreation.java index 8483dfd071..25ece6f55a 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/ArrayCreation.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/ArrayCreation.java @@ -4,15 +4,15 @@ import java.util.Objects; import javax.lang.model.type.TypeMirror; import org.checkerframework.checker.nullness.qual.Nullable; -import org.plumelib.util.UtilPlume; +import org.plumelib.util.StringsPlume; /** FlowExpression for array creations. {@code new String[]()}. */ -public class ArrayCreation extends Receiver { +public class ArrayCreation extends JavaExpression { /** List of dimensions expressions. {code null} means that there is no dimension expression. */ - protected final List dimensions; + protected final List dimensions; /** List of initializers. */ - protected final List initializers; + protected final List initializers; /** * Creates an ArrayCreation object. @@ -24,8 +24,8 @@ public class ArrayCreation extends Receiver { */ public ArrayCreation( TypeMirror type, - List dimensions, - List initializers) { + List dimensions, + List initializers) { super(type); this.dimensions = dimensions; this.initializers = initializers; @@ -36,22 +36,22 @@ public ArrayCreation( * * @return a list of receivers representing the dimension of this array creation */ - public List getDimensions() { + public List getDimensions() { return dimensions; } - public List getInitializers() { + public List getInitializers() { return initializers; } @Override - public boolean containsOfClass(Class clazz) { - for (Receiver n : dimensions) { + public boolean containsOfClass(Class clazz) { + for (JavaExpression n : dimensions) { if (n != null && n.getClass() == clazz) { return true; } } - for (Receiver n : initializers) { + for (JavaExpression n : initializers) { if (n.getClass() == clazz) { return true; } @@ -88,12 +88,12 @@ public boolean equals(@Nullable Object obj) { } @Override - public boolean syntacticEquals(Receiver other) { + public boolean syntacticEquals(JavaExpression other) { return this.equals(other); } @Override - public boolean containsSyntacticEqualReceiver(Receiver other) { + public boolean containsSyntacticEqualJavaExpression(JavaExpression other) { return syntacticEquals(other); } @@ -102,7 +102,7 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append("new " + type); if (!dimensions.isEmpty()) { - for (Receiver dim : dimensions) { + for (JavaExpression dim : dimensions) { sb.append("["); sb.append(dim == null ? "" : dim); sb.append("]"); @@ -110,7 +110,7 @@ public String toString() { } if (!initializers.isEmpty()) { sb.append(" {"); - sb.append(UtilPlume.join(", ", initializers)); + sb.append(StringsPlume.join(", ", initializers)); sb.append("}"); } return sb.toString(); diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/BinaryOperation.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/BinaryOperation.java index c9cb9852b4..0b86b84391 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/BinaryOperation.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/BinaryOperation.java @@ -8,17 +8,17 @@ import org.checkerframework.dataflow.analysis.Store; import org.checkerframework.dataflow.cfg.node.BinaryOperationNode; -/** FlowExpression.Receiver for binary operations. */ -public class BinaryOperation extends Receiver { +/** JavaExpression for binary operations. */ +public class BinaryOperation extends JavaExpression { /** The binary operation kind. */ protected final Kind operationKind; /** The binary operation kind for pretty printing. */ protected final JCTree.Tag tag; /** The left operand. */ - protected final Receiver left; + protected final JavaExpression left; /** The right operand. */ - protected final Receiver right; + protected final JavaExpression right; /** * Create a binary operation. @@ -27,7 +27,7 @@ public class BinaryOperation extends Receiver { * @param left the left operand * @param right the right operand */ - public BinaryOperation(BinaryOperationNode node, Receiver left, Receiver right) { + public BinaryOperation(BinaryOperationNode node, JavaExpression left, JavaExpression right) { super(node.getType()); this.operationKind = node.getTree().getKind(); this.tag = ((JCTree) node.getTree()).getTag(); @@ -49,7 +49,7 @@ public Kind getOperationKind() { * * @return the left operand */ - public Receiver getLeft() { + public JavaExpression getLeft() { return left; } @@ -58,12 +58,12 @@ public Receiver getLeft() { * * @return the right operand */ - public Receiver getRight() { + public JavaExpression getRight() { return right; } @Override - public boolean containsOfClass(Class clazz) { + public boolean containsOfClass(Class clazz) { if (getClass() == clazz) { return true; } @@ -81,7 +81,7 @@ public boolean isUnmodifiableByOtherCode() { } @Override - public boolean syntacticEquals(Receiver other) { + public boolean syntacticEquals(JavaExpression other) { if (!(other instanceof BinaryOperation)) { return false; } @@ -93,7 +93,7 @@ public boolean syntacticEquals(Receiver other) { } @Override - public boolean containsModifiableAliasOf(Store store, Receiver other) { + public boolean containsModifiableAliasOf(Store store, JavaExpression other) { return left.containsModifiableAliasOf(store, other) || right.containsModifiableAliasOf(store, other); } diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/ClassName.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/ClassName.java index 03f681bbf6..9a08b3eee4 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/ClassName.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/ClassName.java @@ -9,7 +9,7 @@ * A ClassName represents the occurrence of a class as part of a static field access or method * invocation. */ -public class ClassName extends Receiver { +public class ClassName extends JavaExpression { private final String typeString; public ClassName(TypeMirror type) { @@ -37,12 +37,12 @@ public String toString() { } @Override - public boolean containsOfClass(Class clazz) { + public boolean containsOfClass(Class clazz) { return getClass() == clazz; } @Override - public boolean syntacticEquals(Receiver other) { + public boolean syntacticEquals(JavaExpression other) { return this.equals(other); } @@ -57,7 +57,7 @@ public boolean isUnmodifiableByOtherCode() { } @Override - public boolean containsModifiableAliasOf(Store store, Receiver other) { + public boolean containsModifiableAliasOf(Store store, JavaExpression other) { return false; // not modifiable } } diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/FieldAccess.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/FieldAccess.java index 1c0a006c64..ac55471da4 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/FieldAccess.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/FieldAccess.java @@ -9,11 +9,11 @@ import org.checkerframework.javacutil.ElementUtils; import org.checkerframework.javacutil.TypesUtils; -public class FieldAccess extends Receiver { - protected final Receiver receiver; +public class FieldAccess extends JavaExpression { + protected final JavaExpression receiver; protected final VariableElement field; - public Receiver getReceiver() { + public JavaExpression getReceiver() { return receiver; } @@ -21,13 +21,13 @@ public VariableElement getField() { return field; } - public FieldAccess(Receiver receiver, FieldAccessNode node) { + public FieldAccess(JavaExpression receiver, FieldAccessNode node) { super(node.getType()); this.receiver = receiver; this.field = node.getElement(); } - public FieldAccess(Receiver receiver, TypeMirror type, VariableElement fieldElement) { + public FieldAccess(JavaExpression receiver, TypeMirror type, VariableElement fieldElement) { super(type); this.receiver = receiver; this.field = fieldElement; @@ -56,18 +56,18 @@ public int hashCode() { } @Override - public boolean containsModifiableAliasOf(Store store, Receiver other) { + public boolean containsModifiableAliasOf(Store store, JavaExpression other) { return super.containsModifiableAliasOf(store, other) || receiver.containsModifiableAliasOf(store, other); } @Override - public boolean containsSyntacticEqualReceiver(Receiver other) { - return syntacticEquals(other) || receiver.containsSyntacticEqualReceiver(other); + public boolean containsSyntacticEqualJavaExpression(JavaExpression other) { + return syntacticEquals(other) || receiver.containsSyntacticEqualJavaExpression(other); } @Override - public boolean syntacticEquals(Receiver other) { + public boolean syntacticEquals(JavaExpression other) { if (!(other instanceof FieldAccess)) { return false; } @@ -87,7 +87,7 @@ public String toString() { } @Override - public boolean containsOfClass(Class clazz) { + public boolean containsOfClass(Class clazz) { return getClass() == clazz || receiver.containsOfClass(clazz); } diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/FlowExpressions.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/JavaExpression.java similarity index 50% rename from dataflow/src/main/java/org/checkerframework/dataflow/expression/FlowExpressions.java rename to dataflow/src/main/java/org/checkerframework/dataflow/expression/JavaExpression.java index 79317b03f4..b0f7d53eb3 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/FlowExpressions.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/JavaExpression.java @@ -8,6 +8,7 @@ import com.sun.source.tree.MethodInvocationTree; import com.sun.source.tree.MethodTree; import com.sun.source.tree.NewArrayTree; +import com.sun.source.tree.NewClassTree; import com.sun.source.tree.UnaryTree; import com.sun.source.tree.VariableTree; import com.sun.source.util.TreePath; @@ -18,12 +19,14 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeMirror; +import org.checkerframework.checker.interning.qual.EqualsMethod; import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.dataflow.analysis.Store; import org.checkerframework.dataflow.cfg.node.ArrayAccessNode; import org.checkerframework.dataflow.cfg.node.ArrayCreationNode; import org.checkerframework.dataflow.cfg.node.BinaryOperationNode; import org.checkerframework.dataflow.cfg.node.ClassNameNode; -import org.checkerframework.dataflow.cfg.node.ExplicitThisLiteralNode; +import org.checkerframework.dataflow.cfg.node.ExplicitThisNode; import org.checkerframework.dataflow.cfg.node.FieldAccessNode; import org.checkerframework.dataflow.cfg.node.LocalVariableNode; import org.checkerframework.dataflow.cfg.node.MethodInvocationNode; @@ -31,7 +34,7 @@ import org.checkerframework.dataflow.cfg.node.Node; import org.checkerframework.dataflow.cfg.node.StringConversionNode; import org.checkerframework.dataflow.cfg.node.SuperNode; -import org.checkerframework.dataflow.cfg.node.ThisLiteralNode; +import org.checkerframework.dataflow.cfg.node.ThisNode; import org.checkerframework.dataflow.cfg.node.ValueLiteralNode; import org.checkerframework.dataflow.cfg.node.WideningConversionNode; import org.checkerframework.dataflow.util.PurityUtils; @@ -40,19 +43,117 @@ import org.checkerframework.javacutil.ElementUtils; import org.checkerframework.javacutil.TreeUtils; +// The syntax that the Checker Framework uses for Java expressions also includes "" and +// "#1" for formal parameters. However, there are no special subclasses (AST nodes) for those +// extensions. /** - * Collection of classes and helper functions to represent Java expressions about which the - * org.checkerframework.dataflow analysis can possibly infer facts. Expressions include: + * This class represents a Java expression and its type. It does not represent all possible Java + * expressions (for example, it does not represent a ternary conditional expression {@code ?:}; use + * {@link org.checkerframework.dataflow.expression.Unknown} for unrepresentable expressions). * - *
      - *
    • Field accesses (e.g., o.f) - *
    • Local variables (e.g., l) - *
    • This reference (e.g., this) - *
    • Pure method calls (e.g., o.m()) - *
    • Unknown other expressions to mark that something else was present. - *
    + *

    This class's representation is like an AST: subparts are also expressions. For declared names + * (fields, local variables, and methods), it also contains an Element. + * + *

    Each subclass represents a different type of expression, such as {@link + * org.checkerframework.dataflow.expression.MethodCall}, {@link + * org.checkerframework.dataflow.expression.ArrayAccess}, {@link + * org.checkerframework.dataflow.expression.LocalVariable}, etc. + * + * @see the syntax of + * Java expressions supported by the Checker Framework */ -public class FlowExpressions { +public abstract class JavaExpression { + /** The type of this expression. */ + protected final TypeMirror type; + + /** + * Create a JavaExpression. + * + * @param type the type of the expression + */ + protected JavaExpression(TypeMirror type) { + assert type != null; + this.type = type; + } + + public TypeMirror getType() { + return type; + } + + public abstract boolean containsOfClass(Class clazz); + + public boolean containsUnknown() { + return containsOfClass(Unknown.class); + } + + /** + * Returns true if and only if the value this expression stands for cannot be changed (with + * respect to ==) by a method call. This is the case for local variables, the self reference, + * final field accesses whose receiver is {@link #isUnassignableByOtherCode}, and binary + * operations whose left and right operands are both {@link #isUnmodifiableByOtherCode}. + * + * @see #isUnmodifiableByOtherCode + */ + public abstract boolean isUnassignableByOtherCode(); + + /** + * Returns true if and only if the value this expression stands for cannot be changed by a + * method call, including changes to any of its fields. + * + *

    Approximately, this returns true if the expression is {@link #isUnassignableByOtherCode} + * and its type is immutable. + * + * @see #isUnassignableByOtherCode + */ + public abstract boolean isUnmodifiableByOtherCode(); + + /** + * Returns true if and only if the two receivers are syntactically identical. + * + * @param other the other object to compare to this one + * @return true if and only if the two receivers are syntactically identical + */ + @EqualsMethod + public boolean syntacticEquals(JavaExpression other) { + return other == this; + } + + /** + * Returns true if and only if this receiver contains a receiver that is syntactically equal to + * {@code other}. + * + * @return true if and only if this receiver contains a receiver that is syntactically equal to + * {@code other} + */ + public boolean containsSyntacticEqualJavaExpression(JavaExpression other) { + return syntacticEquals(other); + } + + /** + * Returns true if and only if {@code other} appears anywhere in this receiver or an expression + * appears in this receiver such that {@code other} might alias this expression, and that + * expression is modifiable. + * + *

    This is always true, except for cases where the Java type information prevents aliasing + * and none of the subexpressions can alias 'other'. + */ + public boolean containsModifiableAliasOf(Store store, JavaExpression other) { + return this.equals(other) || store.canAlias(this, other); + } + + /** + * Print this verbosely, for debugging. + * + * @return a verbose string representation of this + */ + public String toStringDebug() { + return String.format( + "JavaExpression (%s) %s type=%s", getClass().getSimpleName(), toString(), type); + } + + /// + /// Static methods + /// /** * Returns the internal representation (as {@link FieldAccess}) of a {@link FieldAccessNode}. @@ -61,14 +162,14 @@ public class FlowExpressions { * @return the internal representation (as {@link FieldAccess}) of a {@link FieldAccessNode}. * Can contain {@link Unknown} as receiver. */ - public static FieldAccess internalReprOfFieldAccess( + public static FieldAccess fromNodeFieldAccess( AnnotationProvider provider, FieldAccessNode node) { - Receiver receiver; Node receiverNode = node.getReceiver(); + JavaExpression receiver; if (node.isStatic()) { receiver = new ClassName(receiverNode.getType()); } else { - receiver = internalReprOf(provider, receiverNode); + receiver = fromNode(provider, receiverNode); } return new FieldAccess(receiver, node); } @@ -80,94 +181,91 @@ public static FieldAccess internalReprOfFieldAccess( * @return the internal representation (as {@link FieldAccess}) of a {@link FieldAccessNode}. * Can contain {@link Unknown} as receiver. */ - public static ArrayAccess internalReprOfArrayAccess( - AnnotationProvider provider, ArrayAccessNode node) { - Receiver receiver = internalReprOf(provider, node.getArray()); - Receiver index = internalReprOf(provider, node.getIndex()); - return new ArrayAccess(node.getType(), receiver, index); + public static ArrayAccess fromArrayAccess(AnnotationProvider provider, ArrayAccessNode node) { + JavaExpression array = fromNode(provider, node.getArray()); + JavaExpression index = fromNode(provider, node.getIndex()); + return new ArrayAccess(node.getType(), array, index); } /** * We ignore operations such as widening and narrowing when computing the internal * representation. * - * @return the internal representation (as {@link Receiver}) of any {@link Node}. Might contain - * {@link Unknown}. + * @return the internal representation of any {@link Node}. Might contain {@link Unknown}. */ - public static Receiver internalReprOf(AnnotationProvider provider, Node receiverNode) { - return internalReprOf(provider, receiverNode, false); + public static JavaExpression fromNode(AnnotationProvider provider, Node node) { + return fromNode(provider, node, false); } /** * We ignore operations such as widening and narrowing when computing the internal * representation. * - * @return the internal representation (as {@link Receiver}) of any {@link Node}. Might contain - * {@link Unknown}. + * @return the internal representation of any {@link Node}. Might contain {@link Unknown}. */ - public static Receiver internalReprOf( + public static JavaExpression fromNode( AnnotationProvider provider, Node receiverNode, boolean allowNonDeterministic) { - Receiver receiver = null; + JavaExpression result = null; if (receiverNode instanceof FieldAccessNode) { FieldAccessNode fan = (FieldAccessNode) receiverNode; if (fan.getFieldName().equals("this")) { // For some reason, "className.this" is considered a field access. // We right this wrong here. - receiver = new ThisReference(fan.getReceiver().getType()); + result = new ThisReference(fan.getReceiver().getType()); } else if (fan.getFieldName().equals("class")) { // "className.class" is considered a field access. This makes sense, // since .class is similar to a field access which is the equivalent // of a call to getClass(). However for the purposes of dataflow // analysis, and value stores, this is the equivalent of a ClassNameNode. - receiver = new ClassName(fan.getReceiver().getType()); + result = new ClassName(fan.getReceiver().getType()); } else { - receiver = internalReprOfFieldAccess(provider, fan); + result = fromNodeFieldAccess(provider, fan); } - } else if (receiverNode instanceof ExplicitThisLiteralNode) { - receiver = new ThisReference(receiverNode.getType()); - } else if (receiverNode instanceof ThisLiteralNode) { - receiver = new ThisReference(receiverNode.getType()); + } else if (receiverNode instanceof ExplicitThisNode) { + result = new ThisReference(receiverNode.getType()); + } else if (receiverNode instanceof ThisNode) { + result = new ThisReference(receiverNode.getType()); } else if (receiverNode instanceof SuperNode) { - receiver = new ThisReference(receiverNode.getType()); + result = new ThisReference(receiverNode.getType()); } else if (receiverNode instanceof LocalVariableNode) { LocalVariableNode lv = (LocalVariableNode) receiverNode; - receiver = new LocalVariable(lv); + result = new LocalVariable(lv); } else if (receiverNode instanceof ArrayAccessNode) { ArrayAccessNode a = (ArrayAccessNode) receiverNode; - receiver = internalReprOfArrayAccess(provider, a); + result = fromArrayAccess(provider, a); } else if (receiverNode instanceof StringConversionNode) { // ignore string conversion - return internalReprOf(provider, ((StringConversionNode) receiverNode).getOperand()); + return fromNode(provider, ((StringConversionNode) receiverNode).getOperand()); } else if (receiverNode instanceof WideningConversionNode) { // ignore widening - return internalReprOf(provider, ((WideningConversionNode) receiverNode).getOperand()); + return fromNode(provider, ((WideningConversionNode) receiverNode).getOperand()); } else if (receiverNode instanceof NarrowingConversionNode) { // ignore narrowing - return internalReprOf(provider, ((NarrowingConversionNode) receiverNode).getOperand()); + return fromNode(provider, ((NarrowingConversionNode) receiverNode).getOperand()); } else if (receiverNode instanceof BinaryOperationNode) { BinaryOperationNode bopn = (BinaryOperationNode) receiverNode; return new BinaryOperation( bopn, - internalReprOf(provider, bopn.getLeftOperand(), allowNonDeterministic), - internalReprOf(provider, bopn.getRightOperand(), allowNonDeterministic)); + fromNode(provider, bopn.getLeftOperand(), allowNonDeterministic), + fromNode(provider, bopn.getRightOperand(), allowNonDeterministic)); } else if (receiverNode instanceof ClassNameNode) { ClassNameNode cn = (ClassNameNode) receiverNode; - receiver = new ClassName(cn.getType()); + result = new ClassName(cn.getType()); } else if (receiverNode instanceof ValueLiteralNode) { ValueLiteralNode vn = (ValueLiteralNode) receiverNode; - receiver = new ValueLiteral(vn.getType(), vn); + result = new ValueLiteral(vn.getType(), vn); } else if (receiverNode instanceof ArrayCreationNode) { ArrayCreationNode an = (ArrayCreationNode) receiverNode; - List dimensions = new ArrayList<>(); + List dimensions = new ArrayList<>(); for (Node dimension : an.getDimensions()) { - dimensions.add(internalReprOf(provider, dimension, allowNonDeterministic)); + dimensions.add(fromNode(provider, dimension, allowNonDeterministic)); } - List initializers = new ArrayList<>(); + List initializers = new ArrayList<>(); for (Node initializer : an.getInitializers()) { - initializers.add(internalReprOf(provider, initializer, allowNonDeterministic)); + initializers.add(fromNode(provider, initializer, allowNonDeterministic)); } - receiver = new ArrayCreation(an.getType(), dimensions, initializers); + result = new ArrayCreation(an.getType(), dimensions, initializers); } else if (receiverNode instanceof MethodInvocationNode) { MethodInvocationNode mn = (MethodInvocationNode) receiverNode; MethodInvocationTree t = mn.getTree(); @@ -178,55 +276,53 @@ public static Receiver internalReprOf( ExecutableElement invokedMethod = TreeUtils.elementFromUse(t); if (allowNonDeterministic || PurityUtils.isDeterministic(provider, invokedMethod)) { - List parameters = new ArrayList<>(); + List parameters = new ArrayList<>(); for (Node p : mn.getArguments()) { - parameters.add(internalReprOf(provider, p)); + parameters.add(fromNode(provider, p)); } - Receiver methodReceiver; + JavaExpression methodReceiver; if (ElementUtils.isStatic(invokedMethod)) { methodReceiver = new ClassName(mn.getTarget().getReceiver().getType()); } else { - methodReceiver = internalReprOf(provider, mn.getTarget().getReceiver()); + methodReceiver = fromNode(provider, mn.getTarget().getReceiver()); } - receiver = new MethodCall(mn.getType(), invokedMethod, methodReceiver, parameters); + result = new MethodCall(mn.getType(), invokedMethod, methodReceiver, parameters); } } - if (receiver == null) { - receiver = new Unknown(receiverNode.getType()); + if (result == null) { + result = new Unknown(receiverNode.getType()); } - return receiver; + return result; } /** - * Returns the internal representation (as {@link Receiver}) of any {@link ExpressionTree}. - * Might contain {@link Unknown}. + * Returns the internal representation of any {@link ExpressionTree}. Might contain {@link + * Unknown}. * - * @return the internal representation (as {@link Receiver}) of any {@link ExpressionTree}. - * Might contain {@link Unknown}. + * @return the internal representation of any {@link ExpressionTree}. Might contain {@link + * Unknown}. */ - public static Receiver internalReprOf( + public static JavaExpression fromTree( AnnotationProvider provider, ExpressionTree receiverTree) { - return internalReprOf(provider, receiverTree, true); + return fromTree(provider, receiverTree, true); } /** * We ignore operations such as widening and narrowing when computing the internal * representation. * - * @return the internal representation (as {@link Receiver}) of any {@link ExpressionTree}. - * Might contain {@link Unknown}. + * @return the internal representation of any {@link ExpressionTree}. Might contain {@link + * Unknown}. */ - public static Receiver internalReprOf( - AnnotationProvider provider, - ExpressionTree receiverTree, - boolean allowNonDeterministic) { - Receiver receiver; - switch (receiverTree.getKind()) { + public static JavaExpression fromTree( + AnnotationProvider provider, ExpressionTree tree, boolean allowNonDeterministic) { + JavaExpression result; + switch (tree.getKind()) { case ARRAY_ACCESS: - ArrayAccessTree a = (ArrayAccessTree) receiverTree; - Receiver arrayAccessExpression = internalReprOf(provider, a.getExpression()); - Receiver index = internalReprOf(provider, a.getIndex()); - receiver = new ArrayAccess(TreeUtils.typeOf(a), arrayAccessExpression, index); + ArrayAccessTree a = (ArrayAccessTree) tree; + JavaExpression arrayAccessExpression = fromTree(provider, a.getExpression()); + JavaExpression index = fromTree(provider, a.getIndex()); + result = new ArrayAccess(TreeUtils.typeOf(a), arrayAccessExpression, index); break; case BOOLEAN_LITERAL: case CHAR_LITERAL: @@ -236,70 +332,63 @@ public static Receiver internalReprOf( case LONG_LITERAL: case NULL_LITERAL: case STRING_LITERAL: - LiteralTree vn = (LiteralTree) receiverTree; - receiver = new ValueLiteral(TreeUtils.typeOf(receiverTree), vn.getValue()); + LiteralTree vn = (LiteralTree) tree; + result = new ValueLiteral(TreeUtils.typeOf(tree), vn.getValue()); break; case NEW_ARRAY: - NewArrayTree newArrayTree = (NewArrayTree) receiverTree; - List dimensions = new ArrayList<>(); + NewArrayTree newArrayTree = (NewArrayTree) tree; + List dimensions = new ArrayList<>(); if (newArrayTree.getDimensions() != null) { for (ExpressionTree dimension : newArrayTree.getDimensions()) { - dimensions.add(internalReprOf(provider, dimension, allowNonDeterministic)); + dimensions.add(fromTree(provider, dimension, allowNonDeterministic)); } } - List initializers = new ArrayList<>(); + List initializers = new ArrayList<>(); if (newArrayTree.getInitializers() != null) { for (ExpressionTree initializer : newArrayTree.getInitializers()) { - initializers.add( - internalReprOf(provider, initializer, allowNonDeterministic)); + initializers.add(fromTree(provider, initializer, allowNonDeterministic)); } } - receiver = - new ArrayCreation(TreeUtils.typeOf(receiverTree), dimensions, initializers); + result = new ArrayCreation(TreeUtils.typeOf(tree), dimensions, initializers); break; case METHOD_INVOCATION: - MethodInvocationTree mn = (MethodInvocationTree) receiverTree; + MethodInvocationTree mn = (MethodInvocationTree) tree; assert TreeUtils.isUseOfElement(mn) : "@AssumeAssertion(nullness): tree kind"; ExecutableElement invokedMethod = TreeUtils.elementFromUse(mn); if (PurityUtils.isDeterministic(provider, invokedMethod) || allowNonDeterministic) { - List parameters = new ArrayList<>(); + List parameters = new ArrayList<>(); for (ExpressionTree p : mn.getArguments()) { - parameters.add(internalReprOf(provider, p)); + parameters.add(fromTree(provider, p)); } - Receiver methodReceiver; + JavaExpression methodReceiver; if (ElementUtils.isStatic(invokedMethod)) { methodReceiver = new ClassName(TreeUtils.typeOf(mn.getMethodSelect())); } else { - ExpressionTree methodReceiverTree = TreeUtils.getReceiverTree(mn); - if (methodReceiverTree != null) { - methodReceiver = internalReprOf(provider, methodReceiverTree); - } else { - methodReceiver = internalReprOfImplicitReceiver(invokedMethod); - } + methodReceiver = getReceiver(mn, provider); } TypeMirror type = TreeUtils.typeOf(mn); - receiver = new MethodCall(type, invokedMethod, methodReceiver, parameters); + result = new MethodCall(type, invokedMethod, methodReceiver, parameters); } else { - receiver = null; + result = null; } break; case MEMBER_SELECT: - receiver = internalReprOfMemberSelect(provider, (MemberSelectTree) receiverTree); + result = fromMemberSelect(provider, (MemberSelectTree) tree); break; case IDENTIFIER: - IdentifierTree identifierTree = (IdentifierTree) receiverTree; + IdentifierTree identifierTree = (IdentifierTree) tree; TypeMirror typeOfId = TreeUtils.typeOf(identifierTree); if (identifierTree.getName().contentEquals("this") || identifierTree.getName().contentEquals("super")) { - receiver = new ThisReference(typeOfId); + result = new ThisReference(typeOfId); break; } assert TreeUtils.isUseOfElement(identifierTree) : "@AssumeAssertion(nullness): tree kind"; Element ele = TreeUtils.elementFromUse(identifierTree); - if (ElementUtils.isClassElement(ele)) { - receiver = new ClassName(ele.asType()); + if (ElementUtils.isTypeElement(ele)) { + result = new ClassName(ele.asType()); break; } switch (ele.getKind()) { @@ -307,11 +396,11 @@ public static Receiver internalReprOf( case RESOURCE_VARIABLE: case EXCEPTION_PARAMETER: case PARAMETER: - receiver = new LocalVariable(ele); + result = new LocalVariable(ele); break; case FIELD: // Implicit access expression, such as "this" or a class name - Receiver fieldAccessExpression; + JavaExpression fieldAccessExpression; @SuppressWarnings( "nullness:dereference.of.nullable") // a field has enclosing class TypeMirror enclosingType = ElementUtils.enclosingClass(ele).asType(); @@ -320,72 +409,28 @@ public static Receiver internalReprOf( } else { fieldAccessExpression = new ThisReference(enclosingType); } - receiver = + result = new FieldAccess( fieldAccessExpression, typeOfId, (VariableElement) ele); break; default: - receiver = null; + result = null; } break; case UNARY_PLUS: - return internalReprOf( - provider, - ((UnaryTree) receiverTree).getExpression(), - allowNonDeterministic); + return fromTree( + provider, ((UnaryTree) tree).getExpression(), allowNonDeterministic); default: - receiver = null; + result = null; } - if (receiver == null) { - receiver = new Unknown(TreeUtils.typeOf(receiverTree)); + if (result == null) { + result = new Unknown(TreeUtils.typeOf(tree)); } - return receiver; + return result; } - /** - * Returns the implicit receiver of ele. - * - *

    Returns either a new ClassName or a new ThisReference depending on whether ele is static - * or not. The passed element must be a field, method, or class. - * - * @param ele field, method, or class - * @return either a new ClassName or a new ThisReference depending on whether ele is static or - * not - */ - public static Receiver internalReprOfImplicitReceiver(Element ele) { - TypeElement enclosingClass = ElementUtils.enclosingClass(ele); - if (enclosingClass == null) { - throw new BugInCF( - "internalReprOfImplicitReceiver's arg has no enclosing class: " + ele); - } - TypeMirror enclosingType = enclosingClass.asType(); - if (ElementUtils.isStatic(ele)) { - return new ClassName(enclosingType); - } else { - return new ThisReference(enclosingType); - } - } - - /** - * Returns either a new ClassName or ThisReference Receiver object for the enclosingType. - * - *

    The Tree should be an expression or a statement that does not have a receiver or an - * implicit receiver. For example, a local variable declaration. - * - * @param path TreePath to tree - * @param enclosingType type of the enclosing type - * @return a new ClassName or ThisReference that is a Receiver object for the enclosingType - */ - public static Receiver internalReprOfPseudoReceiver(TreePath path, TypeMirror enclosingType) { - if (TreeUtils.isTreeInStaticScope(path)) { - return new ClassName(enclosingType); - } else { - return new ThisReference(enclosingType); - } - } - - private static Receiver internalReprOfMemberSelect( + private static JavaExpression fromMemberSelect( AnnotationProvider provider, MemberSelectTree memberSelectTree) { TypeMirror expressionType = TreeUtils.typeOf(memberSelectTree.getExpression()); if (TreeUtils.isClassLiteral(memberSelectTree)) { @@ -393,7 +438,7 @@ private static Receiver internalReprOfMemberSelect( } assert TreeUtils.isUseOfElement(memberSelectTree) : "@AssumeAssertion(nullness): tree kind"; Element ele = TreeUtils.elementFromUse(memberSelectTree); - if (ElementUtils.isClassElement(ele)) { + if (ElementUtils.isTypeElement(ele)) { // o instanceof MyClass.InnerClass // o instanceof MyClass.InnerInterface TypeMirror selectType = TreeUtils.typeOf(memberSelectTree); @@ -402,35 +447,103 @@ private static Receiver internalReprOfMemberSelect( switch (ele.getKind()) { case METHOD: case CONSTRUCTOR: - return internalReprOf(provider, memberSelectTree.getExpression()); + return fromTree(provider, memberSelectTree.getExpression()); case ENUM_CONSTANT: case FIELD: TypeMirror fieldType = TreeUtils.typeOf(memberSelectTree); - Receiver r = internalReprOf(provider, memberSelectTree.getExpression()); - return new FieldAccess(r, fieldType, (VariableElement) ele); + JavaExpression je = fromTree(provider, memberSelectTree.getExpression()); + return new FieldAccess(je, fieldType, (VariableElement) ele); default: throw new BugInCF("Unexpected element kind: %s element: %s", ele.getKind(), ele); } } /** - * Returns Receiver objects for the formal parameters of the method in which path is enclosed. + * Returns the formal parameters of the method in which path is enclosed. * * @param annotationProvider annotationProvider * @param path TreePath that is enclosed by the method - * @return list of Receiver objects for the formal parameters of the method in which path is - * enclosed, {@code null} otherwise + * @return the formal parameters of the method in which path is enclosed, {@code null} otherwise */ - public static @Nullable List getParametersOfEnclosingMethod( + public static @Nullable List getParametersOfEnclosingMethod( AnnotationProvider annotationProvider, TreePath path) { MethodTree methodTree = TreeUtils.enclosingMethod(path); if (methodTree == null) { return null; } - List internalArguments = new ArrayList<>(); + List internalArguments = new ArrayList<>(); for (VariableTree arg : methodTree.getParameters()) { - internalArguments.add(internalReprOf(annotationProvider, new LocalVariableNode(arg))); + internalArguments.add(fromNode(annotationProvider, new LocalVariableNode(arg))); } return internalArguments; } + + /// + /// Obtaining the receiver + /// + + /** + * Returns the receiver of ele, whether explicit or implicit. + * + * @param accessTree method or constructor invocation + * @param provider an AnnotationProvider + * @return the receiver of ele, whether explicit or implicit + */ + public static JavaExpression getReceiver( + ExpressionTree accessTree, AnnotationProvider provider) { + // TODO: Handle field accesses too? + assert accessTree instanceof MethodInvocationTree || accessTree instanceof NewClassTree; + ExpressionTree receiverTree = TreeUtils.getReceiverTree(accessTree); + if (receiverTree != null) { + return fromTree(provider, receiverTree); + } else { + Element ele = TreeUtils.elementFromUse(accessTree); + if (ele == null) { + throw new BugInCF("TreeUtils.elementFromUse(" + accessTree + ") => null"); + } + return getImplicitReceiver(ele); + } + } + + /** + * Returns the implicit receiver of ele. + * + *

    Returns either a new ClassName or a new ThisReference depending on whether ele is static + * or not. The passed element must be a field, method, or class. + * + * @param ele field, method, or class + * @return either a new ClassName or a new ThisReference depending on whether ele is static or + * not + */ + public static JavaExpression getImplicitReceiver(Element ele) { + TypeElement enclosingClass = ElementUtils.enclosingClass(ele); + if (enclosingClass == null) { + throw new BugInCF("getImplicitReceiver's arg has no enclosing class: " + ele); + } + TypeMirror enclosingType = enclosingClass.asType(); + if (ElementUtils.isStatic(ele)) { + return new ClassName(enclosingType); + } else { + return new ThisReference(enclosingType); + } + } + + /** + * Returns either a new ClassName or ThisReference JavaExpression object for the enclosingType. + * + *

    The Tree should be an expression or a statement that does not have a receiver or an + * implicit receiver. For example, a local variable declaration. + * + * @param path TreePath to tree + * @param enclosingType type of the enclosing type + * @return a new ClassName or ThisReference that is a JavaExpression object for the + * enclosingType + */ + public static JavaExpression getPseudoReceiver(TreePath path, TypeMirror enclosingType) { + if (TreeUtils.isTreeInStaticScope(path)) { + return new ClassName(enclosingType); + } else { + return new ThisReference(enclosingType); + } + } } diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/LocalVariable.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/LocalVariable.java index a41d51ad7d..584b627eb0 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/LocalVariable.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/LocalVariable.java @@ -9,7 +9,7 @@ import org.checkerframework.javacutil.TypeAnnotationUtils; import org.checkerframework.javacutil.TypesUtils; -public class LocalVariable extends Receiver { +public class LocalVariable extends JavaExpression { protected final Element element; public LocalVariable(LocalVariableNode localVar) { @@ -59,12 +59,12 @@ public String toString() { } @Override - public boolean containsOfClass(Class clazz) { + public boolean containsOfClass(Class clazz) { return getClass() == clazz; } @Override - public boolean syntacticEquals(Receiver other) { + public boolean syntacticEquals(JavaExpression other) { if (!(other instanceof LocalVariable)) { return false; } @@ -73,7 +73,7 @@ public boolean syntacticEquals(Receiver other) { } @Override - public boolean containsSyntacticEqualReceiver(Receiver other) { + public boolean containsSyntacticEqualJavaExpression(JavaExpression other) { return syntacticEquals(other); } diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/MethodCall.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/MethodCall.java index b5c4597495..25abf0c481 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/MethodCall.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/MethodCall.java @@ -8,20 +8,20 @@ import javax.lang.model.type.TypeMirror; import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.analysis.Store; -import org.plumelib.util.UtilPlume; +import org.plumelib.util.StringsPlume; /** A call to a @Deterministic method. */ -public class MethodCall extends Receiver { +public class MethodCall extends JavaExpression { - protected final Receiver receiver; - protected final List parameters; + protected final JavaExpression receiver; + protected final List parameters; protected final ExecutableElement method; public MethodCall( TypeMirror type, ExecutableElement method, - Receiver receiver, - List parameters) { + JavaExpression receiver, + List parameters) { super(type); this.receiver = receiver; this.parameters = parameters; @@ -29,14 +29,14 @@ public MethodCall( } @Override - public boolean containsOfClass(Class clazz) { + public boolean containsOfClass(Class clazz) { if (getClass() == clazz) { return true; } if (receiver.containsOfClass(clazz)) { return true; } - for (Receiver p : parameters) { + for (JavaExpression p : parameters) { if (p.containsOfClass(clazz)) { return true; } @@ -49,7 +49,7 @@ public boolean containsOfClass(Class clazz) { * * @return the method call receiver (for inspection only - do not modify) */ - public Receiver getReceiver() { + public JavaExpression getReceiver() { return receiver; } @@ -60,7 +60,7 @@ public Receiver getReceiver() { * @return the method call parameters (for inspection only - do not modify any of the * parameters) */ - public List getParameters() { + public List getParameters() { return Collections.unmodifiableList(parameters); } @@ -78,7 +78,7 @@ public boolean isUnassignableByOtherCode() { // There is no need to check that the method is deterministic, because a MethodCall is // only created for deterministic methods. return receiver.isUnmodifiableByOtherCode() - && parameters.stream().allMatch(Receiver::isUnmodifiableByOtherCode); + && parameters.stream().allMatch(JavaExpression::isUnmodifiableByOtherCode); } @Override @@ -87,12 +87,12 @@ public boolean isUnmodifiableByOtherCode() { } @Override - public boolean containsSyntacticEqualReceiver(Receiver other) { + public boolean containsSyntacticEqualJavaExpression(JavaExpression other) { return syntacticEquals(other) || receiver.syntacticEquals(other); } @Override - public boolean syntacticEquals(Receiver other) { + public boolean syntacticEquals(JavaExpression other) { if (!(other instanceof MethodCall)) { return false; } @@ -104,7 +104,7 @@ public boolean syntacticEquals(Receiver other) { return false; } int i = 0; - for (Receiver p : parameters) { + for (JavaExpression p : parameters) { if (!p.syntacticEquals(otherMethod.parameters.get(i))) { return false; } @@ -114,8 +114,8 @@ public boolean syntacticEquals(Receiver other) { } public boolean containsSyntacticEqualParameter(LocalVariable var) { - for (Receiver p : parameters) { - if (p.containsSyntacticEqualReceiver(var)) { + for (JavaExpression p : parameters) { + if (p.containsSyntacticEqualJavaExpression(var)) { return true; } } @@ -123,11 +123,11 @@ public boolean containsSyntacticEqualParameter(LocalVariable var) { } @Override - public boolean containsModifiableAliasOf(Store store, Receiver other) { + public boolean containsModifiableAliasOf(Store store, JavaExpression other) { if (receiver.containsModifiableAliasOf(store, other)) { return true; } - for (Receiver p : parameters) { + for (JavaExpression p : parameters) { if (p.containsModifiableAliasOf(store, other)) { return true; } @@ -172,7 +172,7 @@ public String toString() { String methodName = method.getSimpleName().toString(); result.append(methodName); result.append("("); - result.append(UtilPlume.join(", ", parameters)); + result.append(StringsPlume.join(", ", parameters)); result.append(")"); return result.toString(); } diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/Receiver.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/Receiver.java deleted file mode 100644 index e0fb8793ff..0000000000 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/Receiver.java +++ /dev/null @@ -1,114 +0,0 @@ -package org.checkerframework.dataflow.expression; - -import javax.lang.model.type.TypeMirror; -import org.checkerframework.checker.interning.qual.EqualsMethod; -import org.checkerframework.dataflow.analysis.Store; - -// The syntax that the Checker Framework uses for Java expressions also includes "" and -// "#1" for formal parameters. However, there are no special subclasses (AST nodes) for those -// extensions. -/** - * This class represents a Java expression and its type. It does not represent all possible Java - * expressions (for example, it does not represent a ternary conditional expression {@code ?:}; use - * {@link org.checkerframework.dataflow.expression.Unknown} for unrepresentable expressions). - * - *

    This class's representation is like an AST: subparts are also expressions. For declared names - * (fields, local variables, and methods), it also contains an Element. - * - *

    Each subclass represents a different type of expression, such as {@link - * org.checkerframework.dataflow.expression.MethodCall}, {@link - * org.checkerframework.dataflow.expression.ArrayAccess}, {@link - * org.checkerframework.dataflow.expression.LocalVariable}, etc. - * - * @see the syntax of - * Java expressions supported by the Checker Framework - */ -public abstract class Receiver { - /** The type of this expression. */ - protected final TypeMirror type; - - /** - * Create a Receiver (a Java AST node representing an expression). - * - * @param type the type of the expression - */ - protected Receiver(TypeMirror type) { - assert type != null; - this.type = type; - } - - public TypeMirror getType() { - return type; - } - - public abstract boolean containsOfClass(Class clazz); - - public boolean containsUnknown() { - return containsOfClass(Unknown.class); - } - - /** - * Returns true if and only if the value this expression stands for cannot be changed (with - * respect to ==) by a method call. This is the case for local variables, the self reference, - * final field accesses whose receiver is {@link #isUnassignableByOtherCode}, and binary - * operations whose left and right operands are both {@link #isUnmodifiableByOtherCode}. - * - * @see #isUnmodifiableByOtherCode - */ - public abstract boolean isUnassignableByOtherCode(); - - /** - * Returns true if and only if the value this expression stands for cannot be changed by a - * method call, including changes to any of its fields. - * - *

    Approximately, this returns true if the expression is {@link #isUnassignableByOtherCode} - * and its type is immutable. - * - * @see #isUnassignableByOtherCode - */ - public abstract boolean isUnmodifiableByOtherCode(); - - /** - * Returns true if and only if the two receivers are syntactically identical. - * - * @param other the other object to compare to this one - * @return true if and only if the two receivers are syntactically identical - */ - @EqualsMethod - public boolean syntacticEquals(Receiver other) { - return other == this; - } - - /** - * Returns true if and only if this receiver contains a receiver that is syntactically equal to - * {@code other}. - * - * @return true if and only if this receiver contains a receiver that is syntactically equal to - * {@code other} - */ - public boolean containsSyntacticEqualReceiver(Receiver other) { - return syntacticEquals(other); - } - - /** - * Returns true if and only if {@code other} appears anywhere in this receiver or an expression - * appears in this receiver such that {@code other} might alias this expression, and that - * expression is modifiable. - * - *

    This is always true, except for cases where the Java type information prevents aliasing - * and none of the subexpressions can alias 'other'. - */ - public boolean containsModifiableAliasOf(Store store, Receiver other) { - return this.equals(other) || store.canAlias(this, other); - } - - /** - * Print this verbosely, for debugging. - * - * @return a verbose string representation of this - */ - public String toStringDebug() { - return String.format( - "Receiver (%s) %s type=%s", getClass().getSimpleName(), toString(), type); - } -} diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/ThisReference.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/ThisReference.java index e2a6cdf755..0991bb7fa1 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/ThisReference.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/ThisReference.java @@ -5,7 +5,7 @@ import org.checkerframework.dataflow.analysis.Store; import org.checkerframework.javacutil.TypesUtils; -public class ThisReference extends Receiver { +public class ThisReference extends JavaExpression { public ThisReference(TypeMirror type) { super(type); } @@ -26,12 +26,12 @@ public String toString() { } @Override - public boolean containsOfClass(Class clazz) { + public boolean containsOfClass(Class clazz) { return getClass() == clazz; } @Override - public boolean syntacticEquals(Receiver other) { + public boolean syntacticEquals(JavaExpression other) { return other instanceof ThisReference; } @@ -46,7 +46,7 @@ public boolean isUnmodifiableByOtherCode() { } @Override - public boolean containsModifiableAliasOf(Store store, Receiver other) { + public boolean containsModifiableAliasOf(Store store, JavaExpression other) { return false; // 'this' is not modifiable } } diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/Unknown.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/Unknown.java index 76e2c3828e..f75581241b 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/Unknown.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/Unknown.java @@ -7,7 +7,7 @@ /** Stands for any expression that the Dataflow Framework lacks explicit support for. */ @UsesObjectEquals -public class Unknown extends Receiver { +public class Unknown extends JavaExpression { /** * Create a new Unknown receiver. * @@ -34,12 +34,12 @@ public String toString() { } @Override - public boolean containsModifiableAliasOf(Store store, Receiver other) { + public boolean containsModifiableAliasOf(Store store, JavaExpression other) { return true; } @Override - public boolean containsOfClass(Class clazz) { + public boolean containsOfClass(Class clazz) { return getClass() == clazz; } diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/expression/ValueLiteral.java b/dataflow/src/main/java/org/checkerframework/dataflow/expression/ValueLiteral.java index 21d31b8a8a..00b1ff4cb7 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/expression/ValueLiteral.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/expression/ValueLiteral.java @@ -8,8 +8,8 @@ import org.checkerframework.dataflow.cfg.node.ValueLiteralNode; import org.checkerframework.javacutil.TypesUtils; -/** FlowExpression.Receiver for literals. */ -public class ValueLiteral extends Receiver { +/** FlowExpression.JavaExpression for literals. */ +public class ValueLiteral extends JavaExpression { /** The value of the literal. */ protected final @Nullable Object value; @@ -38,7 +38,7 @@ public ValueLiteral(TypeMirror type, Object value) { } @Override - public boolean containsOfClass(Class clazz) { + public boolean containsOfClass(Class clazz) { return getClass() == clazz; } @@ -82,12 +82,12 @@ public int hashCode() { } @Override - public boolean syntacticEquals(Receiver other) { + public boolean syntacticEquals(JavaExpression other) { return this.equals(other); } @Override - public boolean containsModifiableAliasOf(Store store, Receiver other) { + public boolean containsModifiableAliasOf(Store store, JavaExpression other) { return false; // not modifiable } diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/livevariable/LiveVarStore.java b/dataflow/src/main/java/org/checkerframework/dataflow/livevariable/LiveVarStore.java index 91b801aefc..711575cd33 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/livevariable/LiveVarStore.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/livevariable/LiveVarStore.java @@ -15,7 +15,7 @@ import org.checkerframework.dataflow.cfg.node.TypeCastNode; import org.checkerframework.dataflow.cfg.node.UnaryOperationNode; import org.checkerframework.dataflow.cfg.visualize.CFGVisualizer; -import org.checkerframework.dataflow.expression.Receiver; +import org.checkerframework.dataflow.expression.JavaExpression; import org.checkerframework.javacutil.BugInCF; /** A live variable store contains a set of live variables represented by nodes. */ @@ -121,7 +121,7 @@ public LiveVarStore widenedUpperBound(LiveVarStore previous) { } @Override - public boolean canAlias(Receiver a, Receiver b) { + public boolean canAlias(JavaExpression a, JavaExpression b) { return true; } diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/util/IdentityMostlySingleton.java b/dataflow/src/main/java/org/checkerframework/dataflow/util/IdentityMostlySingleton.java index 8db5a703d0..e49340cd32 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/util/IdentityMostlySingleton.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/util/IdentityMostlySingleton.java @@ -22,7 +22,6 @@ public IdentityMostlySingleton(T value) { } @Override - @SuppressWarnings("fallthrough") public boolean add(@FindDistinct T e) { switch (state) { case EMPTY: @@ -38,7 +37,7 @@ public boolean add(@FindDistinct T e) { assert value != null : "@AssumeAssertion(nullness): previous add is non-null"; set.add(value); value = null; - // fallthrough + // fall through case ANY: assert set != null : "@AssumeAssertion(nullness): set initialized before"; return set.add(e); diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/util/MostlySingleton.java b/dataflow/src/main/java/org/checkerframework/dataflow/util/MostlySingleton.java index d22626caf6..13d535b878 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/util/MostlySingleton.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/util/MostlySingleton.java @@ -21,7 +21,6 @@ public MostlySingleton(T value) { } @Override - @SuppressWarnings("fallthrough") public boolean add(T e) { switch (state) { case EMPTY: @@ -34,7 +33,7 @@ public boolean add(T e) { assert value != null : "@AssumeAssertion(nullness): previous add is non-null"; set.add(value); value = null; - // fallthrough + // fall through case ANY: assert set != null : "@AssumeAssertion(nullness): set initialized before"; return set.add(e); diff --git a/dataflow/src/main/java/org/checkerframework/dataflow/util/PurityChecker.java b/dataflow/src/main/java/org/checkerframework/dataflow/util/PurityChecker.java index bd756bb08a..e635ee1ba3 100644 --- a/dataflow/src/main/java/org/checkerframework/dataflow/util/PurityChecker.java +++ b/dataflow/src/main/java/org/checkerframework/dataflow/util/PurityChecker.java @@ -209,7 +209,7 @@ public Void visitMethodInvocation(MethodInvocationTree node, Void ignore) { assert TreeUtils.isUseOfElement(node) : "@AssumeAssertion(nullness): tree kind"; Element elt = TreeUtils.elementFromUse(node); if (!PurityUtils.hasPurityAnnotation(annoProvider, elt)) { - purityResult.addNotBothReason(node, "call.method"); + purityResult.addNotBothReason(node, "call"); } else { EnumSet purityKinds = (assumeDeterministic && assumeSideEffectFree) @@ -220,11 +220,11 @@ public Void visitMethodInvocation(MethodInvocationTree node, Void ignore) { boolean seFree = assumeSideEffectFree || purityKinds.contains(Kind.SIDE_EFFECT_FREE); if (!det && !seFree) { - purityResult.addNotBothReason(node, "call.method"); + purityResult.addNotBothReason(node, "call"); } else if (!det) { - purityResult.addNotDetReason(node, "call.method"); + purityResult.addNotDetReason(node, "call"); } else if (!seFree) { - purityResult.addNotSEFreeReason(node, "call.method"); + purityResult.addNotSEFreeReason(node, "call"); } } return super.visitMethodInvocation(node, ignore); @@ -278,7 +278,7 @@ public Void visitNewClass(NewClassTree node, Void ignore) { purityResult.addNotDetReason(node, "object.creation"); } if (!sideEffectFree) { - purityResult.addNotSEFreeReason(node, "call.constructor"); + purityResult.addNotSEFreeReason(node, "call"); } // TODO: if okThrowDeterministic, permit arguments to the newClass to be diff --git a/docs/checker-framework-webpage.html b/docs/checker-framework-webpage.html index d4a27042a5..82edfd7c0b 100644 --- a/docs/checker-framework-webpage.html +++ b/docs/checker-framework-webpage.html @@ -30,8 +30,8 @@

    The Checker Framework

    Installation instructions and tutorial.
  • - Download: checker-framework-3.7.1.zip - (2 Nov 2020); + Download: checker-framework-3.8.0.zip + (1 Dec 2020); includes source, platform-independent binary, tests, and documentation.
    Then, see the installation @@ -93,7 +93,7 @@

    The Checker Framework

    the .class file. The tools support both Java 5 declaration annotations and Java 8 type annotations.