diff --git a/README.textile b/README.textile index 0d816d5208..6efab66bd8 100644 --- a/README.textile +++ b/README.textile @@ -27,3 +27,5 @@ h3. Contributors Hidoyatov Victor, Troshin Sergey, Svinukhov Vladimir, "Ilia Dubinin":https://github.com/sabaka, Dmitry Gridyushko, "Vadym Chekrii":https://github.com/vchekrii, "Vadim Panasiuk":https://github.com/VadimPanasiuk, "Aleksey Grigirov":https://github.com/KTannenberg, Alexander Berezovsky, "Sergey Burtsev":https://github.com/burtsevsergey, "Baratali Izmailov":https://github.com/baratali, "Max Vetrenko":https://github.com/maxvetrenko, "Pavel Baranchikov":https://github.com/pbaranchikov , "Ashutosh Agarwal":https://github.com/Radsaggi, "Alexey Nesterenko":https://github.com/alexkravin. , ...... for whole list please look at "contributors list":https://github.com/sevntu-checkstyle/sevntu.checkstyle/network/members . + +The "Jsr305AnnotationsCheck" is based on the "JSR305CheckstylePlugin":https://github.com/bjrke/JSR305CheckstylePlugin by "Jan Burkhardt":https://github.com/bjrke with contributions from Mattias Nissler, Thorsten Ehlers, Fabian Loewner and Ole Langbehn. \ No newline at end of file diff --git a/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/annotation/checkstyle-metadata.xml b/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/annotation/checkstyle-metadata.xml index c2f55ecdac..dcada39336 100755 --- a/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/annotation/checkstyle-metadata.xml +++ b/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/annotation/checkstyle-metadata.xml @@ -1,7 +1,7 @@ +"https://checkstyle.org/eclipse-cs/dtds/checkstyle-metadata_1_1.dtd"> diff --git a/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/coding/checkstyle-metadata.properties b/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/coding/checkstyle-metadata.properties index e7efd317dd..b7859c2c4a 100755 --- a/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/coding/checkstyle-metadata.properties +++ b/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/coding/checkstyle-metadata.properties @@ -188,3 +188,10 @@ MoveVariableInsideIfCheck.desc = Checks if a variable is only used inside if sta RequireFailForTryCatchInJunitCheck.name = Require Fail For Try/Catch in JUnit Check RequireFailForTryCatchInJunitCheck.desc = Checks if a try/catch block has a junit fail assertion inside the try for a junit method. + +Jsr305AnnotationsCheck.name=Jsr305AnnotationsCheck +Jsr305AnnotationsCheck.desc=Checks method parameters and return values for the presence of @Nonnull, @Nullable, or @CheckForNull annotations. +Jsr305AnnotationsCheck.packages=Sets the parent package for all classes that will be checked. +Jsr305AnnotationsCheck.excludePackages=Packages excluded from checking. This can be useful if under the parent package set with "packages" there are subpackages which should not be checked. +Jsr305AnnotationsCheck.allowOverridingReturnValue=Annotating return values "@CheckForNull" in overridden methods is flagged as a violation. When setting this property to true, this will be ignored (useful for upgrading). +Jsr305AnnotationsCheck.allowOverridingParameter=Annotating parameters "@Nonnull" in overridden methods is flagged as a violation. When setting this property to true, this will be ignored (useful for upgrading). diff --git a/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/coding/checkstyle-metadata.xml b/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/coding/checkstyle-metadata.xml index 3392c3bec1..fcba5c0679 100644 --- a/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/coding/checkstyle-metadata.xml +++ b/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/coding/checkstyle-metadata.xml @@ -1,7 +1,7 @@ +"https://checkstyle.org/eclipse-cs/dtds/checkstyle-metadata_1_1.dtd"> @@ -556,5 +556,48 @@ + + + %Jsr305AnnotationsCheck.desc + + %Jsr305AnnotationsCheck.packages + + + %Jsr305AnnotationsCheck.excludePackages + + + %Jsr305AnnotationsCheck.allowOverridingReturnValue + + + %Jsr305AnnotationsCheck.allowOverridingParameter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/design/checkstyle-metadata.xml b/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/design/checkstyle-metadata.xml index b55cc10551..fed1a16517 100644 --- a/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/design/checkstyle-metadata.xml +++ b/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/design/checkstyle-metadata.xml @@ -1,7 +1,7 @@ +"https://checkstyle.org/eclipse-cs/dtds/checkstyle-metadata_1_1.dtd"> diff --git a/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/naming/checkstyle-metadata.xml b/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/naming/checkstyle-metadata.xml index d96cd7fce5..cc36cae9ca 100644 --- a/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/naming/checkstyle-metadata.xml +++ b/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/naming/checkstyle-metadata.xml @@ -1,7 +1,7 @@ +"https://checkstyle.org/eclipse-cs/dtds/checkstyle-metadata_1_1.dtd"> diff --git a/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/sizes/checkstyle-metadata.xml b/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/sizes/checkstyle-metadata.xml index d76ad4d19c..cdf360e456 100755 --- a/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/sizes/checkstyle-metadata.xml +++ b/eclipsecs-sevntu-plugin/src/com/github/sevntu/checkstyle/checks/sizes/checkstyle-metadata.xml @@ -1,7 +1,7 @@ +"https://checkstyle.org/eclipse-cs/dtds/checkstyle-metadata_1_1.dtd"> diff --git a/sevntu-checks/pom.xml b/sevntu-checks/pom.xml index 51520c4a20..a40e2ffc47 100644 --- a/sevntu-checks/pom.xml +++ b/sevntu-checks/pom.xml @@ -45,6 +45,18 @@ test ${checkstyle.eclipse-cs.version} + + + com.google.code.findbugs + jsr305 + 3.0.2 + + + + com.google.code.findbugs + annotations + 3.0.1 + junit junit @@ -283,7 +295,7 @@ .*.checks.coding.MapIterationInForEachLoopCheck9098 .*.checks.coding.NoNullForCollectionReturnCheck8596 .*.checks.coding.OverridableMethodInConstructorCheck9499 - .*.checks.design.HideUtilityClassConstructorCheck94100 + .*.checks.design.HideUtilityClassConstructorCheck96100 diff --git a/sevntu-checks/sevntu-checks.xml b/sevntu-checks/sevntu-checks.xml index d4c7612e18..bc40e129f3 100644 --- a/sevntu-checks/sevntu-checks.xml +++ b/sevntu-checks/sevntu-checks.xml @@ -1,5 +1,5 @@  - + @@ -159,6 +159,15 @@ + + + + + + + + + diff --git a/sevntu-checks/src/main/java/com/github/sevntu/checkstyle/checks/coding/Jsr305AnnotationsCheck.java b/sevntu-checks/src/main/java/com/github/sevntu/checkstyle/checks/coding/Jsr305AnnotationsCheck.java new file mode 100644 index 0000000000..30149e9d63 --- /dev/null +++ b/sevntu-checks/src/main/java/com/github/sevntu/checkstyle/checks/coding/Jsr305AnnotationsCheck.java @@ -0,0 +1,1075 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2019 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.sevntu.checkstyle.checks.coding; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import antlr.collections.AST; +import com.github.sevntu.checkstyle.SevntuUtil; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.FullIdent; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; + +/** + *

+ * The Jsr305 annotations (annotations for + * software defect detection) contain a subset of "nullness" annotations that can be used to mark + * parameters as possibly null ({@code @Nullable}) or always non-null ({@code @Nonnull}), function + * return values as to be checked for null ({@code @CheckForNull}) or always non-null + * ({@code @Nonnull}) including defaults on class level ({@code @ParametersAreNonnullByDefault}, + * {@code @ParametersAreNullableByDefault}, {@code @ReturnValuesAreNonnullByDefault}). + *

+ *

+ * Using these annotations a programmer can declare how the code is meant to behave, and static code + * analysis (like e.g. FindBugs) can be used to verify that this is actually true. Also these + * annotations help others understanding code more easily, e.g. if confrontend with an annotated + * interface the necessity for null checks can easily be deducted from the annotations. + *

+ *

+ * The Jsr305AnnotationsCheck supports enforcing the following code style: + *

+ *
    + *
  • Every method declaration, implementation or lambda requires nullness annotations for all + * parameters and return values except for primitive types (because a void or an int can never be + * null anyway).
  • + *
  • The annotation can be made directly or applied through either inheritance from an already + * annotated class or a annotation for class-wide defaults.
  • + *
  • Annotations need to make sense. For instance, a class-scope annotation cannot be used for a + * method, and a method annotation cannot be used for a class.
  • + *
  • In overridden methods, the following rule applies (regardless of what was annotated in the + * parent method): For parameter definitions {@code @Nonnull} annotation is always illegal because + * being less "nullable" cannot be assumed for a parameter in an inherited method. Conversely + * {@code @Nullable} is always allowed. For return values it is the other way round: + * {@code @CheckForNull} is always illegal while {@code @Nonnull} is always legal.
  • + *
+ *

+ * The following configuration properties are supported: + *

+ *
+ *
{@code packages = com.github.sevntu.pkg1,com.github.sevntu.pkg2}
+ *
Activate this check for a list of parent packages and their children.
+ *
{@code excludePackages = com.github.sevntu.pkg1.sub1,com.github.sevntu.pkg1.sub2}
+ *
Set packages excluded from checking. This setting can be useful if under the parent package + * set with "packages" there are subpackages which should not be checked.
+ *
{@code allowOverridingReturnValue = true}
+ *
Annotating return values "@CheckForNull" in overridden methods is flagged as a violation. + * When setting the this property to true, this will be ignored (useful for upgrading).
+ *
{@code allowOverridingParameters = true}
+ *
Annotating parameters "@Nonnull" in overridden methods is flagged as a violation. When + * setting this property to true, this will be ignored (useful for upgrading).
+ *
+ *

+ * Note that by default no files will be checked. To enable this check, you need to set the + * {@code packages} property to one or more parent packages. + *

+ *

+ * Example code: + *

+ *

+ * Configure the check so that it scans the packages of the classes we want to run this on: + *

