Clover Coverage Report - Checkstyle
Coverage timestamp: Fri May 9 2008 10:48:13 EST
../../../../../../img/srcFileCovDistChart10.png 0% of files have more coverage
54   292   29   7.71
32   163   0.54   7
7     4.14  
1    
 
  UnnecessaryParenthesesCheck       Line # 54 97.8% 0.97849464
29.01 54 29 29 0.54
 
  (2)
 
1    ////////////////////////////////////////////////////////////////////////////////
2    // checkstyle: Checks Java source code for adherence to a set of rules.
3    // Copyright (C) 2001-2005 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.coding;
21   
22    import antlr.collections.AST;
23    import com.puppycrawl.tools.checkstyle.api.Check;
24    import com.puppycrawl.tools.checkstyle.api.DetailAST;
25    import com.puppycrawl.tools.checkstyle.api.TokenTypes;
26   
27    /**
28    * <p>
29    * Checks if unnecessary parentheses are used in a statement or expression.
30    * The check will flag the following with warnings:
31    * </p>
32    * <pre>
33    * return (x); // parens around identifier
34    * return (x + 1); // parens around return value
35    * int x = (y / 2 + 1); // parens around assignment rhs
36    * for (int i = (0); i &lt; 10; i++) { // parens around literal
37    * t -= (z + 1); // parens around assignment rhs</pre>
38    * <p>
39    * The check is not "type aware", that is to say, it can't tell if parentheses
40    * are unnecessary based on the types in an expression. It also doesn't know
41    * about operator precedence and associatvity; therefore it won't catch
42    * something like
43    * </p>
44    * <pre>
45    * int x = (a + b) + c;</pre>
46    * <p>
47    * In the above case, given that <em>a</em>, <em>b</em>, and <em>c</em> are
48    * all <code>int</code> variables, the parentheses around <code>a + b</code>
49    * are not needed.
50    * </p>
51    *
52    * @author Eric Roe
53    */
 
54    public class UnnecessaryParenthesesCheck extends Check
55    {
56    /** The minimum number of child nodes to consider for a match. */
57    private static final int MIN_CHILDREN_FOR_MATCH = 3;
58    /** The maximum string length before we chop the string. */
59    private static final int MAX_QUOTED_LENGTH = 25;
60   
61    /** Token types for literals. */
62    private static final int [] LITERALS = {
63    TokenTypes.NUM_DOUBLE,
64    TokenTypes.NUM_FLOAT,
65    TokenTypes.NUM_INT,
66    TokenTypes.NUM_LONG,
67    TokenTypes.STRING_LITERAL,
68    TokenTypes.LITERAL_NULL,
69    TokenTypes.LITERAL_FALSE,
70    TokenTypes.LITERAL_TRUE,
71    };
72   
73    /** Token types for assignment operations. */
74    private static final int [] ASSIGNMENTS = {
75    TokenTypes.ASSIGN,
76    TokenTypes.BAND_ASSIGN,
77    TokenTypes.BOR_ASSIGN,
78    TokenTypes.BSR_ASSIGN,
79    TokenTypes.BXOR_ASSIGN,
80    TokenTypes.DIV_ASSIGN,
81    TokenTypes.MINUS_ASSIGN,
82    TokenTypes.MOD_ASSIGN,
83    TokenTypes.PLUS_ASSIGN,
84    TokenTypes.SL_ASSIGN,
85    TokenTypes.SR_ASSIGN,
86    TokenTypes.STAR_ASSIGN,
87    };
88   
89    /**
90    * Used to test if logging a warning in a parent node may be skipped
91    * because a warning was already logged on an immediate child node.
92    */
93    private DetailAST mParentToSkip;
94    /** Depth of nested assignments. Normally this will be 0 or 1. */
95    private int mAssignDepth;
96   
97    /** {@inheritDoc} */
 
98  2 toggle public int[] getDefaultTokens()
99    {
100  2 return new int [] {
101    TokenTypes.EXPR,
102    TokenTypes.IDENT,
103    TokenTypes.NUM_DOUBLE,
104    TokenTypes.NUM_FLOAT,
105    TokenTypes.NUM_INT,
106    TokenTypes.NUM_LONG,
107    TokenTypes.STRING_LITERAL,
108    TokenTypes.LITERAL_NULL,
109    TokenTypes.LITERAL_FALSE,
110    TokenTypes.LITERAL_TRUE,
111    TokenTypes.ASSIGN,
112    TokenTypes.BAND_ASSIGN,
113    TokenTypes.BOR_ASSIGN,
114    TokenTypes.BSR_ASSIGN,
115    TokenTypes.BXOR_ASSIGN,
116    TokenTypes.DIV_ASSIGN,
117    TokenTypes.MINUS_ASSIGN,
118    TokenTypes.MOD_ASSIGN,
119    TokenTypes.PLUS_ASSIGN,
120    TokenTypes.SL_ASSIGN,
121    TokenTypes.SR_ASSIGN,
122    TokenTypes.STAR_ASSIGN,
123    };
124    }
125   
126    /** {@inheritDoc} */
 
127  327 toggle public void visitToken(DetailAST aAST)
128    {
129  327 final int type = aAST.getType();
130  327 final boolean surrounded = isSurrounded(aAST);
131  327 final DetailAST parent = aAST.getParent();
132   
133  327 if ((type == TokenTypes.ASSIGN)
134    && (parent.getType() == TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR))
135    {
136    // shouldn't process assign in annotation pairs
137  2 return;
138    }
139   
140    // An identifier surrounded by parentheses.
141  325 if (surrounded && (type == TokenTypes.IDENT)) {
142  9 mParentToSkip = aAST.getParent();
143  9 log(aAST, "unnecessary.paren.ident", aAST.getText());
144  9 return;
145    }
146   
147    // A literal (numeric or string) surrounded by parentheses.
148  316 if (surrounded && inTokenList(type, LITERALS)) {
149  11 mParentToSkip = aAST.getParent();
150  11 if (type == TokenTypes.STRING_LITERAL) {
151  3 log(aAST, "unnecessary.paren.string",
152    chopString(aAST.getText()));
153    }
154    else {
155  8 log(aAST, "unnecessary.paren.literal", aAST.getText());
156    }
157  11 return;
158    }
159   
160    // The rhs of an assignment surrounded by parentheses.
161  305 if (inTokenList(type, ASSIGNMENTS)) {
162  37 mAssignDepth++;
163  37 final DetailAST last = aAST.getLastChild();
164  37 if (last.getType() == TokenTypes.RPAREN) {
165  13 log(aAST, "unnecessary.paren.assign");
166    }
167    }
168    }
169   
170    /** {@inheritDoc} */
 
171  327 toggle public void leaveToken(DetailAST aAST)
172    {
173  327 final int type = aAST.getType();
174  327 final DetailAST parent = aAST.getParent();
175   
176  327 if ((type == TokenTypes.ASSIGN)
177    && (parent.getType() == TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR))
178    {
179    // shouldn't process assign in annotation pairs
180  2 return;
181    }
182   
183    // An expression is surrounded by parentheses.
184  325 if (type == TokenTypes.EXPR) {
185   
186    // If 'mParentToSkip' == 'aAST', then we've already logged a
187    // warning about an immediate child node in visitToken, so we don't
188    // need to log another one here.
189   
190  63 if ((mParentToSkip != aAST) && exprSurrounded(aAST)) {
191  11 if (mAssignDepth >= 1) {
192  5 log(aAST, "unnecessary.paren.assign");
193    }
194  6 else if (aAST.getParent().getType()
195    == TokenTypes.LITERAL_RETURN)