Checkstyle for API

This commit is contained in:
Jake Potrebic
2024-12-27 23:45:56 -08:00
parent 782ce950b8
commit bfe7c906ca
22 changed files with 1315 additions and 23 deletions

View File

@@ -0,0 +1,6 @@
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
<suppressions>
<suppress checks="MissingJavadoc.*" files="src[\\/]test[\\/]java[^\\/]*[\\/].*"/>
</suppressions>

View File

@@ -0,0 +1,9 @@
NonNull
NotNull
Nullable
UnknownNullability
Unmodifiable
UnmodifiableView
Range
Positive
NonNegative

View File

@@ -0,0 +1,17 @@
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionXpathFilter Experimental Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2_xpath_experimental.dtd">
<suppressions>
<!--ignores all checks for @Deprecated(forRemoval=*) children-->
<suppress-xpath checks=".*" query="//*[MODIFIERS/ANNOTATION[(@text = 'Deprecated' or *[@text = 'Deprecated'] and ANNOTATION_MEMBER_VALUE_PAIR/IDENT[@text='forRemoval'])]]/descendant-or-self::node()"/>
<!--special case to ignore extra checks outside the root CLASS_DEF if the root CLASS_DEF is marked as deprecated for removal-->
<suppress-xpath checks=".*" query="/COMPILATION_UNIT[CLASS_DEF/MODIFIERS/ANNOTATION[IDENT[@text = 'Deprecated'] and ANNOTATION_MEMBER_VALUE_PAIR/IDENT[@text='forRemoval']]]/descendant-or-self::node()"/>
<!--ignores MissingJavadoc for ApiStatus.Internal children-->
<suppress-xpath checks="MissingJavadoc(Method|Type)" query="//*[MODIFIERS/ANNOTATION/DOT[@text = 'Internal' or *[@text = 'Internal']]]/descendant-or-self::node()"/>
<!--skip for private classes-->
<suppress-xpath checks="FinalClass" query="//CLASS_DEF[MODIFIERS/LITERAL_PRIVATE]"/>
<!--skip for classes inside of methods-->
<suppress-xpath checks="HideUtilityClassConstructor|MissingJavadoc(Method|Type)" query="//CLASS_DEF[ancestor::METHOD_DEF]"/>
</suppressions>

View File

@@ -10,6 +10,7 @@ ij_any_block_comment_add_space = false
ij_any_block_comment_at_first_column = false ij_any_block_comment_at_first_column = false
ij_any_line_comment_at_first_column = false ij_any_line_comment_at_first_column = false
ij_any_line_comment_add_space = true ij_any_line_comment_add_space = true
trim_trailing_whitespace = true
[*.tiny] [*.tiny]
indent_style = tab indent_style = tab
@@ -20,7 +21,7 @@ end_of_line = crlf
[*.yml] [*.yml]
indent_size = 2 indent_size = 2
[*.patch] [{*.patch,*.md}]
trim_trailing_whitespace = false trim_trailing_whitespace = false
[*.java] [*.java]
@@ -29,12 +30,26 @@ ij_java_class_count_to_use_import_on_demand = 999999
ij_java_insert_inner_class_imports = false ij_java_insert_inner_class_imports = false
ij_java_names_count_to_use_import_on_demand = 999999 ij_java_names_count_to_use_import_on_demand = 999999
ij_java_imports_layout = *, |, $* ij_java_imports_layout = *, |, $*
ij_java_layout_static_imports_separately = true
ij_java_generate_final_locals = true ij_java_generate_final_locals = true
ij_java_generate_final_parameters = true ij_java_generate_final_parameters = true
ij_java_method_parameters_new_line_after_left_paren = true ij_java_method_parameters_new_line_after_left_paren = true
ij_java_method_parameters_right_paren_on_new_line = true ij_java_method_parameters_right_paren_on_new_line = true
ij_java_use_fq_class_names = false ij_java_use_fq_class_names = false
ij_java_class_names_in_javadoc = 1 ij_java_class_names_in_javadoc = 1
# javadoc
ij_java_doc_add_blank_line_after_description = true
ij_java_doc_add_blank_line_after_param_comments = false
ij_java_doc_add_blank_line_after_return = false
ij_java_doc_add_p_tag_on_empty_lines = true
ij_java_doc_align_exception_comments = true
ij_java_doc_align_param_comments = true
ij_java_doc_do_not_wrap_if_one_line = false
ij_java_doc_enable_formatting = true
ij_java_doc_enable_leading_asterisks = true
ij_java_doc_indent_on_continuation = true
ij_java_doc_param_description_on_new_line = false
ij_java_doc_use_throws_not_exception_tag = true
[paper-server/src/minecraft/java/**/*.java] [paper-server/src/minecraft/java/**/*.java]
ij_java_use_fq_class_names = true ij_java_use_fq_class_names = true

View File

@@ -1,8 +1,10 @@
import io.papermc.paperweight.checkstyle.PaperCheckstyleExt
import io.papermc.paperweight.checkstyle.PaperCheckstyleTask
import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent import org.gradle.api.tasks.testing.logging.TestLogEvent
plugins { plugins {
id("io.papermc.paperweight.core") version "2.0.0-beta.18" apply false id("io.papermc.paperweight.core") version "2.0.0-SNAPSHOT" apply false
} }
subprojects { subprojects {
@@ -19,6 +21,27 @@ subprojects {
isPreserveFileTimestamps = false isPreserveFileTimestamps = false
isReproducibleFileOrder = true isReproducibleFileOrder = true
} }
val tempDisabled = setOf("paper-server", "paper-generator", "test-plugin")
if (name !in tempDisabled) {
apply(plugin = "io.papermc.paperweight.paper-checkstyle")
extensions.configure<PaperCheckstyleExt> {
val typeUseAnnotationsProvider = providers
.fileContents(rootProject.layout.projectDirectory.file(".checkstyle/type-use-annotations.txt"))
.asText.map { it.trim().split("\n").toSet() }
typeUseAnnotations.set(typeUseAnnotationsProvider)
}
tasks.withType<PaperCheckstyleTask>().configureEach {
configDirectory = rootProject.layout.projectDirectory.dir(".checkstyle")
configFile = layout.projectDirectory.file(".checkstyle/checkstyle.xml").asFile
}
dependencies {
"checkstyle"(project(":paper-checkstyle"))
}
}
} }
val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/" val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"

View File

