1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.checks.whitespace;
21
22 import com.puppycrawl.tools.checkstyle.StatelessCheck;
23 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
24 import com.puppycrawl.tools.checkstyle.api.DetailAST;
25 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
26 import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
27
28
29
30
31
32
33
34
35 @StatelessCheck
36 public class NoWhitespaceBeforeCaseDefaultColonCheck
37 extends AbstractCheck {
38
39
40
41
42
43 public static final String MSG_KEY = "ws.preceded";
44
45
46
47
48 public NoWhitespaceBeforeCaseDefaultColonCheck() {
49
50 }
51
52 @Override
53 public int[] getDefaultTokens() {
54 return getRequiredTokens();
55 }
56
57 @Override
58 public int[] getAcceptableTokens() {
59 return getRequiredTokens();
60 }
61
62 @Override
63 public int[] getRequiredTokens() {
64 return new int[] {TokenTypes.COLON};
65 }
66
67 @Override
68 public boolean isCommentNodesRequired() {
69 return true;
70 }
71
72 @Override
73 public void visitToken(DetailAST ast) {
74 if (isInSwitch(ast) && isWhiteSpaceBeforeColon(ast)) {
75 log(ast, MSG_KEY, ast.getText());
76 }
77 }
78
79
80
81
82
83
84
85 private static boolean isInSwitch(DetailAST colonAst) {
86 return TokenUtil.isOfType(colonAst.getParent(), TokenTypes.LITERAL_CASE,
87 TokenTypes.LITERAL_DEFAULT);
88 }
89
90
91
92
93
94
95
96 private static boolean isWhiteSpaceBeforeColon(DetailAST colonAst) {
97 final DetailAST parent = colonAst.getParent();
98 final boolean result;
99 if (isOnDifferentLineWithPreviousToken(colonAst)) {
100 result = true;
101 }
102 else if (parent.getType() == TokenTypes.LITERAL_CASE) {
103 result = isWhitespaceBeforeColonOfCase(colonAst);
104 }
105 else {
106 result = isWhitespaceBeforeColonOfDefault(colonAst);
107 }
108 return result;
109 }
110
111
112
113
114
115
116
117 private static boolean isWhitespaceBeforeColonOfCase(DetailAST colonAst) {
118 final DetailAST previousSibling = colonAst.getPreviousSibling();
119 int offset = 0;
120 if (previousSibling.getType() == TokenTypes.BLOCK_COMMENT_BEGIN) {
121 offset = 1;
122 }
123 return colonAst.getColumnNo() != getLastColumnNumberOf(previousSibling) + offset;
124 }
125
126
127
128
129
130
131
132 private static boolean isWhitespaceBeforeColonOfDefault(DetailAST colonAst) {
133 final boolean result;
134 final DetailAST previousSibling = colonAst.getPreviousSibling();
135 if (previousSibling == null) {
136 final DetailAST literalDefault = colonAst.getParent();
137 result = colonAst.getColumnNo()
138 != literalDefault.getColumnNo() + literalDefault.getText().length();
139 }
140 else {
141 result =
142 colonAst.getColumnNo() != getLastColumnNumberOf(previousSibling) + 1;
143 }
144 return result;
145 }
146
147
148
149
150
151
152
153 private static boolean isOnDifferentLineWithPreviousToken(DetailAST colonAst) {
154 final DetailAST previousSibling;
155 final DetailAST parent = colonAst.getParent();
156 if (parent.getType() == TokenTypes.LITERAL_CASE) {
157 previousSibling = colonAst.getPreviousSibling();
158 }
159 else {
160 previousSibling = colonAst.getParent();
161 }
162 return !TokenUtil.areOnSameLine(previousSibling, colonAst);
163 }
164
165
166
167
168
169
170
171 private static int getLastColumnNumberOf(DetailAST ast) {
172 DetailAST lastChild = ast;
173 while (lastChild.hasChildren()) {
174 lastChild = lastChild.getLastChild();
175 }
176 return lastChild.getColumnNo() + lastChild.getText().length();
177 }
178
179 }