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