OLD | NEW |
1 #!/usr/bin/python2.4 | 1 #!/usr/bin/python2.4 |
2 # | 2 # |
3 # cpplint.py is Copyright (C) 2009 Google Inc. | 3 # Copyright (c) 2009 Google Inc. All rights reserved. |
4 # | 4 # |
5 # It is free software; you can redistribute it and/or modify it under the | 5 # Redistribution and use in source and binary forms, with or without |
6 # terms of either: | 6 # modification, are permitted provided that the following conditions are |
| 7 # met: |
7 # | 8 # |
8 # a) the GNU General Public License as published by the Free Software | 9 # * Redistributions of source code must retain the above copyright |
9 # Foundation; either version 1, or (at your option) any later version, or | 10 # notice, this list of conditions and the following disclaimer. |
| 11 # * Redistributions in binary form must reproduce the above |
| 12 # copyright notice, this list of conditions and the following disclaimer |
| 13 # in the documentation and/or other materials provided with the |
| 14 # distribution. |
| 15 # * Neither the name of Google Inc. nor the names of its |
| 16 # contributors may be used to endorse or promote products derived from |
| 17 # this software without specific prior written permission. |
10 # | 18 # |
11 # b) the "Artistic License". | 19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
12 | 30 |
13 # Here are some issues that I've had people identify in my code during reviews, | 31 # Here are some issues that I've had people identify in my code during reviews, |
14 # that I think are possible to flag automatically in a lint tool. If these were | 32 # that I think are possible to flag automatically in a lint tool. If these were |
15 # caught by lint, it would save time both for myself and that of my reviewers. | 33 # caught by lint, it would save time both for myself and that of my reviewers. |
16 # Most likely, some of these are beyond the scope of the current lint framework, | 34 # Most likely, some of these are beyond the scope of the current lint framework, |
17 # but I think it is valuable to retain these wish-list items even if they cannot | 35 # but I think it is valuable to retain these wish-list items even if they cannot |
18 # be immediately implemented. | 36 # be immediately implemented. |
19 # | 37 # |
20 # Suggestions | 38 # Suggestions |
21 # ----------- | 39 # ----------- |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 import os | 85 import os |
68 import re | 86 import re |
69 import sre_compile | 87 import sre_compile |
70 import string | 88 import string |
71 import sys | 89 import sys |
72 import unicodedata | 90 import unicodedata |
73 | 91 |
74 | 92 |
75 _USAGE = """ | 93 _USAGE = """ |
76 Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...] | 94 Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...] |
| 95 [--counting=total|toplevel|detailed] |
77 <file> [file] ... | 96 <file> [file] ... |
78 | 97 |
79 The style guidelines this tries to follow are those in | 98 The style guidelines this tries to follow are those in |
80 http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml | 99 http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml |
81 | 100 |
82 Every problem is given a confidence score from 1-5, with 5 meaning we are | 101 Every problem is given a confidence score from 1-5, with 5 meaning we are |
83 certain of the problem, and 1 meaning it could be a legitimate construct. | 102 certain of the problem, and 1 meaning it could be a legitimate construct. |
84 This will miss some errors, and is not a substitute for a code review. | 103 This will miss some errors, and is not a substitute for a code review. |
85 | 104 |
86 To prevent specific lines from being linted, add a '// NOLINT' comment to the | 105 To prevent specific lines from being linted, add a '// NOLINT' comment to the |
(...skipping 18 matching lines...) Expand all Loading... |
105 "[whitespace/indent]".) Filters are evaluated left to right. | 124 "[whitespace/indent]".) Filters are evaluated left to right. |
106 "-FOO" and "FOO" means "do not print categories that start with FOO". | 125 "-FOO" and "FOO" means "do not print categories that start with FOO". |
107 "+FOO" means "do print categories that start with FOO". | 126 "+FOO" means "do print categories that start with FOO". |
108 | 127 |
109 Examples: --filter=-whitespace,+whitespace/braces | 128 Examples: --filter=-whitespace,+whitespace/braces |
110 --filter=whitespace,runtime/printf,+runtime/printf_format | 129 --filter=whitespace,runtime/printf,+runtime/printf_format |
111 --filter=-,+build/include_what_you_use | 130 --filter=-,+build/include_what_you_use |
112 | 131 |
113 To see a list of all the categories used in cpplint, pass no arg: | 132 To see a list of all the categories used in cpplint, pass no arg: |
114 --filter= | 133 --filter= |
| 134 |
| 135 counting=total|toplevel|detailed |
| 136 The total number of errors found is always printed. If |
| 137 'toplevel' is provided, then the count of errors in each of |
| 138 the top-level categories like 'build' and 'whitespace' will |
| 139 also be printed. If 'detailed' is provided, then a count |
| 140 is provided for each category like 'build/class'. |
115 """ | 141 """ |
116 | 142 |
117 # We categorize each error message we print. Here are the categories. | 143 # We categorize each error message we print. Here are the categories. |
118 # We want an explicit list so we can list them all in cpplint --filter=. | 144 # We want an explicit list so we can list them all in cpplint --filter=. |
119 # If you add a new error message with a new category, add it to the list | 145 # If you add a new error message with a new category, add it to the list |
120 # here! cpplint_unittest.py should tell you if you forget to do this. | 146 # here! cpplint_unittest.py should tell you if you forget to do this. |
121 # \ used for clearer layout -- pylint: disable-msg=C6013 | 147 # \ used for clearer layout -- pylint: disable-msg=C6013 |
122 _ERROR_CATEGORIES = '''\ | 148 _ERROR_CATEGORIES = '''\ |
123 build/class | 149 build/class |
124 build/deprecated | 150 build/deprecated |
125 build/endif_comment | 151 build/endif_comment |
126 build/forward_decl | 152 build/forward_decl |
127 build/header_guard | 153 build/header_guard |
128 build/include | 154 build/include |
| 155 build/include_alpha |
129 build/include_order | 156 build/include_order |
130 build/include_what_you_use | 157 build/include_what_you_use |
131 build/namespaces | 158 build/namespaces |
132 build/printf_format | 159 build/printf_format |
133 build/storage_class | 160 build/storage_class |
134 legal/copyright | 161 legal/copyright |
135 readability/braces | 162 readability/braces |
136 readability/casting | 163 readability/casting |
137 readability/check | 164 readability/check |
138 readability/constructors | 165 readability/constructors |
139 readability/fn_size | 166 readability/fn_size |
140 readability/function | 167 readability/function |
141 readability/multiline_comment | 168 readability/multiline_comment |
142 readability/multiline_string | 169 readability/multiline_string |
143 readability/streams | 170 readability/streams |
144 readability/todo | 171 readability/todo |
145 readability/utf8 | 172 readability/utf8 |
146 runtime/arrays | 173 runtime/arrays |
147 runtime/casting | 174 runtime/casting |
148 runtime/explicit | 175 runtime/explicit |
149 runtime/int | 176 runtime/int |
150 runtime/init | 177 runtime/init |
151 runtime/invalid_increment | 178 runtime/invalid_increment |
| 179 runtime/member_string_references |
152 runtime/memset | 180 runtime/memset |
| 181 runtime/operator |
153 runtime/printf | 182 runtime/printf |
154 runtime/printf_format | 183 runtime/printf_format |
155 runtime/references | 184 runtime/references |
156 runtime/rtti | 185 runtime/rtti |
157 runtime/sizeof | 186 runtime/sizeof |
158 runtime/string | 187 runtime/string |
159 runtime/threadsafe_fn | 188 runtime/threadsafe_fn |
160 runtime/virtual | 189 runtime/virtual |
161 whitespace/blank_line | 190 whitespace/blank_line |
162 whitespace/braces | 191 whitespace/braces |
163 whitespace/comma | 192 whitespace/comma |
164 whitespace/comments | 193 whitespace/comments |
165 whitespace/end_of_line | 194 whitespace/end_of_line |
166 whitespace/ending_newline | 195 whitespace/ending_newline |
167 whitespace/indent | 196 whitespace/indent |
168 whitespace/labels | 197 whitespace/labels |
169 whitespace/line_length | 198 whitespace/line_length |
170 whitespace/newline | 199 whitespace/newline |
171 whitespace/operators | 200 whitespace/operators |
172 whitespace/parens | 201 whitespace/parens |
173 whitespace/semicolon | 202 whitespace/semicolon |
174 whitespace/tab | 203 whitespace/tab |
175 whitespace/todo | 204 whitespace/todo |
176 ''' | 205 ''' |
177 | 206 |
178 # The default state of the category filter. This is overrided by the --filter= | 207 # The default state of the category filter. This is overrided by the --filter= |
179 # flag. By default all errors are on, so only add here categories that should be | 208 # flag. By default all errors are on, so only add here categories that should be |
180 # off by default (i.e., categories that must be enabled by the --filter= flags). | 209 # off by default (i.e., categories that must be enabled by the --filter= flags). |
181 # All entries here should start with a '-' or '+', as in the --filter= flag. | 210 # All entries here should start with a '-' or '+', as in the --filter= flag. |
182 _DEFAULT_FILTERS = [] | 211 _DEFAULT_FILTERS = [ '-build/include_alpha' ] |
183 | 212 |
184 # We used to check for high-bit characters, but after much discussion we | 213 # We used to check for high-bit characters, but after much discussion we |
185 # decided those were OK, as long as they were in UTF-8 and didn't represent | 214 # decided those were OK, as long as they were in UTF-8 and didn't represent |
186 # hard-coded international strings, which belong in a seperate i18n file. | 215 # hard-coded international strings, which belong in a seperate i18n file. |
187 | 216 |
188 # Headers that we consider STL headers. | 217 # Headers that we consider STL headers. |
189 _STL_HEADERS = frozenset([ | 218 _STL_HEADERS = frozenset([ |
190 'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception', | 219 'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception', |
191 'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set', | 220 'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set', |
192 'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'pair.h', | 221 'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'pair.h', |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
305 _SECTION_NAMES = { | 334 _SECTION_NAMES = { |
306 _INITIAL_SECTION: "... nothing. (This can't be an error.)", | 335 _INITIAL_SECTION: "... nothing. (This can't be an error.)", |
307 _MY_H_SECTION: 'a header this file implements', | 336 _MY_H_SECTION: 'a header this file implements', |
308 _C_SECTION: 'C system header', | 337 _C_SECTION: 'C system header', |
309 _CPP_SECTION: 'C++ system header', | 338 _CPP_SECTION: 'C++ system header', |
310 _OTHER_H_SECTION: 'other header', | 339 _OTHER_H_SECTION: 'other header', |
311 } | 340 } |
312 | 341 |
313 def __init__(self): | 342 def __init__(self): |
314 dict.__init__(self) | 343 dict.__init__(self) |
| 344 # The name of the current section. |
315 self._section = self._INITIAL_SECTION | 345 self._section = self._INITIAL_SECTION |
| 346 # The path of last found header. |
| 347 self._last_header = '' |
| 348 |
| 349 def CanonicalizeAlphabeticalOrder(self, header_path): |
| 350 """Returns a path canonicalized for alphabetical comparisson. |
| 351 |
| 352 - replaces "-" with "_" so they both cmp the same. |
| 353 - removes '-inl' since we don't require them to be after the main header. |
| 354 - lowercase everything, just in case. |
| 355 |
| 356 Args: |
| 357 header_path: Path to be canonicalized. |
| 358 |
| 359 Returns: |
| 360 Canonicalized path. |
| 361 """ |
| 362 return header_path.replace('-inl.h', '.h').replace('-', '_').lower() |
| 363 |
| 364 def IsInAlphabeticalOrder(self, header_path): |
| 365 """Check if a header is in alphabetical order with the previous header. |
| 366 |
| 367 Args: |
| 368 header_path: Header to be checked. |
| 369 |
| 370 Returns: |
| 371 Returns true if the header is in alphabetical order. |
| 372 """ |
| 373 canonical_header = self.CanonicalizeAlphabeticalOrder(header_path) |
| 374 if self._last_header > canonical_header: |
| 375 return False |
| 376 self._last_header = canonical_header |
| 377 return True |
316 | 378 |
317 def CheckNextIncludeOrder(self, header_type): | 379 def CheckNextIncludeOrder(self, header_type): |
318 """Returns a non-empty error message if the next header is out of order. | 380 """Returns a non-empty error message if the next header is out of order. |
319 | 381 |
320 This function also updates the internal state to be ready to check | 382 This function also updates the internal state to be ready to check |
321 the next include. | 383 the next include. |
322 | 384 |
323 Args: | 385 Args: |
324 header_type: One of the _XXX_HEADER constants defined above. | 386 header_type: One of the _XXX_HEADER constants defined above. |
325 | 387 |
326 Returns: | 388 Returns: |
327 The empty string if the header is in the right order, or an | 389 The empty string if the header is in the right order, or an |
328 error message describing what's wrong. | 390 error message describing what's wrong. |
329 | 391 |
330 """ | 392 """ |
331 error_message = ('Found %s after %s' % | 393 error_message = ('Found %s after %s' % |
332 (self._TYPE_NAMES[header_type], | 394 (self._TYPE_NAMES[header_type], |
333 self._SECTION_NAMES[self._section])) | 395 self._SECTION_NAMES[self._section])) |
334 | 396 |
| 397 last_section = self._section |
| 398 |
335 if header_type == _C_SYS_HEADER: | 399 if header_type == _C_SYS_HEADER: |
336 if self._section <= self._C_SECTION: | 400 if self._section <= self._C_SECTION: |
337 self._section = self._C_SECTION | 401 self._section = self._C_SECTION |
338 else: | 402 else: |
| 403 self._last_header = '' |
339 return error_message | 404 return error_message |
340 elif header_type == _CPP_SYS_HEADER: | 405 elif header_type == _CPP_SYS_HEADER: |
341 if self._section <= self._CPP_SECTION: | 406 if self._section <= self._CPP_SECTION: |
342 self._section = self._CPP_SECTION | 407 self._section = self._CPP_SECTION |
343 else: | 408 else: |
| 409 self._last_header = '' |
344 return error_message | 410 return error_message |
345 elif header_type == _LIKELY_MY_HEADER: | 411 elif header_type == _LIKELY_MY_HEADER: |
346 if self._section <= self._MY_H_SECTION: | 412 if self._section <= self._MY_H_SECTION: |
347 self._section = self._MY_H_SECTION | 413 self._section = self._MY_H_SECTION |
348 else: | 414 else: |
349 self._section = self._OTHER_H_SECTION | 415 self._section = self._OTHER_H_SECTION |
350 elif header_type == _POSSIBLE_MY_HEADER: | 416 elif header_type == _POSSIBLE_MY_HEADER: |
351 if self._section <= self._MY_H_SECTION: | 417 if self._section <= self._MY_H_SECTION: |
352 self._section = self._MY_H_SECTION | 418 self._section = self._MY_H_SECTION |
353 else: | 419 else: |
354 # This will always be the fallback because we're not sure | 420 # This will always be the fallback because we're not sure |
355 # enough that the header is associated with this file. | 421 # enough that the header is associated with this file. |
356 self._section = self._OTHER_H_SECTION | 422 self._section = self._OTHER_H_SECTION |
357 else: | 423 else: |
358 assert header_type == _OTHER_HEADER | 424 assert header_type == _OTHER_HEADER |
359 self._section = self._OTHER_H_SECTION | 425 self._section = self._OTHER_H_SECTION |
360 | 426 |
| 427 if last_section != self._section: |
| 428 self._last_header = '' |
| 429 |
361 return '' | 430 return '' |
362 | 431 |
363 | 432 |
364 class _CppLintState(object): | 433 class _CppLintState(object): |
365 """Maintains module-wide state..""" | 434 """Maintains module-wide state..""" |
366 | 435 |
367 def __init__(self): | 436 def __init__(self): |
368 self.verbose_level = 1 # global setting. | 437 self.verbose_level = 1 # global setting. |
369 self.error_count = 0 # global count of reported errors | 438 self.error_count = 0 # global count of reported errors |
370 # filters to apply when emitting error messages | 439 # filters to apply when emitting error messages |
371 self.filters = _DEFAULT_FILTERS[:] | 440 self.filters = _DEFAULT_FILTERS[:] |
| 441 self.counting = 'total' # In what way are we counting errors? |
| 442 self.errors_by_category = {} # string to int dict storing error counts |
372 | 443 |
373 # output format: | 444 # output format: |
374 # "emacs" - format that emacs can parse (default) | 445 # "emacs" - format that emacs can parse (default) |
375 # "vs7" - format that Microsoft Visual Studio 7 can parse | 446 # "vs7" - format that Microsoft Visual Studio 7 can parse |
376 self.output_format = 'emacs' | 447 self.output_format = 'emacs' |
377 | 448 |
378 def SetOutputFormat(self, output_format): | 449 def SetOutputFormat(self, output_format): |
379 """Sets the output format for errors.""" | 450 """Sets the output format for errors.""" |
380 self.output_format = output_format | 451 self.output_format = output_format |
381 | 452 |
382 def SetVerboseLevel(self, level): | 453 def SetVerboseLevel(self, level): |
383 """Sets the module's verbosity, and returns the previous setting.""" | 454 """Sets the module's verbosity, and returns the previous setting.""" |
384 last_verbose_level = self.verbose_level | 455 last_verbose_level = self.verbose_level |
385 self.verbose_level = level | 456 self.verbose_level = level |
386 return last_verbose_level | 457 return last_verbose_level |
387 | 458 |
| 459 def SetCountingStyle(self, counting_style): |
| 460 """Sets the module's counting options.""" |
| 461 self.counting = counting_style |
| 462 |
388 def SetFilters(self, filters): | 463 def SetFilters(self, filters): |
389 """Sets the error-message filters. | 464 """Sets the error-message filters. |
390 | 465 |
391 These filters are applied when deciding whether to emit a given | 466 These filters are applied when deciding whether to emit a given |
392 error message. | 467 error message. |
393 | 468 |
394 Args: | 469 Args: |
395 filters: A string of comma-separated filters (eg "+whitespace/indent"). | 470 filters: A string of comma-separated filters (eg "+whitespace/indent"). |
396 Each filter should start with + or -; else we die. | 471 Each filter should start with + or -; else we die. |
397 | 472 |
398 Raises: | 473 Raises: |
399 ValueError: The comma-separated filters did not all start with '+' or '-'. | 474 ValueError: The comma-separated filters did not all start with '+' or '-'. |
400 E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter" | 475 E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter" |
401 """ | 476 """ |
402 # Default filters always have less priority than the flag ones. | 477 # Default filters always have less priority than the flag ones. |
403 self.filters = _DEFAULT_FILTERS[:] | 478 self.filters = _DEFAULT_FILTERS[:] |
404 for filt in filters.split(','): | 479 for filt in filters.split(','): |
405 clean_filt = filt.strip() | 480 clean_filt = filt.strip() |
406 if clean_filt: | 481 if clean_filt: |
407 self.filters.append(clean_filt) | 482 self.filters.append(clean_filt) |
408 for filt in self.filters: | 483 for filt in self.filters: |
409 if not (filt.startswith('+') or filt.startswith('-')): | 484 if not (filt.startswith('+') or filt.startswith('-')): |
410 raise ValueError('Every filter in --filters must start with + or -' | 485 raise ValueError('Every filter in --filters must start with + or -' |
411 ' (%s does not)' % filt) | 486 ' (%s does not)' % filt) |
412 | 487 |
413 def ResetErrorCount(self): | 488 def ResetErrorCounts(self): |
414 """Sets the module's error statistic back to zero.""" | 489 """Sets the module's error statistic back to zero.""" |
415 self.error_count = 0 | 490 self.error_count = 0 |
| 491 self.errors_by_category = {} |
416 | 492 |
417 def IncrementErrorCount(self): | 493 def IncrementErrorCount(self, category): |
418 """Bumps the module's error statistic.""" | 494 """Bumps the module's error statistic.""" |
419 self.error_count += 1 | 495 self.error_count += 1 |
| 496 if self.counting in ('toplevel', 'detailed'): |
| 497 if self.counting != 'detailed': |
| 498 category = category.split('/')[0] |
| 499 if category not in self.errors_by_category: |
| 500 self.errors_by_category[category] = 0 |
| 501 self.errors_by_category[category] += 1 |
420 | 502 |
| 503 def PrintErrorCounts(self): |
| 504 """Print a summary of errors by category, and the total.""" |
| 505 for category, count in self.errors_by_category.iteritems(): |
| 506 sys.stderr.write('Category \'%s\' errors found: %d\n' % |
| 507 (category, count)) |
| 508 sys.stderr.write('Total errors found: %d\n' % self.error_count) |
421 | 509 |
422 _cpplint_state = _CppLintState() | 510 _cpplint_state = _CppLintState() |
423 | 511 |
424 | 512 |
425 def _OutputFormat(): | 513 def _OutputFormat(): |
426 """Gets the module's output format.""" | 514 """Gets the module's output format.""" |
427 return _cpplint_state.output_format | 515 return _cpplint_state.output_format |
428 | 516 |
429 | 517 |
430 def _SetOutputFormat(output_format): | 518 def _SetOutputFormat(output_format): |
431 """Sets the module's output format.""" | 519 """Sets the module's output format.""" |
432 _cpplint_state.SetOutputFormat(output_format) | 520 _cpplint_state.SetOutputFormat(output_format) |
433 | 521 |
434 | 522 |
435 def _VerboseLevel(): | 523 def _VerboseLevel(): |
436 """Returns the module's verbosity setting.""" | 524 """Returns the module's verbosity setting.""" |
437 return _cpplint_state.verbose_level | 525 return _cpplint_state.verbose_level |
438 | 526 |
439 | 527 |
440 def _SetVerboseLevel(level): | 528 def _SetVerboseLevel(level): |
441 """Sets the module's verbosity, and returns the previous setting.""" | 529 """Sets the module's verbosity, and returns the previous setting.""" |
442 return _cpplint_state.SetVerboseLevel(level) | 530 return _cpplint_state.SetVerboseLevel(level) |
443 | 531 |
444 | 532 |
| 533 def _SetCountingStyle(level): |
| 534 """Sets the module's counting options.""" |
| 535 _cpplint_state.SetCountingStyle(level) |
| 536 |
| 537 |
445 def _Filters(): | 538 def _Filters(): |
446 """Returns the module's list of output filters, as a list.""" | 539 """Returns the module's list of output filters, as a list.""" |
447 return _cpplint_state.filters | 540 return _cpplint_state.filters |
448 | 541 |
449 | 542 |
450 def _SetFilters(filters): | 543 def _SetFilters(filters): |
451 """Sets the module's error-message filters. | 544 """Sets the module's error-message filters. |
452 | 545 |
453 These filters are applied when deciding whether to emit a given | 546 These filters are applied when deciding whether to emit a given |
454 error message. | 547 error message. |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
643 falls under: "whitespace", say, or "runtime". Categories | 736 falls under: "whitespace", say, or "runtime". Categories |
644 may have a hierarchy separated by slashes: "whitespace/indent". | 737 may have a hierarchy separated by slashes: "whitespace/indent". |
645 confidence: A number from 1-5 representing a confidence score for | 738 confidence: A number from 1-5 representing a confidence score for |
646 the error, with 5 meaning that we are certain of the problem, | 739 the error, with 5 meaning that we are certain of the problem, |
647 and 1 meaning that it could be a legitimate construct. | 740 and 1 meaning that it could be a legitimate construct. |
648 message: The error message. | 741 message: The error message. |
649 """ | 742 """ |
650 # There are two ways we might decide not to print an error message: | 743 # There are two ways we might decide not to print an error message: |
651 # the verbosity level isn't high enough, or the filters filter it out. | 744 # the verbosity level isn't high enough, or the filters filter it out. |
652 if _ShouldPrintError(category, confidence): | 745 if _ShouldPrintError(category, confidence): |
653 _cpplint_state.IncrementErrorCount() | 746 _cpplint_state.IncrementErrorCount(category) |
654 if _cpplint_state.output_format == 'vs7': | 747 if _cpplint_state.output_format == 'vs7': |
655 sys.stderr.write('%s(%s): %s [%s] [%d]\n' % ( | 748 sys.stderr.write('%s(%s): %s [%s] [%d]\n' % ( |
656 filename, linenum, message, category, confidence)) | 749 filename, linenum, message, category, confidence)) |
657 else: | 750 else: |
658 sys.stderr.write('%s:%s: %s [%s] [%d]\n' % ( | 751 sys.stderr.write('%s:%s: %s [%s] [%d]\n' % ( |
659 filename, linenum, message, category, confidence)) | 752 filename, linenum, message, category, confidence)) |
660 | 753 |
661 | 754 |
662 # Matches standard C++ escape esequences per 2.13.2.3 of the C++ standard. | 755 # Matches standard C++ escape esequences per 2.13.2.3 of the C++ standard. |
663 _RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile( | 756 _RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile( |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
906 endif_linenum = linenum | 999 endif_linenum = linenum |
907 | 1000 |
908 if not ifndef or not define or ifndef != define: | 1001 if not ifndef or not define or ifndef != define: |
909 error(filename, 0, 'build/header_guard', 5, | 1002 error(filename, 0, 'build/header_guard', 5, |
910 'No #ifndef header guard found, suggested CPP variable is: %s' % | 1003 'No #ifndef header guard found, suggested CPP variable is: %s' % |
911 cppvar) | 1004 cppvar) |
912 return | 1005 return |
913 | 1006 |
914 # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__ | 1007 # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__ |
915 # for backward compatibility. | 1008 # for backward compatibility. |
916 if ifndef != cppvar: | 1009 if ifndef != cppvar and not Search(r'\bNOLINT\b', lines[ifndef_linenum]): |
917 error_level = 0 | 1010 error_level = 0 |
918 if ifndef != cppvar + '_': | 1011 if ifndef != cppvar + '_': |
919 error_level = 5 | 1012 error_level = 5 |
920 | 1013 |
921 error(filename, ifndef_linenum, 'build/header_guard', error_level, | 1014 error(filename, ifndef_linenum, 'build/header_guard', error_level, |
922 '#ifndef header guard has wrong style, please use: %s' % cppvar) | 1015 '#ifndef header guard has wrong style, please use: %s' % cppvar) |
923 | 1016 |
924 if endif != ('#endif // %s' % cppvar): | 1017 if (endif != ('#endif // %s' % cppvar) and |
| 1018 not Search(r'\bNOLINT\b', lines[endif_linenum])): |
925 error_level = 0 | 1019 error_level = 0 |
926 if endif != ('#endif // %s' % (cppvar + '_')): | 1020 if endif != ('#endif // %s' % (cppvar + '_')): |
927 error_level = 5 | 1021 error_level = 5 |
928 | 1022 |
929 error(filename, endif_linenum, 'build/header_guard', error_level, | 1023 error(filename, endif_linenum, 'build/header_guard', error_level, |
930 '#endif line should be "#endif // %s"' % cppvar) | 1024 '#endif line should be "#endif // %s"' % cppvar) |
931 | 1025 |
932 | 1026 |
933 def CheckForUnicodeReplacementCharacters(filename, lines, error): | 1027 def CheckForUnicodeReplacementCharacters(filename, lines, error): |
934 """Logs an error for each line containing Unicode replacement characters. | 1028 """Logs an error for each line containing Unicode replacement characters. |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1042 ix = line.find(single_thread_function) | 1136 ix = line.find(single_thread_function) |
1043 # Comparisons made explicit for clarity -- pylint: disable-msg=C6403 | 1137 # Comparisons made explicit for clarity -- pylint: disable-msg=C6403 |
1044 if ix >= 0 and (ix == 0 or (not line[ix - 1].isalnum() and | 1138 if ix >= 0 and (ix == 0 or (not line[ix - 1].isalnum() and |
1045 line[ix - 1] not in ('_', '.', '>'))): | 1139 line[ix - 1] not in ('_', '.', '>'))): |
1046 error(filename, linenum, 'runtime/threadsafe_fn', 2, | 1140 error(filename, linenum, 'runtime/threadsafe_fn', 2, |
1047 'Consider using ' + multithread_safe_function + | 1141 'Consider using ' + multithread_safe_function + |
1048 '...) instead of ' + single_thread_function + | 1142 '...) instead of ' + single_thread_function + |
1049 '...) for improved thread safety.') | 1143 '...) for improved thread safety.') |
1050 | 1144 |
1051 | 1145 |
1052 # Matches invalid increment: *count++, which moves pointer insead of | 1146 # Matches invalid increment: *count++, which moves pointer instead of |
1053 # incrementing a value. | 1147 # incrementing a value. |
1054 _RE_PATTERN_IVALID_INCREMENT = re.compile( | 1148 _RE_PATTERN_INVALID_INCREMENT = re.compile( |
1055 r'^\s*\*\w+(\+\+|--);') | 1149 r'^\s*\*\w+(\+\+|--);') |
1056 | 1150 |
1057 | 1151 |
1058 def CheckInvalidIncrement(filename, clean_lines, linenum, error): | 1152 def CheckInvalidIncrement(filename, clean_lines, linenum, error): |
1059 """Checks for invalud increment *count++. | 1153 """Checks for invalid increment *count++. |
1060 | 1154 |
1061 For example following function: | 1155 For example following function: |
1062 void increment_counter(int* count) { | 1156 void increment_counter(int* count) { |
1063 *count++; | 1157 *count++; |
1064 } | 1158 } |
1065 is invalid, because it effectively does count++, moving pointer, and should | 1159 is invalid, because it effectively does count++, moving pointer, and should |
1066 be replaced with ++*count, (*count)++ or *count += 1. | 1160 be replaced with ++*count, (*count)++ or *count += 1. |
1067 | 1161 |
1068 Args: | 1162 Args: |
1069 filename: The name of the current file. | 1163 filename: The name of the current file. |
1070 clean_lines: A CleansedLines instance containing the file. | 1164 clean_lines: A CleansedLines instance containing the file. |
1071 linenum: The number of the line to check. | 1165 linenum: The number of the line to check. |
1072 error: The function to call with any errors found. | 1166 error: The function to call with any errors found. |
1073 """ | 1167 """ |
1074 line = clean_lines.elided[linenum] | 1168 line = clean_lines.elided[linenum] |
1075 if _RE_PATTERN_IVALID_INCREMENT.match(line): | 1169 if _RE_PATTERN_INVALID_INCREMENT.match(line): |
1076 error(filename, linenum, 'runtime/invalid_increment', 5, | 1170 error(filename, linenum, 'runtime/invalid_increment', 5, |
1077 'Changing pointer instead of value (or unused value of operator*).') | 1171 'Changing pointer instead of value (or unused value of operator*).') |
1078 | 1172 |
1079 | 1173 |
1080 class _ClassInfo(object): | 1174 class _ClassInfo(object): |
1081 """Stores information about a class.""" | 1175 """Stores information about a class.""" |
1082 | 1176 |
1083 def __init__(self, name, linenum): | 1177 def __init__(self, name, linenum): |
1084 self.name = name | 1178 self.name = name |
1085 self.linenum = linenum | 1179 self.linenum = linenum |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1129 - put storage class first (e.g. "static const" instead of "const static"). | 1223 - put storage class first (e.g. "static const" instead of "const static"). |
1130 - "%lld" instead of %qd" in printf-type functions. | 1224 - "%lld" instead of %qd" in printf-type functions. |
1131 - "%1$d" is non-standard in printf-type functions. | 1225 - "%1$d" is non-standard in printf-type functions. |
1132 - "\%" is an undefined character escape sequence. | 1226 - "\%" is an undefined character escape sequence. |
1133 - text after #endif is not allowed. | 1227 - text after #endif is not allowed. |
1134 - invalid inner-style forward declaration. | 1228 - invalid inner-style forward declaration. |
1135 - >? and <? operators, and their >?= and <?= cousins. | 1229 - >? and <? operators, and their >?= and <?= cousins. |
1136 - classes with virtual methods need virtual destructors (compiler warning | 1230 - classes with virtual methods need virtual destructors (compiler warning |
1137 available, but not turned on yet.) | 1231 available, but not turned on yet.) |
1138 | 1232 |
1139 Additionally, check for constructor/destructor style violations as it | 1233 Additionally, check for constructor/destructor style violations and reference |
1140 is very convenient to do so while checking for gcc-2 compliance. | 1234 members, as it is very convenient to do so while checking for |
| 1235 gcc-2 compliance. |
1141 | 1236 |
1142 Args: | 1237 Args: |
1143 filename: The name of the current file. | 1238 filename: The name of the current file. |
1144 clean_lines: A CleansedLines instance containing the file. | 1239 clean_lines: A CleansedLines instance containing the file. |
1145 linenum: The number of the line to check. | 1240 linenum: The number of the line to check. |
1146 class_state: A _ClassState instance which maintains information about | 1241 class_state: A _ClassState instance which maintains information about |
1147 the current stack of nested class declarations being parsed. | 1242 the current stack of nested class declarations being parsed. |
1148 error: A callable to which errors are reported, which takes 4 arguments: | 1243 error: A callable to which errors are reported, which takes 4 arguments: |
1149 filename, line number, error level, and message | 1244 filename, line number, error level, and message |
1150 """ | 1245 """ |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1184 | 1279 |
1185 if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line): | 1280 if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line): |
1186 error(filename, linenum, 'build/forward_decl', 5, | 1281 error(filename, linenum, 'build/forward_decl', 5, |
1187 'Inner-style forward declarations are invalid. Remove this line.') | 1282 'Inner-style forward declarations are invalid. Remove this line.') |
1188 | 1283 |
1189 if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?', | 1284 if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?', |
1190 line): | 1285 line): |
1191 error(filename, linenum, 'build/deprecated', 3, | 1286 error(filename, linenum, 'build/deprecated', 3, |
1192 '>? and <? (max and min) operators are non-standard and deprecated.') | 1287 '>? and <? (max and min) operators are non-standard and deprecated.') |
1193 | 1288 |
| 1289 if Search(r'^\s*const\s*string\s*&\s*\w+\s*;', line): |
| 1290 # TODO(unknown): Could it be expanded safely to arbitrary references, |
| 1291 # without triggering too many false positives? The first |
| 1292 # attempt triggered 5 warnings for mostly benign code in the regtest, hence |
| 1293 # the restriction. |
| 1294 # Here's the original regexp, for the reference: |
| 1295 # type_name = r'\w+((\s*::\s*\w+)|(\s*<\s*\w+?\s*>))?' |
| 1296 # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;' |
| 1297 error(filename, linenum, 'runtime/member_string_references', 2, |
| 1298 'const string& members are dangerous. It is much better to use ' |
| 1299 'alternatives, such as pointers or simple constants.') |
| 1300 |
1194 # Track class entry and exit, and attempt to find cases within the | 1301 # Track class entry and exit, and attempt to find cases within the |
1195 # class declaration that don't meet the C++ style | 1302 # class declaration that don't meet the C++ style |
1196 # guidelines. Tracking is very dependent on the code matching Google | 1303 # guidelines. Tracking is very dependent on the code matching Google |
1197 # style guidelines, but it seems to perform well enough in testing | 1304 # style guidelines, but it seems to perform well enough in testing |
1198 # to be a worthwhile addition to the checks. | 1305 # to be a worthwhile addition to the checks. |
1199 classinfo_stack = class_state.classinfo_stack | 1306 classinfo_stack = class_state.classinfo_stack |
1200 # Look for a class declaration | 1307 # Look for a class declaration |
1201 class_decl_match = Match( | 1308 class_decl_match = Match( |
1202 r'\s*(template\s*<[\w\s<>,:]*>\s*)?(class|struct)\s+(\w+(::\w+)*)', line) | 1309 r'\s*(template\s*<[\w\s<>,:]*>\s*)?(class|struct)\s+(\w+(::\w+)*)', line) |
1203 if class_decl_match: | 1310 if class_decl_match: |
(...skipping 920 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2124 # We classify each include statement as one of those 5 types | 2231 # We classify each include statement as one of those 5 types |
2125 # using a number of techniques. The include_state object keeps | 2232 # using a number of techniques. The include_state object keeps |
2126 # track of the highest type seen, and complains if we see a | 2233 # track of the highest type seen, and complains if we see a |
2127 # lower type after that. | 2234 # lower type after that. |
2128 error_message = include_state.CheckNextIncludeOrder( | 2235 error_message = include_state.CheckNextIncludeOrder( |
2129 _ClassifyInclude(fileinfo, include, is_system)) | 2236 _ClassifyInclude(fileinfo, include, is_system)) |
2130 if error_message: | 2237 if error_message: |
2131 error(filename, linenum, 'build/include_order', 4, | 2238 error(filename, linenum, 'build/include_order', 4, |
2132 '%s. Should be: %s.h, c system, c++ system, other.' % | 2239 '%s. Should be: %s.h, c system, c++ system, other.' % |
2133 (error_message, fileinfo.BaseName())) | 2240 (error_message, fileinfo.BaseName())) |
| 2241 if not include_state.IsInAlphabeticalOrder(include): |
| 2242 error(filename, linenum, 'build/include_alpha', 4, |
| 2243 'Include "%s" not in alphabetical order' % include) |
2134 | 2244 |
2135 # Look for any of the stream classes that are part of standard C++. | 2245 # Look for any of the stream classes that are part of standard C++. |
2136 match = _RE_PATTERN_INCLUDE.match(line) | 2246 match = _RE_PATTERN_INCLUDE.match(line) |
2137 if match: | 2247 if match: |
2138 include = match.group(2) | 2248 include = match.group(2) |
2139 if Match(r'(f|ind|io|i|o|parse|pf|stdio|str|)?stream$', include): | 2249 if Match(r'(f|ind|io|i|o|parse|pf|stdio|str|)?stream$', include): |
2140 # Many unit tests use cout, so we exempt them. | 2250 # Many unit tests use cout, so we exempt them. |
2141 if not _IsTestFilename(filename): | 2251 if not _IsTestFilename(filename): |
2142 error(filename, linenum, 'readability/streams', 3, | 2252 error(filename, linenum, 'readability/streams', 3, |
2143 'Streams are highly discouraged.') | 2253 'Streams are highly discouraged.') |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2202 fnline): | 2312 fnline): |
2203 error(filename, linenum, 'runtime/references', 2, | 2313 error(filename, linenum, 'runtime/references', 2, |
2204 'Is this a non-const reference? ' | 2314 'Is this a non-const reference? ' |
2205 'If so, make const or use a pointer.') | 2315 'If so, make const or use a pointer.') |
2206 | 2316 |
2207 # Check to see if they're using an conversion function cast. | 2317 # Check to see if they're using an conversion function cast. |
2208 # I just try to capture the most common basic types, though there are more. | 2318 # I just try to capture the most common basic types, though there are more. |
2209 # Parameterless conversion functions, such as bool(), are allowed as they are | 2319 # Parameterless conversion functions, such as bool(), are allowed as they are |
2210 # probably a member operator declaration or default constructor. | 2320 # probably a member operator declaration or default constructor. |
2211 match = Search( | 2321 match = Search( |
2212 r'\b(int|float|double|bool|char|int32|uint32|int64|uint64)\([^)]', line) | 2322 r'(\bnew\s+)?\b' # Grab 'new' operator, if it's there |
| 2323 r'(int|float|double|bool|char|int32|uint32|int64|uint64)\([^)]', line) |
2213 if match: | 2324 if match: |
2214 # gMock methods are defined using some variant of MOCK_METHODx(name, type) | 2325 # gMock methods are defined using some variant of MOCK_METHODx(name, type) |
2215 # where type may be float(), int(string), etc. Without context they are | 2326 # where type may be float(), int(string), etc. Without context they are |
2216 # virtually indistinguishable from int(x) casts. | 2327 # virtually indistinguishable from int(x) casts. |
2217 if not Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line): | 2328 if (match.group(1) is None and # If new operator, then this isn't a cast |
| 2329 not Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line)): |
2218 error(filename, linenum, 'readability/casting', 4, | 2330 error(filename, linenum, 'readability/casting', 4, |
2219 'Using deprecated casting style. ' | 2331 'Using deprecated casting style. ' |
2220 'Use static_cast<%s>(...) instead' % | 2332 'Use static_cast<%s>(...) instead' % |
2221 match.group(1)) | 2333 match.group(2)) |
2222 | 2334 |
2223 CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum], | 2335 CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum], |
2224 'static_cast', | 2336 'static_cast', |
2225 r'\((int|float|double|bool|char|u?int(16|32|64))\)', | 2337 r'\((int|float|double|bool|char|u?int(16|32|64))\)', |
2226 error) | 2338 error) |
2227 # This doesn't catch all cases. Consider (const char * const)"hello". | 2339 # This doesn't catch all cases. Consider (const char * const)"hello". |
2228 CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum], | 2340 CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum], |
2229 'reinterpret_cast', r'\((\w+\s?\*+\s?)\)', error) | 2341 'reinterpret_cast', r'\((\w+\s?\*+\s?)\)', error) |
2230 | 2342 |
2231 # In addition, we look for people taking the address of a cast. This | 2343 # In addition, we look for people taking the address of a cast. This |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2298 'Never use sprintf. Use snprintf instead.') | 2410 'Never use sprintf. Use snprintf instead.') |
2299 match = Search(r'\b(strcpy|strcat)\b', line) | 2411 match = Search(r'\b(strcpy|strcat)\b', line) |
2300 if match: | 2412 if match: |
2301 error(filename, linenum, 'runtime/printf', 4, | 2413 error(filename, linenum, 'runtime/printf', 4, |
2302 'Almost always, snprintf is better than %s' % match.group(1)) | 2414 'Almost always, snprintf is better than %s' % match.group(1)) |
2303 | 2415 |
2304 if Search(r'\bsscanf\b', line): | 2416 if Search(r'\bsscanf\b', line): |
2305 error(filename, linenum, 'runtime/printf', 1, | 2417 error(filename, linenum, 'runtime/printf', 1, |
2306 'sscanf can be ok, but is slow and can overflow buffers.') | 2418 'sscanf can be ok, but is slow and can overflow buffers.') |
2307 | 2419 |
| 2420 # Check if some verboten operator overloading is going on |
| 2421 # TODO(unknown): catch out-of-line unary operator&: |
| 2422 # class X {}; |
| 2423 # int operator&(const X& x) { return 42; } // unary operator& |
| 2424 # The trick is it's hard to tell apart from binary operator&: |
| 2425 # class Y { int operator&(const Y& x) { return 23; } }; // binary operator& |
| 2426 if Search(r'\boperator\s*&\s*\(\s*\)', line): |
| 2427 error(filename, linenum, 'runtime/operator', 4, |
| 2428 'Unary operator& is dangerous. Do not use it.') |
| 2429 |
2308 # Check for suspicious usage of "if" like | 2430 # Check for suspicious usage of "if" like |
2309 # } if (a == b) { | 2431 # } if (a == b) { |
2310 if Search(r'\}\s*if\s*\(', line): | 2432 if Search(r'\}\s*if\s*\(', line): |
2311 error(filename, linenum, 'readability/braces', 4, | 2433 error(filename, linenum, 'readability/braces', 4, |
2312 'Did you mean "else if"? If not, start a new line for "if".') | 2434 'Did you mean "else if"? If not, start a new line for "if".') |
2313 | 2435 |
2314 # Check for potential format string bugs like printf(foo). | 2436 # Check for potential format string bugs like printf(foo). |
2315 # We constrain the pattern not to pick things like DocidForPrintf(foo). | 2437 # We constrain the pattern not to pick things like DocidForPrintf(foo). |
2316 # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str()) | 2438 # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str()) |
2317 match = re.search(r'\b((?:string)?printf)\s*\(([\w.\->()]+)\)', line, re.I) | 2439 match = re.search(r'\b((?:string)?printf)\s*\(([\w.\->()]+)\)', line, re.I) |
(...skipping 536 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2854 This may set the output format and verbosity level as side-effects. | 2976 This may set the output format and verbosity level as side-effects. |
2855 | 2977 |
2856 Args: | 2978 Args: |
2857 args: The command line arguments: | 2979 args: The command line arguments: |
2858 | 2980 |
2859 Returns: | 2981 Returns: |
2860 The list of filenames to lint. | 2982 The list of filenames to lint. |
2861 """ | 2983 """ |
2862 try: | 2984 try: |
2863 (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=', | 2985 (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=', |
| 2986 'counting=', |
2864 'filter=']) | 2987 'filter=']) |
2865 except getopt.GetoptError: | 2988 except getopt.GetoptError: |
2866 PrintUsage('Invalid arguments.') | 2989 PrintUsage('Invalid arguments.') |
2867 | 2990 |
2868 verbosity = _VerboseLevel() | 2991 verbosity = _VerboseLevel() |
2869 output_format = _OutputFormat() | 2992 output_format = _OutputFormat() |
2870 filters = '' | 2993 filters = '' |
| 2994 counting_style = '' |
2871 | 2995 |
2872 for (opt, val) in opts: | 2996 for (opt, val) in opts: |
2873 if opt == '--help': | 2997 if opt == '--help': |
2874 PrintUsage(None) | 2998 PrintUsage(None) |
2875 elif opt == '--output': | 2999 elif opt == '--output': |
2876 if not val in ('emacs', 'vs7'): | 3000 if not val in ('emacs', 'vs7'): |
2877 PrintUsage('The only allowed output formats are emacs and vs7.') | 3001 PrintUsage('The only allowed output formats are emacs and vs7.') |
2878 output_format = val | 3002 output_format = val |
2879 elif opt == '--verbose': | 3003 elif opt == '--verbose': |
2880 verbosity = int(val) | 3004 verbosity = int(val) |
2881 elif opt == '--filter': | 3005 elif opt == '--filter': |
2882 filters = val | 3006 filters = val |
2883 if not filters: | 3007 if not filters: |
2884 PrintCategories() | 3008 PrintCategories() |
| 3009 elif opt == '--counting': |
| 3010 if val not in ('total', 'toplevel', 'detailed'): |
| 3011 PrintUsage('Valid counting options are total, toplevel, and detailed') |
| 3012 counting_style = val |
2885 | 3013 |
2886 if not filenames: | 3014 if not filenames: |
2887 PrintUsage('No files were specified.') | 3015 PrintUsage('No files were specified.') |
2888 | 3016 |
2889 _SetOutputFormat(output_format) | 3017 _SetOutputFormat(output_format) |
2890 _SetVerboseLevel(verbosity) | 3018 _SetVerboseLevel(verbosity) |
2891 _SetFilters(filters) | 3019 _SetFilters(filters) |
| 3020 _SetCountingStyle(counting_style) |
2892 | 3021 |
2893 return filenames | 3022 return filenames |
2894 | 3023 |
2895 | 3024 |
2896 def main(): | 3025 def main(): |
2897 filenames = ParseArguments(sys.argv[1:]) | 3026 filenames = ParseArguments(sys.argv[1:]) |
2898 | 3027 |
2899 # Change stderr to write with replacement characters so we don't die | 3028 # Change stderr to write with replacement characters so we don't die |
2900 # if we try to print something containing non-ASCII characters. | 3029 # if we try to print something containing non-ASCII characters. |
2901 sys.stderr = codecs.StreamReaderWriter(sys.stderr, | 3030 sys.stderr = codecs.StreamReaderWriter(sys.stderr, |
2902 codecs.getreader('utf8'), | 3031 codecs.getreader('utf8'), |
2903 codecs.getwriter('utf8'), | 3032 codecs.getwriter('utf8'), |
2904 'replace') | 3033 'replace') |
2905 | 3034 |
2906 _cpplint_state.ResetErrorCount() | 3035 _cpplint_state.ResetErrorCounts() |
2907 for filename in filenames: | 3036 for filename in filenames: |
2908 ProcessFile(filename, _cpplint_state.verbose_level) | 3037 ProcessFile(filename, _cpplint_state.verbose_level) |
2909 sys.stderr.write('Total errors found: %d\n' % _cpplint_state.error_count) | 3038 _cpplint_state.PrintErrorCounts() |
| 3039 |
2910 sys.exit(_cpplint_state.error_count > 0) | 3040 sys.exit(_cpplint_state.error_count > 0) |
2911 | 3041 |
2912 | 3042 |
2913 if __name__ == '__main__': | 3043 if __name__ == '__main__': |
2914 main() | 3044 main() |
OLD | NEW |