@@ -0,0 +1,219 @@
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
<module name="SuppressionFilter">
<property name="file" value="${config_loc}/suppressions.xml"/>
<property name="optional" value="false"/>
</module>
<!--Single Suppression Filters-->
<module name="SuppressionSingleFilter">
<!--Suppresses warnings except for common TYPE_USE that should be on same line-->
<property name="checks" value="AnnotationOnSameLine"/>
<property name="message" value="^Annotation '(?!(${type_use_annotations}))"/>
</module>
<module name="SuppressionSingleFilter">
<property name="checks" value="Javadoc(Method|Type)"/>
<!--[A-Z].* check is for java annotations inside code blocks inside javadocs-->
<property name="message" value="^Unknown tag '(${custom_javadoc_tags}|[A-Z].*)'.$"/>
</module>
<!--Javadoc Comments-->
<module name="JavadocPackage"/>
<!--Misc-->
<module name="NewlineAtEndOfFile"/>
<module name="OrderedProperties"/>
<!--Whitespace-->
<module name="FileTabCharacter"/>
<module name="TreeWalker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config_loc}/xpath-suppressions.xml"/>
<property name="optional" value="false"/>
</module>
<!--Annotations-->
<module name="AnnotationOnSameLine">
<!--matches all annotations, but most are suppressed in above-->
<property name="tokens" value="METHOD_DEF"/>
</module>
<module name="AnnotationUseStyle"/>
<module name="MissingDeprecated"/>
<!--Block Checks-->
<module name="AvoidNestedBlocks"/>
<module name="EmptyBlock"/>
<module name="LeftCurly"/>
<module name="RightCurly"/>
<module name="OneTopLevelClass"/>
<module name="SealedShouldHavePermitsList"/>
<!--Class Design-->
<module name="FinalClass"/>
<module name="HideUtilityClassConstructor"/>
<module name="InterfaceIsType"/>
<!--Coding-->
<module name="ArrayTrailingComma"/>
<module name="AvoidDoubleBraceInitialization"/>
<module name="AvoidNoArgumentSuperConstructorCall"/>
<module name="ConstructorsDeclarationGrouping"/>
<module name="CovariantEquals"/>
<module name="DeclarationOrder"/>
<module name="DefaultComesLast"/>
<module name="EmptyStatement"/>
<module name="EqualsAvoidNull"/>
<module name="EqualsHashCode"/>
<module name="FallThrough"/>
<module name="FinalLocalVariable">
<property name="validateEnhancedForLoopVariable" value="true"/>
<property name="validateUnnamedVariables" value="true"/>
<property name="tokens" value="PARAMETER_DEF,VARIABLE_DEF"/>
</module>
<module name="IllegalToken"/> <!--just labels by default-->
<module name="IllegalType"/>
<module name="PatternVariableAssignment"/>
<module name="RequireThis">
<property name="validateOnlyOverlapping" value="false"/>
</module>
<module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/>
<module name="StringLiteralEquality"/>
<module name="UnnecessaryNullCheckWithInstanceOf"/>
<module name="UnnecessarySemicolonAfterOuterTypeDeclaration"/>
<module name="UnnecessarySemicolonAfterTypeMemberDeclaration"/>
<module name="UnnecessarySemicolonInEnumeration"/>
<module name="UnnecessarySemicolonInTryWithResources"/>
<module name="UnusedCatchParameterShouldBeUnnamed"/>
<module name="UnusedLambdaParameterShouldBeUnnamed"/>
<module name="UnusedLocalVariable"/>
<module name="WhenShouldBeUsed"/>
<!--Headers--> <!--N/A-->
<!--Imports-->
<module name="AvoidStarImport"/>
<module name="CustomImportOrder">
<property name="customImportOrderRules" value="THIRD_PARTY_PACKAGE,STATIC"/>
<property name="standardPackageRegExp" value="^$"/>
<property name="sortImportsInGroupAlphabetically" value="true"/>
</module>
<module name="IllegalImport">
<property name="regexp" value="true"/>
<!--checker-qual nullability-->
<property name="illegalClasses" value="org\.checkerframework\.checker\.nullness\.qual\.(Nullable|NonNull|DefaultQualifier)"/>
<!--jetbrains nullability-->
<property name="illegalClasses" value="org\.jetbrains\.annotations\.(NotNull|Nullable|NotNullByDefault)"/>
<!--javax nullability-->
</module>
<module name="IllegalImport">
<property name="regexp" value="true"/>
<!--attempts to guard against nested imports (by looking for capital letters in imports)-->
<property name="illegalClasses" value="^[^\.A-Z]+(\.[^\.A-Z]+)+?(\.[A-Z][^\.]*)(\.[A-Z][^\.]*)+$"/>
<message key="import.illegal" value="Illegal nested import - {0}"/>
</module>
<module name="RedundantImport"/>
<module name="UnusedImports"/>
<!--Javadoc Comments-->
<module name="AtclauseOrder">
<property name="tagOrder" value="@param, @return, @throws, @see, @deprecated, @hidden"/>
</module>
<module name="InvalidJavadocPosition"/>
<module name="JavadocBlockTagLocation"/>
<module name="JavadocContentLocation"/>
<module name="JavadocLeadingAsteriskAlign"/>
<module name="JavadocMethod">
<!--checks all, but doesn't require. If we have a doc, it should be valid-->
<property name="validateThrows" value="true"/>
</module>
<module name="JavadocMissingLeadingAsterisk"/>
<module name="JavadocMissingWhitespaceAfterAsterisk"/>
<module name="JavadocStyle"/> <!--checks all, but doesn't require. If we have a doc, it should be valid-->
<module name="JavadocTagContinuationIndentation"/>
<module name="JavadocType"/> <!--checks all, but doesn't require. If we have a doc, it should be valid-->
<module name="MissingJavadocMethod">
<property name="allowedAnnotations" value="Override, ApiStatus.Internal"/>
<property name="ignoreMethodNamesRegex" value="^getHandlerList$"/>
</module>
<module name="MissingJavadocPackage"/>
<module name="MissingJavadocType">
<property name="skipAnnotations" value="Generated, ApiStatus.Internal" />
</module>
<module name="NonEmptyAtclauseDescription"/>
<module name="RequireEmptyLineBeforeBlockTagGroup"/>
<!--Metrics--> <!--N/A-->
<!--Miscellaneous-->
<module name="ArrayTypeStyle"/>
<module name="AvoidEscapedUnicodeCharacters"/>
<module name="CommentsIndentation"/>
<module name="FinalParameters">
<!-- TODO pattern variable assignment isn't checked yet: PATTERN_VARIABLE_DEF-->
<!-- https://github.com/checkstyle/checkstyle/issues/17366 -->
<property name="tokens" value="METHOD_DEF,CTOR_DEF,LITERAL_CATCH,FOR_EACH_CLAUSE"/>
</module>
<module name="NoCodeInFile"/>
<module name="OuterTypeFilename"/>
<module name="UpperEll"/>
<!--Modifiers-->
<module name="ModifierOrder"/>
<module name="RedundantModifier"/>
<!--Naming Conventions-->
<module name="AbbreviationAsWordInName">
<property name="allowedAbbreviations" value="JSON,UUID"/>
<property name="ignoreFinal" value="false"/>
</module>
<module name="ClassTypeParameterName"/>
<module name="ConstantName"/>
<module name="IllegalIdentifierName"/>
<module name="InterfaceTypeParameterName"/>
<module name="LambdaParameterName"/>
<module name="LocalFinalVariableName"/>
<module name="LocalVariableName"/>
<module name="MemberName"/>
<module name="MethodName"/>
<module name="MethodTypeParameterName"/>
<module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
</module>
<module name="ParameterName"/>
<module name="PatternVariableName"/>
<module name="RecordComponentName"/>
<module name="RecordTypeParameterName"/>
<module name="StaticVariableName"/>
<module name="TypeName"/>
<!--Regexp--> <!--N/A-->
<!--Size Violations--> <!--N/A-->
<!--Whitespace-->
<module name="EmptyForInitializerPad"/>
<module name="EmptyForIteratorPad"/>
<module name="EmptyLineSeparator">
<property name="allowNoEmptyLineBetweenFields" value="true"/>
<property name="tokens" value="IMPORT,STATIC_IMPORT,CLASS_DEF,INTERFACE_DEF,ENUM_DEF,STATIC_INIT,INSTANCE_INIT,METHOD_DEF,CTOR_DEF,VARIABLE_DEF,RECORD_DEF,COMPACT_CTOR_DEF"/>
</module>
<module name="GenericWhitespace"/>
<module name="MethodParamPad"/>
<module name="NoLineWrap"/> <!--just imports and packages-->
<module name="NoWhitespaceAfter"/>
<module name="NoWhitespaceBefore"/>
<module name="NoWhitespaceBeforeCaseDefaultColon"/>
<module name="ParenPad"/>
<module name="SingleSpaceSeparator"/>
<module name="TypecastParenPad"/>
<module name="WhitespaceAfter"/>
<module name="WhitespaceAround"/>
<!--Custom-->
<module name="JavadocAlignParameterDescription"/>
<module name="NullabilityAnnotations"/>
<module name="RedundantNullability"/>
</module>
</module>

View File

