Source code: com/puppycrawl/tools/checkstyle/checks/indentation/IndentationCheck.java
1 ////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code for adherence to a set of rules.
3 // Copyright (C) 2001-2003 Oliver Burn
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ////////////////////////////////////////////////////////////////////////////////
19 package com.puppycrawl.tools.checkstyle.checks.indentation;
20
21 import com.puppycrawl.tools.checkstyle.api.Check;
22 import com.puppycrawl.tools.checkstyle.api.DetailAST;
23
24 import org.apache.commons.collections.ArrayStack;
25
26 // TODO: allow preset indentation styles (IE... GNU style, Sun style, etc...)?
27
28 // TODO: optionally make imports (and other?) statements required to start
29 // line? -- but maybe this should be a different check
30
31 // TODO: optionally allow array children, throws clause, etc...
32 // to be of any indentation > required, for emacs-style indentation
33
34 // TODO: this is not illegal, but probably should be:
35 // myfunc3(11, 11, Integer.
36 // getInteger("mytest").intValue(), // this should be in 4 more
37 // 11);
38
39 // TODO: any dot-based indentation doesn't work (at least not yet...) the
40 // problem is that we don't know which way an expression tree will be built
41 // and with dot trees, they are built backwards. This means code like
42 //
43 // org.blah.mystuff
44 // .myclass.getFactoryObject()
45 // .objFunc().otherMethod();
46 // and
47 // return ((MethodCallHandler) parent)
48 // .findContainingMethodCall(this);
49 // is all checked at the level of the first line. Simple dots are actually
50 // checked but the method call handler will have to be changed drastically
51 // to fix the above...
52
53
54 /**
55 * Checks correct indentation of Java Code.
56 *
57 * <p>
58 * The basic idea behind this is that while
59 * pretty printers are sometimes convienent for bulk reformats of
60 * legacy code, they often either aren't configurable enough or
61 * just can't anticipate how format should be done. Sometimes this is
62 * personal preference, other times it is practical experience. In any
63 * case, this check should just ensure that a minimal set of indentation
64 * rules are followed.
65 * </p>
66 *
67 * <p>
68 * Implementation --
69 * Basically, this check requests visitation for all handled token
70 * types (those tokens registered in the HandlerFactory). When visitToken
71 * is called, a new ExpressionHandler is created for the AST and pushed
72 * onto the mHandlers stack. The new handler then checks the indentation
73 * for the currently visiting AST. When leaveToken is called, the
74 * ExpressionHandler is popped from the stack.
75 * </p>
76 *
77 * <p>
78 * While on the stack the ExpressionHandler can be queried for the
79 * indentation level it suggests for children as well as for other
80 * values.
81 * </p>
82 *
83 * <p>
84 * While an ExpressionHandler checks the indentation level of its own
85 * AST, it typically also checks surrounding ASTs. For instance, a
86 * while loop handler checks the while loop as well as the braces
87 * and immediate children.
88 * </p>
89 * Created on November 2, 2002, 10:59 PM
90 * <p>
91 * <pre>
92 * - handler class -to-> ID mapping kept in Map
93 * - parent passed in during construction
94 * - suggest child indent level
95 * - allows for some tokens to be on same line (ie inner classes OBJBLOCK)
96 * and not increase indentation level
97 * - looked at using double dispatch for suggestedChildLevel(), but it
98 * doesn't seem worthwhile, at least now
99 * - both tabs and spaces are considered whitespace in front of the line...
100 * tabs are converted to spaces
101 * - block parents with parens -- for, while, if, etc... -- are checked that
102 * they match the level of the parent
103 * </pre>
104 *
105 * @author jrichard
106 * @author o_sukhodolsky
107 */
108
109 public class IndentationCheck extends Check
110 {
111 /** Default indentation amount - based on Sun */
112 private static final int DEFAULT_INDENTATION = 4;
113
114 /** how many tabs or spaces to use */
115 private int mBasicOffset = DEFAULT_INDENTATION;
116
117 /** how much to indent a case label */
118 private int mCaseIndentationAmount = DEFAULT_INDENTATION;
119
120 /** how far brace should be indented when on next line */
121 private int mBraceAdjustment;
122
123 /** handlers currently in use */
124 private ArrayStack mHandlers = new ArrayStack();
125
126 /** factory from which handlers are distributed */
127 private HandlerFactory mHandlerFactory = new HandlerFactory();
128
129 /** Creates a new instance of IndentationCheck. */
130 public IndentationCheck()
131 {
132 }
133
134 /**
135 * Set the basic offset.
136 *
137 * @param aBasicOffset the number of tabs or spaces to indent
138 */
139 public void setBasicOffset(int aBasicOffset)
140 {
141 mBasicOffset = aBasicOffset;
142 }
143
144 /**
145 * Get the basic offset.
146 *
147 * @return the number of tabs or spaces to indent
148 */
149 public int getBasicOffset()
150 {
151 return mBasicOffset;
152 }
153
154 /**
155 * Adjusts brace indentation (positive offset).
156 *
157 * @param aAdjustmentAmount the brace offset
158 */
159 public void setBraceAdjustment(int aAdjustmentAmount)
160 {
161 mBraceAdjustment = aAdjustmentAmount;
162 }
163
164 /**
165 * Get the brace adjustment amount.
166 *
167 * @return the positive offset to adjust braces
168 */
169 public int getBraceAdjustement()
170 {
171 return mBraceAdjustment;
172 }
173
174 /**
175 * Set the case indentation level.
176 *
177 * @param aAmount the case indentation level
178 */
179 public void setCaseIndent(int aAmount)
180 {
181 mCaseIndentationAmount = aAmount;
182 }
183
184 /**
185 * Get the case indentation level.
186 *
187 * @return the case indentation level
188 */
189 public int getCaseIndent()
190 {
191 return mCaseIndentationAmount;
192 }
193
194 /**
195 * Log an error message.
196 *
197 * @param aLine the line number where the error was found
198 * @param aKey the message that describes the error
199 * @param aArgs the details of the message
200 *
201 * @see java.text.MessageFormat
202 */
203 public void indentationLog(int aLine, String aKey, Object[] aArgs)
204 {
205 super.log(aLine, aKey, aArgs);
206 }
207
208 /**
209 * Get the width of a tab.
210 *
211 * @return the width of a tab
212 */
213 public int getIndentationTabWidth()
214 {
215 return getTabWidth();
216 }
217
218 /**
219 * Get the tokens that this check will handle.
220 *
221 * @return the array of tokens that this check handles
222 */
223 public int[] getDefaultTokens()
224 {
225 return mHandlerFactory.getHandledTypes();
226 }
227
228 /**
229 * @see com.puppycrawl.tools.checkstyle.api.Check
230 */
231 public void beginTree(DetailAST aAst)
232 {
233 mHandlerFactory.clearCreatedHandlers();
234 mHandlers.clear();
235 mHandlers.push(new PrimordialHandler(this));
236 }
237
238 /**
239 * @see com.puppycrawl.tools.checkstyle.api.Check
240 */
241 public void visitToken(DetailAST aAST)
242 {
243 ExpressionHandler handler = mHandlerFactory.getHandler(this, aAST,
244 (ExpressionHandler) mHandlers.peek());
245 mHandlers.push(handler);
246 handler.checkIndentation();
247 }
248
249 /**
250 * @see com.puppycrawl.tools.checkstyle.api.Check
251 */
252 public void leaveToken(DetailAST aAST)
253 {
254 mHandlers.pop();
255 }
256
257 /**
258 * Accessor for the handler factory.
259 *
260 * @return the handler factory
261 */
262 final HandlerFactory getHandlerFactory()
263 {
264 return mHandlerFactory;
265 }
266 }