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.checks.indentation;
021
022import java.util.ArrayDeque;
023import java.util.Deque;
024
025import com.puppycrawl.tools.checkstyle.api.Check;
026import com.puppycrawl.tools.checkstyle.api.DetailAST;
027
028/**
029 * Checks correct indentation of Java Code.
030 *
031 * <p>
032 * The basic idea behind this is that while
033 * pretty printers are sometimes convenient for reformats of
034 * legacy code, they often either aren't configurable enough or
035 * just can't anticipate how format should be done.  Sometimes this is
036 * personal preference, other times it is practical experience.  In any
037 * case, this check should just ensure that a minimal set of indentation
038 * rules are followed.
039 * </p>
040 *
041 * <p>
042 * Implementation --
043 *  Basically, this check requests visitation for all handled token
044 *  types (those tokens registered in the HandlerFactory).  When visitToken
045 *  is called, a new ExpressionHandler is created for the AST and pushed
046 *  onto the handlers stack.  The new handler then checks the indentation
047 *  for the currently visiting AST.  When leaveToken is called, the
048 *  ExpressionHandler is popped from the stack.
049 * </p>
050 *
051 * <p>
052 *  While on the stack the ExpressionHandler can be queried for the
053 *  indentation level it suggests for children as well as for other
054 *  values.
055 * </p>
056 *
057 * <p>
058 *  While an ExpressionHandler checks the indentation level of its own
059 *  AST, it typically also checks surrounding ASTs.  For instance, a
060 *  while loop handler checks the while loop as well as the braces
061 *  and immediate children.
062 * </p>
063 * <pre>
064 *   - handler class -to-&gt; ID mapping kept in Map
065 *   - parent passed in during construction
066 *   - suggest child indent level
067 *   - allows for some tokens to be on same line (ie inner classes OBJBLOCK)
068 *     and not increase indentation level
069 *   - looked at using double dispatch for suggestedChildLevel(), but it
070 *     doesn't seem worthwhile, at least now
071 *   - both tabs and spaces are considered whitespace in front of the line...
072 *     tabs are converted to spaces
073 *   - block parents with parens -- for, while, if, etc... -- are checked that
074 *     they match the level of the parent
075 * </pre>
076 *
077 * @author jrichard
078 * @author o_sukhodolsky
079 * @author Maikel Steneker
080 * @author maxvetrenko
081 */
082public class IndentationCheck extends Check {
083    /** Default indentation amount - based on Sun. */
084    private static final int DEFAULT_INDENTATION = 4;
085
086    /** How many tabs or spaces to use. */
087    private int basicOffset = DEFAULT_INDENTATION;
088
089    /** How much to indent a case label. */
090    private int caseIndent = DEFAULT_INDENTATION;
091
092    /** How far brace should be indented when on next line. */
093    private int braceAdjustment;
094
095    /** How far throws should be indented when on next line. */
096    private int throwsIndent = DEFAULT_INDENTATION;
097
098    /** How much to indent an array initialization when on next line. */
099    private int arrayInitIndent = DEFAULT_INDENTATION;
100
101    /** How far continuation line should be indented when line-wrapping is present. */
102    private int lineWrappingIndentation = DEFAULT_INDENTATION;
103
104    /**
105     * Force strict condition in line wrapping case. If value is true, line wrap indent
106     * have to be same as lineWrappingIndentation parameter, if value is false, line wrap indent
107     * have to be not less than lineWrappingIndentation parameter.
108     */
109    private boolean forceStrictCondition;
110
111    /** Handlers currently in use. */
112    private final Deque<AbstractExpressionHandler> handlers = new ArrayDeque<>();
113
114    /** Factory from which handlers are distributed. */
115    private final HandlerFactory handlerFactory = new HandlerFactory();
116
117    /**
118     * Get forcing strict condition.
119     * @return forceStrictCondition value.
120     */
121    public boolean isForceStrictCondition() {
122        return forceStrictCondition;
123    }
124
125    /**
126     * Set forcing strict condition.
127     * @param value user's value of forceStrictCondition.
128     */
129    public void setForceStrictCondition(boolean value) {
130        forceStrictCondition = value;
131    }
132
133    /**
134     * Set the basic offset.
135     *
136     * @param basicOffset   the number of tabs or spaces to indent
137     */
138    public void setBasicOffset(int basicOffset) {
139        this.basicOffset = basicOffset;
140    }
141
142    /**
143     * Get the basic offset.
144     *
145     * @return the number of tabs or spaces to indent
146     */
147    public int getBasicOffset() {
148        return basicOffset;
149    }
150
151    /**
152     * Adjusts brace indentation (positive offset).
153     *
154     * @param adjustmentAmount   the brace offset
155     */
156    public void setBraceAdjustment(int adjustmentAmount) {
157        braceAdjustment = adjustmentAmount;
158    }
159
160    /**
161     * Get the brace adjustment amount.
162     *
163     * @return the positive offset to adjust braces
164     */
165    public int getBraceAdjustment() {
166        return braceAdjustment;
167    }
168
169    /**
170     * Set the case indentation level.
171     *
172     * @param amount   the case indentation level
173     */
174    public void setCaseIndent(int amount) {
175        caseIndent = amount;
176    }
177
178    /**
179     * Get the case indentation level.
180     *
181     * @return the case indentation level
182     */
183    public int getCaseIndent() {
184        return caseIndent;
185    }
186
187    /**
188     * Set the throws indentation level.
189     *
190     * @param throwsIndent the throws indentation level
191     */
192    public void setThrowsIndent(int throwsIndent) {
193        this.throwsIndent = throwsIndent;
194    }
195
196    /**
197     * Get the throws indentation level.
198     *
199     * @return the throws indentation level
200     */
201    public int getThrowsIndent() {
202        return throwsIndent;
203    }
204
205    /**
206     * Set the array initialisation indentation level.
207     *
208     * @param arrayInitIndent the array initialisation indentation level
209     */
210    public void setArrayInitIndent(int arrayInitIndent) {
211        this.arrayInitIndent = arrayInitIndent;
212    }
213
214    /**
215     * Get the line-wrapping indentation level.
216     *
217     * @return the initialisation indentation level
218     */
219    public int getArrayInitIndent() {
220        return arrayInitIndent;
221    }
222
223    /**
224     * Get the array line-wrapping indentation level.
225     *
226     * @return the line-wrapping indentation level
227     */
228    public int getLineWrappingIndentation() {
229        return lineWrappingIndentation;
230    }
231
232    /**
233     * Set the line-wrapping indentation level.
234     *
235     * @param lineWrappingIndentation the line-wrapping indentation level
236     */
237    public void setLineWrappingIndentation(int lineWrappingIndentation) {
238        this.lineWrappingIndentation = lineWrappingIndentation;
239    }
240
241    /**
242     * Log an error message.
243     *
244     * @param line the line number where the error was found
245     * @param key the message that describes the error
246     * @param args the details of the message
247     *
248     * @see java.text.MessageFormat
249     */
250    public void indentationLog(int line, String key, Object... args) {
251        log(line, key, args);
252    }
253
254    /**
255     * Get the width of a tab.
256     *
257     * @return the width of a tab
258     */
259    public int getIndentationTabWidth() {
260        return getTabWidth();
261    }
262
263    @Override
264    public int[] getDefaultTokens() {
265        return getAcceptableTokens();
266    }
267
268    @Override
269    public int[] getAcceptableTokens() {
270        return handlerFactory.getHandledTypes();
271    }
272
273    @Override
274    public int[] getRequiredTokens() {
275        return getAcceptableTokens();
276    }
277
278    @Override
279    public void beginTree(DetailAST ast) {
280        handlerFactory.clearCreatedHandlers();
281        handlers.clear();
282        final PrimordialHandler primordialHandler = new PrimordialHandler(this);
283        handlers.push(primordialHandler);
284        primordialHandler.checkIndentation();
285    }
286
287    @Override
288    public void visitToken(DetailAST ast) {
289        final AbstractExpressionHandler handler = handlerFactory.getHandler(this, ast,
290            handlers.peek());
291        handlers.push(handler);
292        handler.checkIndentation();
293    }
294
295    @Override
296    public void leaveToken(DetailAST ast) {
297        handlers.pop();
298    }
299
300    /**
301     * Accessor for the handler factory.
302     *
303     * @return the handler factory
304     */
305    final HandlerFactory getHandlerFactory() {
306        return handlerFactory;
307    }
308}