1 | //////////////////////////////////////////////////////////////////////////////// | |
2 | // checkstyle: Checks Java source code for adherence to a set of rules. | |
3 | // Copyright (C) 2001-2017 the original author or authors. | |
4 | // | |
5 | // This library is free software; you can redistribute it and/or | |
6 | // modify it under the terms of the GNU Lesser General Public | |
7 | // License as published by the Free Software Foundation; either | |
8 | // version 2.1 of the License, or (at your option) any later version. | |
9 | // | |
10 | // This library is distributed in the hope that it will be useful, | |
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | // Lesser General Public License for more details. | |
14 | // | |
15 | // You should have received a copy of the GNU Lesser General Public | |
16 | // License along with this library; if not, write to the Free Software | |
17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | //////////////////////////////////////////////////////////////////////////////// | |
19 | ||
20 | package com.puppycrawl.tools.checkstyle.checks.whitespace; | |
21 | ||
22 | import com.puppycrawl.tools.checkstyle.api.AbstractCheck; | |
23 | import com.puppycrawl.tools.checkstyle.api.DetailAST; | |
24 | import com.puppycrawl.tools.checkstyle.utils.CommonUtils; | |
25 | ||
26 | /** | |
27 | * <p> | |
28 | * Checks that non-whitespace characters are separated by no more than one | |
29 | * whitespace. Separating characters by tabs or multiple spaces will be | |
30 | * reported. Currently the check doesn't permit horizontal alignment. To inspect | |
31 | * whitespaces before and after comments, set the property | |
32 | * <b>validateComments</b> to true. | |
33 | * </p> | |
34 | * | |
35 | * <p> | |
36 | * Setting <b>validateComments</b> to false will ignore cases like: | |
37 | * </p> | |
38 | * | |
39 | * <pre> | |
40 | * int i; // Multiple whitespaces before comment tokens will be ignored. | |
41 | * private void foo(int /* whitespaces before and after block-comments will be | |
42 | * ignored */ i) { | |
43 | * </pre> | |
44 | * | |
45 | * <p> | |
46 | * Sometimes, users like to space similar items on different lines to the same | |
47 | * column position for easier reading. This feature isn't supported by this | |
48 | * check, so both braces in the following case will be reported as violations. | |
49 | * </p> | |
50 | * | |
51 | * <pre> | |
52 | * public long toNanos(long d) { return d; } // 2 violations | |
53 | * public long toMicros(long d) { return d / (C1 / C0); } | |
54 | * </pre> | |
55 | * | |
56 | * <p> | |
57 | * Check have following options: | |
58 | * </p> | |
59 | * | |
60 | * <ul> | |
61 | * <li>validateComments - Boolean when set to {@code true}, whitespaces | |
62 | * surrounding comments will be ignored. Default value is {@code false}.</li> | |
63 | * </ul> | |
64 | * | |
65 | * <p> | |
66 | * To configure the check: | |
67 | * </p> | |
68 | * | |
69 | * <pre> | |
70 | * <module name="SingleSpaceSeparator"/> | |
71 | * </pre> | |
72 | * | |
73 | * <p> | |
74 | * To configure the check so that it validates comments: | |
75 | * </p> | |
76 | * | |
77 | * <pre> | |
78 | * <module name="SingleSpaceSeparator"> | |
79 | * <property name="validateComments" value="true"/> | |
80 | * </module> | |
81 | * </pre> | |
82 | * | |
83 | * @author Robert Whitebit | |
84 | * @author Richard Veach | |
85 | */ | |
86 | public class SingleSpaceSeparatorCheck extends AbstractCheck { | |
87 | /** | |
88 | * A key is pointing to the warning message text in "messages.properties" | |
89 | * file. | |
90 | */ | |
91 | public static final String MSG_KEY = "single.space.separator"; | |
92 | ||
93 | /** Indicates if whitespaces surrounding comments will be ignored. */ | |
94 | private boolean validateComments; | |
95 | ||
96 | /** | |
97 | * Sets whether or not to validate surrounding whitespaces at comments. | |
98 | * | |
99 | * @param validateComments {@code true} to validate surrounding whitespaces at comments. | |
100 | */ | |
101 | public void setValidateComments(boolean validateComments) { | |
102 | this.validateComments = validateComments; | |
103 | } | |
104 | ||
105 | @Override | |
106 | public int[] getDefaultTokens() { | |
107 |
1
1. getDefaultTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/whitespace/SingleSpaceSeparatorCheck::getDefaultTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return CommonUtils.EMPTY_INT_ARRAY; |
108 | } | |
109 | ||
110 | @Override | |
111 | public int[] getAcceptableTokens() { | |
112 |
1
1. getAcceptableTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/whitespace/SingleSpaceSeparatorCheck::getAcceptableTokens to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return getDefaultTokens(); |
113 | } | |
114 | ||
115 | @Override | |
116 | public int[] getRequiredTokens() { | |
117 |
1
1. getRequiredTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/whitespace/SingleSpaceSeparatorCheck::getRequiredTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return getDefaultTokens(); |
118 | } | |
119 | ||
120 | // -@cs[SimpleAccessorNameNotation] Overrides method from base class. | |
121 | // Issue: https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/166 | |
122 | @Override | |
123 | public boolean isCommentNodesRequired() { | |
124 |
1
1. isCommentNodesRequired : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return validateComments; |
125 | } | |
126 | ||
127 | @Override | |
128 | public void beginTree(DetailAST rootAST) { | |
129 |
1
1. beginTree : removed call to com/puppycrawl/tools/checkstyle/checks/whitespace/SingleSpaceSeparatorCheck::visitEachToken → KILLED |
visitEachToken(rootAST); |
130 | } | |
131 | ||
132 | /** | |
133 | * Examines every sibling and child of {@code node} for violations. | |
134 | * | |
135 | * @param node The node to start examining. | |
136 | */ | |
137 | private void visitEachToken(DetailAST node) { | |
138 | DetailAST sibling = node; | |
139 | ||
140 |
1
1. visitEachToken : negated conditional → KILLED |
while (sibling != null) { |
141 |
1
1. visitEachToken : Replaced integer subtraction with addition → KILLED |
final int columnNo = sibling.getColumnNo() - 1; |
142 | ||
143 |
2
1. visitEachToken : changed conditional boundary → SURVIVED 2. visitEachToken : negated conditional → KILLED |
if (columnNo >= 0 |
144 |
2
1. visitEachToken : Replaced integer subtraction with addition → KILLED 2. visitEachToken : negated conditional → KILLED |
&& !isTextSeparatedCorrectlyFromPrevious(getLine(sibling.getLineNo() - 1), |
145 | columnNo)) { | |
146 |
1
1. visitEachToken : removed call to com/puppycrawl/tools/checkstyle/checks/whitespace/SingleSpaceSeparatorCheck::log → KILLED |
log(sibling.getLineNo(), columnNo, MSG_KEY); |
147 | } | |
148 |
2
1. visitEachToken : changed conditional boundary → SURVIVED 2. visitEachToken : negated conditional → KILLED |
if (sibling.getChildCount() > 0) { |
149 |
1
1. visitEachToken : removed call to com/puppycrawl/tools/checkstyle/checks/whitespace/SingleSpaceSeparatorCheck::visitEachToken → KILLED |
visitEachToken(sibling.getFirstChild()); |
150 | } | |
151 | ||
152 | sibling = sibling.getNextSibling(); | |
153 | } | |
154 | } | |
155 | ||
156 | /** | |
157 | * Checks if characters in {@code line} at and around {@code columnNo} has | |
158 | * the correct number of spaces. to return {@code true} the following | |
159 | * conditions must be met:<br /> | |
160 | * - the character at {@code columnNo} is the first in the line.<br /> | |
161 | * - the character at {@code columnNo} is not separated by whitespaces from | |
162 | * the previous non-whitespace character. <br /> | |
163 | * - the character at {@code columnNo} is separated by only one whitespace | |
164 | * from the previous non-whitespace character.<br /> | |
165 | * - {@link #validateComments} is disabled and the previous text is the | |
166 | * end of a block comment. | |
167 | * | |
168 | * @param line The line in the file to examine. | |
169 | * @param columnNo The column position in the {@code line} to examine. | |
170 | * @return {@code true} if the text at {@code columnNo} is separated | |
171 | * correctly from the previous token. | |
172 | */ | |
173 | private boolean isTextSeparatedCorrectlyFromPrevious(String line, int columnNo) { | |
174 |
2
1. isTextSeparatedCorrectlyFromPrevious : negated conditional → KILLED 2. isTextSeparatedCorrectlyFromPrevious : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return isSingleSpace(line, columnNo) |
175 |
1
1. isTextSeparatedCorrectlyFromPrevious : negated conditional → KILLED |
|| !isWhitespace(line, columnNo) |
176 |
2
1. isTextSeparatedCorrectlyFromPrevious : negated conditional → KILLED 2. isTextSeparatedCorrectlyFromPrevious : negated conditional → KILLED |
|| isFirstInLine(line, columnNo) |
177 |
1
1. isTextSeparatedCorrectlyFromPrevious : negated conditional → KILLED |
|| !validateComments && isBlockCommentEnd(line, columnNo); |
178 | } | |
179 | ||
180 | /** | |
181 | * Checks if the {@code line} at {@code columnNo} is a single space, and not | |
182 | * preceded by another space. | |
183 | * | |
184 | * @param line The line in the file to examine. | |
185 | * @param columnNo The column position in the {@code line} to examine. | |
186 | * @return {@code true} if the character at {@code columnNo} is a space, and | |
187 | * not preceded by another space. | |
188 | */ | |
189 | private static boolean isSingleSpace(String line, int columnNo) { | |
190 |
2
1. isSingleSpace : negated conditional → KILLED 2. isSingleSpace : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return !isPrecededByMultipleWhitespaces(line, columnNo) |
191 |
1
1. isSingleSpace : negated conditional → KILLED |
&& isSpace(line, columnNo); |
192 | } | |
193 | ||
194 | /** | |
195 | * Checks if the {@code line} at {@code columnNo} is a space. | |
196 | * | |
197 | * @param line The line in the file to examine. | |
198 | * @param columnNo The column position in the {@code line} to examine. | |
199 | * @return {@code true} if the character at {@code columnNo} is a space. | |
200 | */ | |
201 | private static boolean isSpace(String line, int columnNo) { | |
202 |
2
1. isSpace : negated conditional → KILLED 2. isSpace : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return line.charAt(columnNo) == ' '; |
203 | } | |
204 | ||
205 | /** | |
206 | * Checks if the {@code line} at {@code columnNo} is preceded by at least 2 | |
207 | * whitespaces. | |
208 | * | |
209 | * @param line The line in the file to examine. | |
210 | * @param columnNo The column position in the {@code line} to examine. | |
211 | * @return {@code true} if there are at least 2 whitespace characters before | |
212 | * {@code columnNo}. | |
213 | */ | |
214 | private static boolean isPrecededByMultipleWhitespaces(String line, int columnNo) { | |
215 |
3
1. isPrecededByMultipleWhitespaces : changed conditional boundary → SURVIVED 2. isPrecededByMultipleWhitespaces : negated conditional → KILLED 3. isPrecededByMultipleWhitespaces : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return columnNo >= 1 |
216 |
2
1. isPrecededByMultipleWhitespaces : Replaced integer subtraction with addition → KILLED 2. isPrecededByMultipleWhitespaces : negated conditional → KILLED |
&& Character.isWhitespace(line.charAt(columnNo)) |
217 |
1
1. isPrecededByMultipleWhitespaces : negated conditional → KILLED |
&& Character.isWhitespace(line.charAt(columnNo - 1)); |
218 | } | |
219 | ||
220 | /** | |
221 | * Checks if the {@code line} at {@code columnNo} is a whitespace character. | |
222 | * | |
223 | * @param line The line in the file to examine. | |
224 | * @param columnNo The column position in the {@code line} to examine. | |
225 | * @return {@code true} if the character at {@code columnNo} is a | |
226 | * whitespace. | |
227 | */ | |
228 | private static boolean isWhitespace(String line, int columnNo) { | |
229 |
1
1. isWhitespace : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return Character.isWhitespace(line.charAt(columnNo)); |
230 | } | |
231 | ||
232 | /** | |
233 | * Checks if the {@code line} up to and including {@code columnNo} is all | |
234 | * non-whitespace text encountered. | |
235 | * | |
236 | * @param line The line in the file to examine. | |
237 | * @param columnNo The column position in the {@code line} to examine. | |
238 | * @return {@code true} if the column position is the first non-whitespace | |
239 | * text on the {@code line}. | |
240 | */ | |
241 | private static boolean isFirstInLine(String line, int columnNo) { | |
242 |
2
1. isFirstInLine : Replaced integer addition with subtraction → SURVIVED 2. isFirstInLine : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return CommonUtils.isBlank(line.substring(0, columnNo + 1)); |
243 | } | |
244 | ||
245 | /** | |
246 | * Checks if the {@code line} at {@code columnNo} is the end of a comment, | |
247 | * '*/'. | |
248 | * | |
249 | * @param line The line in the file to examine. | |
250 | * @param columnNo The column position in the {@code line} to examine. | |
251 | * @return {@code true} if the previous text is a end comment block. | |
252 | */ | |
253 | private static boolean isBlockCommentEnd(String line, int columnNo) { | |
254 |
1
1. isBlockCommentEnd : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return line.substring(0, columnNo).trim().endsWith("*/"); |
255 | } | |
256 | } | |
Mutations | ||
107 |
1.1 |
|
112 |
1.1 |
|
117 |
1.1 |
|
124 |
1.1 |
|
129 |
1.1 |
|
140 |
1.1 |
|
141 |
1.1 |
|
143 |
1.1 2.2 |
|
144 |
1.1 2.2 |
|
146 |
1.1 |
|
148 |
1.1 2.2 |
|
149 |
1.1 |
|
174 |
1.1 2.2 |
|
175 |
1.1 |
|
176 |
1.1 2.2 |
|
177 |
1.1 |
|
190 |
1.1 2.2 |
|
191 |
1.1 |
|
202 |
1.1 2.2 |
|
215 |
1.1 2.2 3.3 |
|
216 |
1.1 2.2 |
|
217 |
1.1 |
|
229 |
1.1 |
|
242 |
1.1 2.2 |
|
254 |
1.1 |