/
AbstractCheck.java
333 lines (295 loc) · 9.84 KB
/
AbstractCheck.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2022 the original author or authors.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
////////////////////////////////////////////////////////////////////////////////
package com.puppycrawl.tools.checkstyle.api;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
/**
* The base class for checks.
*
* @see <a href="{@docRoot}/../writingchecks.html" target="_top">Writing
* your own checks</a>
* @noinspection NoopMethodInAbstractClass
*/
public abstract class AbstractCheck extends AbstractViolationReporter {
/**
* The check context.
*
* @noinspection ThreadLocalNotStaticFinal
*/
private final ThreadLocal<FileContext> context = ThreadLocal.withInitial(FileContext::new);
/** The tokens the check is interested in. */
private final Set<String> tokens = new HashSet<>();
/** The tab width for column reporting. */
private int tabWidth = CommonUtil.DEFAULT_TAB_WIDTH;
/**
* Returns the default token a check is interested in. Only used if the
* configuration for a check does not define the tokens.
*
* @return the default tokens
* @see TokenTypes
*/
public abstract int[] getDefaultTokens();
/**
* The configurable token set.
* Used to protect Checks against malicious users who specify an
* unacceptable token set in the configuration file.
* The default implementation returns the check's default tokens.
*
* @return the token set this check is designed for.
* @see TokenTypes
*/
public abstract int[] getAcceptableTokens();
/**
* The tokens that this check must be registered for.
*
* @return the token set this must be registered for.
* @see TokenTypes
*/
public abstract int[] getRequiredTokens();
/**
* Whether comment nodes are required or not.
*
* @return false as a default value.
*/
public boolean isCommentNodesRequired() {
return false;
}
/**
* Adds a set of tokens the check is interested in.
*
* @param strRep the string representation of the tokens interested in
* @noinspection WeakerAccess
*/
public final void setTokens(String... strRep) {
Collections.addAll(tokens, strRep);
}
/**
* Returns the tokens registered for the check.
*
* @return the set of token names
*/
public final Set<String> getTokenNames() {
return Collections.unmodifiableSet(tokens);
}
/**
* Returns the sorted set of {@link Violation}.
*
* @return the sorted set of {@link Violation}.
*/
public SortedSet<Violation> getViolations() {
return new TreeSet<>(context.get().violations);
}
/**
* Clears the sorted set of {@link Violation} of the check.
*/
public final void clearViolations() {
context.get().violations.clear();
}
/**
* Initialize the check. This is the time to verify that the check has
* everything required to perform it job.
*/
public void init() {
// No code by default, should be overridden only by demand at subclasses
}
/**
* Destroy the check. It is being retired from service.
*/
public void destroy() {
context.remove();
}
/**
* Called before the starting to process a tree. Ideal place to initialize
* information that is to be collected whilst processing a tree.
*
* @param rootAST the root of the tree
*/
public void beginTree(DetailAST rootAST) {
// No code by default, should be overridden only by demand at subclasses
}
/**
* Called after finished processing a tree. Ideal place to report on
* information collected whilst processing a tree.
*
* @param rootAST the root of the tree
*/
public void finishTree(DetailAST rootAST) {
// No code by default, should be overridden only by demand at subclasses
}
/**
* Called to process a token.
*
* @param ast the token to process
*/
public void visitToken(DetailAST ast) {
// No code by default, should be overridden only by demand at subclasses
}
/**
* Called after all the child nodes have been process.
*
* @param ast the token leaving
*/
public void leaveToken(DetailAST ast) {
// No code by default, should be overridden only by demand at subclasses
}
/**
* Set the file contents associated with the tree.
*
* @param contents the manager
*/
public final void setFileContents(FileContents contents) {
context.get().fileContents = contents;
}
/**
* Returns the file contents associated with the tree.
*
* @return the file contents
* @deprecated
* Usage of this method is no longer accepted.
* Please use AST based methods instead.
* @noinspection WeakerAccess
*/
@Deprecated(since = "9.3")
public final FileContents getFileContents() {
return context.get().fileContents;
}
/**
* Get tab width to report audit events with.
*
* @return the tab width to audit events with
*/
protected final int getTabWidth() {
return tabWidth;
}
/**
* Set the tab width to report audit events with.
*
* @param tabWidth an {@code int} value
*/
public final void setTabWidth(int tabWidth) {
this.tabWidth = tabWidth;
}
@Override
public final void log(int line, String key, Object... args) {
context.get().violations.add(
new Violation(
line,
getMessageBundle(),
key,
args,
getSeverityLevel(),
getId(),
getClass(),
getCustomMessages().get(key)));
}
@Override
public final void log(int lineNo, int colNo, String key,
Object... args) {
final int col = 1 + CommonUtil.lengthExpandedTabs(
getLines()[lineNo - 1], colNo, tabWidth);
context.get().violations.add(
new Violation(
lineNo,
col,
getMessageBundle(),
key,
args,
getSeverityLevel(),
getId(),
getClass(),
getCustomMessages().get(key)));
}
/**
* Helper method to log a Violation.
*
* @param ast a node to get line id column numbers associated
* with the violation
* @param key key to locale violation format
* @param args arguments to format
*/
public final void log(DetailAST ast, String key, Object... args) {
// CommonUtil.lengthExpandedTabs returns column number considering tabulation
// characters, it takes line from the file by line number, ast column number and tab
// width as arguments. Returned value is 0-based, but user must see column number starting
// from 1, that is why result of the method CommonUtil.lengthExpandedTabs
// is increased by one.
final int col = 1 + CommonUtil.lengthExpandedTabs(
getLines()[ast.getLineNo() - 1], ast.getColumnNo(), tabWidth);
context.get().violations.add(
new Violation(
ast.getLineNo(),
col,
ast.getColumnNo(),
ast.getType(),
getMessageBundle(),
key,
args,
getSeverityLevel(),
getId(),
getClass(),
getCustomMessages().get(key)));
}
/**
* Returns the lines associated with the tree.
*
* @return the file contents
*/
public final String[] getLines() {
return context.get().fileContents.getLines();
}
/**
* Returns the line associated with the tree.
*
* @param index index of the line
* @return the line from the file contents
*/
public final String getLine(int index) {
return context.get().fileContents.getLine(index);
}
/**
* Returns full path to the file.
*
* @return full path to file.
*/
public final String getFilePath() {
return context.get().fileContents.getFileName();
}
/**
* Returns code point representation of file text from given line number.
*
* @param index index of the line
* @return the array of Unicode code points
*/
public final int[] getLineCodePoints(int index) {
return getLine(index).codePoints().toArray();
}
/**
* The actual context holder.
*/
private static class FileContext {
/** The sorted set for collecting violations. */
private final SortedSet<Violation> violations = new TreeSet<>();
/** The current file contents. */
private FileContents fileContents;
}
}