Skip to content

Commit 2210ee7

Browse files
committed
Issue #3730: Add type annotation tokens to AnnotationLocation check
1 parent 8652da7 commit 2210ee7

File tree

11 files changed

+422
-2
lines changed

11 files changed

+422
-2
lines changed

src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationLocationCheck.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,12 @@ public int[] getAcceptableTokens() {
169169
TokenTypes.ANNOTATION_FIELD_DEF,
170170
TokenTypes.RECORD_DEF,
171171
TokenTypes.COMPACT_CTOR_DEF,
172+
TokenTypes.TYPECAST,
173+
TokenTypes.TYPE_ARGUMENT,
174+
TokenTypes.DOT,
175+
TokenTypes.LITERAL_NEW,
176+
TokenTypes.LITERAL_THROWS,
177+
TokenTypes.IMPLEMENTS_CLAUSE,
172178
};
173179
}
174180

src/site/xdoc/checks/annotation/annotationlocation.xml

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,18 @@ public String getNameIfPresent() { ... }
114114
RECORD_DEF</a>
115115
, <a href="../../apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#COMPACT_CTOR_DEF">
116116
COMPACT_CTOR_DEF</a>
117+
, <a href="../../apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#TYPECAST">
118+
TYPECAST</a>
119+
, <a href="../../apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#TYPE_ARGUMENT">
120+
TYPE_ARGUMENT</a>
121+
, <a href="../../apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#DOT">
122+
DOT</a>
123+
, <a href="../../apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_NEW">
124+
LITERAL_NEW</a>
125+
, <a href="../../apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_THROWS">
126+
LITERAL_THROWS</a>
127+
, <a href="../../apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#IMPLEMENTS_CLAUSE">
128+
IMPLEMENTS_CLAUSE</a>
117129
.
118130
</td>
119131
<td>
@@ -278,6 +290,133 @@ class Example4 {
278290
// violation above, 'Annotation 'SuppressWarnings' should be alone on line.'
279291
@NotNull @Mock DataLoader loader2;
280292
}
293+
</code></pre></div><hr class="example-separator"/>
294+
<p id="Example5-config">
295+
To configure the check to validate annotations on type arguments:
296+
</p>
297+
<div class="wrapper"><pre class="prettyprint"><code class="language-xml">
298+
&lt;module name="Checker"&gt;
299+
&lt;module name="TreeWalker"&gt;
300+
&lt;module name="AnnotationLocation"&gt;
301+
&lt;property name="tokens" value="TYPE_ARGUMENT"/&gt;
302+
&lt;/module&gt;
303+
&lt;/module&gt;
304+
&lt;/module&gt;
305+
</code></pre></div>
306+
<p id="Example5-code">Example:</p>
307+
<div class="wrapper"><pre class="prettyprint"><code class="language-java">
308+
class Example5 {
309+
List&lt;@TypeArgAnnotation1 String&gt; names; // ok
310+
List&lt;@TypeArgAnnotation1 @TypeArgAnnotation2 String&gt; data;
311+
// violation above, 'Annotation 'TypeArgAnnotation2' should be alone on line.'
312+
Map&lt;@TypeArgAnnotation1 String, @TypeArgAnnotation1 Integer&gt; map; // ok
313+
}
314+
</code></pre></div><hr class="example-separator"/>
315+
<p id="Example6-config">
316+
To configure the check to validate annotations on typecasts:
317+
</p>
318+
<div class="wrapper"><pre class="prettyprint"><code class="language-xml">
319+
&lt;module name="Checker"&gt;
320+
&lt;module name="TreeWalker"&gt;
321+
&lt;module name="AnnotationLocation"&gt;
322+
&lt;property name="tokens" value="TYPECAST"/&gt;
323+
&lt;/module&gt;
324+
&lt;/module&gt;
325+
&lt;/module&gt;
326+
</code></pre></div>
327+
<p id="Example6-code">Example:</p>
328+
<div class="wrapper"><pre class="prettyprint"><code class="language-java">
329+
class Example6 {
330+
void method(Object obj) {
331+
String s1 = (@TypeCastAnnotation1 String) obj; // ok
332+
String s2 = (@TypeCastAnnotation1 @TypeCastAnnotation2 String) obj;
333+
// violation above, 'Annotation 'TypeCastAnnotation2' should be alone on line.'
334+
}
335+
}
336+
</code></pre></div><hr class="example-separator"/>
337+
<p id="Example7-config">
338+
To configure the check to validate annotations on constructor invocations:
339+
</p>
340+
<div class="wrapper"><pre class="prettyprint"><code class="language-xml">
341+
&lt;module name="Checker"&gt;
342+
&lt;module name="TreeWalker"&gt;
343+
&lt;module name="AnnotationLocation"&gt;
344+
&lt;property name="tokens" value="LITERAL_NEW"/&gt;
345+
&lt;/module&gt;
346+
&lt;/module&gt;
347+
&lt;/module&gt;
348+
</code></pre></div>
349+
<p id="Example7-code">Example:</p>
350+
<div class="wrapper"><pre class="prettyprint"><code class="language-java">
351+
class Example7 {
352+
void method() {
353+
String[] arr1 = new @NewObjectAnnotation1 String[10]; // ok
354+
String[] arr2 = new @NewObjectAnnotation1 @NewObjectAnnotation2 String[10];
355+
// violation above, 'Annotation 'NewObjectAnnotation2' should be alone on line.'
356+
Object obj = new @NewObjectAnnotation1 Object(); // ok
357+
}
358+
}
359+
</code></pre></div><hr class="example-separator"/>
360+
<p id="Example8-config">
361+
To configure the check to validate annotations on exception types in throws clause:
362+
</p>
363+
<div class="wrapper"><pre class="prettyprint"><code class="language-xml">
364+
&lt;module name="Checker"&gt;
365+
&lt;module name="TreeWalker"&gt;
366+
&lt;module name="AnnotationLocation"&gt;
367+
&lt;property name="tokens" value="LITERAL_THROWS"/&gt;
368+
&lt;/module&gt;
369+
&lt;/module&gt;
370+
&lt;/module&gt;
371+
</code></pre></div>
372+
<p id="Example8-code">Example:</p>
373+
<div class="wrapper"><pre class="prettyprint"><code class="language-java">
374+
class Example8 {
375+
void method1() throws @ThrowsAnnotation1 IOException { } // ok
376+
void method2() throws @ThrowsAnnotation1 @ThrowsAnnotation2 IOException { }
377+
// violation above, 'Annotation 'ThrowsAnnotation2' should be alone on line.'
378+
}
379+
</code></pre></div><hr class="example-separator"/>
380+
<p id="Example9-config">
381+
To configure the check to validate annotations on interface types in implements clause:
382+
</p>
383+
<div class="wrapper"><pre class="prettyprint"><code class="language-xml">
384+
&lt;module name="Checker"&gt;
385+
&lt;module name="TreeWalker"&gt;
386+
&lt;module name="AnnotationLocation"&gt;
387+
&lt;property name="tokens" value="IMPLEMENTS_CLAUSE"/&gt;
388+
&lt;/module&gt;
389+
&lt;/module&gt;
390+
&lt;/module&gt;
391+
</code></pre></div>
392+
<p id="Example9-code">Example:</p>
393+
<div class="wrapper"><pre class="prettyprint"><code class="language-java">
394+
class Example9 implements @ImplementsAnnotation1 Serializable { } // ok
395+
class Example9a implements @ImplementsAnnotation1 @ImplementsAnnotation2
396+
Serializable { }
397+
// violation above, 'Annotation 'ImplementsAnnotation2' should be alone on line.'
398+
</code></pre></div><hr class="example-separator"/>
399+
<p id="Example10-config">
400+
To configure the check to validate annotations on qualified types:
401+
</p>
402+
<div class="wrapper"><pre class="prettyprint"><code class="language-xml">
403+
&lt;module name="Checker"&gt;
404+
&lt;module name="TreeWalker"&gt;
405+
&lt;module name="AnnotationLocation"&gt;
406+
&lt;property name="tokens" value="DOT"/&gt;
407+
&lt;/module&gt;
408+
&lt;/module&gt;
409+
&lt;/module&gt;
410+
</code></pre></div>
411+
<p id="Example10-code">Example:</p>
412+
<div class="wrapper"><pre class="prettyprint"><code class="language-java">
413+
class Example10 {
414+
void method() {
415+
java.lang.@DotAnnotation1 String s; // ok
416+
java.lang.@DotAnnotation1 @DotAnnotation2 String s2;
417+
// violation above, 'Annotation 'DotAnnotation2' should be alone on line.'
418+
}
419+
}
281420
</code></pre></div>
282421
</subsection>
283422

