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