Source code: com/puppycrawl/tools/checkstyle/checks/ParenPadCheck.java
1 ////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code for adherence to a set of rules.
3 // Copyright (C) 2001-2002 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
20 package com.puppycrawl.tools.checkstyle.checks;
21
22 import com.puppycrawl.tools.checkstyle.api.DetailAST;
23 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
24 import com.puppycrawl.tools.checkstyle.api.Utils;
25
26 /**
27 * <p>Checks the padding of parentheses; that is whether a space is required
28 * after a left parenthesis and before a right parenthesis, or such spaces are
29 * forbidden, with the exception that it does
30 * not check for padding of the right parenthesis at an empty for iterator.
31 * Use Check {@link EmptyForIteratorPad} to validate empty for iterators.
32 * <p>
33 * </p>
34 * The policy to verify is specified using the {@link PadOption} class and
35 * defaults to {@link PadOption#NOSPACE}.
36 * </p>
37 * <p> By default the check will check parentheses that occur with the following
38 * tokens:
39 * {@link TokenTypes#CTOR_CALL CTOR_CALL},
40 * {@link TokenTypes#LPAREN LPAREN},
41 * {@link TokenTypes#METHOD_CALL METHOD_CALL},
42 * {@link TokenTypes#RPAREN RPAREN},
43 * {@link TokenTypes#SUPER_CTOR_CALL SUPER_CTOR_CALL},
44 * {@link TokenTypes#TYPECAST TYPECAST}.
45 * </p>
46 * <p>
47 * An example of how to configure the check is:
48 * </p>
49 * <pre>
50 * <module name="ParenPad"/>
51 * </pre>
52 * <p>
53 * An example of how to configure the check to require spaces for the
54 * parentheses of constructor, method, and super constructor invocations is:
55 * </p>
56 * <pre>
57 * <module name="ParenPad">
58 * <property name="tokens"
59 * value="CTOR_CALL, METHOD_CALL, SUPER_CTOR_CALL"/>
60 * <property name="option" value="space"/>
61 * </module>
62 * </pre>
63 * @author <a href="mailto:checkstyle@puppycrawl.com">Oliver Burn</a>
64 * @version 1.0
65 */
66 public class ParenPadCheck
67 extends AbstractOptionCheck
68 {
69 /**
70 * Sets the paren pad otion to nospace.
71 */
72 public ParenPadCheck()
73 {
74 super(PadOption.NOSPACE);
75 }
76
77 /** @see com.puppycrawl.tools.checkstyle.api.Check */
78 public int[] getDefaultTokens()
79 {
80 return new int[] {TokenTypes.RPAREN,
81 TokenTypes.LPAREN,
82 TokenTypes.CTOR_CALL,
83 TokenTypes.SUPER_CTOR_CALL,
84 TokenTypes.TYPECAST, // TODO: treat this?
85 TokenTypes.METHOD_CALL,
86 };
87 }
88
89 /** @see com.puppycrawl.tools.checkstyle.api.Check */
90 public void visitToken(DetailAST aAST)
91 {
92 if (aAST.getType() == TokenTypes.RPAREN) {
93 processRight(aAST);
94 }
95 else {
96 processLeft(aAST);
97 }
98 }
99
100 /**
101 * Process a token representing a left parentheses.
102 * @param aAST the token representing a left parentheses
103 */
104 private void processLeft(DetailAST aAST)
105 {
106 final String line = getLines()[aAST.getLineNo() - 1];
107 final int after = aAST.getColumnNo() + 1;
108 if (after < line.length()) {
109 if ((PadOption.NOSPACE == getAbstractOption())
110 && (Character.isWhitespace(line.charAt(after))))
111 {
112 log(aAST.getLineNo(), after, "ws.followed", "(");
113 }
114 else if ((PadOption.SPACE == getAbstractOption())
115 && !Character.isWhitespace(line.charAt(after))
116 && (line.charAt(after) != ')'))
117 {
118 log(aAST.getLineNo(), after, "ws.notFollowed", "(");
119 }
120 }
121 }
122
123 /**
124 * Process a token representing a right parentheses.
125 * @param aAST the token representing a right parentheses
126 */
127 private void processRight(DetailAST aAST)
128 {
129 final String line = getLines()[aAST.getLineNo() - 1];
130 final int before = aAST.getColumnNo() - 1;
131 if (before >= 0) {
132 boolean followsEmptyForIterator = false;
133 final DetailAST parent = aAST.getParent();
134 if ((parent != null)
135 && (parent.getType() == TokenTypes.LITERAL_FOR))
136 {
137 final DetailAST forIterator =
138 parent.findFirstToken(TokenTypes.FOR_ITERATOR);
139 followsEmptyForIterator = (forIterator.getChildCount() == 0)
140 && (aAST == forIterator.getNextSibling());
141 }
142 if (followsEmptyForIterator) {
143 return;
144 }
145 else if ((PadOption.NOSPACE == getAbstractOption())
146 && Character.isWhitespace(line.charAt(before))
147 && !Utils.whitespaceBefore(before, line))
148 {
149 log(aAST.getLineNo(), before, "ws.preceeded", ")");
150 }
151 else if ((PadOption.SPACE == getAbstractOption())
152 && !Character.isWhitespace(line.charAt(before))
153 && (line.charAt(before) != '('))
154 {
155 log(aAST.getLineNo(), aAST.getColumnNo(),
156 "ws.notPreceeded", ")");
157 }
158 }
159 }
160 }