src/site/xdoc/checks/annotation/annotationlocation.xml.template

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,90 @@
9191
<param name="path"
9292
value="resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/Example4.java"/>
9393
<param name="type" value="code"/>
94+
</macro><hr class="example-separator"/>
95+
<p id="Example5-config">
96+
To configure the check to validate annotations on type arguments:
97+
</p>
98+
<macro name="example">
99+
<param name="path"
100+
value="resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/Example5.java"/>
101+
<param name="type" value="config"/>
102+
</macro>
103+
<p id="Example5-code">Example:</p>
104+
<macro name="example">
105+
<param name="path"
106+
value="resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/Example5.java"/>
107+
<param name="type" value="code"/>
108+
</macro><hr class="example-separator"/>
109+
<p id="Example6-config">
110+
To configure the check to validate annotations on typecasts:
111+
</p>
112+
<macro name="example">
113+
<param name="path"
114+
value="resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/Example6.java"/>
115+
<param name="type" value="config"/>
116+
</macro>
117+
<p id="Example6-code">Example:</p>
118+
<macro name="example">
119+
<param name="path"
120+
value="resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/Example6.java"/>
121+
<param name="type" value="code"/>
122+
</macro><hr class="example-separator"/>
123+
<p id="Example7-config">
124+
To configure the check to validate annotations on constructor invocations:
125+
</p>
126+
<macro name="example">
127+
<param name="path"
128+
value="resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/Example7.java"/>
129+
<param name="type" value="config"/>
130+
</macro>
131+
<p id="Example7-code">Example:</p>
132+
<macro name="example">
133+
<param name="path"
134+
value="resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/Example7.java"/>
135+
<param name="type" value="code"/>
136+
</macro><hr class="example-separator"/>
137+
<p id="Example8-config">
138+
To configure the check to validate annotations on exception types in throws clause:
139+
</p>
140+
<macro name="example">
141+
<param name="path"
142+
value="resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/Example8.java"/>
143+
<param name="type" value="config"/>
144+
</macro>
145+
<p id="Example8-code">Example:</p>
146+
<macro name="example">
147+
<param name="path"
148+
value="resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/Example8.java"/>
149+
<param name="type" value="code"/>
150+
</macro><hr class="example-separator"/>
151+
<p id="Example9-config">
152+
To configure the check to validate annotations on interface types in implements clause:
153+
</p>
154+
<macro name="example">
155+
<param name="path"
156+
value="resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/Example9.java"/>
157+
<param name="type" value="config"/>
158+
</macro>
159+
<p id="Example9-code">Example:</p>
160+
<macro name="example">
161+
<param name="path"
162+
value="resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/Example9.java"/>
163+
<param name="type" value="code"/>
164+
</macro><hr class="example-separator"/>
165+
<p id="Example10-config">
166+
To configure the check to validate annotations on qualified types:
167+
</p>
168+
<macro name="example">
169+
<param name="path"
170+
value="resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/Example10.java"/>
171+
<param name="type" value="config"/>
172+
</macro>
173+
<p id="Example10-code">Example:</p>
174+
<macro name="example">
175+
<param name="path"
176+
value="resources/com/puppycrawl/tools/checkstyle/checks/annotation/annotationlocation/Example10.java"/>
177+
<param name="type" value="code"/>
94178
</macro>
95179
</subsection>
96180

