diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationLocationCheck.java b/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationLocationCheck.java index e51a6529b917..d71d0bbc6670 100644 --- a/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationLocationCheck.java +++ b/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationLocationCheck.java @@ -24,6 +24,7 @@ import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CommonUtil; +import com.puppycrawl.tools.checkstyle.utils.TokenUtil; /** * Check location of annotation on language elements. @@ -302,7 +303,10 @@ else if (annotation.getColumnNo() != correctIndentation && !hasNodeBefore(annota * @return true if the annotation has parameters. */ private static boolean isParameterized(DetailAST annotation) { - return annotation.findFirstToken(TokenTypes.EXPR) != null; + return TokenUtil.findFirstTokenByPredicate(annotation, ast -> { + return ast.getType() == TokenTypes.EXPR + || ast.getType() == TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR; + }).isPresent(); } /** diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationLocationCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationLocationCheckTest.java index 116a5e185979..b548a4be56a2 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationLocationCheckTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationLocationCheckTest.java @@ -59,6 +59,7 @@ public void testIncorrect() throws Exception { final String[] expected = { "6: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnn"), "11: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation1"), + "14: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation1"), "17: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation1", 8, 4), "25: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation1", 8, 4), "29: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation1"), @@ -68,13 +69,17 @@ public void testIncorrect() throws Exception { "37: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation3", 6, 4), "38: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation4", 10, 4), "41: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation1"), + "45: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation1"), "48: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation1", 12, 8), + "56: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation1"), "61: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation2", 12, 8), "65: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation2", 12, 8), "70: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation2", 7, 4), "73: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation1"), + "75: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation1"), "85: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation2", 11, 8), "88: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation2", 10, 8), + "91: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation1"), "98: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation2", 0, 3), }; verify(checkConfig, getPath("InputAnnotationLocationIncorrect.java"), expected); @@ -88,6 +93,7 @@ public void testIncorrectAllTokens() throws Exception { final String[] expected = { "6: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnn"), "11: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation1"), + "14: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation1"), "17: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation1", 8, 4), "25: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation1", 8, 4), "29: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation1"), @@ -97,13 +103,17 @@ public void testIncorrectAllTokens() throws Exception { "37: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation3", 6, 4), "38: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation4", 10, 4), "41: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation1"), + "45: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation1"), "48: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation1", 12, 8), + "56: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation1"), "61: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation2", 12, 8), "65: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation2", 12, 8), "70: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation2", 7, 4), "73: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation1"), + "75: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation1"), "85: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation2", 11, 8), "88: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation2", 10, 8), + "91: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation1"), "98: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION, "MyAnnotation2", 0, 3), "100: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "MyAnnotation2"), }; @@ -193,4 +203,45 @@ public void testAnnotationInForEachLoopParameterAndVariableDef() throws Exceptio verify(checkConfig, getPath("InputAnnotationLocationDeprecatedAndCustom.java"), expected); } + @Test + public void testAnnotationMultiple() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(AnnotationLocationCheck.class); + checkConfig.addAttribute("allowSamelineMultipleAnnotations", "true"); + checkConfig.addAttribute("allowSamelineSingleParameterlessAnnotation", "false"); + checkConfig.addAttribute("allowSamelineParameterizedAnnotation", "false"); + final String[] expected = CommonUtil.EMPTY_STRING_ARRAY; + verify(checkConfig, getPath("InputAnnotationLocationMultiple.java"), expected); + } + + @Test + public void testAnnotationParameterized() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(AnnotationLocationCheck.class); + checkConfig.addAttribute("allowSamelineMultipleAnnotations", "false"); + checkConfig.addAttribute("allowSamelineSingleParameterlessAnnotation", "false"); + checkConfig.addAttribute("allowSamelineParameterizedAnnotation", "true"); + final String[] expected = { + "15: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "Annotation"), + "17: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "Annotation"), + "23: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "Annotation"), + "25: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "Annotation"), + }; + verify(checkConfig, getPath("InputAnnotationLocationParameterized.java"), expected); + } + + @Test + public void testAnnotationSingleParameterless() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(AnnotationLocationCheck.class); + checkConfig.addAttribute("allowSamelineMultipleAnnotations", "false"); + checkConfig.addAttribute("allowSamelineSingleParameterlessAnnotation", "true"); + checkConfig.addAttribute("allowSamelineParameterizedAnnotation", "false"); + final String[] expected = { + "17: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "Annotation"), + "19: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "Annotation"), + "21: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "Annotation"), + "23: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "Annotation"), + "25: " + getCheckMessage(MSG_KEY_ANNOTATION_LOCATION_ALONE, "Annotation"), + }; + verify(checkConfig, getPath("InputAnnotationLocationSingleParameterless.java"), expected); + } + } diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/InputAnnotationLocationIncorrect.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/InputAnnotationLocationIncorrect.java index ac764290f4f4..3000b009d85b 100644 --- a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/InputAnnotationLocationIncorrect.java +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/InputAnnotationLocationIncorrect.java @@ -11,7 +11,7 @@ class InputAnnotationLocationIncorrect @MyAnnotation2 @MyAnnotation1(value = "") public int a; - @MyAnnotation1(value = "") public int b; + @MyAnnotation1(value = "") public int b; //warn @MyAnnotation2 @MyAnnotation1 //warn @@ -42,7 +42,7 @@ class InnerClass (value = "") public int a; - @MyAnnotation1(value = "") public int b; + @MyAnnotation1(value = "") public int b; //warn @MyAnnotation2 @MyAnnotation1 //warn @@ -53,7 +53,7 @@ class InnerClass public int d; @MyAnnotation2 - @MyAnnotation1(value = "") public InnerClass() + @MyAnnotation1(value = "") public InnerClass() //warn { // comment } @@ -72,7 +72,7 @@ void foo2() {} { @MyAnnotation2 @MyAnnotation1(value = "") public int a; - @MyAnnotation1(value = "") public int b; + @MyAnnotation1(value = "") public int b; //warn @MyAnnotation2 @MyAnnotation1(value = "") @@ -88,7 +88,7 @@ void foo2() {} @MyAnnotation2 //warn void foo2() {} - @MyAnnotation1(value = "") void foo42() {} + @MyAnnotation1(value = "") void foo42() {} //warn }; } diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/InputAnnotationLocationMultiple.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/InputAnnotationLocationMultiple.java new file mode 100644 index 000000000000..48bca254beb1 --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/InputAnnotationLocationMultiple.java @@ -0,0 +1,36 @@ +package com.puppycrawl.tools.checkstyle.checks.annotation.annotationlocation; + +import java.lang.annotation.Repeatable; + +/** + * This test-input is intended to be checked using following configuration: + * + * allowSamelineSingleParameterlessAnnotation = false + * allowSamelineParameterizedAnnotation = false + * allowSamelineMultipleAnnotations = true + */ + +class InputAnnotationLocationMultiple { + + @Annotation void singleParameterless() {} + + @Annotation @Annotation void multipleParameterless() {} + + @Annotation("") void parameterized() {} + + @Annotation(value = "") void namedParameterized() {} + + @Annotation @Annotation("") @Annotation(value = "") void multiple() {} + + @Annotation("") @Annotation(value = "") void multipleParametrized() {} + + @Repeatable(Annotations.class) + @interface Annotation { + String value() default ""; + } + + @interface Annotations { + Annotation[] value(); + } + +} diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/InputAnnotationLocationParameterized.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/InputAnnotationLocationParameterized.java new file mode 100644 index 000000000000..87d178ee0296 --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/InputAnnotationLocationParameterized.java @@ -0,0 +1,36 @@ +package com.puppycrawl.tools.checkstyle.checks.annotation.annotationlocation; + +import java.lang.annotation.Repeatable; + +/** + * This test-input is intended to be checked using following configuration: + * + * allowSamelineSingleParameterlessAnnotation = false + * allowSamelineParameterizedAnnotation = true + * allowSamelineMultipleAnnotations = false + */ + +class InputAnnotationLocationParameterized { + + @Annotation void singleParameterless() {} //warn + + @Annotation @Annotation void multipleParameterless() {} //warn + + @Annotation("") void parameterized() {} + + @Annotation(value = "") void namedParameterized() {} + + @Annotation @Annotation("") @Annotation(value = "") void multiple() {} //warn + + @Annotation("") @Annotation(value = "") void multipleParametrized() {} //warn + + @Repeatable(Annotations.class) + @interface Annotation { + String value() default ""; + } + + @interface Annotations { + Annotation[] value(); + } + +} diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/InputAnnotationLocationSingleParameterless.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/InputAnnotationLocationSingleParameterless.java new file mode 100644 index 000000000000..3cf1c4484431 --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/InputAnnotationLocationSingleParameterless.java @@ -0,0 +1,36 @@ +package com.puppycrawl.tools.checkstyle.checks.annotation.annotationlocation; + +import java.lang.annotation.Repeatable; + +/** + * This test-input is intended to be checked using following configuration: + * + * allowSamelineSingleParameterlessAnnotation = + * allowSamelineParameterizedAnnotation = + * allowSamelineMultipleAnnotations = + */ + +class InputAnnotationLocationSingleParameterless { + + @Annotation void singleParameterless() {} + + @Annotation @Annotation void multipleParameterless() {} //warn + + @Annotation("") void parameterized() {} //warn + + @Annotation(value = "") void namedParameterized() {} //warn + + @Annotation @Annotation("") @Annotation(value = "") void multiple() {} //warn + + @Annotation("") @Annotation(value = "") void multipleParametrized() {} //warn + + @Repeatable(Annotations.class) + @interface Annotation { + String value() default ""; + } + + @interface Annotations { + Annotation[] value(); + } + +}