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