@@ -0,0 +1,198 @@
paper-api/src/generated/java/com/destroystokyo/paper/entity/ai/
paper-api/src/generated/java/io/papermc/paper/registry/keys/
paper-api/src/generated/java/io/papermc/paper/registry/keys/tags/
paper-api/src/main/java/co/aikar/timings/
paper-api/src/main/java/co/aikar/util/
paper-api/src/main/java/com/destroystokyo/paper/
paper-api/src/main/java/com/destroystokyo/paper/block/
paper-api/src/main/java/com/destroystokyo/paper/brigadier/
paper-api/src/main/java/com/destroystokyo/paper/entity/
paper-api/src/main/java/com/destroystokyo/paper/entity/ai/
paper-api/src/main/java/com/destroystokyo/paper/entity/villager/
paper-api/src/main/java/com/destroystokyo/paper/event/block/
paper-api/src/main/java/com/destroystokyo/paper/event/brigadier/
paper-api/src/main/java/com/destroystokyo/paper/event/entity/
paper-api/src/main/java/com/destroystokyo/paper/event/inventory/
paper-api/src/main/java/com/destroystokyo/paper/event/player/
paper-api/src/main/java/com/destroystokyo/paper/event/profile/
paper-api/src/main/java/com/destroystokyo/paper/event/server/
paper-api/src/main/java/com/destroystokyo/paper/exception/
paper-api/src/main/java/com/destroystokyo/paper/inventory/meta/
paper-api/src/main/java/com/destroystokyo/paper/loottable/
paper-api/src/main/java/com/destroystokyo/paper/network/
paper-api/src/main/java/com/destroystokyo/paper/profile/
paper-api/src/main/java/com/destroystokyo/paper/util/
paper-api/src/main/java/com/destroystokyo/paper/utils/
paper-api/src/main/java/io/papermc/paper/advancement/
paper-api/src/main/java/io/papermc/paper/annotation/
paper-api/src/main/java/io/papermc/paper/ban/
paper-api/src/main/java/io/papermc/paper/block/
paper-api/src/main/java/io/papermc/paper/block/fluid/
paper-api/src/main/java/io/papermc/paper/block/fluid/type/
paper-api/src/main/java/io/papermc/paper/brigadier/
paper-api/src/main/java/io/papermc/paper/chat/
paper-api/src/main/java/io/papermc/paper/command/
paper-api/src/main/java/io/papermc/paper/command/brigadier/
paper-api/src/main/java/io/papermc/paper/command/brigadier/argument/
paper-api/src/main/java/io/papermc/paper/command/brigadier/argument/predicate/
paper-api/src/main/java/io/papermc/paper/command/brigadier/argument/range/
paper-api/src/main/java/io/papermc/paper/command/brigadier/argument/resolvers/
paper-api/src/main/java/io/papermc/paper/command/brigadier/argument/resolvers/selector/
paper-api/src/main/java/io/papermc/paper/configuration/
paper-api/src/main/java/io/papermc/paper/connection/
paper-api/src/main/java/io/papermc/paper/datacomponent/
paper-api/src/main/java/io/papermc/paper/datacomponent/item/
paper-api/src/main/java/io/papermc/paper/datacomponent/item/attribute/
paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocksattacks/
paper-api/src/main/java/io/papermc/paper/datacomponent/item/consumable/
paper-api/src/main/java/io/papermc/paper/datapack/
paper-api/src/main/java/io/papermc/paper/dialog/
paper-api/src/main/java/io/papermc/paper/enchantments/
paper-api/src/main/java/io/papermc/paper/entity/
paper-api/src/main/java/io/papermc/paper/event/block/
paper-api/src/main/java/io/papermc/paper/event/connection/
paper-api/src/main/java/io/papermc/paper/event/connection/configuration/
paper-api/src/main/java/io/papermc/paper/event/entity/
paper-api/src/main/java/io/papermc/paper/event/executor/
paper-api/src/main/java/io/papermc/paper/event/packet/
paper-api/src/main/java/io/papermc/paper/event/player/
paper-api/src/main/java/io/papermc/paper/event/server/
paper-api/src/main/java/io/papermc/paper/event/world/
paper-api/src/main/java/io/papermc/paper/event/world/border/
paper-api/src/main/java/io/papermc/paper/generated/
paper-api/src/main/java/io/papermc/paper/inventory/
paper-api/src/main/java/io/papermc/paper/inventory/tooltip/
paper-api/src/main/java/io/papermc/paper/item/
paper-api/src/main/java/io/papermc/paper/math/
paper-api/src/main/java/io/papermc/paper/persistence/
paper-api/src/main/java/io/papermc/paper/plugin/
paper-api/src/main/java/io/papermc/paper/plugin/bootstrap/
paper-api/src/main/java/io/papermc/paper/plugin/configuration/
paper-api/src/main/java/io/papermc/paper/plugin/lifecycle/event/
paper-api/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/
paper-api/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/
paper-api/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/
paper-api/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/
paper-api/src/main/java/io/papermc/paper/plugin/loader/
paper-api/src/main/java/io/papermc/paper/plugin/loader/library/
paper-api/src/main/java/io/papermc/paper/plugin/loader/library/impl/
paper-api/src/main/java/io/papermc/paper/plugin/provider/classloader/
paper-api/src/main/java/io/papermc/paper/plugin/provider/entrypoint/
paper-api/src/main/java/io/papermc/paper/plugin/provider/util/
paper-api/src/main/java/io/papermc/paper/potion/
paper-api/src/main/java/io/papermc/paper/raytracing/
paper-api/src/main/java/io/papermc/paper/registry/
paper-api/src/main/java/io/papermc/paper/registry/data/
paper-api/src/main/java/io/papermc/paper/registry/data/client/
paper-api/src/main/java/io/papermc/paper/registry/data/dialog/
paper-api/src/main/java/io/papermc/paper/registry/data/dialog/action/
paper-api/src/main/java/io/papermc/paper/registry/data/dialog/body/
paper-api/src/main/java/io/papermc/paper/registry/data/dialog/input/
paper-api/src/main/java/io/papermc/paper/registry/data/dialog/type/
paper-api/src/main/java/io/papermc/paper/registry/event/
paper-api/src/main/java/io/papermc/paper/registry/event/type/
paper-api/src/main/java/io/papermc/paper/registry/holder/
paper-api/src/main/java/io/papermc/paper/registry/set/
paper-api/src/main/java/io/papermc/paper/registry/tag/
paper-api/src/main/java/io/papermc/paper/scoreboard/numbers/
paper-api/src/main/java/io/papermc/paper/tag/
paper-api/src/main/java/io/papermc/paper/text/
paper-api/src/main/java/io/papermc/paper/threadedregions/scheduler/
paper-api/src/main/java/io/papermc/paper/util/
paper-api/src/main/java/io/papermc/paper/world/
paper-api/src/main/java/io/papermc/paper/world/damagesource/
paper-api/src/main/java/io/papermc/paper/world/flag/
paper-api/src/main/java/org/bukkit/
paper-api/src/main/java/org/bukkit/advancement/
paper-api/src/main/java/org/bukkit/attribute/
paper-api/src/main/java/org/bukkit/ban/
paper-api/src/main/java/org/bukkit/block/
paper-api/src/main/java/org/bukkit/block/banner/
paper-api/src/main/java/org/bukkit/block/data/
paper-api/src/main/java/org/bukkit/block/data/type/
paper-api/src/main/java/org/bukkit/block/sign/
paper-api/src/main/java/org/bukkit/block/spawner/
paper-api/src/main/java/org/bukkit/block/structure/
paper-api/src/main/java/org/bukkit/boss/
paper-api/src/main/java/org/bukkit/command/
paper-api/src/main/java/org/bukkit/command/defaults/
paper-api/src/main/java/org/bukkit/configuration/
paper-api/src/main/java/org/bukkit/configuration/file/
paper-api/src/main/java/org/bukkit/configuration/serialization/
paper-api/src/main/java/org/bukkit/conversations/
paper-api/src/main/java/org/bukkit/damage/
paper-api/src/main/java/org/bukkit/enchantments/
paper-api/src/main/java/org/bukkit/entity/
paper-api/src/main/java/org/bukkit/entity/boat/
paper-api/src/main/java/org/bukkit/entity/memory/
paper-api/src/main/java/org/bukkit/entity/minecart/
paper-api/src/main/java/org/bukkit/event/
paper-api/src/main/java/org/bukkit/event/block/
paper-api/src/main/java/org/bukkit/event/command/
paper-api/src/main/java/org/bukkit/event/enchantment/
paper-api/src/main/java/org/bukkit/event/entity/
paper-api/src/main/java/org/bukkit/event/hanging/
paper-api/src/main/java/org/bukkit/event/inventory/
paper-api/src/main/java/org/bukkit/event/player/
paper-api/src/main/java/org/bukkit/event/raid/
paper-api/src/main/java/org/bukkit/event/server/
paper-api/src/main/java/org/bukkit/event/vehicle/
paper-api/src/main/java/org/bukkit/event/weather/
paper-api/src/main/java/org/bukkit/event/world/
paper-api/src/main/java/org/bukkit/generator/
paper-api/src/main/java/org/bukkit/generator/structure/
paper-api/src/main/java/org/bukkit/help/
paper-api/src/main/java/org/bukkit/inventory/
paper-api/src/main/java/org/bukkit/inventory/meta/
paper-api/src/main/java/org/bukkit/inventory/meta/components/
paper-api/src/main/java/org/bukkit/inventory/meta/tags/
paper-api/src/main/java/org/bukkit/inventory/meta/trim/
paper-api/src/main/java/org/bukkit/inventory/recipe/
paper-api/src/main/java/org/bukkit/inventory/view/
paper-api/src/main/java/org/bukkit/inventory/view/builder/
paper-api/src/main/java/org/bukkit/loot/
paper-api/src/main/java/org/bukkit/map/
paper-api/src/main/java/org/bukkit/material/
paper-api/src/main/java/org/bukkit/material/types/
paper-api/src/main/java/org/bukkit/metadata/
paper-api/src/main/java/org/bukkit/packs/
paper-api/src/main/java/org/bukkit/permissions/
paper-api/src/main/java/org/bukkit/persistence/
paper-api/src/main/java/org/bukkit/plugin/
paper-api/src/main/java/org/bukkit/plugin/java/
paper-api/src/main/java/org/bukkit/plugin/messaging/
paper-api/src/main/java/org/bukkit/potion/
paper-api/src/main/java/org/bukkit/profile/
paper-api/src/main/java/org/bukkit/projectiles/
paper-api/src/main/java/org/bukkit/scheduler/
paper-api/src/main/java/org/bukkit/scoreboard/
paper-api/src/main/java/org/bukkit/spawner/
paper-api/src/main/java/org/bukkit/structure/
paper-api/src/main/java/org/bukkit/tag/
paper-api/src/main/java/org/bukkit/util/
paper-api/src/main/java/org/bukkit/util/io/
paper-api/src/main/java/org/bukkit/util/noise/
paper-api/src/main/java/org/bukkit/util/permissions/
paper-api/src/main/java/org/spigotmc/
paper-api/src/main/java/org/spigotmc/event/player/
paper-api/src/test/java/com/destroystokyo/paper/
paper-api/src/test/java/io/papermc/paper/
paper-api/src/test/java/io/papermc/paper/adventure/
paper-api/src/test/java/io/papermc/paper/registry/
paper-api/src/test/java/io/papermc/paper/testing/
paper-api/src/test/java/io/papermc/paper/util/
paper-api/src/test/java/org/bukkit/
paper-api/src/test/java/org/bukkit/configuration/
paper-api/src/test/java/org/bukkit/configuration/file/
paper-api/src/test/java/org/bukkit/conversations/
paper-api/src/test/java/org/bukkit/event/
paper-api/src/test/java/org/bukkit/materials/
paper-api/src/test/java/org/bukkit/metadata/
paper-api/src/test/java/org/bukkit/plugin/
paper-api/src/test/java/org/bukkit/plugin/messaging/
paper-api/src/test/java/org/bukkit/scoreboard/
paper-api/src/test/java/org/bukkit/support/
paper-api/src/test/java/org/bukkit/support/provider/
paper-api/src/test/java/org/bukkit/support/test/
paper-api/src/test/java/org/bukkit/util/
paper-api/src/test/java/org/bukkit/util/io/

