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) 1132fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return re.sub(r'[-./\s]', '_', file_path_from_root).upper() + '_' 1133fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1134fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1135fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckForHeaderGuard(filename, lines, error): 1136fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Checks that the file contains a header guard. 1137fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1138fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Logs an error if no #ifndef header guard is present. For other 1139fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov headers, checks that the full pathname is used. 1140fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1141fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1142fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the C++ header file. 1143fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov lines: An array of strings, each representing a line of the file. 1144fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 1145fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1146fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1147fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov cppvar = GetHeaderGuardCPPVariable(filename) 1148fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1149fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ifndef = None 1150fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ifndef_linenum = 0 1151fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov define = None 1152fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov endif = None 1153fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov endif_linenum = 0 1154fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for linenum, line in enumerate(lines): 1155fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linesplit = line.split() 1156fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if len(linesplit) >= 2: 1157fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # find the first occurrence of #ifndef and #define, save arg 1158fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not ifndef and linesplit[0] == '#ifndef': 1159fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # set ifndef to the header guard presented on the #ifndef line. 1160fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ifndef = linesplit[1] 1161fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ifndef_linenum = linenum 1162fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not define and linesplit[0] == '#define': 1163fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov define = linesplit[1] 1164fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # find the last occurrence of #endif, save entire line 1165fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if line.startswith('#endif'): 1166fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov endif = line 1167fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov endif_linenum = linenum 1168fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1169fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not ifndef: 1170fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, 0, 'build/header_guard', 5, 1171fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'No #ifndef header guard found, suggested CPP variable is: %s' % 1172fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov cppvar) 1173fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return 1174fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1175fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not define: 1176fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, 0, 'build/header_guard', 5, 1177fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'No #define header guard found, suggested CPP variable is: %s' % 1178fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov cppvar) 1179fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return 1180fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1181fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__ 1182fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # for backward compatibility. 1183fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if ifndef != cppvar: 1184fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error_level = 0 1185fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if ifndef != cppvar + '_': 1186fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error_level = 5 1187fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1188fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ParseNolintSuppressions(filename, lines[ifndef_linenum], ifndef_linenum, 1189fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error) 1190fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, ifndef_linenum, 'build/header_guard', error_level, 1191fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '#ifndef header guard has wrong style, please use: %s' % cppvar) 1192fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1193fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if define != ifndef: 1194fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, 0, 'build/header_guard', 5, 1195fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '#ifndef and #define don\'t match, suggested CPP variable is: %s' % 1196fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov cppvar) 1197fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return 1198fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1199fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if endif != ('#endif // %s' % cppvar): 1200fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error_level = 0 1201fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if endif != ('#endif // %s' % (cppvar + '_')): 1202fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error_level = 5 1203fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1204fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ParseNolintSuppressions(filename, lines[endif_linenum], endif_linenum, 1205fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error) 1206fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, endif_linenum, 'build/header_guard', error_level, 1207fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '#endif line should be "#endif // %s"' % cppvar) 1208fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1209fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1210fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckForUnicodeReplacementCharacters(filename, lines, error): 1211fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Logs an error for each line containing Unicode replacement characters. 1212fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1213fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov These indicate that either the file contained invalid UTF-8 (likely) 1214fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov or Unicode replacement characters (which it shouldn't). Note that 1215fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov it's possible for this to throw off line numbering if the invalid 1216fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov UTF-8 occurred adjacent to a newline. 1217fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1218fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1219fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 1220fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov lines: An array of strings, each representing a line of the file. 1221fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 1222fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1223fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for linenum, line in enumerate(lines): 1224fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if u'\ufffd' in line: 1225fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/utf8', 5, 1226fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Line contains invalid UTF-8 (or Unicode replacement character).') 1227fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1228fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1229fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckForNewlineAtEOF(filename, lines, error): 1230fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Logs an error if there is no newline char at the end of the file. 1231fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1232fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1233fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 1234fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov lines: An array of strings, each representing a line of the file. 1235fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 1236fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1237fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1238fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # The array lines() was created by adding two newlines to the 1239fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # original file (go figure), then splitting on \n. 1240fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # To verify that the file ends in \n, we just have to make sure the 1241fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # last-but-two element of lines() exists and is empty. 1242fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if len(lines) < 3 or lines[-2]: 1243fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, len(lines) - 2, 'whitespace/ending_newline', 5, 1244fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Could not find a newline character at the end of the file.') 1245fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1246fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1247fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error): 1248fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Logs an error if we see /* ... */ or "..." that extend past one line. 1249fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1250fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov /* ... */ comments are legit inside macros, for one line. 1251fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Otherwise, we prefer // comments, so it's ok to warn about the 1252fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov other. Likewise, it's ok for strings to extend across multiple 1253fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov lines, as long as a line continuation character (backslash) 1254fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov terminates each line. Although not currently prohibited by the C++ 1255fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov style guide, it's ugly and unnecessary. We don't do well with either 1256fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov in this lint program, so we warn about both. 1257fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1258fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1259fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 1260fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 1261fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 1262fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 1263fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1264fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.elided[linenum] 1265fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1266fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Remove all \\ (escaped backslashes) from the line. They are OK, and the 1267fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # second (escaped) slash may trigger later \" detection erroneously. 1268fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = line.replace('\\\\', '') 1269fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1270fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if line.count('/*') > line.count('*/'): 1271fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/multiline_comment', 5, 1272fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Complex multi-line /*...*/-style comment found. ' 1273fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Lint may give bogus warnings. ' 1274fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Consider replacing these with //-style comments, ' 1275fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'with #if 0...#endif, ' 1276fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'or with more clearly structured multi-line comments.') 1277fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1278fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (line.count('"') - line.count('\\"')) % 2: 1279fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/multiline_string', 5, 1280fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Multi-line string ("...") found. This lint script doesn\'t ' 1281fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'do well with such strings, and may give bogus warnings. They\'re ' 1282fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'ugly and unnecessary, and you should use concatenation instead".') 1283fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1284fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1285fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovthreading_list = ( 1286fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('asctime(', 'asctime_r('), 1287fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('ctime(', 'ctime_r('), 1288fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('getgrgid(', 'getgrgid_r('), 1289fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('getgrnam(', 'getgrnam_r('), 1290fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('getlogin(', 'getlogin_r('), 1291fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('getpwnam(', 'getpwnam_r('), 1292fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('getpwuid(', 'getpwuid_r('), 1293fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('gmtime(', 'gmtime_r('), 1294fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('localtime(', 'localtime_r('), 1295fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('rand(', 'rand_r('), 1296fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('readdir(', 'readdir_r('), 1297fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('strtok(', 'strtok_r('), 1298fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('ttyname(', 'ttyname_r('), 1299fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ) 1300fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1301fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1302fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckPosixThreading(filename, clean_lines, linenum, error): 1303fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Checks for calls to thread-unsafe functions. 1304fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1305fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Much code has been originally written without consideration of 1306fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov multi-threading. Also, engineers are relying on their old experience; 1307fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov they have learned posix before threading extensions were added. These 1308fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov tests guide the engineers to use thread-safe functions (when using 1309fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov posix directly). 1310fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1311fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1312fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 1313fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 1314fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 1315fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 1316fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1317fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.elided[linenum] 1318fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for single_thread_function, multithread_safe_function in threading_list: 1319fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ix = line.find(single_thread_function) 1320fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Comparisons made explicit for clarity -- pylint: disable-msg=C6403 1321fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if ix >= 0 and (ix == 0 or (not line[ix - 1].isalnum() and 1322fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line[ix - 1] not in ('_', '.', '>'))): 1323fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/threadsafe_fn', 2, 1324fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Consider using ' + multithread_safe_function + 1325fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '...) instead of ' + single_thread_function + 1326fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '...) for improved thread safety.') 1327fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1328fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1329fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Matches invalid increment: *count++, which moves pointer instead of 1330fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# incrementing a value. 1331fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_INVALID_INCREMENT = re.compile( 1332fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'^\s*\*\w+(\+\+|--);') 1333fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1334fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1335fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckInvalidIncrement(filename, clean_lines, linenum, error): 1336fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Checks for invalid increment *count++. 1337fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1338fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov For example following function: 1339fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov void increment_counter(int* count) { 1340fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov *count++; 1341fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov } 1342fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov is invalid, because it effectively does count++, moving pointer, and should 1343fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov be replaced with ++*count, (*count)++ or *count += 1. 1344fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1345fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1346fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 1347fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 1348fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 1349fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 1350fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1351fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.elided[linenum] 1352fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if _RE_PATTERN_INVALID_INCREMENT.match(line): 1353fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/invalid_increment', 5, 1354fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Changing pointer instead of value (or unused value of operator*).') 1355fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1356fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1357fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass _BlockInfo(object): 1358fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Stores information about a generic block of code.""" 1359fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1360fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def __init__(self, seen_open_brace): 1361fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.seen_open_brace = seen_open_brace 1362fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.open_parentheses = 0 1363fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.inline_asm = _NO_ASM 1364fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1365fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def CheckBegin(self, filename, clean_lines, linenum, error): 1366fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Run checks that applies to text up to the opening brace. 1367fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1368fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov This is mostly for checking the text after the class identifier 1369fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov and the "{", usually where the base class is specified. For other 1370fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov blocks, there isn't much to check, so we always pass. 1371fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1372fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1373fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 1374fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 1375fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 1376fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 1377fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1378fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov pass 1379fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1380fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def CheckEnd(self, filename, clean_lines, linenum, error): 1381fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Run checks that applies to text after the closing brace. 1382fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1383fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov This is mostly used for checking end of namespace comments. 1384fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1385fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1386fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 1387fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 1388fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 1389fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 1390fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1391fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov pass 1392fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1393fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1394fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass _ClassInfo(_BlockInfo): 1395fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Stores information about a class.""" 1396fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1397fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def __init__(self, name, class_or_struct, clean_lines, linenum): 1398fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _BlockInfo.__init__(self, False) 1399fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.name = name 1400fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.starting_linenum = linenum 1401fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.is_derived = False 1402fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if class_or_struct == 'struct': 1403fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.access = 'public' 1404fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 1405fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.access = 'private' 1406fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1407fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Try to find the end of the class. This will be confused by things like: 1408fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # class A { 1409fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # } *x = { ... 1410fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 1411fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # But it's still good enough for CheckSectionSpacing. 1412fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.last_line = 0 1413fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov depth = 0 1414fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for i in range(linenum, clean_lines.NumLines()): 1415fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.elided[i] 1416fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov depth += line.count('{') - line.count('}') 1417fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not depth: 1418fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.last_line = i 1419fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov break 1420fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1421fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def CheckBegin(self, filename, clean_lines, linenum, error): 1422fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Look for a bare ':' 1423fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search('(^|[^:]):($|[^:])', clean_lines.elided[linenum]): 1424fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.is_derived = True 1425fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1426fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1427fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass _NamespaceInfo(_BlockInfo): 1428fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Stores information about a namespace.""" 1429fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1430fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def __init__(self, name, linenum): 1431fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _BlockInfo.__init__(self, False) 1432fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.name = name or '' 1433fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.starting_linenum = linenum 1434fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1435fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def CheckEnd(self, filename, clean_lines, linenum, error): 1436fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Check end of namespace comments.""" 1437fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.raw_lines[linenum] 1438fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1439fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Check how many lines is enclosed in this namespace. Don't issue 1440fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # warning for missing namespace comments if there aren't enough 1441fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # lines. However, do apply checks if there is already an end of 1442fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # namespace comment and it's incorrect. 1443fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 1444fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # TODO(unknown): We always want to check end of namespace comments 1445fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # if a namespace is large, but sometimes we also want to apply the 1446fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # check if a short namespace contained nontrivial things (something 1447fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # other than forward declarations). There is currently no logic on 1448fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # deciding what these nontrivial things are, so this check is 1449fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # triggered by namespace size only, which works most of the time. 1450fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (linenum - self.starting_linenum < 10 1451fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov and not Match(r'};*\s*(//|/\*).*\bnamespace\b', line)): 1452fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return 1453fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1454fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Look for matching comment at end of namespace. 1455fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 1456fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Note that we accept C style "/* */" comments for terminating 1457fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # namespaces, so that code that terminate namespaces inside 1458fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # preprocessor macros can be cpplint clean. Example: http://go/nxpiz 1459fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 1460fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # We also accept stuff like "// end of namespace <name>." with the 1461fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # period at the end. 1462fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 1463fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Besides these, we don't accept anything else, otherwise we might 1464fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # get false negatives when existing comment is a substring of the 1465fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # expected namespace. Example: http://go/ldkdc, http://cl/23548205 1466fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if self.name: 1467fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Named namespace 1468fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not Match((r'};*\s*(//|/\*).*\bnamespace\s+' + re.escape(self.name) + 1469fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'[\*/\.\\\s]*$'), 1470fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line): 1471fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/namespace', 5, 1472fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Namespace should be terminated with "// namespace %s"' % 1473fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.name) 1474fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 1475fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Anonymous namespace 1476fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not Match(r'};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line): 1477fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/namespace', 5, 1478fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Namespace should be terminated with "// namespace"') 1479fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1480fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1481fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass _PreprocessorInfo(object): 1482fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Stores checkpoints of nesting stacks when #if/#else is seen.""" 1483fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1484fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def __init__(self, stack_before_if): 1485fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # The entire nesting stack before #if 1486fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.stack_before_if = stack_before_if 1487fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1488fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # The entire nesting stack up to #else 1489fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.stack_before_else = [] 1490fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1491fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Whether we have already seen #else or #elif 1492fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.seen_else = False 1493fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1494fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1495fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovclass _NestingState(object): 1496fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Holds states related to parsing braces.""" 1497fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1498fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def __init__(self): 1499fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Stack for tracking all braces. An object is pushed whenever we 1500fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # see a "{", and popped when we see a "}". Only 3 types of 1501fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # objects are possible: 1502fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # - _ClassInfo: a class or struct. 1503fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # - _NamespaceInfo: a namespace. 1504fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # - _BlockInfo: some other type of block. 1505fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.stack = [] 1506fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1507fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Stack of _PreprocessorInfo objects. 1508fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.pp_stack = [] 1509fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1510fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def SeenOpenBrace(self): 1511fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Check if we have seen the opening brace for the innermost block. 1512fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1513fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 1514fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov True if we have seen the opening brace, False if the innermost 1515fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov block is still expecting an opening brace. 1516fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1517fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return (not self.stack) or self.stack[-1].seen_open_brace 1518fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1519fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def InNamespaceBody(self): 1520fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Check if we are currently one level inside a namespace body. 1521fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1522fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 1523fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov True if top of the stack is a namespace block, False otherwise. 1524fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1525fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return self.stack and isinstance(self.stack[-1], _NamespaceInfo) 1526fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1527fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def UpdatePreprocessor(self, line): 1528fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Update preprocessor stack. 1529fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1530fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov We need to handle preprocessors due to classes like this: 1531fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov #ifdef SWIG 1532fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov struct ResultDetailsPageElementExtensionPoint { 1533fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov #else 1534fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov struct ResultDetailsPageElementExtensionPoint : public Extension { 1535fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov #endif 1536fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (see http://go/qwddn for original example) 1537fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1538fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov We make the following assumptions (good enough for most files): 1539fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov - Preprocessor condition evaluates to true from #if up to first 1540fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov #else/#elif/#endif. 1541fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1542fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov - Preprocessor condition evaluates to false from #else/#elif up 1543fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov to #endif. We still perform lint checks on these lines, but 1544fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov these do not affect nesting stack. 1545fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1546fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1547fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line: current line to check. 1548fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1549fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r'^\s*#\s*(if|ifdef|ifndef)\b', line): 1550fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Beginning of #if block, save the nesting stack here. The saved 1551fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # stack will allow us to restore the parsing state in the #else case. 1552fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.pp_stack.append(_PreprocessorInfo(copy.deepcopy(self.stack))) 1553fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif Match(r'^\s*#\s*(else|elif)\b', line): 1554fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Beginning of #else block 1555fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if self.pp_stack: 1556fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not self.pp_stack[-1].seen_else: 1557fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # This is the first #else or #elif block. Remember the 1558fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # whole nesting stack up to this point. This is what we 1559fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # keep after the #endif. 1560fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.pp_stack[-1].seen_else = True 1561fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.pp_stack[-1].stack_before_else = copy.deepcopy(self.stack) 1562fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1563fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Restore the stack to how it was before the #if 1564fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if) 1565fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 1566fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # TODO(unknown): unexpected #else, issue warning? 1567fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov pass 1568fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif Match(r'^\s*#\s*endif\b', line): 1569fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # End of #if or #else blocks. 1570fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if self.pp_stack: 1571fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If we saw an #else, we will need to restore the nesting 1572fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # stack to its former state before the #else, otherwise we 1573fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # will just continue from where we left off. 1574fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if self.pp_stack[-1].seen_else: 1575fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Here we can just use a shallow copy since we are the last 1576fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # reference to it. 1577fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.stack = self.pp_stack[-1].stack_before_else 1578fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Drop the corresponding #if 1579fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.pp_stack.pop() 1580fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 1581fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # TODO(unknown): unexpected #endif, issue warning? 1582fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov pass 1583fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1584fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def Update(self, filename, clean_lines, linenum, error): 1585fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Update nesting state with current line. 1586fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1587fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1588fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 1589fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 1590fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 1591fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 1592fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1593fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.elided[linenum] 1594fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1595fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Update pp_stack first 1596fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.UpdatePreprocessor(line) 1597fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1598fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Count parentheses. This is to avoid adding struct arguments to 1599fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # the nesting stack. 1600fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if self.stack: 1601fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov inner_block = self.stack[-1] 1602fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov depth_change = line.count('(') - line.count(')') 1603fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov inner_block.open_parentheses += depth_change 1604fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1605fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Also check if we are starting or ending an inline assembly block. 1606fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if inner_block.inline_asm in (_NO_ASM, _END_ASM): 1607fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (depth_change != 0 and 1608fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov inner_block.open_parentheses == 1 and 1609fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _MATCH_ASM.match(line)): 1610fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Enter assembly block 1611fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov inner_block.inline_asm = _INSIDE_ASM 1612fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 1613fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Not entering assembly block. If previous line was _END_ASM, 1614fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # we will now shift to _NO_ASM state. 1615fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov inner_block.inline_asm = _NO_ASM 1616fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif (inner_block.inline_asm == _INSIDE_ASM and 1617fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov inner_block.open_parentheses == 0): 1618fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Exit assembly block 1619fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov inner_block.inline_asm = _END_ASM 1620fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1621fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Consume namespace declaration at the beginning of the line. Do 1622fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # this in a loop so that we catch same line declarations like this: 1623fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # namespace proto2 { namespace bridge { class MessageSet; } } 1624fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov while True: 1625fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Match start of namespace. The "\b\s*" below catches namespace 1626fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # declarations even if it weren't followed by a whitespace, this 1627fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # is so that we don't confuse our namespace checker. The 1628fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # missing spaces will be flagged by CheckSpacing. 1629fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov namespace_decl_match = Match(r'^\s*namespace\b\s*([:\w]+)?(.*)$', line) 1630fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not namespace_decl_match: 1631fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov break 1632fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1633fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov new_namespace = _NamespaceInfo(namespace_decl_match.group(1), linenum) 1634fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.stack.append(new_namespace) 1635fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1636fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = namespace_decl_match.group(2) 1637fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if line.find('{') != -1: 1638fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov new_namespace.seen_open_brace = True 1639fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = line[line.find('{') + 1:] 1640fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1641fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Look for a class declaration in whatever is left of the line 1642fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # after parsing namespaces. The regexp accounts for decorated classes 1643fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # such as in: 1644fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # class LOCKABLE API Object { 1645fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # }; 1646fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 1647fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Templates with class arguments may confuse the parser, for example: 1648fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # template <class T 1649fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # class Comparator = less<T>, 1650fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # class Vector = vector<T> > 1651fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # class HeapQueue { 1652fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 1653fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Because this parser has no nesting state about templates, by the 1654fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # time it saw "class Comparator", it may think that it's a new class. 1655fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Nested templates have a similar problem: 1656fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # template < 1657fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # typename ExportedType, 1658fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # typename TupleType, 1659fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # template <typename, typename> class ImplTemplate> 1660fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 1661fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # To avoid these cases, we ignore classes that are followed by '=' or '>' 1662fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov class_decl_match = Match( 1663fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'\s*(template\s*<[\w\s<>,:]*>\s*)?' 1664fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '(class|struct)\s+([A-Z_]+\s+)*(\w+(?:::\w+)*)' 1665fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '(([^=>]|<[^<>]*>)*)$', line) 1666fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (class_decl_match and 1667fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (not self.stack or self.stack[-1].open_parentheses == 0)): 1668fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.stack.append(_ClassInfo( 1669fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov class_decl_match.group(4), class_decl_match.group(2), 1670fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines, linenum)) 1671fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = class_decl_match.group(5) 1672fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1673fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If we have not yet seen the opening brace for the innermost block, 1674fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # run checks here. 1675fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not self.SeenOpenBrace(): 1676fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.stack[-1].CheckBegin(filename, clean_lines, linenum, error) 1677fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1678fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Update access control if we are inside a class/struct 1679fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if self.stack and isinstance(self.stack[-1], _ClassInfo): 1680fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov access_match = Match(r'\s*(public|private|protected)\s*:', line) 1681fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if access_match: 1682fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.stack[-1].access = access_match.group(1) 1683fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1684fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Consume braces or semicolons from what's left of the line 1685fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov while True: 1686fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Match first brace, semicolon, or closed parenthesis. 1687fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov matched = Match(r'^[^{;)}]*([{;)}])(.*)$', line) 1688fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not matched: 1689fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov break 1690fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1691fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov token = matched.group(1) 1692fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if token == '{': 1693fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If namespace or class hasn't seen a opening brace yet, mark 1694fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # namespace/class head as complete. Push a new block onto the 1695fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # stack otherwise. 1696fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not self.SeenOpenBrace(): 1697fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.stack[-1].seen_open_brace = True 1698fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 1699fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.stack.append(_BlockInfo(True)) 1700fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if _MATCH_ASM.match(line): 1701fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.stack[-1].inline_asm = _BLOCK_ASM 1702fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif token == ';' or token == ')': 1703fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If we haven't seen an opening brace yet, but we already saw 1704fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # a semicolon, this is probably a forward declaration. Pop 1705fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # the stack for these. 1706fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 1707fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Similarly, if we haven't seen an opening brace yet, but we 1708fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # already saw a closing parenthesis, then these are probably 1709fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # function arguments with extra "class" or "struct" keywords. 1710fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Also pop these stack for these. 1711fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not self.SeenOpenBrace(): 1712fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.stack.pop() 1713fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: # token == '}' 1714fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Perform end of block checks and pop the stack. 1715fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if self.stack: 1716fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.stack[-1].CheckEnd(filename, clean_lines, linenum, error) 1717fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov self.stack.pop() 1718fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = matched.group(2) 1719fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1720fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def InnermostClass(self): 1721fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Get class info on the top of the stack. 1722fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1723fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 1724fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov A _ClassInfo object if we are inside a class, or None otherwise. 1725fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1726fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for i in range(len(self.stack), 0, -1): 1727fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov classinfo = self.stack[i - 1] 1728fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if isinstance(classinfo, _ClassInfo): 1729fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return classinfo 1730fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return None 1731fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1732fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov def CheckClassFinished(self, filename, error): 1733fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Checks that all classes have been completely parsed. 1734fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1735fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Call this when all lines in a file have been processed. 1736fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1737fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 1738fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 1739fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1740fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Note: This test can result in false positives if #ifdef constructs 1741fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # get in the way of brace matching. See the testBuildClass test in 1742fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # cpplint_unittest.py for an example of this. 1743fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for obj in self.stack: 1744fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if isinstance(obj, _ClassInfo): 1745fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, obj.starting_linenum, 'build/class', 5, 1746fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Failed to find complete declaration of class %s' % 1747fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov obj.name) 1748fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1749fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1750fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckForNonStandardConstructs(filename, clean_lines, linenum, 1751fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_state, error): 1752fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Logs an error if we see certain non-ANSI constructs ignored by gcc-2. 1753fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1754fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Complain about several constructs which gcc-2 accepts, but which are 1755fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not standard C++. Warning about these in lint is one way to ease the 1756fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov transition to new compilers. 1757fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov - put storage class first (e.g. "static const" instead of "const static"). 1758fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov - "%lld" instead of %qd" in printf-type functions. 1759fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov - "%1$d" is non-standard in printf-type functions. 1760fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov - "\%" is an undefined character escape sequence. 1761fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov - text after #endif is not allowed. 1762fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov - invalid inner-style forward declaration. 1763fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov - >? and <? operators, and their >?= and <?= cousins. 1764fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1765fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Additionally, check for constructor/destructor style violations and reference 1766fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov members, as it is very convenient to do so while checking for 1767fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov gcc-2 compliance. 1768fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1769fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1770fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 1771fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 1772fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 1773fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_state: A _NestingState instance which maintains information about 1774fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov the current stack of nested blocks being parsed. 1775fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: A callable to which errors are reported, which takes 4 arguments: 1776fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename, line number, error level, and message 1777fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1778fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1779fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Remove comments from the line, but leave in strings for now. 1780fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.lines[linenum] 1781fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1782fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'printf\s*\(.*".*%[-+ ]?\d*q', line): 1783fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/printf_format', 3, 1784fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '%q in format strings is deprecated. Use %ll instead.') 1785fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1786fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'printf\s*\(.*".*%\d+\$', line): 1787fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/printf_format', 2, 1788fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '%N$ formats are unconventional. Try rewriting to avoid them.') 1789fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1790fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Remove escaped backslashes before looking for undefined escapes. 1791fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = line.replace('\\\\', '') 1792fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1793fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'("|\').*\\(%|\[|\(|{)', line): 1794fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'build/printf_format', 3, 1795fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '%, [, (, and { are undefined character escapes. Unescape them.') 1796fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1797fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # For the rest, work with both comments and strings removed. 1798fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.elided[linenum] 1799fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1800fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'\b(const|volatile|void|char|short|int|long' 1801fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'|float|double|signed|unsigned' 1802fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'|schar|u?int8|u?int16|u?int32|u?int64)' 1803fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'\s+(register|static|extern|typedef)\b', 1804fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line): 1805fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'build/storage_class', 5, 1806fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Storage class (static, extern, typedef, etc) should be first.') 1807fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1808fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r'\s*#\s*endif\s*[^/\s]+', line): 1809fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'build/endif_comment', 5, 1810fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Uncommented text after #endif is non-standard. Use a comment.') 1811fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1812fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line): 1813fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'build/forward_decl', 5, 1814fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Inner-style forward declarations are invalid. Remove this line.') 1815fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1816fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?', 1817fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line): 1818fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'build/deprecated', 3, 1819fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '>? and <? (max and min) operators are non-standard and deprecated.') 1820fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1821fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'^\s*const\s*string\s*&\s*\w+\s*;', line): 1822fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # TODO(unknown): Could it be expanded safely to arbitrary references, 1823fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # without triggering too many false positives? The first 1824fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # attempt triggered 5 warnings for mostly benign code in the regtest, hence 1825fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # the restriction. 1826fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Here's the original regexp, for the reference: 1827fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # type_name = r'\w+((\s*::\s*\w+)|(\s*<\s*\w+?\s*>))?' 1828fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;' 1829fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/member_string_references', 2, 1830fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'const string& members are dangerous. It is much better to use ' 1831fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'alternatives, such as pointers or simple constants.') 1832fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1833fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Everything else in this function operates on class declarations. 1834fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Return early if the top of the nesting stack is not a class, or if 1835fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # the class head is not completed yet. 1836fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov classinfo = nesting_state.InnermostClass() 1837fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not classinfo or not classinfo.seen_open_brace: 1838fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return 1839fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1840fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # The class may have been declared with namespace or classname qualifiers. 1841fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # The constructor and destructor will not have those qualifiers. 1842fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov base_classname = classinfo.name.split('::')[-1] 1843fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1844fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Look for single-argument constructors that aren't marked explicit. 1845fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Technically a valid construct, but against style. 1846fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov args = Match(r'\s+(?:inline\s+)?%s\s*\(([^,()]+)\)' 1847fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov % re.escape(base_classname), 1848fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line) 1849fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (args and 1850fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov args.group(1) != 'void' and 1851fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not Match(r'(const\s+)?%s\s*(?:<\w+>\s*)?&' % re.escape(base_classname), 1852fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov args.group(1).strip())): 1853fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/explicit', 5, 1854fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Single-argument constructors should be marked explicit.') 1855fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1856fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1857fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckSpacingForFunctionCall(filename, line, linenum, error): 1858fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Checks for the correctness of various spacing around function calls. 1859fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1860fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1861fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 1862fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line: The text of the line to check. 1863fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 1864fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 1865fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1866fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1867fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Since function calls often occur inside if/for/while/switch 1868fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # expressions - which have their own, more liberal conventions - we 1869fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # first see if we should be looking inside such an expression for a 1870fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # function call, to which we can apply more strict standards. 1871fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov fncall = line # if there's no control flow construct, look at whole line 1872fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for pattern in (r'\bif\s*\((.*)\)\s*{', 1873fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'\bfor\s*\((.*)\)\s*{', 1874fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'\bwhile\s*\((.*)\)\s*[{;]', 1875fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'\bswitch\s*\((.*)\)\s*{'): 1876fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Search(pattern, line) 1877fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match: 1878fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov fncall = match.group(1) # look inside the parens for function calls 1879fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov break 1880fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1881fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Except in if/for/while/switch, there should never be space 1882fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # immediately inside parens (eg "f( 3, 4 )"). We make an exception 1883fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # for nested parens ( (a+b) + c ). Likewise, there should never be 1884fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # a space before a ( when it's a function argument. I assume it's a 1885fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # function argument when the char before the whitespace is legal in 1886fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # a function name (alnum + _) and we're not starting a macro. Also ignore 1887fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # pointers and references to arrays and functions coz they're too tricky: 1888fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # we use a very simple way to recognize these: 1889fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # " (something)(maybe-something)" or 1890fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # " (something)(maybe-something," or 1891fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # " (something)[something]" 1892fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Note that we assume the contents of [] to be short enough that 1893fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # they'll never need to wrap. 1894fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if ( # Ignore control structures. 1895fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not Search(r'\b(if|for|while|switch|return|delete)\b', fncall) and 1896fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Ignore pointers/references to functions. 1897fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and 1898fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Ignore pointers/references to arrays. 1899fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not Search(r' \([^)]+\)\[[^\]]+\]', fncall)): 1900fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'\w\s*\(\s(?!\s*\\$)', fncall): # a ( used for a fn call 1901fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/parens', 4, 1902fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Extra space after ( in function call') 1903fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif Search(r'\(\s+(?!(\s*\\)|\()', fncall): 1904fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/parens', 2, 1905fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Extra space after (') 1906fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (Search(r'\w\s+\(', fncall) and 1907fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not Search(r'#\s*define|typedef', fncall) and 1908fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not Search(r'\w\s+\((\w+::)?\*\w+\)\(', fncall)): 1909fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/parens', 4, 1910fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Extra space before ( in function call') 1911fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If the ) is followed only by a newline or a { + newline, assume it's 1912fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # part of a control statement (if/while/etc), and don't complain 1913fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'[^)]\s+\)\s*[^{\s]', fncall): 1914fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If the closing parenthesis is preceded by only whitespaces, 1915fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # try to give a more descriptive error message. 1916fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'^\s+\)', fncall): 1917fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/parens', 2, 1918fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Closing ) should be moved to the previous line') 1919fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 1920fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/parens', 2, 1921fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Extra space before )') 1922fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1923fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1924fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef IsBlankLine(line): 1925fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Returns true if the given line is blank. 1926fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1927fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov We consider a line to be blank if the line is empty or consists of 1928fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov only white spaces. 1929fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1930fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1931fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line: A line of a string. 1932fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1933fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 1934fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov True, if the given line is blank. 1935fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1936fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return not line or line.isspace() 1937fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1938fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1939fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckForFunctionLengths(filename, clean_lines, linenum, 1940fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov function_state, error): 1941fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Reports for long function bodies. 1942fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1943fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov For an overview why this is done, see: 1944fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions 1945fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1946fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Uses a simplistic algorithm assuming other style guidelines 1947fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (especially spacing) are followed. 1948fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Only checks unindented functions, so class members are unchecked. 1949fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Trivial bodies are unchecked, so constructors with huge initializer lists 1950fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov may be missed. 1951fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Blank/comment lines are not counted so as to avoid encouraging the removal 1952fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov of vertical space and comments just to get through a lint check. 1953fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov NOLINT *on the last line of a function* disables this check. 1954fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1955fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 1956fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 1957fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 1958fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 1959fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov function_state: Current function name and lines in body so far. 1960fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 1961fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 1962fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov lines = clean_lines.lines 1963fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = lines[linenum] 1964fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov raw = clean_lines.raw_lines 1965fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov raw_line = raw[linenum] 1966fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov joined_line = '' 1967fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1968fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov starting_func = False 1969fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov regexp = r'(\w(\w|::|\*|\&|\s)*)\(' # decls * & space::name( ... 1970fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match_result = Match(regexp, line) 1971fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match_result: 1972fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If the name is all caps and underscores, figure it's a macro and 1973fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # ignore it, unless it's TEST or TEST_F. 1974fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov function_name = match_result.group(1).split()[-1] 1975fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if function_name == 'TEST' or function_name == 'TEST_F' or ( 1976fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not Match(r'[A-Z_]+$', function_name)): 1977fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov starting_func = True 1978fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 1979fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if starting_func: 1980fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov body_found = False 1981fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for start_linenum in xrange(linenum, clean_lines.NumLines()): 1982fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov start_line = lines[start_linenum] 1983fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov joined_line += ' ' + start_line.lstrip() 1984fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'(;|})', start_line): # Declarations and trivial functions 1985fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov body_found = True 1986fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov break # ... ignore 1987fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif Search(r'{', start_line): 1988fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov body_found = True 1989fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov function = Search(r'((\w|:)*)\(', line).group(1) 1990fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r'TEST', function): # Handle TEST... macros 1991fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov parameter_regexp = Search(r'(\(.*\))', joined_line) 1992fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if parameter_regexp: # Ignore bad syntax 1993fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov function += parameter_regexp.group(1) 1994fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 1995fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov function += '()' 1996fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov function_state.Begin(function) 1997fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov break 1998fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not body_found: 1999fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # No body for the function (or evidence of a non-function) was found. 2000fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/fn_size', 5, 2001fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Lint failed to find start of function body.') 2002fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif Match(r'^\}\s*$', line): # function end 2003fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov function_state.Check(error, filename, linenum) 2004fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov function_state.End() 2005fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif not Match(r'^\s*$', line): 2006fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov function_state.Count() # Count non-blank/non-comment lines. 2007fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2008fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2009fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_TODO = re.compile(r'^//(\s*)TODO(\(.+?\))?:?(\s|$)?') 2010fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2011fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2012fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckComment(comment, filename, linenum, error): 2013fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Checks for common mistakes in TODO comments. 2014fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2015fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 2016fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov comment: The text of the comment from the line in question. 2017fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 2018fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 2019fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 2020fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 2021fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = _RE_PATTERN_TODO.match(comment) 2022fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match: 2023fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # One whitespace is correct; zero whitespace is handled elsewhere. 2024fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov leading_whitespace = match.group(1) 2025fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if len(leading_whitespace) > 1: 2026fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/todo', 2, 2027fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Too many spaces before TODO') 2028fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2029fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov username = match.group(2) 2030fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not username: 2031fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/todo', 2, 2032fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Missing username in TODO; it should look like ' 2033fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '"// TODO(my_username): Stuff."') 2034fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2035fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov middle_whitespace = match.group(3) 2036fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Comparisons made explicit for correctness -- pylint: disable-msg=C6403 2037fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if middle_whitespace != ' ' and middle_whitespace != '': 2038fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/todo', 2, 2039fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'TODO(my_username) should be followed by a space') 2040fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2041fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckAccess(filename, clean_lines, linenum, nesting_state, error): 2042fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Checks for improper use of DISALLOW* macros. 2043fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2044fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 2045fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 2046fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 2047fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 2048fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_state: A _NestingState instance which maintains information about 2049fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov the current stack of nested blocks being parsed. 2050fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 2051fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 2052fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.elided[linenum] # get rid of comments and strings 2053fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2054fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov matched = Match((r'\s*(DISALLOW_COPY_AND_ASSIGN|' 2055fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'DISALLOW_EVIL_CONSTRUCTORS|' 2056fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'DISALLOW_IMPLICIT_CONSTRUCTORS)'), line) 2057fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not matched: 2058fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return 2059fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if nesting_state.stack and isinstance(nesting_state.stack[-1], _ClassInfo): 2060fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if nesting_state.stack[-1].access != 'private': 2061fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/constructors', 3, 2062fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '%s must be in the private: section' % matched.group(1)) 2063fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2064fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 2065fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Found DISALLOW* macro outside a class declaration, or perhaps it 2066fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # was used inside a function when it should have been part of the 2067fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # class declaration. We could issue a warning here, but it 2068fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # probably resulted in a compiler error already. 2069fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov pass 2070fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2071fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2072fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef FindNextMatchingAngleBracket(clean_lines, linenum, init_suffix): 2073fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Find the corresponding > to close a template. 2074fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2075fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 2076fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 2077fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: Current line number. 2078fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov init_suffix: Remainder of the current line after the initial <. 2079fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2080fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 2081fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov True if a matching bracket exists. 2082fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 2083fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = init_suffix 2084fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_stack = ['<'] 2085fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov while True: 2086fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Find the next operator that can tell us whether < is used as an 2087fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # opening bracket or as a less-than operator. We only want to 2088fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # warn on the latter case. 2089fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 2090fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # We could also check all other operators and terminate the search 2091fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # early, e.g. if we got something like this "a<b+c", the "<" is 2092fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # most likely a less-than operator, but then we will get false 2093fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # positives for default arguments (e.g. http://go/prccd) and 2094fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # other template expressions (e.g. http://go/oxcjq). 2095fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Search(r'^[^<>(),;\[\]]*([<>(),;\[\]])(.*)$', line) 2096fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match: 2097fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Found an operator, update nesting stack 2098fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov operator = match.group(1) 2099fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = match.group(2) 2100fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2101fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if nesting_stack[-1] == '<': 2102fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Expecting closing angle bracket 2103fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if operator in ('<', '(', '['): 2104fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_stack.append(operator) 2105fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif operator == '>': 2106fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_stack.pop() 2107fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not nesting_stack: 2108fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Found matching angle bracket 2109fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return True 2110fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif operator == ',': 2111fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Got a comma after a bracket, this is most likely a template 2112fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # argument. We have not seen a closing angle bracket yet, but 2113fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # it's probably a few lines later if we look for it, so just 2114fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # return early here. 2115fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return True 2116fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 2117fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Got some other operator. 2118fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return False 2119fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2120fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 2121fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Expecting closing parenthesis or closing bracket 2122fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if operator in ('<', '(', '['): 2123fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_stack.append(operator) 2124fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif operator in (')', ']'): 2125fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # We don't bother checking for matching () or []. If we got 2126fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # something like (] or [), it would have been a syntax error. 2127fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_stack.pop() 2128fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2129fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 2130fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Scan the next line 2131fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum += 1 2132fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if linenum >= len(clean_lines.elided): 2133fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov break 2134fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.elided[linenum] 2135fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2136fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Exhausted all remaining lines and still no matching angle bracket. 2137fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Most likely the input was incomplete, otherwise we should have 2138fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # seen a semicolon and returned early. 2139fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return True 2140fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2141fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2142fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef FindPreviousMatchingAngleBracket(clean_lines, linenum, init_prefix): 2143fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Find the corresponding < that started a template. 2144fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2145fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 2146fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 2147fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: Current line number. 2148fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov init_prefix: Part of the current line before the initial >. 2149fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2150fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 2151fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov True if a matching bracket exists. 2152fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 2153fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = init_prefix 2154fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_stack = ['>'] 2155fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov while True: 2156fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Find the previous operator 2157fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Search(r'^(.*)([<>(),;\[\]])[^<>(),;\[\]]*$', line) 2158fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match: 2159fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Found an operator, update nesting stack 2160fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov operator = match.group(2) 2161fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = match.group(1) 2162fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2163fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if nesting_stack[-1] == '>': 2164fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Expecting opening angle bracket 2165fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if operator in ('>', ')', ']'): 2166fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_stack.append(operator) 2167fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif operator == '<': 2168fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_stack.pop() 2169fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not nesting_stack: 2170fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Found matching angle bracket 2171fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return True 2172fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif operator == ',': 2173fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Got a comma before a bracket, this is most likely a 2174fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # template argument. The opening angle bracket is probably 2175fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # there if we look for it, so just return early here. 2176fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return True 2177fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 2178fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Got some other operator. 2179fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return False 2180fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2181fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 2182fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Expecting opening parenthesis or opening bracket 2183fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if operator in ('>', ')', ']'): 2184fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_stack.append(operator) 2185fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif operator in ('(', '['): 2186fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_stack.pop() 2187fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2188fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 2189fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Scan the previous line 2190fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum -= 1 2191fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if linenum < 0: 2192fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov break 2193fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.elided[linenum] 2194fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2195fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Exhausted all earlier lines and still no matching angle bracket. 2196fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return False 2197fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2198fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2199fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckSpacing(filename, clean_lines, linenum, nesting_state, error): 2200fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Checks for the correctness of various spacing issues in the code. 2201fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2202fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Things we check for: spaces around operators, spaces after 2203fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if/for/while/switch, no spaces around parens in function calls, two 2204fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov spaces between code and comment, don't start a block with a blank 2205fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line, don't end a function with a blank line, don't add a blank line 2206fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov after public/protected/private, don't have too many blank lines in a row. 2207fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2208fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 2209fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 2210fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 2211fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 2212fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_state: A _NestingState instance which maintains information about 2213fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov the current stack of nested blocks being parsed. 2214fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 2215fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 2216fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2217fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov raw = clean_lines.raw_lines 2218fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = raw[linenum] 2219fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2220fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Before nixing comments, check if the line is blank for no good 2221fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # reason. This includes the first line after a block is opened, and 2222fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # blank lines at the end of a function (ie, right before a line like '}' 2223fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 2224fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Skip all the blank line checks if we are immediately inside a 2225fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # namespace body. In other words, don't issue blank line warnings 2226fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # for this block: 2227fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # namespace { 2228fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 2229fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # } 2230fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 2231fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # A warning about missing end of namespace comments will be issued instead. 2232fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if IsBlankLine(line) and not nesting_state.InNamespaceBody(): 2233fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elided = clean_lines.elided 2234fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov prev_line = elided[linenum - 1] 2235fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov prevbrace = prev_line.rfind('{') 2236fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # TODO(unknown): Don't complain if line before blank line, and line after, 2237fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # both start with alnums and are indented the same amount. 2238fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # This ignores whitespace at the start of a namespace block 2239fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # because those are not usually indented. 2240fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if prevbrace != -1 and prev_line[prevbrace:].find('}') == -1: 2241fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # OK, we have a blank line at the start of a code block. Before we 2242fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # complain, we check if it is an exception to the rule: The previous 2243fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # non-empty line has the parameters of a function header that are indented 2244fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 4 spaces (because they did not fit in a 80 column line when placed on 2245fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # the same line as the function name). We also check for the case where 2246fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # the previous line is indented 6 spaces, which may happen when the 2247fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # initializers of a constructor do not fit into a 80 column line. 2248fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov exception = False 2249fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r' {6}\w', prev_line): # Initializer list? 2250fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # We are looking for the opening column of initializer list, which 2251fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # should be indented 4 spaces to cause 6 space indentation afterwards. 2252fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov search_position = linenum-2 2253fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov while (search_position >= 0 2254fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov and Match(r' {6}\w', elided[search_position])): 2255fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov search_position -= 1 2256fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov exception = (search_position >= 0 2257fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov and elided[search_position][:5] == ' :') 2258fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 2259fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Search for the function arguments or an initializer list. We use a 2260fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # simple heuristic here: If the line is indented 4 spaces; and we have a 2261fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # closing paren, without the opening paren, followed by an opening brace 2262fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # or colon (for initializer lists) we assume that it is the last line of 2263fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # a function header. If we have a colon indented 4 spaces, it is an 2264fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # initializer list. 2265fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)', 2266fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov prev_line) 2267fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov or Match(r' {4}:', prev_line)) 2268fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2269fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not exception: 2270fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/blank_line', 2, 2271fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Blank line at the start of a code block. Is this needed?') 2272fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Ignore blank lines at the end of a block in a long if-else 2273fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # chain, like this: 2274fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # if (condition1) { 2275fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # // Something followed by a blank line 2276fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 2277fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # } else if (condition2) { 2278fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # // Something else 2279fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # } 2280fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if linenum + 1 < clean_lines.NumLines(): 2281fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov next_line = raw[linenum + 1] 2282fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (next_line 2283fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov and Match(r'\s*}', next_line) 2284fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov and next_line.find('} else ') == -1): 2285fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/blank_line', 3, 2286fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Blank line at the end of a code block. Is this needed?') 2287fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2288fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov matched = Match(r'\s*(public|protected|private):', prev_line) 2289fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if matched: 2290fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/blank_line', 3, 2291fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Do not leave a blank line after "%s:"' % matched.group(1)) 2292fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2293fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Next, we complain if there's a comment too near the text 2294fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov commentpos = line.find('//') 2295fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if commentpos != -1: 2296fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Check if the // may be in quotes. If so, ignore it 2297fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Comparisons made explicit for clarity -- pylint: disable-msg=C6403 2298fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (line.count('"', 0, commentpos) - 2299fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line.count('\\"', 0, commentpos)) % 2 == 0: # not in quotes 2300fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Allow one space for new scopes, two spaces otherwise: 2301fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (not Match(r'^\s*{ //', line) and 2302fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ((commentpos >= 1 and 2303fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line[commentpos-1] not in string.whitespace) or 2304fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (commentpos >= 2 and 2305fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line[commentpos-2] not in string.whitespace))): 2306fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/comments', 2, 2307fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'At least two spaces is best between code and comments') 2308fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # There should always be a space between the // and the comment 2309fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov commentend = commentpos + 2 2310fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if commentend < len(line) and not line[commentend] == ' ': 2311fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # but some lines are exceptions -- e.g. if they're big 2312fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # comment delimiters like: 2313fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # //---------------------------------------------------------- 2314fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # or are an empty C++ style Doxygen comment, like: 2315fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # /// 2316fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # or they begin with multiple slashes followed by a space: 2317fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # //////// Header comment 2318fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = (Search(r'[=/-]{4,}\s*$', line[commentend:]) or 2319fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Search(r'^/$', line[commentend:]) or 2320fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Search(r'^/+ ', line[commentend:])) 2321fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not match: 2322fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/comments', 4, 2323fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Should have a space between // and comment') 2324fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckComment(line[commentpos:], filename, linenum, error) 2325fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2326fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.elided[linenum] # get rid of comments and strings 2327fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2328fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Don't try to do spacing checks for operator methods 2329fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = re.sub(r'operator(==|!=|<|<<|<=|>=|>>|>)\(', 'operator\(', line) 2330fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2331fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )". 2332fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Otherwise not. Note we only check for non-spaces on *both* sides; 2333fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # sometimes people put non-spaces on one side when aligning ='s among 2334fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # many lines (not that this is behavior that I approve of...) 2335fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'[\w.]=[\w.]', line) and not Search(r'\b(if|while) ', line): 2336fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/operators', 4, 2337fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Missing spaces around =') 2338fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2339fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # It's ok not to have spaces around binary operators like + - * /, but if 2340fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # there's too little whitespace, we get concerned. It's hard to tell, 2341fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # though, so we punt on this one for now. TODO. 2342fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2343fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # You should always have whitespace around binary operators. 2344fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 2345fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Check <= and >= first to avoid false positives with < and >, then 2346fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # check non-include lines for spacing around < and >. 2347fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Search(r'[^<>=!\s](==|!=|<=|>=)[^<>=!\s]', line) 2348fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match: 2349fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/operators', 3, 2350fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Missing spaces around %s' % match.group(1)) 2351fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # We allow no-spaces around << when used like this: 10<<20, but 2352fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # not otherwise (particularly, not when used as streams) 2353fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Search(r'(\S)(?:L|UL|ULL|l|ul|ull)?<<(\S)', line) 2354fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match and not (match.group(1).isdigit() and match.group(2).isdigit()): 2355fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/operators', 3, 2356fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Missing spaces around <<') 2357fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif not Match(r'#.*include', line): 2358fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Avoid false positives on -> 2359fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov reduced_line = line.replace('->', '') 2360fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2361fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Look for < that is not surrounded by spaces. This is only 2362fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # triggered if both sides are missing spaces, even though 2363fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # technically should should flag if at least one side is missing a 2364fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # space. This is done to avoid some false positives with shifts. 2365fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Search(r'[^\s<]<([^\s=<].*)', reduced_line) 2366fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (match and 2367fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not FindNextMatchingAngleBracket(clean_lines, linenum, match.group(1))): 2368fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/operators', 3, 2369fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Missing spaces around <') 2370fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2371fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Look for > that is not surrounded by spaces. Similar to the 2372fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # above, we only trigger if both sides are missing spaces to avoid 2373fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # false positives with shifts. 2374fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Search(r'^(.*[^\s>])>[^\s=>]', reduced_line) 2375fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (match and 2376fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not FindPreviousMatchingAngleBracket(clean_lines, linenum, 2377fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match.group(1))): 2378fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/operators', 3, 2379fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Missing spaces around >') 2380fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2381fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # We allow no-spaces around >> for almost anything. This is because 2382fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # C++11 allows ">>" to close nested templates, which accounts for 2383fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # most cases when ">>" is not followed by a space. 2384fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 2385fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # We still warn on ">>" followed by alpha character, because that is 2386fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # likely due to ">>" being used for right shifts, e.g.: 2387fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # value >> alpha 2388fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 2389fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # When ">>" is used to close templates, the alphanumeric letter that 2390fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # follows would be part of an identifier, and there should still be 2391fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # a space separating the template type and the identifier. 2392fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # type<type<type>> alpha 2393fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Search(r'>>[a-zA-Z_]', line) 2394fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match: 2395fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/operators', 3, 2396fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Missing spaces around >>') 2397fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2398fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # There shouldn't be space around unary operators 2399fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line) 2400fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match: 2401fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/operators', 4, 2402fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Extra space for operator %s' % match.group(1)) 2403fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2404fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # A pet peeve of mine: no spaces after an if, while, switch, or for 2405fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Search(r' (if\(|for\(|while\(|switch\()', line) 2406fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match: 2407fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/parens', 5, 2408fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Missing space before ( in %s' % match.group(1)) 2409fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2410fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # For if/for/while/switch, the left and right parens should be 2411fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # consistent about how many spaces are inside the parens, and 2412fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # there should either be zero or one spaces inside the parens. 2413fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # We don't want: "if ( foo)" or "if ( foo )". 2414fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed. 2415fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Search(r'\b(if|for|while|switch)\s*' 2416fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$', 2417fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line) 2418fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match: 2419fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if len(match.group(2)) != len(match.group(4)): 2420fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not (match.group(3) == ';' and 2421fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov len(match.group(2)) == 1 + len(match.group(4)) or 2422fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not match.group(2) and Search(r'\bfor\s*\(.*; \)', line)): 2423fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/parens', 5, 2424fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Mismatching spaces inside () in %s' % match.group(1)) 2425fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not len(match.group(2)) in [0, 1]: 2426fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/parens', 5, 2427fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Should have zero or one spaces inside ( and ) in %s' % 2428fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match.group(1)) 2429fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2430fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # You should always have a space after a comma (either as fn arg or operator) 2431fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r',[^\s]', line): 2432fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/comma', 3, 2433fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Missing space after ,') 2434fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2435fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # You should always have a space after a semicolon 2436fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # except for few corner cases 2437fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more 2438fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # space after ; 2439fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r';[^\s};\\)/]', line): 2440fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/semicolon', 3, 2441fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Missing space after ;') 2442fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2443fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Next we will look for issues with function calls. 2444fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckSpacingForFunctionCall(filename, line, linenum, error) 2445fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2446fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Except after an opening paren, or after another opening brace (in case of 2447fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # an initializer list, for instance), you should have spaces before your 2448fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # braces. And since you should never have braces at the beginning of a line, 2449fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # this is an easy test. 2450fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'[^ ({]{', line): 2451fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/braces', 5, 2452fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Missing space before {') 2453fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2454fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Make sure '} else {' has spaces. 2455fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'}else', line): 2456fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/braces', 5, 2457fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Missing space before else') 2458fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2459fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # You shouldn't have spaces before your brackets, except maybe after 2460fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 'delete []' or 'new char * []'. 2461fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'\w\s+\[', line) and not Search(r'delete\s+\[', line): 2462fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/braces', 5, 2463fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Extra space before [') 2464fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2465fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # You shouldn't have a space before a semicolon at the end of the line. 2466fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # There's a special case for "for" since the style guide allows space before 2467fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # the semicolon there. 2468fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r':\s*;\s*$', line): 2469fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/semicolon', 5, 2470fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Semicolon defining empty statement. Use {} instead.') 2471fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif Search(r'^\s*;\s*$', line): 2472fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/semicolon', 5, 2473fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Line contains only semicolon. If this should be an empty statement, ' 2474fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'use {} instead.') 2475fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif (Search(r'\s+;\s*$', line) and 2476fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not Search(r'\bfor\b', line)): 2477fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/semicolon', 5, 2478fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Extra space before last semicolon. If this should be an empty ' 2479fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'statement, use {} instead.') 2480fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2481fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # In range-based for, we wanted spaces before and after the colon, but 2482fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # not around "::" tokens that might appear. 2483fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (Search('for *\(.*[^:]:[^: ]', line) or 2484fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Search('for *\(.*[^: ]:[^:]', line)): 2485fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/forcolon', 2, 2486fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Missing space around colon in range-based for loop') 2487fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2488fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2489fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckSectionSpacing(filename, clean_lines, class_info, linenum, error): 2490fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Checks for additional blank line issues related to sections. 2491fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2492fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Currently the only thing checked here is blank line before protected/private. 2493fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2494fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 2495fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 2496fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 2497fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov class_info: A _ClassInfo objects. 2498fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 2499fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 2500fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 2501fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Skip checks if the class is small, where small means 25 lines or less. 2502fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 25 lines seems like a good cutoff since that's the usual height of 2503fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # terminals, and any class that can't fit in one screen can't really 2504fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # be considered "small". 2505fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 2506fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Also skip checks if we are on the first line. This accounts for 2507fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # classes that look like 2508fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # class Foo { public: ... }; 2509fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 2510fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If we didn't find the end of the class, last_line would be zero, 2511fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # and the check will be skipped by the first condition. 2512fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (class_info.last_line - class_info.starting_linenum <= 24 or 2513fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum <= class_info.starting_linenum): 2514fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return 2515fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2516fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov matched = Match(r'\s*(public|protected|private):', clean_lines.lines[linenum]) 2517fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if matched: 2518fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Issue warning if the line before public/protected/private was 2519fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # not a blank line, but don't do this if the previous line contains 2520fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # "class" or "struct". This can happen two ways: 2521fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # - We are at the beginning of the class. 2522fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # - We are forward-declaring an inner class that is semantically 2523fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # private, but needed to be public for implementation reasons. 2524fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Also ignores cases where the previous line ends with a backslash as can be 2525fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # common when defining classes in C macros. 2526fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov prev_line = clean_lines.lines[linenum - 1] 2527fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (not IsBlankLine(prev_line) and 2528fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not Search(r'\b(class|struct)\b', prev_line) and 2529fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not Search(r'\\$', prev_line)): 2530fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Try a bit harder to find the beginning of the class. This is to 2531fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # account for multi-line base-specifier lists, e.g.: 2532fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # class Derived 2533fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # : public Base { 2534fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov end_class_head = class_info.starting_linenum 2535fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for i in range(class_info.starting_linenum, linenum): 2536fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'\{\s*$', clean_lines.lines[i]): 2537fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov end_class_head = i 2538fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov break 2539fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if end_class_head < linenum - 1: 2540fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/blank_line', 3, 2541fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '"%s:" should be preceded by a blank line' % matched.group(1)) 2542fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2543fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2544fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef GetPreviousNonBlankLine(clean_lines, linenum): 2545fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Return the most recent non-blank line and its line number. 2546fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2547fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 2548fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file contents. 2549fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 2550fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2551fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 2552fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov A tuple with two elements. The first element is the contents of the last 2553fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov non-blank line before the current line, or the empty string if this is the 2554fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov first non-blank line. The second is the line number of that line, or -1 2555fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if this is the first non-blank line. 2556fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 2557fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2558fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov prevlinenum = linenum - 1 2559fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov while prevlinenum >= 0: 2560fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov prevline = clean_lines.elided[prevlinenum] 2561fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not IsBlankLine(prevline): # if not a blank line... 2562fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return (prevline, prevlinenum) 2563fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov prevlinenum -= 1 2564fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return ('', -1) 2565fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2566fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2567fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckBraces(filename, clean_lines, linenum, error): 2568fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Looks for misplaced braces (e.g. at the end of line). 2569fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2570fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 2571fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 2572fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 2573fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 2574fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 2575fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 2576fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2577fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.elided[linenum] # get rid of comments and strings 2578fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2579fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r'\s*{\s*$', line): 2580fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # We allow an open brace to start a line in the case where someone 2581fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # is using braces in a block to explicitly create a new scope, 2582fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # which is commonly used to control the lifetime of 2583fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # stack-allocated variables. We don't detect this perfectly: we 2584fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # just don't complain if the last non-whitespace character on the 2585fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # previous non-blank line is ';', ':', '{', or '}', or if the previous 2586fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # line starts a preprocessor block. 2587fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] 2588fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (not Search(r'[;:}{]\s*$', prevline) and 2589fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not Match(r'\s*#', prevline)): 2590fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/braces', 4, 2591fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '{ should almost always be at the end of the previous line') 2592fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2593fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # An else clause should be on the same line as the preceding closing brace. 2594fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r'\s*else\s*', line): 2595fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] 2596fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r'\s*}\s*$', prevline): 2597fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/newline', 4, 2598fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'An else should appear on the same line as the preceding }') 2599fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2600fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If braces come on one side of an else, they should be on both. 2601fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # However, we have to worry about "else if" that spans multiple lines! 2602fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line): 2603fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'}\s*else if([^{]*)$', line): # could be multi-line if 2604fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # find the ( after the if 2605fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov pos = line.find('else if') 2606fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov pos = line.find('(', pos) 2607fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if pos > 0: 2608fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos) 2609fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if endline[endpos:].find('{') == -1: # must be brace after if 2610fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/braces', 5, 2611fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'If an else has a brace on one side, it should have it on both') 2612fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: # common case: else not followed by a multi-line if 2613fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/braces', 5, 2614fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'If an else has a brace on one side, it should have it on both') 2615fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2616fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Likewise, an else should never have the else clause on the same line 2617fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line): 2618fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/newline', 4, 2619fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Else clause should never be on same line as else (use 2 lines)') 2620fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2621fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # In the same way, a do/while should never be on one line 2622fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r'\s*do [^\s{]', line): 2623fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/newline', 4, 2624fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'do/while clauses should not be on a single line') 2625fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2626fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Braces shouldn't be followed by a ; unless they're defining a struct 2627fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # or initializing an array. 2628fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # We can't tell in general, but we can for some common cases. 2629fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov prevlinenum = linenum 2630fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov while True: 2631fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (prevline, prevlinenum) = GetPreviousNonBlankLine(clean_lines, prevlinenum) 2632fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r'\s+{.*}\s*;', line) and not prevline.count(';'): 2633fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = prevline + line 2634fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 2635fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov break 2636fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (Search(r'{.*}\s*;', line) and 2637fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line.count('{') == line.count('}') and 2638fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not Search(r'struct|class|enum|\s*=\s*{', line)): 2639fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/braces', 4, 2640fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov "You don't need a ; after a }") 2641fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2642fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2643fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckEmptyLoopBody(filename, clean_lines, linenum, error): 2644fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Loop for empty loop body with only a single semicolon. 2645fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2646fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 2647fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 2648fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 2649fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 2650fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 2651fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 2652fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2653fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Search for loop keywords at the beginning of the line. Because only 2654fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # whitespaces are allowed before the keywords, this will also ignore most 2655fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # do-while-loops, since those lines should start with closing brace. 2656fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.elided[linenum] 2657fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r'\s*(for|while)\s*\(', line): 2658fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Find the end of the conditional expression 2659fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (end_line, end_linenum, end_pos) = CloseExpression( 2660fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines, linenum, line.find('(')) 2661fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2662fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Output warning if what follows the condition expression is a semicolon. 2663fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # No warning for all other cases, including whitespace or newline, since we 2664fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # have a separate check for semicolons preceded by whitespace. 2665fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if end_pos >= 0 and Match(r';', end_line[end_pos:]): 2666fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, end_linenum, 'whitespace/empty_loop_body', 5, 2667fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Empty loop bodies should use {} or continue') 2668fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2669fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2670fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef ReplaceableCheck(operator, macro, line): 2671fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Determine whether a basic CHECK can be replaced with a more specific one. 2672fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2673fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov For example suggest using CHECK_EQ instead of CHECK(a == b) and 2674fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov similarly for CHECK_GE, CHECK_GT, CHECK_LE, CHECK_LT, CHECK_NE. 2675fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2676fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 2677fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov operator: The C++ operator used in the CHECK. 2678fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov macro: The CHECK or EXPECT macro being called. 2679fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line: The current source line. 2680fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2681fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 2682fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov True if the CHECK can be replaced with a more specific one. 2683fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 2684fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2685fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # This matches decimal and hex integers, strings, and chars (in that order). 2686fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match_constant = r'([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')' 2687fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2688fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Expression to match two sides of the operator with something that 2689fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # looks like a literal, since CHECK(x == iterator) won't compile. 2690fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # This means we can't catch all the cases where a more specific 2691fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # CHECK is possible, but it's less annoying than dealing with 2692fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # extraneous warnings. 2693fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match_this = (r'\s*' + macro + r'\((\s*' + 2694fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match_constant + r'\s*' + operator + r'[^<>].*|' 2695fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'.*[^<>]' + operator + r'\s*' + match_constant + 2696fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'\s*\))') 2697fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2698fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Don't complain about CHECK(x == NULL) or similar because 2699fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # CHECK_EQ(x, NULL) won't compile (requires a cast). 2700fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Also, don't complain about more complex boolean expressions 2701fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # involving && or || such as CHECK(a == b || c == d). 2702fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return Match(match_this, line) and not Search(r'NULL|&&|\|\|', line) 2703fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2704fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2705fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckCheck(filename, clean_lines, linenum, error): 2706fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Checks the use of CHECK and EXPECT macros. 2707fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2708fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 2709fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 2710fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 2711fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 2712fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 2713fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 2714fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2715fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Decide the set of replacement macros that should be suggested 2716fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov raw_lines = clean_lines.raw_lines 2717fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov current_macro = '' 2718fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for macro in _CHECK_MACROS: 2719fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if raw_lines[linenum].find(macro) >= 0: 2720fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov current_macro = macro 2721fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov break 2722fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not current_macro: 2723fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Don't waste time here if line doesn't contain 'CHECK' or 'EXPECT' 2724fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return 2725fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2726fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.elided[linenum] # get rid of comments and strings 2727fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2728fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Encourage replacing plain CHECKs with CHECK_EQ/CHECK_NE/etc. 2729fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for operator in ['==', '!=', '>=', '>', '<=', '<']: 2730fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if ReplaceableCheck(operator, current_macro, line): 2731fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/check', 2, 2732fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Consider using %s instead of %s(a %s b)' % ( 2733fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _CHECK_REPLACEMENT[current_macro][operator], 2734fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov current_macro, operator)) 2735fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov break 2736fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2737fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2738fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckAltTokens(filename, clean_lines, linenum, error): 2739fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Check alternative keywords being used in boolean expressions. 2740fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2741fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 2742fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 2743fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 2744fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 2745fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 2746fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 2747fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.elided[linenum] 2748fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2749fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Avoid preprocessor lines 2750fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r'^\s*#', line): 2751fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return 2752fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2753fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Last ditch effort to avoid multi-line comments. This will not help 2754fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # if the comment started before the current line or ended after the 2755fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # current line, but it catches most of the false positives. At least, 2756fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # it provides a way to workaround this warning for people who use 2757fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # multi-line comments in preprocessor macros. 2758fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 2759fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # TODO(unknown): remove this once cpplint has better support for 2760fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # multi-line comments. 2761fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if line.find('/*') >= 0 or line.find('*/') >= 0: 2762fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return 2763fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2764fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for match in _ALT_TOKEN_REPLACEMENT_PATTERN.finditer(line): 2765fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/alt_tokens', 2, 2766fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Use operator %s instead of %s' % ( 2767fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1))) 2768fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2769fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2770fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef GetLineWidth(line): 2771fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Determines the width of the line in column positions. 2772fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2773fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 2774fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line: A string, which may be a Unicode string. 2775fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2776fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 2777fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov The width of the line in column positions, accounting for Unicode 2778fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov combining characters and wide characters. 2779fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 2780fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if isinstance(line, unicode): 2781fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov width = 0 2782fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for uc in unicodedata.normalize('NFC', line): 2783fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if unicodedata.east_asian_width(uc) in ('W', 'F'): 2784fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov width += 2 2785fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif not unicodedata.combining(uc): 2786fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov width += 1 2787fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return width 2788fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 2789fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return len(line) 2790fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2791fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2792fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state, 2793fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error): 2794fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Checks rules from the 'C++ style rules' section of cppguide.html. 2795fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2796fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Most of these rules are hard to test (naming, comment style), but we 2797fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov do what we can. In particular we check for 2-space indents, line lengths, 2798fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov tab usage, spaces inside code, etc. 2799fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2800fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 2801fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 2802fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 2803fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 2804fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov file_extension: The extension (without the dot) of the filename. 2805fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_state: A _NestingState instance which maintains information about 2806fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov the current stack of nested blocks being parsed. 2807fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 2808fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 2809fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2810fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov raw_lines = clean_lines.raw_lines 2811fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = raw_lines[linenum] 2812fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2813fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if line.find('\t') != -1: 2814fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/tab', 1, 2815fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Tab found; better to use spaces') 2816fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2817fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # One or three blank spaces at the beginning of the line is weird; it's 2818fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # hard to reconcile that with 2-space indents. 2819fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # NOTE: here are the conditions rob pike used for his tests. Mine aren't 2820fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # as sophisticated, but it may be worth becoming so: RLENGTH==initial_spaces 2821fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # if(RLENGTH > 20) complain = 0; 2822fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # if(match($0, " +(error|private|public|protected):")) complain = 0; 2823fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # if(match(prev, "&& *$")) complain = 0; 2824fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # if(match(prev, "\\|\\| *$")) complain = 0; 2825fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # if(match(prev, "[\",=><] *$")) complain = 0; 2826fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # if(match($0, " <<")) complain = 0; 2827fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # if(match(prev, " +for \\(")) complain = 0; 2828fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # if(prevodd && match(prevprev, " +for \\(")) complain = 0; 2829fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov initial_spaces = 0 2830fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov cleansed_line = clean_lines.elided[linenum] 2831fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov while initial_spaces < len(line) and line[initial_spaces] == ' ': 2832fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov initial_spaces += 1 2833fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if line and line[-1].isspace(): 2834fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/end_of_line', 4, 2835fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Line ends in whitespace. Consider deleting these extra spaces.') 2836fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # There are certain situations we allow one space, notably for labels 2837fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif ((initial_spaces == 1 or initial_spaces == 3) and 2838fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not Match(r'\s*\w+\s*:\s*$', cleansed_line)): 2839fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/indent', 3, 2840fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Weird number of spaces at line-start. ' 2841fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Are you using a 2-space indent?') 2842fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Labels should always be indented at least one space. 2843fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif not initial_spaces and line[:2] != '//' and Search(r'[^:]:\s*$', 2844fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line): 2845fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/labels', 4, 2846fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Labels should always be indented at least one space. ' 2847fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'If this is a member-initializer list in a constructor or ' 2848fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'the base class list in a class definition, the colon should ' 2849fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'be on the following line.') 2850fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2851fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2852fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Check if the line is a header guard. 2853fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov is_header_guard = False 2854fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if file_extension == 'h': 2855fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov cppvar = GetHeaderGuardCPPVariable(filename) 2856fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (line.startswith('#ifndef %s' % cppvar) or 2857fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line.startswith('#define %s' % cppvar) or 2858fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line.startswith('#endif // %s' % cppvar)): 2859fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov is_header_guard = True 2860fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # #include lines and header guards can be long, since there's no clean way to 2861fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # split them. 2862fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 2863fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # URLs can be long too. It's possible to split these, but it makes them 2864fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # harder to cut&paste. 2865fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 2866fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # The "$Id:...$" comment may also get very long without it being the 2867fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # developers fault. 2868fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (not line.startswith('#include') and not is_header_guard and 2869fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not Match(r'^\s*//.*http(s?)://\S*$', line) and 2870fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not Match(r'^// \$Id:.*#[0-9]+ \$$', line)): 2871fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line_width = GetLineWidth(line) 2872fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if line_width > 100: 2873fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/line_length', 4, 2874fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Lines should very rarely be longer than 100 characters') 2875fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif line_width > 80: 2876fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/line_length', 2, 2877fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Lines should be <= 80 characters long') 2878fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2879fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (cleansed_line.count(';') > 1 and 2880fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # for loops are allowed two ;'s (and may run over two lines). 2881fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov cleansed_line.find('for') == -1 and 2882fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1 or 2883fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1) and 2884fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # It's ok to have many commands in a switch case that fits in 1 line 2885fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not ((cleansed_line.find('case ') != -1 or 2886fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov cleansed_line.find('default:') != -1) and 2887fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov cleansed_line.find('break;') != -1)): 2888fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'whitespace/newline', 0, 2889fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'More than one command on the same line') 2890fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2891fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Some more style checks 2892fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckBraces(filename, clean_lines, linenum, error) 2893fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckEmptyLoopBody(filename, clean_lines, linenum, error) 2894fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckAccess(filename, clean_lines, linenum, nesting_state, error) 2895fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckSpacing(filename, clean_lines, linenum, nesting_state, error) 2896fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckCheck(filename, clean_lines, linenum, error) 2897fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckAltTokens(filename, clean_lines, linenum, error) 2898fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov classinfo = nesting_state.InnermostClass() 2899fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if classinfo: 2900fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckSectionSpacing(filename, clean_lines, classinfo, linenum, error) 2901fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2902fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2903fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_INCLUDE_NEW_STYLE = re.compile(r'#include +"[^/]+\.h"') 2904fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$') 2905fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# Matches the first component of a filename delimited by -s and _s. That is: 2906fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo' 2907fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo' 2908fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo' 2909fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov# _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo' 2910fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+') 2911fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2912fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2913fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _DropCommonSuffixes(filename): 2914fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Drops common suffixes like _test.cc or -inl.h from filename. 2915fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2916fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov For example: 2917fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov >>> _DropCommonSuffixes('foo/foo-inl.h') 2918fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'foo/foo' 2919fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov >>> _DropCommonSuffixes('foo/bar/foo.cc') 2920fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'foo/bar/foo' 2921fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov >>> _DropCommonSuffixes('foo/foo_internal.h') 2922fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'foo/foo' 2923fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov >>> _DropCommonSuffixes('foo/foo_unusualinternal.h') 2924fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'foo/foo_unusualinternal' 2925fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2926fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 2927fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The input filename. 2928fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2929fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 2930fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov The filename with the common suffix removed. 2931fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 2932fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for suffix in ('test.cc', 'regtest.cc', 'unittest.cc', 2933fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'inl.h', 'impl.h', 'internal.h'): 2934fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (filename.endswith(suffix) and len(filename) > len(suffix) and 2935fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename[-len(suffix) - 1] in ('-', '_')): 2936fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return filename[:-len(suffix) - 1] 2937fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return os.path.splitext(filename)[0] 2938fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2939fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2940fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _IsTestFilename(filename): 2941fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Determines if the given filename has a suffix that identifies it as a test. 2942fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2943fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 2944fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The input filename. 2945fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2946fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 2947fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov True if 'filename' looks like a test, False otherwise. 2948fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 2949fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (filename.endswith('_test.cc') or 2950fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename.endswith('_unittest.cc') or 2951fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename.endswith('_regtest.cc')): 2952fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return True 2953fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 2954fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return False 2955fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2956fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2957fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _ClassifyInclude(fileinfo, include, is_system): 2958fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Figures out what kind of header 'include' is. 2959fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2960fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 2961fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov fileinfo: The current file cpplint is running over. A FileInfo instance. 2962fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include: The path to a #included file. 2963fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov is_system: True if the #include used <> rather than "". 2964fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2965fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 2966fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov One of the _XXX_HEADER constants. 2967fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2968fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov For example: 2969fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'stdio.h', True) 2970fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _C_SYS_HEADER 2971fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'string', True) 2972fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _CPP_SYS_HEADER 2973fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', False) 2974fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _LIKELY_MY_HEADER 2975fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov >>> _ClassifyInclude(FileInfo('foo/foo_unknown_extension.cc'), 2976fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ... 'bar/foo_other_ext.h', False) 2977fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _POSSIBLE_MY_HEADER 2978fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/bar.h', False) 2979fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _OTHER_HEADER 2980fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 2981fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # This is a list of all standard c++ header files, except 2982fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # those already checked for above. 2983fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov is_stl_h = include in _STL_HEADERS 2984fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov is_cpp_h = is_stl_h or include in _CPP_HEADERS 2985fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2986fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if is_system: 2987fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if is_cpp_h: 2988fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return _CPP_SYS_HEADER 2989fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 2990fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return _C_SYS_HEADER 2991fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 2992fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If the target file and the include we're checking share a 2993fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # basename when we drop common extensions, and the include 2994fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # lives in . , then it's likely to be owned by the target file. 2995fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov target_dir, target_base = ( 2996fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov os.path.split(_DropCommonSuffixes(fileinfo.RepositoryName()))) 2997fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include_dir, include_base = os.path.split(_DropCommonSuffixes(include)) 2998fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if target_base == include_base and ( 2999fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include_dir == target_dir or 3000fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include_dir == os.path.normpath(target_dir + '/../public')): 3001fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return _LIKELY_MY_HEADER 3002fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3003fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If the target and include share some initial basename 3004fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # component, it's possible the target is implementing the 3005fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # include, so it's allowed to be first, but we'll never 3006fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # complain if it's not there. 3007fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov target_first_component = _RE_FIRST_COMPONENT.match(target_base) 3008fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include_first_component = _RE_FIRST_COMPONENT.match(include_base) 3009fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (target_first_component and include_first_component and 3010fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov target_first_component.group(0) == 3011fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include_first_component.group(0)): 3012fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return _POSSIBLE_MY_HEADER 3013fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3014fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return _OTHER_HEADER 3015fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3016fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3017fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3018fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckIncludeLine(filename, clean_lines, linenum, include_state, error): 3019fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Check rules that are applicable to #include lines. 3020fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3021fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Strings on #include lines are NOT removed from elided line, to make 3022fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov certain tasks easier. However, to prevent false positives, checks 3023fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov applicable to #include lines in CheckLanguage must be put here. 3024fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3025fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 3026fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 3027fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 3028fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 3029fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include_state: An _IncludeState instance in which the headers are inserted. 3030fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 3031fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 3032fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov fileinfo = FileInfo(filename) 3033fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3034fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.lines[linenum] 3035fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3036fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # "include" should use the new style "foo/bar.h" instead of just "bar.h" 3037fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if _RE_PATTERN_INCLUDE_NEW_STYLE.search(line): 3038fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'build/include', 4, 3039fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Include the directory when naming .h files') 3040fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3041fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # we shouldn't include a file more than once. actually, there are a 3042fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # handful of instances where doing so is okay, but in general it's 3043fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # not. 3044fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = _RE_PATTERN_INCLUDE.search(line) 3045fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match: 3046fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include = match.group(2) 3047fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov is_system = (match.group(1) == '<') 3048fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if include in include_state: 3049fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'build/include', 4, 3050fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '"%s" already included at %s:%s' % 3051fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (include, filename, include_state[include])) 3052fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 3053fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include_state[include] = linenum 3054fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3055fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # We want to ensure that headers appear in the right order: 3056fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 1) for foo.cc, foo.h (preferred location) 3057fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 2) c system files 3058fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 3) cpp system files 3059fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 4) for foo.cc, foo.h (deprecated location) 3060fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 5) other google headers 3061fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 3062fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # We classify each include statement as one of those 5 types 3063fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # using a number of techniques. The include_state object keeps 3064fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # track of the highest type seen, and complains if we see a 3065fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # lower type after that. 3066fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error_message = include_state.CheckNextIncludeOrder( 3067fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _ClassifyInclude(fileinfo, include, is_system)) 3068fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if error_message: 3069fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'build/include_order', 4, 3070fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '%s. Should be: %s.h, c system, c++ system, other.' % 3071fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (error_message, fileinfo.BaseName())) 3072fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not include_state.IsInAlphabeticalOrder(include): 3073fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'build/include_alpha', 4, 3074fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Include "%s" not in alphabetical order' % include) 3075fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3076fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Look for any of the stream classes that are part of standard C++. 3077fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = _RE_PATTERN_INCLUDE.match(line) 3078fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match: 3079fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include = match.group(2) 3080fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r'(f|ind|io|i|o|parse|pf|stdio|str|)?stream$', include): 3081fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Many unit tests use cout, so we exempt them. 3082fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not _IsTestFilename(filename): 3083fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/streams', 3, 3084fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Streams are highly discouraged.') 3085fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3086fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3087fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef _GetTextInside(text, start_pattern): 3088fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Retrieves all the text between matching open and close parentheses. 3089fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3090fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Given a string of lines and a regular expression string, retrieve all the text 3091fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov following the expression and between opening punctuation symbols like 3092fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (, [, or {, and the matching close-punctuation symbol. This properly nested 3093fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov occurrences of the punctuations, so for the text like 3094fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov printf(a(), b(c())); 3095fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'. 3096fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov start_pattern must match string having an open punctuation symbol at the end. 3097fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3098fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 3099fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov text: The lines to extract text. Its comments and strings must be elided. 3100fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov It can be single line and can span multiple lines. 3101fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov start_pattern: The regexp string indicating where to start extracting 3102fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov the text. 3103fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 3104fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov The extracted text. 3105fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov None if either the opening string or ending punctuation could not be found. 3106fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 3107fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # TODO(sugawarayu): Audit cpplint.py to see what places could be profitably 3108fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # rewritten to use _GetTextInside (and use inferior regexp matching today). 3109fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3110fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Give opening punctuations to get the matching close-punctuations. 3111fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov matching_punctuation = {'(': ')', '{': '}', '[': ']'} 3112fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov closing_punctuation = set(matching_punctuation.itervalues()) 3113fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3114fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Find the position to start extracting text. 3115fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = re.search(start_pattern, text, re.M) 3116fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not match: # start_pattern not found in text. 3117fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return None 3118fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov start_position = match.end(0) 3119fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3120fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov assert start_position > 0, ( 3121fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'start_pattern must ends with an opening punctuation.') 3122fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov assert text[start_position - 1] in matching_punctuation, ( 3123fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'start_pattern must ends with an opening punctuation.') 3124fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Stack of closing punctuations we expect to have in text after position. 3125fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov punctuation_stack = [matching_punctuation[text[start_position - 1]]] 3126fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov position = start_position 3127fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov while punctuation_stack and position < len(text): 3128fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if text[position] == punctuation_stack[-1]: 3129fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov punctuation_stack.pop() 3130fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif text[position] in closing_punctuation: 3131fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # A closing punctuation without matching opening punctuations. 3132fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return None 3133fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif text[position] in matching_punctuation: 3134fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov punctuation_stack.append(matching_punctuation[text[position]]) 3135fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov position += 1 3136fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if punctuation_stack: 3137fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Opening punctuations left without matching close-punctuations. 3138fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return None 3139fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # punctuations match. 3140fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return text[start_position:position - 1] 3141fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3142fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3143fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckLanguage(filename, clean_lines, linenum, file_extension, include_state, 3144fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error): 3145fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Checks rules from the 'C++ language rules' section of cppguide.html. 3146fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3147fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Some of these rules are hard to test (function overloading, using 3148fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov uint32 inappropriately), but we do the best we can. 3149fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3150fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 3151fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 3152fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 3153fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 3154fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov file_extension: The extension (without the dot) of the filename. 3155fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include_state: An _IncludeState instance in which the headers are inserted. 3156fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 3157fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 3158fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If the line is empty or consists of entirely a comment, no need to 3159fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # check it. 3160fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.elided[linenum] 3161fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not line: 3162fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return 3163fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3164fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = _RE_PATTERN_INCLUDE.search(line) 3165fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match: 3166fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckIncludeLine(filename, clean_lines, linenum, include_state, error) 3167fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return 3168fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3169fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Create an extended_line, which is the concatenation of the current and 3170fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # next lines, for more effective checking of code that may span more than one 3171fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # line. 3172fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if linenum + 1 < clean_lines.NumLines(): 3173fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov extended_line = line + clean_lines.elided[linenum + 1] 3174fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 3175fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov extended_line = line 3176fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3177fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Make Windows paths like Unix. 3178fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov fullname = os.path.abspath(filename).replace('\\', '/') 3179fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3180fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # TODO(unknown): figure out if they're using default arguments in fn proto. 3181fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3182fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Check for non-const references in functions. This is tricky because & 3183fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # is also used to take the address of something. We allow <> for templates, 3184fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # (ignoring whatever is between the braces) and : for classes. 3185fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # These are complicated re's. They try to capture the following: 3186fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # paren (for fn-prototype start), typename, &, varname. For the const 3187fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # version, we're willing for const to be before typename or after 3188fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Don't check the implementation on same line. 3189fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov fnline = line.split('{', 1)[0] 3190fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (len(re.findall(r'\([^()]*\b(?:[\w:]|<[^()]*>)+(\s?&|&\s?)\w+', fnline)) > 3191fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov len(re.findall(r'\([^()]*\bconst\s+(?:typename\s+)?(?:struct\s+)?' 3192fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'(?:[\w:]|<[^()]*>)+(\s?&|&\s?)\w+', fnline)) + 3193fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov len(re.findall(r'\([^()]*\b(?:[\w:]|<[^()]*>)+\s+const(\s?&|&\s?)[\w]+', 3194fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov fnline))): 3195fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3196fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # We allow non-const references in a few standard places, like functions 3197fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # called "swap()" or iostream operators like "<<" or ">>". We also filter 3198fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # out for loops, which lint otherwise mistakenly thinks are functions. 3199fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not Search( 3200fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'(for|swap|Swap|operator[<>][<>])\s*\(\s*' 3201fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'(?:(?:typename\s*)?[\w:]|<.*>)+\s*&', 3202fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov fnline): 3203fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/references', 2, 3204fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Is this a non-const reference? ' 3205fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'If so, make const or use a pointer.') 3206fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3207fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Check to see if they're using an conversion function cast. 3208fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # I just try to capture the most common basic types, though there are more. 3209fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Parameterless conversion functions, such as bool(), are allowed as they are 3210fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # probably a member operator declaration or default constructor. 3211fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Search( 3212fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'(\bnew\s+)?\b' # Grab 'new' operator, if it's there 3213fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'(int|float|double|bool|char|int32|uint32|int64|uint64)\([^)]', line) 3214fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match: 3215fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # gMock methods are defined using some variant of MOCK_METHODx(name, type) 3216fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # where type may be float(), int(string), etc. Without context they are 3217fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # virtually indistinguishable from int(x) casts. Likewise, gMock's 3218fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # MockCallback takes a template parameter of the form return_type(arg_type), 3219fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # which looks much like the cast we're trying to detect. 3220fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (match.group(1) is None and # If new operator, then this isn't a cast 3221fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) or 3222fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Match(r'^\s*MockCallback<.*>', line))): 3223fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Try a bit harder to catch gmock lines: the only place where 3224fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # something looks like an old-style cast is where we declare the 3225fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # return type of the mocked method, and the only time when we 3226fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # are missing context is if MOCK_METHOD was split across 3227fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # multiple lines (for example http://go/hrfhr ), so we only need 3228fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # to check the previous line for MOCK_METHOD. 3229fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (linenum == 0 or 3230fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov not Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(\S+,\s*$', 3231fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines.elided[linenum - 1])): 3232fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/casting', 4, 3233fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Using deprecated casting style. ' 3234fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Use static_cast<%s>(...) instead' % 3235fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match.group(2)) 3236fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3237fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum], 3238fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'static_cast', 3239fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'\((int|float|double|bool|char|u?int(16|32|64))\)', error) 3240fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3241fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # This doesn't catch all cases. Consider (const char * const)"hello". 3242fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 3243fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # (char *) "foo" should always be a const_cast (reinterpret_cast won't 3244fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # compile). 3245fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum], 3246fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'const_cast', r'\((char\s?\*+\s?)\)\s*"', error): 3247fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov pass 3248fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 3249fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Check pointer casts for other than string constants 3250fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckCStyleCast(filename, linenum, line, clean_lines.raw_lines[linenum], 3251fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'reinterpret_cast', r'\((\w+\s?\*+\s?)\)', error) 3252fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3253fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # In addition, we look for people taking the address of a cast. This 3254fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # is dangerous -- casts can assign to temporaries, so the pointer doesn't 3255fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # point where you think. 3256fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search( 3257fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'(&\([^)]+\)[\w(])|(&(static|dynamic|reinterpret)_cast\b)', line): 3258fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/casting', 4, 3259fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('Are you taking an address of a cast? ' 3260fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'This is dangerous: could be a temp var. ' 3261fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Take the address before doing the cast, rather than after')) 3262fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3263fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Check for people declaring static/global STL strings at the top level. 3264fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # This is dangerous because the C++ language does not guarantee that 3265fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # globals with constructors are initialized before the first access. 3266fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Match( 3267fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'((?:|static +)(?:|const +))string +([a-zA-Z0-9_:]+)\b(.*)', 3268fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line) 3269fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Make sure it's not a function. 3270fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Function template specialization looks like: "string foo<Type>(...". 3271fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Class template definitions look like: "string Foo<Type>::Method(...". 3272fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match and not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)?\s*\(([^"]|$)', 3273fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match.group(3)): 3274fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/string', 4, 3275fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'For a static/global string constant, use a C style string instead: ' 3276fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '"%schar %s[]".' % 3277fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (match.group(1), match.group(2))) 3278fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3279fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Check that we're not using RTTI outside of testing code. 3280fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'\bdynamic_cast<', line) and not _IsTestFilename(filename): 3281fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/rtti', 5, 3282fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Do not use dynamic_cast<>. If you need to cast within a class ' 3283fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov "hierarchy, use static_cast<> to upcast. Google doesn't support " 3284fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'RTTI.') 3285fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3286fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line): 3287fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/init', 4, 3288fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'You seem to be initializing a member variable with itself.') 3289fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3290fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if file_extension == 'h': 3291fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # TODO(unknown): check that 1-arg constructors are explicit. 3292fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # How to tell it's a constructor? 3293fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # (handled in CheckForNonStandardConstructs for now) 3294fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # TODO(unknown): check that classes have DISALLOW_EVIL_CONSTRUCTORS 3295fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # (level 1 error) 3296fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov pass 3297fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3298fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Check if people are using the verboten C basic types. The only exception 3299fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # we regularly allow is "unsigned short port" for port. 3300fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'\bshort port\b', line): 3301fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not Search(r'\bunsigned short port\b', line): 3302fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/int', 4, 3303fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Use "unsigned short" for ports, not "short"') 3304fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 3305fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Search(r'\b(short|long(?! +double)|long long)\b', line) 3306fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match: 3307fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/int', 4, 3308fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Use int16/int64/etc, rather than the C type %s' % match.group(1)) 3309fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3310fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # When snprintf is used, the second argument shouldn't be a literal. 3311fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line) 3312fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match and match.group(2) != '0': 3313fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If 2nd arg is zero, snprintf is used to calculate size. 3314fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/printf', 3, 3315fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'If you can, use sizeof(%s) instead of %s as the 2nd arg ' 3316fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'to snprintf.' % (match.group(1), match.group(2))) 3317fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3318fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Check if some verboten C functions are being used. 3319fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'\bsprintf\b', line): 3320fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/printf', 5, 3321fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Never use sprintf. Use snprintf instead.') 3322fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Search(r'\b(strcpy|strcat)\b', line) 3323fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match: 3324fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/printf', 4, 3325fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Almost always, snprintf is better than %s' % match.group(1)) 3326fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3327fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'\bsscanf\b', line): 3328fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/printf', 1, 3329fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'sscanf can be ok, but is slow and can overflow buffers.') 3330fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3331fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Check if some verboten operator overloading is going on 3332fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # TODO(unknown): catch out-of-line unary operator&: 3333fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # class X {}; 3334fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # int operator&(const X& x) { return 42; } // unary operator& 3335fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # The trick is it's hard to tell apart from binary operator&: 3336fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # class Y { int operator&(const Y& x) { return 23; } }; // binary operator& 3337fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'\boperator\s*&\s*\(\s*\)', line): 3338fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/operator', 4, 3339fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Unary operator& is dangerous. Do not use it.') 3340fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3341fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Check for suspicious usage of "if" like 3342fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # } if (a == b) { 3343fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'\}\s*if\s*\(', line): 3344fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/braces', 4, 3345fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Did you mean "else if"? If not, start a new line for "if".') 3346fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3347fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Check for potential format string bugs like printf(foo). 3348fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # We constrain the pattern not to pick things like DocidForPrintf(foo). 3349fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str()) 3350fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # TODO(sugawarayu): Catch the following case. Need to change the calling 3351fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # convention of the whole function to process multiple line to handle it. 3352fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # printf( 3353fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line); 3354fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(') 3355fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if printf_args: 3356fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Match(r'([\w.\->()]+)$', printf_args) 3357fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match and match.group(1) != '__VA_ARGS__': 3358fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov function_name = re.search(r'\b((?:string)?printf)\s*\(', 3359fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line, re.I).group(1) 3360fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/printf', 4, 3361fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Potential format string bug. Do %s("%%s", %s) instead.' 3362fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov % (function_name, match.group(1))) 3363fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3364fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Check for potential memset bugs like memset(buf, sizeof(buf), 0). 3365fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line) 3366fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)): 3367fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/memset', 4, 3368fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Did you mean "memset(%s, 0, %s)"?' 3369fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov % (match.group(1), match.group(2))) 3370fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3371fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'\busing namespace\b', line): 3372fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'build/namespaces', 5, 3373fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Do not use namespace using-directives. ' 3374fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Use using-declarations instead.') 3375fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3376fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Detect variable-length arrays. 3377fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line) 3378fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (match and match.group(2) != 'return' and match.group(2) != 'delete' and 3379fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match.group(3).find(']') == -1): 3380fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Split the size using space and arithmetic operators as delimiters. 3381fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If any of the resulting tokens are not compile time constants then 3382fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # report the error. 3383fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3)) 3384fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov is_const = True 3385fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov skip_next = False 3386fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for tok in tokens: 3387fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if skip_next: 3388fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov skip_next = False 3389fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov continue 3390fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3391fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'sizeof\(.+\)', tok): continue 3392fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Search(r'arraysize\(\w+\)', tok): continue 3393fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3394fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov tok = tok.lstrip('(') 3395fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov tok = tok.rstrip(')') 3396fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not tok: continue 3397fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r'\d+', tok): continue 3398fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r'0[xX][0-9a-fA-F]+', tok): continue 3399fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r'k[A-Z0-9]\w*', tok): continue 3400fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue 3401fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue 3402fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # A catch all for tricky sizeof cases, including 'sizeof expression', 3403fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)' 3404fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # requires skipping the next token because we split on ' ' and '*'. 3405fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if tok.startswith('sizeof'): 3406fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov skip_next = True 3407fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov continue 3408fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov is_const = False 3409fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov break 3410fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not is_const: 3411fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/arrays', 1, 3412fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Do not use variable-length arrays. Use an appropriately named ' 3413fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov "('k' followed by CamelCase) compile-time constant for the size.") 3414fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3415fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If DISALLOW_EVIL_CONSTRUCTORS, DISALLOW_COPY_AND_ASSIGN, or 3416fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # DISALLOW_IMPLICIT_CONSTRUCTORS is present, then it should be the last thing 3417fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # in the class declaration. 3418fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Match( 3419fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (r'\s*' 3420fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'(DISALLOW_(EVIL_CONSTRUCTORS|COPY_AND_ASSIGN|IMPLICIT_CONSTRUCTORS))' 3421fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov r'\(.*\);$'), 3422fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line) 3423fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match and linenum + 1 < clean_lines.NumLines(): 3424fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov next_line = clean_lines.elided[linenum + 1] 3425fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # We allow some, but not all, declarations of variables to be present 3426fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # in the statement that defines the class. The [\w\*,\s]* fragment of 3427fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # the regular expression below allows users to declare instances of 3428fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # the class or pointers to instances, but not less common types such 3429fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # as function pointers or arrays. It's a tradeoff between allowing 3430fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # reasonable code and avoiding trying to parse more C++ using regexps. 3431fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not Search(r'^\s*}[\w\*,\s]*;', next_line): 3432fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/constructors', 3, 3433fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match.group(1) + ' should be the last thing in the class') 3434fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3435fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Check for use of unnamed namespaces in header files. Registration 3436fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # macros are typically OK, so we allow use of "namespace {" on lines 3437fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # that end with backslashes. 3438fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (file_extension == 'h' 3439fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov and Search(r'\bnamespace\s*{', line) 3440fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov and line[-1] != '\\'): 3441fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'build/namespaces', 4, 3442fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Do not use unnamed namespaces in header files. See ' 3443fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces' 3444fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ' for more information.') 3445fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3446fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3447fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckCStyleCast(filename, linenum, line, raw_line, cast_type, pattern, 3448fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error): 3449fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Checks for a C-style cast by looking for the pattern. 3450fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3451fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov This also handles sizeof(type) warnings, due to similarity of content. 3452fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3453fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 3454fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 3455fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 3456fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line: The line of code to check. 3457fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov raw_line: The raw line of code to check, with comments. 3458fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov cast_type: The string for the C++ cast to recommend. This is either 3459fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov reinterpret_cast, static_cast, or const_cast, depending. 3460fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov pattern: The regular expression used to find C-style casts. 3461fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 3462fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3463fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 3464fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov True if an error was emitted. 3465fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov False otherwise. 3466fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 3467fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = Search(pattern, line) 3468fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not match: 3469fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return False 3470fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3471fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # e.g., sizeof(int) 3472fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov sizeof_match = Match(r'.*sizeof\s*$', line[0:match.start(1) - 1]) 3473fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if sizeof_match: 3474fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'runtime/sizeof', 1, 3475fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Using sizeof(type). Use sizeof(varname) instead if possible') 3476fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return True 3477fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3478fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # operator++(int) and operator--(int) 3479fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (line[0:match.start(1) - 1].endswith(' operator++') or 3480fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line[0:match.start(1) - 1].endswith(' operator--')): 3481fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return False 3482fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3483fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov remainder = line[match.end(0):] 3484fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3485fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # The close paren is for function pointers as arguments to a function. 3486fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # eg, void foo(void (*bar)(int)); 3487fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # The semicolon check is a more basic function check; also possibly a 3488fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # function pointer typedef. 3489fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # eg, void foo(int); or void foo(int) const; 3490fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # The equals check is for function pointer assignment. 3491fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # eg, void *(*foo)(int) = ... 3492fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # The > is for MockCallback<...> ... 3493fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # 3494fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Right now, this will only catch cases where there's a single argument, and 3495fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # it's unnamed. It should probably be expanded to check for multiple 3496fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # arguments with some unnamed. 3497fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov function_match = Match(r'\s*(\)|=|(const)?\s*(;|\{|throw\(\)|>))', remainder) 3498fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if function_match: 3499fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (not function_match.group(3) or 3500fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov function_match.group(3) == ';' or 3501fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('MockCallback<' not in raw_line and 3502fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '/*' not in raw_line)): 3503fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/function', 3, 3504fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'All parameters should be named in a function') 3505fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return True 3506fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3507fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # At this point, all that should be left is actual casts. 3508fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'readability/casting', 4, 3509fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Using C-style cast. Use %s<%s>(...) instead' % 3510fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (cast_type, match.group(1))) 3511fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3512fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return True 3513fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3514fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3515fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_HEADERS_CONTAINING_TEMPLATES = ( 3516fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('<deque>', ('deque',)), 3517fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('<functional>', ('unary_function', 'binary_function', 3518fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'plus', 'minus', 'multiplies', 'divides', 'modulus', 3519fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'negate', 3520fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'equal_to', 'not_equal_to', 'greater', 'less', 3521fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'greater_equal', 'less_equal', 3522fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'logical_and', 'logical_or', 'logical_not', 3523fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'unary_negate', 'not1', 'binary_negate', 'not2', 3524fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'bind1st', 'bind2nd', 3525fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'pointer_to_unary_function', 3526fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'pointer_to_binary_function', 3527fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'ptr_fun', 3528fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t', 3529fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'mem_fun_ref_t', 3530fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'const_mem_fun_t', 'const_mem_fun1_t', 3531fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'const_mem_fun_ref_t', 'const_mem_fun1_ref_t', 3532fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'mem_fun_ref', 3533fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov )), 3534fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('<limits>', ('numeric_limits',)), 3535fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('<list>', ('list',)), 3536fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('<map>', ('map', 'multimap',)), 3537fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('<memory>', ('allocator',)), 3538fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('<queue>', ('queue', 'priority_queue',)), 3539fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('<set>', ('set', 'multiset',)), 3540fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('<stack>', ('stack',)), 3541fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('<string>', ('char_traits', 'basic_string',)), 3542fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('<utility>', ('pair',)), 3543fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('<vector>', ('vector',)), 3544fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3545fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # gcc extensions. 3546fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Note: std::hash is their hash, ::hash is our hash 3547fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('<hash_map>', ('hash_map', 'hash_multimap',)), 3548fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('<hash_set>', ('hash_set', 'hash_multiset',)), 3549fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ('<slist>', ('slist',)), 3550fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ) 3551fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3552fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_STRING = re.compile(r'\bstring\b') 3553fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3554fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_re_pattern_algorithm_header = [] 3555fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovfor _template in ('copy', 'max', 'min', 'min_element', 'sort', 'swap', 3556fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'transform'): 3557fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or 3558fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # type::max(). 3559fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _re_pattern_algorithm_header.append( 3560fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'), 3561fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _template, 3562fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '<algorithm>')) 3563fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3564fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_re_pattern_templates = [] 3565fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovfor _header, _templates in _HEADERS_CONTAINING_TEMPLATES: 3566fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for _template in _templates: 3567fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _re_pattern_templates.append( 3568fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (re.compile(r'(\<|\b)' + _template + r'\s*\<'), 3569fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _template + '<>', 3570fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _header)) 3571fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3572fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3573fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef FilesBelongToSameModule(filename_cc, filename_h): 3574fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Check if these two filenames belong to the same module. 3575fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3576fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov The concept of a 'module' here is a as follows: 3577fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the 3578fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov same 'module' if they are in the same directory. 3579fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov some/path/public/xyzzy and some/path/internal/xyzzy are also considered 3580fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov to belong to the same module here. 3581fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3582fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov If the filename_cc contains a longer path than the filename_h, for example, 3583fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov '/absolute/path/to/base/sysinfo.cc', and this file would include 3584fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'base/sysinfo.h', this function also produces the prefix needed to open the 3585fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov header. This is used by the caller of this function to more robustly open the 3586fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov header file. We don't have access to the real include paths in this context, 3587fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov so we need this guesswork here. 3588fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3589fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Known bugs: tools/base/bar.cc and base/bar.h belong to the same module 3590fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov according to this implementation. Because of this, this function gives 3591fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov some false positives. This should be sufficiently rare in practice. 3592fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3593fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 3594fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename_cc: is the path for the .cc file 3595fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename_h: is the path for the header path 3596fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3597fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 3598fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Tuple with a bool and a string: 3599fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov bool: True if filename_cc and filename_h belong to the same module. 3600fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov string: the additional prefix needed to open the header file. 3601fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 3602fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3603fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not filename_cc.endswith('.cc'): 3604fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return (False, '') 3605fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename_cc = filename_cc[:-len('.cc')] 3606fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if filename_cc.endswith('_unittest'): 3607fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename_cc = filename_cc[:-len('_unittest')] 3608fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif filename_cc.endswith('_test'): 3609fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename_cc = filename_cc[:-len('_test')] 3610fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename_cc = filename_cc.replace('/public/', '/') 3611fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename_cc = filename_cc.replace('/internal/', '/') 3612fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3613fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not filename_h.endswith('.h'): 3614fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return (False, '') 3615fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename_h = filename_h[:-len('.h')] 3616fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if filename_h.endswith('-inl'): 3617fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename_h = filename_h[:-len('-inl')] 3618fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename_h = filename_h.replace('/public/', '/') 3619fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename_h = filename_h.replace('/internal/', '/') 3620fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3621fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov files_belong_to_same_module = filename_cc.endswith(filename_h) 3622fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov common_path = '' 3623fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if files_belong_to_same_module: 3624fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov common_path = filename_cc[:-len(filename_h)] 3625fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return files_belong_to_same_module, common_path 3626fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3627fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3628fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef UpdateIncludeState(filename, include_state, io=codecs): 3629fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Fill up the include_state with new includes found from the file. 3630fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3631fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 3632fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: the name of the header to read. 3633fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include_state: an _IncludeState instance in which the headers are inserted. 3634fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov io: The io factory to use to read the file. Provided for testability. 3635fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3636fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 36372d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines True if a header was successfully added. False otherwise. 3638fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 3639fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov headerfile = None 3640fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov try: 3641fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov headerfile = io.open(filename, 'r', 'utf8', 'replace') 3642fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov except IOError: 3643fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return False 3644fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum = 0 3645fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for line in headerfile: 3646fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum += 1 3647fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_line = CleanseComments(line) 3648fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = _RE_PATTERN_INCLUDE.search(clean_line) 3649fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match: 3650fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include = match.group(2) 3651fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # The value formatting is cute, but not really used right now. 3652fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # What matters here is that the key is in include_state. 3653fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include_state.setdefault(include, '%s:%d' % (filename, linenum)) 3654fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return True 3655fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3656fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3657fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, 3658fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov io=codecs): 3659fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Reports for missing stl includes. 3660fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3661fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov This function will output warnings to make sure you are including the headers 3662fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov necessary for the stl containers and functions that you use. We only give one 3663fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov reason to include a header. For example, if you use both equal_to<> and 3664fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov less<> in a .h file, only one (the latter in the file) of these will be 3665fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov reported as a reason to include the <functional>. 3666fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3667fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 3668fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 3669fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 3670fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include_state: An _IncludeState instance. 3671fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 3672fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov io: The IO factory to use to read the header file. Provided for unittest 3673fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov injection. 3674fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 3675fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov required = {} # A map of header name to linenumber and the template entity. 3676fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Example of required: { '<functional>': (1219, 'less<>') } 3677fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3678fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for linenum in xrange(clean_lines.NumLines()): 3679fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = clean_lines.elided[linenum] 3680fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not line or line[0] == '#': 3681fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov continue 3682fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3683fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # String is special -- it is a non-templatized type in STL. 3684fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov matched = _RE_PATTERN_STRING.search(line) 3685fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if matched: 3686fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Don't warn about strings in non-STL namespaces: 3687fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # (We check only the first match per line; good enough.) 3688fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov prefix = line[:matched.start()] 3689fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if prefix.endswith('std::') or not prefix.endswith('::'): 3690fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov required['<string>'] = (linenum, 'string') 3691fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3692fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for pattern, template, header in _re_pattern_algorithm_header: 3693fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if pattern.search(line): 3694fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov required[header] = (linenum, template) 3695fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3696fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # The following function is just a speed up, no semantics are changed. 3697fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not '<' in line: # Reduces the cpu time usage by skipping lines. 3698fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov continue 3699fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3700fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for pattern, template, header in _re_pattern_templates: 3701fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if pattern.search(line): 3702fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov required[header] = (linenum, template) 3703fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3704fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # The policy is that if you #include something in foo.h you don't need to 3705fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # include it again in foo.cc. Here, we will look at possible includes. 3706fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Let's copy the include_state so it is only messed up within this function. 3707fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include_state = include_state.copy() 3708fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 37092d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines # Did we find the header for this file (if any) and successfully load it? 3710fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov header_found = False 3711fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3712fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Use the absolute path so that matching works properly. 3713fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov abs_filename = FileInfo(filename).FullName() 3714fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3715fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # For Emacs's flymake. 3716fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If cpplint is invoked from Emacs's flymake, a temporary file is generated 3717fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # by flymake and that file name might end with '_flymake.cc'. In that case, 3718fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # restore original file name here so that the corresponding header file can be 3719fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # found. 3720fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h' 3721fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # instead of 'foo_flymake.h' 3722fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename) 3723fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3724fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # include_state is modified during iteration, so we iterate over a copy of 3725fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # the keys. 3726fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov header_keys = include_state.keys() 3727fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for header in header_keys: 3728fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (same_module, common_path) = FilesBelongToSameModule(abs_filename, header) 3729fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov fullpath = common_path + header 3730fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if same_module and UpdateIncludeState(fullpath, include_state, io): 3731fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov header_found = True 3732fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3733fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If we can't find the header file for a .cc, assume it's because we don't 3734fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # know where to look. In that case we'll give up as we're not sure they 3735fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # didn't include it in the .h file. 3736fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # TODO(unknown): Do a better job of finding .h files so we are confident that 3737fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # not having the .h file means there isn't one. 3738fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if filename.endswith('.cc') and not header_found: 3739fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return 3740fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3741fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # All the lines have been processed, report the errors found. 3742fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for required_header_unstripped in required: 3743fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov template = required[required_header_unstripped][1] 3744fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if required_header_unstripped.strip('<>"') not in include_state: 3745fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, required[required_header_unstripped][0], 3746fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'build/include_what_you_use', 4, 3747fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'Add #include ' + required_header_unstripped + ' for ' + template) 3748fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3749fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3750fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov_RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<') 3751fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3752fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3753fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef CheckMakePairUsesDeduction(filename, clean_lines, linenum, error): 3754fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Check that make_pair's template arguments are deduced. 3755fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3756fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov G++ 4.6 in C++0x mode fails badly if make_pair's template arguments are 3757fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov specified explicitly, and such use isn't intended in any case. 3758fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3759fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 3760fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the current file. 3761fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: A CleansedLines instance containing the file. 3762fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov linenum: The number of the line to check. 3763fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: The function to call with any errors found. 3764fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 3765fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov raw = clean_lines.raw_lines 3766fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line = raw[linenum] 3767fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line) 3768fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if match: 3769fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error(filename, linenum, 'build/explicit_make_pair', 3770fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 4, # 4 = high confidence 3771fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'For C++11-compatibility, omit template arguments from make_pair' 3772fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ' OR use pair directly OR if appropriate, construct a pair directly') 3773fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3774fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3775fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef ProcessLine(filename, file_extension, clean_lines, line, 3776fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include_state, function_state, nesting_state, error, 3777fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov extra_check_functions=[]): 3778fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Processes a single line in the file. 3779fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3780fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 3781fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: Filename of the file that is being processed. 3782fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov file_extension: The extension (dot not included) of the file. 3783fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines: An array of strings, each representing a line of the file, 3784fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov with comments stripped. 3785fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov line: Number of line being processed. 3786fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include_state: An _IncludeState instance in which the headers are inserted. 3787fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov function_state: A _FunctionState instance which counts function lines, etc. 3788fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_state: A _NestingState instance which maintains information about 3789fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov the current stack of nested blocks being parsed. 3790fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: A callable to which errors are reported, which takes 4 arguments: 3791fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename, line number, error level, and message 3792fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov extra_check_functions: An array of additional check functions that will be 3793fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov run on each source line. Each function takes 4 3794fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov arguments: filename, clean_lines, line, error 3795fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 3796fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov raw_lines = clean_lines.raw_lines 3797fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ParseNolintSuppressions(filename, raw_lines[line], line, error) 3798fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_state.Update(filename, clean_lines, line, error) 3799fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if nesting_state.stack and nesting_state.stack[-1].inline_asm != _NO_ASM: 3800fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return 3801fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckForFunctionLengths(filename, clean_lines, line, function_state, error) 3802fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error) 3803fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error) 3804fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckLanguage(filename, clean_lines, line, file_extension, include_state, 3805fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error) 3806fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckForNonStandardConstructs(filename, clean_lines, line, 3807fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_state, error) 3808fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckPosixThreading(filename, clean_lines, line, error) 3809fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckInvalidIncrement(filename, clean_lines, line, error) 3810fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckMakePairUsesDeduction(filename, clean_lines, line, error) 3811fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for check_fn in extra_check_functions: 3812fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov check_fn(filename, clean_lines, line, error) 3813fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3814fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef ProcessFileData(filename, file_extension, lines, error, 3815fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov extra_check_functions=[]): 3816fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Performs lint checks and reports any errors to the given error function. 3817fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3818fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 3819fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: Filename of the file that is being processed. 3820fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov file_extension: The extension (dot not included) of the file. 3821fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov lines: An array of strings, each representing a line of the file, with the 3822fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov last element being empty if the file is terminated with a newline. 3823fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov error: A callable to which errors are reported, which takes 4 arguments: 3824fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename, line number, error level, and message 3825fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov extra_check_functions: An array of additional check functions that will be 3826fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov run on each source line. Each function takes 4 3827fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov arguments: filename, clean_lines, line, error 3828fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 3829fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov lines = (['// marker so line numbers and indices both start at 1'] + lines + 3830fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ['// marker so line numbers end in a known way']) 3831fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3832fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include_state = _IncludeState() 3833fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov function_state = _FunctionState() 3834fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_state = _NestingState() 3835fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3836fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ResetNolintSuppressions() 3837fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3838fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckForCopyright(filename, lines, error) 3839fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3840fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if file_extension == 'h': 3841fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckForHeaderGuard(filename, lines, error) 3842fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3843fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov RemoveMultiLineComments(filename, lines, error) 3844fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov clean_lines = CleansedLines(lines) 3845fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for line in xrange(clean_lines.NumLines()): 3846fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ProcessLine(filename, file_extension, clean_lines, line, 3847fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov include_state, function_state, nesting_state, error, 3848fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov extra_check_functions) 3849fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov nesting_state.CheckClassFinished(filename, error) 3850fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3851fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error) 3852fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3853fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # We check here rather than inside ProcessLine so that we see raw 3854fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # lines rather than "cleaned" lines. 3855fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckForUnicodeReplacementCharacters(filename, lines, error) 3856fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3857fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov CheckForNewlineAtEOF(filename, lines, error) 3858fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3859fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef ProcessFile(filename, vlevel, extra_check_functions=[]): 3860fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Does google-lint on a single file. 3861fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3862fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 3863fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filename: The name of the file to parse. 3864fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3865fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov vlevel: The level of errors to report. Every error of confidence 3866fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov >= verbose_level will be reported. 0 is a good default. 3867fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3868fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov extra_check_functions: An array of additional check functions that will be 3869fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov run on each source line. Each function takes 4 3870fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov arguments: filename, clean_lines, line, error 3871fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 3872fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3873fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _SetVerboseLevel(vlevel) 3874fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3875fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov try: 3876fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Support the UNIX convention of using "-" for stdin. Note that 3877fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # we are not opening the file with universal newline support 3878fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # (which codecs doesn't support anyway), so the resulting lines do 3879fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # contain trailing '\r' characters if we are reading a file that 3880fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # has CRLF endings. 3881fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # If after the split a trailing '\r' is present, it is removed 3882fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # below. If it is not expected to be present (i.e. os.linesep != 3883fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # '\r\n' as in Windows), a warning is issued below if this file 3884fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # is processed. 3885fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3886fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if filename == '-': 3887fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov lines = codecs.StreamReaderWriter(sys.stdin, 3888fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov codecs.getreader('utf8'), 3889fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov codecs.getwriter('utf8'), 3890fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'replace').read().split('\n') 3891fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 3892fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n') 3893fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3894fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov carriage_return_found = False 3895fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Remove trailing '\r'. 3896fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for linenum in range(len(lines)): 3897fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if lines[linenum].endswith('\r'): 3898fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov lines[linenum] = lines[linenum].rstrip('\r') 3899fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov carriage_return_found = True 3900fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3901fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov except IOError: 3902fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov sys.stderr.write( 3903fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov "Skipping input '%s': Can't open for reading\n" % filename) 3904fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return 3905fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3906fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Note, if no dot is found, this will give the entire filename as the ext. 3907fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov file_extension = filename[filename.rfind('.') + 1:] 3908fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3909fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # When reading from stdin, the extension is unknown, so no cpplint tests 3910fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # should rely on the extension. 3911fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if (filename != '-' and file_extension != 'cc' and file_extension != 'h' 3912fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov and file_extension != 'cpp'): 3913fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov sys.stderr.write('Ignoring %s; not a .cc or .h file\n' % filename) 3914fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 3915fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ProcessFileData(filename, file_extension, lines, Error, 3916fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov extra_check_functions) 3917fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if carriage_return_found and os.linesep != '\r\n': 3918fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Use 0 for linenum since outputting only one error for potentially 3919fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # several lines. 3920fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Error(filename, 0, 'whitespace/newline', 1, 3921fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'One or more unexpected \\r (^M) found;' 3922fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'better to use only a \\n') 3923fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3924fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov sys.stderr.write('Done processing %s\n' % filename) 3925fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3926fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3927fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef PrintUsage(message): 3928fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Prints a brief usage string and exits, optionally with an error message. 3929fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3930fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 3931fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov message: The optional error message. 3932fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 3933fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov sys.stderr.write(_USAGE) 3934fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if message: 3935fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov sys.exit('\nFATAL ERROR: ' + message) 3936fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov else: 3937fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov sys.exit(1) 3938fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3939fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3940fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef PrintCategories(): 3941fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Prints a list of all the error-categories used by error messages. 3942fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3943fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov These are the categories used to filter messages via --filter. 3944fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 3945fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov sys.stderr.write(''.join(' %s\n' % cat for cat in _ERROR_CATEGORIES)) 3946fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov sys.exit(0) 3947fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3948fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3949fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef ParseArguments(args): 3950fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """Parses the command line arguments. 3951fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3952fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov This may set the output format and verbosity level as side-effects. 3953fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3954fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Args: 3955fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov args: The command line arguments: 3956fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3957fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov Returns: 3958fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov The list of filenames to lint. 3959fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov """ 3960fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov try: 3961fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=', 3962fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'counting=', 3963fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'filter=', 3964fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'root=']) 3965fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov except getopt.GetoptError: 3966fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov PrintUsage('Invalid arguments.') 3967fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3968fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov verbosity = _VerboseLevel() 3969fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov output_format = _OutputFormat() 3970fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filters = '' 3971fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov counting_style = '' 3972fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3973fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for (opt, val) in opts: 3974fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if opt == '--help': 3975fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov PrintUsage(None) 3976fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif opt == '--output': 3977fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not val in ('emacs', 'vs7', 'eclipse'): 3978fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.') 3979fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov output_format = val 3980fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif opt == '--verbose': 3981fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov verbosity = int(val) 3982fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif opt == '--filter': 3983fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filters = val 3984fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not filters: 3985fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov PrintCategories() 3986fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif opt == '--counting': 3987fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if val not in ('total', 'toplevel', 'detailed'): 3988fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov PrintUsage('Valid counting options are total, toplevel, and detailed') 3989fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov counting_style = val 3990fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov elif opt == '--root': 3991fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov global _root 3992fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _root = val 3993fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3994fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov if not filenames: 3995fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov PrintUsage('No files were specified.') 3996fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 3997fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _SetOutputFormat(output_format) 3998fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _SetVerboseLevel(verbosity) 3999fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _SetFilters(filters) 4000fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _SetCountingStyle(counting_style) 4001fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 4002fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov return filenames 4003fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 4004fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 4005fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovdef main(): 4006fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov filenames = ParseArguments(sys.argv[1:]) 4007fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 4008fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # Change stderr to write with replacement characters so we don't die 4009fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov # if we try to print something containing non-ASCII characters. 4010fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov sys.stderr = codecs.StreamReaderWriter(sys.stderr, 4011fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov codecs.getreader('utf8'), 4012fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov codecs.getwriter('utf8'), 4013fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 'replace') 4014fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 4015fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _cpplint_state.ResetErrorCounts() 4016fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov for filename in filenames: 4017fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov ProcessFile(filename, _cpplint_state.verbose_level) 4018fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov _cpplint_state.PrintErrorCounts() 4019fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 4020fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov sys.exit(_cpplint_state.error_count > 0) 4021fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 4022fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov 4023fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonovif __name__ == '__main__': 4024fafab2f5e27eecbfaaee727f66ecd068dafa41feAlexey Samsonov main() 4025