OLD | NEW |
1 # Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE). | 1 # Copyright (c) 2003-2006 LOGILAB S.A. (Paris, FRANCE). |
2 # http://www.logilab.fr/ -- mailto:contact@logilab.fr | 2 # http://www.logilab.fr/ -- mailto:contact@logilab.fr |
3 # | 3 # |
4 # This program is free software; you can redistribute it and/or modify it under | 4 # This program is free software; you can redistribute it and/or modify it under |
5 # the terms of the GNU General Public License as published by the Free Software | 5 # the terms of the GNU General Public License as published by the Free Software |
6 # Foundation; either version 2 of the License, or (at your option) any later | 6 # Foundation; either version 2 of the License, or (at your option) any later |
7 # version. | 7 # version. |
8 # | 8 # |
9 # This program is distributed in the hope that it will be useful, but WITHOUT | 9 # This program is distributed in the hope that it will be useful, but WITHOUT |
10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
11 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. | 11 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
12 # | 12 # |
13 # You should have received a copy of the GNU General Public License along with | 13 # You should have received a copy of the GNU General Public License along with |
14 # this program; if not, write to the Free Software Foundation, Inc., | 14 # this program; if not, write to the Free Software Foundation, Inc., |
15 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 15 # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
16 """check for signs of poor design""" | 16 """check for signs of poor design |
17 | 17 |
18 from astroid import Function, If, InferenceError | |
19 | 18 |
20 from pylint.interfaces import IAstroidChecker | 19 see http://intranet.logilab.fr/jpl/view?rql=Any%20X%20where%20X%20eid%201243 |
| 20 FIXME: missing 13, 15, 16 |
| 21 """ |
| 22 |
| 23 from logilab.astng import Function, If, InferenceError |
| 24 |
| 25 from pylint.interfaces import IASTNGChecker |
21 from pylint.checkers import BaseChecker | 26 from pylint.checkers import BaseChecker |
22 from pylint.checkers.utils import check_messages | |
23 | 27 |
24 import re | 28 import re |
25 | 29 |
26 # regexp for ignored argument name | 30 # regexp for ignored argument name |
27 IGNORED_ARGUMENT_NAMES = re.compile('_.*') | 31 IGNORED_ARGUMENT_NAMES = re.compile('_.*') |
28 | 32 |
29 | |
30 def class_is_abstract(klass): | 33 def class_is_abstract(klass): |
31 """return true if the given class node should be considered as an abstract | 34 """return true if the given class node should be considered as an abstract |
32 class | 35 class |
33 """ | 36 """ |
34 for attr in klass.values(): | 37 for attr in klass.values(): |
35 if isinstance(attr, Function): | 38 if isinstance(attr, Function): |
36 if attr.is_abstract(pass_is_abstract=False): | 39 if attr.is_abstract(pass_is_abstract=False): |
37 return True | 40 return True |
38 return False | 41 return False |
39 | 42 |
40 | 43 |
41 MSGS = { | 44 MSGS = { |
42 'R0901': ('Too many ancestors (%s/%s)', | 45 'R0901': ('Too many ancestors (%s/%s)', |
43 'too-many-ancestors', | |
44 'Used when class has too many parent classes, try to reduce \ | 46 'Used when class has too many parent classes, try to reduce \ |
45 this to get a simpler (and so easier to use) class.'), | 47 this to get a more simple (and so easier to use) class.'), |
46 'R0902': ('Too many instance attributes (%s/%s)', | 48 'R0902': ('Too many instance attributes (%s/%s)', |
47 'too-many-instance-attributes', | |
48 'Used when class has too many instance attributes, try to reduce \ | 49 'Used when class has too many instance attributes, try to reduce \ |
49 this to get a simpler (and so easier to use) class.'), | 50 this to get a more simple (and so easier to use) class.'), |
50 'R0903': ('Too few public methods (%s/%s)', | 51 'R0903': ('Too few public methods (%s/%s)', |
51 'too-few-public-methods', | |
52 'Used when class has too few public methods, so be sure it\'s \ | 52 'Used when class has too few public methods, so be sure it\'s \ |
53 really worth it.'), | 53 really worth it.'), |
54 'R0904': ('Too many public methods (%s/%s)', | 54 'R0904': ('Too many public methods (%s/%s)', |
55 'too-many-public-methods', | |
56 'Used when class has too many public methods, try to reduce \ | 55 'Used when class has too many public methods, try to reduce \ |
57 this to get a simpler (and so easier to use) class.'), | 56 this to get a more simple (and so easier to use) class.'), |
58 | 57 |
59 'R0911': ('Too many return statements (%s/%s)', | 58 'R0911': ('Too many return statements (%s/%s)', |
60 'too-many-return-statements', | |
61 'Used when a function or method has too many return statement, \ | 59 'Used when a function or method has too many return statement, \ |
62 making it hard to follow.'), | 60 making it hard to follow.'), |
63 'R0912': ('Too many branches (%s/%s)', | 61 'R0912': ('Too many branches (%s/%s)', |
64 'too-many-branches', | |
65 'Used when a function or method has too many branches, \ | 62 'Used when a function or method has too many branches, \ |
66 making it hard to follow.'), | 63 making it hard to follow.'), |
67 'R0913': ('Too many arguments (%s/%s)', | 64 'R0913': ('Too many arguments (%s/%s)', |
68 'too-many-arguments', | |
69 'Used when a function or method takes too many arguments.'), | 65 'Used when a function or method takes too many arguments.'), |
70 'R0914': ('Too many local variables (%s/%s)', | 66 'R0914': ('Too many local variables (%s/%s)', |
71 'too-many-locals', | |
72 'Used when a function or method has too many local variables.'), | 67 'Used when a function or method has too many local variables.'), |
73 'R0915': ('Too many statements (%s/%s)', | 68 'R0915': ('Too many statements (%s/%s)', |
74 'too-many-statements', | |
75 'Used when a function or method has too many statements. You \ | 69 'Used when a function or method has too many statements. You \ |
76 should then split it in smaller functions / methods.'), | 70 should then split it in smaller functions / methods.'), |
77 | 71 |
78 'R0921': ('Abstract class not referenced', | 72 'R0921': ('Abstract class not referenced', |
79 'abstract-class-not-used', | |
80 'Used when an abstract class is not used as ancestor anywhere.'), | 73 'Used when an abstract class is not used as ancestor anywhere.'), |
81 'R0922': ('Abstract class is only referenced %s times', | 74 'R0922': ('Abstract class is only referenced %s times', |
82 'abstract-class-little-used', | |
83 'Used when an abstract class is used less than X times as \ | 75 'Used when an abstract class is used less than X times as \ |
84 ancestor.'), | 76 ancestor.'), |
85 'R0923': ('Interface not implemented', | 77 'R0923': ('Interface not implemented', |
86 'interface-not-implemented', | |
87 'Used when an interface class is not implemented anywhere.'), | 78 'Used when an interface class is not implemented anywhere.'), |
88 } | 79 } |
89 | 80 |
90 | 81 |
91 class MisdesignChecker(BaseChecker): | 82 class MisdesignChecker(BaseChecker): |
92 """checks for sign of poor/misdesign: | 83 """checks for sign of poor/misdesign: |
93 * number of methods, attributes, local variables... | 84 * number of methods, attributes, local variables... |
94 * size, complexity of functions, methods | 85 * size, complexity of functions, methods |
95 """ | 86 """ |
96 | 87 |
97 __implements__ = (IAstroidChecker,) | 88 __implements__ = (IASTNGChecker,) |
98 | 89 |
99 # configuration section name | 90 # configuration section name |
100 name = 'design' | 91 name = 'design' |
101 # messages | 92 # messages |
102 msgs = MSGS | 93 msgs = MSGS |
103 priority = -2 | 94 priority = -2 |
104 # configuration options | 95 # configuration options |
105 options = (('max-args', | 96 options = (('max-args', |
106 {'default' : 5, 'type' : 'int', 'metavar' : '<int>', | 97 {'default' : 5, 'type' : 'int', 'metavar' : '<int>', |
107 'help': 'Maximum number of arguments for function / method'} | 98 'help': 'Maximum number of arguments for function / method'} |
108 ), | 99 ), |
109 ('ignored-argument-names', | 100 ('ignored-argument-names', |
110 {'default' : IGNORED_ARGUMENT_NAMES, | 101 {'default' : IGNORED_ARGUMENT_NAMES, |
111 'type' :'regexp', 'metavar' : '<regexp>', | 102 'type' :'regexp', 'metavar' : '<regexp>', |
112 'help' : 'Argument names that match this expression will be ' | 103 'help' : 'Argument names that match this expression will be ' |
113 'ignored. Default to name with leading underscore'} | 104 'ignored. Default to name with leading underscore'} |
114 ), | 105 ), |
115 ('max-locals', | 106 ('max-locals', |
116 {'default' : 15, 'type' : 'int', 'metavar' : '<int>', | 107 {'default' : 15, 'type' : 'int', 'metavar' : '<int>', |
117 'help': 'Maximum number of locals for function / method body'} | 108 'help': 'Maximum number of locals for function / method body'} |
118 ), | 109 ), |
119 ('max-returns', | 110 ('max-returns', |
120 {'default' : 6, 'type' : 'int', 'metavar' : '<int>', | 111 {'default' : 6, 'type' : 'int', 'metavar' : '<int>', |
121 'help': 'Maximum number of return / yield for function / ' | 112 'help': 'Maximum number of return / yield for function / ' |
122 'method body'} | 113 'method body'} |
123 ), | 114 ), |
124 ('max-branches', | 115 ('max-branchs', |
125 {'default' : 12, 'type' : 'int', 'metavar' : '<int>', | 116 {'default' : 12, 'type' : 'int', 'metavar' : '<int>', |
126 'help': 'Maximum number of branch for function / method body'} | 117 'help': 'Maximum number of branch for function / method body'} |
127 ), | 118 ), |
128 ('max-statements', | 119 ('max-statements', |
129 {'default' : 50, 'type' : 'int', 'metavar' : '<int>', | 120 {'default' : 50, 'type' : 'int', 'metavar' : '<int>', |
130 'help': 'Maximum number of statements in function / method ' | 121 'help': 'Maximum number of statements in function / method ' |
131 'body'} | 122 'body'} |
132 ), | 123 ), |
133 ('max-parents', | 124 ('max-parents', |
134 {'default' : 7, | 125 {'default' : 7, |
135 'type' : 'int', | 126 'type' : 'int', |
136 'metavar' : '<num>', | 127 'metavar' : '<num>', |
137 'help' : 'Maximum number of parents for a class (see R0901).'} | 128 'help' : 'Maximum number of parents for a class (see R0901).'} |
138 ), | 129 ), |
139 ('max-attributes', | 130 ('max-attributes', |
140 {'default' : 7, | 131 {'default' : 7, |
141 'type' : 'int', | 132 'type' : 'int', |
142 'metavar' : '<num>', | 133 'metavar' : '<num>', |
143 'help' : 'Maximum number of attributes for a class \ | 134 'help' : 'Maximum number of attributes for a class \ |
144 (see R0902).'} | 135 (see R0902).'} |
145 ), | 136 ), |
146 ('min-public-methods', | 137 ('min-public-methods', |
147 {'default' : 2, | 138 {'default' : 2, |
148 'type' : 'int', | 139 'type' : 'int', |
149 'metavar' : '<num>', | 140 'metavar' : '<num>', |
150 'help' : 'Minimum number of public methods for a class \ | 141 'help' : 'Minimum number of public methods for a class \ |
151 (see R0903).'} | 142 (see R0903).'} |
152 ), | 143 ), |
153 ('max-public-methods', | 144 ('max-public-methods', |
154 {'default' : 20, | 145 {'default' : 20, |
155 'type' : 'int', | 146 'type' : 'int', |
156 'metavar' : '<num>', | 147 'metavar' : '<num>', |
157 'help' : 'Maximum number of public methods for a class \ | 148 'help' : 'Maximum number of public methods for a class \ |
158 (see R0904).'} | 149 (see R0904).'} |
159 ), | 150 ), |
160 ) | 151 ) |
161 | 152 |
162 def __init__(self, linter=None): | 153 def __init__(self, linter=None): |
163 BaseChecker.__init__(self, linter) | 154 BaseChecker.__init__(self, linter) |
164 self.stats = None | 155 self.stats = None |
165 self._returns = None | 156 self._returns = None |
166 self._branches = None | 157 self._branchs = None |
167 self._used_abstracts = None | 158 self._used_abstracts = None |
168 self._used_ifaces = None | 159 self._used_ifaces = None |
169 self._abstracts = None | 160 self._abstracts = None |
170 self._ifaces = None | 161 self._ifaces = None |
171 self._stmts = 0 | 162 self._stmts = 0 |
172 | 163 |
173 def open(self): | 164 def open(self): |
174 """initialize visit variables""" | 165 """initialize visit variables""" |
175 self.stats = self.linter.add_stats() | 166 self.stats = self.linter.add_stats() |
176 self._returns = [] | 167 self._returns = [] |
177 self._branches = [] | 168 self._branchs = [] |
178 self._used_abstracts = {} | 169 self._used_abstracts = {} |
179 self._used_ifaces = {} | 170 self._used_ifaces = {} |
180 self._abstracts = [] | 171 self._abstracts = [] |
181 self._ifaces = [] | 172 self._ifaces = [] |
182 | 173 |
183 # Check 'R0921', 'R0922', 'R0923' | |
184 def close(self): | 174 def close(self): |
185 """check that abstract/interface classes are used""" | 175 """check that abstract/interface classes are used""" |
186 for abstract in self._abstracts: | 176 for abstract in self._abstracts: |
187 if not abstract in self._used_abstracts: | 177 if not abstract in self._used_abstracts: |
188 self.add_message('abstract-class-not-used', node=abstract) | 178 self.add_message('R0921', node=abstract) |
189 elif self._used_abstracts[abstract] < 2: | 179 elif self._used_abstracts[abstract] < 2: |
190 self.add_message('abstract-class-little-used', node=abstract, | 180 self.add_message('R0922', node=abstract, |
191 args=self._used_abstracts[abstract]) | 181 args=self._used_abstracts[abstract]) |
192 for iface in self._ifaces: | 182 for iface in self._ifaces: |
193 if not iface in self._used_ifaces: | 183 if not iface in self._used_ifaces: |
194 self.add_message('interface-not-implemented', node=iface) | 184 self.add_message('R0923', node=iface) |
195 | 185 |
196 @check_messages('too-many-ancestors', 'too-many-instance-attributes', | |
197 'too-few-public-methods', 'too-many-public-methods', | |
198 'abstract-class-not-used', 'abstract-class-little-used', | |
199 'interface-not-implemented') | |
200 def visit_class(self, node): | 186 def visit_class(self, node): |
201 """check size of inheritance hierarchy and number of instance attributes | 187 """check size of inheritance hierarchy and number of instance attributes |
202 """ | 188 """ |
203 self._inc_branch() | 189 self._inc_branch() |
204 # Is the total inheritance hierarchy is 7 or less? | 190 # Is the total inheritance hierarchy is 7 or less? |
205 nb_parents = len(list(node.ancestors())) | 191 nb_parents = len(list(node.ancestors())) |
206 if nb_parents > self.config.max_parents: | 192 if nb_parents > self.config.max_parents: |
207 self.add_message('too-many-ancestors', node=node, | 193 self.add_message('R0901', node=node, |
208 args=(nb_parents, self.config.max_parents)) | 194 args=(nb_parents, self.config.max_parents)) |
209 # Does the class contain less than 20 attributes for | 195 # Does the class contain less than 20 attributes for |
210 # non-GUI classes (40 for GUI)? | 196 # non-GUI classes (40 for GUI)? |
211 # FIXME detect gui classes | 197 # FIXME detect gui classes |
212 if len(node.instance_attrs) > self.config.max_attributes: | 198 if len(node.instance_attrs) > self.config.max_attributes: |
213 self.add_message('too-many-instance-attributes', node=node, | 199 self.add_message('R0902', node=node, |
214 args=(len(node.instance_attrs), | 200 args=(len(node.instance_attrs), |
215 self.config.max_attributes)) | 201 self.config.max_attributes)) |
216 # update abstract / interface classes structures | 202 # update abstract / interface classes structures |
217 if class_is_abstract(node): | 203 if class_is_abstract(node): |
218 self._abstracts.append(node) | 204 self._abstracts.append(node) |
219 elif node.type == 'interface' and node.name != 'Interface': | 205 elif node.type == 'interface' and node.name != 'Interface': |
220 self._ifaces.append(node) | 206 self._ifaces.append(node) |
221 for parent in node.ancestors(False): | 207 for parent in node.ancestors(False): |
222 if parent.name == 'Interface': | 208 if parent.name == 'Interface': |
223 continue | 209 continue |
224 self._used_ifaces[parent] = 1 | 210 self._used_ifaces[parent] = 1 |
225 try: | 211 try: |
226 for iface in node.interfaces(): | 212 for iface in node.interfaces(): |
227 self._used_ifaces[iface] = 1 | 213 self._used_ifaces[iface] = 1 |
228 except InferenceError: | 214 except InferenceError: |
229 # XXX log ? | 215 # XXX log ? |
230 pass | 216 pass |
231 for parent in node.ancestors(): | 217 for parent in node.ancestors(): |
232 try: | 218 try: |
233 self._used_abstracts[parent] += 1 | 219 self._used_abstracts[parent] += 1 |
234 except KeyError: | 220 except KeyError: |
235 self._used_abstracts[parent] = 1 | 221 self._used_abstracts[parent] = 1 |
236 | 222 |
237 @check_messages('too-many-ancestors', 'too-many-instance-attributes', | |
238 'too-few-public-methods', 'too-many-public-methods', | |
239 'abstract-class-not-used', 'abstract-class-little-used', | |
240 'interface-not-implemented') | |
241 def leave_class(self, node): | 223 def leave_class(self, node): |
242 """check number of public methods""" | 224 """check number of public methods""" |
243 nb_public_methods = 0 | 225 nb_public_methods = 0 |
244 special_methods = set() | |
245 for method in node.methods(): | 226 for method in node.methods(): |
246 if not method.name.startswith('_'): | 227 if not method.name.startswith('_'): |
247 nb_public_methods += 1 | 228 nb_public_methods += 1 |
248 if method.name.startswith("__"): | |
249 special_methods.add(method.name) | |
250 # Does the class contain less than 20 public methods ? | 229 # Does the class contain less than 20 public methods ? |
251 if nb_public_methods > self.config.max_public_methods: | 230 if nb_public_methods > self.config.max_public_methods: |
252 self.add_message('too-many-public-methods', node=node, | 231 self.add_message('R0904', node=node, |
253 args=(nb_public_methods, | 232 args=(nb_public_methods, |
254 self.config.max_public_methods)) | 233 self.config.max_public_methods)) |
255 # stop here for exception, metaclass and interface classes | 234 # stop here for exception, metaclass and interface classes |
256 if node.type != 'class': | 235 if node.type != 'class': |
257 return | 236 return |
258 # Does the class contain more than 5 public methods ? | 237 # Does the class contain more than 5 public methods ? |
259 if nb_public_methods < self.config.min_public_methods: | 238 if nb_public_methods < self.config.min_public_methods: |
260 self.add_message('R0903', node=node, | 239 self.add_message('R0903', node=node, |
261 args=(nb_public_methods, | 240 args=(nb_public_methods, |
262 self.config.min_public_methods)) | 241 self.config.min_public_methods)) |
263 | 242 |
264 @check_messages('too-many-return-statements', 'too-many-branches', | 243 |
265 'too-many-arguments', 'too-many-locals', 'too-many-statement
s') | |
266 def visit_function(self, node): | 244 def visit_function(self, node): |
267 """check function name, docstring, arguments, redefinition, | 245 """check function name, docstring, arguments, redefinition, |
268 variable names, max locals | 246 variable names, max locals |
269 """ | 247 """ |
270 self._inc_branch() | 248 self._inc_branch() |
271 # init branch and returns counters | 249 # init branch and returns counters |
272 self._returns.append(0) | 250 self._returns.append(0) |
273 self._branches.append(0) | 251 self._branchs.append(0) |
274 # check number of arguments | 252 # check number of arguments |
275 args = node.args.args | 253 args = node.args.args |
276 if args is not None: | 254 if args is not None: |
277 ignored_args_num = len( | 255 ignored_args_num = len( |
278 [arg for arg in args | 256 [arg for arg in args |
279 if self.config.ignored_argument_names.match(arg.name)]) | 257 if self.config.ignored_argument_names.match(arg.name)]) |
280 argnum = len(args) - ignored_args_num | 258 argnum = len(args) - ignored_args_num |
281 if argnum > self.config.max_args: | 259 if argnum > self.config.max_args: |
282 self.add_message('too-many-arguments', node=node, | 260 self.add_message('R0913', node=node, |
283 args=(len(args), self.config.max_args)) | 261 args=(len(args), self.config.max_args)) |
284 else: | 262 else: |
285 ignored_args_num = 0 | 263 ignored_args_num = 0 |
286 # check number of local variables | 264 # check number of local variables |
287 locnum = len(node.locals) - ignored_args_num | 265 locnum = len(node.locals) - ignored_args_num |
288 if locnum > self.config.max_locals: | 266 if locnum > self.config.max_locals: |
289 self.add_message('too-many-locals', node=node, | 267 self.add_message('R0914', node=node, |
290 args=(locnum, self.config.max_locals)) | 268 args=(locnum, self.config.max_locals)) |
291 # init statements counter | 269 # init statements counter |
292 self._stmts = 1 | 270 self._stmts = 1 |
293 | 271 |
294 @check_messages('too-many-return-statements', 'too-many-branches', 'too-many
-arguments', 'too-many-locals', 'too-many-statements') | |
295 def leave_function(self, node): | 272 def leave_function(self, node): |
296 """most of the work is done here on close: | 273 """most of the work is done here on close: |
297 checks for max returns, branch, return in __init__ | 274 checks for max returns, branch, return in __init__ |
298 """ | 275 """ |
299 returns = self._returns.pop() | 276 returns = self._returns.pop() |
300 if returns > self.config.max_returns: | 277 if returns > self.config.max_returns: |
301 self.add_message('too-many-return-statements', node=node, | 278 self.add_message('R0911', node=node, |
302 args=(returns, self.config.max_returns)) | 279 args=(returns, self.config.max_returns)) |
303 branches = self._branches.pop() | 280 branchs = self._branchs.pop() |
304 if branches > self.config.max_branches: | 281 if branchs > self.config.max_branchs: |
305 self.add_message('too-many-branches', node=node, | 282 self.add_message('R0912', node=node, |
306 args=(branches, self.config.max_branches)) | 283 args=(branchs, self.config.max_branchs)) |
307 # check number of statements | 284 # check number of statements |
308 if self._stmts > self.config.max_statements: | 285 if self._stmts > self.config.max_statements: |
309 self.add_message('too-many-statements', node=node, | 286 self.add_message('R0915', node=node, |
310 args=(self._stmts, self.config.max_statements)) | 287 args=(self._stmts, self.config.max_statements)) |
311 | 288 |
312 def visit_return(self, _): | 289 def visit_return(self, _): |
313 """count number of returns""" | 290 """count number of returns""" |
314 if not self._returns: | 291 if not self._returns: |
315 return # return outside function, reported by the base checker | 292 return # return outside function, reported by the base checker |
316 self._returns[-1] += 1 | 293 self._returns[-1] += 1 |
317 | 294 |
318 def visit_default(self, node): | 295 def visit_default(self, node): |
319 """default visit method -> increments the statements counter if | 296 """default visit method -> increments the statements counter if |
320 necessary | 297 necessary |
321 """ | 298 """ |
322 if node.is_statement: | 299 if node.is_statement: |
323 self._stmts += 1 | 300 self._stmts += 1 |
324 | 301 |
325 def visit_tryexcept(self, node): | 302 def visit_tryexcept(self, node): |
326 """increments the branches counter""" | 303 """increments the branchs counter""" |
327 branches = len(node.handlers) | 304 branchs = len(node.handlers) |
328 if node.orelse: | 305 if node.orelse: |
329 branches += 1 | 306 branchs += 1 |
330 self._inc_branch(branches) | 307 self._inc_branch(branchs) |
331 self._stmts += branches | 308 self._stmts += branchs |
332 | 309 |
333 def visit_tryfinally(self, _): | 310 def visit_tryfinally(self, _): |
334 """increments the branches counter""" | 311 """increments the branchs counter""" |
335 self._inc_branch(2) | 312 self._inc_branch(2) |
336 self._stmts += 2 | 313 self._stmts += 2 |
337 | 314 |
338 def visit_if(self, node): | 315 def visit_if(self, node): |
339 """increments the branches counter""" | 316 """increments the branchs counter""" |
340 branches = 1 | 317 branchs = 1 |
341 # don't double count If nodes coming from some 'elif' | 318 # don't double count If nodes coming from some 'elif' |
342 if node.orelse and (len(node.orelse) > 1 or | 319 if node.orelse and (len(node.orelse)>1 or |
343 not isinstance(node.orelse[0], If)): | 320 not isinstance(node.orelse[0], If)): |
344 branches += 1 | 321 branchs += 1 |
345 self._inc_branch(branches) | 322 self._inc_branch(branchs) |
346 self._stmts += branches | 323 self._stmts += branchs |
347 | 324 |
348 def visit_while(self, node): | 325 def visit_while(self, node): |
349 """increments the branches counter""" | 326 """increments the branchs counter""" |
350 branches = 1 | 327 branchs = 1 |
351 if node.orelse: | 328 if node.orelse: |
352 branches += 1 | 329 branchs += 1 |
353 self._inc_branch(branches) | 330 self._inc_branch(branchs) |
354 | 331 |
355 visit_for = visit_while | 332 visit_for = visit_while |
356 | 333 |
357 def _inc_branch(self, branchesnum=1): | 334 def _inc_branch(self, branchsnum=1): |
358 """increments the branches counter""" | 335 """increments the branchs counter""" |
359 branches = self._branches | 336 branchs = self._branchs |
360 for i in xrange(len(branches)): | 337 for i in xrange(len(branchs)): |
361 branches[i] += branchesnum | 338 branchs[i] += branchsnum |
362 | 339 |
363 # FIXME: make a nice report... | 340 # FIXME: make a nice report... |
364 | 341 |
365 def register(linter): | 342 def register(linter): |
366 """required method to auto register this checker """ | 343 """required method to auto register this checker """ |
367 linter.register_checker(MisdesignChecker(linter)) | 344 linter.register_checker(MisdesignChecker(linter)) |
OLD | NEW |