Skip to content

Commit 1b3cf72

Browse files
committed
Add Nullaway Checkstyle
- Require package-info.java with @NullMarked in every package - Suppress package checks for tests and modules that haven't been worked on - Prevent non org.jspecify Nullability imports on enabled modules - Validate Nullable is before modifiers Closes gh-18564
1 parent d7fbf36 commit 1b3cf72

2 files changed

Lines changed: 72 additions & 5 deletions

File tree

etc/checkstyle/checkstyle-suppressions.xml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
<suppress files="BCrypt\.java|BCryptTests\.java" checks=".*"/>
1616
<suppress files="org[\\/]springframework[\\/]security[\\/]core[\\/]ComparableVersion\.java" checks=".*"/>
1717

18+
<!-- Suppress sun.misc.Unsafe in this class (we should eventually remove its usage but it is unrelated to nullability imports) -->
19+
<suppress files="StaticFinalReflectionUtils\.java" checks="IllegalImport" id="bannedNullabilityImports"/>
20+
1821
<!-- Method Visibility that we can't reduce -->
1922
<suppress files="AbstractAclVoterTests\.java" checks="SpringMethodVisibility"/>
2023
<suppress files="AnnotationParameterNameDiscovererTests\.java" checks="SpringMethodVisibility"/>
@@ -49,4 +52,46 @@
4952
<!-- Ignore String.toUpperCase() and String.toLowerCase() checks in tests -->
5053
<suppress files="[\\/]src[\\/]test[\\/]" checks="RegexpSinglelineJava" id="toLowerCaseWithoutLocale"/>
5154
<suppress files="[\\/]src[\\/]test[\\/]" checks="RegexpSinglelineJava" id="toUpperCaseWithoutLocale"/>
55+
56+
<!-- Suppress @NullMarked check for all files that are NOT package-info.java -->
57+
<suppress files=".*(?&lt;!package-info)\.java$" checks="RegexpMultiline" id="requireNullMarkedInPackageInfo"/>
58+
59+
<!-- Suppress package-info.java and @NullMarked checks for test sources -->
60+
<suppress files="[\\/]src[\\/]test[\\/]" checks="JavadocPackage"/>
61+
<suppress files="[\\/]src[\\/]test[\\/].*package-info\.java$" checks="RegexpMultiline" id="requireNullMarkedInPackageInfo"/>
62+
63+
<!-- Suppress nullability checks for modules that don't have JSpecify nullability applied yet -->
64+
<suppress files="access[\\/]" checks="IllegalImport" id="bannedNullabilityImports"/>
65+
<suppress files="access[\\/]" checks="JavadocPackage"/>
66+
<suppress files="access[\\/].*package-info\.java" checks="RegexpMultiline" id="requireNullMarkedInPackageInfo"/>
67+
<suppress files="aspects[\\/]" checks="IllegalImport" id="bannedNullabilityImports"/>
68+
<suppress files="aspects[\\/]" checks="JavadocPackage"/>
69+
<suppress files="aspects[\\/].*package-info\.java" checks="RegexpMultiline" id="requireNullMarkedInPackageInfo"/>
70+
<suppress files="config[\\/]" checks="IllegalImport" id="bannedNullabilityImports"/>
71+
<suppress files="config[\\/]" checks="JavadocPackage"/>
72+
<suppress files="config[\\/].*package-info\.java" checks="RegexpMultiline" id="requireNullMarkedInPackageInfo"/>
73+
<suppress files="itest[\\/]" checks="IllegalImport" id="bannedNullabilityImports"/>
74+
<suppress files="itest[\\/]" checks="JavadocPackage"/>
75+
<suppress files="itest[\\/].*package-info\.java" checks="RegexpMultiline" id="requireNullMarkedInPackageInfo"/>
76+
<suppress files="ldap[\\/]" checks="IllegalImport" id="bannedNullabilityImports"/>
77+
<suppress files="ldap[\\/]" checks="JavadocPackage"/>
78+
<suppress files="ldap[\\/].*package-info\.java" checks="RegexpMultiline" id="requireNullMarkedInPackageInfo"/>
79+
<suppress files="oauth2[\\/]oauth2-authorization-server[\\/]" checks="IllegalImport" id="bannedNullabilityImports"/>
80+
<suppress files="oauth2[\\/]oauth2-authorization-server[\\/]" checks="JavadocPackage"/>
81+
<suppress files="oauth2[\\/]oauth2-authorization-server[\\/].*package-info\.java" checks="RegexpMultiline" id="requireNullMarkedInPackageInfo"/>
82+
<suppress files="oauth2[\\/]oauth2-client[\\/]" checks="IllegalImport" id="bannedNullabilityImports"/>
83+
<suppress files="oauth2[\\/]oauth2-client[\\/]" checks="JavadocPackage"/>
84+
<suppress files="oauth2[\\/]oauth2-client[\\/].*package-info\.java" checks="RegexpMultiline" id="requireNullMarkedInPackageInfo"/>
85+
<suppress files="oauth2[\\/]oauth2-core[\\/]" checks="IllegalImport" id="bannedNullabilityImports"/>
86+
<suppress files="oauth2[\\/]oauth2-core[\\/]" checks="JavadocPackage"/>
87+
<suppress files="oauth2[\\/]oauth2-core[\\/].*package-info\.java" checks="RegexpMultiline" id="requireNullMarkedInPackageInfo"/>
88+
<suppress files="oauth2[\\/]oauth2-jose[\\/]" checks="IllegalImport" id="bannedNullabilityImports"/>
89+
<suppress files="oauth2[\\/]oauth2-jose[\\/]" checks="JavadocPackage"/>
90+
<suppress files="oauth2[\\/]oauth2-jose[\\/].*package-info\.java" checks="RegexpMultiline" id="requireNullMarkedInPackageInfo"/>
91+
<suppress files="oauth2[\\/]oauth2-resource-server[\\/]" checks="IllegalImport" id="bannedNullabilityImports"/>
92+
<suppress files="oauth2[\\/]oauth2-resource-server[\\/]" checks="JavadocPackage"/>
93+
<suppress files="oauth2[\\/]oauth2-resource-server[\\/].*package-info\.java" checks="RegexpMultiline" id="requireNullMarkedInPackageInfo"/>
94+
<suppress files="saml2[\\/]saml2-service-provider[\\/]" checks="IllegalImport" id="bannedNullabilityImports"/>
95+
<suppress files="saml2[\\/]saml2-service-provider[\\/]" checks="JavadocPackage"/>
96+
<suppress files="saml2[\\/]saml2-service-provider[\\/].*package-info\.java" checks="RegexpMultiline" id="requireNullMarkedInPackageInfo"/>
5297
</suppressions>

