Source code: com/puppycrawl/tools/checkstyle/checks/blocks/LeftCurlyCheck.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.blocks;
20
21 import com.puppycrawl.tools.checkstyle.api.DetailAST;
22 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
23 import com.puppycrawl.tools.checkstyle.api.Utils;
24 import com.puppycrawl.tools.checkstyle.checks.AbstractOptionCheck;
25
26 /**
27 * <p>
28 * Checks the placement of left curly braces on types, methods and other the
29 * other blocks:
30 * {@link TokenTypes#LITERAL_CATCH LITERAL_CATCH}, {@link
31 * TokenTypes#LITERAL_DO LITERAL_DO}, {@link TokenTypes#LITERAL_ELSE
32 * LITERAL_ELSE}, {@link TokenTypes#LITERAL_FINALLY LITERAL_FINALLY}, {@link
33 * TokenTypes#LITERAL_FOR LITERAL_FOR}, {@link TokenTypes#LITERAL_IF
34 * LITERAL_IF}, {@link TokenTypes#LITERAL_SWITCH LITERAL_SWITCH}, {@link
35 * TokenTypes#LITERAL_SYNCHRONIZED LITERAL_SYNCHRONIZED}, {@link
36 * TokenTypes#LITERAL_TRY LITERAL_TRY}, {@link TokenTypes#LITERAL_WHILE
37 * LITERAL_WHILE}.
38 * </p>
39 *
40 * <p>
41 * The policy to verify is specified using the {@link LeftCurlyOption} class and
42 * defaults to {@link LeftCurlyOption#EOL}. Policies {@link LeftCurlyOption#EOL}
43 * and {@link LeftCurlyOption#NLOW} take into account property maxLineLength.
44 * The default value for maxLineLength is 80.
45 * </p>
46 * <p>
47 * An example of how to configure the check is:
48 * </p>
49 * <pre>
50 * <module name="LeftCurly"/>
51 * </pre>
52 * <p>
53 * An example of how to configure the check with policy
54 * {@link LeftCurlyOption#NLOW} and maxLineLength 120 is:
55 * </p>
56 * <pre>
57 * <module name="LeftCurly">
58 * <property name="option"
59 * value="nlow"/> <property name="maxLineLength" value="120"/> <
60 * /module>
61 * </pre>
62 * @author Oliver Burn
63 * @author lkuehne
64 * @version 1.0
65 */
66 public class LeftCurlyCheck
67 extends AbstractOptionCheck
68 {
69 /** default maximum line length */
70 private static final int DEFAULT_MAX_LINE_LENGTH = 80;
71
72 /** TODO: replace this ugly hack **/
73 private int mMaxLineLength = DEFAULT_MAX_LINE_LENGTH;
74
75 /**
76 * Creates a default instance and sets the policy to EOL.
77 */
78 public LeftCurlyCheck()
79 {
80 super(LeftCurlyOption.EOL);
81 }
82
83 /**
84 * Sets the maximum line length used in calculating the placement of the
85 * left curly brace.
86 * @param aMaxLineLength the max allowed line length
87 */
88 public void setMaxLineLength(int aMaxLineLength)
89 {
90 mMaxLineLength = aMaxLineLength;
91 }
92
93 /** @see com.puppycrawl.tools.checkstyle.api.Check */
94 public int[] getDefaultTokens()
95 {
96 return new int[] {
97 TokenTypes.INTERFACE_DEF,
98 TokenTypes.CLASS_DEF,
99 TokenTypes.CTOR_DEF,
100 TokenTypes.METHOD_DEF,
101 TokenTypes.LITERAL_WHILE,
102 TokenTypes.LITERAL_TRY,
103 TokenTypes.LITERAL_CATCH,
104 TokenTypes.LITERAL_FINALLY,
105 TokenTypes.LITERAL_SYNCHRONIZED,
106 TokenTypes.LITERAL_SWITCH,
107 TokenTypes.LITERAL_DO,
108 TokenTypes.LITERAL_IF,
109 TokenTypes.LITERAL_ELSE,
110 TokenTypes.LITERAL_FOR,
111 // TODO: need to handle....
112 //TokenTypes.STATIC_INIT,
113 };
114 }
115
116 /** @see com.puppycrawl.tools.checkstyle.api.Check */
117 public void visitToken(DetailAST aAST)
118 {
119 final DetailAST startToken;
120 final DetailAST brace;
121
122 switch (aAST.getType()) {
123 case TokenTypes.CTOR_DEF :
124 case TokenTypes.METHOD_DEF :
125 startToken = aAST;
126 brace = aAST.findFirstToken(TokenTypes.SLIST);
127 break;
128
129 case TokenTypes.INTERFACE_DEF :
130 case TokenTypes.CLASS_DEF :
131 // TODO: should check for modifiers
132 startToken = (DetailAST) aAST.getFirstChild().getNextSibling();
133 brace = (DetailAST) aAST.getLastChild().getFirstChild();
134 break;
135
136 case TokenTypes.LITERAL_WHILE:
137 case TokenTypes.LITERAL_CATCH:
138 case TokenTypes.LITERAL_SYNCHRONIZED:
139 case TokenTypes.LITERAL_FOR:
140 case TokenTypes.LITERAL_TRY:
141 case TokenTypes.LITERAL_FINALLY:
142 case TokenTypes.LITERAL_DO:
143 case TokenTypes.LITERAL_IF :
144 startToken = aAST;
145 brace = aAST.findFirstToken(TokenTypes.SLIST);
146 break;
147
148 case TokenTypes.LITERAL_ELSE :
149 startToken = aAST;
150 final DetailAST candidate = (DetailAST) aAST.getFirstChild();
151 brace =
152 (candidate.getType() == TokenTypes.SLIST)
153 ? candidate
154 : null; // silently ignore
155 break;
156
157 case TokenTypes.LITERAL_SWITCH :
158 startToken = aAST;
159 brace = aAST.findFirstToken(TokenTypes.LCURLY);
160 break;
161
162 default :
163 startToken = null;
164 brace = null;
165 }
166
167 if ((brace != null) && (startToken != null)) {
168 verifyBrace(brace, startToken);
169 }
170 }
171
172 /**
173 * Verifies that a specified left curly brace is placed correctly
174 * according to policy.
175 * @param aBrace token for left curly brace
176 * @param aStartToken token for start of expression
177 */
178 private void verifyBrace(final DetailAST aBrace,
179 final DetailAST aStartToken)
180 {
181 final String braceLine = getLines()[aBrace.getLineNo() - 1];
182
183 // calculate the previous line length without trailing whitespace. Need
184 // to handle the case where there is no previous line, cause the line
185 // being check is the first line in the file.
186 final int prevLineLen = (aBrace.getLineNo() == 1)
187 ? mMaxLineLength
188 : Utils.lengthMinusTrailingWhitespace(
189 getLines()[aBrace.getLineNo() - 2]);
190
191 // Check for being told to ignore, or have '{}' which is a special case
192 if ((braceLine.length() > (aBrace.getColumnNo() + 1))
193 && (braceLine.charAt(aBrace.getColumnNo() + 1) == '}'))
194 {
195 ; // ignore
196 }
197 else if (getAbstractOption() == LeftCurlyOption.NL) {
198 if (!Utils.whitespaceBefore(aBrace.getColumnNo(), braceLine)) {
199 log(aBrace.getLineNo(), aBrace.getColumnNo(),
200 "line.new", "{");
201 }
202 }
203 else if (getAbstractOption() == LeftCurlyOption.EOL) {
204 if (Utils.whitespaceBefore(aBrace.getColumnNo(), braceLine)
205 && ((prevLineLen + 2) <= mMaxLineLength))
206 {
207 log(aBrace.getLineNo(), aBrace.getColumnNo(),
208 "line.previous", "{");
209 }
210 }
211 else if (getAbstractOption() == LeftCurlyOption.NLOW) {
212 if (aStartToken.getLineNo() == aBrace.getLineNo()) {
213 ; // all ok as on the same line
214 }
215 else if ((aStartToken.getLineNo() + 1) == aBrace.getLineNo()) {
216 if (!Utils.whitespaceBefore(aBrace.getColumnNo(), braceLine)) {
217 log(aBrace.getLineNo(), aBrace.getColumnNo(),
218 "line.new", "{");
219 }
220 else if ((prevLineLen + 2) <= mMaxLineLength) {
221 log(aBrace.getLineNo(), aBrace.getColumnNo(),
222 "line.previous", "{");
223 }
224 }
225 else if (!Utils.whitespaceBefore(aBrace.getColumnNo(), braceLine)) {
226 log(aBrace.getLineNo(), aBrace.getColumnNo(),
227 "line.new", "{");
228 }
229 }
230 }
231 }