001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2016 the original author or authors.
004//
005// This library is free software; you can redistribute it and/or
006// modify it under the terms of the GNU Lesser General Public
007// License as published by the Free Software Foundation; either
008// version 2.1 of the License, or (at your option) any later version.
009//
010// This library is distributed in the hope that it will be useful,
011// but WITHOUT ANY WARRANTY; without even the implied warranty of
012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013// Lesser General Public License for more details.
014//
015// You should have received a copy of the GNU Lesser General Public
016// License along with this library; if not, write to the Free Software
017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
018////////////////////////////////////////////////////////////////////////////////
019
020package com.puppycrawl.tools.checkstyle.api;
021
022import java.util.Collections;
023import java.util.Set;
024
025import com.google.common.collect.Sets;
026
027import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
028
029/**
030 * The base class for checks.
031 *
032 * @author Oliver Burn
033 * @see <a href="{@docRoot}/../writingchecks.html" target="_top">Writing
034 * your own checks</a>
035 */
036public abstract class AbstractCheck extends AbstractViolationReporter {
037    /** Default tab width for column reporting. */
038    private static final int DEFAULT_TAB_WIDTH = 8;
039
040    /** The tokens the check is interested in. */
041    private final Set<String> tokens = Sets.newHashSet();
042
043    /** The current file contents. */
044    private FileContents fileContents;
045
046    /** The object for collecting messages. */
047    private LocalizedMessages messages;
048
049    /** The tab width for column reporting. */
050    private int tabWidth = DEFAULT_TAB_WIDTH;
051
052    /**
053     * The class loader to load external classes. Not initialized as this must
054     * be set by my creator.
055     */
056    private ClassLoader classLoader;
057
058    /**
059     * Returns the default token a check is interested in. Only used if the
060     * configuration for a check does not define the tokens.
061     * @return the default tokens
062     * @see TokenTypes
063     */
064    public abstract int[] getDefaultTokens();
065
066    /**
067     * Whether comment nodes are required or not.
068     * @return false as a default value.
069     */
070    public boolean isCommentNodesRequired() {
071        return false;
072    }
073
074    /**
075     * The configurable token set.
076     * Used to protect Checks against malicious users who specify an
077     * unacceptable token set in the configuration file.
078     * The default implementation returns the check's default tokens.
079     * @return the token set this check is designed for.
080     * @see TokenTypes
081     */
082    public int[] getAcceptableTokens() {
083        final int[] defaultTokens = getDefaultTokens();
084        final int[] copy = new int[defaultTokens.length];
085        System.arraycopy(defaultTokens, 0, copy, 0, defaultTokens.length);
086        return copy;
087    }
088
089    /**
090     * The tokens that this check must be registered for.
091     * @return the token set this must be registered for.
092     * @see TokenTypes
093     */
094    public int[] getRequiredTokens() {
095        return CommonUtils.EMPTY_INT_ARRAY;
096    }
097
098    /**
099     * Adds a set of tokens the check is interested in.
100     * @param strRep the string representation of the tokens interested in
101     */
102    public final void setTokens(String... strRep) {
103        Collections.addAll(tokens, strRep);
104    }
105
106    /**
107     * Returns the tokens registered for the check.
108     * @return the set of token names
109     */
110    public final Set<String> getTokenNames() {
111        return Collections.unmodifiableSet(tokens);
112    }
113
114    /**
115     * Set the global object used to collect messages.
116     * @param messages the messages to log with
117     */
118    public final void setMessages(LocalizedMessages messages) {
119        this.messages = messages;
120    }
121
122    /**
123     * Initialize the check. This is the time to verify that the check has
124     * everything required to perform it job.
125     */
126    public void init() {
127        // No code by default, should be overridden only by demand at subclasses
128    }
129
130    /**
131     * Destroy the check. It is being retired from service.
132     */
133    public void destroy() {
134        // No code by default, should be overridden only by demand at subclasses
135    }
136
137    /**
138     * Called before the starting to process a tree. Ideal place to initialize
139     * information that is to be collected whilst processing a tree.
140     * @param rootAST the root of the tree
141     */
142    public void beginTree(DetailAST rootAST) {
143        // No code by default, should be overridden only by demand at subclasses
144    }
145
146    /**
147     * Called after finished processing a tree. Ideal place to report on
148     * information collected whilst processing a tree.
149     * @param rootAST the root of the tree
150     */
151    public void finishTree(DetailAST rootAST) {
152        // No code by default, should be overridden only by demand at subclasses
153    }
154
155    /**
156     * Called to process a token.
157     * @param ast the token to process
158     */
159    public void visitToken(DetailAST ast) {
160        // No code by default, should be overridden only by demand at subclasses
161    }
162
163    /**
164     * Called after all the child nodes have been process.
165     * @param ast the token leaving
166     */
167    public void leaveToken(DetailAST ast) {
168        // No code by default, should be overridden only by demand at subclasses
169    }
170
171    /**
172     * Returns the lines associated with the tree.
173     * @return the file contents
174     */
175    public final String[] getLines() {
176        return fileContents.getLines();
177    }
178
179    /**
180     * Returns the line associated with the tree.
181     * @param index index of the line
182     * @return the line from the file contents
183     */
184    public final String getLine(int index) {
185        return fileContents.getLine(index);
186    }
187
188    /**
189     * Set the file contents associated with the tree.
190     * @param contents the manager
191     */
192    public final void setFileContents(FileContents contents) {
193        fileContents = contents;
194    }
195
196    /**
197     * Returns the file contents associated with the tree.
198     * @return the file contents
199     */
200    public final FileContents getFileContents() {
201        return fileContents;
202    }
203
204    /**
205     * Set the class loader associated with the tree.
206     * @param classLoader the class loader
207     */
208    public final void setClassLoader(ClassLoader classLoader) {
209        this.classLoader = classLoader;
210    }
211
212    /**
213     * Returns the class loader associated with the tree.
214     * @return the class loader
215     */
216    public final ClassLoader getClassLoader() {
217        return classLoader;
218    }
219
220    /**
221     * Get tab width to report errors with.
222     * @return the tab width to report errors with
223     */
224    protected final int getTabWidth() {
225        return tabWidth;
226    }
227
228    /**
229     * Set the tab width to report errors with.
230     * @param tabWidth an {@code int} value
231     */
232    public final void setTabWidth(int tabWidth) {
233        this.tabWidth = tabWidth;
234    }
235
236    @Override
237    public final void log(int line, String key, Object... args) {
238        messages.add(
239            new LocalizedMessage(
240                line,
241                getMessageBundle(),
242                key,
243                args,
244                getSeverityLevel(),
245                getId(),
246                getClass(),
247                getCustomMessages().get(key)));
248    }
249
250    @Override
251    public final void log(int lineNo, int colNo, String key,
252            Object... args) {
253        final int col = 1 + CommonUtils.lengthExpandedTabs(
254            getLines()[lineNo - 1], colNo, tabWidth);
255        messages.add(
256            new LocalizedMessage(
257                lineNo,
258                col,
259                getMessageBundle(),
260                key,
261                args,
262                getSeverityLevel(),
263                getId(),
264                getClass(),
265                getCustomMessages().get(key)));
266    }
267}