Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
BooleanExpressionComplexityCheck |
|
| 2.0;2 | ||||
BooleanExpressionComplexityCheck$Context |
|
| 2.0;2 |
1 | //////////////////////////////////////////////////////////////////////////////// | |
2 | // checkstyle: Checks Java source code for adherence to a set of rules. | |
3 | // Copyright (C) 2001-2014 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.metrics; | |
20 | ||
21 | import com.puppycrawl.tools.checkstyle.api.Check; | |
22 | import com.puppycrawl.tools.checkstyle.api.DetailAST; | |
23 | import com.puppycrawl.tools.checkstyle.api.FastStack; | |
24 | import com.puppycrawl.tools.checkstyle.api.TokenTypes; | |
25 | import com.puppycrawl.tools.checkstyle.checks.CheckUtils; | |
26 | ||
27 | /** | |
28 | * Restricts nested boolean operators (&&, ||, &, | and ^) to | |
29 | * a specified depth (default = 3). | |
30 | * | |
31 | * @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris</a> | |
32 | * @author o_sukhodolsky | |
33 | */ | |
34 | public final class BooleanExpressionComplexityCheck extends Check | |
35 | { | |
36 | /** Default allowed complexity. */ | |
37 | private static final int DEFAULT_MAX = 3; | |
38 | ||
39 | /** Stack of contexts. */ | |
40 | 2 | private final FastStack<Context> mContextStack = FastStack.newInstance(); |
41 | /** Maximum allowed complexity. */ | |
42 | private int mMax; | |
43 | /** Current context. */ | |
44 | private Context mContext; | |
45 | ||
46 | /** Creates new instance of the check. */ | |
47 | public BooleanExpressionComplexityCheck() | |
48 | 2 | { |
49 | 2 | setMax(DEFAULT_MAX); |
50 | 2 | } |
51 | ||
52 | @Override | |
53 | public int[] getDefaultTokens() | |
54 | { | |
55 | 2 | return new int[] { |
56 | TokenTypes.CTOR_DEF, | |
57 | TokenTypes.METHOD_DEF, | |
58 | TokenTypes.EXPR, | |
59 | TokenTypes.LAND, | |
60 | TokenTypes.BAND, | |
61 | TokenTypes.LOR, | |
62 | TokenTypes.BOR, | |
63 | TokenTypes.BXOR, | |
64 | }; | |
65 | } | |
66 | ||
67 | @Override | |
68 | public int[] getRequiredTokens() | |
69 | { | |
70 | 1 | return new int[] { |
71 | TokenTypes.CTOR_DEF, | |
72 | TokenTypes.METHOD_DEF, | |
73 | TokenTypes.EXPR, | |
74 | }; | |
75 | } | |
76 | ||
77 | /** | |
78 | * Getter for maximum allowed complexity. | |
79 | * @return value of maximum allowed complexity. | |
80 | */ | |
81 | public int getMax() | |
82 | { | |
83 | 22 | return mMax; |
84 | } | |
85 | ||
86 | /** | |
87 | * Setter for maximum allowed complexity. | |
88 | * @param aMax new maximum allowed complexity. | |
89 | */ | |
90 | public void setMax(int aMax) | |
91 | { | |
92 | 3 | mMax = aMax; |
93 | 3 | } |
94 | ||
95 | @Override | |
96 | public void visitToken(DetailAST aAST) | |
97 | { | |
98 | 64 | switch (aAST.getType()) { |
99 | case TokenTypes.CTOR_DEF: | |
100 | case TokenTypes.METHOD_DEF: | |
101 | 6 | visitMethodDef(aAST); |
102 | 6 | break; |
103 | case TokenTypes.EXPR: | |
104 | 22 | visitExpr(); |
105 | 22 | break; |
106 | case TokenTypes.LAND: | |
107 | case TokenTypes.BAND: | |
108 | case TokenTypes.LOR: | |
109 | case TokenTypes.BOR: | |
110 | case TokenTypes.BXOR: | |
111 | 36 | mContext.visitBooleanOperator(); |
112 | 36 | break; |
113 | default: | |
114 | 0 | throw new IllegalStateException(aAST.toString()); |
115 | } | |
116 | 64 | } |
117 | ||
118 | @Override | |
119 | public void leaveToken(DetailAST aAST) | |
120 | { | |
121 | 64 | switch (aAST.getType()) { |
122 | case TokenTypes.CTOR_DEF: | |
123 | case TokenTypes.METHOD_DEF: | |
124 | 6 | leaveMethodDef(); |
125 | 6 | break; |
126 | case TokenTypes.EXPR: | |
127 | 22 | leaveExpr(aAST); |
128 | 22 | break; |
129 | default: | |
130 | // Do nothing | |
131 | } | |
132 | 64 | } |
133 | ||
134 | /** | |
135 | * Creates new context for a given method. | |
136 | * @param aAST a method we start to check. | |
137 | */ | |
138 | private void visitMethodDef(DetailAST aAST) | |
139 | { | |
140 | 6 | mContextStack.push(mContext); |
141 | 6 | mContext = new Context(!CheckUtils.isEqualsMethod(aAST)); |
142 | 6 | } |
143 | ||
144 | /** Removes old context. */ | |
145 | private void leaveMethodDef() | |
146 | { | |
147 | 6 | mContext = mContextStack.pop(); |
148 | 6 | } |
149 | ||
150 | /** Creates and pushes new context. */ | |
151 | private void visitExpr() | |
152 | { | |
153 | 22 | mContextStack.push(mContext); |
154 | 22 | mContext = new Context((mContext == null) || mContext.isChecking()); |
155 | 22 | } |
156 | ||
157 | /** | |
158 | * Restores previous context. | |
159 | * @param aAST expression we leave. | |
160 | */ | |
161 | private void leaveExpr(DetailAST aAST) | |
162 | { | |
163 | 22 | mContext.checkCount(aAST); |
164 | 22 | mContext = mContextStack.pop(); |
165 | 22 | } |
166 | ||
167 | /** | |
168 | * Represents context (method/expression) in which we check complexity. | |
169 | * | |
170 | * @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris</a> | |
171 | * @author o_sukhodolsky | |
172 | */ | |
173 | private class Context | |
174 | { | |
175 | /** | |
176 | * Should we perform check in current context or not. | |
177 | * Usually false if we are inside equals() method. | |
178 | */ | |
179 | private final boolean mChecking; | |
180 | /** Count of boolean operators. */ | |
181 | private int mCount; | |
182 | ||
183 | /** | |
184 | * Creates new instance. | |
185 | * @param aChecking should we check in current context or not. | |
186 | */ | |
187 | public Context(boolean aChecking) | |
188 | 28 | { |
189 | 28 | mChecking = aChecking; |
190 | 28 | mCount = 0; |
191 | 28 | } |
192 | ||
193 | /** | |
194 | * Getter for checking property. | |
195 | * @return should we check in current context or not. | |
196 | */ | |
197 | public boolean isChecking() | |
198 | { | |
199 | 14 | return mChecking; |
200 | } | |
201 | ||
202 | /** Increases operator counter. */ | |
203 | public void visitBooleanOperator() | |
204 | { | |
205 | 36 | ++mCount; |
206 | 36 | } |
207 | ||
208 | /** | |
209 | * Checks if we violates maximum allowed complexity. | |
210 | * @param aAST a node we check now. | |
211 | */ | |
212 | public void checkCount(DetailAST aAST) | |
213 | { | |
214 | 22 | if (mChecking && (mCount > getMax())) { |
215 | 2 | final DetailAST parentAST = aAST.getParent(); |
216 | ||
217 | 2 | log(parentAST.getLineNo(), parentAST.getColumnNo(), |
218 | "booleanExpressionComplexity", mCount, getMax()); | |
219 | } | |
220 | 22 | } |
221 | } | |
222 | } |