View File

@@ -1,3 +1,7 @@
import io.papermc.paperweight.checkstyle.JavadocTag
import io.papermc.paperweight.checkstyle.PaperCheckstyleTask
import io.papermc.paperweight.checkstyle.setCustomJavadocTags
plugins { plugins {
`java-library` `java-library`
`maven-publish` `maven-publish`
@@ -9,6 +13,22 @@ java {
withJavadocJar() withJavadocJar()
} }
val customJavadocTags = setOf(
JavadocTag("apiNote", "a", "API Note:"),
)
paperCheckstyle {
val packagesToSkipSource = providers
.fileContents(layout.projectDirectory.file(".checkstyle/packages.txt"))
.asText.map { it.trim().split("\n").toSet() }
directoriesToSkip.set(packagesToSkipSource)
}
tasks.withType<PaperCheckstyleTask>().configureEach {
setCustomJavadocTags(customJavadocTags)
}
val annotationsVersion = "26.0.2" val annotationsVersion = "26.0.2"
// Keep in sync with paper-server adventure-text-serializer-ansi dep // Keep in sync with paper-server adventure-text-serializer-ansi dep
val adventureVersion = "4.23.0" val adventureVersion = "4.23.0"
@@ -187,7 +207,7 @@ tasks.withType<Javadoc>().configureEach {
"https://logging.apache.org/log4j/2.x/javadoc/log4j-api/", "https://logging.apache.org/log4j/2.x/javadoc/log4j-api/",
"https://javadoc.io/doc/org.apache.maven.resolver/maven-resolver-api/1.7.3", "https://javadoc.io/doc/org.apache.maven.resolver/maven-resolver-api/1.7.3",
) )
options.tags("apiNote:a:API Note:") options.tags(customJavadocTags.map { it.toOptionString() })
inputs.files(apiAndDocs).ignoreEmptyDirectories().withPropertyName(apiAndDocs.name + "-configuration") inputs.files(apiAndDocs).ignoreEmptyDirectories().withPropertyName(apiAndDocs.name + "-configuration")
val apiAndDocsElements = apiAndDocs.elements val apiAndDocsElements = apiAndDocs.elements

View File