etc/checkstyle/checkstyle.xml

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@
1111
<property name="headerFile" value="${config_loc}/header.txt" />
1212
<property name="fileExtensions" value="java" />
1313
</module>
14+
<module name="com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocPackageCheck" /><!-- Require package-info.java -->
15+
<module name="com.puppycrawl.tools.checkstyle.checks.regexp.RegexpMultilineCheck">
16+
<property name="id" value="requireNullMarkedInPackageInfo"/>
17+
<property name="format" value="@NullMarked\s+package"/>
18+
<property name="minimum" value="1"/>
19+
<property name="maximum" value="1"/>
20+
<property name="message" value="package-info.java must include @NullMarked annotation before the package declaration"/>
21+
<property name="fileExtensions" value="java"/>
22+
</module>
1423
<module name="io.spring.javaformat.checkstyle.SpringChecks">
1524
<property name="excludes" value="io.spring.javaformat.checkstyle.check.SpringHeaderCheck" />
1625
<property name="excludes" value="com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocPackageCheck" />
@@ -47,10 +56,23 @@
4756
value="String.toUpperCase() should be String.toUpperCase(Locale.ROOT) or String.toUpperCase(Locale.ENGLISH)"/>
4857
<property name="ignoreComments" value="true"/>
4958
</module>
50-
<module name="com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck">
51-
<property name="id" value="bannedImports"/>
52-
<property name="regexp" value="true"/>
53-
<property name="illegalPkgs" value="org.jetbrains.annotations, reactor.util.annotation, javax.annotation"/>
54-
</module>
59+
<module name="com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck">
60+
<property name="id" value="bannedImports"/>
61+
<property name="regexp" value="true"/>
62+
<property name="illegalPkgs" value="org.jetbrains.annotations, reactor.util.annotation, javax.annotation"/>
63+
</module>
64+
<module name="com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck">
65+
<property name="id" value="bannedNullabilityImports"/>
66+
<property name="regexp" value="true"/>
67+
<!-- Rejects all NonNull, Nonnull, and Nullable types that are NOT in the org.jspecify.annotations package. -->
68+
<property name="illegalClasses" value="^(?!org\.jspecify\.annotations).*(Non[Nn]ull|Nullable)$"/>
69+
</module>
70+
<module name="com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck">
71+
<property name="id" value="nullableAfterModifiers"/>
72+
<property name="format" value="^\s*(public|protected|private|static|final|synchronized|native|strictfp|abstract)\s+@Nullable\s+(public|protected|private|static|final|synchronized|native|strictfp|abstract)\s"/>
73+
<property name="maximum" value="0"/>
74+
<property name="message" value="@Nullable must appear immediately before the type, after all other modifiers (e.g., 'private final @Nullable Object' not 'private @Nullable final Object')"/>
75+
<property name="ignoreComments" value="true"/>
76+
</module>
5577
</module>
5678
</module>

0 commit comments

Comments
 (0)