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