amiro-os / tools / cpplint / python / cpplint.py @ e545e620
History | View | Annotate | Download (236.226 KB)
| 1 | e545e620 | Thomas Schöpping | #!/usr/bin/env python
|
|---|---|---|---|
| 2 | #
|
||
| 3 | # Copyright (c) 2009 Google Inc. All rights reserved.
|
||
| 4 | #
|
||
| 5 | # Redistribution and use in source and binary forms, with or without
|
||
| 6 | # modification, are permitted provided that the following conditions are
|
||
| 7 | # met:
|
||
| 8 | #
|
||
| 9 | # * Redistributions of source code must retain the above copyright
|
||
| 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.
|
||
| 18 | #
|
||
| 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.
|
||
| 30 | |||
| 31 | """Does google-lint on c++ files.
|
||
| 32 |
|
||
| 33 | The goal of this script is to identify places in the code that *may*
|
||
| 34 | be in non-compliance with google style. It does not attempt to fix
|
||
| 35 | up these problems -- the point is to educate. It does also not
|
||
| 36 | attempt to find all problems, or to ensure that everything it does
|
||
| 37 | find is legitimately a problem.
|
||
| 38 |
|
||
| 39 | In particular, we can get very confused by /* and // inside strings!
|
||
| 40 | We do a small hack, which is to ignore //'s with "'s after them on the
|
||
| 41 | same line, but it is far from perfect (in either direction).
|
||
| 42 | """
|
||
| 43 | |||
| 44 | import codecs |
||
| 45 | import copy |
||
| 46 | import getopt |
||
| 47 | import math # for log |
||
| 48 | import os |
||
| 49 | import re |
||
| 50 | import sre_compile |
||
| 51 | import string |
||
| 52 | import sys |
||
| 53 | import unicodedata |
||
| 54 | |||
| 55 | |||
| 56 | _USAGE = """
|
||
| 57 | Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
|
||
| 58 | [--counting=total|toplevel|detailed] [--root=subdir]
|
||
| 59 | [--linelength=digits]
|
||
| 60 | <file> [file] ...
|
||
| 61 |
|
||
| 62 | The style guidelines this tries to follow are those in
|
||
| 63 | http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
|
||
| 64 |
|
||
| 65 | Every problem is given a confidence score from 1-5, with 5 meaning we are
|
||
| 66 | certain of the problem, and 1 meaning it could be a legitimate construct.
|
||
| 67 | This will miss some errors, and is not a substitute for a code review.
|
||
| 68 |
|
||
| 69 | To suppress false-positive errors of a certain category, add a
|
||
| 70 | 'NOLINT(category)' comment to the line. NOLINT or NOLINT(*)
|
||
| 71 | suppresses errors of all categories on that line.
|
||
| 72 |
|
||
| 73 | The files passed in will be linted; at least one file must be provided.
|
||
| 74 | Default linted extensions are .cc, .cpp, .cu, .cuh and .h. Change the
|
||
| 75 | extensions with the --extensions flag.
|
||
| 76 |
|
||
| 77 | Flags:
|
||
| 78 |
|
||
| 79 | output=vs7
|
||
| 80 | By default, the output is formatted to ease emacs parsing. Visual Studio
|
||
| 81 | compatible output (vs7) may also be used. Other formats are unsupported.
|
||
| 82 |
|
||
| 83 | verbose=#
|
||
| 84 | Specify a number 0-5 to restrict errors to certain verbosity levels.
|
||
| 85 |
|
||
| 86 | filter=-x,+y,...
|
||
| 87 | Specify a comma-separated list of category-filters to apply: only
|
||
| 88 | error messages whose category names pass the filters will be printed.
|
||
| 89 | (Category names are printed with the message and look like
|
||
| 90 | "[whitespace/indent]".) Filters are evaluated left to right.
|
||
| 91 | "-FOO" and "FOO" means "do not print categories that start with FOO".
|
||
| 92 | "+FOO" means "do print categories that start with FOO".
|
||
| 93 |
|
||
| 94 | Examples: --filter=-whitespace,+whitespace/braces
|
||
| 95 | --filter=whitespace,runtime/printf,+runtime/printf_format
|
||
| 96 | --filter=-,+build/include_what_you_use
|
||
| 97 |
|
||
| 98 | To see a list of all the categories used in cpplint, pass no arg:
|
||
| 99 | --filter=
|
||
| 100 |
|
||
| 101 | counting=total|toplevel|detailed
|
||
| 102 | The total number of errors found is always printed. If
|
||
| 103 | 'toplevel' is provided, then the count of errors in each of
|
||
| 104 | the top-level categories like 'build' and 'whitespace' will
|
||
| 105 | also be printed. If 'detailed' is provided, then a count
|
||
| 106 | is provided for each category like 'build/class'.
|
||
| 107 |
|
||
| 108 | root=subdir
|
||
| 109 | The root directory used for deriving header guard CPP variable.
|
||
| 110 | By default, the header guard CPP variable is calculated as the relative
|
||
| 111 | path to the directory that contains .git, .hg, or .svn. When this flag
|
||
| 112 | is specified, the relative path is calculated from the specified
|
||
| 113 | directory. If the specified directory does not exist, this flag is
|
||
| 114 | ignored.
|
||
| 115 |
|
||
| 116 | Examples:
|
||
| 117 | Assuming that src/.git exists, the header guard CPP variables for
|
||
| 118 | src/chrome/browser/ui/browser.h are:
|
||
| 119 |
|
||
| 120 | No flag => CHROME_BROWSER_UI_BROWSER_H_
|
||
| 121 | --root=chrome => BROWSER_UI_BROWSER_H_
|
||
| 122 | --root=chrome/browser => UI_BROWSER_H_
|
||
| 123 |
|
||
| 124 | linelength=digits
|
||
| 125 | This is the allowed line length for the project. The default value is
|
||
| 126 | 80 characters.
|
||
| 127 |
|
||
| 128 | Examples:
|
||
| 129 | --linelength=120
|
||
| 130 |
|
||
| 131 | extensions=extension,extension,...
|
||
| 132 | The allowed file extensions that cpplint will check
|
||
| 133 |
|
||
| 134 | Examples:
|
||
| 135 | --extensions=hpp,cpp
|
||
| 136 |
|
||
| 137 | cpplint.py supports per-directory configurations specified in CPPLINT.cfg
|
||
| 138 | files. CPPLINT.cfg file can contain a number of key=value pairs.
|
||
| 139 | Currently the following options are supported:
|
||
| 140 |
|
||
| 141 | set noparent
|
||
| 142 | filter=+filter1,-filter2,...
|
||
| 143 | exclude_files=regex
|
||
| 144 | linelength=80
|
||
| 145 |
|
||
| 146 | "set noparent" option prevents cpplint from traversing directory tree
|
||
| 147 | upwards looking for more .cfg files in parent directories. This option
|
||
| 148 | is usually placed in the top-level project directory.
|
||
| 149 |
|
||
| 150 | The "filter" option is similar in function to --filter flag. It specifies
|
||
| 151 | message filters in addition to the |_DEFAULT_FILTERS| and those specified
|
||
| 152 | through --filter command-line flag.
|
||
| 153 |
|
||
| 154 | "exclude_files" allows to specify a regular expression to be matched against
|
||
| 155 | a file name. If the expression matches, the file is skipped and not run
|
||
| 156 | through liner.
|
||
| 157 |
|
||
| 158 | "linelength" allows to specify the allowed line length for the project.
|
||
| 159 |
|
||
| 160 | CPPLINT.cfg has an effect on files in the same directory and all
|
||
| 161 | sub-directories, unless overridden by a nested configuration file.
|
||
| 162 |
|
||
| 163 | Example file:
|
||
| 164 | filter=-build/include_order,+build/include_alpha
|
||
| 165 | exclude_files=.*\.cc
|
||
| 166 |
|
||
| 167 | The above example disables build/include_order warning and enables
|
||
| 168 | build/include_alpha as well as excludes all .cc from being
|
||
| 169 | processed by linter, in the current directory (where the .cfg
|
||
| 170 | file is located) and all sub-directories.
|
||
| 171 | """
|
||
| 172 | |||
| 173 | # We categorize each error message we print. Here are the categories.
|
||
| 174 | # We want an explicit list so we can list them all in cpplint --filter=.
|
||
| 175 | # If you add a new error message with a new category, add it to the list
|
||
| 176 | # here! cpplint_unittest.py should tell you if you forget to do this.
|
||
| 177 | _ERROR_CATEGORIES = [ |
||
| 178 | 'build/class',
|
||
| 179 | 'build/c++11',
|
||
| 180 | 'build/deprecated',
|
||
| 181 | 'build/endif_comment',
|
||
| 182 | 'build/explicit_make_pair',
|
||
| 183 | 'build/forward_decl',
|
||
| 184 | 'build/header_guard',
|
||
| 185 | 'build/include',
|
||
| 186 | 'build/include_alpha',
|
||
| 187 | 'build/include_order',
|
||
| 188 | 'build/include_what_you_use',
|
||
| 189 | 'build/namespaces',
|
||
| 190 | 'build/printf_format',
|
||
| 191 | 'build/storage_class',
|
||
| 192 | 'legal/copyright',
|
||
| 193 | 'readability/alt_tokens',
|
||
| 194 | 'readability/braces',
|
||
| 195 | 'readability/casting',
|
||
| 196 | 'readability/check',
|
||
| 197 | 'readability/constructors',
|
||
| 198 | 'readability/fn_size',
|
||
| 199 | 'readability/function',
|
||
| 200 | 'readability/inheritance',
|
||
| 201 | 'readability/multiline_comment',
|
||
| 202 | 'readability/multiline_string',
|
||
| 203 | 'readability/namespace',
|
||
| 204 | 'readability/nolint',
|
||
| 205 | 'readability/nul',
|
||
| 206 | 'readability/strings',
|
||
| 207 | 'readability/todo',
|
||
| 208 | 'readability/utf8',
|
||
| 209 | 'runtime/arrays',
|
||
| 210 | 'runtime/casting',
|
||
| 211 | 'runtime/explicit',
|
||
| 212 | 'runtime/int',
|
||
| 213 | 'runtime/init',
|
||
| 214 | 'runtime/invalid_increment',
|
||
| 215 | 'runtime/member_string_references',
|
||
| 216 | 'runtime/memset',
|
||
| 217 | 'runtime/indentation_namespace',
|
||
| 218 | 'runtime/operator',
|
||
| 219 | 'runtime/printf',
|
||
| 220 | 'runtime/printf_format',
|
||
| 221 | 'runtime/references',
|
||
| 222 | 'runtime/string',
|
||
| 223 | 'runtime/threadsafe_fn',
|
||
| 224 | 'runtime/vlog',
|
||
| 225 | 'whitespace/blank_line',
|
||
| 226 | 'whitespace/braces',
|
||
| 227 | 'whitespace/comma',
|
||
| 228 | 'whitespace/comments',
|
||
| 229 | 'whitespace/empty_conditional_body',
|
||
| 230 | 'whitespace/empty_loop_body',
|
||
| 231 | 'whitespace/end_of_line',
|
||
| 232 | 'whitespace/ending_newline',
|
||
| 233 | 'whitespace/forcolon',
|
||
| 234 | 'whitespace/indent',
|
||
| 235 | 'whitespace/line_length',
|
||
| 236 | 'whitespace/newline',
|
||
| 237 | 'whitespace/operators',
|
||
| 238 | 'whitespace/parens',
|
||
| 239 | 'whitespace/semicolon',
|
||
| 240 | 'whitespace/tab',
|
||
| 241 | 'whitespace/todo',
|
||
| 242 | ] |
||
| 243 | |||
| 244 | # These error categories are no longer enforced by cpplint, but for backwards-
|
||
| 245 | # compatibility they may still appear in NOLINT comments.
|
||
| 246 | _LEGACY_ERROR_CATEGORIES = [ |
||
| 247 | 'readability/streams',
|
||
| 248 | ] |
||
| 249 | |||
| 250 | # The default state of the category filter. This is overridden by the --filter=
|
||
| 251 | # flag. By default all errors are on, so only add here categories that should be
|
||
| 252 | # off by default (i.e., categories that must be enabled by the --filter= flags).
|
||
| 253 | # All entries here should start with a '-' or '+', as in the --filter= flag.
|
||
| 254 | _DEFAULT_FILTERS = ['-build/include_alpha']
|
||
| 255 | |||
| 256 | # We used to check for high-bit characters, but after much discussion we
|
||
| 257 | # decided those were OK, as long as they were in UTF-8 and didn't represent
|
||
| 258 | # hard-coded international strings, which belong in a separate i18n file.
|
||
| 259 | |||
| 260 | # C++ headers
|
||
| 261 | _CPP_HEADERS = frozenset([
|
||
| 262 | # Legacy
|
||
| 263 | 'algobase.h',
|
||
| 264 | 'algo.h',
|
||
| 265 | 'alloc.h',
|
||
| 266 | 'builtinbuf.h',
|
||
| 267 | 'bvector.h',
|
||
| 268 | 'complex.h',
|
||
| 269 | 'defalloc.h',
|
||
| 270 | 'deque.h',
|
||
| 271 | 'editbuf.h',
|
||
| 272 | 'fstream.h',
|
||
| 273 | 'function.h',
|
||
| 274 | 'hash_map',
|
||
| 275 | 'hash_map.h',
|
||
| 276 | 'hash_set',
|
||
| 277 | 'hash_set.h',
|
||
| 278 | 'hashtable.h',
|
||
| 279 | 'heap.h',
|
||
| 280 | 'indstream.h',
|
||
| 281 | 'iomanip.h',
|
||
| 282 | 'iostream.h',
|
||
| 283 | 'istream.h',
|
||
| 284 | 'iterator.h',
|
||
| 285 | 'list.h',
|
||
| 286 | 'map.h',
|
||
| 287 | 'multimap.h',
|
||
| 288 | 'multiset.h',
|
||
| 289 | 'ostream.h',
|
||
| 290 | 'pair.h',
|
||
| 291 | 'parsestream.h',
|
||
| 292 | 'pfstream.h',
|
||
| 293 | 'procbuf.h',
|
||
| 294 | 'pthread_alloc',
|
||
| 295 | 'pthread_alloc.h',
|
||
| 296 | 'rope',
|
||
| 297 | 'rope.h',
|
||
| 298 | 'ropeimpl.h',
|
||
| 299 | 'set.h',
|
||
| 300 | 'slist',
|
||
| 301 | 'slist.h',
|
||
| 302 | 'stack.h',
|
||
| 303 | 'stdiostream.h',
|
||
| 304 | 'stl_alloc.h',
|
||
| 305 | 'stl_relops.h',
|
||
| 306 | 'streambuf.h',
|
||
| 307 | 'stream.h',
|
||
| 308 | 'strfile.h',
|
||
| 309 | 'strstream.h',
|
||
| 310 | 'tempbuf.h',
|
||
| 311 | 'tree.h',
|
||
| 312 | 'type_traits.h',
|
||
| 313 | 'vector.h',
|
||
| 314 | # 17.6.1.2 C++ library headers
|
||
| 315 | 'algorithm',
|
||
| 316 | 'array',
|
||
| 317 | 'atomic',
|
||
| 318 | 'bitset',
|
||
| 319 | 'chrono',
|
||
| 320 | 'codecvt',
|
||
| 321 | 'complex',
|
||
| 322 | 'condition_variable',
|
||
| 323 | 'deque',
|
||
| 324 | 'exception',
|
||
| 325 | 'forward_list',
|
||
| 326 | 'fstream',
|
||
| 327 | 'functional',
|
||
| 328 | 'future',
|
||
| 329 | 'initializer_list',
|
||
| 330 | 'iomanip',
|
||
| 331 | 'ios',
|
||
| 332 | 'iosfwd',
|
||
| 333 | 'iostream',
|
||
| 334 | 'istream',
|
||
| 335 | 'iterator',
|
||
| 336 | 'limits',
|
||
| 337 | 'list',
|
||
| 338 | 'locale',
|
||
| 339 | 'map',
|
||
| 340 | 'memory',
|
||
| 341 | 'mutex',
|
||
| 342 | 'new',
|
||
| 343 | 'numeric',
|
||
| 344 | 'ostream',
|
||
| 345 | 'queue',
|
||
| 346 | 'random',
|
||
| 347 | 'ratio',
|
||
| 348 | 'regex',
|
||
| 349 | 'set',
|
||
| 350 | 'sstream',
|
||
| 351 | 'stack',
|
||
| 352 | 'stdexcept',
|
||
| 353 | 'streambuf',
|
||
| 354 | 'string',
|
||
| 355 | 'strstream',
|
||
| 356 | 'system_error',
|
||
| 357 | 'thread',
|
||
| 358 | 'tuple',
|
||
| 359 | 'typeindex',
|
||
| 360 | 'typeinfo',
|
||
| 361 | 'type_traits',
|
||
| 362 | 'unordered_map',
|
||
| 363 | 'unordered_set',
|
||
| 364 | 'utility',
|
||
| 365 | 'valarray',
|
||
| 366 | 'vector',
|
||
| 367 | # 17.6.1.2 C++ headers for C library facilities
|
||
| 368 | 'cassert',
|
||
| 369 | 'ccomplex',
|
||
| 370 | 'cctype',
|
||
| 371 | 'cerrno',
|
||
| 372 | 'cfenv',
|
||
| 373 | 'cfloat',
|
||
| 374 | 'cinttypes',
|
||
| 375 | 'ciso646',
|
||
| 376 | 'climits',
|
||
| 377 | 'clocale',
|
||
| 378 | 'cmath',
|
||
| 379 | 'csetjmp',
|
||
| 380 | 'csignal',
|
||
| 381 | 'cstdalign',
|
||
| 382 | 'cstdarg',
|
||
| 383 | 'cstdbool',
|
||
| 384 | 'cstddef',
|
||
| 385 | 'cstdint',
|
||
| 386 | 'cstdio',
|
||
| 387 | 'cstdlib',
|
||
| 388 | 'cstring',
|
||
| 389 | 'ctgmath',
|
||
| 390 | 'ctime',
|
||
| 391 | 'cuchar',
|
||
| 392 | 'cwchar',
|
||
| 393 | 'cwctype',
|
||
| 394 | ]) |
||
| 395 | |||
| 396 | |||
| 397 | # These headers are excluded from [build/include] and [build/include_order]
|
||
| 398 | # checks:
|
||
| 399 | # - Anything not following google file name conventions (containing an
|
||
| 400 | # uppercase character, such as Python.h or nsStringAPI.h, for example).
|
||
| 401 | # - Lua headers.
|
||
| 402 | _THIRD_PARTY_HEADERS_PATTERN = re.compile( |
||
| 403 | r'^(?:[^/]*[A-Z][^/]*\.h|lua\.h|lauxlib\.h|lualib\.h)$')
|
||
| 404 | |||
| 405 | |||
| 406 | # Assertion macros. These are defined in base/logging.h and
|
||
| 407 | # testing/base/gunit.h. Note that the _M versions need to come first
|
||
| 408 | # for substring matching to work.
|
||
| 409 | _CHECK_MACROS = [ |
||
| 410 | 'DCHECK', 'CHECK', |
||
| 411 | 'EXPECT_TRUE_M', 'EXPECT_TRUE', |
||
| 412 | 'ASSERT_TRUE_M', 'ASSERT_TRUE', |
||
| 413 | 'EXPECT_FALSE_M', 'EXPECT_FALSE', |
||
| 414 | 'ASSERT_FALSE_M', 'ASSERT_FALSE', |
||
| 415 | ] |
||
| 416 | |||
| 417 | # Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE
|
||
| 418 | _CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS]) |
||
| 419 | |||
| 420 | for op, replacement in [('==', 'EQ'), ('!=', 'NE'), |
||
| 421 | ('>=', 'GE'), ('>', 'GT'), |
||
| 422 | ('<=', 'LE'), ('<', 'LT')]: |
||
| 423 | _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement |
||
| 424 | _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement |
||
| 425 | _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement |
||
| 426 | _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement |
||
| 427 | _CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement |
||
| 428 | _CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % replacement |
||
| 429 | |||
| 430 | for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'), |
||
| 431 | ('>=', 'LT'), ('>', 'LE'), |
||
| 432 | ('<=', 'GT'), ('<', 'GE')]: |
||
| 433 | _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement |
||
| 434 | _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement |
||
| 435 | _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement |
||
| 436 | _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % inv_replacement |
||
| 437 | |||
| 438 | # Alternative tokens and their replacements. For full list, see section 2.5
|
||
| 439 | # Alternative tokens [lex.digraph] in the C++ standard.
|
||
| 440 | #
|
||
| 441 | # Digraphs (such as '%:') are not included here since it's a mess to
|
||
| 442 | # match those on a word boundary.
|
||
| 443 | _ALT_TOKEN_REPLACEMENT = {
|
||
| 444 | 'and': '&&', |
||
| 445 | 'bitor': '|', |
||
| 446 | 'or': '||', |
||
| 447 | 'xor': '^', |
||
| 448 | 'compl': '~', |
||
| 449 | 'bitand': '&', |
||
| 450 | 'and_eq': '&=', |
||
| 451 | 'or_eq': '|=', |
||
| 452 | 'xor_eq': '^=', |
||
| 453 | 'not': '!', |
||
| 454 | 'not_eq': '!=' |
||
| 455 | } |
||
| 456 | |||
| 457 | # Compile regular expression that matches all the above keywords. The "[ =()]"
|
||
| 458 | # bit is meant to avoid matching these keywords outside of boolean expressions.
|
||
| 459 | #
|
||
| 460 | # False positives include C-style multi-line comments and multi-line strings
|
||
| 461 | # but those have always been troublesome for cpplint.
|
||
| 462 | _ALT_TOKEN_REPLACEMENT_PATTERN = re.compile( |
||
| 463 | r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)') |
||
| 464 | |||
| 465 | |||
| 466 | # These constants define types of headers for use with
|
||
| 467 | # _IncludeState.CheckNextIncludeOrder().
|
||
| 468 | _C_SYS_HEADER = 1
|
||
| 469 | _CPP_SYS_HEADER = 2
|
||
| 470 | _LIKELY_MY_HEADER = 3
|
||
| 471 | _POSSIBLE_MY_HEADER = 4
|
||
| 472 | _OTHER_HEADER = 5
|
||
| 473 | |||
| 474 | # These constants define the current inline assembly state
|
||
| 475 | _NO_ASM = 0 # Outside of inline assembly block |
||
| 476 | _INSIDE_ASM = 1 # Inside inline assembly block |
||
| 477 | _END_ASM = 2 # Last line of inline assembly block |
||
| 478 | _BLOCK_ASM = 3 # The whole block is an inline assembly block |
||
| 479 | |||
| 480 | # Match start of assembly blocks
|
||
| 481 | _MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)'
|
||
| 482 | r'(?:\s+(volatile|__volatile__))?'
|
||
| 483 | r'\s*[{(]')
|
||
| 484 | |||
| 485 | |||
| 486 | _regexp_compile_cache = {}
|
||
| 487 | |||
| 488 | # {str, set(int)}: a map from error categories to sets of linenumbers
|
||
| 489 | # on which those errors are expected and should be suppressed.
|
||
| 490 | _error_suppressions = {}
|
||
| 491 | |||
| 492 | # The root directory used for deriving header guard CPP variable.
|
||
| 493 | # This is set by --root flag.
|
||
| 494 | _root = None
|
||
| 495 | |||
| 496 | # The allowed line length of files.
|
||
| 497 | # This is set by --linelength flag.
|
||
| 498 | _line_length = 80
|
||
| 499 | |||
| 500 | # The allowed extensions for file names
|
||
| 501 | # This is set by --extensions flag.
|
||
| 502 | _valid_extensions = set(['cc', 'h', 'cpp', 'cu', 'cuh']) |
||
| 503 | |||
| 504 | def ParseNolintSuppressions(filename, raw_line, linenum, error): |
||
| 505 | """Updates the global list of error-suppressions.
|
||
| 506 |
|
||
| 507 | Parses any NOLINT comments on the current line, updating the global
|
||
| 508 | error_suppressions store. Reports an error if the NOLINT comment
|
||
| 509 | was malformed.
|
||
| 510 |
|
||
| 511 | Args:
|
||
| 512 | filename: str, the name of the input file.
|
||
| 513 | raw_line: str, the line of input text, with comments.
|
||
| 514 | linenum: int, the number of the current line.
|
||
| 515 | error: function, an error handler.
|
||
| 516 | """
|
||
| 517 | matched = Search(r'\bNOLINT(NEXTLINE)?\b(\([^)]+\))?', raw_line)
|
||
| 518 | if matched:
|
||
| 519 | if matched.group(1): |
||
| 520 | suppressed_line = linenum + 1
|
||
| 521 | else:
|
||
| 522 | suppressed_line = linenum |
||
| 523 | category = matched.group(2)
|
||
| 524 | if category in (None, '(*)'): # => "suppress all" |
||
| 525 | _error_suppressions.setdefault(None, set()).add(suppressed_line) |
||
| 526 | else:
|
||
| 527 | if category.startswith('(') and category.endswith(')'): |
||
| 528 | category = category[1:-1] |
||
| 529 | if category in _ERROR_CATEGORIES: |
||
| 530 | _error_suppressions.setdefault(category, set()).add(suppressed_line)
|
||
| 531 | elif category not in _LEGACY_ERROR_CATEGORIES: |
||
| 532 | error(filename, linenum, 'readability/nolint', 5, |
||
| 533 | 'Unknown NOLINT error category: %s' % category)
|
||
| 534 | |||
| 535 | |||
| 536 | def ResetNolintSuppressions(): |
||
| 537 | """Resets the set of NOLINT suppressions to empty."""
|
||
| 538 | _error_suppressions.clear() |
||
| 539 | |||
| 540 | |||
| 541 | def IsErrorSuppressedByNolint(category, linenum): |
||
| 542 | """Returns true if the specified error category is suppressed on this line.
|
||
| 543 |
|
||
| 544 | Consults the global error_suppressions map populated by
|
||
| 545 | ParseNolintSuppressions/ResetNolintSuppressions.
|
||
| 546 |
|
||
| 547 | Args:
|
||
| 548 | category: str, the category of the error.
|
||
| 549 | linenum: int, the current line number.
|
||
| 550 | Returns:
|
||
| 551 | bool, True iff the error should be suppressed due to a NOLINT comment.
|
||
| 552 | """
|
||
| 553 | return (linenum in _error_suppressions.get(category, set()) or |
||
| 554 | linenum in _error_suppressions.get(None, set())) |
||
| 555 | |||
| 556 | |||
| 557 | def Match(pattern, s): |
||
| 558 | """Matches the string with the pattern, caching the compiled regexp."""
|
||
| 559 | # The regexp compilation caching is inlined in both Match and Search for
|
||
| 560 | # performance reasons; factoring it out into a separate function turns out
|
||
| 561 | # to be noticeably expensive.
|
||
| 562 | if pattern not in _regexp_compile_cache: |
||
| 563 | _regexp_compile_cache[pattern] = sre_compile.compile(pattern) |
||
| 564 | return _regexp_compile_cache[pattern].match(s)
|
||
| 565 | |||
| 566 | |||
| 567 | def ReplaceAll(pattern, rep, s): |
||
| 568 | """Replaces instances of pattern in a string with a replacement.
|
||
| 569 |
|
||
| 570 | The compiled regex is kept in a cache shared by Match and Search.
|
||
| 571 |
|
||
| 572 | Args:
|
||
| 573 | pattern: regex pattern
|
||
| 574 | rep: replacement text
|
||
| 575 | s: search string
|
||
| 576 |
|
||
| 577 | Returns:
|
||
| 578 | string with replacements made (or original string if no replacements)
|
||
| 579 | """
|
||
| 580 | if pattern not in _regexp_compile_cache: |
||
| 581 | _regexp_compile_cache[pattern] = sre_compile.compile(pattern) |
||
| 582 | return _regexp_compile_cache[pattern].sub(rep, s)
|
||
| 583 | |||
| 584 | |||
| 585 | def Search(pattern, s): |
||
| 586 | """Searches the string for the pattern, caching the compiled regexp."""
|
||
| 587 | if pattern not in _regexp_compile_cache: |
||
| 588 | _regexp_compile_cache[pattern] = sre_compile.compile(pattern) |
||
| 589 | return _regexp_compile_cache[pattern].search(s)
|
||
| 590 | |||
| 591 | |||
| 592 | class _IncludeState(object): |
||
| 593 | """Tracks line numbers for includes, and the order in which includes appear.
|
||
| 594 |
|
||
| 595 | include_list contains list of lists of (header, line number) pairs.
|
||
| 596 | It's a lists of lists rather than just one flat list to make it
|
||
| 597 | easier to update across preprocessor boundaries.
|
||
| 598 |
|
||
| 599 | Call CheckNextIncludeOrder() once for each header in the file, passing
|
||
| 600 | in the type constants defined above. Calls in an illegal order will
|
||
| 601 | raise an _IncludeError with an appropriate error message.
|
||
| 602 |
|
||
| 603 | """
|
||
| 604 | # self._section will move monotonically through this set. If it ever
|
||
| 605 | # needs to move backwards, CheckNextIncludeOrder will raise an error.
|
||
| 606 | _INITIAL_SECTION = 0
|
||
| 607 | _MY_H_SECTION = 1
|
||
| 608 | _C_SECTION = 2
|
||
| 609 | _CPP_SECTION = 3
|
||
| 610 | _OTHER_H_SECTION = 4
|
||
| 611 | |||
| 612 | _TYPE_NAMES = {
|
||
| 613 | _C_SYS_HEADER: 'C system header',
|
||
| 614 | _CPP_SYS_HEADER: 'C++ system header',
|
||
| 615 | _LIKELY_MY_HEADER: 'header this file implements',
|
||
| 616 | _POSSIBLE_MY_HEADER: 'header this file may implement',
|
||
| 617 | _OTHER_HEADER: 'other header',
|
||
| 618 | } |
||
| 619 | _SECTION_NAMES = {
|
||
| 620 | _INITIAL_SECTION: "... nothing. (This can't be an error.)",
|
||
| 621 | _MY_H_SECTION: 'a header this file implements',
|
||
| 622 | _C_SECTION: 'C system header',
|
||
| 623 | _CPP_SECTION: 'C++ system header',
|
||
| 624 | _OTHER_H_SECTION: 'other header',
|
||
| 625 | } |
||
| 626 | |||
| 627 | def __init__(self): |
||
| 628 | self.include_list = [[]]
|
||
| 629 | self.ResetSection('') |
||
| 630 | |||
| 631 | def FindHeader(self, header): |
||
| 632 | """Check if a header has already been included.
|
||
| 633 |
|
||
| 634 | Args:
|
||
| 635 | header: header to check.
|
||
| 636 | Returns:
|
||
| 637 | Line number of previous occurrence, or -1 if the header has not
|
||
| 638 | been seen before.
|
||
| 639 | """
|
||
| 640 | for section_list in self.include_list: |
||
| 641 | for f in section_list: |
||
| 642 | if f[0] == header: |
||
| 643 | return f[1] |
||
| 644 | return -1 |
||
| 645 | |||
| 646 | def ResetSection(self, directive): |
||
| 647 | """Reset section checking for preprocessor directive.
|
||
| 648 |
|
||
| 649 | Args:
|
||
| 650 | directive: preprocessor directive (e.g. "if", "else").
|
||
| 651 | """
|
||
| 652 | # The name of the current section.
|
||
| 653 | self._section = self._INITIAL_SECTION |
||
| 654 | # The path of last found header.
|
||
| 655 | self._last_header = '' |
||
| 656 | |||
| 657 | # Update list of includes. Note that we never pop from the
|
||
| 658 | # include list.
|
||