src/test/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationLocationCheckTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,12 @@ public void testGetAcceptableTokens() {
150150
TokenTypes.ANNOTATION_FIELD_DEF,
151151
TokenTypes.RECORD_DEF,
152152
TokenTypes.COMPACT_CTOR_DEF,
153+
TokenTypes.TYPECAST,
154+
TokenTypes.TYPE_ARGUMENT,
155+
TokenTypes.DOT,
156+
TokenTypes.LITERAL_NEW,
157+
TokenTypes.LITERAL_THROWS,
158+
TokenTypes.IMPLEMENTS_CLAUSE,
153159
};
154160
assertWithMessage("Default acceptable tokens are invalid")
155161
.that(actual)

src/test/java/com/puppycrawl/tools/checkstyle/internal/AllChecksTest.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,10 @@ public class AllChecksTest extends AbstractModuleTestSupport {
151151
CHECKSTYLE_TOKENS_IN_CONFIG_TO_IGNORE.put("AnnotationLocation",
152152
Stream.of("CLASS_DEF", "CTOR_DEF", "ENUM_DEF", "INTERFACE_DEF",
153153
"METHOD_DEF", "VARIABLE_DEF",
154-
"RECORD_DEF", "COMPACT_CTOR_DEF")
154+
"RECORD_DEF", "COMPACT_CTOR_DEF",
155+
// Type annotation tokens - opt-in only, not used by default
156+
"TYPECAST", "TYPE_ARGUMENT", "DOT", "LITERAL_NEW",
157+
"LITERAL_THROWS", "IMPLEMENTS_CLAUSE")
155158
.collect(Collectors.toUnmodifiableSet()));
156159
CHECKSTYLE_TOKENS_IN_CONFIG_TO_IGNORE.put("NoLineWrap", Stream.of(
157160
// method/constructor declaration could be long due to "parameters/exceptions", it
@@ -188,7 +191,10 @@ public class AllChecksTest extends AbstractModuleTestSupport {
188191
GOOGLE_TOKENS_IN_CONFIG_TO_IGNORE.put("AnnotationLocation", Stream.of(
189192
// state of the configuration when test was made until reason found in
190193
// https://github.com/checkstyle/checkstyle/issues/3730
191-
"ANNOTATION_DEF", "ANNOTATION_FIELD_DEF", "ENUM_CONSTANT_DEF", "PACKAGE_DEF")
194+
"ANNOTATION_DEF", "ANNOTATION_FIELD_DEF", "ENUM_CONSTANT_DEF", "PACKAGE_DEF",
195+
// Type annotation tokens - opt-in only, not used by default
196+
"TYPECAST", "TYPE_ARGUMENT", "DOT", "LITERAL_NEW",
197+
"LITERAL_THROWS", "IMPLEMENTS_CLAUSE")
192198
.collect(Collectors.toUnmodifiableSet()));
193199
GOOGLE_TOKENS_IN_CONFIG_TO_IGNORE.put("AbbreviationAsWordInName", Stream.of(
194200
// enum values should be uppercase
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*xml
2+
<module name="Checker">
3+
<module name="TreeWalker">
4+
<module name="AnnotationLocation">
5+
<property name="tokens" value="DOT"/>
6+
</module>
7+
</module>
8+
</module>
9+
*/
10+
11+
package com.puppycrawl.tools.checkstyle.checks.annotation.annotationlocation;
12+
13+
import java.lang.annotation.ElementType;
14+
import java.lang.annotation.Target;
15+
16+
@Target(ElementType.TYPE_USE)
17+
@interface DotAnnotation1 {}
18+
19+
@Target(ElementType.TYPE_USE)
20+
@interface DotAnnotation2 {}
21+
22+
// xdoc section -- start
23+
class Example10 {
24+
void method() {
25+
java.lang.@DotAnnotation1 String s; // ok
26+
java.lang.@DotAnnotation1 @DotAnnotation2 String s2;
27+
// violation above, 'Annotation 'DotAnnotation2' should be alone on line.'
28+
}
29+
}
30+
// xdoc section -- end
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*xml
2+
<module name="Checker">
3+
<module name="TreeWalker">
4+
<module name="AnnotationLocation">
5+
<property name="tokens" value="TYPE_ARGUMENT"/>
6+
</module>
7+
</module>
8+
</module>
9+
*/
10+
11+
package com.puppycrawl.tools.checkstyle.checks.annotation.annotationlocation;
12+
13+
import java.lang.annotation.ElementType;
14+
import java.lang.annotation.Target;
15+
import java.util.List;
16+
import java.util.Map;
17+
18+
@Target(ElementType.TYPE_USE)
19+
@interface TypeArgAnnotation1 {}
20+
21+
@Target(ElementType.TYPE_USE)
22+
@interface TypeArgAnnotation2 {}
23+
24+
// xdoc section -- start
25+
class Example5 {
26+
List<@TypeArgAnnotation1 String> names; // ok
27+
List<@TypeArgAnnotation1 @TypeArgAnnotation2 String> data;
28+
// violation above, 'Annotation 'TypeArgAnnotation2' should be alone on line.'
29+
Map<@TypeArgAnnotation1 String, @TypeArgAnnotation1 Integer> map; // ok
30+
}
31+
// xdoc section -- end
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*xml
2+
<module name="Checker">
3+
<module name="TreeWalker">
4+
<module name="AnnotationLocation">
5+
<property name="tokens" value="TYPECAST"/>
6+
</module>
7+
</module>
8+
</module>
9+
*/
10+
11+
package com.puppycrawl.tools.checkstyle.checks.annotation.annotationlocation;
12+
13+
import java.lang.annotation.ElementType;
14+
import java.lang.annotation.Target;
15+
16+
@Target(ElementType.TYPE_USE)
17+
@interface TypeCastAnnotation1 {}
18+
19+
@Target(ElementType.TYPE_USE)
20+
@interface TypeCastAnnotation2 {}
21+
22+
// xdoc section -- start
23+
class Example6 {
24+
void method(Object obj) {
25+
String s1 = (@TypeCastAnnotation1 String) obj; // ok
26+
String s2 = (@TypeCastAnnotation1 @TypeCastAnnotation2 String) obj;
27+
// violation above, 'Annotation 'TypeCastAnnotation2' should be alone on line.'
28+
}
29+
}
30+
// xdoc section -- end

0 commit comments

Comments
 (0)