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