+ * + *
+ * <module name="Jsr305Annotations">
+ *   <property name="packages" value="org,com"/>
+ *   </module>
+ * 
+ * + * + *
+ * // Example 1: a class without any class-level annotations
+ * class Class1 {
+ *     @CheckForNull // Violation: obj2 not annotated!
+ *     String method1(@Nullable Object obj1, Object obj2) {
+ *         return "";
+ *     }
+ *
+ *     // Violation: return value not annotated
+ *     String method2() {
+ *         return "";
+ *     }
+ * }
+ *
+ * // Example 2: a class with class-level annotations for parameters
+ * @ParametersAreNonnullByDefault
+ * class Class2 {
+ *     @CheckForNull // Legal
+ *     String method1(Object obj1, Object obj2) {
+ *         return "";
+ *     }
+ *
+ *     @Nonnull // Legal
+ *     String method2(Object obj1, @Nullable Object obj2) {
+ *         return "";
+ *     }
+ *
+ *     @Nonnull // Violation, redefinition of obj2's nullness
+ *     String method3(Object obj1, @Nonnull Object obj2) {
+ *         return "";
+ *     }
+ *
+ *     // Violation: return value not annotated
+ *     String method4() {
+ *         return "";
+ *     }
+ * }
+ *
+ * // Example 3: a class overriding some methods
+ * class Class3 implements Interface1 {
+ *     @Override // Legal
+ *     public Object method1(Object obj1, Object obj2) {
+ *         return "";
+ *     }
+ *
+ *     @Override
+ *     @Nonnull // Legal, return value becomes less "nullable"
+ *     public Object method2(Object obj1, Object obj2) {
+ *         return "";
+ *     }
+ *
+ *     @Override // Violation: Setting a parameter to non-null in an overridden method
+ *     public Object method3(@Nonnull Object obj1, Object obj2) {
+ *         return "";
+ *     }
+ *
+ *     @Override // Legal: parameter obj2 becomes more "nullable"
+ *     public Object method4(Object obj1, @Nullable Object obj2) {
+ *         return "";
+ *     }
+ *
+ *     @Override
+ *     @CheckForNull // Violation: return value becomes more "nullable"
+ *     public Object method5() {
+ *         return "";
+ *     }
+ * }
+ * 
+ */ +public class Jsr305AnnotationsCheck extends AbstractCheck { + + /** Key for violation message. */ + public static final String MSG_ILLEGAL_CLASS_LEVEL_ANNOTATION = + "jsr305.illegal.class.level.annotation"; + + /** Key for violation message. */ + public static final String MSG_CONTRADICTING_CLASS_LEVEL_ANNOTATIONS = + "jsr305.contradicting.class.level.annotations"; + + /** Key for violation message. */ + public static final String MSG_PARAM_DEFINITIONS_WITH_CHECK = + "jsr305.param.definitions.with.check.annotation"; + + /** Key for violation message. */ + public static final String MSG_PARAM_DEFINITION_WITH_OVERRIDE = + "jsr305.param.definition.with.override.annotation"; + + /** Key for violation message. */ + public static final String MSG_PARAM_DEFINITION_WITH_NONNULL_BY_DEFAULT = + "jsr305.param.definition.with.nonnull.by.default.annotation"; + + /** Key for violation message. */ + public static final String MSG_PARAM_DEFINITION_WITH_NULLABLE_BY_DEFAULT = + "jsr305.param.definition.with.nullable.by.default.annotation"; + + /** Key for violation message. */ + public static final String MSG_PARAM_DEFINITION_WITH_RETURN_DEFAULT = + "jsr305.param.definition.with.return.values.default.annotation"; + + /** Key for violation message. */ + public static final String MSG_PARAM_NONNULL_AND_NULLABLE = + "jsr305.param.nonnull.and.nullable.annotation"; + + /** Key for violation message. */ + public static final String MSG_PRIMITIVES_WITH_NULLNESS_ANNOTATION = + "jsr305.primitives.with.nullness.annotation"; + + /** Key for violation message. */ + public static final String MSG_OVERRIDDEN_WITH_INCREASED_CONSTRAINT = + "jsr305.overridden.definitions.with.increased.param.constraint"; + + /** Key for violation message. */ + public static final String MSG_REDUNDANT_NONNULL_PARAM_ANNOTATION = + "jsr305.redundant.nonnull.param.annotation"; + + /** Key for violation message. */ + public static final String MSG_REDUNDANT_NULLABLE_PARAM_ANNOTATION = + "jsr305.redundant.nullable.param.annotation"; + + /** Key for violation message. */ + public static final String MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION = + "jsr305.parameter.without.nullness.annotation"; + + /** Key for violation message. */ + public static final String MSG_RETURN_VALUE_WITH_NONNULL_BY_DEFAULT = + "jsr305.return.value.with.nonnull.by.default.annotation"; + + /** Key for violation message. */ + public static final String MSG_RETURN_VALUE_WITH_NULLABLE = + "jsr305.return.value.with.nullable.annotation"; + + /** Key for violation message. */ + public static final String MSG_CONTRADICTING_RETURN_VALUE_ANNOTATIONS = + "jsr305.contradicting.return.value.annotations"; + + /** Key for violation message. */ + public static final String MSG_OVERRIDDEN_METHOD_WITH_CHECK_RETURN_VALUE = + "jsr305.overridden.method.with.check.return.value.annotation"; + + /** Key for violation message. */ + public static final String MSG_REDUNDANT_NONNULL_BY_DEFAULT_ANNOTATION = + "jsr305.redundant.nonnull.by.default.annotation"; + + /** Key for violation message. */ + public static final String MSG_REDUNDANT_NULLABLE_BY_DEFAULT_ANNOTATION = + "jsr305.redundant.nullable.by.default.annotation"; + + /** Key for violation message. */ + public static final String MSG_VOID_WITH_CHECK_RETURN_VALUE_ANNOTATION = + "jsr305.void.with.check.return.value.annotation"; + + /** Key for violation message. */ + public static final String MSG_REDUNDANT_NONNULL_RETURN_ANNOTATION = + "jsr305.redundant.nonnull.return.annotation"; + + /** Key for violation message. */ + public static final String MSG_RETURN_WITHOUT_NULLNESS_ANNOTATION = + "jsr305.return.without.nullness.annotation"; + + /** Key for violation message. */ + public static final String MSG_OVERRIDDEN_METHODS_ALLOW_ONLY_NONNULL = + "jsr305.overridden.methods.allow.only.nonnull"; + + /** Key for violation message. */ + public static final String MSG_NEED_TO_INHERIT_PARAM_ANNOTATIONS = + "jsr305.need.to.inherit.param.annotations"; + + /** Key for violation message. */ + public static final String MSG_CONSTRUCTOR_WITH_RETURN_ANNOTATION = + "jsr305.constructor.with.return.annotation"; + + /** Package name. */ + private static final String PKG_JAVAX_ANNOTATION = "javax.annotation"; + + /** + * Class NullnessAnnotation. The annotations we consider as "nullness-relevant". + */ + private enum NullnessAnnotation { + + /** Override. */ + OVERRIDE("Override", "java.lang"), + /** CheckForNull. */ + CHECK_FOR_NULL("CheckForNull", PKG_JAVAX_ANNOTATION), + /** Nullable. */ + NULLABLE("Nullable", PKG_JAVAX_ANNOTATION), + /** Nonnull. */ + NONNULL("Nonnull", PKG_JAVAX_ANNOTATION), + /** CheckReturnValue. */ + CHECK_RETURN_VALUE("CheckReturnValue", PKG_JAVAX_ANNOTATION), + /** ParametersAreNonnullByDefault. */ + PARAMETERS_ARE_NONNULL_BY_DEFAULT("ParametersAreNonnullByDefault", PKG_JAVAX_ANNOTATION), + /** ParametersAreNullableByDefault. */ + PARAMETERS_ARE_NULLABLE_BY_DEFAULT("ParametersAreNullableByDefault", PKG_JAVAX_ANNOTATION), + /** ReturnValuesAreNonnullByDefault. */ + RETURN_VALUES_ARE_NONNULL_BY_DEFAULT("ReturnValuesAreNonnullByDefault", + "edu.umd.cs.findbugs.annotations"); + + /** The annotation's name. */ + private final String annotationName; + + /** The annotation's fully qualified class name. */ + private final String fullyQualifiedClassName; + + /** + * Constructor. + * @param annotationName + * the annotation's name + * @param packageName + * the package name + */ + NullnessAnnotation(final String annotationName, final String packageName) { + this.annotationName = annotationName; + this.fullyQualifiedClassName = packageName + "." + annotationName; + } + + } + + /** The map of annotations against their respective names. */ + private static final Map STRING2ANNOTATION = + createString2AnnotationMap(); + + /** Parameter: packages to check. */ + private String[] packages = new String[0]; + /** Parameter: packages to exclude from checking. */ + private String[] excludePackages = new String[0]; + /** Parameter: overriding return value annotations allowed. */ + private boolean allowOverridingReturnValue; + /** Parameter: overriding parameter annotations allowed. */ + private boolean allowOverridingParameter; + + /** State, is a package excluded. */ + private boolean packageExcluded; + + @Override + public final int[] getDefaultTokens() { + return getAcceptableTokens(); + } + + @Override + public final int[] getRequiredTokens() { + return new int[0]; + } + + @Override + public final int[] getAcceptableTokens() { + return new int[] { + TokenTypes.PARAMETER_DEF, + TokenTypes.METHOD_DEF, + TokenTypes.PACKAGE_DEF, + TokenTypes.CTOR_DEF, + TokenTypes.CLASS_DEF, + TokenTypes.INTERFACE_DEF, + TokenTypes.ENUM_DEF, + }; + } + + @Override + public void beginTree(DetailAST rootAST) { + packageExcluded = false; + } + + @Override + public final void visitToken(final DetailAST ast) { + if (ast.getType() == TokenTypes.PACKAGE_DEF) { + final DetailAST nameAST = ast.getLastChild().getPreviousSibling(); + packageExcluded = isPackageExcluded(FullIdent.createFullIdent(nameAST)); + } + else if (!packageExcluded) { + final AbstractJsr305Handler handler = handleDefinition(ast); + if (handler != null) { + handler.check(); + } + } + } + + /** + * Sets the included packages property. + * @param packageNames + * the package names, comma separated + */ + public void setPackages(final String... packageNames) { + packages = transformToUnique(packageNames); + } + + /** + * Sets the excluded packages property. + * @param packageNames + * the package names, comma separated + */ + public void setExcludePackages(final String... packageNames) { + excludePackages = transformToUnique(packageNames); + } + + /** + * Sets the property for allowing overriding return values. + * @param newAllowOverridingReturnValue + * true if yes + */ + public void setAllowOverridingReturnValue(final boolean newAllowOverridingReturnValue) { + this.allowOverridingReturnValue = newAllowOverridingReturnValue; + } + + /** + * Sets the property for allowing overriding parameters. + * @param newAllowOverridingParameter + * true if yes + */ + public void setAllowOverridingParameter(final boolean newAllowOverridingParameter) { + this.allowOverridingParameter = newAllowOverridingParameter; + } + + /** + * Maps annotations to their respective names. + * @return the map + */ + private static Map createString2AnnotationMap() { + final Map result = new HashMap<>(); + + for (final NullnessAnnotation annotation : NullnessAnnotation.values()) { + result.put(annotation.annotationName, annotation); + result.put(annotation.fullyQualifiedClassName, annotation); + } + + return Collections.unmodifiableMap(result); + } + + /** + * Removes duplicates from an array of strings. + * @param input + * the array + * @return a new, duplicate-free array + */ + private static String[] transformToUnique(final String... input) { + final Set inputSet = new HashSet<>(Arrays.asList(input)); + return inputSet.toArray(new String[0]); + } + + /** + * Checks whether a package is excluded. + * @param fullIdent + * the identifier + * @return true if yes + */ + private boolean isPackageExcluded(final FullIdent fullIdent) { + Boolean result = null; + final String packageName = fullIdent.getText(); + for (final String excludesPackageName : excludePackages) { + if (packageName.startsWith(excludesPackageName)) { + result = true; + break; + } + } + if (result == null) { + for (final String includePackageName : packages) { + if (packageName.startsWith(includePackageName)) { + result = false; + break; + } + } + } + if (result == null) { + result = true; + } + return result; + } + + /** + * Returns the check to use for a given definition. + * @param ast + * the ast + * @return the check. + */ + private AbstractJsr305Handler handleDefinition(final DetailAST ast) { + + // no definition in catch clause + final DetailAST parent = ast.getParent(); + AbstractJsr305Handler result = null; + if (parent == null || parent.getType() != TokenTypes.LITERAL_CATCH) { + // search modifiers + final int type = ast.getType(); + switch (type) { + case TokenTypes.METHOD_DEF: + result = new MethodJsr305Handler(ast); + break; + case TokenTypes.CTOR_DEF: + result = new ConstructorJsr305Handler(ast); + break; + case TokenTypes.PARAMETER_DEF: + result = new ParameterJsr305Handler(ast); + break; + case TokenTypes.CLASS_DEF: + case TokenTypes.INTERFACE_DEF: + case TokenTypes.ENUM_DEF: + result = new ClassJsr305Handler(ast); + break; + default: + SevntuUtil.reportInvalidToken(ast.getType()); + break; + } + } + return result; + } + + /** + * Find the nullness annotations. + * @param ast + * the ast + * @return the annotations. + */ + private static Set findAnnotations(final DetailAST ast) { + final Set result = new HashSet<>(); + + final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); + for (AST child = modifiers.getFirstChild(); child != null; child = child.getNextSibling()) { + if (child.getType() == TokenTypes.ANNOTATION) { + addNextNullnessAnnotation(result, (DetailAST) child); + } + } + + return result; + } + + /** + * Adds the nullness annotation from the argument's first token if any. + * @param result + * the result + * @param ast + * the ast + */ + private static void addNextNullnessAnnotation(final Set result, + DetailAST ast) { + final DetailAST identifier = ast.findFirstToken(TokenTypes.IDENT); + final String annotationName = identifier.getText(); + final NullnessAnnotation annotation = STRING2ANNOTATION.get(annotationName); + if (annotation != null) { + result.add(annotation); + } + } + + /** + * Class ClassJsr305Handler. Checks a class. + */ + private final class ClassJsr305Handler extends AbstractJsr305Handler { + + /** + * Constructor. + * @param ast + * the ast + */ + protected ClassJsr305Handler(final DetailAST ast) { + super(ast); + } + + /** + * Run the actual check. + */ + @Override + protected void runcheck() { + checkContainsAny(MSG_ILLEGAL_CLASS_LEVEL_ANNOTATION, + NullnessAnnotation.CHECK_FOR_NULL, NullnessAnnotation.CHECK_RETURN_VALUE, + NullnessAnnotation.NONNULL, NullnessAnnotation.NULLABLE); + checkContainsAll(MSG_CONTRADICTING_CLASS_LEVEL_ANNOTATIONS, + NullnessAnnotation.PARAMETERS_ARE_NONNULL_BY_DEFAULT, + NullnessAnnotation.PARAMETERS_ARE_NULLABLE_BY_DEFAULT); + } + + } + + /** + * Class ParameterJsr305Handler. Checks a parameter. + */ + private final class ParameterJsr305Handler extends AbstractJsr305Handler { + + /** + * Constructor. + * @param ast + * the ast + */ + protected ParameterJsr305Handler(final DetailAST ast) { + super(ast); + } + + /** + * Run the actual check. + */ + @Override + protected void runcheck() { + checkContainsAny(MSG_PARAM_DEFINITIONS_WITH_CHECK, + NullnessAnnotation.CHECK_FOR_NULL, NullnessAnnotation.CHECK_RETURN_VALUE); + checkContainsAny(MSG_PARAM_DEFINITION_WITH_OVERRIDE, + NullnessAnnotation.OVERRIDE); + checkContainsAny(MSG_PARAM_DEFINITION_WITH_NONNULL_BY_DEFAULT, + NullnessAnnotation.PARAMETERS_ARE_NONNULL_BY_DEFAULT); + checkContainsAny(MSG_PARAM_DEFINITION_WITH_NULLABLE_BY_DEFAULT, + NullnessAnnotation.PARAMETERS_ARE_NULLABLE_BY_DEFAULT); + checkContainsAny(MSG_PARAM_DEFINITION_WITH_RETURN_DEFAULT, + NullnessAnnotation.RETURN_VALUES_ARE_NONNULL_BY_DEFAULT); + checkContainsAll(MSG_PARAM_NONNULL_AND_NULLABLE, + NullnessAnnotation.NONNULL, NullnessAnnotation.NULLABLE); + + if (isPrimitiveType()) { + checkContainsAny(MSG_PRIMITIVES_WITH_NULLNESS_ANNOTATION, + NullnessAnnotation.CHECK_FOR_NULL, NullnessAnnotation.NONNULL, + NullnessAnnotation.NULLABLE); + } + else { + final NullnessAnnotation firstAncestorAnnotation = + getParentMethodOrClassAnnotation( + NullnessAnnotation.PARAMETERS_ARE_NONNULL_BY_DEFAULT, + NullnessAnnotation.PARAMETERS_ARE_NULLABLE_BY_DEFAULT); + final boolean isMethodOverridden = isMethodOverridden(); + final boolean parametersAreNonnullByDefault = firstAncestorAnnotation + == NullnessAnnotation.PARAMETERS_ARE_NONNULL_BY_DEFAULT; + final boolean parametersAreNullableByDefault = firstAncestorAnnotation + == NullnessAnnotation.PARAMETERS_ARE_NULLABLE_BY_DEFAULT; + + if (isMethodOverridden && !allowOverridingParameter) { + checkContainsAny(MSG_OVERRIDDEN_WITH_INCREASED_CONSTRAINT, + NullnessAnnotation.NONNULL); + } + if (parametersAreNonnullByDefault) { + checkContainsAny(MSG_REDUNDANT_NONNULL_PARAM_ANNOTATION, + NullnessAnnotation.NONNULL); + } + if (parametersAreNullableByDefault) { + checkContainsAny(MSG_REDUNDANT_NULLABLE_PARAM_ANNOTATION, + NullnessAnnotation.NULLABLE); + } + + if (!isMethodOverridden && !parametersAreNonnullByDefault + && !parametersAreNullableByDefault) { + checkContainsNone(MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, + NullnessAnnotation.NONNULL, NullnessAnnotation.NULLABLE); + } + } + } + } + + /** + * Class AbstractMethodJsr305Handler. A check on a method or constructor (special case). + */ + private abstract class AbstractMethodJsr305Handler extends AbstractJsr305Handler { + + /** + * Constructor. + * @param ast + * the ast + */ + private AbstractMethodJsr305Handler(final DetailAST ast) { + super(ast); + } + + /** + * Run the actual check. + */ + @Override + protected void runcheck() { + checkContainsAll(MSG_CONTRADICTING_CLASS_LEVEL_ANNOTATIONS, + NullnessAnnotation.PARAMETERS_ARE_NONNULL_BY_DEFAULT, + NullnessAnnotation.PARAMETERS_ARE_NULLABLE_BY_DEFAULT); + runReturnAnnotationCheck(); + } + + /** + * Run annotation check for return. + */ + protected abstract void runReturnAnnotationCheck(); + + } + + /** + * Class MethodJsr305Handler. A check for a method. + */ + private final class MethodJsr305Handler extends AbstractMethodJsr305Handler { + + /** + * Constructor. + * @param ast + * the ast + */ + protected MethodJsr305Handler(final DetailAST ast) { + super(ast); + } + + /** + * Run annotation check for return. + */ + @Override + protected void runReturnAnnotationCheck() { + checkContainsAny(MSG_RETURN_VALUE_WITH_NONNULL_BY_DEFAULT, + NullnessAnnotation.RETURN_VALUES_ARE_NONNULL_BY_DEFAULT); + checkContainsAny(MSG_RETURN_VALUE_WITH_NULLABLE, + NullnessAnnotation.NULLABLE); + checkContainsAll(MSG_CONTRADICTING_RETURN_VALUE_ANNOTATIONS, NullnessAnnotation.NONNULL, + NullnessAnnotation.CHECK_FOR_NULL); + checkContainsAll(MSG_OVERRIDDEN_METHOD_WITH_CHECK_RETURN_VALUE, + NullnessAnnotation.CHECK_RETURN_VALUE, NullnessAnnotation.OVERRIDE); + checkRedundancyDueToClassLevelAnnotation(MSG_REDUNDANT_NONNULL_BY_DEFAULT_ANNOTATION, + NullnessAnnotation.PARAMETERS_ARE_NONNULL_BY_DEFAULT); + checkRedundancyDueToClassLevelAnnotation(MSG_REDUNDANT_NULLABLE_BY_DEFAULT_ANNOTATION, + NullnessAnnotation.PARAMETERS_ARE_NULLABLE_BY_DEFAULT); + + if (isVoid()) { + checkContainsAny(MSG_VOID_WITH_CHECK_RETURN_VALUE_ANNOTATION, + NullnessAnnotation.CHECK_RETURN_VALUE); + } + if (isPrimitiveType()) { + checkContainsAny(MSG_PRIMITIVES_WITH_NULLNESS_ANNOTATION, + NullnessAnnotation.CHECK_FOR_NULL, NullnessAnnotation.NONNULL, + NullnessAnnotation.NULLABLE); + } + else { + final NullnessAnnotation annotation = getParentMethodOrClassAnnotation( + NullnessAnnotation.RETURN_VALUES_ARE_NONNULL_BY_DEFAULT); + final boolean returnValuesAreNonnullByDefault = annotation + == NullnessAnnotation.RETURN_VALUES_ARE_NONNULL_BY_DEFAULT; + final boolean isMethodOverridden = isMethodOverridden(); + + if (returnValuesAreNonnullByDefault) { + if (!isMethodOverridden) { + checkContainsAny(MSG_REDUNDANT_NONNULL_RETURN_ANNOTATION, + NullnessAnnotation.NONNULL); + } + } + else { + checkContainsNone(MSG_RETURN_WITHOUT_NULLNESS_ANNOTATION, + NullnessAnnotation.CHECK_FOR_NULL, NullnessAnnotation.NONNULL, + NullnessAnnotation.OVERRIDE); + } + + if (isMethodOverridden && !allowOverridingReturnValue) { + checkContainsAny(MSG_OVERRIDDEN_METHODS_ALLOW_ONLY_NONNULL, + NullnessAnnotation.CHECK_FOR_NULL, NullnessAnnotation.NULLABLE); + } + + if (isMethodOverridden) { + checkContainsAny(MSG_NEED_TO_INHERIT_PARAM_ANNOTATIONS, + NullnessAnnotation.PARAMETERS_ARE_NONNULL_BY_DEFAULT); + } + } + } + + } + + /** + * Class ConstructorJsr305Handler. Check a constructor. + */ + private final class ConstructorJsr305Handler extends AbstractMethodJsr305Handler { + + /** + * Constructor. + * @param ast + * the ast + */ + protected ConstructorJsr305Handler(final DetailAST ast) { + super(ast); + } + + /** + * Check for return type nullness annotations (which are illegal). + */ + @Override + protected void runReturnAnnotationCheck() { + checkContainsAny(MSG_CONSTRUCTOR_WITH_RETURN_ANNOTATION, + NullnessAnnotation.CHECK_FOR_NULL, NullnessAnnotation.CHECK_RETURN_VALUE, + NullnessAnnotation.NONNULL, NullnessAnnotation.NULLABLE, + NullnessAnnotation.OVERRIDE); + } + + } + + /** + * An abstract check, the base for checks on parameters, methods, classes. Class + * AbstractJsr305Check. + */ + public abstract class AbstractJsr305Handler { + + /** Has a violation been found. */ + private boolean violationFound; + /** The found annotations. */ + private final Set annotations; + /** The ast. */ + private final DetailAST ast; + + /** + * Construtor. + * @param ast + * the ast + */ + private AbstractJsr305Handler(final DetailAST ast) { + this.ast = ast; + this.violationFound = false; + annotations = findAnnotations(ast); + } + + /** + * Run the actual check. + */ + public final void check() { + runcheck(); + } + + /** + * Run the actual check. + */ + protected abstract void runcheck(); + + /** + * Emits a violation if any of the given annotations are found. + * @param msg + * the violation message to emit + * @param search + * the annotations to look for + */ + protected void checkContainsAny(final String msg, final NullnessAnnotation... search) { + if (!violationFound && containsAny(search)) { + violation(msg); + } + } + + /** + * Check whether any of the given annotations are found. + * @param search + * the annotations to look for + * @return true if yes + */ + private boolean containsAny(final NullnessAnnotation... search) { + boolean result = false; + if (!this.annotations.isEmpty()) { + for (final NullnessAnnotation obj : search) { + if (this.annotations.contains(obj)) { + result = true; + break; + } + } + } + return result; + } + + /** + * Emits a violation if all given annotations are found. + * @param msg + * the violation message to emit + * @param search + * the annotations to look for + */ + protected void checkContainsAll(final String msg, final NullnessAnnotation... search) { + if (!violationFound && containsAll(search)) { + violation(msg); + } + } + + /** + * Emits a violation if both this and the parent class have redundant nullness annotations. + * @param msg + * the violation message to emit + * @param search + * the annotations to look for + */ + protected void checkRedundancyDueToClassLevelAnnotation(final String msg, + final NullnessAnnotation... search) { + if (!violationFound) { + for (final NullnessAnnotation nullnessAnnotation : search) { + final boolean thisIsAnnotated = this.annotations.contains(nullnessAnnotation); + final boolean parentIsAnnotated = + getParentMethodOrClassAnnotation(nullnessAnnotation) != null; + if (thisIsAnnotated && parentIsAnnotated) { + violation(msg); + break; + } + } + } + } + + /** + * Check whether all the given annotations are present. + * @param search + * the annotations to look for + * @return true if yes + */ + private boolean containsAll(final NullnessAnnotation... search) { + boolean result = true; + if (this.annotations.isEmpty()) { + // an empty list of annotations can never contain all + result = false; + } + else { + for (final NullnessAnnotation obj : search) { + if (!this.annotations.contains(obj)) { + result = false; + break; + } + } + } + return result; + } + + /** + * Make sure that none of the given annotations are present. + * @param msg + * the violation message to emit if one of the given annotations was found + * @param search + * the annotations to look for + */ + protected void checkContainsNone(final String msg, + final NullnessAnnotation... search) { + if (!violationFound && !containsAny(search)) { + violation(msg); + } + } + + /** + * Handle a violation (log and set 'violationFound' to 'true'). + * + * @param msg + * the violation message + */ + private void violation(final String msg) { + log(ast, msg); + violationFound = true; + } + + /** + * Is the current symbol a primitive type. + * @return true if yes + */ + protected boolean isPrimitiveType() { + final DetailAST parameterType = ast.findFirstToken(TokenTypes.TYPE); + final boolean result; + final DetailAST identToken = parameterType.getFirstChild(); + + switch (identToken.getType()) { + case TokenTypes.LITERAL_BOOLEAN: + case TokenTypes.LITERAL_INT: + case TokenTypes.LITERAL_LONG: + case TokenTypes.LITERAL_SHORT: + case TokenTypes.LITERAL_BYTE: + case TokenTypes.LITERAL_CHAR: + case TokenTypes.LITERAL_VOID: + case TokenTypes.LITERAL_DOUBLE: + case TokenTypes.LITERAL_FLOAT: + result = !isArrayOrElipsis(parameterType); + break; + default: + result = false; + } + return result; + } + + /** + * Checks whether token is array or elipsis. + * @param identToken + * the token + * @return true if yes + */ + private boolean isArrayOrElipsis(final DetailAST identToken) { + final DetailAST next = identToken.getNextSibling(); + final boolean result; + switch (next.getType()) { + case TokenTypes.ARRAY_DECLARATOR: + case TokenTypes.ELLIPSIS: + result = true; + break; + default: + result = false; + } + return result; + } + + /** + * Is the current symbol of void type. + * @return true if yes + */ + protected boolean isVoid() { + final DetailAST parameterType = ast.findFirstToken(TokenTypes.TYPE); + final boolean result; + final DetailAST identToken = parameterType.getFirstChild(); + result = identToken.getType() == TokenTypes.LITERAL_VOID; + return result; + } + + /** + * Gets the nullness annotation for the parent method or class. + * @param annotationsToLookFor + * the annotations to look for. + * @return the annotation or null if none was found + */ + protected NullnessAnnotation + getParentMethodOrClassAnnotation(final NullnessAnnotation... annotationsToLookFor) { + + boolean finished = false; + NullnessAnnotation result = null; + for (DetailAST current = ast.getParent(); current != null && !finished; current = + current.getParent()) { + final int tokenType = current.getType(); + + if (isPossibleTokenTypeForNullnessAnnotations(tokenType)) { + final Set foundAndLookedFor = + collectLookedForAnnotations(current, annotationsToLookFor); + if (foundAndLookedFor.size() == 1) { + result = foundAndLookedFor.iterator().next(); + finished = true; + } + else if (!foundAndLookedFor.isEmpty()) { + finished = true; + } + } + // break on inner and anonymous classes/interfaces, we can't + // handle inheritance correctly + if (tokenType == TokenTypes.LITERAL_NEW || tokenType == TokenTypes.CLASS_DEF + || tokenType == TokenTypes.INTERFACE_DEF + || tokenType == TokenTypes.ENUM_DEF) { + finished = true; + } + } + return result; + } + + /** + * Is the current tokenType a possible type for nullness annotations. + * @param tokenType the token type + * @return true if yes + */ + private boolean isPossibleTokenTypeForNullnessAnnotations(final int tokenType) { + return tokenType == TokenTypes.CLASS_DEF || tokenType == TokenTypes.INTERFACE_DEF + || tokenType == TokenTypes.METHOD_DEF || tokenType == TokenTypes.CTOR_DEF + || tokenType == TokenTypes.ENUM_DEF; + } + + /** + * Extracts all given annotations from the current ast. + * @param current the current ast + * @param annotationsToLookFor the annotations we are looking for + * @return the annotations + */ + private Set collectLookedForAnnotations(DetailAST current, + final NullnessAnnotation... annotationsToLookFor) { + final Set foundAnnotations = findAnnotations(current); + final Set foundAndLookedFor = new HashSet<>(); + for (final NullnessAnnotation nullnessAnnotation : annotationsToLookFor) { + if (foundAnnotations.contains(nullnessAnnotation)) { + foundAndLookedFor.add(nullnessAnnotation); + } + } + return foundAndLookedFor; + } + + /** + * Is the current method overridden. + * @return true if yes + */ + protected boolean isMethodOverridden() { + DetailAST current = ast; + Boolean result = null; + for (; current != null && result == null; current = current.getParent()) { + switch (current.getType()) { + case TokenTypes.METHOD_DEF: + result = findAnnotations(current).contains(NullnessAnnotation.OVERRIDE); + break; + case TokenTypes.LAMBDA: + result = true; + break; + default: + } + } + if (result == null) { + result = false; + } + return result; + } + + } + +} diff --git a/sevntu-checks/src/main/resources/com/github/sevntu/checkstyle/checks/coding/messages.properties b/sevntu-checks/src/main/resources/com/github/sevntu/checkstyle/checks/coding/messages.properties index 04ee0a0026..20b1898476 100644 --- a/sevntu-checks/src/main/resources/com/github/sevntu/checkstyle/checks/coding/messages.properties +++ b/sevntu-checks/src/main/resources/com/github/sevntu/checkstyle/checks/coding/messages.properties @@ -59,3 +59,28 @@ useless.super.ctor.call.without.args= Redundant super constructor call could be return.null.Boolean=Method declares to return Boolean and returns null. return.boolean.ternary=Returning explicit boolean from ternary operator. whitespace.before.array.initializer=Array initializer should have whitespace before. +jsr305.illegal.class.level.annotation=@CheckForNull, @Nullable, @Nonnull and @CheckReturnValue are not allowed on class level. Use @ParametersAreNonnullByDefault, @ParametersAreNullableByDefault and @ReturnValuesAreNonnullByDefault. +jsr305.contradicting.class.level.annotations=@ParametersAreNullableByDefault and @ParametersAreNonnullByDefault are not allowed together. +jsr305.param.definitions.with.check.annotation=Parameter definitions don''t need checking, use @Nullable or @Nonnull. +jsr305.param.definition.with.override.annotation=@Override is not allowed on parameter definition. +jsr305.param.definition.with.nonnull.by.default.annotation=@ParametersAreNonnullByDefault is not allowed on parameter definition. +jsr305.param.definition.with.nullable.by.default.annotation=@ParametersAreNullableByDefault is not allowed on parameter definition. +jsr305.param.definition.with.return.values.default.annotation=@ReturnValuesAreNonnullByDefault is not allowed on parameter definition. +jsr305.param.nonnull.and.nullable.annotation=@Nonnull and @Nullable are not allowed together. +jsr305.primitives.with.nullness.annotation=Primitives must not have any nullness annotations. +jsr305.overridden.definitions.with.increased.param.constraint=It is not allowed to increase nullness constraint for overriden method parameter definitions. +jsr305.redundant.nonnull.param.annotation=It is not necessary to annotate @Nonnull if you annotated the method or class with @ParametersAreNonnullByDefault. +jsr305.redundant.nullable.param.annotation=It is not necessary to annotate @Nullable if you annoted the method or class with @ParametersAreNullableByDefault. +jsr305.parameter.without.nullness.annotation=No nullness Annotation for parameter definition found. +jsr305.return.value.with.nonnull.by.default.annotation=@ReturnValuesAreNonnullByDefault is not allowed on method return values. +jsr305.return.value.with.nullable.annotation=@Nullable is not allowed on method return values. +jsr305.contradicting.return.value.annotations=@Nonnull and @CheckForNull are not allowed together. +jsr305.overridden.method.with.check.return.value.annotation=@CheckReturnValue is not allowed on overriden methods, annotate the interface or superclass. +jsr305.redundant.nonnull.by.default.annotation=Redundant @ParametersAreNonnullByDefault, the class is annotated with the same annotation. +jsr305.redundant.nullable.by.default.annotation=Redundant @ParametersAreNullableByDefault, the class is annotated with the same annotation. +jsr305.void.with.check.return.value.annotation=There is nothing to check on void return methods, remove @CheckReturnValue. +jsr305.redundant.nonnull.return.annotation=It is not necessary to annotate @Nonnull if you annoted the class with @ReturnValuesAreNonnullByDefault. +jsr305.return.without.nullness.annotation=Return value must have nullness Annotation (@Nonnull or @CheckForNull). +jsr305.overridden.methods.allow.only.nonnull=Overriden methods allow only @Nonnull. +jsr305.need.to.inherit.param.annotations=You have to inherit parameter annotations. +jsr305.constructor.with.return.annotation=Constructors have no return value and must not be annotated. diff --git a/sevntu-checks/src/test/java/com/github/sevntu/checkstyle/checks/coding/Jsr305AnnotationsCheckTest.java b/sevntu-checks/src/test/java/com/github/sevntu/checkstyle/checks/coding/Jsr305AnnotationsCheckTest.java new file mode 100644 index 0000000000..b0e561b675 --- /dev/null +++ b/sevntu-checks/src/test/java/com/github/sevntu/checkstyle/checks/coding/Jsr305AnnotationsCheckTest.java @@ -0,0 +1,394 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2019 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.sevntu.checkstyle.checks.coding; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.junit.Assert; +import org.junit.Test; + +import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport; +import com.puppycrawl.tools.checkstyle.DefaultConfiguration; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil; + +public class Jsr305AnnotationsCheckTest extends AbstractModuleTestSupport { + + @Override + protected String getPackageLocation() { + return "com/github/sevntu/checkstyle/checks/coding"; + } + + @Test + public void testParameters() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(Jsr305AnnotationsCheck.class); + checkConfig.addAttribute("packages", "com.github.sevntu.checkstyle.checks.coding"); + + final String[] expected = { + "36:44: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "40:45: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "40:64: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "68:41: " + + getCheckMessage(Jsr305AnnotationsCheck.MSG_PARAM_DEFINITIONS_WITH_CHECK, "e"), + "73:27: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_OVERRIDDEN_WITH_INCREASED_CONSTRAINT, "e"), + "88:35: " + getCheckMessage(Jsr305AnnotationsCheck.MSG_PARAM_NONNULL_AND_NULLABLE, "e"), + }; + + verify(checkConfig, getPath("InputJsr305AnnotationsCheckWithParameter.java"), expected); + } + + @Test + public void testPrimitives() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(Jsr305AnnotationsCheck.class); + checkConfig.addAttribute("packages", "com.github.sevntu.checkstyle.checks.coding"); + + final String[] expected = { + "28:37: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PRIMITIVES_WITH_NULLNESS_ANNOTATION, "e"), + "32:38: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PRIMITIVES_WITH_NULLNESS_ANNOTATION, "e"), + "36:42: " + + getCheckMessage(Jsr305AnnotationsCheck.MSG_PARAM_DEFINITIONS_WITH_CHECK, "e"), + "40:5: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PRIMITIVES_WITH_NULLNESS_ANNOTATION, "e"), + "45:5: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PRIMITIVES_WITH_NULLNESS_ANNOTATION, "e"), + "50:5: " + getCheckMessage(Jsr305AnnotationsCheck.MSG_RETURN_VALUE_WITH_NULLABLE, "e"), + "55:5: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PRIMITIVES_WITH_NULLNESS_ANNOTATION, "e"), + "61:5: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PRIMITIVES_WITH_NULLNESS_ANNOTATION, "e"), + "99:34: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PRIMITIVES_WITH_NULLNESS_ANNOTATION, "e"), + }; + + verify(checkConfig, getPath("InputJsr305AnnotationsCheckWithPrimitives.java"), expected); + } + + @Test + public void testReturnValues() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(Jsr305AnnotationsCheck.class); + checkConfig.addAttribute("packages", "com.github.sevntu.checkstyle.checks.coding"); + + final String[] expected = { + "46:5: " + getCheckMessage(Jsr305AnnotationsCheck.MSG_RETURN_VALUE_WITH_NULLABLE, "e"), + "51:5: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_CONTRADICTING_RETURN_VALUE_ANNOTATIONS, "e"), + "69:5: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PRIMITIVES_WITH_NULLNESS_ANNOTATION, "e"), + "75:5: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PRIMITIVES_WITH_NULLNESS_ANNOTATION, "e"), + "92:5: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_CONTRADICTING_CLASS_LEVEL_ANNOTATIONS, "e"), + "95:26: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "95:48: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "99:5: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_OVERRIDDEN_METHOD_WITH_CHECK_RETURN_VALUE, "e"), + "105:5: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_VOID_WITH_CHECK_RETURN_VALUE_ANNOTATION, "e"), + "110:5: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PRIMITIVES_WITH_NULLNESS_ANNOTATION, "e"), + }; + + verify(checkConfig, getPath("InputJsr305AnnotationsCheckWithReturnValue.java"), expected); + } + + @Test + public void testConstructors() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(Jsr305AnnotationsCheck.class); + checkConfig.addAttribute("packages", "com.github.sevntu.checkstyle.checks.coding"); + + final String[] expected = { + "37:55: " + getCheckMessage(Jsr305AnnotationsCheck.MSG_PARAM_NONNULL_AND_NULLABLE, "e"), + "42:55: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "54:55: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_REDUNDANT_NONNULL_PARAM_ANNOTATION, "e"), + "66:75: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_REDUNDANT_NULLABLE_PARAM_ANNOTATION, "e"), + }; + + verify(checkConfig, getPath("InputJsr305AnnotationsCheckWithConstructor.java"), expected); + } + + @Test + public void testArrays() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(Jsr305AnnotationsCheck.class); + checkConfig.addAttribute("packages", "com.github.sevntu.checkstyle.checks.coding"); + + final String[] expected = { + "40:43: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "52:43: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "64:43: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "76:43: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "90:8: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_RETURN_WITHOUT_NULLNESS_ANNOTATION, "e"), + "102:32: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "114:34: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + }; + + verify(checkConfig, getPath("InputJsr305AnnotationsCheckWithArrays.java"), expected); + } + + @Test + public void testClasses() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(Jsr305AnnotationsCheck.class); + checkConfig.addAttribute("packages", "com.github.sevntu.checkstyle.checks.coding"); + + final String[] expected = { + "32:5: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_CONTRADICTING_CLASS_LEVEL_ANNOTATIONS, "e"), + "43:26: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_REDUNDANT_NULLABLE_PARAM_ANNOTATION, "e"), + "51:29: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "68:32: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_REDUNDANT_NONNULL_PARAM_ANNOTATION, "e"), + "75:36: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "119:43: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "125:9: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_REDUNDANT_NONNULL_RETURN_ANNOTATION, "e"), + "128:9: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_RETURN_VALUE_WITH_NONNULL_BY_DEFAULT, "e"), + "137:9: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_REDUNDANT_NONNULL_RETURN_ANNOTATION, "e"), + "142:9: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_RETURN_VALUE_WITH_NONNULL_BY_DEFAULT, "e"), + "157:9: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_RETURN_VALUE_WITH_NONNULL_BY_DEFAULT, "e"), + }; + + verify(checkConfig, getPath("InputJsr305AnnotationsCheckWithClass.java"), expected); + } + + @Test + public void testEnums() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(Jsr305AnnotationsCheck.class); + checkConfig.addAttribute("packages", "com.github.sevntu.checkstyle.checks.coding"); + + final String[] expected = { + "42:32: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_REDUNDANT_NONNULL_PARAM_ANNOTATION, "e"), + "50:36: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "64:9: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_REDUNDANT_NONNULL_RETURN_ANNOTATION, "e"), + "69:9: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_RETURN_VALUE_WITH_NONNULL_BY_DEFAULT, "e"), + "80:5: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_CONTRADICTING_CLASS_LEVEL_ANNOTATIONS, "e"), + }; + + verify(checkConfig, getPath("InputJsr305AnnotationsCheckWithEnum.java"), expected); + } + + @Test + public void testInheritance() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(Jsr305AnnotationsCheck.class); + checkConfig.addAttribute("packages", "com.github.sevntu.checkstyle.checks.coding"); + + final String[] expected = { + "43:47: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "75:43: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + }; + + verify(checkConfig, getPath("InputJsr305AnnotationsCheckWithInheritance.java"), expected); + } + + @Test + public void testReturnValueDefaults() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(Jsr305AnnotationsCheck.class); + checkConfig.addAttribute("packages", "com.github.sevntu.checkstyle.checks.coding"); + + final String[] expected = { + "35:5: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_REDUNDANT_NONNULL_RETURN_ANNOTATION, "e"), + }; + + verify(checkConfig, getPath("InputJsr305AnnotationsCheckWithDefaultReturnValues.java"), + expected); + } + + @Test + public void testRedudantClassLevelAnnotations() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(Jsr305AnnotationsCheck.class); + checkConfig.addAttribute("packages", "com.github.sevntu.checkstyle.checks.coding"); + + final String[] expected = { + "28:5: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_REDUNDANT_NULLABLE_BY_DEFAULT_ANNOTATION, "e"), + }; + + verify(checkConfig, getPath("InputJsr305AnnotationsCheckWithRedundantClassLevel.java"), + expected); + } + + @Test + public void testLambdas() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(Jsr305AnnotationsCheck.class); + checkConfig.addAttribute("packages", "com.github.sevntu.checkstyle.checks.coding"); + + final String[] expected = { + "33:10: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_OVERRIDDEN_WITH_INCREASED_CONSTRAINT, "e"), + "42:5: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_RETURN_WITHOUT_NULLNESS_ANNOTATION, "e"), + }; + + verify(checkConfig, getPath("InputJsr305AnnotationsCheckWithLambda.java"), expected); + } + + @Test + public void testAllowOverridingParameters() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(Jsr305AnnotationsCheck.class); + checkConfig.addAttribute("packages", "com.github.sevntu.checkstyle.checks.coding"); + checkConfig.addAttribute("allowOverridingReturnValue", "true"); + checkConfig.addAttribute("allowOverridingParameter", "true"); + + final String[] expected = { + "36:44: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "40:45: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "40:64: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "68:41: " + + getCheckMessage(Jsr305AnnotationsCheck.MSG_PARAM_DEFINITIONS_WITH_CHECK, "e"), + "88:35: " + getCheckMessage(Jsr305AnnotationsCheck.MSG_PARAM_NONNULL_AND_NULLABLE, "e"), + }; + + verify(checkConfig, getPath("InputJsr305AnnotationsCheckWithParameter.java"), expected); + } + + @Test + public void testAllowOverridingLambdas() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(Jsr305AnnotationsCheck.class); + checkConfig.addAttribute("packages", "com.github.sevntu.checkstyle.checks.coding"); + checkConfig.addAttribute("allowOverridingReturnValue", "true"); + checkConfig.addAttribute("allowOverridingParameter", "true"); + + final String[] expected = { + "42:5: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_RETURN_WITHOUT_NULLNESS_ANNOTATION, "e"), + }; + + verify(checkConfig, getPath("InputJsr305AnnotationsCheckWithLambda.java"), expected); + } + + @Test + public void testAllowOverridingInheritance() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(Jsr305AnnotationsCheck.class); + checkConfig.addAttribute("packages", "com.github.sevntu.checkstyle.checks.coding"); + checkConfig.addAttribute("allowOverridingReturnValue", "true"); + checkConfig.addAttribute("allowOverridingParameter", "true"); + + final String[] expected = { + "43:47: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + "75:43: " + getCheckMessage( + Jsr305AnnotationsCheck.MSG_PARAMETER_WITHOUT_NULLNESS_ANNOTATION, "e"), + }; + + verify(checkConfig, getPath("InputJsr305AnnotationsCheckWithInheritance.java"), expected); + } + + @Test + public void testCatch() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(Jsr305AnnotationsCheck.class); + checkConfig.addAttribute("packages", "com.github.sevntu.checkstyle.checks.coding"); + verify(checkConfig, getPath("InputJsr305AnnotationsCheckWithCatch.java"), + new String[0]); + } + + @Test + public void testInclude1Package() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(Jsr305AnnotationsCheck.class); + checkConfig.addAttribute("packages", + "com.github.sevntu.checkstyle.checks.naming"); + + verify(checkConfig, getPath("InputJsr305AnnotationsCheckWithCatch.java"), new String[0]); + } + + @Test + public void testInclude2Packages() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(Jsr305AnnotationsCheck.class); + checkConfig.addAttribute("packages", + "com.github.sevntu.checkstyle.internal,com.github.sevntu.checkstyle.checks.coding"); + + verify(checkConfig, getPath("InputJsr305AnnotationsCheckWithCatch.java"), new String[0]); + } + + @Test + public void testExcludePackage() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(Jsr305AnnotationsCheck.class); + checkConfig.addAttribute("packages", "com.github.sevntu.checkstyle.checks.coding"); + checkConfig.addAttribute("excludePackages", + "com.github.sevntu.checkstyle.internal,com.github.sevntu.checkstyle.checks.coding"); + + final String[] expected = {}; + + verify(checkConfig, getPath("InputJsr305AnnotationsCheckWithParameter.java"), expected); + } + + /** + * This must be a reflection test as it is too difficult to hit normally and the responsible + * code can't be removed without hitting checkstyle violations. This test targets the handling + * of token types not in 'acceptable tokens' (which should normally not occur). + * + * @throws Exception + * if there is an unexcpected error. + */ + @Test + public void testHandleDefinition() throws Exception { + final DetailAST ast = new DetailAST(); + ast.setType(TokenTypes.WILDCARD_TYPE); + + final Method handleDefinition = + TestUtil.getClassDeclaredMethod(Jsr305AnnotationsCheck.class, "handleDefinition"); + + try { + handleDefinition.invoke(new Jsr305AnnotationsCheck(), ast); + Assert.fail("Exception expected."); + } + catch (final InvocationTargetException exc) { + Assert.assertTrue("IllegalArgumentException expected from 'handleDefinition'", + exc.getCause().getClass().equals(IllegalArgumentException.class)); + } + } + +} diff --git a/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithArrays.java b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithArrays.java new file mode 100644 index 0000000000..6bd0a53e1f --- /dev/null +++ b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithArrays.java @@ -0,0 +1,122 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2019 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.sevntu.checkstyle.checks.coding; + +import java.io.Serializable; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class InputJsr305AnnotationsCheckWithArrays { + + private final Object obj; + + InputJsr305AnnotationsCheckWithArrays(@Nonnull final int[] nonnull) { // ok + obj = nonnull; + } + + InputJsr305AnnotationsCheckWithArrays(@Nullable final long[] nullable) { // ok + obj = nullable; + } + + InputJsr305AnnotationsCheckWithArrays(final short[] array) { // violation + obj = array; + } + + InputJsr305AnnotationsCheckWithArrays(@Nonnull final byte... varargs) { // ok + obj = varargs; + } + + InputJsr305AnnotationsCheckWithArrays(@Nullable final float... varargs) { // ok + obj = varargs; + } + + InputJsr305AnnotationsCheckWithArrays(final double... varargs) { // violation + obj = varargs; + } + + InputJsr305AnnotationsCheckWithArrays(@Nonnull final String... varargs) { // ok + obj = varargs; + } + + InputJsr305AnnotationsCheckWithArrays(@Nullable final Object... varargs) { // ok + obj = varargs; + } + + InputJsr305AnnotationsCheckWithArrays(final Serializable... varargs) { // violation + obj = varargs; + } + + InputJsr305AnnotationsCheckWithArrays(@Nonnull final Class[] clazz) { // ok + obj = clazz; + } + + InputJsr305AnnotationsCheckWithArrays(@Nullable final Iterable[] iterable) { // ok + obj = iterable; + } + + InputJsr305AnnotationsCheckWithArrays(final Comparable comparable) { // violation + obj = comparable; + } + + @Nonnull + int[] retNonnul() { // ok + return new int[] {}; + } + + @CheckForNull + int[] retCheckForNull() { // ok + return null; + } + + int[] retNoAnnotation() { // violation + return new int[] {}; + } + + void testNonnullArray(@Nonnull final int[] array) { // ok + array[1] = 0; + } + + void testNullableArray(@Nullable final int[] array) { // ok + array[1] = 0; + } + + void testNoAnnotationArray(final int[] array) { // violation + array[1] = 0; + } + + void testNonnullVarargs(@Nonnull final int... varargs) { // ok + varargs[1] = 0; + } + + void testNullableVarargs(@Nullable final int... varargs) { // ok + varargs[1] = 0; + } + + void testNoAnnotationVarargs(final int... varargs) { // violation + varargs[1] = 0; + } + + @Override + public String toString() { // ok + return String.valueOf(obj); + } +} diff --git a/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithCatch.java b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithCatch.java new file mode 100644 index 0000000000..cf07ff31fe --- /dev/null +++ b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithCatch.java @@ -0,0 +1,44 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2019 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.sevntu.checkstyle.checks.coding; + +import java.io.Serializable; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class InputJsr305AnnotationsCheckWithCatch { + + public InputJsr305AnnotationsCheckWithCatch() throws Exception { + try { + System.out.println("foo"); + } + catch (Exception exc) { + throw new Exception() { + @Override + public String getMessage() { + return "foo"; + } + }; + } + } + +} diff --git a/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithClass.java b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithClass.java new file mode 100644 index 0000000000..26b796a0d2 --- /dev/null +++ b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithClass.java @@ -0,0 +1,164 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2019 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.sevntu.checkstyle.checks.coding; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; +import javax.annotation.ParametersAreNullableByDefault; + +import edu.umd.cs.findbugs.annotations.ReturnValuesAreNonnullByDefault; + +public class InputJsr305AnnotationsCheckWithClass { + + @ParametersAreNonnullByDefault // violation, double annotation + @ParametersAreNullableByDefault + class BothParameterAnnotationsClass { + + } + + @ParametersAreNullableByDefault // ok + interface ParameterAnnotationsInterface { + + void setUnannotated(String unannotated); // ok + + void setNullable(@Nullable String nullable); // violation, redundant + + void setNonnull(@Nonnull String nonnull); // ok + + } + + interface NoParameterAnnotationsInterface { + + void setUnannotated(String unannotated); // violation, missing + + void setNullable(@Nonnull String nullable); // ok + + void setNonnull(@Nullable String nonnull); // ok + + } + + @ParametersAreNonnullByDefault + class ParameterAnnotationsClass { + + public void setUnannotated(final String unannotated) { // ok + } + + public void setNullable(@Nullable final String nullable) { // ok + } + + public void setNonnull(@Nonnull final String nonnull) { // violation, redundant + } + + } + + class NoParameterAnnotationsClass { + + public void setUnannotated(final String unannotated) { // violation, missing + } + + public void setNullable(@Nullable final String nullable) { // ok + } + + public void setNonnull(@Nonnull final String nonnull) { // ok + } + + } + + @ParametersAreNonnullByDefault + static class DefaultNullableParameterInheritingClass implements ParameterAnnotationsInterface { + + @Override + public void setUnannotated(final String unannotated) { // ok + } + + @Override + public void setNullable(final String nullable) { // ok + } + + @Override + public void setNonnull(final String nonnull) { // ok + } + + public void setAnotherUnannotated(final String unannotated) { // ok + } + } + + static class NullableParameterInheritingClass implements ParameterAnnotationsInterface { + + @Override + public void setUnannotated(final String unannotated) { // ok + } + + @Override + public void setNullable(final String nullable) { // ok + } + + @Override + public void setNonnull(final String nonnull) { // ok + } + + public void setAnotherUnannotated(final String unannotated) { // violation + } + } + + @ReturnValuesAreNonnullByDefault + interface ReturnValueAnnotationInterface { + @Nonnull // violation, redundant + String getNonnull(); + + @ReturnValuesAreNonnullByDefault // violation, disallowed + String getNonnullByDefault(); + + @CheckForNull // ok + String getCheckForNull(); + } + + @ReturnValuesAreNonnullByDefault + static class ReturnValueAnnotationClass { + @Nonnull // violation, redundant + public String getNonnull() { + return ""; + } + + @ReturnValuesAreNonnullByDefault // violation, disallowed + public String getNonnullByDefault() { + return ""; + } + + @CheckForNull // ok + public String getCheckForNull() { + return ""; + } + } + + interface NoReturnValueAnnotationInterface { + @Nonnull // ok + String getNonnull(); + + @ReturnValuesAreNonnullByDefault // violation, disallowed + String getNonnullByDefault(); + + @CheckForNull // ok + String getCheckForNull(); + } + +} diff --git a/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithConstructor.java b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithConstructor.java new file mode 100644 index 0000000000..941765096d --- /dev/null +++ b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithConstructor.java @@ -0,0 +1,97 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2019 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.sevntu.checkstyle.checks.coding; + +import javax.annotation.CheckForNull; +import javax.annotation.CheckReturnValue; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; +import javax.annotation.ParametersAreNullableByDefault; + +public class InputJsr305AnnotationsCheckWithConstructor { + + @Nonnull + private final Object nonnull; + + @Nullable + private final Object nullable; + + public InputJsr305AnnotationsCheckWithConstructor(@Nonnull @Nullable final Enum value) { // violation + nullable = value; + nonnull = new Object(); + } + + public InputJsr305AnnotationsCheckWithConstructor(final Class clz) { // violation + nonnull = new Object(); + nullable = clz; + } + + @ParametersAreNonnullByDefault + public InputJsr305AnnotationsCheckWithConstructor(final String string1, @Nullable final String string2) { // ok + nonnull = string1; + nullable = string2; + } + + @ParametersAreNonnullByDefault + public InputJsr305AnnotationsCheckWithConstructor(@Nonnull final String string1, final Integer string2) { // violation + nonnull = string1; + nullable = string2; + } + + @ParametersAreNullableByDefault + public InputJsr305AnnotationsCheckWithConstructor(@Nonnull final Integer int1, final Integer int2) { // ok + nonnull = int1; + nullable = int2; + } + + @ParametersAreNullableByDefault + public InputJsr305AnnotationsCheckWithConstructor(final Integer int1, @Nullable final String int2) { // violation + if (int1 != null) { + nonnull = int1; + } + else { + nonnull = Integer.valueOf(1); + } + nullable = int2; + } + + public InputJsr305AnnotationsCheckWithConstructor(@Nullable final String obj) { // ok + nonnull = new Object(); + nullable = obj; + } + + public InputJsr305AnnotationsCheckWithConstructor(@Nonnull final Integer obj) { // ok + nonnull = obj; + nullable = null; + } + + @CheckForNull + public Object getNullable() { // ok + return nullable; + } + + @CheckReturnValue + @Nonnull + public Object getNonnull() { // ok + return nonnull; + } + +} diff --git a/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithDefaultReturnValues.java b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithDefaultReturnValues.java new file mode 100644 index 0000000000..68475ac15c --- /dev/null +++ b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithDefaultReturnValues.java @@ -0,0 +1,40 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2019 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.sevntu.checkstyle.checks.coding; + +import javax.annotation.Nonnull; + +import edu.umd.cs.findbugs.annotations.ReturnValuesAreNonnullByDefault; + +@ReturnValuesAreNonnullByDefault +public class InputJsr305AnnotationsCheckWithDefaultReturnValues { + + @Override + @Nonnull // ok + public String toString() { + return super.toString(); + } + + @Nonnull // violation + public Object bar() { + return new Object(); + } + +} diff --git a/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithEnum.java b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithEnum.java new file mode 100644 index 0000000000..7b067f1dce --- /dev/null +++ b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithEnum.java @@ -0,0 +1,86 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2019 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.sevntu.checkstyle.checks.coding; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; +import javax.annotation.ParametersAreNullableByDefault; + +import edu.umd.cs.findbugs.annotations.ReturnValuesAreNonnullByDefault; + +public class InputJsr305AnnotationsCheckWithEnum { + + @ParametersAreNonnullByDefault + enum ParameterAnnotationsEnum { + TEST; + + public void setUnannotated(final String foo) { // ok + } + + public void setNullable(@Nullable final String foo) { // ok + } + + public void setNonnull(@Nonnull final String foo) { // violation, redundant + } + + } + + enum NoParameterAnnotationsEnum { + TEST; + + public void setUnannotated(final String foo) { // violation, missing + } + + public void setNullable(@Nullable final String foo) { // ok + } + + public void setNonnull(@Nonnull final String foo) { // ok + } + + } + + @ReturnValuesAreNonnullByDefault + enum ReturnValueAnnotationEnum { + TEST; + @Nonnull // violation, redundant + public String getNonnull() { + return ""; + } + + @ReturnValuesAreNonnullByDefault // violation, disallowed + public String getNonnnullByDefault() { + return ""; + } + + @CheckForNull // ok + public String getCheckForNull() { + return ""; + } + } + + @ParametersAreNonnullByDefault // violation + @ParametersAreNullableByDefault + enum BothAnnotations { + TEST; + } + +} diff --git a/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithInheritance.java b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithInheritance.java new file mode 100644 index 0000000000..18943c82f4 --- /dev/null +++ b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithInheritance.java @@ -0,0 +1,108 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2019 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.sevntu.checkstyle.checks.coding; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; +import javax.annotation.ParametersAreNullableByDefault; + +@ParametersAreNullableByDefault +public class InputJsr305AnnotationsCheckWithInheritance { + + // anonymous classes can't be annotated, but this should inherit the + // annotations from the superclass + public void testAnonClasses() { + final Inherited anonymousClassInstance = new Inherited() { + + @Override + public void getUnannotated(final String unannotated) { + } + + @Override + public void getNullable(final String nullable) { + } + + public void getAnotherUnannotated(final String getAnotherUnannotated) { // violation + } + + @Override + public Object nonnull() { + return ""; + } + }; + } + + @ParametersAreNonnullByDefault + interface Inherited { + + void getUnannotated(String unannotated); // ok + + void getNullable(@Nullable String nullable); // ok + + @Nonnull + Object nonnull(); + } + + // ok + static class UnannotatedInheritor implements Inherited { + + @Override // ok, since we're overriding @NonnullByDefault from the interface + public void getUnannotated(@Nullable final String unannotated) { + } + + @Override // ok + public void getNullable(final String nullable) { + } + + public void getAnotherUnannotated(final String unannotated) { // violation + } + + @Override + public Object nonnull() { + return ""; + } + + } + + @ParametersAreNullableByDefault // ok + static class AnnotatedInheritor implements Inherited { + + // this should not be an violation, we are inheriting via the @Override + // annotation + @Override + public void getUnannotated(final String unannotated) { + } + + @Override // ok + public void getNullable(final String nullable) { + } + + public void getAnotherUnannotated(final String unannotated) { // ok + } + + @Override + @Nonnull // ok + public Object nonnull() { + return ""; + } + } + +} diff --git a/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithLambda.java b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithLambda.java new file mode 100644 index 0000000000..28443157d4 --- /dev/null +++ b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithLambda.java @@ -0,0 +1,46 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2019 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.sevntu.checkstyle.checks.coding; + +import java.util.function.Function; +import java.util.function.ToIntFunction; + +import javax.annotation.Nonnull; + +public final class InputJsr305AnnotationsCheckWithLambda { + + public static final Function TO_STRING = + object -> object.toString(); // ok + + public static final ToIntFunction HASH_CODE = + (@Nonnull Object object) -> object.hashCode(); // violation + + /** + * Private util class constructor. + */ + private InputJsr305AnnotationsCheckWithLambda() { + // empty + } + + public String violation() { // violation + return ""; + } + +} diff --git a/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithParameter.java b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithParameter.java new file mode 100644 index 0000000000..feb8058106 --- /dev/null +++ b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithParameter.java @@ -0,0 +1,100 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2019 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.sevntu.checkstyle.checks.coding; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class InputJsr305AnnotationsCheckWithParameter + implements Comparable, Serializable { + + private static final long serialVersionUID = 1L; + + @Nonnull + public String missingNullnessParameter(final Object obj) { // violation + return obj.toString(); + } + + public boolean missingNullnessParameter(final Object obj1, final Object obj2) { // 2x violation + return obj1.equals(obj2); + } + + @Nonnull + public String nonnullParameter(@Nonnull final Object obj) { // ok + return obj.toString(); + } + + public boolean nonnullParameter(@Nonnull final Object obj1, + @Nonnull final Object obj2) { // ok + return obj1.equals(obj2); + } + + @Nonnull + public String nullableParameter(@Nullable final Object obj) { // ok + return String.valueOf(obj); + } + + public boolean nullableParameter(@Nullable final Object obj1, + @Nullable final Object obj2) { // ok + if (obj1 != null) { + System.out.println("bonk"); + } + return obj2 == null; + } + + @Nonnull + public String checkForNullParameter(@CheckForNull final Object obj) { // violation + return String.valueOf(obj); + } + + @Override + public boolean equals(@Nonnull final Object obj) { // violation + return super.equals(obj); + } + + @Override + public int hashCode() { // ok + return super.hashCode(); + } + + @Override + public int compareTo(@Nullable final InputJsr305AnnotationsCheckWithParameter obj) { // ok + return 0; + } + + @Nonnull + public String nonnullNullable(@Nonnull @Nullable final Object obj) { // violation + return String.valueOf(obj); + } + + @Nonnull + @SuppressWarnings("unchecked") + public List typeCast() { // ok + final Object list = new ArrayList<>(); + final List result = (List) list; + return result; + } + +} diff --git a/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithPrimitives.java b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithPrimitives.java new file mode 100644 index 0000000000..5d3bfeccbd --- /dev/null +++ b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithPrimitives.java @@ -0,0 +1,103 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2019 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.sevntu.checkstyle.checks.coding; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class InputJsr305AnnotationsCheckWithPrimitives { + + public boolean nonnullParameter(@Nonnull final int param) { // violation + return param == 0; + } + + public boolean nullableParameter(@Nullable final int param) { // violation + return param == 0; + } + + public boolean checkForNullParameter(@CheckForNull final int param) { // violation + return param == 0; + } + + @Nonnull // violation + public int returnNonnull() { + return 0; + } + + @CheckForNull // violation + public int returnCheckForNull() { + return 0; + } + + @Nullable // violation + public int returnNullable() { + return 0; + } + + @Override // violation + @Nonnull + public boolean equals(Object object) { + return super.equals(object); + } + + @Override // violation + @Nonnull + public int hashCode() { + return super.hashCode(); + } + + public int primitivesInt(final int primitive) { // ok + return primitive + 1; + } + + public byte primitivesByte(final byte primitive) { // ok + return primitive; + } + + public boolean primitivesBoolean(final boolean primitive) { // ok + return !primitive; + } + + public float primitivesFloat(final float primitive) { // ok + return primitive + 1.0F; + } + + public double primitivesDouble(final double primitive) { // ok + return primitive + 1.0D; + } + + public long primitivesLong(final long primitive) { // ok + return primitive + 1L; + } + + public short primitivesShort(final short primitive) { // ok + return primitive; + } + + public char primitivesChar(final char primitive) { // ok + return primitive; + } + + public int primitivesNonnull(@Nonnull final int primitive) { // violation + return primitive + 1; + } + +} diff --git a/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithRedundantClassLevel.java b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithRedundantClassLevel.java new file mode 100644 index 0000000000..cd179414f1 --- /dev/null +++ b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithRedundantClassLevel.java @@ -0,0 +1,38 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2019 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.sevntu.checkstyle.checks.coding; + +import javax.annotation.ParametersAreNonnullByDefault; +import javax.annotation.ParametersAreNullableByDefault; + +@ParametersAreNullableByDefault +public class InputJsr305AnnotationsCheckWithRedundantClassLevel { + + @ParametersAreNullableByDefault // violation + public void redundant1() { + } + + public void redundant2() { // ok + } + + @ParametersAreNonnullByDefault // ok + public void redundant3() { + } +} diff --git a/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithReturnValue.java b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithReturnValue.java new file mode 100644 index 0000000000..adad1f5c0d --- /dev/null +++ b/sevntu-checks/src/test/resources/com/github/sevntu/checkstyle/checks/coding/InputJsr305AnnotationsCheckWithReturnValue.java @@ -0,0 +1,115 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2019 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.github.sevntu.checkstyle.checks.coding; + +import java.io.Serializable; + +import javax.annotation.CheckForNull; +import javax.annotation.CheckReturnValue; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; +import javax.annotation.ParametersAreNullableByDefault; + +public class InputJsr305AnnotationsCheckWithReturnValue + implements Comparable, Serializable, Runnable { + + private static final long serialVersionUID = 1L; + + @Nonnull // ok + Object returnNonnull() { + return new Object(); + } + + @CheckForNull // ok + Object returnCheckForNull() { + return null; + } + + @Nullable // violation + Object returnNullable() { + return null; + } + + @Nonnull // violation + @CheckForNull + Object returnNonnullCheckForNull() { + return new Object(); + } + + @CheckReturnValue // ok + @CheckForNull + Object returnCheckReturnValueCheckForNull() { + return new Object(); + } + + @CheckReturnValue // ok + @Nonnull + Object returnCheckReturnValueNonnull() { + return new Object(); + } + + @Override // violation + @Nonnull + public boolean equals(final Object obj) { + return super.equals(obj); + } + + @Override // violation + @CheckForNull + public int hashCode() { + return super.hashCode(); + } + + @Override // ok + public void run() { + hashCode(); + } + + @Override // ok + @Nonnull + public String toString() { + return super.toString(); + } + + @ParametersAreNonnullByDefault // violation + @ParametersAreNullableByDefault + @Nonnull + public String concat(final String string1, final String string2) { // violation + return string1 + string2; + } + + @Override // violation + @CheckReturnValue + public int compareTo(@Nullable final InputJsr305AnnotationsCheckWithReturnValue obj) { + return 0; + } + + @CheckReturnValue // violation + public void voidNoCheckReturnValue() { + hashCode(); + } + + @Nonnull // violation + public void voidNoNonnull() { + hashCode(); + } + +} diff --git a/sevntu-checkstyle-maven-plugin/src/main/resources/checkstyle_packages.xml b/sevntu-checkstyle-maven-plugin/src/main/resources/checkstyle_packages.xml index 649dabc258..86130ae36a 100644 --- a/sevntu-checkstyle-maven-plugin/src/main/resources/checkstyle_packages.xml +++ b/sevntu-checkstyle-maven-plugin/src/main/resources/checkstyle_packages.xml @@ -34,4 +34,4 @@ - \ No newline at end of file + diff --git a/sevntu-checkstyle-sonar-plugin/src/main/resources/com/github/sevntu/checkstyle/sonar/checkstyle-extensions.xml b/sevntu-checkstyle-sonar-plugin/src/main/resources/com/github/sevntu/checkstyle/sonar/checkstyle-extensions.xml index 083323a6c7..66d2dce25b 100644 --- a/sevntu-checkstyle-sonar-plugin/src/main/resources/com/github/sevntu/checkstyle/sonar/checkstyle-extensions.xml +++ b/sevntu-checkstyle-sonar-plugin/src/main/resources/com/github/sevntu/checkstyle/sonar/checkstyle-extensions.xml @@ -921,6 +921,31 @@ Checker/TreeWalker/com.github.sevntu.checkstyle.checks.coding.RequireFailForTryCatchInJunitCheck + + com.github.sevntu.checkstyle.checks.coding.Jsr305AnnotationsCheck + Jsr305AnnotationsCheck + + Checks method parameters and return values for the presence of @Nonnull, @Nullable, or @CheckForNull annotations. + Checker/TreeWalker/com.github.sevntu.checkstyle.checks.coding.Jsr305AnnotationsCheck + + + + Sets the parent package for all classes that will be checked. + + + + Packages excluded from checking. This can be useful if under the parent package set with "packages" there are subpackages which should not be checked. + + + false + In overridden methods annotating return values "@CheckForNull" is flagged as a violation. When setting this property to true, this will be ignored (useful for upgrading). + + + false + In overridden methods annotating parameters "@Nonnull" is flagged as a violation. When setting this property to true, this will be ignored (useful for upgrading). + + + com.github.sevntu.checkstyle.checks.design.CheckstyleTestMakeupCheck Custom check to ensure Checkstyle tests are designed correctly.