@@ -3,17 +3,15 @@ package io.papermc.paper;
import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.world.damagesource.CombatEntry; import io.papermc.paper.world.damagesource.CombatEntry;
import io.papermc.paper.world.damagesource.FallLocationType; import io.papermc.paper.world.damagesource.FallLocationType;
import java.util.function.Predicate;
import net.kyori.adventure.util.Services; import net.kyori.adventure.util.Services;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.damage.DamageEffect; import org.bukkit.damage.DamageEffect;
import org.bukkit.damage.DamageSource; import org.bukkit.damage.DamageSource;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable; import org.jspecify.annotations.Nullable;
import java.util.function.Predicate;
/** /**
* Static bridge to the server internals. * Static bridge to the server internals.
* <p> * <p>
@@ -21,7 +19,6 @@ import java.util.function.Predicate;
* cause issues when called under unexpected circumstances. * cause issues when called under unexpected circumstances.
*/ */
@ApiStatus.Internal @ApiStatus.Internal
@NullMarked
public interface InternalAPIBridge { public interface InternalAPIBridge {
/** /**
@@ -31,6 +28,7 @@ public interface InternalAPIBridge {
*/ */
static InternalAPIBridge get() { static InternalAPIBridge get() {
class Holder { class Holder {
public static final InternalAPIBridge INSTANCE = Services.service(InternalAPIBridge.class).orElseThrow(); public static final InternalAPIBridge INSTANCE = Services.service(InternalAPIBridge.class).orElseThrow();
} }
@@ -49,30 +47,31 @@ public interface InternalAPIBridge {
* Constructs the legacy custom biome instance for the biome enum. * Constructs the legacy custom biome instance for the biome enum.
* *
* @return the created biome. * @return the created biome.
* @deprecated for removal, legacy custom biome constant isn't supported
*/ */
@Deprecated(forRemoval = true, since = "1.21.5") @Deprecated(forRemoval = true, since = "1.21.5")
@ApiStatus.ScheduledForRemoval(inVersion = "1.22") @ApiStatus.ScheduledForRemoval(inVersion = "1.22")
Biome constructLegacyCustomBiome(); Biome constructLegacyCustomBiome();
/** /**
* Creates a new combat entry. * Creates a new combat entry.
* <p> * <p>
* The fall location and fall distance will be calculated from the entity's current state. * The fall location and fall distance will be calculated from the entity's current state.
* *
* @param entity entity * @param entity entity
* @param damageSource damage source * @param damageSource damage source
* @param damage damage amount * @param damage damage amount
* @return new combat entry * @return new combat entry
*/ */
CombatEntry createCombatEntry(LivingEntity entity, DamageSource damageSource, float damage); CombatEntry createCombatEntry(LivingEntity entity, DamageSource damageSource, float damage);
/** /**
* Creates a new combat entry * Creates a new combat entry.
* *
* @param damageSource damage source * @param damageSource damage source
* @param damage damage amount * @param damage damage amount
* @param fallLocationType fall location type * @param fallLocationType fall location type
* @param fallDistance fall distance * @param fallDistance fall distance
* @return combat entry * @return combat entry
*/ */
CombatEntry createCombatEntry(DamageSource damageSource, float damage, @Nullable FallLocationType fallLocationType, float fallDistance); CombatEntry createCombatEntry(DamageSource damageSource, float damage, @Nullable FallLocationType fallLocationType, float fallDistance);
@@ -87,4 +86,3 @@ public interface InternalAPIBridge {
*/ */
Predicate<CommandSourceStack> restricted(Predicate<CommandSourceStack> predicate); Predicate<CommandSourceStack> restricted(Predicate<CommandSourceStack> predicate);
} }

View File

@@ -6,12 +6,10 @@ import java.util.OptionalInt;
import net.kyori.adventure.key.Key; import net.kyori.adventure.key.Key;
import net.kyori.adventure.util.Services; import net.kyori.adventure.util.Services;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
/** /**
* Information about the current server build. * Information about the current server build.
*/ */
@NullMarked
@ApiStatus.NonExtendable @ApiStatus.NonExtendable
public interface ServerBuildInfo { public interface ServerBuildInfo {
/** /**
@@ -30,6 +28,7 @@ public interface ServerBuildInfo {
static final Optional<ServerBuildInfo> INSTANCE = Services.service(ServerBuildInfo.class); static final Optional<ServerBuildInfo> INSTANCE = Services.service(ServerBuildInfo.class);
} }
//</editor-fold> //</editor-fold>
return Holder.INSTANCE.orElseThrow(); return Holder.INSTANCE.orElseThrow();
} }
@@ -47,7 +46,7 @@ public interface ServerBuildInfo {
* @return {@code true} if the server supports the specified brand * @return {@code true} if the server supports the specified brand
*/ */
@ApiStatus.Experimental @ApiStatus.Experimental
boolean isBrandCompatible(final Key brandId); boolean isBrandCompatible(Key brandId);
/** /**
* Gets the brand name of the server. * Gets the brand name of the server.
@@ -104,7 +103,7 @@ public interface ServerBuildInfo {
* @param representation the type of representation * @param representation the type of representation
* @return a string * @return a string
*/ */
String asString(final StringRepresentation representation); String asString(StringRepresentation representation);
/** /**
* String representation types. * String representation types.

View File

@@ -0,0 +1,7 @@
/**
* Root package for the Paper API.
*/
@NullMarked
package io.papermc.paper;
import org.jspecify.annotations.NullMarked;

View File

@@ -0,0 +1,206 @@
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
<module name="SuppressionFilter">
<property name="file" value="${config_loc}/suppressions.xml"/>
<property name="optional" value="false"/>
</module>
<!--Single Suppression Filters-->
<module name="SuppressionSingleFilter">
<!--Suppresses warnings except for common TYPE_USE that should be on same line-->
<property name="checks" value="AnnotationOnSameLine"/>
<property name="message" value="^Annotation '(?!(${type_use_annotations}))"/>
</module>
<!--Javadoc Comments-->
<module name="JavadocPackage"/>
<!--Misc-->
<module name="NewlineAtEndOfFile"/>
<module name="OrderedProperties"/>
<!--Whitespace-->
<module name="FileTabCharacter"/>
<module name="TreeWalker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config_loc}/xpath-suppressions.xml"/>
<property name="optional" value="false"/>
</module>
<!--Annotations-->
<module name="AnnotationOnSameLine">
<!--matches all annotations, but most are suppressed in above-->
<property name="tokens" value="METHOD_DEF"/>
</module>
<module name="AnnotationUseStyle"/>
<module name="MissingDeprecated"/>
<!--Block Checks-->
<module name="AvoidNestedBlocks"/>
<module name="EmptyBlock"/>
<module name="LeftCurly"/>
<module name="RightCurly"/>
<module name="OneTopLevelClass"/>
<module name="SealedShouldHavePermitsList"/>
<!--Class Design-->
<module name="FinalClass"/>
<module name="HideUtilityClassConstructor"/>
<module name="InterfaceIsType"/>
<!--Coding-->
<module name="ArrayTrailingComma"/>
<module name="AvoidDoubleBraceInitialization"/>
<module name="AvoidNoArgumentSuperConstructorCall"/>
<module name="ConstructorsDeclarationGrouping"/>
<module name="CovariantEquals"/>
<module name="DeclarationOrder"/>
<module name="DefaultComesLast"/>
<module name="EmptyStatement"/>
<module name="EqualsAvoidNull"/>
<module name="EqualsHashCode"/>
<module name="FallThrough"/>
<module name="FinalLocalVariable">
<property name="validateEnhancedForLoopVariable" value="true"/>
<property name="validateUnnamedVariables" value="true"/>
<property name="tokens" value="PARAMETER_DEF,VARIABLE_DEF"/>
</module>
<module name="IllegalToken"/> <!--just labels by default-->
<module name="IllegalType"/>
<module name="PatternVariableAssignment"/>
<module name="RequireThis">
<property name="validateOnlyOverlapping" value="false"/>
</module>
<module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/>
<module name="StringLiteralEquality"/>
<module name="UnnecessaryNullCheckWithInstanceOf"/>
<module name="UnnecessarySemicolonAfterOuterTypeDeclaration"/>
<module name="UnnecessarySemicolonAfterTypeMemberDeclaration"/>
<module name="UnnecessarySemicolonInEnumeration"/>
<module name="UnnecessarySemicolonInTryWithResources"/>
<module name="UnusedCatchParameterShouldBeUnnamed"/>
<module name="UnusedLambdaParameterShouldBeUnnamed"/>
<module name="UnusedLocalVariable"/>
<module name="WhenShouldBeUsed"/>
<!--Headers--> <!--N/A-->
<!--Imports-->
<module name="AvoidStarImport"/>
<module name="CustomImportOrder">
<property name="customImportOrderRules" value="THIRD_PARTY_PACKAGE,STATIC"/>
<property name="standardPackageRegExp" value="^$"/>
<property name="sortImportsInGroupAlphabetically" value="true"/>
</module>
<module name="IllegalImport">
<property name="regexp" value="true"/>
<!--checker-qual nullability-->
<property name="illegalClasses" value="org\.checkerframework\.checker\.nullness\.qual\.(Nullable|NonNull|DefaultQualifier)"/>
<!--jetbrains nullability-->
<property name="illegalClasses" value="org\.jetbrains\.annotations\.(NotNull|Nullable|NotNullByDefault)"/>
<!--javax nullability-->
</module>
<module name="IllegalImport">
<property name="regexp" value="true"/>
<!--attempts to guard against nested imports (by looking for capital letters in imports)-->
<property name="illegalClasses" value="^[^\.A-Z]+(\.[^\.A-Z]+)+?(\.[A-Z][^\.]*)(\.[A-Z][^\.]*)+$"/>
<message key="import.illegal" value="Illegal nested import - {0}"/>
</module>
<module name="RedundantImport"/>
<module name="UnusedImports"/>
<!--Javadoc Comments-->
<module name="AtclauseOrder">
<property name="tagOrder" value="@param, @return, @throws, @see, @deprecated, @hidden"/>
</module>
<module name="InvalidJavadocPosition"/>
<module name="JavadocBlockTagLocation"/>
<module name="JavadocContentLocation"/>
<module name="JavadocLeadingAsteriskAlign"/>
<module name="JavadocMethod">
<!--checks all, but doesn't require. If we have a doc, it should be valid-->
<property name="validateThrows" value="true"/>
</module>
<module name="JavadocMissingLeadingAsterisk"/>
<module name="JavadocMissingWhitespaceAfterAsterisk"/>
<module name="JavadocStyle"/> <!--checks all, but doesn't require. If we have a doc, it should be valid-->
<module name="JavadocTagContinuationIndentation"/>
<module name="JavadocType"/> <!--checks all, but doesn't require. If we have a doc, it should be valid-->
<module name="NonEmptyAtclauseDescription"/>
<module name="RequireEmptyLineBeforeBlockTagGroup"/>
<!--Metrics--> <!--N/A-->
<!--Miscellaneous-->
<module name="ArrayTypeStyle"/>
<module name="AvoidEscapedUnicodeCharacters"/>
<module name="CommentsIndentation"/>
<module name="FinalParameters">
<!-- TODO pattern variable assignment isn't checked yet: PATTERN_VARIABLE_DEF-->
<!-- https://github.com/checkstyle/checkstyle/issues/17366 -->
<property name="tokens" value="METHOD_DEF,CTOR_DEF,LITERAL_CATCH,FOR_EACH_CLAUSE"/>
</module>
<module name="NoCodeInFile"/>
<module name="OuterTypeFilename"/>
<module name="UpperEll"/>
<!--Modifiers-->
<module name="ModifierOrder"/>
<module name="RedundantModifier"/>
<!--Naming Conventions-->
<module name="AbbreviationAsWordInName">
<property name="allowedAbbreviations" value="JSON,UUID"/>
<property name="ignoreFinal" value="false"/>
</module>
<module name="ClassTypeParameterName"/>
<module name="ConstantName"/>
<module name="IllegalIdentifierName"/>
<module name="InterfaceTypeParameterName"/>
<module name="LambdaParameterName"/>
<module name="LocalFinalVariableName"/>
<module name="LocalVariableName"/>
<module name="MemberName"/>
<module name="MethodName"/>
<module name="MethodTypeParameterName"/>
<module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
</module>
<module name="ParameterName"/>
<module name="PatternVariableName"/>
<module name="RecordComponentName"/>
<module name="RecordTypeParameterName"/>
<module name="StaticVariableName"/>
<module name="TypeName"/>
<!--Regexp--> <!--N/A-->
<!--Size Violations--> <!--N/A-->
<!--Whitespace-->
<module name="EmptyForInitializerPad"/>
<module name="EmptyForIteratorPad"/>
<module name="EmptyLineSeparator">
<property name="allowNoEmptyLineBetweenFields" value="true"/>
<property name="tokens" value="IMPORT,STATIC_IMPORT,CLASS_DEF,INTERFACE_DEF,ENUM_DEF,STATIC_INIT,INSTANCE_INIT,METHOD_DEF,CTOR_DEF,VARIABLE_DEF,RECORD_DEF,COMPACT_CTOR_DEF"/>
</module>
<module name="GenericWhitespace"/>
<module name="MethodParamPad"/>
<module name="NoLineWrap"/> <!--just imports and packages-->
<module name="NoWhitespaceAfter"/>
<module name="NoWhitespaceBefore"/>
<module name="NoWhitespaceBeforeCaseDefaultColon"/>
<module name="ParenPad"/>
<module name="SingleSpaceSeparator"/>
<module name="TypecastParenPad"/>
<module name="WhitespaceAfter"/>
<module name="WhitespaceAround"/>
<!--Custom-->
<module name="JavadocAlignParameterDescription"/>
<module name="NullabilityAnnotations"/>
<module name="RedundantNullability"/>
</module>
</module>

View File

@@ -0,0 +1,8 @@
plugins {
java
}
dependencies {
implementation("com.puppycrawl.tools:checkstyle:10.26.1")
implementation("org.jspecify:jspecify:1.0.0")
}

View File

@@ -0,0 +1,129 @@
package io.papermc.checkstyle;
import com.puppycrawl.tools.checkstyle.JavaParser;
import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.DetailNode;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
import com.puppycrawl.tools.checkstyle.utils.JavadocUtil;
import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.function.Predicate;
import org.jspecify.annotations.Nullable;
/**
* Utility class containing utility methods for custom checkstyle checks.
*/
public final class Util {
private Util() {
}
/**
* Gets the previous sibling of the given node with the given type.
*
* @param node the node
* @param type the type
* @return the previous sibling with the given type, or {@code null} if not found
*/
public static @Nullable DetailNode getPreviousSibling(final DetailNode node, final int type) {
DetailNode sibling = JavadocUtil.getPreviousSibling(node);
while (sibling != null && sibling.getType() != type) {
sibling = JavadocUtil.getPreviousSibling(sibling);
}
return sibling;
}
/**
* Gets the next sibling of the given node with the given type.
*
* @param node the node
* @param type the type
* @return the next sibling with the given type, or {@code null} if not found
*/
public static @Nullable DetailAST getNextSibling(final DetailAST node, final int type) {
DetailAST sibling = node.getNextSibling();
while (sibling != null && sibling.getType() != type) {
sibling = sibling.getNextSibling();
}
return sibling;
}
/**
* Gets the enclosing type declaration of the given node.
*
* @param node the node
* @return the enclosing type declaration, or {@code null} if not found
*/
public static @Nullable DetailAST getEnclosingTypeDeclaration(final DetailAST node) {
DetailAST parent = node.getParent();
while (parent != null && !TokenUtil.isTypeDeclaration(parent.getType())) {
parent = parent.getParent();
}
return parent;
}
/**
* Gets an iterator over the children of the given node with the given type.
*
* @param ast the node
* @param type the type
* @return the iterator
*/
public static Iterable<DetailAST> childrenIterator(final DetailAST ast, final int type) {
return () -> new Iterator<>() {
private @Nullable DetailAST current = TokenUtil.findFirstTokenByPredicate(ast, child -> child.getType() == type).orElse(null);
@Override
public boolean hasNext() {
return this.current != null;
}
@Override
public DetailAST next() {
if (this.current == null) {
throw new NoSuchElementException();
}
final DetailAST result = this.current;
this.current = getNextSibling(this.current, type);
return result;
}
};
}
public static @Nullable DetailAST findPackageInfoFor(final Path filePath) {
final Path packageInfo = filePath.getParent().resolve("package-info.java");
if (Files.notExists(packageInfo)) {
return null;
}
final DetailAST packageInfoAst;
try {
packageInfoAst = JavaParser.parseFile(packageInfo.toFile(), JavaParser.Options.WITHOUT_COMMENTS);
} catch (final IOException | CheckstyleException e) {
throw new RuntimeException(e);
}
return packageInfoAst;
}
public static boolean isPackageInfoAnnotated(final Path filePath, final Predicate<DetailAST> annotationPredicate) {
final DetailAST packageInfoAst = Util.findPackageInfoFor(filePath);
if (packageInfoAst == null) {
return false;
}
final DetailAST firstToken = packageInfoAst.findFirstToken(TokenTypes.PACKAGE_DEF);
if (firstToken == null) {
return false;
}
final DetailAST annotations = firstToken.findFirstToken(TokenTypes.ANNOTATIONS);
for (final DetailAST annotation : Util.childrenIterator(annotations, TokenTypes.ANNOTATION)) {
if (annotationPredicate.test(annotation)) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,49 @@
package io.papermc.checkstyle.checks;
import com.puppycrawl.tools.checkstyle.api.DetailNode;
import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes;
import com.puppycrawl.tools.checkstyle.checks.javadoc.AbstractJavadocCheck;
import com.puppycrawl.tools.checkstyle.utils.JavadocUtil;
import io.papermc.checkstyle.Util;
import java.util.ArrayList;
import java.util.List;
/**
* Checks that parameter descriptions in Javadoc are aligned.
*/
public final class JavadocAlignParameterDescriptionCheck extends AbstractJavadocCheck {
@Override
public int[] getDefaultJavadocTokens() {
return new int[]{JavadocTokenTypes.JAVADOC};
}
@Override
public void visitJavadocToken(final DetailNode detailNode) {
final List<DetailNode> params = new ArrayList<>();
int maxColumn = -1;
for (final DetailNode child : detailNode.getChildren()) {
final DetailNode paramLiteralNode = JavadocUtil.findFirstToken(child, JavadocTokenTypes.PARAM_LITERAL);
if (child.getType() != JavadocTokenTypes.JAVADOC_TAG || paramLiteralNode == null) {
continue;
}
final DetailNode paramDescription = JavadocUtil.getNextSibling(paramLiteralNode, JavadocTokenTypes.DESCRIPTION);
maxColumn = Math.max(maxColumn, paramDescription.getColumnNumber());
params.add(paramDescription);
}
for (final DetailNode param : params) {
if (param.getColumnNumber() != maxColumn) {
final DetailNode paramNameNode = Util.getPreviousSibling(param, JavadocTokenTypes.PARAMETER_NAME);
if (paramNameNode == null) {
continue;
}
this.log(
param.getLineNumber(),
param.getColumnNumber() - 1,
"Param description for %s should start at column %d".formatted(paramNameNode.getText(), maxColumn)
);
}
}
}
}

View File

@@ -0,0 +1,116 @@
package io.papermc.checkstyle.checks;
import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
import io.papermc.checkstyle.Util;
import java.nio.file.Path;
import java.util.Set;
import org.jspecify.annotations.Nullable;
/**
* Checks that nullability annotations are present where required.
*/
public final class NullabilityAnnotationsCheck extends AbstractCheck {
private static final Set<String> NULLABILITY_ANNOTATIONS = Set.of("Nullable", "NonNull");
@Override
public int[] getDefaultTokens() {
return this.getRequiredTokens();
}
@Override
public int[] getAcceptableTokens() {
return this.getRequiredTokens();
}
@Override
public int[] getRequiredTokens() {
return new int[]{
TokenTypes.METHOD_DEF,
TokenTypes.PARAMETER_DEF,
TokenTypes.ANNOTATION_FIELD_DEF,
TokenTypes.RECORD_COMPONENT_DEF, // annotations are in ANNOTATIONS token block
};
}
private static boolean hasNoNullabilityAnnotationChildren(final @Nullable DetailAST ast) {
if (ast == null) {
return true;
}
for (final DetailAST annotation : Util.childrenIterator(ast, TokenTypes.ANNOTATION)) {
if (annotation.getChildCount(TokenTypes.IDENT) != 1) {
// skip `.` annotations like ApiStatus.Internal as these aren't nullability annotations
continue;
}
final String ident = annotation.findFirstToken(TokenTypes.IDENT).getText();
if (NULLABILITY_ANNOTATIONS.contains(ident)) {
return false;
}
}
return true;
}
private void visitMethodDefOrParamDef(final DetailAST holderDef, final int baseAnnotationHolderType) {
final DetailAST type = holderDef.findFirstToken(TokenTypes.TYPE);
final DetailAST arrayTypeStart = type.findFirstToken(TokenTypes.ARRAY_DECLARATOR);
if (arrayTypeStart != null) {
final DetailAST arrayAnnotations = type.findFirstToken(TokenTypes.ANNOTATIONS);
if (hasNoNullabilityAnnotationChildren(arrayAnnotations)) {
this.log(arrayTypeStart.getLineNo(), arrayTypeStart.getColumnNo() - 1, "Array is missing nullability annotation");
}
}
final DetailAST dot = type.findFirstToken(TokenTypes.DOT);
final DetailAST annotationHolder;
final DetailAST identLoc;
if (dot != null) {
annotationHolder = dot.findFirstToken(TokenTypes.ANNOTATIONS);
identLoc = dot.findFirstToken(TokenTypes.IDENT);
} else {
annotationHolder = holderDef.findFirstToken(baseAnnotationHolderType);
identLoc = type;
}
if (hasNoNullabilityAnnotationChildren(annotationHolder)) {
this.log(identLoc.getLineNo(), identLoc.getColumnNo() - 1, "Missing nullability annotation for '" + holderDef.findFirstToken(TokenTypes.IDENT).getText() + "'");
}
}
public static boolean isNullMarkedAnnotation(final DetailAST annotation) {
if (annotation.getChildCount(TokenTypes.IDENT) != 1) {
return false;
}
final String ident = annotation.findFirstToken(TokenTypes.IDENT).getText();
return "NullMarked".equals(ident);
}
public static @Nullable DetailAST getNullMarkedAnnotation(final DetailAST typeDeclaration) {
final DetailAST modifiers = typeDeclaration.findFirstToken(TokenTypes.MODIFIERS);
if (modifiers == null) {
return null;
}
for (final DetailAST annotation : Util.childrenIterator(modifiers, TokenTypes.ANNOTATION)) {
if (isNullMarkedAnnotation(annotation)) {
return annotation;
}
}
return null;
}
@Override
public void visitToken(final DetailAST ast) {
if (Util.isPackageInfoAnnotated(Path.of(this.getFilePath()), NullabilityAnnotationsCheck::isNullMarkedAnnotation)) {
return;
}
for (DetailAST parentDef = Util.getEnclosingTypeDeclaration(ast); parentDef != null; parentDef = Util.getEnclosingTypeDeclaration(parentDef)) {
if (getNullMarkedAnnotation(parentDef) != null) {
return;
}
}
switch (ast.getType()) {
case TokenTypes.METHOD_DEF, TokenTypes.PARAMETER_DEF, TokenTypes.ANNOTATION_FIELD_DEF -> this.visitMethodDefOrParamDef(ast, TokenTypes.MODIFIERS);
case TokenTypes.RECORD_COMPONENT_DEF -> this.visitMethodDefOrParamDef(ast, TokenTypes.ANNOTATIONS);
}
}
}

View File

@@ -0,0 +1,40 @@
package io.papermc.checkstyle.checks;
import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
import io.papermc.checkstyle.Util;
import java.nio.file.Path;
public class RedundantNullabilityCheck extends AbstractCheck {
@Override
public int[] getDefaultTokens() {
return this.getRequiredTokens();
}
@Override
public int[] getAcceptableTokens() {
return this.getRequiredTokens();
}
@Override
public int[] getRequiredTokens() {
return new int[]{
TokenTypes.CLASS_DEF,
TokenTypes.INTERFACE_DEF,
TokenTypes.ANNOTATION_DEF,
TokenTypes.RECORD_DEF,
TokenTypes.ENUM_DEF,
};
}
@Override
public void visitToken(final DetailAST ast) {
final boolean pkgIsNullMarked = Util.isPackageInfoAnnotated(Path.of(this.getFilePath()), NullabilityAnnotationsCheck::isNullMarkedAnnotation);
final DetailAST nullMarkedAnnotation = NullabilityAnnotationsCheck.getNullMarkedAnnotation(ast);
if (pkgIsNullMarked && nullMarkedAnnotation != null) {
this.log(nullMarkedAnnotation.getLineNo(), ast.getColumnNo() - 1, "Redundant NullMarked annotation");
}
}
}

View File

@@ -0,0 +1,8 @@
/**
* Custom checkstyle checks for PaperMC projects.
*/
@NullMarked
@SuppressWarnings("unused")
package io.papermc.checkstyle.checks;
import org.jspecify.annotations.NullMarked;

View File

@@ -0,0 +1,7 @@
/**
* This package contains custom checkstyle rules for PaperMC projects.
*/
@NullMarked
package io.papermc.checkstyle;
import org.jspecify.annotations.NullMarked;

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE checkstyle-packages PUBLIC
"-//Checkstyle//DTD Package Names Configuration 1.0//EN"
"https://checkstyle.org/dtds/packages_1_0.dtd">
<checkstyle-packages>
<package name="io.papermc.checkstyle.checks"/>
</checkstyle-packages>

View File

@@ -0,0 +1,206 @@
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
<module name="SuppressionFilter">
<property name="file" value="${config_loc}/suppressions.xml"/>
<property name="optional" value="false"/>
</module>
<!--Single Suppression Filters-->
<module name="SuppressionSingleFilter">
<!--Suppresses warnings except for common TYPE_USE that should be on same line-->
<property name="checks" value="AnnotationOnSameLine"/>
<property name="message" value="^Annotation '(?!(${type_use_annotations}))"/>
</module>
<!--Javadoc Comments-->
<module name="JavadocPackage"/>
<!--Misc-->
<module name="NewlineAtEndOfFile"/>
<module name="OrderedProperties"/>
<!--Whitespace-->
<module name="FileTabCharacter"/>
<module name="TreeWalker">
<module name="SuppressionXpathFilter">
<property name="file" value="${config_loc}/xpath-suppressions.xml"/>
<property name="optional" value="false"/>
</module>
<!--Annotations-->
<module name="AnnotationOnSameLine">
<!--matches all annotations, but most are suppressed in above-->
<property name="tokens" value="METHOD_DEF"/>
</module>
<module name="AnnotationUseStyle"/>
<module name="MissingDeprecated"/>
<!--Block Checks-->
<module name="AvoidNestedBlocks"/>
<module name="EmptyBlock"/>
<module name="LeftCurly"/>
<module name="RightCurly"/>
<module name="OneTopLevelClass"/>
<module name="SealedShouldHavePermitsList"/>
<!--Class Design-->
<module name="FinalClass"/>
<module name="HideUtilityClassConstructor"/>
<module name="InterfaceIsType"/>
<!--Coding-->
<module name="ArrayTrailingComma"/>
<module name="AvoidDoubleBraceInitialization"/>
<module name="AvoidNoArgumentSuperConstructorCall"/>
<module name="ConstructorsDeclarationGrouping"/>
<module name="CovariantEquals"/>
<module name="DeclarationOrder"/>
<module name="DefaultComesLast"/>
<module name="EmptyStatement"/>
<module name="EqualsAvoidNull"/>
<module name="EqualsHashCode"/>
<module name="FallThrough"/>
<module name="FinalLocalVariable">
<property name="validateEnhancedForLoopVariable" value="true"/>
<property name="validateUnnamedVariables" value="true"/>
<property name="tokens" value="PARAMETER_DEF,VARIABLE_DEF"/>
</module>
<module name="IllegalToken"/> <!--just labels by default-->
<module name="IllegalType"/>
<module name="PatternVariableAssignment"/>
<module name="RequireThis">
<property name="validateOnlyOverlapping" value="false"/>
</module>
<module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/>
<module name="StringLiteralEquality"/>
<module name="UnnecessaryNullCheckWithInstanceOf"/>
<module name="UnnecessarySemicolonAfterOuterTypeDeclaration"/>
<module name="UnnecessarySemicolonAfterTypeMemberDeclaration"/>
<module name="UnnecessarySemicolonInEnumeration"/>
<module name="UnnecessarySemicolonInTryWithResources"/>
<module name="UnusedCatchParameterShouldBeUnnamed"/>
<module name="UnusedLambdaParameterShouldBeUnnamed"/>
<module name="UnusedLocalVariable"/>
<module name="WhenShouldBeUsed"/>
<!--Headers--> <!--N/A-->
<!--Imports-->
<module name="AvoidStarImport"/>
<module name="CustomImportOrder">
<property name="customImportOrderRules" value="THIRD_PARTY_PACKAGE,STATIC"/>
<property name="standardPackageRegExp" value="^$"/>
<property name="sortImportsInGroupAlphabetically" value="true"/>
</module>
<module name="IllegalImport">
<property name="regexp" value="true"/>
<!--checker-qual nullability-->
<property name="illegalClasses" value="org\.checkerframework\.checker\.nullness\.qual\.(Nullable|NonNull|DefaultQualifier)"/>
<!--jetbrains nullability-->
<property name="illegalClasses" value="org\.jetbrains\.annotations\.(NotNull|Nullable|NotNullByDefault)"/>
<!--javax nullability-->
</module>
<module name="IllegalImport">
<property name="regexp" value="true"/>
<!--attempts to guard against nested imports (by looking for capital letters in imports)-->
<property name="illegalClasses" value="^[^\.A-Z]+(\.[^\.A-Z]+)+?(\.[A-Z][^\.]*)(\.[A-Z][^\.]*)+$"/>
<message key="import.illegal" value="Illegal nested import - {0}"/>
</module>
<module name="RedundantImport"/>
<module name="UnusedImports"/>
<!--Javadoc Comments-->
<module name="AtclauseOrder">
<property name="tagOrder" value="@param, @return, @throws, @see, @deprecated, @hidden"/>
</module>
<module name="InvalidJavadocPosition"/>
<module name="JavadocBlockTagLocation"/>
<module name="JavadocContentLocation"/>
<module name="JavadocLeadingAsteriskAlign"/>
<module name="JavadocMethod">
<!--checks all, but doesn't require. If we have a doc, it should be valid-->
<property name="validateThrows" value="true"/>
</module>
<module name="JavadocMissingLeadingAsterisk"/>
<module name="JavadocMissingWhitespaceAfterAsterisk"/>
<module name="JavadocStyle"/> <!--checks all, but doesn't require. If we have a doc, it should be valid-->
<module name="JavadocTagContinuationIndentation"/>
<module name="JavadocType"/> <!--checks all, but doesn't require. If we have a doc, it should be valid-->
<module name="NonEmptyAtclauseDescription"/>
<module name="RequireEmptyLineBeforeBlockTagGroup"/>
<!--Metrics--> <!--N/A-->
<!--Miscellaneous-->
<module name="ArrayTypeStyle"/>
<module name="AvoidEscapedUnicodeCharacters"/>
<module name="CommentsIndentation"/>
<module name="FinalParameters">
<!-- TODO pattern variable assignment isn't checked yet: PATTERN_VARIABLE_DEF-->
<!-- https://github.com/checkstyle/checkstyle/issues/17366 -->
<property name="tokens" value="METHOD_DEF,CTOR_DEF,LITERAL_CATCH,FOR_EACH_CLAUSE"/>
</module>
<module name="NoCodeInFile"/>
<module name="OuterTypeFilename"/>
<module name="UpperEll"/>
<!--Modifiers-->
<module name="ModifierOrder"/>
<module name="RedundantModifier"/>
<!--Naming Conventions-->
<module name="AbbreviationAsWordInName">
<property name="allowedAbbreviations" value="JSON,UUID"/>
<property name="ignoreFinal" value="false"/>
</module>
<module name="ClassTypeParameterName"/>
<module name="ConstantName"/>
<module name="IllegalIdentifierName"/>
<module name="InterfaceTypeParameterName"/>
<module name="LambdaParameterName"/>
<module name="LocalFinalVariableName"/>
<module name="LocalVariableName"/>
<module name="MemberName"/>
<module name="MethodName"/>
<module name="MethodTypeParameterName"/>
<module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
</module>
<module name="ParameterName"/>
<module name="PatternVariableName"/>
<module name="RecordComponentName"/>
<module name="RecordTypeParameterName"/>
<module name="StaticVariableName"/>
<module name="TypeName"/>
<!--Regexp--> <!--N/A-->
<!--Size Violations--> <!--N/A-->
<!--Whitespace-->
<module name="EmptyForInitializerPad"/>
<module name="EmptyForIteratorPad"/>
<module name="EmptyLineSeparator">
<property name="allowNoEmptyLineBetweenFields" value="true"/>
<property name="tokens" value="IMPORT,STATIC_IMPORT,CLASS_DEF,INTERFACE_DEF,ENUM_DEF,STATIC_INIT,INSTANCE_INIT,METHOD_DEF,CTOR_DEF,VARIABLE_DEF,RECORD_DEF,COMPACT_CTOR_DEF"/>
</module>
<module name="GenericWhitespace"/>
<module name="MethodParamPad"/>
<module name="NoLineWrap"/> <!--just imports and packages-->
<module name="NoWhitespaceAfter"/>
<module name="NoWhitespaceBefore"/>
<module name="NoWhitespaceBeforeCaseDefaultColon"/>
<module name="ParenPad"/>
<module name="SingleSpaceSeparator"/>
<module name="TypecastParenPad"/>
<module name="WhitespaceAfter"/>
<module name="WhitespaceAround"/>
<!--Custom-->
<module name="JavadocAlignParameterDescription"/>
<module name="NullabilityAnnotations"/>
<module name="RedundantNullability"/>
</module>
</module>

View File

@@ -1,5 +1,6 @@
pluginManagement { pluginManagement {
repositories { repositories {
mavenLocal()
gradlePluginPortal() gradlePluginPortal()
maven("https://repo.papermc.io/repository/maven-public/") maven("https://repo.papermc.io/repository/maven-public/")
} }
@@ -11,17 +12,17 @@ plugins {
if (!file(".git").exists()) { if (!file(".git").exists()) {
val errorText = """ val errorText = """
=====================[ ERROR ]===================== =====================[ ERROR ]=====================
The Paper project directory is not a properly cloned Git repository. The Paper project directory is not a properly cloned Git repository.
In order to build Paper from source you must clone In order to build Paper from source you must clone
the Paper repository using Git, not download a code the Paper repository using Git, not download a code
zip from GitHub. zip from GitHub.
Built Paper jars are available for download at Built Paper jars are available for download at
https://papermc.io/downloads/paper https://papermc.io/downloads/paper
See https://github.com/PaperMC/Paper/blob/main/CONTRIBUTING.md See https://github.com/PaperMC/Paper/blob/main/CONTRIBUTING.md
for further information on building and modifying Paper. for further information on building and modifying Paper.
=================================================== ===================================================
@@ -36,6 +37,8 @@ for (name in listOf("paper-api", "paper-server")) {
file(name).mkdirs() file(name).mkdirs()
} }
include("paper-checkstyle")
optionalInclude("test-plugin") optionalInclude("test-plugin")
optionalInclude("paper-generator") optionalInclude("paper-generator")