1fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov#!/usr/bin/python 2fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# 3fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Copyright (c) 2009 Google Inc. All rights reserved. 4fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# 5fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Redistribution and use in source and binary forms, with or without 6fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# modification, are permitted provided that the following conditions are 7fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# met: 8fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# 9fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# * Redistributions of source code must retain the above copyright 10fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# notice, this list of conditions and the following disclaimer. 11fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# * Redistributions in binary form must reproduce the above 12fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# copyright notice, this list of conditions and the following disclaimer 13fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# in the documentation and/or other materials provided with the 14fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# distribution. 15fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# * Neither the name of Google Inc. nor the names of its 16fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# contributors may be used to endorse or promote products derived from 17fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# this software without specific prior written permission. 18fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# 19fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 31fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Here are some issues that I've had people identify in my code during reviews, 32fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# that I think are possible to flag automatically in a lint tool. If these were 33fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# caught by lint, it would save time both for myself and that of my reviewers. 34fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Most likely, some of these are beyond the scope of the current lint framework, 35fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# but I think it is valuable to retain these wish-list items even if they cannot 36fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# be immediately implemented. 37fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# 38fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Suggestions 39fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# ----------- 40fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# - Check for no 'explicit' for multi-arg ctor 41fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# - Check for boolean assign RHS in parens 42fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# - Check for ctor initializer-list colon position and spacing 43fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# - Check that if there's a ctor, there should be a dtor 44fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# - Check accessors that return non-pointer member variables are 45fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# declared const 46fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# - Check accessors that return non-const pointer member vars are 47fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# *not* declared const 48fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# - Check for using public includes for testing 49fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# - Check for spaces between brackets in one-line inline method 50fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# - Check for no assert() 51fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# - Check for spaces surrounding operators 52fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# - Check for 0 in pointer context (should be NULL) 53fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# - Check for 0 in char context (should be '\0') 54fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# - Check for camel-case method name conventions for methods 55fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# that are not simple inline getters and setters 56fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# - Do not indent namespace contents 57fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# - Avoid inlining non-trivial constructors in header files 58fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# - Check for old-school (void) cast for call-sites of functions 59fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# ignored return value 60fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# - Check gUnit usage of anonymous namespace 61fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# - Check for class declaration order (typedefs, consts, enums, 62fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# ctor(s?), dtor, friend declarations, methods, member vars) 63fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# 64fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 65fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov"""Does google-lint on c++ files. 66fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 67fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey SamsonovThe goal of this script is to identify places in the code that *may* 68fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovbe in non-compliance with google style. It does not attempt to fix 69fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovup these problems -- the point is to educate. It does also not 70fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovattempt to find all problems, or to ensure that everything it does 71fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovfind is legitimately a problem. 72fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 73fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey SamsonovIn particular, we can get very confused by /* and // inside strings! 74fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey SamsonovWe do a small hack, which is to ignore //'s with "'s after them on the 75fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovsame line, but it is far from perfect (in either direction). 76fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov""" 77fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 78fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport codecs 79fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport copy 80fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport getopt 81fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport math # for log 82fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport os 83fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport re 84fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport sre_compile 85fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport string 86fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport sys 87fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovimport unicodedata 88fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 89fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 90fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_USAGE = """ 91fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey SamsonovSyntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...] 92fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov [--counting=total|toplevel|detailed] 93fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov <file> [file] ... 94fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 95fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov The style guidelines this tries to follow are those in 96fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml 97fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 98fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Every problem is given a confidence score from 1-5, with 5 meaning we are 99fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov certain of the problem, and 1 meaning it could be a legitimate construct. 100fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov This will miss some errors, and is not a substitute for a code review. 101fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 102fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov To suppress false-positive errors of a certain category, add a 103fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'NOLINT(category)' comment to the line. NOLINT or NOLINT(*) 104fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov suppresses errors of all categories on that line. 105fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 106fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov The files passed in will be linted; at least one file must be provided. 107fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Linted extensions are .cc, .cpp, and .h. Other file types will be ignored. 108fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 109fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Flags: 110fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 111fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov output=vs7 112fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov By default, the output is formatted to ease emacs parsing. Visual Studio 113fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov compatible output (vs7) may also be used. Other formats are unsupported. 114fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 115fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov verbose=# 116fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Specify a number 0-5 to restrict errors to certain verbosity levels. 117fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 118fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filter=-x,+y,... 119fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Specify a comma-separated list of category-filters to apply: only 120fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error messages whose category names pass the filters will be printed. 121fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (Category names are printed with the message and look like 122fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov "[whitespace/indent]".) Filters are evaluated left to right. 123fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov "-FOO" and "FOO" means "do not print categories that start with FOO". 124fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov "+FOO" means "do print categories that start with FOO". 125fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 126fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Examples: --filter=-whitespace,+whitespace/braces 127fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov --filter=whitespace,runtime/printf,+runtime/printf_format 128fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov --filter=-,+build/include_what_you_use 129fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 130fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov To see a list of all the categories used in cpplint, pass no arg: 131fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov --filter= 132fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 133fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov counting=total|toplevel|detailed 134fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov The total number of errors found is always printed. If 135fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'toplevel' is provided, then the count of errors in each of 136fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov the top-level categories like 'build' and 'whitespace' will 137fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov also be printed. If 'detailed' is provided, then a count 138fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov is provided for each category like 'build/class'. 139fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 140fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov root=subdir 141fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov The root directory used for deriving header guard CPP variable. 142fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov By default, the header guard CPP variable is calculated as the relative 143fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov path to the directory that contains .git, .hg, or .svn. When this flag 144fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov is specified, the relative path is calculated from the specified 145fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov directory. If the specified directory does not exist, this flag is 146fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ignored. 147fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 148fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Examples: 149fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Assuing that src/.git exists, the header guard CPP variables for 150fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov src/chrome/browser/ui/browser.h are: 151fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 152fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov No flag => CHROME_BROWSER_UI_BROWSER_H_ 153fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov --root=chrome => BROWSER_UI_BROWSER_H_ 154fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov --root=chrome/browser => UI_BROWSER_H_ 155fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov""" 156fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 157fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# We categorize each error message we print. Here are the categories. 158fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# We want an explicit list so we can list them all in cpplint --filter=. 159fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# If you add a new error message with a new category, add it to the list 160fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# here! cpplint_unittest.py should tell you if you forget to do this. 161fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# \ used for clearer layout -- pylint: disable-msg=C6013 162fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_ERROR_CATEGORIES = [ 163fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'build/class', 164fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'build/deprecated', 165fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'build/endif_comment', 166fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'build/explicit_make_pair', 167fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'build/forward_decl', 168fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'build/header_guard', 169fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'build/include', 170fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'build/include_alpha', 171fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'build/include_order', 172fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'build/include_what_you_use', 173fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'build/namespaces', 174fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'build/printf_format', 175fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'build/storage_class', 176fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'legal/copyright', 177fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'readability/alt_tokens', 178fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'readability/braces', 179fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'readability/casting', 180fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'readability/check', 181fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'readability/constructors', 182fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'readability/fn_size', 183fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'readability/function', 184fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'readability/multiline_comment', 185fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'readability/multiline_string', 186fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'readability/namespace', 187fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'readability/nolint', 188fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'readability/streams', 189fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'readability/todo', 190fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'readability/utf8', 191fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'runtime/arrays', 192fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'runtime/casting', 193fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'runtime/explicit', 194fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'runtime/int', 195fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'runtime/init', 196fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'runtime/invalid_increment', 197fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'runtime/member_string_references', 198fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'runtime/memset', 199fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'runtime/operator', 200fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'runtime/printf', 201fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'runtime/printf_format', 202fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'runtime/references', 203fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'runtime/rtti', 204fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'runtime/sizeof', 205fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'runtime/string', 206fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'runtime/threadsafe_fn', 207fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'whitespace/blank_line', 208fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'whitespace/braces', 209fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'whitespace/comma', 210fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'whitespace/comments', 211fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'whitespace/empty_loop_body', 212fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'whitespace/end_of_line', 213fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'whitespace/ending_newline', 214fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'whitespace/forcolon', 215fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'whitespace/indent', 216fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'whitespace/labels', 217fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'whitespace/line_length', 218fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'whitespace/newline', 219fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'whitespace/operators', 220fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'whitespace/parens', 221fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'whitespace/semicolon', 222fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'whitespace/tab', 223fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'whitespace/todo' 224fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ] 225fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 226fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# The default state of the category filter. This is overrided by the --filter= 227fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# flag. By default all errors are on, so only add here categories that should be 228fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# off by default (i.e., categories that must be enabled by the --filter= flags). 229fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# All entries here should start with a '-' or '+', as in the --filter= flag. 230fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_DEFAULT_FILTERS = ['-build/include_alpha'] 231fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 232fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# We used to check for high-bit characters, but after much discussion we 233fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# decided those were OK, as long as they were in UTF-8 and didn't represent 234fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# hard-coded international strings, which belong in a separate i18n file. 235fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 236fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Headers that we consider STL headers. 237fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_STL_HEADERS = frozenset([ 238fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception', 239fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set', 240fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'new', 241fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'pair.h', 'pthread_alloc', 'queue', 'set', 'set.h', 'sstream', 'stack', 242fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'stl_alloc.h', 'stl_relops.h', 'type_traits.h', 243fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'utility', 'vector', 'vector.h', 244fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ]) 245fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 246fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 247fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Non-STL C++ system headers. 248fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_CPP_HEADERS = frozenset([ 249fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'algo.h', 'builtinbuf.h', 'bvector.h', 'cassert', 'cctype', 250fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'cerrno', 'cfloat', 'ciso646', 'climits', 'clocale', 'cmath', 251fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'complex', 'complex.h', 'csetjmp', 'csignal', 'cstdarg', 'cstddef', 252fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'cstdio', 'cstdlib', 'cstring', 'ctime', 'cwchar', 'cwctype', 253fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'defalloc.h', 'deque.h', 'editbuf.h', 'exception', 'fstream', 254fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'fstream.h', 'hashtable.h', 'heap.h', 'indstream.h', 'iomanip', 255fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'iomanip.h', 'ios', 'iosfwd', 'iostream', 'iostream.h', 'istream', 256fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'istream.h', 'iterator.h', 'limits', 'map.h', 'multimap.h', 'multiset.h', 257fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'numeric', 'ostream', 'ostream.h', 'parsestream.h', 'pfstream.h', 258fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'PlotFile.h', 'procbuf.h', 'pthread_alloc.h', 'rope', 'rope.h', 259fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'ropeimpl.h', 'SFile.h', 'slist', 'slist.h', 'stack.h', 'stdexcept', 260fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'stdiostream.h', 'streambuf', 'streambuf.h', 'stream.h', 'strfile.h', 261fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'string', 'strstream', 'strstream.h', 'tempbuf.h', 'tree.h', 'typeinfo', 262fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'valarray', 263fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ]) 264fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 265fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 266fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Assertion macros. These are defined in base/logging.h and 267fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# testing/base/gunit.h. Note that the _M versions need to come first 268fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# for substring matching to work. 269fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_CHECK_MACROS = [ 270fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'DCHECK', 'CHECK', 271fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'EXPECT_TRUE_M', 'EXPECT_TRUE', 272fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'ASSERT_TRUE_M', 'ASSERT_TRUE', 273fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'EXPECT_FALSE_M', 'EXPECT_FALSE', 274fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'ASSERT_FALSE_M', 'ASSERT_FALSE', 275fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ] 276fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 277fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE 278fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS]) 279fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 280fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovfor op, replacement in [('==', 'EQ'), ('!=', 'NE'), 281fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('>=', 'GE'), ('>', 'GT'), 282fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('<=', 'LE'), ('<', 'LT')]: 283fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement 284fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement 285fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement 286fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement 287fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement 288fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % replacement 289fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 290fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovfor op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'), 291fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('>=', 'LT'), ('>', 'LE'), 292fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('<=', 'GT'), ('<', 'GE')]: 293fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement 294fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement 295fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement 296fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % inv_replacement 297fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 298fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Alternative tokens and their replacements. For full list, see section 2.5 299fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Alternative tokens [lex.digraph] in the C++ standard. 300fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# 301fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Digraphs (such as '%:') are not included here since it's a mess to 302fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# match those on a word boundary. 303fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_ALT_TOKEN_REPLACEMENT = { 304fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'and': '&&', 305fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'bitor': '|', 306fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'or': '||', 307fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'xor': '^', 308fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'compl': '~', 309fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'bitand': '&', 310fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'and_eq': '&=', 311fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'or_eq': '|=', 312fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'xor_eq': '^=', 313fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'not': '!', 314fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'not_eq': '!=' 315fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov } 316fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 317fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Compile regular expression that matches all the above keywords. The "[ =()]" 318fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# bit is meant to avoid matching these keywords outside of boolean expressions. 319fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# 320fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# False positives include C-style multi-line comments (http://go/nsiut ) 321fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# and multi-line strings (http://go/beujw ), but those have always been 322fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# troublesome for cpplint. 323fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_ALT_TOKEN_REPLACEMENT_PATTERN = re.compile( 324fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)') 325fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 326fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 327fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# These constants define types of headers for use with 328fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# _IncludeState.CheckNextIncludeOrder(). 329fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_C_SYS_HEADER = 1 330fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_CPP_SYS_HEADER = 2 331fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_LIKELY_MY_HEADER = 3 332fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_POSSIBLE_MY_HEADER = 4 333fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_OTHER_HEADER = 5 334fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 335fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# These constants define the current inline assembly state 336fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_NO_ASM = 0 # Outside of inline assembly block 337fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_INSIDE_ASM = 1 # Inside inline assembly block 338fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_END_ASM = 2 # Last line of inline assembly block 339fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_BLOCK_ASM = 3 # The whole block is an inline assembly block 340fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 341fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Match start of assembly blocks 342fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)' 343fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'(?:\s+(volatile|__volatile__))?' 344fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'\s*[{(]') 345fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 346fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 347fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_regexp_compile_cache = {} 348fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 349fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Finds occurrences of NOLINT or NOLINT(...). 350fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_SUPPRESSION = re.compile(r'\bNOLINT\b(\([^)]*\))?') 351fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 352fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# {str, set(int)}: a map from error categories to sets of linenumbers 353fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# on which those errors are expected and should be suppressed. 354fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_error_suppressions = {} 355fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 356fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# The root directory used for deriving header guard CPP variable. 357fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# This is set by --root flag. 358fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_root = None 359fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 360fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef ParseNolintSuppressions(filename, raw_line, linenum, error): 361fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Updates the global list of error-suppressions. 362fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 363fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Parses any NOLINT comments on the current line, updating the global 364fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error_suppressions store. Reports an error if the NOLINT comment 365fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov was malformed. 366fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 367fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 368fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: str, the name of the input file. 369fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov raw_line: str, the line of input text, with comments. 370fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: int, the number of the current line. 371fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: function, an error handler. 372fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 373fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # FIXME(adonovan): "NOLINT(" is misparsed as NOLINT(*). 374fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov matched = _RE_SUPPRESSION.search(raw_line) 375fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if matched: 376fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov category = matched.group(1) 377fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if category in (None, '(*)'): # => "suppress all" 378fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _error_suppressions.setdefault(None, set()).add(linenum) 379fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 380fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if category.startswith('(') and category.endswith(')'): 381fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov category = category[1:-1] 382fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if category in _ERROR_CATEGORIES: 383fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _error_suppressions.setdefault(category, set()).add(linenum) 384fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 385fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/nolint', 5, 386fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Unknown NOLINT error category: %s' % category) 387fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 388fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 389fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef ResetNolintSuppressions(): 390fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov "Resets the set of NOLINT suppressions to empty." 391fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _error_suppressions.clear() 392fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 393fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 394fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef IsErrorSuppressedByNolint(category, linenum): 395fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Returns true if the specified error category is suppressed on this line. 396fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 397fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Consults the global error_suppressions map populated by 398fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ParseNolintSuppressions/ResetNolintSuppressions. 399fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 400fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 401fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov category: str, the category of the error. 402fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: int, the current line number. 403fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 404fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov bool, True iff the error should be suppressed due to a NOLINT comment. 405fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 406fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return (linenum in _error_suppressions.get(category, set()) or 407fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum in _error_suppressions.get(None, set())) 408fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 409fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef Match(pattern, s): 410fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Matches the string with the pattern, caching the compiled regexp.""" 411fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # The regexp compilation caching is inlined in both Match and Search for 412fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # performance reasons; factoring it out into a separate function turns out 413fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # to be noticeably expensive. 414fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not pattern in _regexp_compile_cache: 415fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _regexp_compile_cache[pattern] = sre_compile.compile(pattern) 416fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return _regexp_compile_cache[pattern].match(s) 417fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 418fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 419fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef Search(pattern, s): 420fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Searches the string for the pattern, caching the compiled regexp.""" 421fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not pattern in _regexp_compile_cache: 422fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _regexp_compile_cache[pattern] = sre_compile.compile(pattern) 423fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return _regexp_compile_cache[pattern].search(s) 424fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 425fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 426fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass _IncludeState(dict): 427fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Tracks line numbers for includes, and the order in which includes appear. 428fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 429fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov As a dict, an _IncludeState object serves as a mapping between include 430fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename and line number on which that file was included. 431fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 432fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Call CheckNextIncludeOrder() once for each header in the file, passing 433fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov in the type constants defined above. Calls in an illegal order will 434fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov raise an _IncludeError with an appropriate error message. 435fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 436fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 437fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # self._section will move monotonically through this set. If it ever 438fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # needs to move backwards, CheckNextIncludeOrder will raise an error. 439fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _INITIAL_SECTION = 0 440fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _MY_H_SECTION = 1 441fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _C_SECTION = 2 442fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _CPP_SECTION = 3 443fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _OTHER_H_SECTION = 4 444fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 445fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _TYPE_NAMES = { 446fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _C_SYS_HEADER: 'C system header', 447fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _CPP_SYS_HEADER: 'C++ system header', 448fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _LIKELY_MY_HEADER: 'header this file implements', 449fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _POSSIBLE_MY_HEADER: 'header this file may implement', 450fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _OTHER_HEADER: 'other header', 451fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov } 452fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _SECTION_NAMES = { 453fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _INITIAL_SECTION: "... nothing. (This can't be an error.)", 454fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _MY_H_SECTION: 'a header this file implements', 455fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _C_SECTION: 'C system header', 456fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _CPP_SECTION: 'C++ system header', 457fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _OTHER_H_SECTION: 'other header', 458fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov } 459fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 460fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def __init__(self): 461fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov dict.__init__(self) 462fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # The name of the current section. 463fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self._section = self._INITIAL_SECTION 464fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # The path of last found header. 465fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self._last_header = '' 466fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 467fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def CanonicalizeAlphabeticalOrder(self, header_path): 468fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Returns a path canonicalized for alphabetical comparison. 469fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 470fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov - replaces "-" with "_" so they both cmp the same. 471fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov - removes '-inl' since we don't require them to be after the main header. 472fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov - lowercase everything, just in case. 473fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 474fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 475fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov header_path: Path to be canonicalized. 476fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 477fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 478fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Canonicalized path. 479fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 480fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return header_path.replace('-inl.h', '.h').replace('-', '_').lower() 481fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 482fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def IsInAlphabeticalOrder(self, header_path): 483fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Check if a header is in alphabetical order with the previous header. 484fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 485fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 486fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov header_path: Header to be checked. 487fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 488fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 489fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns true if the header is in alphabetical order. 490fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 491fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov canonical_header = self.CanonicalizeAlphabeticalOrder(header_path) 492fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if self._last_header > canonical_header: 493fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return False 494fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self._last_header = canonical_header 495fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return True 496fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 497fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def CheckNextIncludeOrder(self, header_type): 498fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Returns a non-empty error message if the next header is out of order. 499fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 500fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov This function also updates the internal state to be ready to check 501fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov the next include. 502fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 503fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 504fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov header_type: One of the _XXX_HEADER constants defined above. 505fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 506fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 507fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov The empty string if the header is in the right order, or an 508fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error message describing what's wrong. 509fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 510fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 511fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error_message = ('Found %s after %s' % 512fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (self._TYPE_NAMES[header_type], 513fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self._SECTION_NAMES[self._section])) 514fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 515fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov last_section = self._section 516fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 517fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if header_type == _C_SYS_HEADER: 518fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if self._section <= self._C_SECTION: 519fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self._section = self._C_SECTION 520fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 521fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self._last_header = '' 522fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return error_message 523fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif header_type == _CPP_SYS_HEADER: 524fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if self._section <= self._CPP_SECTION: 525fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self._section = self._CPP_SECTION 526fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 527fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self._last_header = '' 528fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return error_message 529fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif header_type == _LIKELY_MY_HEADER: 530fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if self._section <= self._MY_H_SECTION: 531fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self._section = self._MY_H_SECTION 532fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 533fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self._section = self._OTHER_H_SECTION 534fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif header_type == _POSSIBLE_MY_HEADER: 535fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if self._section <= self._MY_H_SECTION: 536fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self._section = self._MY_H_SECTION 537fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 538fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # This will always be the fallback because we're not sure 539fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # enough that the header is associated with this file. 540fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self._section = self._OTHER_H_SECTION 541fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 542fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov assert header_type == _OTHER_HEADER 543fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self._section = self._OTHER_H_SECTION 544fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 545fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if last_section != self._section: 546fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self._last_header = '' 547fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 548fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return '' 549fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 550fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 551fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass _CppLintState(object): 552fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Maintains module-wide state..""" 553fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 554fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def __init__(self): 555fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.verbose_level = 1 # global setting. 556fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.error_count = 0 # global count of reported errors 557fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # filters to apply when emitting error messages 558fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.filters = _DEFAULT_FILTERS[:] 559fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.counting = 'total' # In what way are we counting errors? 560fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.errors_by_category = {} # string to int dict storing error counts 561fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 562fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # output format: 563fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # "emacs" - format that emacs can parse (default) 564fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # "vs7" - format that Microsoft Visual Studio 7 can parse 565fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.output_format = 'emacs' 566fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 567fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def SetOutputFormat(self, output_format): 568fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Sets the output format for errors.""" 569fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.output_format = output_format 570fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 571fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def SetVerboseLevel(self, level): 572fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Sets the module's verbosity, and returns the previous setting.""" 573fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov last_verbose_level = self.verbose_level 574fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.verbose_level = level 575fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return last_verbose_level 576fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 577fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def SetCountingStyle(self, counting_style): 578fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Sets the module's counting options.""" 579fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.counting = counting_style 580fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 581fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def SetFilters(self, filters): 582fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Sets the error-message filters. 583fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 584fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov These filters are applied when deciding whether to emit a given 585fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error message. 586fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 587fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 588fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filters: A string of comma-separated filters (eg "+whitespace/indent"). 589fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Each filter should start with + or -; else we die. 590fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 591fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Raises: 592fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ValueError: The comma-separated filters did not all start with '+' or '-'. 593fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter" 594fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 595fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Default filters always have less priority than the flag ones. 596fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.filters = _DEFAULT_FILTERS[:] 597fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for filt in filters.split(','): 598fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_filt = filt.strip() 599fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if clean_filt: 600fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.filters.append(clean_filt) 601fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for filt in self.filters: 602fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not (filt.startswith('+') or filt.startswith('-')): 603fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov raise ValueError('Every filter in --filters must start with + or -' 604fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ' (%s does not)' % filt) 605fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 606fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def ResetErrorCounts(self): 607fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Sets the module's error statistic back to zero.""" 608fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.error_count = 0 609fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.errors_by_category = {} 610fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 611fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def IncrementErrorCount(self, category): 612fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Bumps the module's error statistic.""" 613fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.error_count += 1 614fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if self.counting in ('toplevel', 'detailed'): 615fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if self.counting != 'detailed': 616fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov category = category.split('/')[0] 617fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if category not in self.errors_by_category: 618fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.errors_by_category[category] = 0 619fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.errors_by_category[category] += 1 620fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 621fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def PrintErrorCounts(self): 622fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Print a summary of errors by category, and the total.""" 623fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for category, count in self.errors_by_category.iteritems(): 624fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov sys.stderr.write('Category \'%s\' errors found: %d\n' % 625fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (category, count)) 626fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov sys.stderr.write('Total errors found: %d\n' % self.error_count) 627fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 628fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_cpplint_state = _CppLintState() 629fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 630fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 631fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _OutputFormat(): 632fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Gets the module's output format.""" 633fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return _cpplint_state.output_format 634fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 635fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 636fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _SetOutputFormat(output_format): 637fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Sets the module's output format.""" 638fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _cpplint_state.SetOutputFormat(output_format) 639fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 640fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 641fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _VerboseLevel(): 642fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Returns the module's verbosity setting.""" 643fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return _cpplint_state.verbose_level 644fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 645fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 646fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _SetVerboseLevel(level): 647fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Sets the module's verbosity, and returns the previous setting.""" 648fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return _cpplint_state.SetVerboseLevel(level) 649fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 650fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 651fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _SetCountingStyle(level): 652fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Sets the module's counting options.""" 653fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _cpplint_state.SetCountingStyle(level) 654fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 655fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 656fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _Filters(): 657fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Returns the module's list of output filters, as a list.""" 658fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return _cpplint_state.filters 659fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 660fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 661fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _SetFilters(filters): 662fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Sets the module's error-message filters. 663fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 664fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov These filters are applied when deciding whether to emit a given 665fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error message. 666fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 667fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 668fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filters: A string of comma-separated filters (eg "whitespace/indent"). 669fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Each filter should start with + or -; else we die. 670fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 671fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _cpplint_state.SetFilters(filters) 672fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 673fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 674fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass _FunctionState(object): 675fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Tracks current function name and the number of lines in its body.""" 676fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 677fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc. 678fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER. 679fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 680fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def __init__(self): 681fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.in_a_function = False 682fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.lines_in_function = 0 683fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.current_function = '' 684fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 685fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def Begin(self, function_name): 686fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Start analyzing function body. 687fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 688fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 689fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov function_name: The name of the function being tracked. 690fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 691fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.in_a_function = True 692fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.lines_in_function = 0 693fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.current_function = function_name 694fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 695fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def Count(self): 696fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Count line in current function body.""" 697fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if self.in_a_function: 698fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.lines_in_function += 1 699fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 700fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def Check(self, error, filename, linenum): 701fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Report if too many lines in function body. 702fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 703fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 704fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 705fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 706fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 707fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 708fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r'T(EST|est)', self.current_function): 709fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov base_trigger = self._TEST_TRIGGER 710fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 711fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov base_trigger = self._NORMAL_TRIGGER 712fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov trigger = base_trigger * 2**_VerboseLevel() 713fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 714fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if self.lines_in_function > trigger: 715fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error_level = int(math.log(self.lines_in_function / base_trigger, 2)) 716fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ... 717fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if error_level > 5: 718fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error_level = 5 719fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/fn_size', error_level, 720fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Small and focused functions are preferred:' 721fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ' %s has %d non-comment lines' 722fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ' (error triggered by exceeding %d lines).' % ( 723fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.current_function, self.lines_in_function, trigger)) 724fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 725fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def End(self): 726fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Stop analyzing function body.""" 727fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.in_a_function = False 728fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 729fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 730fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass _IncludeError(Exception): 731fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Indicates a problem with the include order in a file.""" 732fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov pass 733fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 734fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 735fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass FileInfo: 736fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Provides utility functions for filenames. 737fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 738fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov FileInfo provides easy access to the components of a file's path 739fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov relative to the project root. 740fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 741fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 742fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def __init__(self, filename): 743fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self._filename = filename 744fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 745fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def FullName(self): 746fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Make Windows paths like Unix.""" 747fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return os.path.abspath(self._filename).replace('\\', '/') 748fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 749fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def RepositoryName(self): 750fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """FullName after removing the local path to the repository. 751fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 752fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov If we have a real absolute path name here we can try to do something smart: 753fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov detecting the root of the checkout and truncating /path/to/checkout from 754fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov the name so that we get header guards that don't include things like 755fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov "C:\Documents and Settings\..." or "/home/username/..." in them and thus 756fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov people on different computers who have checked the source out to different 757fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov locations won't see bogus errors. 758fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 759fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov fullname = self.FullName() 760fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 761fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if os.path.exists(fullname): 762fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov project_dir = os.path.dirname(fullname) 763fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 764fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if os.path.exists(os.path.join(project_dir, ".svn")): 765fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If there's a .svn file in the current directory, we recursively look 766fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # up the directory tree for the top of the SVN checkout 767fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov root_dir = project_dir 768fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov one_up_dir = os.path.dirname(root_dir) 769fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov while os.path.exists(os.path.join(one_up_dir, ".svn")): 770fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov root_dir = os.path.dirname(root_dir) 771fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov one_up_dir = os.path.dirname(one_up_dir) 772fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 773fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov prefix = os.path.commonprefix([root_dir, project_dir]) 774fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return fullname[len(prefix) + 1:] 775fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 776fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Not SVN <= 1.6? Try to find a git, hg, or svn top level directory by 777fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # searching up from the current path. 778fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov root_dir = os.path.dirname(fullname) 779fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov while (root_dir != os.path.dirname(root_dir) and 780fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not os.path.exists(os.path.join(root_dir, ".git")) and 781fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not os.path.exists(os.path.join(root_dir, ".hg")) and 782fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not os.path.exists(os.path.join(root_dir, ".svn"))): 783fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov root_dir = os.path.dirname(root_dir) 784fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 785fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (os.path.exists(os.path.join(root_dir, ".git")) or 786fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov os.path.exists(os.path.join(root_dir, ".hg")) or 787fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov os.path.exists(os.path.join(root_dir, ".svn"))): 788fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov prefix = os.path.commonprefix([root_dir, project_dir]) 789fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return fullname[len(prefix) + 1:] 790fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 791fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Don't know what to do; header guard warnings may be wrong... 792fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return fullname 793fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 794fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def Split(self): 795fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Splits the file into the directory, basename, and extension. 796fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 797fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov For 'chrome/browser/browser.cc', Split() would 798fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return ('chrome/browser', 'browser', '.cc') 799fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 800fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 801fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov A tuple of (directory, basename, extension). 802fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 803fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 804fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov googlename = self.RepositoryName() 805fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov project, rest = os.path.split(googlename) 806fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return (project,) + os.path.splitext(rest) 807fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 808fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def BaseName(self): 809fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """File base name - text after the final slash, before the final period.""" 810fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return self.Split()[1] 811fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 812fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def Extension(self): 813fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """File extension - text following the final period.""" 814fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return self.Split()[2] 815fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 816fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def NoExtension(self): 817fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """File has no source file extension.""" 818fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return '/'.join(self.Split()[0:2]) 819fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 820fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def IsSource(self): 821fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """File has a source file extension.""" 822fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return self.Extension()[1:] in ('c', 'cc', 'cpp', 'cxx') 823fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 824fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 825fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _ShouldPrintError(category, confidence, linenum): 826fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """If confidence >= verbose, category passes filter and is not suppressed.""" 827fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 828fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # There are three ways we might decide not to print an error message: 829fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # a "NOLINT(category)" comment appears in the source, 830fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # the verbosity level isn't high enough, or the filters filter it out. 831fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if IsErrorSuppressedByNolint(category, linenum): 832fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return False 833fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if confidence < _cpplint_state.verbose_level: 834fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return False 835fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 836fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov is_filtered = False 837fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for one_filter in _Filters(): 838fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if one_filter.startswith('-'): 839fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if category.startswith(one_filter[1:]): 840fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov is_filtered = True 841fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif one_filter.startswith('+'): 842fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if category.startswith(one_filter[1:]): 843fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov is_filtered = False 844fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 845fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov assert False # should have been checked for in SetFilter. 846fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if is_filtered: 847fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return False 848fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 849fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return True 850fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 851fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 852fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef Error(filename, linenum, category, confidence, message): 853fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Logs the fact we've found a lint error. 854fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 855fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov We log where the error was found, and also our confidence in the error, 856fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov that is, how certain we are this is a legitimate style regression, and 857fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not a misidentification or a use that's sometimes justified. 858fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 859fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov False positives can be suppressed by the use of 860fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov "cpplint(category)" comments on the offending line. These are 861fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov parsed into _error_suppressions. 862fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 863fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 864fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the file containing the error. 865fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line containing the error. 866fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov category: A string used to describe the "category" this bug 867fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov falls under: "whitespace", say, or "runtime". Categories 868fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov may have a hierarchy separated by slashes: "whitespace/indent". 869fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov confidence: A number from 1-5 representing a confidence score for 870fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov the error, with 5 meaning that we are certain of the problem, 871fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov and 1 meaning that it could be a legitimate construct. 872fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov message: The error message. 873fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 874fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if _ShouldPrintError(category, confidence, linenum): 875fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _cpplint_state.IncrementErrorCount(category) 876fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if _cpplint_state.output_format == 'vs7': 877fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov sys.stderr.write('%s(%s): %s [%s] [%d]\n' % ( 878fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename, linenum, message, category, confidence)) 879fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif _cpplint_state.output_format == 'eclipse': 880fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov sys.stderr.write('%s:%s: warning: %s [%s] [%d]\n' % ( 881fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename, linenum, message, category, confidence)) 882fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 883fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov sys.stderr.write('%s:%s: %s [%s] [%d]\n' % ( 884fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename, linenum, message, category, confidence)) 885fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 886fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 887fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Matches standard C++ escape esequences per 2.13.2.3 of the C++ standard. 888fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile( 889fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)') 890fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Matches strings. Escape codes should already be removed by ESCAPES. 891fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES = re.compile(r'"[^"]*"') 892fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Matches characters. Escape codes should already be removed by ESCAPES. 893fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES = re.compile(r"'.'") 894fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Matches multi-line C++ comments. 895fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# This RE is a little bit more complicated than one might expect, because we 896fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# have to take care of space removals tools so we can handle comments inside 897fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# statements better. 898fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# The current rule is: We only clear spaces from both sides when we're at the 899fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# end of the line. Otherwise, we try to remove spaces from the right side, 900fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# if this doesn't work we try on left side but only if there's a non-character 901fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# on the right. 902fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile( 903fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r"""(\s*/\*.*\*/\s*$| 904fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov /\*.*\*/\s+| 905fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov \s+/\*.*\*/(?=\W)| 906fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov /\*.*\*/)""", re.VERBOSE) 907fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 908fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 909fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef IsCppString(line): 910fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Does line terminate so, that the next symbol is in string constant. 911fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 912fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov This function does not consider single-line nor multi-line comments. 913fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 914fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 915fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line: is a partial line of code starting from the 0..n. 916fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 917fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 918fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov True, if next character appended to 'line' is inside a 919fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov string constant. 920fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 921fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 922fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = line.replace(r'\\', 'XX') # after this, \\" does not match to \" 923fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1 924fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 925fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 926fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef FindNextMultiLineCommentStart(lines, lineix): 927fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Find the beginning marker for a multiline comment.""" 928fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov while lineix < len(lines): 929fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if lines[lineix].strip().startswith('/*'): 930fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Only return this marker if the comment goes beyond this line 931fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if lines[lineix].strip().find('*/', 2) < 0: 932fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return lineix 933fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov lineix += 1 934fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return len(lines) 935fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 936fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 937fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef FindNextMultiLineCommentEnd(lines, lineix): 938fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """We are inside a comment, find the end marker.""" 939fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov while lineix < len(lines): 940fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if lines[lineix].strip().endswith('*/'): 941fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return lineix 942fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov lineix += 1 943fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return len(lines) 944fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 945fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 946fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef RemoveMultiLineCommentsFromRange(lines, begin, end): 947fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Clears a range of lines for multi-line comments.""" 948fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Having // dummy comments makes the lines non-empty, so we will not get 949fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # unnecessary blank line warnings later in the code. 950fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for i in range(begin, end): 951fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov lines[i] = '// dummy' 952fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 953fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 954fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef RemoveMultiLineComments(filename, lines, error): 955fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Removes multiline (c-style) comments from lines.""" 956fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov lineix = 0 957fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov while lineix < len(lines): 958fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov lineix_begin = FindNextMultiLineCommentStart(lines, lineix) 959fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if lineix_begin >= len(lines): 960fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return 961fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin) 962fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if lineix_end >= len(lines): 963fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, lineix_begin + 1, 'readability/multiline_comment', 5, 964fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Could not find end of multi-line comment') 965fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return 966fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1) 967fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov lineix = lineix_end + 1 968fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 969fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 970fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CleanseComments(line): 971fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Removes //-comments and single-line C-style /* */ comments. 972fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 973fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 974fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line: A line of C++ source. 975fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 976fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 977fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov The line with single-line comments removed. 978fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 979fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov commentpos = line.find('//') 980fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if commentpos != -1 and not IsCppString(line[:commentpos]): 981fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = line[:commentpos].rstrip() 982fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # get rid of /* ... */ 983fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line) 984fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 985fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 986fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass CleansedLines(object): 987fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Holds 3 copies of all lines with different preprocessing applied to them. 988fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 989fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1) elided member contains lines without strings and comments, 990fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2) lines member contains lines without comments, and 991fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3) raw_lines member contains all the lines without processing. 992fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov All these three members are of <type 'list'>, and of the same length. 993fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 994fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 995fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def __init__(self, lines): 996fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.elided = [] 997fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.lines = [] 998fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.raw_lines = lines 999fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.num_lines = len(lines) 1000fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for linenum in range(len(lines)): 1001fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.lines.append(CleanseComments(lines[linenum])) 1002fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elided = self._CollapseStrings(lines[linenum]) 1003fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.elided.append(CleanseComments(elided)) 1004fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1005fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def NumLines(self): 1006fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Returns the number of lines represented.""" 1007fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return self.num_lines 1008fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1009fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov @staticmethod 1010fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def _CollapseStrings(elided): 1011fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Collapses strings and chars on a line to simple "" or '' blocks. 1012fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1013fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov We nix strings first so we're not fooled by text like '"http://"' 1014fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1015fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1016fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elided: The line being processed. 1017fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1018fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 1019fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov The line with collapsed strings. 1020fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1021fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not _RE_PATTERN_INCLUDE.match(elided): 1022fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Remove escaped characters first to make quote/single quote collapsing 1023fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # basic. Things that look like escaped characters shouldn't occur 1024fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # outside of strings and chars. 1025fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided) 1026fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elided = _RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES.sub("''", elided) 1027fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elided = _RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES.sub('""', elided) 1028fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return elided 1029fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1030fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1031fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef FindEndOfExpressionInLine(line, startpos, depth, startchar, endchar): 1032fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Find the position just after the matching endchar. 1033fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1034fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1035fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line: a CleansedLines line. 1036fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov startpos: start searching at this position. 1037fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov depth: nesting level at startpos. 1038fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov startchar: expression opening character. 1039fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov endchar: expression closing character. 1040fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1041fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 1042fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Index just after endchar. 1043fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1044fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for i in xrange(startpos, len(line)): 1045fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if line[i] == startchar: 1046fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov depth += 1 1047fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif line[i] == endchar: 1048fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov depth -= 1 1049fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if depth == 0: 1050fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return i + 1 1051fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return -1 1052fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1053fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1054fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CloseExpression(clean_lines, linenum, pos): 1055fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """If input points to ( or { or [, finds the position that closes it. 1056fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1057fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov If lines[linenum][pos] points to a '(' or '{' or '[', finds the 1058fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum/pos that correspond to the closing of the expression. 1059fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1060fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1061fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 1062fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 1063fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov pos: A position on the line. 1064fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1065fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 1066fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov A tuple (line, linenum, pos) pointer *past* the closing brace, or 1067fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (line, len(lines), -1) if we never find a close. Note we ignore 1068fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov strings and comments when matching; and the line we return is the 1069fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'cleansed' line at linenum. 1070fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1071fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1072fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.elided[linenum] 1073fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov startchar = line[pos] 1074fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if startchar not in '({[': 1075fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return (line, clean_lines.NumLines(), -1) 1076fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if startchar == '(': endchar = ')' 1077fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if startchar == '[': endchar = ']' 1078fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if startchar == '{': endchar = '}' 1079fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1080fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Check first line 1081fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov end_pos = FindEndOfExpressionInLine(line, pos, 0, startchar, endchar) 1082fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if end_pos > -1: 1083fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return (line, linenum, end_pos) 1084fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov tail = line[pos:] 1085fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov num_open = tail.count(startchar) - tail.count(endchar) 1086fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov while linenum < clean_lines.NumLines() - 1: 1087fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum += 1 1088fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.elided[linenum] 1089fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov delta = line.count(startchar) - line.count(endchar) 1090fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if num_open + delta <= 0: 1091fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return (line, linenum, 1092fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov FindEndOfExpressionInLine(line, 0, num_open, startchar, endchar)) 1093fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov num_open += delta 1094fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1095fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Did not find endchar before end of file, give up 1096fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return (line, clean_lines.NumLines(), -1) 1097fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1098fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckForCopyright(filename, lines, error): 1099fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Logs an error if no Copyright message appears at the top of the file.""" 1100fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1101fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # We'll say it should occur by line 10. Don't forget there's a 1102fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # dummy line at the front. 1103fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for line in xrange(1, min(len(lines), 11)): 1104fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if re.search(r'Copyright', lines[line], re.I): break 1105fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: # means no copyright line was found 1106fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, 0, 'legal/copyright', 5, 1107fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'No copyright message found. ' 1108fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'You should have a line: "Copyright [year] <Copyright Owner>"') 1109fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1110fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1111fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef GetHeaderGuardCPPVariable(filename): 1112fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Returns the CPP variable that should be used as a header guard. 1113fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1114fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1115fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of a C++ header file. 1116fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1117fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 1118fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov The CPP variable that should be used as a header guard in the 1119fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov named file. 1120fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1121fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1122fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1123fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Restores original filename in case that cpplint is invoked from Emacs's 1124fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # flymake. 1125fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename = re.sub(r'_flymake\.h$', '.h', filename) 1126fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename = re.sub(r'/\.flymake/([^/]*)$', r'/\1', filename) 1127fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1128fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov fileinfo = FileInfo(filename) 1129fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov file_path_from_root = fileinfo.RepositoryName() 1130fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if _root: 1131fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov file_path_from_root = re.sub('^' + _root + os.sep, '', file_path_from_root) 1132