Skip to content

Commit 89b4dcd

Browse files
esilkensenromani
authored andcommitted
Issue #3238: Java 8 Grammar: annotations on arrays and varargs
1 parent 252cd89 commit 89b4dcd

9 files changed

Lines changed: 514 additions & 8 deletions

File tree

src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceAfterCheck.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,7 @@ public void setAllowLineBreaks(boolean allowLineBreaks) {
170170
public void visitToken(DetailAST ast) {
171171
final DetailAST whitespaceFollowedAst = getWhitespaceFollowedNode(ast);
172172

173-
if (whitespaceFollowedAst.getNextSibling() == null
174-
|| whitespaceFollowedAst.getNextSibling().getType() != TokenTypes.ANNOTATIONS) {
173+
if (shouldCheckWhitespaceAfter(whitespaceFollowedAst)) {
175174
final int whitespaceColumnNo = getPositionAfter(whitespaceFollowedAst);
176175
final int whitespaceLineNo = whitespaceFollowedAst.getLineNo();
177176

@@ -206,6 +205,27 @@ private static DetailAST getWhitespaceFollowedNode(DetailAST ast) {
206205
return whitespaceFollowedAst;
207206
}
208207

208+
/**
209+
* Returns whether whitespace after a visited node should be checked. For example, whitespace
210+
* is not allowed between a type and an array declarator (returns true), except when there is
211+
* an annotation in between the type and array declarator (returns false).
212+
* @param ast the visited node
213+
* @return true if whitespace after ast should be checked
214+
*/
215+
private static boolean shouldCheckWhitespaceAfter(DetailAST ast) {
216+
boolean checkWhitespace = true;
217+
final DetailAST sibling = ast.getNextSibling();
218+
if (sibling != null) {
219+
if (sibling.getType() == TokenTypes.ANNOTATIONS) {
220+
checkWhitespace = false;
221+
}
222+
else if (sibling.getType() == TokenTypes.ARRAY_DECLARATOR) {
223+
checkWhitespace = sibling.getFirstChild().getType() != TokenTypes.ANNOTATIONS;
224+
}
225+
}
226+
return checkWhitespace;
227+
}
228+
209229
/**
210230
* Gets position after token (place of possible redundant whitespace).
211231
* @param ast Node representing token.

src/main/resources/com/puppycrawl/tools/checkstyle/grammar/java.g

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,14 @@ typeSpec[boolean addImagNode]
257257
| builtInTypeSpec[addImagNode]
258258
;
259259
260+
// A type specification for a variable length parameter is a type name with
261+
// possible brackets afterwards that can end with annotations.
262+
variableLengthParameterTypeSpec
263+
: (classOrInterfaceType[false] | builtInType)
264+
({LA(1) == AT}? annotations | )
265+
(lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK ({LA(1) == AT}? annotations | ))*
266+
;
267+
260268
// A class type specification is a class type with either:
261269
// - possible brackets afterwards
262270
// (which would make it an array type).
@@ -387,8 +395,8 @@ builtInTypeSpec[boolean addImagNode]
387395
// A type name. which is either a (possibly qualified and parameterized)
388396
// class name or a primitive (builtin) type
389397
type
390-
: classOrInterfaceType[false]
391-
| builtInType
398+
: ({LA(1) == AT}? annotations | )
399+
(classOrInterfaceType[false] | builtInType)
392400
;
393401

394402
/** A declaration is the creation of a reference or primitive-type variable
@@ -893,9 +901,11 @@ variableDeclarator![AST mods, AST t]
893901
{#variableDeclarator = #(#[VARIABLE_DEF,"VARIABLE_DEF"], mods, #(#[TYPE,"TYPE"],d), id, v);}
894902
;
895903
896-
declaratorBrackets[AST typ]
897-
: {#declaratorBrackets=typ;}
898-
(lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK)*
904+
declaratorBrackets![AST typ]
905+
: ({LA(1) == AT}? an:annotations | ) lb:LBRACK {#lb.setType(ARRAY_DECLARATOR);} rb:RBRACK
906+
db:declaratorBrackets[#(lb, typ, an, rb)]
907+
{#declaratorBrackets = #db;}
908+
| {#declaratorBrackets = typ;}
899909
;
900910
901911
varInitializer
@@ -969,7 +979,7 @@ parameterDeclarationList
969979
;
970980
971981
variableLengthParameterDeclaration!
972-
: pm:parameterModifier t:typeSpec[false] td:ELLIPSIS IDENT
982+
: pm:parameterModifier t:variableLengthParameterTypeSpec td:ELLIPSIS IDENT
973983
pd:declaratorBrackets[#t]
974984
{#variableLengthParameterDeclaration = #(#[PARAMETER_DEF,"PARAMETER_DEF"],
975985
pm, #([TYPE,"TYPE"],pd), td, IDENT);}
@@ -1592,6 +1602,7 @@ newArrayDeclarator
15921602
warnWhenFollowAmbig = false;
15931603
}
15941604
:
1605+
({LA(1) == AT}? annotations | )
15951606
lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);}
15961607
(expression)?
15971608
RBRACK

src/test/java/com/puppycrawl/tools/checkstyle/grammar/AstRegressionTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ public void testJava8ClassAstTree1() throws Exception {
6868
getPath("InputRegressionJava8Class1.java"));
6969
}
7070

71+
@Test
72+
public void testJava8ClassAstTree2() throws Exception {
73+
verifyAst(getPath("InputRegressionJava8Class2Ast.txt"),
74+
getPath("InputRegressionJava8Class2.java"));
75+
}
76+
7177
@Test
7278
public void testInputSemicolonBetweenImports() throws Exception {
7379
verifyAst(getPath("InputSemicolonBetweenImportsAst.txt"),

src/test/java/com/puppycrawl/tools/checkstyle/grammar/java8/AnnotationTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,13 @@ public void testAnnotationInTypeParameters()
132132
verify(checkConfig, getPath("InputAnnotations11.java"), expected);
133133
}
134134

135+
@Test
136+
public void testAnnotationOnVarargs()
137+
throws Exception {
138+
final DefaultConfiguration checkConfig =
139+
createModuleConfig(MemberNameCheck.class);
140+
final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
141+
verify(checkConfig, getPath("InputAnnotations12.java"), expected);
142+
}
143+
135144
}

src/test/resources/com/puppycrawl/tools/checkstyle/checks/whitespace/nowhitespaceafter/InputNoWhitespaceAfterArrayDeclarations3.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ public void testWithAnnotationInMiddle1(final char @AnnotationAfterTest [] a) {}
99
public void testWithAnnotationInMiddle2(final char@AnnotationAfterTest [] a) {}//Correct
1010
public void testWithAnnotationInMiddle3(final char @AnnotationAfterTest[] a) {}//Correct
1111
public void testWithAnnotationInMiddle4(final char@AnnotationAfterTest[]a) {}//Correct
12+
public @AnnotationAfterTest String @AnnotationAfterTest [] testWithAnnotationInMiddle5() {
13+
return new @AnnotationAfterTest String @AnnotationAfterTest [3];//Correct
14+
}
1215

1316
@Target(ElementType.TYPE_USE)
1417
@interface AnnotationAfterTest {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//start line index in expected file is 2
2+
package com.puppycrawl.tools.checkstyle.grammar;
3+
4+
import java.lang.annotation.ElementType;
5+
import java.lang.annotation.Retention;
6+
import java.lang.annotation.RetentionPolicy;
7+
import java.lang.annotation.Target;
8+
import java.util.ArrayList;
9+
import java.util.Collections;
10+
import java.util.Comparator;
11+
import java.util.Map;
12+
import java.util.List;
13+
import java.util.function.IntBinaryOperator;
14+
import java.util.function.Predicate;
15+
import java.util.function.Supplier;
16+
17+
public class InputRegressionJava8Class2 {
18+
static class Inner1 { static class Inner2<V> { public void m() {} } }
19+
static class Inner3<T> { public void m() {} }
20+
21+
public void m1(@MyAnnotation String @MyAnnotation ... vararg) {}
22+
public String m2() @MyAnnotation [] @MyAnnotation [] { return null; }
23+
24+
public void instructions() {
25+
// annotations
26+
Map.@MyAnnotation Entry e;
27+
String str = (@MyAnnotation String) "";
28+
(new Inner3()).<@MyAnnotation String>m();
29+
Object arr = new @MyAnnotation String @MyAnnotation [3];
30+
for (String a @MyAnnotation [] : m2()) {}
31+
Object arr2 = new @MyAnnotation int[3];
32+
}
33+
}
34+
35+
@Retention(RetentionPolicy.CLASS)
36+
@Target({ ElementType.TYPE_USE })
37+
@interface MyAnnotation {
38+
}

0 commit comments

Comments
 (0)