1*8c35d5eeSXin Li#!/usr/bin/env python 2*8c35d5eeSXin Li# 3*8c35d5eeSXin Li# Copyright (c) 2009 Google Inc. All rights reserved. 4*8c35d5eeSXin Li# 5*8c35d5eeSXin Li# Redistribution and use in source and binary forms, with or without 6*8c35d5eeSXin Li# modification, are permitted provided that the following conditions are 7*8c35d5eeSXin Li# met: 8*8c35d5eeSXin Li# 9*8c35d5eeSXin Li# * Redistributions of source code must retain the above copyright 10*8c35d5eeSXin Li# notice, this list of conditions and the following disclaimer. 11*8c35d5eeSXin Li# * Redistributions in binary form must reproduce the above 12*8c35d5eeSXin Li# copyright notice, this list of conditions and the following disclaimer 13*8c35d5eeSXin Li# in the documentation and/or other materials provided with the 14*8c35d5eeSXin Li# distribution. 15*8c35d5eeSXin Li# * Neither the name of Google Inc. nor the names of its 16*8c35d5eeSXin Li# contributors may be used to endorse or promote products derived from 17*8c35d5eeSXin Li# this software without specific prior written permission. 18*8c35d5eeSXin Li# 19*8c35d5eeSXin Li# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20*8c35d5eeSXin Li# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21*8c35d5eeSXin Li# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22*8c35d5eeSXin Li# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23*8c35d5eeSXin Li# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24*8c35d5eeSXin Li# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25*8c35d5eeSXin Li# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26*8c35d5eeSXin Li# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27*8c35d5eeSXin Li# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28*8c35d5eeSXin Li# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29*8c35d5eeSXin Li# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30*8c35d5eeSXin Li 31*8c35d5eeSXin Li"""Does google-lint on c++ files. 32*8c35d5eeSXin Li 33*8c35d5eeSXin LiThe goal of this script is to identify places in the code that *may* 34*8c35d5eeSXin Libe in non-compliance with google style. It does not attempt to fix 35*8c35d5eeSXin Liup these problems -- the point is to educate. It does also not 36*8c35d5eeSXin Liattempt to find all problems, or to ensure that everything it does 37*8c35d5eeSXin Lifind is legitimately a problem. 38*8c35d5eeSXin Li 39*8c35d5eeSXin LiIn particular, we can get very confused by /* and // inside strings! 40*8c35d5eeSXin LiWe do a small hack, which is to ignore //'s with "'s after them on the 41*8c35d5eeSXin Lisame line, but it is far from perfect (in either direction). 42*8c35d5eeSXin Li""" 43*8c35d5eeSXin Li 44*8c35d5eeSXin Liimport codecs 45*8c35d5eeSXin Liimport copy 46*8c35d5eeSXin Liimport getopt 47*8c35d5eeSXin Liimport math # for log 48*8c35d5eeSXin Liimport os 49*8c35d5eeSXin Liimport re 50*8c35d5eeSXin Liimport sre_compile 51*8c35d5eeSXin Liimport string 52*8c35d5eeSXin Liimport sys 53*8c35d5eeSXin Liimport unicodedata 54*8c35d5eeSXin Liimport sysconfig 55*8c35d5eeSXin Li 56*8c35d5eeSXin Litry: 57*8c35d5eeSXin Li xrange # Python 2 58*8c35d5eeSXin Liexcept NameError: 59*8c35d5eeSXin Li xrange = range # Python 3 60*8c35d5eeSXin Li 61*8c35d5eeSXin Li 62*8c35d5eeSXin Li_USAGE = """ 63*8c35d5eeSXin LiSyntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...] 64*8c35d5eeSXin Li [--counting=total|toplevel|detailed] [--root=subdir] 65*8c35d5eeSXin Li [--linelength=digits] [--headers=x,y,...] 66*8c35d5eeSXin Li [--quiet] 67*8c35d5eeSXin Li <file> [file] ... 68*8c35d5eeSXin Li 69*8c35d5eeSXin Li The style guidelines this tries to follow are those in 70*8c35d5eeSXin Li https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml 71*8c35d5eeSXin Li 72*8c35d5eeSXin Li Every problem is given a confidence score from 1-5, with 5 meaning we are 73*8c35d5eeSXin Li certain of the problem, and 1 meaning it could be a legitimate construct. 74*8c35d5eeSXin Li This will miss some errors, and is not a substitute for a code review. 75*8c35d5eeSXin Li 76*8c35d5eeSXin Li To suppress false-positive errors of a certain category, add a 77*8c35d5eeSXin Li 'NOLINT(category)' comment to the line. NOLINT or NOLINT(*) 78*8c35d5eeSXin Li suppresses errors of all categories on that line. 79*8c35d5eeSXin Li 80*8c35d5eeSXin Li The files passed in will be linted; at least one file must be provided. 81*8c35d5eeSXin Li Default linted extensions are .cc, .cpp, .cu, .cuh and .h. Change the 82*8c35d5eeSXin Li extensions with the --extensions flag. 83*8c35d5eeSXin Li 84*8c35d5eeSXin Li Flags: 85*8c35d5eeSXin Li 86*8c35d5eeSXin Li output=vs7 87*8c35d5eeSXin Li By default, the output is formatted to ease emacs parsing. Visual Studio 88*8c35d5eeSXin Li compatible output (vs7) may also be used. Other formats are unsupported. 89*8c35d5eeSXin Li 90*8c35d5eeSXin Li verbose=# 91*8c35d5eeSXin Li Specify a number 0-5 to restrict errors to certain verbosity levels. 92*8c35d5eeSXin Li 93*8c35d5eeSXin Li quiet 94*8c35d5eeSXin Li Don't print anything if no errors are found. 95*8c35d5eeSXin Li 96*8c35d5eeSXin Li filter=-x,+y,... 97*8c35d5eeSXin Li Specify a comma-separated list of category-filters to apply: only 98*8c35d5eeSXin Li error messages whose category names pass the filters will be printed. 99*8c35d5eeSXin Li (Category names are printed with the message and look like 100*8c35d5eeSXin Li "[whitespace/indent]".) Filters are evaluated left to right. 101*8c35d5eeSXin Li "-FOO" and "FOO" means "do not print categories that start with FOO". 102*8c35d5eeSXin Li "+FOO" means "do print categories that start with FOO". 103*8c35d5eeSXin Li 104*8c35d5eeSXin Li Examples: --filter=-whitespace,+whitespace/braces 105*8c35d5eeSXin Li --filter=whitespace,runtime/printf,+runtime/printf_format 106*8c35d5eeSXin Li --filter=-,+build/include_what_you_use 107*8c35d5eeSXin Li 108*8c35d5eeSXin Li To see a list of all the categories used in cpplint, pass no arg: 109*8c35d5eeSXin Li --filter= 110*8c35d5eeSXin Li 111*8c35d5eeSXin Li counting=total|toplevel|detailed 112*8c35d5eeSXin Li The total number of errors found is always printed. If 113*8c35d5eeSXin Li 'toplevel' is provided, then the count of errors in each of 114*8c35d5eeSXin Li the top-level categories like 'build' and 'whitespace' will 115*8c35d5eeSXin Li also be printed. If 'detailed' is provided, then a count 116*8c35d5eeSXin Li is provided for each category like 'build/class'. 117*8c35d5eeSXin Li 118*8c35d5eeSXin Li root=subdir 119*8c35d5eeSXin Li The root directory used for deriving header guard CPP variable. 120*8c35d5eeSXin Li By default, the header guard CPP variable is calculated as the relative 121*8c35d5eeSXin Li path to the directory that contains .git, .hg, or .svn. When this flag 122*8c35d5eeSXin Li is specified, the relative path is calculated from the specified 123*8c35d5eeSXin Li directory. If the specified directory does not exist, this flag is 124*8c35d5eeSXin Li ignored. 125*8c35d5eeSXin Li 126*8c35d5eeSXin Li Examples: 127*8c35d5eeSXin Li Assuming that top/src/.git exists (and cwd=top/src), the header guard 128*8c35d5eeSXin Li CPP variables for top/src/chrome/browser/ui/browser.h are: 129*8c35d5eeSXin Li 130*8c35d5eeSXin Li No flag => CHROME_BROWSER_UI_BROWSER_H_ 131*8c35d5eeSXin Li --root=chrome => BROWSER_UI_BROWSER_H_ 132*8c35d5eeSXin Li --root=chrome/browser => UI_BROWSER_H_ 133*8c35d5eeSXin Li --root=.. => SRC_CHROME_BROWSER_UI_BROWSER_H_ 134*8c35d5eeSXin Li 135*8c35d5eeSXin Li linelength=digits 136*8c35d5eeSXin Li This is the allowed line length for the project. The default value is 137*8c35d5eeSXin Li 80 characters. 138*8c35d5eeSXin Li 139*8c35d5eeSXin Li Examples: 140*8c35d5eeSXin Li --linelength=120 141*8c35d5eeSXin Li 142*8c35d5eeSXin Li extensions=extension,extension,... 143*8c35d5eeSXin Li The allowed file extensions that cpplint will check 144*8c35d5eeSXin Li 145*8c35d5eeSXin Li Examples: 146*8c35d5eeSXin Li --extensions=hpp,cpp 147*8c35d5eeSXin Li 148*8c35d5eeSXin Li headers=x,y,... 149*8c35d5eeSXin Li The header extensions that cpplint will treat as .h in checks. Values are 150*8c35d5eeSXin Li automatically added to --extensions list. 151*8c35d5eeSXin Li 152*8c35d5eeSXin Li Examples: 153*8c35d5eeSXin Li --headers=hpp,hxx 154*8c35d5eeSXin Li --headers=hpp 155*8c35d5eeSXin Li 156*8c35d5eeSXin Li cpplint.py supports per-directory configurations specified in CPPLINT.cfg 157*8c35d5eeSXin Li files. CPPLINT.cfg file can contain a number of key=value pairs. 158*8c35d5eeSXin Li Currently the following options are supported: 159*8c35d5eeSXin Li 160*8c35d5eeSXin Li set noparent 161*8c35d5eeSXin Li filter=+filter1,-filter2,... 162*8c35d5eeSXin Li exclude_files=regex 163*8c35d5eeSXin Li linelength=80 164*8c35d5eeSXin Li root=subdir 165*8c35d5eeSXin Li headers=x,y,... 166*8c35d5eeSXin Li 167*8c35d5eeSXin Li "set noparent" option prevents cpplint from traversing directory tree 168*8c35d5eeSXin Li upwards looking for more .cfg files in parent directories. This option 169*8c35d5eeSXin Li is usually placed in the top-level project directory. 170*8c35d5eeSXin Li 171*8c35d5eeSXin Li The "filter" option is similar in function to --filter flag. It specifies 172*8c35d5eeSXin Li message filters in addition to the |_DEFAULT_FILTERS| and those specified 173*8c35d5eeSXin Li through --filter command-line flag. 174*8c35d5eeSXin Li 175*8c35d5eeSXin Li "exclude_files" allows to specify a regular expression to be matched against 176*8c35d5eeSXin Li a file name. If the expression matches, the file is skipped and not run 177*8c35d5eeSXin Li through liner. 178*8c35d5eeSXin Li 179*8c35d5eeSXin Li "linelength" allows to specify the allowed line length for the project. 180*8c35d5eeSXin Li 181*8c35d5eeSXin Li The "root" option is similar in function to the --root flag (see example 182*8c35d5eeSXin Li above). Paths are relative to the directory of the CPPLINT.cfg. 183*8c35d5eeSXin Li 184*8c35d5eeSXin Li The "headers" option is similar in function to the --headers flag 185*8c35d5eeSXin Li (see example above). 186*8c35d5eeSXin Li 187*8c35d5eeSXin Li CPPLINT.cfg has an effect on files in the same directory and all 188*8c35d5eeSXin Li sub-directories, unless overridden by a nested configuration file. 189*8c35d5eeSXin Li 190*8c35d5eeSXin Li Example file: 191*8c35d5eeSXin Li filter=-build/include_order,+build/include_alpha 192*8c35d5eeSXin Li exclude_files=.*\.cc 193*8c35d5eeSXin Li 194*8c35d5eeSXin Li The above example disables build/include_order warning and enables 195*8c35d5eeSXin Li build/include_alpha as well as excludes all .cc from being 196*8c35d5eeSXin Li processed by linter, in the current directory (where the .cfg 197*8c35d5eeSXin Li file is located) and all sub-directories. 198*8c35d5eeSXin Li""" 199*8c35d5eeSXin Li 200*8c35d5eeSXin Li# We categorize each error message we print. Here are the categories. 201*8c35d5eeSXin Li# We want an explicit list so we can list them all in cpplint --filter=. 202*8c35d5eeSXin Li# If you add a new error message with a new category, add it to the list 203*8c35d5eeSXin Li# here! cpplint_unittest.py should tell you if you forget to do this. 204*8c35d5eeSXin Li_ERROR_CATEGORIES = [ 205*8c35d5eeSXin Li 'build/class', 206*8c35d5eeSXin Li 'build/c++11', 207*8c35d5eeSXin Li 'build/c++14', 208*8c35d5eeSXin Li 'build/c++tr1', 209*8c35d5eeSXin Li 'build/deprecated', 210*8c35d5eeSXin Li 'build/endif_comment', 211*8c35d5eeSXin Li 'build/explicit_make_pair', 212*8c35d5eeSXin Li 'build/forward_decl', 213*8c35d5eeSXin Li 'build/header_guard', 214*8c35d5eeSXin Li 'build/include', 215*8c35d5eeSXin Li 'build/include_alpha', 216*8c35d5eeSXin Li 'build/include_order', 217*8c35d5eeSXin Li 'build/include_what_you_use', 218*8c35d5eeSXin Li 'build/namespaces', 219*8c35d5eeSXin Li 'build/printf_format', 220*8c35d5eeSXin Li 'build/storage_class', 221*8c35d5eeSXin Li 'legal/copyright', 222*8c35d5eeSXin Li 'readability/alt_tokens', 223*8c35d5eeSXin Li 'readability/braces', 224*8c35d5eeSXin Li 'readability/casting', 225*8c35d5eeSXin Li 'readability/check', 226*8c35d5eeSXin Li 'readability/constructors', 227*8c35d5eeSXin Li 'readability/fn_size', 228*8c35d5eeSXin Li 'readability/inheritance', 229*8c35d5eeSXin Li 'readability/multiline_comment', 230*8c35d5eeSXin Li 'readability/multiline_string', 231*8c35d5eeSXin Li 'readability/namespace', 232*8c35d5eeSXin Li 'readability/nolint', 233*8c35d5eeSXin Li 'readability/nul', 234*8c35d5eeSXin Li 'readability/strings', 235*8c35d5eeSXin Li 'readability/todo', 236*8c35d5eeSXin Li 'readability/utf8', 237*8c35d5eeSXin Li 'runtime/arrays', 238*8c35d5eeSXin Li 'runtime/casting', 239*8c35d5eeSXin Li 'runtime/explicit', 240*8c35d5eeSXin Li 'runtime/int', 241*8c35d5eeSXin Li 'runtime/init', 242*8c35d5eeSXin Li 'runtime/invalid_increment', 243*8c35d5eeSXin Li 'runtime/member_string_references', 244*8c35d5eeSXin Li 'runtime/memset', 245*8c35d5eeSXin Li 'runtime/indentation_namespace', 246*8c35d5eeSXin Li 'runtime/operator', 247*8c35d5eeSXin Li 'runtime/printf', 248*8c35d5eeSXin Li 'runtime/printf_format', 249*8c35d5eeSXin Li 'runtime/references', 250*8c35d5eeSXin Li 'runtime/string', 251*8c35d5eeSXin Li 'runtime/threadsafe_fn', 252*8c35d5eeSXin Li 'runtime/vlog', 253*8c35d5eeSXin Li 'whitespace/blank_line', 254*8c35d5eeSXin Li 'whitespace/braces', 255*8c35d5eeSXin Li 'whitespace/comma', 256*8c35d5eeSXin Li 'whitespace/comments', 257*8c35d5eeSXin Li 'whitespace/empty_conditional_body', 258*8c35d5eeSXin Li 'whitespace/empty_if_body', 259*8c35d5eeSXin Li 'whitespace/empty_loop_body', 260*8c35d5eeSXin Li 'whitespace/end_of_line', 261*8c35d5eeSXin Li 'whitespace/ending_newline', 262*8c35d5eeSXin Li 'whitespace/forcolon', 263*8c35d5eeSXin Li 'whitespace/indent', 264*8c35d5eeSXin Li 'whitespace/line_length', 265*8c35d5eeSXin Li 'whitespace/newline', 266*8c35d5eeSXin Li 'whitespace/operators', 267*8c35d5eeSXin Li 'whitespace/parens', 268*8c35d5eeSXin Li 'whitespace/semicolon', 269*8c35d5eeSXin Li 'whitespace/tab', 270*8c35d5eeSXin Li 'whitespace/todo', 271*8c35d5eeSXin Li ] 272*8c35d5eeSXin Li 273*8c35d5eeSXin Li# These error categories are no longer enforced by cpplint, but for backwards- 274*8c35d5eeSXin Li# compatibility they may still appear in NOLINT comments. 275*8c35d5eeSXin Li_LEGACY_ERROR_CATEGORIES = [ 276*8c35d5eeSXin Li 'readability/streams', 277*8c35d5eeSXin Li 'readability/function', 278*8c35d5eeSXin Li ] 279*8c35d5eeSXin Li 280*8c35d5eeSXin Li# The default state of the category filter. This is overridden by the --filter= 281*8c35d5eeSXin Li# flag. By default all errors are on, so only add here categories that should be 282*8c35d5eeSXin Li# off by default (i.e., categories that must be enabled by the --filter= flags). 283*8c35d5eeSXin Li# All entries here should start with a '-' or '+', as in the --filter= flag. 284*8c35d5eeSXin Li_DEFAULT_FILTERS = ['-build/include_alpha'] 285*8c35d5eeSXin Li 286*8c35d5eeSXin Li# The default list of categories suppressed for C (not C++) files. 287*8c35d5eeSXin Li_DEFAULT_C_SUPPRESSED_CATEGORIES = [ 288*8c35d5eeSXin Li 'readability/casting', 289*8c35d5eeSXin Li ] 290*8c35d5eeSXin Li 291*8c35d5eeSXin Li# The default list of categories suppressed for Linux Kernel files. 292*8c35d5eeSXin Li_DEFAULT_KERNEL_SUPPRESSED_CATEGORIES = [ 293*8c35d5eeSXin Li 'whitespace/tab', 294*8c35d5eeSXin Li ] 295*8c35d5eeSXin Li 296*8c35d5eeSXin Li# We used to check for high-bit characters, but after much discussion we 297*8c35d5eeSXin Li# decided those were OK, as long as they were in UTF-8 and didn't represent 298*8c35d5eeSXin Li# hard-coded international strings, which belong in a separate i18n file. 299*8c35d5eeSXin Li 300*8c35d5eeSXin Li# C++ headers 301*8c35d5eeSXin Li_CPP_HEADERS = frozenset([ 302*8c35d5eeSXin Li # Legacy 303*8c35d5eeSXin Li 'algobase.h', 304*8c35d5eeSXin Li 'algo.h', 305*8c35d5eeSXin Li 'alloc.h', 306*8c35d5eeSXin Li 'builtinbuf.h', 307*8c35d5eeSXin Li 'bvector.h', 308*8c35d5eeSXin Li 'complex.h', 309*8c35d5eeSXin Li 'defalloc.h', 310*8c35d5eeSXin Li 'deque.h', 311*8c35d5eeSXin Li 'editbuf.h', 312*8c35d5eeSXin Li 'fstream.h', 313*8c35d5eeSXin Li 'function.h', 314*8c35d5eeSXin Li 'hash_map', 315*8c35d5eeSXin Li 'hash_map.h', 316*8c35d5eeSXin Li 'hash_set', 317*8c35d5eeSXin Li 'hash_set.h', 318*8c35d5eeSXin Li 'hashtable.h', 319*8c35d5eeSXin Li 'heap.h', 320*8c35d5eeSXin Li 'indstream.h', 321*8c35d5eeSXin Li 'iomanip.h', 322*8c35d5eeSXin Li 'iostream.h', 323*8c35d5eeSXin Li 'istream.h', 324*8c35d5eeSXin Li 'iterator.h', 325*8c35d5eeSXin Li 'list.h', 326*8c35d5eeSXin Li 'map.h', 327*8c35d5eeSXin Li 'multimap.h', 328*8c35d5eeSXin Li 'multiset.h', 329*8c35d5eeSXin Li 'ostream.h', 330*8c35d5eeSXin Li 'pair.h', 331*8c35d5eeSXin Li 'parsestream.h', 332*8c35d5eeSXin Li 'pfstream.h', 333*8c35d5eeSXin Li 'procbuf.h', 334*8c35d5eeSXin Li 'pthread_alloc', 335*8c35d5eeSXin Li 'pthread_alloc.h', 336*8c35d5eeSXin Li 'rope', 337*8c35d5eeSXin Li 'rope.h', 338*8c35d5eeSXin Li 'ropeimpl.h', 339*8c35d5eeSXin Li 'set.h', 340*8c35d5eeSXin Li 'slist', 341*8c35d5eeSXin Li 'slist.h', 342*8c35d5eeSXin Li 'stack.h', 343*8c35d5eeSXin Li 'stdiostream.h', 344*8c35d5eeSXin Li 'stl_alloc.h', 345*8c35d5eeSXin Li 'stl_relops.h', 346*8c35d5eeSXin Li 'streambuf.h', 347*8c35d5eeSXin Li 'stream.h', 348*8c35d5eeSXin Li 'strfile.h', 349*8c35d5eeSXin Li 'strstream.h', 350*8c35d5eeSXin Li 'tempbuf.h', 351*8c35d5eeSXin Li 'tree.h', 352*8c35d5eeSXin Li 'type_traits.h', 353*8c35d5eeSXin Li 'vector.h', 354*8c35d5eeSXin Li # 17.6.1.2 C++ library headers 355*8c35d5eeSXin Li 'algorithm', 356*8c35d5eeSXin Li 'array', 357*8c35d5eeSXin Li 'atomic', 358*8c35d5eeSXin Li 'bitset', 359*8c35d5eeSXin Li 'chrono', 360*8c35d5eeSXin Li 'codecvt', 361*8c35d5eeSXin Li 'complex', 362*8c35d5eeSXin Li 'condition_variable', 363*8c35d5eeSXin Li 'deque', 364*8c35d5eeSXin Li 'exception', 365*8c35d5eeSXin Li 'forward_list', 366*8c35d5eeSXin Li 'fstream', 367*8c35d5eeSXin Li 'functional', 368*8c35d5eeSXin Li 'future', 369*8c35d5eeSXin Li 'initializer_list', 370*8c35d5eeSXin Li 'iomanip', 371*8c35d5eeSXin Li 'ios', 372*8c35d5eeSXin Li 'iosfwd', 373*8c35d5eeSXin Li 'iostream', 374*8c35d5eeSXin Li 'istream', 375*8c35d5eeSXin Li 'iterator', 376*8c35d5eeSXin Li 'limits', 377*8c35d5eeSXin Li 'list', 378*8c35d5eeSXin Li 'locale', 379*8c35d5eeSXin Li 'map', 380*8c35d5eeSXin Li 'memory', 381*8c35d5eeSXin Li 'mutex', 382*8c35d5eeSXin Li 'new', 383*8c35d5eeSXin Li 'numeric', 384*8c35d5eeSXin Li 'ostream', 385*8c35d5eeSXin Li 'queue', 386*8c35d5eeSXin Li 'random', 387*8c35d5eeSXin Li 'ratio', 388*8c35d5eeSXin Li 'regex', 389*8c35d5eeSXin Li 'scoped_allocator', 390*8c35d5eeSXin Li 'set', 391*8c35d5eeSXin Li 'sstream', 392*8c35d5eeSXin Li 'stack', 393*8c35d5eeSXin Li 'stdexcept', 394*8c35d5eeSXin Li 'streambuf', 395*8c35d5eeSXin Li 'string', 396*8c35d5eeSXin Li 'strstream', 397*8c35d5eeSXin Li 'system_error', 398*8c35d5eeSXin Li 'thread', 399*8c35d5eeSXin Li 'tuple', 400*8c35d5eeSXin Li 'typeindex', 401*8c35d5eeSXin Li 'typeinfo', 402*8c35d5eeSXin Li 'type_traits', 403*8c35d5eeSXin Li 'unordered_map', 404*8c35d5eeSXin Li 'unordered_set', 405*8c35d5eeSXin Li 'utility', 406*8c35d5eeSXin Li 'valarray', 407*8c35d5eeSXin Li 'vector', 408*8c35d5eeSXin Li # 17.6.1.2 C++ headers for C library facilities 409*8c35d5eeSXin Li 'cassert', 410*8c35d5eeSXin Li 'ccomplex', 411*8c35d5eeSXin Li 'cctype', 412*8c35d5eeSXin Li 'cerrno', 413*8c35d5eeSXin Li 'cfenv', 414*8c35d5eeSXin Li 'cfloat', 415*8c35d5eeSXin Li 'cinttypes', 416*8c35d5eeSXin Li 'ciso646', 417*8c35d5eeSXin Li 'climits', 418*8c35d5eeSXin Li 'clocale', 419*8c35d5eeSXin Li 'cmath', 420*8c35d5eeSXin Li 'csetjmp', 421*8c35d5eeSXin Li 'csignal', 422*8c35d5eeSXin Li 'cstdalign', 423*8c35d5eeSXin Li 'cstdarg', 424*8c35d5eeSXin Li 'cstdbool', 425*8c35d5eeSXin Li 'cstddef', 426*8c35d5eeSXin Li 'cstdint', 427*8c35d5eeSXin Li 'cstdio', 428*8c35d5eeSXin Li 'cstdlib', 429*8c35d5eeSXin Li 'cstring', 430*8c35d5eeSXin Li 'ctgmath', 431*8c35d5eeSXin Li 'ctime', 432*8c35d5eeSXin Li 'cuchar', 433*8c35d5eeSXin Li 'cwchar', 434*8c35d5eeSXin Li 'cwctype', 435*8c35d5eeSXin Li ]) 436*8c35d5eeSXin Li 437*8c35d5eeSXin Li# Type names 438*8c35d5eeSXin Li_TYPES = re.compile( 439*8c35d5eeSXin Li r'^(?:' 440*8c35d5eeSXin Li # [dcl.type.simple] 441*8c35d5eeSXin Li r'(char(16_t|32_t)?)|wchar_t|' 442*8c35d5eeSXin Li r'bool|short|int|long|signed|unsigned|float|double|' 443*8c35d5eeSXin Li # [support.types] 444*8c35d5eeSXin Li r'(ptrdiff_t|size_t|max_align_t|nullptr_t)|' 445*8c35d5eeSXin Li # [cstdint.syn] 446*8c35d5eeSXin Li r'(u?int(_fast|_least)?(8|16|32|64)_t)|' 447*8c35d5eeSXin Li r'(u?int(max|ptr)_t)|' 448*8c35d5eeSXin Li r')$') 449*8c35d5eeSXin Li 450*8c35d5eeSXin Li 451*8c35d5eeSXin Li# These headers are excluded from [build/include] and [build/include_order] 452*8c35d5eeSXin Li# checks: 453*8c35d5eeSXin Li# - Anything not following google file name conventions (containing an 454*8c35d5eeSXin Li# uppercase character, such as Python.h or nsStringAPI.h, for example). 455*8c35d5eeSXin Li# - Lua headers. 456*8c35d5eeSXin Li_THIRD_PARTY_HEADERS_PATTERN = re.compile( 457*8c35d5eeSXin Li r'^(?:[^/]*[A-Z][^/]*\.h|lua\.h|lauxlib\.h|lualib\.h)$') 458*8c35d5eeSXin Li 459*8c35d5eeSXin Li# Pattern for matching FileInfo.BaseName() against test file name 460*8c35d5eeSXin Li_TEST_FILE_SUFFIX = r'(_test|_unittest|_regtest)$' 461*8c35d5eeSXin Li 462*8c35d5eeSXin Li# Pattern that matches only complete whitespace, possibly across multiple lines. 463*8c35d5eeSXin Li_EMPTY_CONDITIONAL_BODY_PATTERN = re.compile(r'^\s*$', re.DOTALL) 464*8c35d5eeSXin Li 465*8c35d5eeSXin Li# Assertion macros. These are defined in base/logging.h and 466*8c35d5eeSXin Li# testing/base/public/gunit.h. 467*8c35d5eeSXin Li_CHECK_MACROS = [ 468*8c35d5eeSXin Li 'DCHECK', 'CHECK', 469*8c35d5eeSXin Li 'EXPECT_TRUE', 'ASSERT_TRUE', 470*8c35d5eeSXin Li 'EXPECT_FALSE', 'ASSERT_FALSE', 471*8c35d5eeSXin Li ] 472*8c35d5eeSXin Li 473*8c35d5eeSXin Li# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE 474*8c35d5eeSXin Li_CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS]) 475*8c35d5eeSXin Li 476*8c35d5eeSXin Lifor op, replacement in [('==', 'EQ'), ('!=', 'NE'), 477*8c35d5eeSXin Li ('>=', 'GE'), ('>', 'GT'), 478*8c35d5eeSXin Li ('<=', 'LE'), ('<', 'LT')]: 479*8c35d5eeSXin Li _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement 480*8c35d5eeSXin Li _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement 481*8c35d5eeSXin Li _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement 482*8c35d5eeSXin Li _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement 483*8c35d5eeSXin Li 484*8c35d5eeSXin Lifor op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'), 485*8c35d5eeSXin Li ('>=', 'LT'), ('>', 'LE'), 486*8c35d5eeSXin Li ('<=', 'GT'), ('<', 'GE')]: 487*8c35d5eeSXin Li _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement 488*8c35d5eeSXin Li _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement 489*8c35d5eeSXin Li 490*8c35d5eeSXin Li# Alternative tokens and their replacements. For full list, see section 2.5 491*8c35d5eeSXin Li# Alternative tokens [lex.digraph] in the C++ standard. 492*8c35d5eeSXin Li# 493*8c35d5eeSXin Li# Digraphs (such as '%:') are not included here since it's a mess to 494*8c35d5eeSXin Li# match those on a word boundary. 495*8c35d5eeSXin Li_ALT_TOKEN_REPLACEMENT = { 496*8c35d5eeSXin Li 'and': '&&', 497*8c35d5eeSXin Li 'bitor': '|', 498*8c35d5eeSXin Li 'or': '||', 499*8c35d5eeSXin Li 'xor': '^', 500*8c35d5eeSXin Li 'compl': '~', 501*8c35d5eeSXin Li 'bitand': '&', 502*8c35d5eeSXin Li 'and_eq': '&=', 503*8c35d5eeSXin Li 'or_eq': '|=', 504*8c35d5eeSXin Li 'xor_eq': '^=', 505*8c35d5eeSXin Li 'not': '!', 506*8c35d5eeSXin Li 'not_eq': '!=' 507*8c35d5eeSXin Li } 508*8c35d5eeSXin Li 509*8c35d5eeSXin Li# Compile regular expression that matches all the above keywords. The "[ =()]" 510*8c35d5eeSXin Li# bit is meant to avoid matching these keywords outside of boolean expressions. 511*8c35d5eeSXin Li# 512*8c35d5eeSXin Li# False positives include C-style multi-line comments and multi-line strings 513*8c35d5eeSXin Li# but those have always been troublesome for cpplint. 514*8c35d5eeSXin Li_ALT_TOKEN_REPLACEMENT_PATTERN = re.compile( 515*8c35d5eeSXin Li r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)') 516*8c35d5eeSXin Li 517*8c35d5eeSXin Li 518*8c35d5eeSXin Li# These constants define types of headers for use with 519*8c35d5eeSXin Li# _IncludeState.CheckNextIncludeOrder(). 520*8c35d5eeSXin Li_C_SYS_HEADER = 1 521*8c35d5eeSXin Li_CPP_SYS_HEADER = 2 522*8c35d5eeSXin Li_LIKELY_MY_HEADER = 3 523*8c35d5eeSXin Li_POSSIBLE_MY_HEADER = 4 524*8c35d5eeSXin Li_OTHER_HEADER = 5 525*8c35d5eeSXin Li 526*8c35d5eeSXin Li# These constants define the current inline assembly state 527*8c35d5eeSXin Li_NO_ASM = 0 # Outside of inline assembly block 528*8c35d5eeSXin Li_INSIDE_ASM = 1 # Inside inline assembly block 529*8c35d5eeSXin Li_END_ASM = 2 # Last line of inline assembly block 530*8c35d5eeSXin Li_BLOCK_ASM = 3 # The whole block is an inline assembly block 531*8c35d5eeSXin Li 532*8c35d5eeSXin Li# Match start of assembly blocks 533*8c35d5eeSXin Li_MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)' 534*8c35d5eeSXin Li r'(?:\s+(volatile|__volatile__))?' 535*8c35d5eeSXin Li r'\s*[{(]') 536*8c35d5eeSXin Li 537*8c35d5eeSXin Li# Match strings that indicate we're working on a C (not C++) file. 538*8c35d5eeSXin Li_SEARCH_C_FILE = re.compile(r'\b(?:LINT_C_FILE|' 539*8c35d5eeSXin Li r'vim?:\s*.*(\s*|:)filetype=c(\s*|:|$))') 540*8c35d5eeSXin Li 541*8c35d5eeSXin Li# Match string that indicates we're working on a Linux Kernel file. 542*8c35d5eeSXin Li_SEARCH_KERNEL_FILE = re.compile(r'\b(?:LINT_KERNEL_FILE)') 543*8c35d5eeSXin Li 544*8c35d5eeSXin Li_regexp_compile_cache = {} 545*8c35d5eeSXin Li 546*8c35d5eeSXin Li# {str, set(int)}: a map from error categories to sets of linenumbers 547*8c35d5eeSXin Li# on which those errors are expected and should be suppressed. 548*8c35d5eeSXin Li_error_suppressions = {} 549*8c35d5eeSXin Li 550*8c35d5eeSXin Li# The root directory used for deriving header guard CPP variable. 551*8c35d5eeSXin Li# This is set by --root flag. 552*8c35d5eeSXin Li_root = None 553*8c35d5eeSXin Li_root_debug = False 554*8c35d5eeSXin Li 555*8c35d5eeSXin Li# The allowed line length of files. 556*8c35d5eeSXin Li# This is set by --linelength flag. 557*8c35d5eeSXin Li_line_length = 80 558*8c35d5eeSXin Li 559*8c35d5eeSXin Li# The allowed extensions for file names 560*8c35d5eeSXin Li# This is set by --extensions flag. 561*8c35d5eeSXin Li_valid_extensions = set(['cc', 'h', 'cpp', 'cu', 'cuh']) 562*8c35d5eeSXin Li 563*8c35d5eeSXin Li# Treat all headers starting with 'h' equally: .h, .hpp, .hxx etc. 564*8c35d5eeSXin Li# This is set by --headers flag. 565*8c35d5eeSXin Li_hpp_headers = set(['h']) 566*8c35d5eeSXin Li 567*8c35d5eeSXin Li# {str, bool}: a map from error categories to booleans which indicate if the 568*8c35d5eeSXin Li# category should be suppressed for every line. 569*8c35d5eeSXin Li_global_error_suppressions = {} 570*8c35d5eeSXin Li 571*8c35d5eeSXin Lidef ProcessHppHeadersOption(val): 572*8c35d5eeSXin Li global _hpp_headers 573*8c35d5eeSXin Li try: 574*8c35d5eeSXin Li _hpp_headers = set(val.split(',')) 575*8c35d5eeSXin Li # Automatically append to extensions list so it does not have to be set 2 times 576*8c35d5eeSXin Li _valid_extensions.update(_hpp_headers) 577*8c35d5eeSXin Li except ValueError: 578*8c35d5eeSXin Li PrintUsage('Header extensions must be comma separated list.') 579*8c35d5eeSXin Li 580*8c35d5eeSXin Lidef IsHeaderExtension(file_extension): 581*8c35d5eeSXin Li return file_extension in _hpp_headers 582*8c35d5eeSXin Li 583*8c35d5eeSXin Lidef ParseNolintSuppressions(filename, raw_line, linenum, error): 584*8c35d5eeSXin Li """Updates the global list of line error-suppressions. 585*8c35d5eeSXin Li 586*8c35d5eeSXin Li Parses any NOLINT comments on the current line, updating the global 587*8c35d5eeSXin Li error_suppressions store. Reports an error if the NOLINT comment 588*8c35d5eeSXin Li was malformed. 589*8c35d5eeSXin Li 590*8c35d5eeSXin Li Args: 591*8c35d5eeSXin Li filename: str, the name of the input file. 592*8c35d5eeSXin Li raw_line: str, the line of input text, with comments. 593*8c35d5eeSXin Li linenum: int, the number of the current line. 594*8c35d5eeSXin Li error: function, an error handler. 595*8c35d5eeSXin Li """ 596*8c35d5eeSXin Li matched = Search(r'\bNOLINT(NEXTLINE)?\b(\([^)]+\))?', raw_line) 597*8c35d5eeSXin Li if matched: 598*8c35d5eeSXin Li if matched.group(1): 599*8c35d5eeSXin Li suppressed_line = linenum + 1 600*8c35d5eeSXin Li else: 601*8c35d5eeSXin Li suppressed_line = linenum 602*8c35d5eeSXin Li category = matched.group(2) 603*8c35d5eeSXin Li if category in (None, '(*)'): # => "suppress all" 604*8c35d5eeSXin Li _error_suppressions.setdefault(None, set()).add(suppressed_line) 605*8c35d5eeSXin Li else: 606*8c35d5eeSXin Li if category.startswith('(') and category.endswith(')'): 607*8c35d5eeSXin Li category = category[1:-1] 608*8c35d5eeSXin Li if category in _ERROR_CATEGORIES: 609*8c35d5eeSXin Li _error_suppressions.setdefault(category, set()).add(suppressed_line) 610*8c35d5eeSXin Li elif category not in _LEGACY_ERROR_CATEGORIES: 611*8c35d5eeSXin Li error(filename, linenum, 'readability/nolint', 5, 612*8c35d5eeSXin Li 'Unknown NOLINT error category: %s' % category) 613*8c35d5eeSXin Li 614*8c35d5eeSXin Li 615*8c35d5eeSXin Lidef ProcessGlobalSuppresions(lines): 616*8c35d5eeSXin Li """Updates the list of global error suppressions. 617*8c35d5eeSXin Li 618*8c35d5eeSXin Li Parses any lint directives in the file that have global effect. 619*8c35d5eeSXin Li 620*8c35d5eeSXin Li Args: 621*8c35d5eeSXin Li lines: An array of strings, each representing a line of the file, with the 622*8c35d5eeSXin Li last element being empty if the file is terminated with a newline. 623*8c35d5eeSXin Li """ 624*8c35d5eeSXin Li for line in lines: 625*8c35d5eeSXin Li if _SEARCH_C_FILE.search(line): 626*8c35d5eeSXin Li for category in _DEFAULT_C_SUPPRESSED_CATEGORIES: 627*8c35d5eeSXin Li _global_error_suppressions[category] = True 628*8c35d5eeSXin Li if _SEARCH_KERNEL_FILE.search(line): 629*8c35d5eeSXin Li for category in _DEFAULT_KERNEL_SUPPRESSED_CATEGORIES: 630*8c35d5eeSXin Li _global_error_suppressions[category] = True 631*8c35d5eeSXin Li 632*8c35d5eeSXin Li 633*8c35d5eeSXin Lidef ResetNolintSuppressions(): 634*8c35d5eeSXin Li """Resets the set of NOLINT suppressions to empty.""" 635*8c35d5eeSXin Li _error_suppressions.clear() 636*8c35d5eeSXin Li _global_error_suppressions.clear() 637*8c35d5eeSXin Li 638*8c35d5eeSXin Li 639*8c35d5eeSXin Lidef IsErrorSuppressedByNolint(category, linenum): 640*8c35d5eeSXin Li """Returns true if the specified error category is suppressed on this line. 641*8c35d5eeSXin Li 642*8c35d5eeSXin Li Consults the global error_suppressions map populated by 643*8c35d5eeSXin Li ParseNolintSuppressions/ProcessGlobalSuppresions/ResetNolintSuppressions. 644*8c35d5eeSXin Li 645*8c35d5eeSXin Li Args: 646*8c35d5eeSXin Li category: str, the category of the error. 647*8c35d5eeSXin Li linenum: int, the current line number. 648*8c35d5eeSXin Li Returns: 649*8c35d5eeSXin Li bool, True iff the error should be suppressed due to a NOLINT comment or 650*8c35d5eeSXin Li global suppression. 651*8c35d5eeSXin Li """ 652*8c35d5eeSXin Li return (_global_error_suppressions.get(category, False) or 653*8c35d5eeSXin Li linenum in _error_suppressions.get(category, set()) or 654*8c35d5eeSXin Li linenum in _error_suppressions.get(None, set())) 655*8c35d5eeSXin Li 656*8c35d5eeSXin Li 657*8c35d5eeSXin Lidef Match(pattern, s): 658*8c35d5eeSXin Li """Matches the string with the pattern, caching the compiled regexp.""" 659*8c35d5eeSXin Li # The regexp compilation caching is inlined in both Match and Search for 660*8c35d5eeSXin Li # performance reasons; factoring it out into a separate function turns out 661*8c35d5eeSXin Li # to be noticeably expensive. 662*8c35d5eeSXin Li if pattern not in _regexp_compile_cache: 663*8c35d5eeSXin Li _regexp_compile_cache[pattern] = sre_compile.compile(pattern) 664*8c35d5eeSXin Li return _regexp_compile_cache[pattern].match(s) 665*8c35d5eeSXin Li 666*8c35d5eeSXin Li 667*8c35d5eeSXin Lidef ReplaceAll(pattern, rep, s): 668*8c35d5eeSXin Li """Replaces instances of pattern in a string with a replacement. 669*8c35d5eeSXin Li 670*8c35d5eeSXin Li The compiled regex is kept in a cache shared by Match and Search. 671*8c35d5eeSXin Li 672*8c35d5eeSXin Li Args: 673*8c35d5eeSXin Li pattern: regex pattern 674*8c35d5eeSXin Li rep: replacement text 675*8c35d5eeSXin Li s: search string 676*8c35d5eeSXin Li 677*8c35d5eeSXin Li Returns: 678*8c35d5eeSXin Li string with replacements made (or original string if no replacements) 679*8c35d5eeSXin Li """ 680*8c35d5eeSXin Li if pattern not in _regexp_compile_cache: 681*8c35d5eeSXin Li _regexp_compile_cache[pattern] = sre_compile.compile(pattern) 682*8c35d5eeSXin Li return _regexp_compile_cache[pattern].sub(rep, s) 683*8c35d5eeSXin Li 684*8c35d5eeSXin Li 685*8c35d5eeSXin Lidef Search(pattern, s): 686*8c35d5eeSXin Li """Searches the string for the pattern, caching the compiled regexp.""" 687*8c35d5eeSXin Li if pattern not in _regexp_compile_cache: 688*8c35d5eeSXin Li _regexp_compile_cache[pattern] = sre_compile.compile(pattern) 689*8c35d5eeSXin Li return _regexp_compile_cache[pattern].search(s) 690*8c35d5eeSXin Li 691*8c35d5eeSXin Li 692*8c35d5eeSXin Lidef _IsSourceExtension(s): 693*8c35d5eeSXin Li """File extension (excluding dot) matches a source file extension.""" 694*8c35d5eeSXin Li return s in ('c', 'cc', 'cpp', 'cxx') 695*8c35d5eeSXin Li 696*8c35d5eeSXin Li 697*8c35d5eeSXin Liclass _IncludeState(object): 698*8c35d5eeSXin Li """Tracks line numbers for includes, and the order in which includes appear. 699*8c35d5eeSXin Li 700*8c35d5eeSXin Li include_list contains list of lists of (header, line number) pairs. 701*8c35d5eeSXin Li It's a lists of lists rather than just one flat list to make it 702*8c35d5eeSXin Li easier to update across preprocessor boundaries. 703*8c35d5eeSXin Li 704*8c35d5eeSXin Li Call CheckNextIncludeOrder() once for each header in the file, passing 705*8c35d5eeSXin Li in the type constants defined above. Calls in an illegal order will 706*8c35d5eeSXin Li raise an _IncludeError with an appropriate error message. 707*8c35d5eeSXin Li 708*8c35d5eeSXin Li """ 709*8c35d5eeSXin Li # self._section will move monotonically through this set. If it ever 710*8c35d5eeSXin Li # needs to move backwards, CheckNextIncludeOrder will raise an error. 711*8c35d5eeSXin Li _INITIAL_SECTION = 0 712*8c35d5eeSXin Li _MY_H_SECTION = 1 713*8c35d5eeSXin Li _C_SECTION = 2 714*8c35d5eeSXin Li _CPP_SECTION = 3 715*8c35d5eeSXin Li _OTHER_H_SECTION = 4 716*8c35d5eeSXin Li 717*8c35d5eeSXin Li _TYPE_NAMES = { 718*8c35d5eeSXin Li _C_SYS_HEADER: 'C system header', 719*8c35d5eeSXin Li _CPP_SYS_HEADER: 'C++ system header', 720*8c35d5eeSXin Li _LIKELY_MY_HEADER: 'header this file implements', 721*8c35d5eeSXin Li _POSSIBLE_MY_HEADER: 'header this file may implement', 722*8c35d5eeSXin Li _OTHER_HEADER: 'other header', 723*8c35d5eeSXin Li } 724*8c35d5eeSXin Li _SECTION_NAMES = { 725*8c35d5eeSXin Li _INITIAL_SECTION: "... nothing. (This can't be an error.)", 726*8c35d5eeSXin Li _MY_H_SECTION: 'a header this file implements', 727*8c35d5eeSXin Li _C_SECTION: 'C system header', 728*8c35d5eeSXin Li _CPP_SECTION: 'C++ system header', 729*8c35d5eeSXin Li _OTHER_H_SECTION: 'other header', 730*8c35d5eeSXin Li } 731*8c35d5eeSXin Li 732*8c35d5eeSXin Li def __init__(self): 733*8c35d5eeSXin Li self.include_list = [[]] 734*8c35d5eeSXin Li self.ResetSection('') 735*8c35d5eeSXin Li 736*8c35d5eeSXin Li def FindHeader(self, header): 737*8c35d5eeSXin Li """Check if a header has already been included. 738*8c35d5eeSXin Li 739*8c35d5eeSXin Li Args: 740*8c35d5eeSXin Li header: header to check. 741*8c35d5eeSXin Li Returns: 742*8c35d5eeSXin Li Line number of previous occurrence, or -1 if the header has not 743*8c35d5eeSXin Li been seen before. 744*8c35d5eeSXin Li """ 745*8c35d5eeSXin Li for section_list in self.include_list: 746*8c35d5eeSXin Li for f in section_list: 747*8c35d5eeSXin Li if f[0] == header: 748*8c35d5eeSXin Li return f[1] 749*8c35d5eeSXin Li return -1 750*8c35d5eeSXin Li 751*8c35d5eeSXin Li def ResetSection(self, directive): 752*8c35d5eeSXin Li """Reset section checking for preprocessor directive. 753*8c35d5eeSXin Li 754*8c35d5eeSXin Li Args: 755*8c35d5eeSXin Li directive: preprocessor directive (e.g. "if", "else"). 756*8c35d5eeSXin Li """ 757*8c35d5eeSXin Li # The name of the current section. 758*8c35d5eeSXin Li self._section = self._INITIAL_SECTION 759*8c35d5eeSXin Li # The path of last found header. 760*8c35d5eeSXin Li self._last_header = '' 761*8c35d5eeSXin Li 762*8c35d5eeSXin Li # Update list of includes. Note that we never pop from the 763*8c35d5eeSXin Li # include list. 764*8c35d5eeSXin Li if directive in ('if', 'ifdef', 'ifndef'): 765*8c35d5eeSXin Li self.include_list.append([]) 766*8c35d5eeSXin Li elif directive in ('else', 'elif'): 767*8c35d5eeSXin Li self.include_list[-1] = [] 768*8c35d5eeSXin Li 769*8c35d5eeSXin Li def SetLastHeader(self, header_path): 770*8c35d5eeSXin Li self._last_header = header_path 771*8c35d5eeSXin Li 772*8c35d5eeSXin Li def CanonicalizeAlphabeticalOrder(self, header_path): 773*8c35d5eeSXin Li """Returns a path canonicalized for alphabetical comparison. 774*8c35d5eeSXin Li 775*8c35d5eeSXin Li - replaces "-" with "_" so they both cmp the same. 776*8c35d5eeSXin Li - removes '-inl' since we don't require them to be after the main header. 777*8c35d5eeSXin Li - lowercase everything, just in case. 778*8c35d5eeSXin Li 779*8c35d5eeSXin Li Args: 780*8c35d5eeSXin Li header_path: Path to be canonicalized. 781*8c35d5eeSXin Li 782*8c35d5eeSXin Li Returns: 783*8c35d5eeSXin Li Canonicalized path. 784*8c35d5eeSXin Li """ 785*8c35d5eeSXin Li return header_path.replace('-inl.h', '.h').replace('-', '_').lower() 786*8c35d5eeSXin Li 787*8c35d5eeSXin Li def IsInAlphabeticalOrder(self, clean_lines, linenum, header_path): 788*8c35d5eeSXin Li """Check if a header is in alphabetical order with the previous header. 789*8c35d5eeSXin Li 790*8c35d5eeSXin Li Args: 791*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 792*8c35d5eeSXin Li linenum: The number of the line to check. 793*8c35d5eeSXin Li header_path: Canonicalized header to be checked. 794*8c35d5eeSXin Li 795*8c35d5eeSXin Li Returns: 796*8c35d5eeSXin Li Returns true if the header is in alphabetical order. 797*8c35d5eeSXin Li """ 798*8c35d5eeSXin Li # If previous section is different from current section, _last_header will 799*8c35d5eeSXin Li # be reset to empty string, so it's always less than current header. 800*8c35d5eeSXin Li # 801*8c35d5eeSXin Li # If previous line was a blank line, assume that the headers are 802*8c35d5eeSXin Li # intentionally sorted the way they are. 803*8c35d5eeSXin Li if (self._last_header > header_path and 804*8c35d5eeSXin Li Match(r'^\s*#\s*include\b', clean_lines.elided[linenum - 1])): 805*8c35d5eeSXin Li return False 806*8c35d5eeSXin Li return True 807*8c35d5eeSXin Li 808*8c35d5eeSXin Li def CheckNextIncludeOrder(self, header_type): 809*8c35d5eeSXin Li """Returns a non-empty error message if the next header is out of order. 810*8c35d5eeSXin Li 811*8c35d5eeSXin Li This function also updates the internal state to be ready to check 812*8c35d5eeSXin Li the next include. 813*8c35d5eeSXin Li 814*8c35d5eeSXin Li Args: 815*8c35d5eeSXin Li header_type: One of the _XXX_HEADER constants defined above. 816*8c35d5eeSXin Li 817*8c35d5eeSXin Li Returns: 818*8c35d5eeSXin Li The empty string if the header is in the right order, or an 819*8c35d5eeSXin Li error message describing what's wrong. 820*8c35d5eeSXin Li 821*8c35d5eeSXin Li """ 822*8c35d5eeSXin Li error_message = ('Found %s after %s' % 823*8c35d5eeSXin Li (self._TYPE_NAMES[header_type], 824*8c35d5eeSXin Li self._SECTION_NAMES[self._section])) 825*8c35d5eeSXin Li 826*8c35d5eeSXin Li last_section = self._section 827*8c35d5eeSXin Li 828*8c35d5eeSXin Li if header_type == _C_SYS_HEADER: 829*8c35d5eeSXin Li if self._section <= self._C_SECTION: 830*8c35d5eeSXin Li self._section = self._C_SECTION 831*8c35d5eeSXin Li else: 832*8c35d5eeSXin Li self._last_header = '' 833*8c35d5eeSXin Li return error_message 834*8c35d5eeSXin Li elif header_type == _CPP_SYS_HEADER: 835*8c35d5eeSXin Li if self._section <= self._CPP_SECTION: 836*8c35d5eeSXin Li self._section = self._CPP_SECTION 837*8c35d5eeSXin Li else: 838*8c35d5eeSXin Li self._last_header = '' 839*8c35d5eeSXin Li return error_message 840*8c35d5eeSXin Li elif header_type == _LIKELY_MY_HEADER: 841*8c35d5eeSXin Li if self._section <= self._MY_H_SECTION: 842*8c35d5eeSXin Li self._section = self._MY_H_SECTION 843*8c35d5eeSXin Li else: 844*8c35d5eeSXin Li self._section = self._OTHER_H_SECTION 845*8c35d5eeSXin Li elif header_type == _POSSIBLE_MY_HEADER: 846*8c35d5eeSXin Li if self._section <= self._MY_H_SECTION: 847*8c35d5eeSXin Li self._section = self._MY_H_SECTION 848*8c35d5eeSXin Li else: 849*8c35d5eeSXin Li # This will always be the fallback because we're not sure 850*8c35d5eeSXin Li # enough that the header is associated with this file. 851*8c35d5eeSXin Li self._section = self._OTHER_H_SECTION 852*8c35d5eeSXin Li else: 853*8c35d5eeSXin Li assert header_type == _OTHER_HEADER 854*8c35d5eeSXin Li self._section = self._OTHER_H_SECTION 855*8c35d5eeSXin Li 856*8c35d5eeSXin Li if last_section != self._section: 857*8c35d5eeSXin Li self._last_header = '' 858*8c35d5eeSXin Li 859*8c35d5eeSXin Li return '' 860*8c35d5eeSXin Li 861*8c35d5eeSXin Li 862*8c35d5eeSXin Liclass _CppLintState(object): 863*8c35d5eeSXin Li """Maintains module-wide state..""" 864*8c35d5eeSXin Li 865*8c35d5eeSXin Li def __init__(self): 866*8c35d5eeSXin Li self.verbose_level = 1 # global setting. 867*8c35d5eeSXin Li self.error_count = 0 # global count of reported errors 868*8c35d5eeSXin Li # filters to apply when emitting error messages 869*8c35d5eeSXin Li self.filters = _DEFAULT_FILTERS[:] 870*8c35d5eeSXin Li # backup of filter list. Used to restore the state after each file. 871*8c35d5eeSXin Li self._filters_backup = self.filters[:] 872*8c35d5eeSXin Li self.counting = 'total' # In what way are we counting errors? 873*8c35d5eeSXin Li self.errors_by_category = {} # string to int dict storing error counts 874*8c35d5eeSXin Li self.quiet = False # Suppress non-error messagess? 875*8c35d5eeSXin Li 876*8c35d5eeSXin Li # output format: 877*8c35d5eeSXin Li # "emacs" - format that emacs can parse (default) 878*8c35d5eeSXin Li # "vs7" - format that Microsoft Visual Studio 7 can parse 879*8c35d5eeSXin Li self.output_format = 'emacs' 880*8c35d5eeSXin Li 881*8c35d5eeSXin Li def SetOutputFormat(self, output_format): 882*8c35d5eeSXin Li """Sets the output format for errors.""" 883*8c35d5eeSXin Li self.output_format = output_format 884*8c35d5eeSXin Li 885*8c35d5eeSXin Li def SetQuiet(self, quiet): 886*8c35d5eeSXin Li """Sets the module's quiet settings, and returns the previous setting.""" 887*8c35d5eeSXin Li last_quiet = self.quiet 888*8c35d5eeSXin Li self.quiet = quiet 889*8c35d5eeSXin Li return last_quiet 890*8c35d5eeSXin Li 891*8c35d5eeSXin Li def SetVerboseLevel(self, level): 892*8c35d5eeSXin Li """Sets the module's verbosity, and returns the previous setting.""" 893*8c35d5eeSXin Li last_verbose_level = self.verbose_level 894*8c35d5eeSXin Li self.verbose_level = level 895*8c35d5eeSXin Li return last_verbose_level 896*8c35d5eeSXin Li 897*8c35d5eeSXin Li def SetCountingStyle(self, counting_style): 898*8c35d5eeSXin Li """Sets the module's counting options.""" 899*8c35d5eeSXin Li self.counting = counting_style 900*8c35d5eeSXin Li 901*8c35d5eeSXin Li def SetFilters(self, filters): 902*8c35d5eeSXin Li """Sets the error-message filters. 903*8c35d5eeSXin Li 904*8c35d5eeSXin Li These filters are applied when deciding whether to emit a given 905*8c35d5eeSXin Li error message. 906*8c35d5eeSXin Li 907*8c35d5eeSXin Li Args: 908*8c35d5eeSXin Li filters: A string of comma-separated filters (eg "+whitespace/indent"). 909*8c35d5eeSXin Li Each filter should start with + or -; else we die. 910*8c35d5eeSXin Li 911*8c35d5eeSXin Li Raises: 912*8c35d5eeSXin Li ValueError: The comma-separated filters did not all start with '+' or '-'. 913*8c35d5eeSXin Li E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter" 914*8c35d5eeSXin Li """ 915*8c35d5eeSXin Li # Default filters always have less priority than the flag ones. 916*8c35d5eeSXin Li self.filters = _DEFAULT_FILTERS[:] 917*8c35d5eeSXin Li self.AddFilters(filters) 918*8c35d5eeSXin Li 919*8c35d5eeSXin Li def AddFilters(self, filters): 920*8c35d5eeSXin Li """ Adds more filters to the existing list of error-message filters. """ 921*8c35d5eeSXin Li for filt in filters.split(','): 922*8c35d5eeSXin Li clean_filt = filt.strip() 923*8c35d5eeSXin Li if clean_filt: 924*8c35d5eeSXin Li self.filters.append(clean_filt) 925*8c35d5eeSXin Li for filt in self.filters: 926*8c35d5eeSXin Li if not (filt.startswith('+') or filt.startswith('-')): 927*8c35d5eeSXin Li raise ValueError('Every filter in --filters must start with + or -' 928*8c35d5eeSXin Li ' (%s does not)' % filt) 929*8c35d5eeSXin Li 930*8c35d5eeSXin Li def BackupFilters(self): 931*8c35d5eeSXin Li """ Saves the current filter list to backup storage.""" 932*8c35d5eeSXin Li self._filters_backup = self.filters[:] 933*8c35d5eeSXin Li 934*8c35d5eeSXin Li def RestoreFilters(self): 935*8c35d5eeSXin Li """ Restores filters previously backed up.""" 936*8c35d5eeSXin Li self.filters = self._filters_backup[:] 937*8c35d5eeSXin Li 938*8c35d5eeSXin Li def ResetErrorCounts(self): 939*8c35d5eeSXin Li """Sets the module's error statistic back to zero.""" 940*8c35d5eeSXin Li self.error_count = 0 941*8c35d5eeSXin Li self.errors_by_category = {} 942*8c35d5eeSXin Li 943*8c35d5eeSXin Li def IncrementErrorCount(self, category): 944*8c35d5eeSXin Li """Bumps the module's error statistic.""" 945*8c35d5eeSXin Li self.error_count += 1 946*8c35d5eeSXin Li if self.counting in ('toplevel', 'detailed'): 947*8c35d5eeSXin Li if self.counting != 'detailed': 948*8c35d5eeSXin Li category = category.split('/')[0] 949*8c35d5eeSXin Li if category not in self.errors_by_category: 950*8c35d5eeSXin Li self.errors_by_category[category] = 0 951*8c35d5eeSXin Li self.errors_by_category[category] += 1 952*8c35d5eeSXin Li 953*8c35d5eeSXin Li def PrintErrorCounts(self): 954*8c35d5eeSXin Li """Print a summary of errors by category, and the total.""" 955*8c35d5eeSXin Li for category, count in self.errors_by_category.iteritems(): 956*8c35d5eeSXin Li sys.stderr.write('Category \'%s\' errors found: %d\n' % 957*8c35d5eeSXin Li (category, count)) 958*8c35d5eeSXin Li sys.stdout.write('Total errors found: %d\n' % self.error_count) 959*8c35d5eeSXin Li 960*8c35d5eeSXin Li_cpplint_state = _CppLintState() 961*8c35d5eeSXin Li 962*8c35d5eeSXin Li 963*8c35d5eeSXin Lidef _OutputFormat(): 964*8c35d5eeSXin Li """Gets the module's output format.""" 965*8c35d5eeSXin Li return _cpplint_state.output_format 966*8c35d5eeSXin Li 967*8c35d5eeSXin Li 968*8c35d5eeSXin Lidef _SetOutputFormat(output_format): 969*8c35d5eeSXin Li """Sets the module's output format.""" 970*8c35d5eeSXin Li _cpplint_state.SetOutputFormat(output_format) 971*8c35d5eeSXin Li 972*8c35d5eeSXin Lidef _Quiet(): 973*8c35d5eeSXin Li """Return's the module's quiet setting.""" 974*8c35d5eeSXin Li return _cpplint_state.quiet 975*8c35d5eeSXin Li 976*8c35d5eeSXin Lidef _SetQuiet(quiet): 977*8c35d5eeSXin Li """Set the module's quiet status, and return previous setting.""" 978*8c35d5eeSXin Li return _cpplint_state.SetQuiet(quiet) 979*8c35d5eeSXin Li 980*8c35d5eeSXin Li 981*8c35d5eeSXin Lidef _VerboseLevel(): 982*8c35d5eeSXin Li """Returns the module's verbosity setting.""" 983*8c35d5eeSXin Li return _cpplint_state.verbose_level 984*8c35d5eeSXin Li 985*8c35d5eeSXin Li 986*8c35d5eeSXin Lidef _SetVerboseLevel(level): 987*8c35d5eeSXin Li """Sets the module's verbosity, and returns the previous setting.""" 988*8c35d5eeSXin Li return _cpplint_state.SetVerboseLevel(level) 989*8c35d5eeSXin Li 990*8c35d5eeSXin Li 991*8c35d5eeSXin Lidef _SetCountingStyle(level): 992*8c35d5eeSXin Li """Sets the module's counting options.""" 993*8c35d5eeSXin Li _cpplint_state.SetCountingStyle(level) 994*8c35d5eeSXin Li 995*8c35d5eeSXin Li 996*8c35d5eeSXin Lidef _Filters(): 997*8c35d5eeSXin Li """Returns the module's list of output filters, as a list.""" 998*8c35d5eeSXin Li return _cpplint_state.filters 999*8c35d5eeSXin Li 1000*8c35d5eeSXin Li 1001*8c35d5eeSXin Lidef _SetFilters(filters): 1002*8c35d5eeSXin Li """Sets the module's error-message filters. 1003*8c35d5eeSXin Li 1004*8c35d5eeSXin Li These filters are applied when deciding whether to emit a given 1005*8c35d5eeSXin Li error message. 1006*8c35d5eeSXin Li 1007*8c35d5eeSXin Li Args: 1008*8c35d5eeSXin Li filters: A string of comma-separated filters (eg "whitespace/indent"). 1009*8c35d5eeSXin Li Each filter should start with + or -; else we die. 1010*8c35d5eeSXin Li """ 1011*8c35d5eeSXin Li _cpplint_state.SetFilters(filters) 1012*8c35d5eeSXin Li 1013*8c35d5eeSXin Lidef _AddFilters(filters): 1014*8c35d5eeSXin Li """Adds more filter overrides. 1015*8c35d5eeSXin Li 1016*8c35d5eeSXin Li Unlike _SetFilters, this function does not reset the current list of filters 1017*8c35d5eeSXin Li available. 1018*8c35d5eeSXin Li 1019*8c35d5eeSXin Li Args: 1020*8c35d5eeSXin Li filters: A string of comma-separated filters (eg "whitespace/indent"). 1021*8c35d5eeSXin Li Each filter should start with + or -; else we die. 1022*8c35d5eeSXin Li """ 1023*8c35d5eeSXin Li _cpplint_state.AddFilters(filters) 1024*8c35d5eeSXin Li 1025*8c35d5eeSXin Lidef _BackupFilters(): 1026*8c35d5eeSXin Li """ Saves the current filter list to backup storage.""" 1027*8c35d5eeSXin Li _cpplint_state.BackupFilters() 1028*8c35d5eeSXin Li 1029*8c35d5eeSXin Lidef _RestoreFilters(): 1030*8c35d5eeSXin Li """ Restores filters previously backed up.""" 1031*8c35d5eeSXin Li _cpplint_state.RestoreFilters() 1032*8c35d5eeSXin Li 1033*8c35d5eeSXin Liclass _FunctionState(object): 1034*8c35d5eeSXin Li """Tracks current function name and the number of lines in its body.""" 1035*8c35d5eeSXin Li 1036*8c35d5eeSXin Li _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc. 1037*8c35d5eeSXin Li _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER. 1038*8c35d5eeSXin Li 1039*8c35d5eeSXin Li def __init__(self): 1040*8c35d5eeSXin Li self.in_a_function = False 1041*8c35d5eeSXin Li self.lines_in_function = 0 1042*8c35d5eeSXin Li self.current_function = '' 1043*8c35d5eeSXin Li 1044*8c35d5eeSXin Li def Begin(self, function_name): 1045*8c35d5eeSXin Li """Start analyzing function body. 1046*8c35d5eeSXin Li 1047*8c35d5eeSXin Li Args: 1048*8c35d5eeSXin Li function_name: The name of the function being tracked. 1049*8c35d5eeSXin Li """ 1050*8c35d5eeSXin Li self.in_a_function = True 1051*8c35d5eeSXin Li self.lines_in_function = 0 1052*8c35d5eeSXin Li self.current_function = function_name 1053*8c35d5eeSXin Li 1054*8c35d5eeSXin Li def Count(self): 1055*8c35d5eeSXin Li """Count line in current function body.""" 1056*8c35d5eeSXin Li if self.in_a_function: 1057*8c35d5eeSXin Li self.lines_in_function += 1 1058*8c35d5eeSXin Li 1059*8c35d5eeSXin Li def Check(self, error, filename, linenum): 1060*8c35d5eeSXin Li """Report if too many lines in function body. 1061*8c35d5eeSXin Li 1062*8c35d5eeSXin Li Args: 1063*8c35d5eeSXin Li error: The function to call with any errors found. 1064*8c35d5eeSXin Li filename: The name of the current file. 1065*8c35d5eeSXin Li linenum: The number of the line to check. 1066*8c35d5eeSXin Li """ 1067*8c35d5eeSXin Li if not self.in_a_function: 1068*8c35d5eeSXin Li return 1069*8c35d5eeSXin Li 1070*8c35d5eeSXin Li if Match(r'T(EST|est)', self.current_function): 1071*8c35d5eeSXin Li base_trigger = self._TEST_TRIGGER 1072*8c35d5eeSXin Li else: 1073*8c35d5eeSXin Li base_trigger = self._NORMAL_TRIGGER 1074*8c35d5eeSXin Li trigger = base_trigger * 2**_VerboseLevel() 1075*8c35d5eeSXin Li 1076*8c35d5eeSXin Li if self.lines_in_function > trigger: 1077*8c35d5eeSXin Li error_level = int(math.log(self.lines_in_function / base_trigger, 2)) 1078*8c35d5eeSXin Li # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ... 1079*8c35d5eeSXin Li if error_level > 5: 1080*8c35d5eeSXin Li error_level = 5 1081*8c35d5eeSXin Li error(filename, linenum, 'readability/fn_size', error_level, 1082*8c35d5eeSXin Li 'Small and focused functions are preferred:' 1083*8c35d5eeSXin Li ' %s has %d non-comment lines' 1084*8c35d5eeSXin Li ' (error triggered by exceeding %d lines).' % ( 1085*8c35d5eeSXin Li self.current_function, self.lines_in_function, trigger)) 1086*8c35d5eeSXin Li 1087*8c35d5eeSXin Li def End(self): 1088*8c35d5eeSXin Li """Stop analyzing function body.""" 1089*8c35d5eeSXin Li self.in_a_function = False 1090*8c35d5eeSXin Li 1091*8c35d5eeSXin Li 1092*8c35d5eeSXin Liclass _IncludeError(Exception): 1093*8c35d5eeSXin Li """Indicates a problem with the include order in a file.""" 1094*8c35d5eeSXin Li pass 1095*8c35d5eeSXin Li 1096*8c35d5eeSXin Li 1097*8c35d5eeSXin Liclass FileInfo(object): 1098*8c35d5eeSXin Li """Provides utility functions for filenames. 1099*8c35d5eeSXin Li 1100*8c35d5eeSXin Li FileInfo provides easy access to the components of a file's path 1101*8c35d5eeSXin Li relative to the project root. 1102*8c35d5eeSXin Li """ 1103*8c35d5eeSXin Li 1104*8c35d5eeSXin Li def __init__(self, filename): 1105*8c35d5eeSXin Li self._filename = filename 1106*8c35d5eeSXin Li 1107*8c35d5eeSXin Li def FullName(self): 1108*8c35d5eeSXin Li """Make Windows paths like Unix.""" 1109*8c35d5eeSXin Li return os.path.abspath(self._filename).replace('\\', '/') 1110*8c35d5eeSXin Li 1111*8c35d5eeSXin Li def RepositoryName(self): 1112*8c35d5eeSXin Li """FullName after removing the local path to the repository. 1113*8c35d5eeSXin Li 1114*8c35d5eeSXin Li If we have a real absolute path name here we can try to do something smart: 1115*8c35d5eeSXin Li detecting the root of the checkout and truncating /path/to/checkout from 1116*8c35d5eeSXin Li the name so that we get header guards that don't include things like 1117*8c35d5eeSXin Li "C:\Documents and Settings\..." or "/home/username/..." in them and thus 1118*8c35d5eeSXin Li people on different computers who have checked the source out to different 1119*8c35d5eeSXin Li locations won't see bogus errors. 1120*8c35d5eeSXin Li """ 1121*8c35d5eeSXin Li fullname = self.FullName() 1122*8c35d5eeSXin Li 1123*8c35d5eeSXin Li if os.path.exists(fullname): 1124*8c35d5eeSXin Li project_dir = os.path.dirname(fullname) 1125*8c35d5eeSXin Li 1126*8c35d5eeSXin Li if os.path.exists(os.path.join(project_dir, ".svn")): 1127*8c35d5eeSXin Li # If there's a .svn file in the current directory, we recursively look 1128*8c35d5eeSXin Li # up the directory tree for the top of the SVN checkout 1129*8c35d5eeSXin Li root_dir = project_dir 1130*8c35d5eeSXin Li one_up_dir = os.path.dirname(root_dir) 1131*8c35d5eeSXin Li while os.path.exists(os.path.join(one_up_dir, ".svn")): 1132*8c35d5eeSXin Li root_dir = os.path.dirname(root_dir) 1133*8c35d5eeSXin Li one_up_dir = os.path.dirname(one_up_dir) 1134*8c35d5eeSXin Li 1135*8c35d5eeSXin Li prefix = os.path.commonprefix([root_dir, project_dir]) 1136*8c35d5eeSXin Li return fullname[len(prefix) + 1:] 1137*8c35d5eeSXin Li 1138*8c35d5eeSXin Li # Not SVN <= 1.6? Try to find a git, hg, or svn top level directory by 1139*8c35d5eeSXin Li # searching up from the current path. 1140*8c35d5eeSXin Li root_dir = current_dir = os.path.dirname(fullname) 1141*8c35d5eeSXin Li while current_dir != os.path.dirname(current_dir): 1142*8c35d5eeSXin Li if (os.path.exists(os.path.join(current_dir, ".git")) or 1143*8c35d5eeSXin Li os.path.exists(os.path.join(current_dir, ".hg")) or 1144*8c35d5eeSXin Li os.path.exists(os.path.join(current_dir, ".svn"))): 1145*8c35d5eeSXin Li root_dir = current_dir 1146*8c35d5eeSXin Li current_dir = os.path.dirname(current_dir) 1147*8c35d5eeSXin Li 1148*8c35d5eeSXin Li if (os.path.exists(os.path.join(root_dir, ".git")) or 1149*8c35d5eeSXin Li os.path.exists(os.path.join(root_dir, ".hg")) or 1150*8c35d5eeSXin Li os.path.exists(os.path.join(root_dir, ".svn"))): 1151*8c35d5eeSXin Li prefix = os.path.commonprefix([root_dir, project_dir]) 1152*8c35d5eeSXin Li return fullname[len(prefix) + 1:] 1153*8c35d5eeSXin Li 1154*8c35d5eeSXin Li # Don't know what to do; header guard warnings may be wrong... 1155*8c35d5eeSXin Li return fullname 1156*8c35d5eeSXin Li 1157*8c35d5eeSXin Li def Split(self): 1158*8c35d5eeSXin Li """Splits the file into the directory, basename, and extension. 1159*8c35d5eeSXin Li 1160*8c35d5eeSXin Li For 'chrome/browser/browser.cc', Split() would 1161*8c35d5eeSXin Li return ('chrome/browser', 'browser', '.cc') 1162*8c35d5eeSXin Li 1163*8c35d5eeSXin Li Returns: 1164*8c35d5eeSXin Li A tuple of (directory, basename, extension). 1165*8c35d5eeSXin Li """ 1166*8c35d5eeSXin Li 1167*8c35d5eeSXin Li googlename = self.RepositoryName() 1168*8c35d5eeSXin Li project, rest = os.path.split(googlename) 1169*8c35d5eeSXin Li return (project,) + os.path.splitext(rest) 1170*8c35d5eeSXin Li 1171*8c35d5eeSXin Li def BaseName(self): 1172*8c35d5eeSXin Li """File base name - text after the final slash, before the final period.""" 1173*8c35d5eeSXin Li return self.Split()[1] 1174*8c35d5eeSXin Li 1175*8c35d5eeSXin Li def Extension(self): 1176*8c35d5eeSXin Li """File extension - text following the final period.""" 1177*8c35d5eeSXin Li return self.Split()[2] 1178*8c35d5eeSXin Li 1179*8c35d5eeSXin Li def NoExtension(self): 1180*8c35d5eeSXin Li """File has no source file extension.""" 1181*8c35d5eeSXin Li return '/'.join(self.Split()[0:2]) 1182*8c35d5eeSXin Li 1183*8c35d5eeSXin Li def IsSource(self): 1184*8c35d5eeSXin Li """File has a source file extension.""" 1185*8c35d5eeSXin Li return _IsSourceExtension(self.Extension()[1:]) 1186*8c35d5eeSXin Li 1187*8c35d5eeSXin Li 1188*8c35d5eeSXin Lidef _ShouldPrintError(category, confidence, linenum): 1189*8c35d5eeSXin Li """If confidence >= verbose, category passes filter and is not suppressed.""" 1190*8c35d5eeSXin Li 1191*8c35d5eeSXin Li # There are three ways we might decide not to print an error message: 1192*8c35d5eeSXin Li # a "NOLINT(category)" comment appears in the source, 1193*8c35d5eeSXin Li # the verbosity level isn't high enough, or the filters filter it out. 1194*8c35d5eeSXin Li if IsErrorSuppressedByNolint(category, linenum): 1195*8c35d5eeSXin Li return False 1196*8c35d5eeSXin Li 1197*8c35d5eeSXin Li if confidence < _cpplint_state.verbose_level: 1198*8c35d5eeSXin Li return False 1199*8c35d5eeSXin Li 1200*8c35d5eeSXin Li is_filtered = False 1201*8c35d5eeSXin Li for one_filter in _Filters(): 1202*8c35d5eeSXin Li if one_filter.startswith('-'): 1203*8c35d5eeSXin Li if category.startswith(one_filter[1:]): 1204*8c35d5eeSXin Li is_filtered = True 1205*8c35d5eeSXin Li elif one_filter.startswith('+'): 1206*8c35d5eeSXin Li if category.startswith(one_filter[1:]): 1207*8c35d5eeSXin Li is_filtered = False 1208*8c35d5eeSXin Li else: 1209*8c35d5eeSXin Li assert False # should have been checked for in SetFilter. 1210*8c35d5eeSXin Li if is_filtered: 1211*8c35d5eeSXin Li return False 1212*8c35d5eeSXin Li 1213*8c35d5eeSXin Li return True 1214*8c35d5eeSXin Li 1215*8c35d5eeSXin Li 1216*8c35d5eeSXin Lidef Error(filename, linenum, category, confidence, message): 1217*8c35d5eeSXin Li """Logs the fact we've found a lint error. 1218*8c35d5eeSXin Li 1219*8c35d5eeSXin Li We log where the error was found, and also our confidence in the error, 1220*8c35d5eeSXin Li that is, how certain we are this is a legitimate style regression, and 1221*8c35d5eeSXin Li not a misidentification or a use that's sometimes justified. 1222*8c35d5eeSXin Li 1223*8c35d5eeSXin Li False positives can be suppressed by the use of 1224*8c35d5eeSXin Li "cpplint(category)" comments on the offending line. These are 1225*8c35d5eeSXin Li parsed into _error_suppressions. 1226*8c35d5eeSXin Li 1227*8c35d5eeSXin Li Args: 1228*8c35d5eeSXin Li filename: The name of the file containing the error. 1229*8c35d5eeSXin Li linenum: The number of the line containing the error. 1230*8c35d5eeSXin Li category: A string used to describe the "category" this bug 1231*8c35d5eeSXin Li falls under: "whitespace", say, or "runtime". Categories 1232*8c35d5eeSXin Li may have a hierarchy separated by slashes: "whitespace/indent". 1233*8c35d5eeSXin Li confidence: A number from 1-5 representing a confidence score for 1234*8c35d5eeSXin Li the error, with 5 meaning that we are certain of the problem, 1235*8c35d5eeSXin Li and 1 meaning that it could be a legitimate construct. 1236*8c35d5eeSXin Li message: The error message. 1237*8c35d5eeSXin Li """ 1238*8c35d5eeSXin Li if _ShouldPrintError(category, confidence, linenum): 1239*8c35d5eeSXin Li _cpplint_state.IncrementErrorCount(category) 1240*8c35d5eeSXin Li if _cpplint_state.output_format == 'vs7': 1241*8c35d5eeSXin Li sys.stderr.write('%s(%s): error cpplint: [%s] %s [%d]\n' % ( 1242*8c35d5eeSXin Li filename, linenum, category, message, confidence)) 1243*8c35d5eeSXin Li elif _cpplint_state.output_format == 'eclipse': 1244*8c35d5eeSXin Li sys.stderr.write('%s:%s: warning: %s [%s] [%d]\n' % ( 1245*8c35d5eeSXin Li filename, linenum, message, category, confidence)) 1246*8c35d5eeSXin Li else: 1247*8c35d5eeSXin Li sys.stderr.write('%s:%s: %s [%s] [%d]\n' % ( 1248*8c35d5eeSXin Li filename, linenum, message, category, confidence)) 1249*8c35d5eeSXin Li 1250*8c35d5eeSXin Li 1251*8c35d5eeSXin Li# Matches standard C++ escape sequences per 2.13.2.3 of the C++ standard. 1252*8c35d5eeSXin Li_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile( 1253*8c35d5eeSXin Li r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)') 1254*8c35d5eeSXin Li# Match a single C style comment on the same line. 1255*8c35d5eeSXin Li_RE_PATTERN_C_COMMENTS = r'/\*(?:[^*]|\*(?!/))*\*/' 1256*8c35d5eeSXin Li# Matches multi-line C style comments. 1257*8c35d5eeSXin Li# This RE is a little bit more complicated than one might expect, because we 1258*8c35d5eeSXin Li# have to take care of space removals tools so we can handle comments inside 1259*8c35d5eeSXin Li# statements better. 1260*8c35d5eeSXin Li# The current rule is: We only clear spaces from both sides when we're at the 1261*8c35d5eeSXin Li# end of the line. Otherwise, we try to remove spaces from the right side, 1262*8c35d5eeSXin Li# if this doesn't work we try on left side but only if there's a non-character 1263*8c35d5eeSXin Li# on the right. 1264*8c35d5eeSXin Li_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile( 1265*8c35d5eeSXin Li r'(\s*' + _RE_PATTERN_C_COMMENTS + r'\s*$|' + 1266*8c35d5eeSXin Li _RE_PATTERN_C_COMMENTS + r'\s+|' + 1267*8c35d5eeSXin Li r'\s+' + _RE_PATTERN_C_COMMENTS + r'(?=\W)|' + 1268*8c35d5eeSXin Li _RE_PATTERN_C_COMMENTS + r')') 1269*8c35d5eeSXin Li 1270*8c35d5eeSXin Li 1271*8c35d5eeSXin Lidef IsCppString(line): 1272*8c35d5eeSXin Li """Does line terminate so, that the next symbol is in string constant. 1273*8c35d5eeSXin Li 1274*8c35d5eeSXin Li This function does not consider single-line nor multi-line comments. 1275*8c35d5eeSXin Li 1276*8c35d5eeSXin Li Args: 1277*8c35d5eeSXin Li line: is a partial line of code starting from the 0..n. 1278*8c35d5eeSXin Li 1279*8c35d5eeSXin Li Returns: 1280*8c35d5eeSXin Li True, if next character appended to 'line' is inside a 1281*8c35d5eeSXin Li string constant. 1282*8c35d5eeSXin Li """ 1283*8c35d5eeSXin Li 1284*8c35d5eeSXin Li line = line.replace(r'\\', 'XX') # after this, \\" does not match to \" 1285*8c35d5eeSXin Li return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1 1286*8c35d5eeSXin Li 1287*8c35d5eeSXin Li 1288*8c35d5eeSXin Lidef CleanseRawStrings(raw_lines): 1289*8c35d5eeSXin Li """Removes C++11 raw strings from lines. 1290*8c35d5eeSXin Li 1291*8c35d5eeSXin Li Before: 1292*8c35d5eeSXin Li static const char kData[] = R"( 1293*8c35d5eeSXin Li multi-line string 1294*8c35d5eeSXin Li )"; 1295*8c35d5eeSXin Li 1296*8c35d5eeSXin Li After: 1297*8c35d5eeSXin Li static const char kData[] = "" 1298*8c35d5eeSXin Li (replaced by blank line) 1299*8c35d5eeSXin Li ""; 1300*8c35d5eeSXin Li 1301*8c35d5eeSXin Li Args: 1302*8c35d5eeSXin Li raw_lines: list of raw lines. 1303*8c35d5eeSXin Li 1304*8c35d5eeSXin Li Returns: 1305*8c35d5eeSXin Li list of lines with C++11 raw strings replaced by empty strings. 1306*8c35d5eeSXin Li """ 1307*8c35d5eeSXin Li 1308*8c35d5eeSXin Li delimiter = None 1309*8c35d5eeSXin Li lines_without_raw_strings = [] 1310*8c35d5eeSXin Li for line in raw_lines: 1311*8c35d5eeSXin Li if delimiter: 1312*8c35d5eeSXin Li # Inside a raw string, look for the end 1313*8c35d5eeSXin Li end = line.find(delimiter) 1314*8c35d5eeSXin Li if end >= 0: 1315*8c35d5eeSXin Li # Found the end of the string, match leading space for this 1316*8c35d5eeSXin Li # line and resume copying the original lines, and also insert 1317*8c35d5eeSXin Li # a "" on the last line. 1318*8c35d5eeSXin Li leading_space = Match(r'^(\s*)\S', line) 1319*8c35d5eeSXin Li line = leading_space.group(1) + '""' + line[end + len(delimiter):] 1320*8c35d5eeSXin Li delimiter = None 1321*8c35d5eeSXin Li else: 1322*8c35d5eeSXin Li # Haven't found the end yet, append a blank line. 1323*8c35d5eeSXin Li line = '""' 1324*8c35d5eeSXin Li 1325*8c35d5eeSXin Li # Look for beginning of a raw string, and replace them with 1326*8c35d5eeSXin Li # empty strings. This is done in a loop to handle multiple raw 1327*8c35d5eeSXin Li # strings on the same line. 1328*8c35d5eeSXin Li while delimiter is None: 1329*8c35d5eeSXin Li # Look for beginning of a raw string. 1330*8c35d5eeSXin Li # See 2.14.15 [lex.string] for syntax. 1331*8c35d5eeSXin Li # 1332*8c35d5eeSXin Li # Once we have matched a raw string, we check the prefix of the 1333*8c35d5eeSXin Li # line to make sure that the line is not part of a single line 1334*8c35d5eeSXin Li # comment. It's done this way because we remove raw strings 1335*8c35d5eeSXin Li # before removing comments as opposed to removing comments 1336*8c35d5eeSXin Li # before removing raw strings. This is because there are some 1337*8c35d5eeSXin Li # cpplint checks that requires the comments to be preserved, but 1338*8c35d5eeSXin Li # we don't want to check comments that are inside raw strings. 1339*8c35d5eeSXin Li matched = Match(r'^(.*?)\b(?:R|u8R|uR|UR|LR)"([^\s\\()]*)\((.*)$', line) 1340*8c35d5eeSXin Li if (matched and 1341*8c35d5eeSXin Li not Match(r'^([^\'"]|\'(\\.|[^\'])*\'|"(\\.|[^"])*")*//', 1342*8c35d5eeSXin Li matched.group(1))): 1343*8c35d5eeSXin Li delimiter = ')' + matched.group(2) + '"' 1344*8c35d5eeSXin Li 1345*8c35d5eeSXin Li end = matched.group(3).find(delimiter) 1346*8c35d5eeSXin Li if end >= 0: 1347*8c35d5eeSXin Li # Raw string ended on same line 1348*8c35d5eeSXin Li line = (matched.group(1) + '""' + 1349*8c35d5eeSXin Li matched.group(3)[end + len(delimiter):]) 1350*8c35d5eeSXin Li delimiter = None 1351*8c35d5eeSXin Li else: 1352*8c35d5eeSXin Li # Start of a multi-line raw string 1353*8c35d5eeSXin Li line = matched.group(1) + '""' 1354*8c35d5eeSXin Li else: 1355*8c35d5eeSXin Li break 1356*8c35d5eeSXin Li 1357*8c35d5eeSXin Li lines_without_raw_strings.append(line) 1358*8c35d5eeSXin Li 1359*8c35d5eeSXin Li # TODO(unknown): if delimiter is not None here, we might want to 1360*8c35d5eeSXin Li # emit a warning for unterminated string. 1361*8c35d5eeSXin Li return lines_without_raw_strings 1362*8c35d5eeSXin Li 1363*8c35d5eeSXin Li 1364*8c35d5eeSXin Lidef FindNextMultiLineCommentStart(lines, lineix): 1365*8c35d5eeSXin Li """Find the beginning marker for a multiline comment.""" 1366*8c35d5eeSXin Li while lineix < len(lines): 1367*8c35d5eeSXin Li if lines[lineix].strip().startswith('/*'): 1368*8c35d5eeSXin Li # Only return this marker if the comment goes beyond this line 1369*8c35d5eeSXin Li if lines[lineix].strip().find('*/', 2) < 0: 1370*8c35d5eeSXin Li return lineix 1371*8c35d5eeSXin Li lineix += 1 1372*8c35d5eeSXin Li return len(lines) 1373*8c35d5eeSXin Li 1374*8c35d5eeSXin Li 1375*8c35d5eeSXin Lidef FindNextMultiLineCommentEnd(lines, lineix): 1376*8c35d5eeSXin Li """We are inside a comment, find the end marker.""" 1377*8c35d5eeSXin Li while lineix < len(lines): 1378*8c35d5eeSXin Li if lines[lineix].strip().endswith('*/'): 1379*8c35d5eeSXin Li return lineix 1380*8c35d5eeSXin Li lineix += 1 1381*8c35d5eeSXin Li return len(lines) 1382*8c35d5eeSXin Li 1383*8c35d5eeSXin Li 1384*8c35d5eeSXin Lidef RemoveMultiLineCommentsFromRange(lines, begin, end): 1385*8c35d5eeSXin Li """Clears a range of lines for multi-line comments.""" 1386*8c35d5eeSXin Li # Having // dummy comments makes the lines non-empty, so we will not get 1387*8c35d5eeSXin Li # unnecessary blank line warnings later in the code. 1388*8c35d5eeSXin Li for i in range(begin, end): 1389*8c35d5eeSXin Li lines[i] = '/**/' 1390*8c35d5eeSXin Li 1391*8c35d5eeSXin Li 1392*8c35d5eeSXin Lidef RemoveMultiLineComments(filename, lines, error): 1393*8c35d5eeSXin Li """Removes multiline (c-style) comments from lines.""" 1394*8c35d5eeSXin Li lineix = 0 1395*8c35d5eeSXin Li while lineix < len(lines): 1396*8c35d5eeSXin Li lineix_begin = FindNextMultiLineCommentStart(lines, lineix) 1397*8c35d5eeSXin Li if lineix_begin >= len(lines): 1398*8c35d5eeSXin Li return 1399*8c35d5eeSXin Li lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin) 1400*8c35d5eeSXin Li if lineix_end >= len(lines): 1401*8c35d5eeSXin Li error(filename, lineix_begin + 1, 'readability/multiline_comment', 5, 1402*8c35d5eeSXin Li 'Could not find end of multi-line comment') 1403*8c35d5eeSXin Li return 1404*8c35d5eeSXin Li RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1) 1405*8c35d5eeSXin Li lineix = lineix_end + 1 1406*8c35d5eeSXin Li 1407*8c35d5eeSXin Li 1408*8c35d5eeSXin Lidef CleanseComments(line): 1409*8c35d5eeSXin Li """Removes //-comments and single-line C-style /* */ comments. 1410*8c35d5eeSXin Li 1411*8c35d5eeSXin Li Args: 1412*8c35d5eeSXin Li line: A line of C++ source. 1413*8c35d5eeSXin Li 1414*8c35d5eeSXin Li Returns: 1415*8c35d5eeSXin Li The line with single-line comments removed. 1416*8c35d5eeSXin Li """ 1417*8c35d5eeSXin Li commentpos = line.find('//') 1418*8c35d5eeSXin Li if commentpos != -1 and not IsCppString(line[:commentpos]): 1419*8c35d5eeSXin Li line = line[:commentpos].rstrip() 1420*8c35d5eeSXin Li # get rid of /* ... */ 1421*8c35d5eeSXin Li return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line) 1422*8c35d5eeSXin Li 1423*8c35d5eeSXin Li 1424*8c35d5eeSXin Liclass CleansedLines(object): 1425*8c35d5eeSXin Li """Holds 4 copies of all lines with different preprocessing applied to them. 1426*8c35d5eeSXin Li 1427*8c35d5eeSXin Li 1) elided member contains lines without strings and comments. 1428*8c35d5eeSXin Li 2) lines member contains lines without comments. 1429*8c35d5eeSXin Li 3) raw_lines member contains all the lines without processing. 1430*8c35d5eeSXin Li 4) lines_without_raw_strings member is same as raw_lines, but with C++11 raw 1431*8c35d5eeSXin Li strings removed. 1432*8c35d5eeSXin Li All these members are of <type 'list'>, and of the same length. 1433*8c35d5eeSXin Li """ 1434*8c35d5eeSXin Li 1435*8c35d5eeSXin Li def __init__(self, lines): 1436*8c35d5eeSXin Li self.elided = [] 1437*8c35d5eeSXin Li self.lines = [] 1438*8c35d5eeSXin Li self.raw_lines = lines 1439*8c35d5eeSXin Li self.num_lines = len(lines) 1440*8c35d5eeSXin Li self.lines_without_raw_strings = CleanseRawStrings(lines) 1441*8c35d5eeSXin Li for linenum in range(len(self.lines_without_raw_strings)): 1442*8c35d5eeSXin Li self.lines.append(CleanseComments( 1443*8c35d5eeSXin Li self.lines_without_raw_strings[linenum])) 1444*8c35d5eeSXin Li elided = self._CollapseStrings(self.lines_without_raw_strings[linenum]) 1445*8c35d5eeSXin Li self.elided.append(CleanseComments(elided)) 1446*8c35d5eeSXin Li 1447*8c35d5eeSXin Li def NumLines(self): 1448*8c35d5eeSXin Li """Returns the number of lines represented.""" 1449*8c35d5eeSXin Li return self.num_lines 1450*8c35d5eeSXin Li 1451*8c35d5eeSXin Li @staticmethod 1452*8c35d5eeSXin Li def _CollapseStrings(elided): 1453*8c35d5eeSXin Li """Collapses strings and chars on a line to simple "" or '' blocks. 1454*8c35d5eeSXin Li 1455*8c35d5eeSXin Li We nix strings first so we're not fooled by text like '"http://"' 1456*8c35d5eeSXin Li 1457*8c35d5eeSXin Li Args: 1458*8c35d5eeSXin Li elided: The line being processed. 1459*8c35d5eeSXin Li 1460*8c35d5eeSXin Li Returns: 1461*8c35d5eeSXin Li The line with collapsed strings. 1462*8c35d5eeSXin Li """ 1463*8c35d5eeSXin Li if _RE_PATTERN_INCLUDE.match(elided): 1464*8c35d5eeSXin Li return elided 1465*8c35d5eeSXin Li 1466*8c35d5eeSXin Li # Remove escaped characters first to make quote/single quote collapsing 1467*8c35d5eeSXin Li # basic. Things that look like escaped characters shouldn't occur 1468*8c35d5eeSXin Li # outside of strings and chars. 1469*8c35d5eeSXin Li elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided) 1470*8c35d5eeSXin Li 1471*8c35d5eeSXin Li # Replace quoted strings and digit separators. Both single quotes 1472*8c35d5eeSXin Li # and double quotes are processed in the same loop, otherwise 1473*8c35d5eeSXin Li # nested quotes wouldn't work. 1474*8c35d5eeSXin Li collapsed = '' 1475*8c35d5eeSXin Li while True: 1476*8c35d5eeSXin Li # Find the first quote character 1477*8c35d5eeSXin Li match = Match(r'^([^\'"]*)([\'"])(.*)$', elided) 1478*8c35d5eeSXin Li if not match: 1479*8c35d5eeSXin Li collapsed += elided 1480*8c35d5eeSXin Li break 1481*8c35d5eeSXin Li head, quote, tail = match.groups() 1482*8c35d5eeSXin Li 1483*8c35d5eeSXin Li if quote == '"': 1484*8c35d5eeSXin Li # Collapse double quoted strings 1485*8c35d5eeSXin Li second_quote = tail.find('"') 1486*8c35d5eeSXin Li if second_quote >= 0: 1487*8c35d5eeSXin Li collapsed += head + '""' 1488*8c35d5eeSXin Li elided = tail[second_quote + 1:] 1489*8c35d5eeSXin Li else: 1490*8c35d5eeSXin Li # Unmatched double quote, don't bother processing the rest 1491*8c35d5eeSXin Li # of the line since this is probably a multiline string. 1492*8c35d5eeSXin Li collapsed += elided 1493*8c35d5eeSXin Li break 1494*8c35d5eeSXin Li else: 1495*8c35d5eeSXin Li # Found single quote, check nearby text to eliminate digit separators. 1496*8c35d5eeSXin Li # 1497*8c35d5eeSXin Li # There is no special handling for floating point here, because 1498*8c35d5eeSXin Li # the integer/fractional/exponent parts would all be parsed 1499*8c35d5eeSXin Li # correctly as long as there are digits on both sides of the 1500*8c35d5eeSXin Li # separator. So we are fine as long as we don't see something 1501*8c35d5eeSXin Li # like "0.'3" (gcc 4.9.0 will not allow this literal). 1502*8c35d5eeSXin Li if Search(r'\b(?:0[bBxX]?|[1-9])[0-9a-fA-F]*$', head): 1503*8c35d5eeSXin Li match_literal = Match(r'^((?:\'?[0-9a-zA-Z_])*)(.*)$', "'" + tail) 1504*8c35d5eeSXin Li collapsed += head + match_literal.group(1).replace("'", '') 1505*8c35d5eeSXin Li elided = match_literal.group(2) 1506*8c35d5eeSXin Li else: 1507*8c35d5eeSXin Li second_quote = tail.find('\'') 1508*8c35d5eeSXin Li if second_quote >= 0: 1509*8c35d5eeSXin Li collapsed += head + "''" 1510*8c35d5eeSXin Li elided = tail[second_quote + 1:] 1511*8c35d5eeSXin Li else: 1512*8c35d5eeSXin Li # Unmatched single quote 1513*8c35d5eeSXin Li collapsed += elided 1514*8c35d5eeSXin Li break 1515*8c35d5eeSXin Li 1516*8c35d5eeSXin Li return collapsed 1517*8c35d5eeSXin Li 1518*8c35d5eeSXin Li 1519*8c35d5eeSXin Lidef FindEndOfExpressionInLine(line, startpos, stack): 1520*8c35d5eeSXin Li """Find the position just after the end of current parenthesized expression. 1521*8c35d5eeSXin Li 1522*8c35d5eeSXin Li Args: 1523*8c35d5eeSXin Li line: a CleansedLines line. 1524*8c35d5eeSXin Li startpos: start searching at this position. 1525*8c35d5eeSXin Li stack: nesting stack at startpos. 1526*8c35d5eeSXin Li 1527*8c35d5eeSXin Li Returns: 1528*8c35d5eeSXin Li On finding matching end: (index just after matching end, None) 1529*8c35d5eeSXin Li On finding an unclosed expression: (-1, None) 1530*8c35d5eeSXin Li Otherwise: (-1, new stack at end of this line) 1531*8c35d5eeSXin Li """ 1532*8c35d5eeSXin Li for i in xrange(startpos, len(line)): 1533*8c35d5eeSXin Li char = line[i] 1534*8c35d5eeSXin Li if char in '([{': 1535*8c35d5eeSXin Li # Found start of parenthesized expression, push to expression stack 1536*8c35d5eeSXin Li stack.append(char) 1537*8c35d5eeSXin Li elif char == '<': 1538*8c35d5eeSXin Li # Found potential start of template argument list 1539*8c35d5eeSXin Li if i > 0 and line[i - 1] == '<': 1540*8c35d5eeSXin Li # Left shift operator 1541*8c35d5eeSXin Li if stack and stack[-1] == '<': 1542*8c35d5eeSXin Li stack.pop() 1543*8c35d5eeSXin Li if not stack: 1544*8c35d5eeSXin Li return (-1, None) 1545*8c35d5eeSXin Li elif i > 0 and Search(r'\boperator\s*$', line[0:i]): 1546*8c35d5eeSXin Li # operator<, don't add to stack 1547*8c35d5eeSXin Li continue 1548*8c35d5eeSXin Li else: 1549*8c35d5eeSXin Li # Tentative start of template argument list 1550*8c35d5eeSXin Li stack.append('<') 1551*8c35d5eeSXin Li elif char in ')]}': 1552*8c35d5eeSXin Li # Found end of parenthesized expression. 1553*8c35d5eeSXin Li # 1554*8c35d5eeSXin Li # If we are currently expecting a matching '>', the pending '<' 1555*8c35d5eeSXin Li # must have been an operator. Remove them from expression stack. 1556*8c35d5eeSXin Li while stack and stack[-1] == '<': 1557*8c35d5eeSXin Li stack.pop() 1558*8c35d5eeSXin Li if not stack: 1559*8c35d5eeSXin Li return (-1, None) 1560*8c35d5eeSXin Li if ((stack[-1] == '(' and char == ')') or 1561*8c35d5eeSXin Li (stack[-1] == '[' and char == ']') or 1562*8c35d5eeSXin Li (stack[-1] == '{' and char == '}')): 1563*8c35d5eeSXin Li stack.pop() 1564*8c35d5eeSXin Li if not stack: 1565*8c35d5eeSXin Li return (i + 1, None) 1566*8c35d5eeSXin Li else: 1567*8c35d5eeSXin Li # Mismatched parentheses 1568*8c35d5eeSXin Li return (-1, None) 1569*8c35d5eeSXin Li elif char == '>': 1570*8c35d5eeSXin Li # Found potential end of template argument list. 1571*8c35d5eeSXin Li 1572*8c35d5eeSXin Li # Ignore "->" and operator functions 1573*8c35d5eeSXin Li if (i > 0 and 1574*8c35d5eeSXin Li (line[i - 1] == '-' or Search(r'\boperator\s*$', line[0:i - 1]))): 1575*8c35d5eeSXin Li continue 1576*8c35d5eeSXin Li 1577*8c35d5eeSXin Li # Pop the stack if there is a matching '<'. Otherwise, ignore 1578*8c35d5eeSXin Li # this '>' since it must be an operator. 1579*8c35d5eeSXin Li if stack: 1580*8c35d5eeSXin Li if stack[-1] == '<': 1581*8c35d5eeSXin Li stack.pop() 1582*8c35d5eeSXin Li if not stack: 1583*8c35d5eeSXin Li return (i + 1, None) 1584*8c35d5eeSXin Li elif char == ';': 1585*8c35d5eeSXin Li # Found something that look like end of statements. If we are currently 1586*8c35d5eeSXin Li # expecting a '>', the matching '<' must have been an operator, since 1587*8c35d5eeSXin Li # template argument list should not contain statements. 1588*8c35d5eeSXin Li while stack and stack[-1] == '<': 1589*8c35d5eeSXin Li stack.pop() 1590*8c35d5eeSXin Li if not stack: 1591*8c35d5eeSXin Li return (-1, None) 1592*8c35d5eeSXin Li 1593*8c35d5eeSXin Li # Did not find end of expression or unbalanced parentheses on this line 1594*8c35d5eeSXin Li return (-1, stack) 1595*8c35d5eeSXin Li 1596*8c35d5eeSXin Li 1597*8c35d5eeSXin Lidef CloseExpression(clean_lines, linenum, pos): 1598*8c35d5eeSXin Li """If input points to ( or { or [ or <, finds the position that closes it. 1599*8c35d5eeSXin Li 1600*8c35d5eeSXin Li If lines[linenum][pos] points to a '(' or '{' or '[' or '<', finds the 1601*8c35d5eeSXin Li linenum/pos that correspond to the closing of the expression. 1602*8c35d5eeSXin Li 1603*8c35d5eeSXin Li TODO(unknown): cpplint spends a fair bit of time matching parentheses. 1604*8c35d5eeSXin Li Ideally we would want to index all opening and closing parentheses once 1605*8c35d5eeSXin Li and have CloseExpression be just a simple lookup, but due to preprocessor 1606*8c35d5eeSXin Li tricks, this is not so easy. 1607*8c35d5eeSXin Li 1608*8c35d5eeSXin Li Args: 1609*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 1610*8c35d5eeSXin Li linenum: The number of the line to check. 1611*8c35d5eeSXin Li pos: A position on the line. 1612*8c35d5eeSXin Li 1613*8c35d5eeSXin Li Returns: 1614*8c35d5eeSXin Li A tuple (line, linenum, pos) pointer *past* the closing brace, or 1615*8c35d5eeSXin Li (line, len(lines), -1) if we never find a close. Note we ignore 1616*8c35d5eeSXin Li strings and comments when matching; and the line we return is the 1617*8c35d5eeSXin Li 'cleansed' line at linenum. 1618*8c35d5eeSXin Li """ 1619*8c35d5eeSXin Li 1620*8c35d5eeSXin Li line = clean_lines.elided[linenum] 1621*8c35d5eeSXin Li if (line[pos] not in '({[<') or Match(r'<[<=]', line[pos:]): 1622*8c35d5eeSXin Li return (line, clean_lines.NumLines(), -1) 1623*8c35d5eeSXin Li 1624*8c35d5eeSXin Li # Check first line 1625*8c35d5eeSXin Li (end_pos, stack) = FindEndOfExpressionInLine(line, pos, []) 1626*8c35d5eeSXin Li if end_pos > -1: 1627*8c35d5eeSXin Li return (line, linenum, end_pos) 1628*8c35d5eeSXin Li 1629*8c35d5eeSXin Li # Continue scanning forward 1630*8c35d5eeSXin Li while stack and linenum < clean_lines.NumLines() - 1: 1631*8c35d5eeSXin Li linenum += 1 1632*8c35d5eeSXin Li line = clean_lines.elided[linenum] 1633*8c35d5eeSXin Li (end_pos, stack) = FindEndOfExpressionInLine(line, 0, stack) 1634*8c35d5eeSXin Li if end_pos > -1: 1635*8c35d5eeSXin Li return (line, linenum, end_pos) 1636*8c35d5eeSXin Li 1637*8c35d5eeSXin Li # Did not find end of expression before end of file, give up 1638*8c35d5eeSXin Li return (line, clean_lines.NumLines(), -1) 1639*8c35d5eeSXin Li 1640*8c35d5eeSXin Li 1641*8c35d5eeSXin Lidef FindStartOfExpressionInLine(line, endpos, stack): 1642*8c35d5eeSXin Li """Find position at the matching start of current expression. 1643*8c35d5eeSXin Li 1644*8c35d5eeSXin Li This is almost the reverse of FindEndOfExpressionInLine, but note 1645*8c35d5eeSXin Li that the input position and returned position differs by 1. 1646*8c35d5eeSXin Li 1647*8c35d5eeSXin Li Args: 1648*8c35d5eeSXin Li line: a CleansedLines line. 1649*8c35d5eeSXin Li endpos: start searching at this position. 1650*8c35d5eeSXin Li stack: nesting stack at endpos. 1651*8c35d5eeSXin Li 1652*8c35d5eeSXin Li Returns: 1653*8c35d5eeSXin Li On finding matching start: (index at matching start, None) 1654*8c35d5eeSXin Li On finding an unclosed expression: (-1, None) 1655*8c35d5eeSXin Li Otherwise: (-1, new stack at beginning of this line) 1656*8c35d5eeSXin Li """ 1657*8c35d5eeSXin Li i = endpos 1658*8c35d5eeSXin Li while i >= 0: 1659*8c35d5eeSXin Li char = line[i] 1660*8c35d5eeSXin Li if char in ')]}': 1661*8c35d5eeSXin Li # Found end of expression, push to expression stack 1662*8c35d5eeSXin Li stack.append(char) 1663*8c35d5eeSXin Li elif char == '>': 1664*8c35d5eeSXin Li # Found potential end of template argument list. 1665*8c35d5eeSXin Li # 1666*8c35d5eeSXin Li # Ignore it if it's a "->" or ">=" or "operator>" 1667*8c35d5eeSXin Li if (i > 0 and 1668*8c35d5eeSXin Li (line[i - 1] == '-' or 1669*8c35d5eeSXin Li Match(r'\s>=\s', line[i - 1:]) or 1670*8c35d5eeSXin Li Search(r'\boperator\s*$', line[0:i]))): 1671*8c35d5eeSXin Li i -= 1 1672*8c35d5eeSXin Li else: 1673*8c35d5eeSXin Li stack.append('>') 1674*8c35d5eeSXin Li elif char == '<': 1675*8c35d5eeSXin Li # Found potential start of template argument list 1676*8c35d5eeSXin Li if i > 0 and line[i - 1] == '<': 1677*8c35d5eeSXin Li # Left shift operator 1678*8c35d5eeSXin Li i -= 1 1679*8c35d5eeSXin Li else: 1680*8c35d5eeSXin Li # If there is a matching '>', we can pop the expression stack. 1681*8c35d5eeSXin Li # Otherwise, ignore this '<' since it must be an operator. 1682*8c35d5eeSXin Li if stack and stack[-1] == '>': 1683*8c35d5eeSXin Li stack.pop() 1684*8c35d5eeSXin Li if not stack: 1685*8c35d5eeSXin Li return (i, None) 1686*8c35d5eeSXin Li elif char in '([{': 1687*8c35d5eeSXin Li # Found start of expression. 1688*8c35d5eeSXin Li # 1689*8c35d5eeSXin Li # If there are any unmatched '>' on the stack, they must be 1690*8c35d5eeSXin Li # operators. Remove those. 1691*8c35d5eeSXin Li while stack and stack[-1] == '>': 1692*8c35d5eeSXin Li stack.pop() 1693*8c35d5eeSXin Li if not stack: 1694*8c35d5eeSXin Li return (-1, None) 1695*8c35d5eeSXin Li if ((char == '(' and stack[-1] == ')') or 1696*8c35d5eeSXin Li (char == '[' and stack[-1] == ']') or 1697*8c35d5eeSXin Li (char == '{' and stack[-1] == '}')): 1698*8c35d5eeSXin Li stack.pop() 1699*8c35d5eeSXin Li if not stack: 1700*8c35d5eeSXin Li return (i, None) 1701*8c35d5eeSXin Li else: 1702*8c35d5eeSXin Li # Mismatched parentheses 1703*8c35d5eeSXin Li return (-1, None) 1704*8c35d5eeSXin Li elif char == ';': 1705*8c35d5eeSXin Li # Found something that look like end of statements. If we are currently 1706*8c35d5eeSXin Li # expecting a '<', the matching '>' must have been an operator, since 1707*8c35d5eeSXin Li # template argument list should not contain statements. 1708*8c35d5eeSXin Li while stack and stack[-1] == '>': 1709*8c35d5eeSXin Li stack.pop() 1710*8c35d5eeSXin Li if not stack: 1711*8c35d5eeSXin Li return (-1, None) 1712*8c35d5eeSXin Li 1713*8c35d5eeSXin Li i -= 1 1714*8c35d5eeSXin Li 1715*8c35d5eeSXin Li return (-1, stack) 1716*8c35d5eeSXin Li 1717*8c35d5eeSXin Li 1718*8c35d5eeSXin Lidef ReverseCloseExpression(clean_lines, linenum, pos): 1719*8c35d5eeSXin Li """If input points to ) or } or ] or >, finds the position that opens it. 1720*8c35d5eeSXin Li 1721*8c35d5eeSXin Li If lines[linenum][pos] points to a ')' or '}' or ']' or '>', finds the 1722*8c35d5eeSXin Li linenum/pos that correspond to the opening of the expression. 1723*8c35d5eeSXin Li 1724*8c35d5eeSXin Li Args: 1725*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 1726*8c35d5eeSXin Li linenum: The number of the line to check. 1727*8c35d5eeSXin Li pos: A position on the line. 1728*8c35d5eeSXin Li 1729*8c35d5eeSXin Li Returns: 1730*8c35d5eeSXin Li A tuple (line, linenum, pos) pointer *at* the opening brace, or 1731*8c35d5eeSXin Li (line, 0, -1) if we never find the matching opening brace. Note 1732*8c35d5eeSXin Li we ignore strings and comments when matching; and the line we 1733*8c35d5eeSXin Li return is the 'cleansed' line at linenum. 1734*8c35d5eeSXin Li """ 1735*8c35d5eeSXin Li line = clean_lines.elided[linenum] 1736*8c35d5eeSXin Li if line[pos] not in ')}]>': 1737*8c35d5eeSXin Li return (line, 0, -1) 1738*8c35d5eeSXin Li 1739*8c35d5eeSXin Li # Check last line 1740*8c35d5eeSXin Li (start_pos, stack) = FindStartOfExpressionInLine(line, pos, []) 1741*8c35d5eeSXin Li if start_pos > -1: 1742*8c35d5eeSXin Li return (line, linenum, start_pos) 1743*8c35d5eeSXin Li 1744*8c35d5eeSXin Li # Continue scanning backward 1745*8c35d5eeSXin Li while stack and linenum > 0: 1746*8c35d5eeSXin Li linenum -= 1 1747*8c35d5eeSXin Li line = clean_lines.elided[linenum] 1748*8c35d5eeSXin Li (start_pos, stack) = FindStartOfExpressionInLine(line, len(line) - 1, stack) 1749*8c35d5eeSXin Li if start_pos > -1: 1750*8c35d5eeSXin Li return (line, linenum, start_pos) 1751*8c35d5eeSXin Li 1752*8c35d5eeSXin Li # Did not find start of expression before beginning of file, give up 1753*8c35d5eeSXin Li return (line, 0, -1) 1754*8c35d5eeSXin Li 1755*8c35d5eeSXin Li 1756*8c35d5eeSXin Lidef CheckForCopyright(filename, lines, error): 1757*8c35d5eeSXin Li """Logs an error if no Copyright message appears at the top of the file.""" 1758*8c35d5eeSXin Li 1759*8c35d5eeSXin Li # We'll say it should occur by line 10. Don't forget there's a 1760*8c35d5eeSXin Li # dummy line at the front. 1761*8c35d5eeSXin Li for line in xrange(1, min(len(lines), 11)): 1762*8c35d5eeSXin Li if re.search(r'Copyright', lines[line], re.I): break 1763*8c35d5eeSXin Li else: # means no copyright line was found 1764*8c35d5eeSXin Li error(filename, 0, 'legal/copyright', 5, 1765*8c35d5eeSXin Li 'No copyright message found. ' 1766*8c35d5eeSXin Li 'You should have a line: "Copyright [year] <Copyright Owner>"') 1767*8c35d5eeSXin Li 1768*8c35d5eeSXin Li 1769*8c35d5eeSXin Lidef GetIndentLevel(line): 1770*8c35d5eeSXin Li """Return the number of leading spaces in line. 1771*8c35d5eeSXin Li 1772*8c35d5eeSXin Li Args: 1773*8c35d5eeSXin Li line: A string to check. 1774*8c35d5eeSXin Li 1775*8c35d5eeSXin Li Returns: 1776*8c35d5eeSXin Li An integer count of leading spaces, possibly zero. 1777*8c35d5eeSXin Li """ 1778*8c35d5eeSXin Li indent = Match(r'^( *)\S', line) 1779*8c35d5eeSXin Li if indent: 1780*8c35d5eeSXin Li return len(indent.group(1)) 1781*8c35d5eeSXin Li else: 1782*8c35d5eeSXin Li return 0 1783*8c35d5eeSXin Li 1784*8c35d5eeSXin Lidef PathSplitToList(path): 1785*8c35d5eeSXin Li """Returns the path split into a list by the separator. 1786*8c35d5eeSXin Li 1787*8c35d5eeSXin Li Args: 1788*8c35d5eeSXin Li path: An absolute or relative path (e.g. '/a/b/c/' or '../a') 1789*8c35d5eeSXin Li 1790*8c35d5eeSXin Li Returns: 1791*8c35d5eeSXin Li A list of path components (e.g. ['a', 'b', 'c]). 1792*8c35d5eeSXin Li """ 1793*8c35d5eeSXin Li lst = [] 1794*8c35d5eeSXin Li while True: 1795*8c35d5eeSXin Li (head, tail) = os.path.split(path) 1796*8c35d5eeSXin Li if head == path: # absolute paths end 1797*8c35d5eeSXin Li lst.append(head) 1798*8c35d5eeSXin Li break 1799*8c35d5eeSXin Li if tail == path: # relative paths end 1800*8c35d5eeSXin Li lst.append(tail) 1801*8c35d5eeSXin Li break 1802*8c35d5eeSXin Li 1803*8c35d5eeSXin Li path = head 1804*8c35d5eeSXin Li lst.append(tail) 1805*8c35d5eeSXin Li 1806*8c35d5eeSXin Li lst.reverse() 1807*8c35d5eeSXin Li return lst 1808*8c35d5eeSXin Li 1809*8c35d5eeSXin Lidef GetHeaderGuardCPPVariable(filename): 1810*8c35d5eeSXin Li """Returns the CPP variable that should be used as a header guard. 1811*8c35d5eeSXin Li 1812*8c35d5eeSXin Li Args: 1813*8c35d5eeSXin Li filename: The name of a C++ header file. 1814*8c35d5eeSXin Li 1815*8c35d5eeSXin Li Returns: 1816*8c35d5eeSXin Li The CPP variable that should be used as a header guard in the 1817*8c35d5eeSXin Li named file. 1818*8c35d5eeSXin Li 1819*8c35d5eeSXin Li """ 1820*8c35d5eeSXin Li 1821*8c35d5eeSXin Li # Restores original filename in case that cpplint is invoked from Emacs's 1822*8c35d5eeSXin Li # flymake. 1823*8c35d5eeSXin Li filename = re.sub(r'_flymake\.h$', '.h', filename) 1824*8c35d5eeSXin Li filename = re.sub(r'/\.flymake/([^/]*)$', r'/\1', filename) 1825*8c35d5eeSXin Li # Replace 'c++' with 'cpp'. 1826*8c35d5eeSXin Li filename = filename.replace('C++', 'cpp').replace('c++', 'cpp') 1827*8c35d5eeSXin Li 1828*8c35d5eeSXin Li fileinfo = FileInfo(filename) 1829*8c35d5eeSXin Li file_path_from_root = fileinfo.RepositoryName() 1830*8c35d5eeSXin Li 1831*8c35d5eeSXin Li def FixupPathFromRoot(): 1832*8c35d5eeSXin Li if _root_debug: 1833*8c35d5eeSXin Li sys.stderr.write("\n_root fixup, _root = '%s', repository name = '%s'\n" 1834*8c35d5eeSXin Li %(_root, fileinfo.RepositoryName())) 1835*8c35d5eeSXin Li 1836*8c35d5eeSXin Li # Process the file path with the --root flag if it was set. 1837*8c35d5eeSXin Li if not _root: 1838*8c35d5eeSXin Li if _root_debug: 1839*8c35d5eeSXin Li sys.stderr.write("_root unspecified\n") 1840*8c35d5eeSXin Li return file_path_from_root 1841*8c35d5eeSXin Li 1842*8c35d5eeSXin Li def StripListPrefix(lst, prefix): 1843*8c35d5eeSXin Li # f(['x', 'y'], ['w, z']) -> None (not a valid prefix) 1844*8c35d5eeSXin Li if lst[:len(prefix)] != prefix: 1845*8c35d5eeSXin Li return None 1846*8c35d5eeSXin Li # f(['a, 'b', 'c', 'd'], ['a', 'b']) -> ['c', 'd'] 1847*8c35d5eeSXin Li return lst[(len(prefix)):] 1848*8c35d5eeSXin Li 1849*8c35d5eeSXin Li # root behavior: 1850*8c35d5eeSXin Li # --root=subdir , lstrips subdir from the header guard 1851*8c35d5eeSXin Li maybe_path = StripListPrefix(PathSplitToList(file_path_from_root), 1852*8c35d5eeSXin Li PathSplitToList(_root)) 1853*8c35d5eeSXin Li 1854*8c35d5eeSXin Li if _root_debug: 1855*8c35d5eeSXin Li sys.stderr.write(("_root lstrip (maybe_path=%s, file_path_from_root=%s," + 1856*8c35d5eeSXin Li " _root=%s)\n") %(maybe_path, file_path_from_root, _root)) 1857*8c35d5eeSXin Li 1858*8c35d5eeSXin Li if maybe_path: 1859*8c35d5eeSXin Li return os.path.join(*maybe_path) 1860*8c35d5eeSXin Li 1861*8c35d5eeSXin Li # --root=.. , will prepend the outer directory to the header guard 1862*8c35d5eeSXin Li full_path = fileinfo.FullName() 1863*8c35d5eeSXin Li root_abspath = os.path.abspath(_root) 1864*8c35d5eeSXin Li 1865*8c35d5eeSXin Li maybe_path = StripListPrefix(PathSplitToList(full_path), 1866*8c35d5eeSXin Li PathSplitToList(root_abspath)) 1867*8c35d5eeSXin Li 1868*8c35d5eeSXin Li if _root_debug: 1869*8c35d5eeSXin Li sys.stderr.write(("_root prepend (maybe_path=%s, full_path=%s, " + 1870*8c35d5eeSXin Li "root_abspath=%s)\n") %(maybe_path, full_path, root_abspath)) 1871*8c35d5eeSXin Li 1872*8c35d5eeSXin Li if maybe_path: 1873*8c35d5eeSXin Li return os.path.join(*maybe_path) 1874*8c35d5eeSXin Li 1875*8c35d5eeSXin Li if _root_debug: 1876*8c35d5eeSXin Li sys.stderr.write("_root ignore, returning %s\n" %(file_path_from_root)) 1877*8c35d5eeSXin Li 1878*8c35d5eeSXin Li # --root=FAKE_DIR is ignored 1879*8c35d5eeSXin Li return file_path_from_root 1880*8c35d5eeSXin Li 1881*8c35d5eeSXin Li file_path_from_root = FixupPathFromRoot() 1882*8c35d5eeSXin Li return re.sub(r'[^a-zA-Z0-9]', '_', file_path_from_root).upper() + '_' 1883*8c35d5eeSXin Li 1884*8c35d5eeSXin Li 1885*8c35d5eeSXin Lidef CheckForHeaderGuard(filename, clean_lines, error): 1886*8c35d5eeSXin Li """Checks that the file contains a header guard. 1887*8c35d5eeSXin Li 1888*8c35d5eeSXin Li Logs an error if no #ifndef header guard is present. For other 1889*8c35d5eeSXin Li headers, checks that the full pathname is used. 1890*8c35d5eeSXin Li 1891*8c35d5eeSXin Li Args: 1892*8c35d5eeSXin Li filename: The name of the C++ header file. 1893*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 1894*8c35d5eeSXin Li error: The function to call with any errors found. 1895*8c35d5eeSXin Li """ 1896*8c35d5eeSXin Li 1897*8c35d5eeSXin Li # Don't check for header guards if there are error suppression 1898*8c35d5eeSXin Li # comments somewhere in this file. 1899*8c35d5eeSXin Li # 1900*8c35d5eeSXin Li # Because this is silencing a warning for a nonexistent line, we 1901*8c35d5eeSXin Li # only support the very specific NOLINT(build/header_guard) syntax, 1902*8c35d5eeSXin Li # and not the general NOLINT or NOLINT(*) syntax. 1903*8c35d5eeSXin Li raw_lines = clean_lines.lines_without_raw_strings 1904*8c35d5eeSXin Li for i in raw_lines: 1905*8c35d5eeSXin Li if Search(r'//\s*NOLINT\(build/header_guard\)', i): 1906*8c35d5eeSXin Li return 1907*8c35d5eeSXin Li 1908*8c35d5eeSXin Li cppvar = GetHeaderGuardCPPVariable(filename) 1909*8c35d5eeSXin Li 1910*8c35d5eeSXin Li ifndef = '' 1911*8c35d5eeSXin Li ifndef_linenum = 0 1912*8c35d5eeSXin Li define = '' 1913*8c35d5eeSXin Li endif = '' 1914*8c35d5eeSXin Li endif_linenum = 0 1915*8c35d5eeSXin Li for linenum, line in enumerate(raw_lines): 1916*8c35d5eeSXin Li linesplit = line.split() 1917*8c35d5eeSXin Li if len(linesplit) >= 2: 1918*8c35d5eeSXin Li # find the first occurrence of #ifndef and #define, save arg 1919*8c35d5eeSXin Li if not ifndef and linesplit[0] == '#ifndef': 1920*8c35d5eeSXin Li # set ifndef to the header guard presented on the #ifndef line. 1921*8c35d5eeSXin Li ifndef = linesplit[1] 1922*8c35d5eeSXin Li ifndef_linenum = linenum 1923*8c35d5eeSXin Li if not define and linesplit[0] == '#define': 1924*8c35d5eeSXin Li define = linesplit[1] 1925*8c35d5eeSXin Li # find the last occurrence of #endif, save entire line 1926*8c35d5eeSXin Li if line.startswith('#endif'): 1927*8c35d5eeSXin Li endif = line 1928*8c35d5eeSXin Li endif_linenum = linenum 1929*8c35d5eeSXin Li 1930*8c35d5eeSXin Li if not ifndef or not define or ifndef != define: 1931*8c35d5eeSXin Li error(filename, 0, 'build/header_guard', 5, 1932*8c35d5eeSXin Li 'No #ifndef header guard found, suggested CPP variable is: %s' % 1933*8c35d5eeSXin Li cppvar) 1934*8c35d5eeSXin Li return 1935*8c35d5eeSXin Li 1936*8c35d5eeSXin Li # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__ 1937*8c35d5eeSXin Li # for backward compatibility. 1938*8c35d5eeSXin Li if ifndef != cppvar: 1939*8c35d5eeSXin Li error_level = 0 1940*8c35d5eeSXin Li if ifndef != cppvar + '_': 1941*8c35d5eeSXin Li error_level = 5 1942*8c35d5eeSXin Li 1943*8c35d5eeSXin Li ParseNolintSuppressions(filename, raw_lines[ifndef_linenum], ifndef_linenum, 1944*8c35d5eeSXin Li error) 1945*8c35d5eeSXin Li error(filename, ifndef_linenum, 'build/header_guard', error_level, 1946*8c35d5eeSXin Li '#ifndef header guard has wrong style, please use: %s' % cppvar) 1947*8c35d5eeSXin Li 1948*8c35d5eeSXin Li # Check for "//" comments on endif line. 1949*8c35d5eeSXin Li ParseNolintSuppressions(filename, raw_lines[endif_linenum], endif_linenum, 1950*8c35d5eeSXin Li error) 1951*8c35d5eeSXin Li match = Match(r'#endif\s*//\s*' + cppvar + r'(_)?\b', endif) 1952*8c35d5eeSXin Li if match: 1953*8c35d5eeSXin Li if match.group(1) == '_': 1954*8c35d5eeSXin Li # Issue low severity warning for deprecated double trailing underscore 1955*8c35d5eeSXin Li error(filename, endif_linenum, 'build/header_guard', 0, 1956*8c35d5eeSXin Li '#endif line should be "#endif // %s"' % cppvar) 1957*8c35d5eeSXin Li return 1958*8c35d5eeSXin Li 1959*8c35d5eeSXin Li # Didn't find the corresponding "//" comment. If this file does not 1960*8c35d5eeSXin Li # contain any "//" comments at all, it could be that the compiler 1961*8c35d5eeSXin Li # only wants "/**/" comments, look for those instead. 1962*8c35d5eeSXin Li no_single_line_comments = True 1963*8c35d5eeSXin Li for i in xrange(1, len(raw_lines) - 1): 1964*8c35d5eeSXin Li line = raw_lines[i] 1965*8c35d5eeSXin Li if Match(r'^(?:(?:\'(?:\.|[^\'])*\')|(?:"(?:\.|[^"])*")|[^\'"])*//', line): 1966*8c35d5eeSXin Li no_single_line_comments = False 1967*8c35d5eeSXin Li break 1968*8c35d5eeSXin Li 1969*8c35d5eeSXin Li if no_single_line_comments: 1970*8c35d5eeSXin Li match = Match(r'#endif\s*/\*\s*' + cppvar + r'(_)?\s*\*/', endif) 1971*8c35d5eeSXin Li if match: 1972*8c35d5eeSXin Li if match.group(1) == '_': 1973*8c35d5eeSXin Li # Low severity warning for double trailing underscore 1974*8c35d5eeSXin Li error(filename, endif_linenum, 'build/header_guard', 0, 1975*8c35d5eeSXin Li '#endif line should be "#endif /* %s */"' % cppvar) 1976*8c35d5eeSXin Li return 1977*8c35d5eeSXin Li 1978*8c35d5eeSXin Li # Didn't find anything 1979*8c35d5eeSXin Li error(filename, endif_linenum, 'build/header_guard', 5, 1980*8c35d5eeSXin Li '#endif line should be "#endif // %s"' % cppvar) 1981*8c35d5eeSXin Li 1982*8c35d5eeSXin Li 1983*8c35d5eeSXin Lidef CheckHeaderFileIncluded(filename, include_state, error): 1984*8c35d5eeSXin Li """Logs an error if a .cc file does not include its header.""" 1985*8c35d5eeSXin Li 1986*8c35d5eeSXin Li # Do not check test files 1987*8c35d5eeSXin Li fileinfo = FileInfo(filename) 1988*8c35d5eeSXin Li if Search(_TEST_FILE_SUFFIX, fileinfo.BaseName()): 1989*8c35d5eeSXin Li return 1990*8c35d5eeSXin Li 1991*8c35d5eeSXin Li headerfile = filename[0:len(filename) - len(fileinfo.Extension())] + '.h' 1992*8c35d5eeSXin Li if not os.path.exists(headerfile): 1993*8c35d5eeSXin Li return 1994*8c35d5eeSXin Li headername = FileInfo(headerfile).RepositoryName() 1995*8c35d5eeSXin Li first_include = 0 1996*8c35d5eeSXin Li for section_list in include_state.include_list: 1997*8c35d5eeSXin Li for f in section_list: 1998*8c35d5eeSXin Li if headername in f[0] or f[0] in headername: 1999*8c35d5eeSXin Li return 2000*8c35d5eeSXin Li if not first_include: 2001*8c35d5eeSXin Li first_include = f[1] 2002*8c35d5eeSXin Li 2003*8c35d5eeSXin Li error(filename, first_include, 'build/include', 5, 2004*8c35d5eeSXin Li '%s should include its header file %s' % (fileinfo.RepositoryName(), 2005*8c35d5eeSXin Li headername)) 2006*8c35d5eeSXin Li 2007*8c35d5eeSXin Li 2008*8c35d5eeSXin Lidef CheckForBadCharacters(filename, lines, error): 2009*8c35d5eeSXin Li """Logs an error for each line containing bad characters. 2010*8c35d5eeSXin Li 2011*8c35d5eeSXin Li Two kinds of bad characters: 2012*8c35d5eeSXin Li 2013*8c35d5eeSXin Li 1. Unicode replacement characters: These indicate that either the file 2014*8c35d5eeSXin Li contained invalid UTF-8 (likely) or Unicode replacement characters (which 2015*8c35d5eeSXin Li it shouldn't). Note that it's possible for this to throw off line 2016*8c35d5eeSXin Li numbering if the invalid UTF-8 occurred adjacent to a newline. 2017*8c35d5eeSXin Li 2018*8c35d5eeSXin Li 2. NUL bytes. These are problematic for some tools. 2019*8c35d5eeSXin Li 2020*8c35d5eeSXin Li Args: 2021*8c35d5eeSXin Li filename: The name of the current file. 2022*8c35d5eeSXin Li lines: An array of strings, each representing a line of the file. 2023*8c35d5eeSXin Li error: The function to call with any errors found. 2024*8c35d5eeSXin Li """ 2025*8c35d5eeSXin Li for linenum, line in enumerate(lines): 2026*8c35d5eeSXin Li if u'\ufffd' in line: 2027*8c35d5eeSXin Li error(filename, linenum, 'readability/utf8', 5, 2028*8c35d5eeSXin Li 'Line contains invalid UTF-8 (or Unicode replacement character).') 2029*8c35d5eeSXin Li if '\0' in line: 2030*8c35d5eeSXin Li error(filename, linenum, 'readability/nul', 5, 'Line contains NUL byte.') 2031*8c35d5eeSXin Li 2032*8c35d5eeSXin Li 2033*8c35d5eeSXin Lidef CheckForNewlineAtEOF(filename, lines, error): 2034*8c35d5eeSXin Li """Logs an error if there is no newline char at the end of the file. 2035*8c35d5eeSXin Li 2036*8c35d5eeSXin Li Args: 2037*8c35d5eeSXin Li filename: The name of the current file. 2038*8c35d5eeSXin Li lines: An array of strings, each representing a line of the file. 2039*8c35d5eeSXin Li error: The function to call with any errors found. 2040*8c35d5eeSXin Li """ 2041*8c35d5eeSXin Li 2042*8c35d5eeSXin Li # The array lines() was created by adding two newlines to the 2043*8c35d5eeSXin Li # original file (go figure), then splitting on \n. 2044*8c35d5eeSXin Li # To verify that the file ends in \n, we just have to make sure the 2045*8c35d5eeSXin Li # last-but-two element of lines() exists and is empty. 2046*8c35d5eeSXin Li if len(lines) < 3 or lines[-2]: 2047*8c35d5eeSXin Li error(filename, len(lines) - 2, 'whitespace/ending_newline', 5, 2048*8c35d5eeSXin Li 'Could not find a newline character at the end of the file.') 2049*8c35d5eeSXin Li 2050*8c35d5eeSXin Li 2051*8c35d5eeSXin Lidef CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error): 2052*8c35d5eeSXin Li """Logs an error if we see /* ... */ or "..." that extend past one line. 2053*8c35d5eeSXin Li 2054*8c35d5eeSXin Li /* ... */ comments are legit inside macros, for one line. 2055*8c35d5eeSXin Li Otherwise, we prefer // comments, so it's ok to warn about the 2056*8c35d5eeSXin Li other. Likewise, it's ok for strings to extend across multiple 2057*8c35d5eeSXin Li lines, as long as a line continuation character (backslash) 2058*8c35d5eeSXin Li terminates each line. Although not currently prohibited by the C++ 2059*8c35d5eeSXin Li style guide, it's ugly and unnecessary. We don't do well with either 2060*8c35d5eeSXin Li in this lint program, so we warn about both. 2061*8c35d5eeSXin Li 2062*8c35d5eeSXin Li Args: 2063*8c35d5eeSXin Li filename: The name of the current file. 2064*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 2065*8c35d5eeSXin Li linenum: The number of the line to check. 2066*8c35d5eeSXin Li error: The function to call with any errors found. 2067*8c35d5eeSXin Li """ 2068*8c35d5eeSXin Li line = clean_lines.elided[linenum] 2069*8c35d5eeSXin Li 2070*8c35d5eeSXin Li # Remove all \\ (escaped backslashes) from the line. They are OK, and the 2071*8c35d5eeSXin Li # second (escaped) slash may trigger later \" detection erroneously. 2072*8c35d5eeSXin Li line = line.replace('\\\\', '') 2073*8c35d5eeSXin Li 2074*8c35d5eeSXin Li if line.count('/*') > line.count('*/'): 2075*8c35d5eeSXin Li error(filename, linenum, 'readability/multiline_comment', 5, 2076*8c35d5eeSXin Li 'Complex multi-line /*...*/-style comment found. ' 2077*8c35d5eeSXin Li 'Lint may give bogus warnings. ' 2078*8c35d5eeSXin Li 'Consider replacing these with //-style comments, ' 2079*8c35d5eeSXin Li 'with #if 0...#endif, ' 2080*8c35d5eeSXin Li 'or with more clearly structured multi-line comments.') 2081*8c35d5eeSXin Li 2082*8c35d5eeSXin Li if (line.count('"') - line.count('\\"')) % 2: 2083*8c35d5eeSXin Li error(filename, linenum, 'readability/multiline_string', 5, 2084*8c35d5eeSXin Li 'Multi-line string ("...") found. This lint script doesn\'t ' 2085*8c35d5eeSXin Li 'do well with such strings, and may give bogus warnings. ' 2086*8c35d5eeSXin Li 'Use C++11 raw strings or concatenation instead.') 2087*8c35d5eeSXin Li 2088*8c35d5eeSXin Li 2089*8c35d5eeSXin Li# (non-threadsafe name, thread-safe alternative, validation pattern) 2090*8c35d5eeSXin Li# 2091*8c35d5eeSXin Li# The validation pattern is used to eliminate false positives such as: 2092*8c35d5eeSXin Li# _rand(); // false positive due to substring match. 2093*8c35d5eeSXin Li# ->rand(); // some member function rand(). 2094*8c35d5eeSXin Li# ACMRandom rand(seed); // some variable named rand. 2095*8c35d5eeSXin Li# ISAACRandom rand(); // another variable named rand. 2096*8c35d5eeSXin Li# 2097*8c35d5eeSXin Li# Basically we require the return value of these functions to be used 2098*8c35d5eeSXin Li# in some expression context on the same line by matching on some 2099*8c35d5eeSXin Li# operator before the function name. This eliminates constructors and 2100*8c35d5eeSXin Li# member function calls. 2101*8c35d5eeSXin Li_UNSAFE_FUNC_PREFIX = r'(?:[-+*/=%^&|(<]\s*|>\s+)' 2102*8c35d5eeSXin Li_THREADING_LIST = ( 2103*8c35d5eeSXin Li ('asctime(', 'asctime_r(', _UNSAFE_FUNC_PREFIX + r'asctime\([^)]+\)'), 2104*8c35d5eeSXin Li ('ctime(', 'ctime_r(', _UNSAFE_FUNC_PREFIX + r'ctime\([^)]+\)'), 2105*8c35d5eeSXin Li ('getgrgid(', 'getgrgid_r(', _UNSAFE_FUNC_PREFIX + r'getgrgid\([^)]+\)'), 2106*8c35d5eeSXin Li ('getgrnam(', 'getgrnam_r(', _UNSAFE_FUNC_PREFIX + r'getgrnam\([^)]+\)'), 2107*8c35d5eeSXin Li ('getlogin(', 'getlogin_r(', _UNSAFE_FUNC_PREFIX + r'getlogin\(\)'), 2108*8c35d5eeSXin Li ('getpwnam(', 'getpwnam_r(', _UNSAFE_FUNC_PREFIX + r'getpwnam\([^)]+\)'), 2109*8c35d5eeSXin Li ('getpwuid(', 'getpwuid_r(', _UNSAFE_FUNC_PREFIX + r'getpwuid\([^)]+\)'), 2110*8c35d5eeSXin Li ('gmtime(', 'gmtime_r(', _UNSAFE_FUNC_PREFIX + r'gmtime\([^)]+\)'), 2111*8c35d5eeSXin Li ('localtime(', 'localtime_r(', _UNSAFE_FUNC_PREFIX + r'localtime\([^)]+\)'), 2112*8c35d5eeSXin Li ('rand(', 'rand_r(', _UNSAFE_FUNC_PREFIX + r'rand\(\)'), 2113*8c35d5eeSXin Li ('strtok(', 'strtok_r(', 2114*8c35d5eeSXin Li _UNSAFE_FUNC_PREFIX + r'strtok\([^)]+\)'), 2115*8c35d5eeSXin Li ('ttyname(', 'ttyname_r(', _UNSAFE_FUNC_PREFIX + r'ttyname\([^)]+\)'), 2116*8c35d5eeSXin Li ) 2117*8c35d5eeSXin Li 2118*8c35d5eeSXin Li 2119*8c35d5eeSXin Lidef CheckPosixThreading(filename, clean_lines, linenum, error): 2120*8c35d5eeSXin Li """Checks for calls to thread-unsafe functions. 2121*8c35d5eeSXin Li 2122*8c35d5eeSXin Li Much code has been originally written without consideration of 2123*8c35d5eeSXin Li multi-threading. Also, engineers are relying on their old experience; 2124*8c35d5eeSXin Li they have learned posix before threading extensions were added. These 2125*8c35d5eeSXin Li tests guide the engineers to use thread-safe functions (when using 2126*8c35d5eeSXin Li posix directly). 2127*8c35d5eeSXin Li 2128*8c35d5eeSXin Li Args: 2129*8c35d5eeSXin Li filename: The name of the current file. 2130*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 2131*8c35d5eeSXin Li linenum: The number of the line to check. 2132*8c35d5eeSXin Li error: The function to call with any errors found. 2133*8c35d5eeSXin Li """ 2134*8c35d5eeSXin Li line = clean_lines.elided[linenum] 2135*8c35d5eeSXin Li for single_thread_func, multithread_safe_func, pattern in _THREADING_LIST: 2136*8c35d5eeSXin Li # Additional pattern matching check to confirm that this is the 2137*8c35d5eeSXin Li # function we are looking for 2138*8c35d5eeSXin Li if Search(pattern, line): 2139*8c35d5eeSXin Li error(filename, linenum, 'runtime/threadsafe_fn', 2, 2140*8c35d5eeSXin Li 'Consider using ' + multithread_safe_func + 2141*8c35d5eeSXin Li '...) instead of ' + single_thread_func + 2142*8c35d5eeSXin Li '...) for improved thread safety.') 2143*8c35d5eeSXin Li 2144*8c35d5eeSXin Li 2145*8c35d5eeSXin Lidef CheckVlogArguments(filename, clean_lines, linenum, error): 2146*8c35d5eeSXin Li """Checks that VLOG() is only used for defining a logging level. 2147*8c35d5eeSXin Li 2148*8c35d5eeSXin Li For example, VLOG(2) is correct. VLOG(INFO), VLOG(WARNING), VLOG(ERROR), and 2149*8c35d5eeSXin Li VLOG(FATAL) are not. 2150*8c35d5eeSXin Li 2151*8c35d5eeSXin Li Args: 2152*8c35d5eeSXin Li filename: The name of the current file. 2153*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 2154*8c35d5eeSXin Li linenum: The number of the line to check. 2155*8c35d5eeSXin Li error: The function to call with any errors found. 2156*8c35d5eeSXin Li """ 2157*8c35d5eeSXin Li line = clean_lines.elided[linenum] 2158*8c35d5eeSXin Li if Search(r'\bVLOG\((INFO|ERROR|WARNING|DFATAL|FATAL)\)', line): 2159*8c35d5eeSXin Li error(filename, linenum, 'runtime/vlog', 5, 2160*8c35d5eeSXin Li 'VLOG() should be used with numeric verbosity level. ' 2161*8c35d5eeSXin Li 'Use LOG() if you want symbolic severity levels.') 2162*8c35d5eeSXin Li 2163*8c35d5eeSXin Li# Matches invalid increment: *count++, which moves pointer instead of 2164*8c35d5eeSXin Li# incrementing a value. 2165*8c35d5eeSXin Li_RE_PATTERN_INVALID_INCREMENT = re.compile( 2166*8c35d5eeSXin Li r'^\s*\*\w+(\+\+|--);') 2167*8c35d5eeSXin Li 2168*8c35d5eeSXin Li 2169*8c35d5eeSXin Lidef CheckInvalidIncrement(filename, clean_lines, linenum, error): 2170*8c35d5eeSXin Li """Checks for invalid increment *count++. 2171*8c35d5eeSXin Li 2172*8c35d5eeSXin Li For example following function: 2173*8c35d5eeSXin Li void increment_counter(int* count) { 2174*8c35d5eeSXin Li *count++; 2175*8c35d5eeSXin Li } 2176*8c35d5eeSXin Li is invalid, because it effectively does count++, moving pointer, and should 2177*8c35d5eeSXin Li be replaced with ++*count, (*count)++ or *count += 1. 2178*8c35d5eeSXin Li 2179*8c35d5eeSXin Li Args: 2180*8c35d5eeSXin Li filename: The name of the current file. 2181*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 2182*8c35d5eeSXin Li linenum: The number of the line to check. 2183*8c35d5eeSXin Li error: The function to call with any errors found. 2184*8c35d5eeSXin Li """ 2185*8c35d5eeSXin Li line = clean_lines.elided[linenum] 2186*8c35d5eeSXin Li if _RE_PATTERN_INVALID_INCREMENT.match(line): 2187*8c35d5eeSXin Li error(filename, linenum, 'runtime/invalid_increment', 5, 2188*8c35d5eeSXin Li 'Changing pointer instead of value (or unused value of operator*).') 2189*8c35d5eeSXin Li 2190*8c35d5eeSXin Li 2191*8c35d5eeSXin Lidef IsMacroDefinition(clean_lines, linenum): 2192*8c35d5eeSXin Li if Search(r'^#define', clean_lines[linenum]): 2193*8c35d5eeSXin Li return True 2194*8c35d5eeSXin Li 2195*8c35d5eeSXin Li if linenum > 0 and Search(r'\\$', clean_lines[linenum - 1]): 2196*8c35d5eeSXin Li return True 2197*8c35d5eeSXin Li 2198*8c35d5eeSXin Li return False 2199*8c35d5eeSXin Li 2200*8c35d5eeSXin Li 2201*8c35d5eeSXin Lidef IsForwardClassDeclaration(clean_lines, linenum): 2202*8c35d5eeSXin Li return Match(r'^\s*(\btemplate\b)*.*class\s+\w+;\s*$', clean_lines[linenum]) 2203*8c35d5eeSXin Li 2204*8c35d5eeSXin Li 2205*8c35d5eeSXin Liclass _BlockInfo(object): 2206*8c35d5eeSXin Li """Stores information about a generic block of code.""" 2207*8c35d5eeSXin Li 2208*8c35d5eeSXin Li def __init__(self, linenum, seen_open_brace): 2209*8c35d5eeSXin Li self.starting_linenum = linenum 2210*8c35d5eeSXin Li self.seen_open_brace = seen_open_brace 2211*8c35d5eeSXin Li self.open_parentheses = 0 2212*8c35d5eeSXin Li self.inline_asm = _NO_ASM 2213*8c35d5eeSXin Li self.check_namespace_indentation = False 2214*8c35d5eeSXin Li 2215*8c35d5eeSXin Li def CheckBegin(self, filename, clean_lines, linenum, error): 2216*8c35d5eeSXin Li """Run checks that applies to text up to the opening brace. 2217*8c35d5eeSXin Li 2218*8c35d5eeSXin Li This is mostly for checking the text after the class identifier 2219*8c35d5eeSXin Li and the "{", usually where the base class is specified. For other 2220*8c35d5eeSXin Li blocks, there isn't much to check, so we always pass. 2221*8c35d5eeSXin Li 2222*8c35d5eeSXin Li Args: 2223*8c35d5eeSXin Li filename: The name of the current file. 2224*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 2225*8c35d5eeSXin Li linenum: The number of the line to check. 2226*8c35d5eeSXin Li error: The function to call with any errors found. 2227*8c35d5eeSXin Li """ 2228*8c35d5eeSXin Li pass 2229*8c35d5eeSXin Li 2230*8c35d5eeSXin Li def CheckEnd(self, filename, clean_lines, linenum, error): 2231*8c35d5eeSXin Li """Run checks that applies to text after the closing brace. 2232*8c35d5eeSXin Li 2233*8c35d5eeSXin Li This is mostly used for checking end of namespace comments. 2234*8c35d5eeSXin Li 2235*8c35d5eeSXin Li Args: 2236*8c35d5eeSXin Li filename: The name of the current file. 2237*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 2238*8c35d5eeSXin Li linenum: The number of the line to check. 2239*8c35d5eeSXin Li error: The function to call with any errors found. 2240*8c35d5eeSXin Li """ 2241*8c35d5eeSXin Li pass 2242*8c35d5eeSXin Li 2243*8c35d5eeSXin Li def IsBlockInfo(self): 2244*8c35d5eeSXin Li """Returns true if this block is a _BlockInfo. 2245*8c35d5eeSXin Li 2246*8c35d5eeSXin Li This is convenient for verifying that an object is an instance of 2247*8c35d5eeSXin Li a _BlockInfo, but not an instance of any of the derived classes. 2248*8c35d5eeSXin Li 2249*8c35d5eeSXin Li Returns: 2250*8c35d5eeSXin Li True for this class, False for derived classes. 2251*8c35d5eeSXin Li """ 2252*8c35d5eeSXin Li return self.__class__ == _BlockInfo 2253*8c35d5eeSXin Li 2254*8c35d5eeSXin Li 2255*8c35d5eeSXin Liclass _ExternCInfo(_BlockInfo): 2256*8c35d5eeSXin Li """Stores information about an 'extern "C"' block.""" 2257*8c35d5eeSXin Li 2258*8c35d5eeSXin Li def __init__(self, linenum): 2259*8c35d5eeSXin Li _BlockInfo.__init__(self, linenum, True) 2260*8c35d5eeSXin Li 2261*8c35d5eeSXin Li 2262*8c35d5eeSXin Liclass _ClassInfo(_BlockInfo): 2263*8c35d5eeSXin Li """Stores information about a class.""" 2264*8c35d5eeSXin Li 2265*8c35d5eeSXin Li def __init__(self, name, class_or_struct, clean_lines, linenum): 2266*8c35d5eeSXin Li _BlockInfo.__init__(self, linenum, False) 2267*8c35d5eeSXin Li self.name = name 2268*8c35d5eeSXin Li self.is_derived = False 2269*8c35d5eeSXin Li self.check_namespace_indentation = True 2270*8c35d5eeSXin Li if class_or_struct == 'struct': 2271*8c35d5eeSXin Li self.access = 'public' 2272*8c35d5eeSXin Li self.is_struct = True 2273*8c35d5eeSXin Li else: 2274*8c35d5eeSXin Li self.access = 'private' 2275*8c35d5eeSXin Li self.is_struct = False 2276*8c35d5eeSXin Li 2277*8c35d5eeSXin Li # Remember initial indentation level for this class. Using raw_lines here 2278*8c35d5eeSXin Li # instead of elided to account for leading comments. 2279*8c35d5eeSXin Li self.class_indent = GetIndentLevel(clean_lines.raw_lines[linenum]) 2280*8c35d5eeSXin Li 2281*8c35d5eeSXin Li # Try to find the end of the class. This will be confused by things like: 2282*8c35d5eeSXin Li # class A { 2283*8c35d5eeSXin Li # } *x = { ... 2284*8c35d5eeSXin Li # 2285*8c35d5eeSXin Li # But it's still good enough for CheckSectionSpacing. 2286*8c35d5eeSXin Li self.last_line = 0 2287*8c35d5eeSXin Li depth = 0 2288*8c35d5eeSXin Li for i in range(linenum, clean_lines.NumLines()): 2289*8c35d5eeSXin Li line = clean_lines.elided[i] 2290*8c35d5eeSXin Li depth += line.count('{') - line.count('}') 2291*8c35d5eeSXin Li if not depth: 2292*8c35d5eeSXin Li self.last_line = i 2293*8c35d5eeSXin Li break 2294*8c35d5eeSXin Li 2295*8c35d5eeSXin Li def CheckBegin(self, filename, clean_lines, linenum, error): 2296*8c35d5eeSXin Li # Look for a bare ':' 2297*8c35d5eeSXin Li if Search('(^|[^:]):($|[^:])', clean_lines.elided[linenum]): 2298*8c35d5eeSXin Li self.is_derived = True 2299*8c35d5eeSXin Li 2300*8c35d5eeSXin Li def CheckEnd(self, filename, clean_lines, linenum, error): 2301*8c35d5eeSXin Li # If there is a DISALLOW macro, it should appear near the end of 2302*8c35d5eeSXin Li # the class. 2303*8c35d5eeSXin Li seen_last_thing_in_class = False 2304*8c35d5eeSXin Li for i in xrange(linenum - 1, self.starting_linenum, -1): 2305*8c35d5eeSXin Li match = Search( 2306*8c35d5eeSXin Li r'\b(DISALLOW_COPY_AND_ASSIGN|DISALLOW_IMPLICIT_CONSTRUCTORS)\(' + 2307*8c35d5eeSXin Li self.name + r'\)', 2308*8c35d5eeSXin Li clean_lines.elided[i]) 2309*8c35d5eeSXin Li if match: 2310*8c35d5eeSXin Li if seen_last_thing_in_class: 2311*8c35d5eeSXin Li error(filename, i, 'readability/constructors', 3, 2312*8c35d5eeSXin Li match.group(1) + ' should be the last thing in the class') 2313*8c35d5eeSXin Li break 2314*8c35d5eeSXin Li 2315*8c35d5eeSXin Li if not Match(r'^\s*$', clean_lines.elided[i]): 2316*8c35d5eeSXin Li seen_last_thing_in_class = True 2317*8c35d5eeSXin Li 2318*8c35d5eeSXin Li # Check that closing brace is aligned with beginning of the class. 2319*8c35d5eeSXin Li # Only do this if the closing brace is indented by only whitespaces. 2320*8c35d5eeSXin Li # This means we will not check single-line class definitions. 2321*8c35d5eeSXin Li indent = Match(r'^( *)\}', clean_lines.elided[linenum]) 2322*8c35d5eeSXin Li if indent and len(indent.group(1)) != self.class_indent: 2323*8c35d5eeSXin Li if self.is_struct: 2324*8c35d5eeSXin Li parent = 'struct ' + self.name 2325*8c35d5eeSXin Li else: 2326*8c35d5eeSXin Li parent = 'class ' + self.name 2327*8c35d5eeSXin Li error(filename, linenum, 'whitespace/indent', 3, 2328*8c35d5eeSXin Li 'Closing brace should be aligned with beginning of %s' % parent) 2329*8c35d5eeSXin Li 2330*8c35d5eeSXin Li 2331*8c35d5eeSXin Liclass _NamespaceInfo(_BlockInfo): 2332*8c35d5eeSXin Li """Stores information about a namespace.""" 2333*8c35d5eeSXin Li 2334*8c35d5eeSXin Li def __init__(self, name, linenum): 2335*8c35d5eeSXin Li _BlockInfo.__init__(self, linenum, False) 2336*8c35d5eeSXin Li self.name = name or '' 2337*8c35d5eeSXin Li self.check_namespace_indentation = True 2338*8c35d5eeSXin Li 2339*8c35d5eeSXin Li def CheckEnd(self, filename, clean_lines, linenum, error): 2340*8c35d5eeSXin Li """Check end of namespace comments.""" 2341*8c35d5eeSXin Li line = clean_lines.raw_lines[linenum] 2342*8c35d5eeSXin Li 2343*8c35d5eeSXin Li # Check how many lines is enclosed in this namespace. Don't issue 2344*8c35d5eeSXin Li # warning for missing namespace comments if there aren't enough 2345*8c35d5eeSXin Li # lines. However, do apply checks if there is already an end of 2346*8c35d5eeSXin Li # namespace comment and it's incorrect. 2347*8c35d5eeSXin Li # 2348*8c35d5eeSXin Li # TODO(unknown): We always want to check end of namespace comments 2349*8c35d5eeSXin Li # if a namespace is large, but sometimes we also want to apply the 2350*8c35d5eeSXin Li # check if a short namespace contained nontrivial things (something 2351*8c35d5eeSXin Li # other than forward declarations). There is currently no logic on 2352*8c35d5eeSXin Li # deciding what these nontrivial things are, so this check is 2353*8c35d5eeSXin Li # triggered by namespace size only, which works most of the time. 2354*8c35d5eeSXin Li if (linenum - self.starting_linenum < 10 2355*8c35d5eeSXin Li and not Match(r'^\s*};*\s*(//|/\*).*\bnamespace\b', line)): 2356*8c35d5eeSXin Li return 2357*8c35d5eeSXin Li 2358*8c35d5eeSXin Li # Look for matching comment at end of namespace. 2359*8c35d5eeSXin Li # 2360*8c35d5eeSXin Li # Note that we accept C style "/* */" comments for terminating 2361*8c35d5eeSXin Li # namespaces, so that code that terminate namespaces inside 2362*8c35d5eeSXin Li # preprocessor macros can be cpplint clean. 2363*8c35d5eeSXin Li # 2364*8c35d5eeSXin Li # We also accept stuff like "// end of namespace <name>." with the 2365*8c35d5eeSXin Li # period at the end. 2366*8c35d5eeSXin Li # 2367*8c35d5eeSXin Li # Besides these, we don't accept anything else, otherwise we might 2368*8c35d5eeSXin Li # get false negatives when existing comment is a substring of the 2369*8c35d5eeSXin Li # expected namespace. 2370*8c35d5eeSXin Li if self.name: 2371*8c35d5eeSXin Li # Named namespace 2372*8c35d5eeSXin Li if not Match((r'^\s*};*\s*(//|/\*).*\bnamespace\s+' + 2373*8c35d5eeSXin Li re.escape(self.name) + r'[\*/\.\\\s]*$'), 2374*8c35d5eeSXin Li line): 2375*8c35d5eeSXin Li error(filename, linenum, 'readability/namespace', 5, 2376*8c35d5eeSXin Li 'Namespace should be terminated with "// namespace %s"' % 2377*8c35d5eeSXin Li self.name) 2378*8c35d5eeSXin Li else: 2379*8c35d5eeSXin Li # Anonymous namespace 2380*8c35d5eeSXin Li if not Match(r'^\s*};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line): 2381*8c35d5eeSXin Li # If "// namespace anonymous" or "// anonymous namespace (more text)", 2382*8c35d5eeSXin Li # mention "// anonymous namespace" as an acceptable form 2383*8c35d5eeSXin Li if Match(r'^\s*}.*\b(namespace anonymous|anonymous namespace)\b', line): 2384*8c35d5eeSXin Li error(filename, linenum, 'readability/namespace', 5, 2385*8c35d5eeSXin Li 'Anonymous namespace should be terminated with "// namespace"' 2386*8c35d5eeSXin Li ' or "// anonymous namespace"') 2387*8c35d5eeSXin Li else: 2388*8c35d5eeSXin Li error(filename, linenum, 'readability/namespace', 5, 2389*8c35d5eeSXin Li 'Anonymous namespace should be terminated with "// namespace"') 2390*8c35d5eeSXin Li 2391*8c35d5eeSXin Li 2392*8c35d5eeSXin Liclass _PreprocessorInfo(object): 2393*8c35d5eeSXin Li """Stores checkpoints of nesting stacks when #if/#else is seen.""" 2394*8c35d5eeSXin Li 2395*8c35d5eeSXin Li def __init__(self, stack_before_if): 2396*8c35d5eeSXin Li # The entire nesting stack before #if 2397*8c35d5eeSXin Li self.stack_before_if = stack_before_if 2398*8c35d5eeSXin Li 2399*8c35d5eeSXin Li # The entire nesting stack up to #else 2400*8c35d5eeSXin Li self.stack_before_else = [] 2401*8c35d5eeSXin Li 2402*8c35d5eeSXin Li # Whether we have already seen #else or #elif 2403*8c35d5eeSXin Li self.seen_else = False 2404*8c35d5eeSXin Li 2405*8c35d5eeSXin Li 2406*8c35d5eeSXin Liclass NestingState(object): 2407*8c35d5eeSXin Li """Holds states related to parsing braces.""" 2408*8c35d5eeSXin Li 2409*8c35d5eeSXin Li def __init__(self): 2410*8c35d5eeSXin Li # Stack for tracking all braces. An object is pushed whenever we 2411*8c35d5eeSXin Li # see a "{", and popped when we see a "}". Only 3 types of 2412*8c35d5eeSXin Li # objects are possible: 2413*8c35d5eeSXin Li # - _ClassInfo: a class or struct. 2414*8c35d5eeSXin Li # - _NamespaceInfo: a namespace. 2415*8c35d5eeSXin Li # - _BlockInfo: some other type of block. 2416*8c35d5eeSXin Li self.stack = [] 2417*8c35d5eeSXin Li 2418*8c35d5eeSXin Li # Top of the previous stack before each Update(). 2419*8c35d5eeSXin Li # 2420*8c35d5eeSXin Li # Because the nesting_stack is updated at the end of each line, we 2421*8c35d5eeSXin Li # had to do some convoluted checks to find out what is the current 2422*8c35d5eeSXin Li # scope at the beginning of the line. This check is simplified by 2423*8c35d5eeSXin Li # saving the previous top of nesting stack. 2424*8c35d5eeSXin Li # 2425*8c35d5eeSXin Li # We could save the full stack, but we only need the top. Copying 2426*8c35d5eeSXin Li # the full nesting stack would slow down cpplint by ~10%. 2427*8c35d5eeSXin Li self.previous_stack_top = [] 2428*8c35d5eeSXin Li 2429*8c35d5eeSXin Li # Stack of _PreprocessorInfo objects. 2430*8c35d5eeSXin Li self.pp_stack = [] 2431*8c35d5eeSXin Li 2432*8c35d5eeSXin Li def SeenOpenBrace(self): 2433*8c35d5eeSXin Li """Check if we have seen the opening brace for the innermost block. 2434*8c35d5eeSXin Li 2435*8c35d5eeSXin Li Returns: 2436*8c35d5eeSXin Li True if we have seen the opening brace, False if the innermost 2437*8c35d5eeSXin Li block is still expecting an opening brace. 2438*8c35d5eeSXin Li """ 2439*8c35d5eeSXin Li return (not self.stack) or self.stack[-1].seen_open_brace 2440*8c35d5eeSXin Li 2441*8c35d5eeSXin Li def InNamespaceBody(self): 2442*8c35d5eeSXin Li """Check if we are currently one level inside a namespace body. 2443*8c35d5eeSXin Li 2444*8c35d5eeSXin Li Returns: 2445*8c35d5eeSXin Li True if top of the stack is a namespace block, False otherwise. 2446*8c35d5eeSXin Li """ 2447*8c35d5eeSXin Li return self.stack and isinstance(self.stack[-1], _NamespaceInfo) 2448*8c35d5eeSXin Li 2449*8c35d5eeSXin Li def InExternC(self): 2450*8c35d5eeSXin Li """Check if we are currently one level inside an 'extern "C"' block. 2451*8c35d5eeSXin Li 2452*8c35d5eeSXin Li Returns: 2453*8c35d5eeSXin Li True if top of the stack is an extern block, False otherwise. 2454*8c35d5eeSXin Li """ 2455*8c35d5eeSXin Li return self.stack and isinstance(self.stack[-1], _ExternCInfo) 2456*8c35d5eeSXin Li 2457*8c35d5eeSXin Li def InClassDeclaration(self): 2458*8c35d5eeSXin Li """Check if we are currently one level inside a class or struct declaration. 2459*8c35d5eeSXin Li 2460*8c35d5eeSXin Li Returns: 2461*8c35d5eeSXin Li True if top of the stack is a class/struct, False otherwise. 2462*8c35d5eeSXin Li """ 2463*8c35d5eeSXin Li return self.stack and isinstance(self.stack[-1], _ClassInfo) 2464*8c35d5eeSXin Li 2465*8c35d5eeSXin Li def InAsmBlock(self): 2466*8c35d5eeSXin Li """Check if we are currently one level inside an inline ASM block. 2467*8c35d5eeSXin Li 2468*8c35d5eeSXin Li Returns: 2469*8c35d5eeSXin Li True if the top of the stack is a block containing inline ASM. 2470*8c35d5eeSXin Li """ 2471*8c35d5eeSXin Li return self.stack and self.stack[-1].inline_asm != _NO_ASM 2472*8c35d5eeSXin Li 2473*8c35d5eeSXin Li def InTemplateArgumentList(self, clean_lines, linenum, pos): 2474*8c35d5eeSXin Li """Check if current position is inside template argument list. 2475*8c35d5eeSXin Li 2476*8c35d5eeSXin Li Args: 2477*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 2478*8c35d5eeSXin Li linenum: The number of the line to check. 2479*8c35d5eeSXin Li pos: position just after the suspected template argument. 2480*8c35d5eeSXin Li Returns: 2481*8c35d5eeSXin Li True if (linenum, pos) is inside template arguments. 2482*8c35d5eeSXin Li """ 2483*8c35d5eeSXin Li while linenum < clean_lines.NumLines(): 2484*8c35d5eeSXin Li # Find the earliest character that might indicate a template argument 2485*8c35d5eeSXin Li line = clean_lines.elided[linenum] 2486*8c35d5eeSXin Li match = Match(r'^[^{};=\[\]\.<>]*(.)', line[pos:]) 2487*8c35d5eeSXin Li if not match: 2488*8c35d5eeSXin Li linenum += 1 2489*8c35d5eeSXin Li pos = 0 2490*8c35d5eeSXin Li continue 2491*8c35d5eeSXin Li token = match.group(1) 2492*8c35d5eeSXin Li pos += len(match.group(0)) 2493*8c35d5eeSXin Li 2494*8c35d5eeSXin Li # These things do not look like template argument list: 2495*8c35d5eeSXin Li # class Suspect { 2496*8c35d5eeSXin Li # class Suspect x; } 2497*8c35d5eeSXin Li if token in ('{', '}', ';'): return False 2498*8c35d5eeSXin Li 2499*8c35d5eeSXin Li # These things look like template argument list: 2500*8c35d5eeSXin Li # template <class Suspect> 2501*8c35d5eeSXin Li # template <class Suspect = default_value> 2502*8c35d5eeSXin Li # template <class Suspect[]> 2503*8c35d5eeSXin Li # template <class Suspect...> 2504*8c35d5eeSXin Li if token in ('>', '=', '[', ']', '.'): return True 2505*8c35d5eeSXin Li 2506*8c35d5eeSXin Li # Check if token is an unmatched '<'. 2507*8c35d5eeSXin Li # If not, move on to the next character. 2508*8c35d5eeSXin Li if token != '<': 2509*8c35d5eeSXin Li pos += 1 2510*8c35d5eeSXin Li if pos >= len(line): 2511*8c35d5eeSXin Li linenum += 1 2512*8c35d5eeSXin Li pos = 0 2513*8c35d5eeSXin Li continue 2514*8c35d5eeSXin Li 2515*8c35d5eeSXin Li # We can't be sure if we just find a single '<', and need to 2516*8c35d5eeSXin Li # find the matching '>'. 2517*8c35d5eeSXin Li (_, end_line, end_pos) = CloseExpression(clean_lines, linenum, pos - 1) 2518*8c35d5eeSXin Li if end_pos < 0: 2519*8c35d5eeSXin Li # Not sure if template argument list or syntax error in file 2520*8c35d5eeSXin Li return False 2521*8c35d5eeSXin Li linenum = end_line 2522*8c35d5eeSXin Li pos = end_pos 2523*8c35d5eeSXin Li return False 2524*8c35d5eeSXin Li 2525*8c35d5eeSXin Li def UpdatePreprocessor(self, line): 2526*8c35d5eeSXin Li """Update preprocessor stack. 2527*8c35d5eeSXin Li 2528*8c35d5eeSXin Li We need to handle preprocessors due to classes like this: 2529*8c35d5eeSXin Li #ifdef SWIG 2530*8c35d5eeSXin Li struct ResultDetailsPageElementExtensionPoint { 2531*8c35d5eeSXin Li #else 2532*8c35d5eeSXin Li struct ResultDetailsPageElementExtensionPoint : public Extension { 2533*8c35d5eeSXin Li #endif 2534*8c35d5eeSXin Li 2535*8c35d5eeSXin Li We make the following assumptions (good enough for most files): 2536*8c35d5eeSXin Li - Preprocessor condition evaluates to true from #if up to first 2537*8c35d5eeSXin Li #else/#elif/#endif. 2538*8c35d5eeSXin Li 2539*8c35d5eeSXin Li - Preprocessor condition evaluates to false from #else/#elif up 2540*8c35d5eeSXin Li to #endif. We still perform lint checks on these lines, but 2541*8c35d5eeSXin Li these do not affect nesting stack. 2542*8c35d5eeSXin Li 2543*8c35d5eeSXin Li Args: 2544*8c35d5eeSXin Li line: current line to check. 2545*8c35d5eeSXin Li """ 2546*8c35d5eeSXin Li if Match(r'^\s*#\s*(if|ifdef|ifndef)\b', line): 2547*8c35d5eeSXin Li # Beginning of #if block, save the nesting stack here. The saved 2548*8c35d5eeSXin Li # stack will allow us to restore the parsing state in the #else case. 2549*8c35d5eeSXin Li self.pp_stack.append(_PreprocessorInfo(copy.deepcopy(self.stack))) 2550*8c35d5eeSXin Li elif Match(r'^\s*#\s*(else|elif)\b', line): 2551*8c35d5eeSXin Li # Beginning of #else block 2552*8c35d5eeSXin Li if self.pp_stack: 2553*8c35d5eeSXin Li if not self.pp_stack[-1].seen_else: 2554*8c35d5eeSXin Li # This is the first #else or #elif block. Remember the 2555*8c35d5eeSXin Li # whole nesting stack up to this point. This is what we 2556*8c35d5eeSXin Li # keep after the #endif. 2557*8c35d5eeSXin Li self.pp_stack[-1].seen_else = True 2558*8c35d5eeSXin Li self.pp_stack[-1].stack_before_else = copy.deepcopy(self.stack) 2559*8c35d5eeSXin Li 2560*8c35d5eeSXin Li # Restore the stack to how it was before the #if 2561*8c35d5eeSXin Li self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if) 2562*8c35d5eeSXin Li else: 2563*8c35d5eeSXin Li # TODO(unknown): unexpected #else, issue warning? 2564*8c35d5eeSXin Li pass 2565*8c35d5eeSXin Li elif Match(r'^\s*#\s*endif\b', line): 2566*8c35d5eeSXin Li # End of #if or #else blocks. 2567*8c35d5eeSXin Li if self.pp_stack: 2568*8c35d5eeSXin Li # If we saw an #else, we will need to restore the nesting 2569*8c35d5eeSXin Li # stack to its former state before the #else, otherwise we 2570*8c35d5eeSXin Li # will just continue from where we left off. 2571*8c35d5eeSXin Li if self.pp_stack[-1].seen_else: 2572*8c35d5eeSXin Li # Here we can just use a shallow copy since we are the last 2573*8c35d5eeSXin Li # reference to it. 2574*8c35d5eeSXin Li self.stack = self.pp_stack[-1].stack_before_else 2575*8c35d5eeSXin Li # Drop the corresponding #if 2576*8c35d5eeSXin Li self.pp_stack.pop() 2577*8c35d5eeSXin Li else: 2578*8c35d5eeSXin Li # TODO(unknown): unexpected #endif, issue warning? 2579*8c35d5eeSXin Li pass 2580*8c35d5eeSXin Li 2581*8c35d5eeSXin Li # TODO(unknown): Update() is too long, but we will refactor later. 2582*8c35d5eeSXin Li def Update(self, filename, clean_lines, linenum, error): 2583*8c35d5eeSXin Li """Update nesting state with current line. 2584*8c35d5eeSXin Li 2585*8c35d5eeSXin Li Args: 2586*8c35d5eeSXin Li filename: The name of the current file. 2587*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 2588*8c35d5eeSXin Li linenum: The number of the line to check. 2589*8c35d5eeSXin Li error: The function to call with any errors found. 2590*8c35d5eeSXin Li """ 2591*8c35d5eeSXin Li line = clean_lines.elided[linenum] 2592*8c35d5eeSXin Li 2593*8c35d5eeSXin Li # Remember top of the previous nesting stack. 2594*8c35d5eeSXin Li # 2595*8c35d5eeSXin Li # The stack is always pushed/popped and not modified in place, so 2596*8c35d5eeSXin Li # we can just do a shallow copy instead of copy.deepcopy. Using 2597*8c35d5eeSXin Li # deepcopy would slow down cpplint by ~28%. 2598*8c35d5eeSXin Li if self.stack: 2599*8c35d5eeSXin Li self.previous_stack_top = self.stack[-1] 2600*8c35d5eeSXin Li else: 2601*8c35d5eeSXin Li self.previous_stack_top = None 2602*8c35d5eeSXin Li 2603*8c35d5eeSXin Li # Update pp_stack 2604*8c35d5eeSXin Li self.UpdatePreprocessor(line) 2605*8c35d5eeSXin Li 2606*8c35d5eeSXin Li # Count parentheses. This is to avoid adding struct arguments to 2607*8c35d5eeSXin Li # the nesting stack. 2608*8c35d5eeSXin Li if self.stack: 2609*8c35d5eeSXin Li inner_block = self.stack[-1] 2610*8c35d5eeSXin Li depth_change = line.count('(') - line.count(')') 2611*8c35d5eeSXin Li inner_block.open_parentheses += depth_change 2612*8c35d5eeSXin Li 2613*8c35d5eeSXin Li # Also check if we are starting or ending an inline assembly block. 2614*8c35d5eeSXin Li if inner_block.inline_asm in (_NO_ASM, _END_ASM): 2615*8c35d5eeSXin Li if (depth_change != 0 and 2616*8c35d5eeSXin Li inner_block.open_parentheses == 1 and 2617*8c35d5eeSXin Li _MATCH_ASM.match(line)): 2618*8c35d5eeSXin Li # Enter assembly block 2619*8c35d5eeSXin Li inner_block.inline_asm = _INSIDE_ASM 2620*8c35d5eeSXin Li else: 2621*8c35d5eeSXin Li # Not entering assembly block. If previous line was _END_ASM, 2622*8c35d5eeSXin Li # we will now shift to _NO_ASM state. 2623*8c35d5eeSXin Li inner_block.inline_asm = _NO_ASM 2624*8c35d5eeSXin Li elif (inner_block.inline_asm == _INSIDE_ASM and 2625*8c35d5eeSXin Li inner_block.open_parentheses == 0): 2626*8c35d5eeSXin Li # Exit assembly block 2627*8c35d5eeSXin Li inner_block.inline_asm = _END_ASM 2628*8c35d5eeSXin Li 2629*8c35d5eeSXin Li # Consume namespace declaration at the beginning of the line. Do 2630*8c35d5eeSXin Li # this in a loop so that we catch same line declarations like this: 2631*8c35d5eeSXin Li # namespace proto2 { namespace bridge { class MessageSet; } } 2632*8c35d5eeSXin Li while True: 2633*8c35d5eeSXin Li # Match start of namespace. The "\b\s*" below catches namespace 2634*8c35d5eeSXin Li # declarations even if it weren't followed by a whitespace, this 2635*8c35d5eeSXin Li # is so that we don't confuse our namespace checker. The 2636*8c35d5eeSXin Li # missing spaces will be flagged by CheckSpacing. 2637*8c35d5eeSXin Li namespace_decl_match = Match(r'^\s*namespace\b\s*([:\w]+)?(.*)$', line) 2638*8c35d5eeSXin Li if not namespace_decl_match: 2639*8c35d5eeSXin Li break 2640*8c35d5eeSXin Li 2641*8c35d5eeSXin Li new_namespace = _NamespaceInfo(namespace_decl_match.group(1), linenum) 2642*8c35d5eeSXin Li self.stack.append(new_namespace) 2643*8c35d5eeSXin Li 2644*8c35d5eeSXin Li line = namespace_decl_match.group(2) 2645*8c35d5eeSXin Li if line.find('{') != -1: 2646*8c35d5eeSXin Li new_namespace.seen_open_brace = True 2647*8c35d5eeSXin Li line = line[line.find('{') + 1:] 2648*8c35d5eeSXin Li 2649*8c35d5eeSXin Li # Look for a class declaration in whatever is left of the line 2650*8c35d5eeSXin Li # after parsing namespaces. The regexp accounts for decorated classes 2651*8c35d5eeSXin Li # such as in: 2652*8c35d5eeSXin Li # class LOCKABLE API Object { 2653*8c35d5eeSXin Li # }; 2654*8c35d5eeSXin Li class_decl_match = Match( 2655*8c35d5eeSXin Li r'^(\s*(?:template\s*<[\w\s<>,:]*>\s*)?' 2656*8c35d5eeSXin Li r'(class|struct)\s+(?:[A-Z_]+\s+)*(\w+(?:::\w+)*))' 2657*8c35d5eeSXin Li r'(.*)$', line) 2658*8c35d5eeSXin Li if (class_decl_match and 2659*8c35d5eeSXin Li (not self.stack or self.stack[-1].open_parentheses == 0)): 2660*8c35d5eeSXin Li # We do not want to accept classes that are actually template arguments: 2661*8c35d5eeSXin Li # template <class Ignore1, 2662*8c35d5eeSXin Li # class Ignore2 = Default<Args>, 2663*8c35d5eeSXin Li # template <Args> class Ignore3> 2664*8c35d5eeSXin Li # void Function() {}; 2665*8c35d5eeSXin Li # 2666*8c35d5eeSXin Li # To avoid template argument cases, we scan forward and look for 2667*8c35d5eeSXin Li # an unmatched '>'. If we see one, assume we are inside a 2668*8c35d5eeSXin Li # template argument list. 2669*8c35d5eeSXin Li end_declaration = len(class_decl_match.group(1)) 2670*8c35d5eeSXin Li if not self.InTemplateArgumentList(clean_lines, linenum, end_declaration): 2671*8c35d5eeSXin Li self.stack.append(_ClassInfo( 2672*8c35d5eeSXin Li class_decl_match.group(3), class_decl_match.group(2), 2673*8c35d5eeSXin Li clean_lines, linenum)) 2674*8c35d5eeSXin Li line = class_decl_match.group(4) 2675*8c35d5eeSXin Li 2676*8c35d5eeSXin Li # If we have not yet seen the opening brace for the innermost block, 2677*8c35d5eeSXin Li # run checks here. 2678*8c35d5eeSXin Li if not self.SeenOpenBrace(): 2679*8c35d5eeSXin Li self.stack[-1].CheckBegin(filename, clean_lines, linenum, error) 2680*8c35d5eeSXin Li 2681*8c35d5eeSXin Li # Update access control if we are inside a class/struct 2682*8c35d5eeSXin Li if self.stack and isinstance(self.stack[-1], _ClassInfo): 2683*8c35d5eeSXin Li classinfo = self.stack[-1] 2684*8c35d5eeSXin Li access_match = Match( 2685*8c35d5eeSXin Li r'^(.*)\b(public|private|protected|signals)(\s+(?:slots\s*)?)?' 2686*8c35d5eeSXin Li r':(?:[^:]|$)', 2687*8c35d5eeSXin Li line) 2688*8c35d5eeSXin Li if access_match: 2689*8c35d5eeSXin Li classinfo.access = access_match.group(2) 2690*8c35d5eeSXin Li 2691*8c35d5eeSXin Li # Check that access keywords are indented +1 space. Skip this 2692*8c35d5eeSXin Li # check if the keywords are not preceded by whitespaces. 2693*8c35d5eeSXin Li indent = access_match.group(1) 2694*8c35d5eeSXin Li if (len(indent) != classinfo.class_indent + 1 and 2695*8c35d5eeSXin Li Match(r'^\s*$', indent)): 2696*8c35d5eeSXin Li if classinfo.is_struct: 2697*8c35d5eeSXin Li parent = 'struct ' + classinfo.name 2698*8c35d5eeSXin Li else: 2699*8c35d5eeSXin Li parent = 'class ' + classinfo.name 2700*8c35d5eeSXin Li slots = '' 2701*8c35d5eeSXin Li if access_match.group(3): 2702*8c35d5eeSXin Li slots = access_match.group(3) 2703*8c35d5eeSXin Li error(filename, linenum, 'whitespace/indent', 3, 2704*8c35d5eeSXin Li '%s%s: should be indented +1 space inside %s' % ( 2705*8c35d5eeSXin Li access_match.group(2), slots, parent)) 2706*8c35d5eeSXin Li 2707*8c35d5eeSXin Li # Consume braces or semicolons from what's left of the line 2708*8c35d5eeSXin Li while True: 2709*8c35d5eeSXin Li # Match first brace, semicolon, or closed parenthesis. 2710*8c35d5eeSXin Li matched = Match(r'^[^{;)}]*([{;)}])(.*)$', line) 2711*8c35d5eeSXin Li if not matched: 2712*8c35d5eeSXin Li break 2713*8c35d5eeSXin Li 2714*8c35d5eeSXin Li token = matched.group(1) 2715*8c35d5eeSXin Li if token == '{': 2716*8c35d5eeSXin Li # If namespace or class hasn't seen a opening brace yet, mark 2717*8c35d5eeSXin Li # namespace/class head as complete. Push a new block onto the 2718*8c35d5eeSXin Li # stack otherwise. 2719*8c35d5eeSXin Li if not self.SeenOpenBrace(): 2720*8c35d5eeSXin Li self.stack[-1].seen_open_brace = True 2721*8c35d5eeSXin Li elif Match(r'^extern\s*"[^"]*"\s*\{', line): 2722*8c35d5eeSXin Li self.stack.append(_ExternCInfo(linenum)) 2723*8c35d5eeSXin Li else: 2724*8c35d5eeSXin Li self.stack.append(_BlockInfo(linenum, True)) 2725*8c35d5eeSXin Li if _MATCH_ASM.match(line): 2726*8c35d5eeSXin Li self.stack[-1].inline_asm = _BLOCK_ASM 2727*8c35d5eeSXin Li 2728*8c35d5eeSXin Li elif token == ';' or token == ')': 2729*8c35d5eeSXin Li # If we haven't seen an opening brace yet, but we already saw 2730*8c35d5eeSXin Li # a semicolon, this is probably a forward declaration. Pop 2731*8c35d5eeSXin Li # the stack for these. 2732*8c35d5eeSXin Li # 2733*8c35d5eeSXin Li # Similarly, if we haven't seen an opening brace yet, but we 2734*8c35d5eeSXin Li # already saw a closing parenthesis, then these are probably 2735*8c35d5eeSXin Li # function arguments with extra "class" or "struct" keywords. 2736*8c35d5eeSXin Li # Also pop these stack for these. 2737*8c35d5eeSXin Li if not self.SeenOpenBrace(): 2738*8c35d5eeSXin Li self.stack.pop() 2739*8c35d5eeSXin Li else: # token == '}' 2740*8c35d5eeSXin Li # Perform end of block checks and pop the stack. 2741*8c35d5eeSXin Li if self.stack: 2742*8c35d5eeSXin Li self.stack[-1].CheckEnd(filename, clean_lines, linenum, error) 2743*8c35d5eeSXin Li self.stack.pop() 2744*8c35d5eeSXin Li line = matched.group(2) 2745*8c35d5eeSXin Li 2746*8c35d5eeSXin Li def InnermostClass(self): 2747*8c35d5eeSXin Li """Get class info on the top of the stack. 2748*8c35d5eeSXin Li 2749*8c35d5eeSXin Li Returns: 2750*8c35d5eeSXin Li A _ClassInfo object if we are inside a class, or None otherwise. 2751*8c35d5eeSXin Li """ 2752*8c35d5eeSXin Li for i in range(len(self.stack), 0, -1): 2753*8c35d5eeSXin Li classinfo = self.stack[i - 1] 2754*8c35d5eeSXin Li if isinstance(classinfo, _ClassInfo): 2755*8c35d5eeSXin Li return classinfo 2756*8c35d5eeSXin Li return None 2757*8c35d5eeSXin Li 2758*8c35d5eeSXin Li def CheckCompletedBlocks(self, filename, error): 2759*8c35d5eeSXin Li """Checks that all classes and namespaces have been completely parsed. 2760*8c35d5eeSXin Li 2761*8c35d5eeSXin Li Call this when all lines in a file have been processed. 2762*8c35d5eeSXin Li Args: 2763*8c35d5eeSXin Li filename: The name of the current file. 2764*8c35d5eeSXin Li error: The function to call with any errors found. 2765*8c35d5eeSXin Li """ 2766*8c35d5eeSXin Li # Note: This test can result in false positives if #ifdef constructs 2767*8c35d5eeSXin Li # get in the way of brace matching. See the testBuildClass test in 2768*8c35d5eeSXin Li # cpplint_unittest.py for an example of this. 2769*8c35d5eeSXin Li for obj in self.stack: 2770*8c35d5eeSXin Li if isinstance(obj, _ClassInfo): 2771*8c35d5eeSXin Li error(filename, obj.starting_linenum, 'build/class', 5, 2772*8c35d5eeSXin Li 'Failed to find complete declaration of class %s' % 2773*8c35d5eeSXin Li obj.name) 2774*8c35d5eeSXin Li elif isinstance(obj, _NamespaceInfo): 2775*8c35d5eeSXin Li error(filename, obj.starting_linenum, 'build/namespaces', 5, 2776*8c35d5eeSXin Li 'Failed to find complete declaration of namespace %s' % 2777*8c35d5eeSXin Li obj.name) 2778*8c35d5eeSXin Li 2779*8c35d5eeSXin Li 2780*8c35d5eeSXin Lidef CheckForNonStandardConstructs(filename, clean_lines, linenum, 2781*8c35d5eeSXin Li nesting_state, error): 2782*8c35d5eeSXin Li r"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2. 2783*8c35d5eeSXin Li 2784*8c35d5eeSXin Li Complain about several constructs which gcc-2 accepts, but which are 2785*8c35d5eeSXin Li not standard C++. Warning about these in lint is one way to ease the 2786*8c35d5eeSXin Li transition to new compilers. 2787*8c35d5eeSXin Li - put storage class first (e.g. "static const" instead of "const static"). 2788*8c35d5eeSXin Li - "%lld" instead of %qd" in printf-type functions. 2789*8c35d5eeSXin Li - "%1$d" is non-standard in printf-type functions. 2790*8c35d5eeSXin Li - "\%" is an undefined character escape sequence. 2791*8c35d5eeSXin Li - text after #endif is not allowed. 2792*8c35d5eeSXin Li - invalid inner-style forward declaration. 2793*8c35d5eeSXin Li - >? and <? operators, and their >?= and <?= cousins. 2794*8c35d5eeSXin Li 2795*8c35d5eeSXin Li Additionally, check for constructor/destructor style violations and reference 2796*8c35d5eeSXin Li members, as it is very convenient to do so while checking for 2797*8c35d5eeSXin Li gcc-2 compliance. 2798*8c35d5eeSXin Li 2799*8c35d5eeSXin Li Args: 2800*8c35d5eeSXin Li filename: The name of the current file. 2801*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 2802*8c35d5eeSXin Li linenum: The number of the line to check. 2803*8c35d5eeSXin Li nesting_state: A NestingState instance which maintains information about 2804*8c35d5eeSXin Li the current stack of nested blocks being parsed. 2805*8c35d5eeSXin Li error: A callable to which errors are reported, which takes 4 arguments: 2806*8c35d5eeSXin Li filename, line number, error level, and message 2807*8c35d5eeSXin Li """ 2808*8c35d5eeSXin Li 2809*8c35d5eeSXin Li # Remove comments from the line, but leave in strings for now. 2810*8c35d5eeSXin Li line = clean_lines.lines[linenum] 2811*8c35d5eeSXin Li 2812*8c35d5eeSXin Li if Search(r'printf\s*\(.*".*%[-+ ]?\d*q', line): 2813*8c35d5eeSXin Li error(filename, linenum, 'runtime/printf_format', 3, 2814*8c35d5eeSXin Li '%q in format strings is deprecated. Use %ll instead.') 2815*8c35d5eeSXin Li 2816*8c35d5eeSXin Li if Search(r'printf\s*\(.*".*%\d+\$', line): 2817*8c35d5eeSXin Li error(filename, linenum, 'runtime/printf_format', 2, 2818*8c35d5eeSXin Li '%N$ formats are unconventional. Try rewriting to avoid them.') 2819*8c35d5eeSXin Li 2820*8c35d5eeSXin Li # Remove escaped backslashes before looking for undefined escapes. 2821*8c35d5eeSXin Li line = line.replace('\\\\', '') 2822*8c35d5eeSXin Li 2823*8c35d5eeSXin Li if Search(r'("|\').*\\(%|\[|\(|{)', line): 2824*8c35d5eeSXin Li error(filename, linenum, 'build/printf_format', 3, 2825*8c35d5eeSXin Li '%, [, (, and { are undefined character escapes. Unescape them.') 2826*8c35d5eeSXin Li 2827*8c35d5eeSXin Li # For the rest, work with both comments and strings removed. 2828*8c35d5eeSXin Li line = clean_lines.elided[linenum] 2829*8c35d5eeSXin Li 2830*8c35d5eeSXin Li if Search(r'\b(const|volatile|void|char|short|int|long' 2831*8c35d5eeSXin Li r'|float|double|signed|unsigned' 2832*8c35d5eeSXin Li r'|schar|u?int8|u?int16|u?int32|u?int64)' 2833*8c35d5eeSXin Li r'\s+(register|static|extern|typedef)\b', 2834*8c35d5eeSXin Li line): 2835*8c35d5eeSXin Li error(filename, linenum, 'build/storage_class', 5, 2836*8c35d5eeSXin Li 'Storage-class specifier (static, extern, typedef, etc) should be ' 2837*8c35d5eeSXin Li 'at the beginning of the declaration.') 2838*8c35d5eeSXin Li 2839*8c35d5eeSXin Li if Match(r'\s*#\s*endif\s*[^/\s]+', line): 2840*8c35d5eeSXin Li error(filename, linenum, 'build/endif_comment', 5, 2841*8c35d5eeSXin Li 'Uncommented text after #endif is non-standard. Use a comment.') 2842*8c35d5eeSXin Li 2843*8c35d5eeSXin Li if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line): 2844*8c35d5eeSXin Li error(filename, linenum, 'build/forward_decl', 5, 2845*8c35d5eeSXin Li 'Inner-style forward declarations are invalid. Remove this line.') 2846*8c35d5eeSXin Li 2847*8c35d5eeSXin Li if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?', 2848*8c35d5eeSXin Li line): 2849*8c35d5eeSXin Li error(filename, linenum, 'build/deprecated', 3, 2850*8c35d5eeSXin Li '>? and <? (max and min) operators are non-standard and deprecated.') 2851*8c35d5eeSXin Li 2852*8c35d5eeSXin Li if Search(r'^\s*const\s*string\s*&\s*\w+\s*;', line): 2853*8c35d5eeSXin Li # TODO(unknown): Could it be expanded safely to arbitrary references, 2854*8c35d5eeSXin Li # without triggering too many false positives? The first 2855*8c35d5eeSXin Li # attempt triggered 5 warnings for mostly benign code in the regtest, hence 2856*8c35d5eeSXin Li # the restriction. 2857*8c35d5eeSXin Li # Here's the original regexp, for the reference: 2858*8c35d5eeSXin Li # type_name = r'\w+((\s*::\s*\w+)|(\s*<\s*\w+?\s*>))?' 2859*8c35d5eeSXin Li # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;' 2860*8c35d5eeSXin Li error(filename, linenum, 'runtime/member_string_references', 2, 2861*8c35d5eeSXin Li 'const string& members are dangerous. It is much better to use ' 2862*8c35d5eeSXin Li 'alternatives, such as pointers or simple constants.') 2863*8c35d5eeSXin Li 2864*8c35d5eeSXin Li # Everything else in this function operates on class declarations. 2865*8c35d5eeSXin Li # Return early if the top of the nesting stack is not a class, or if 2866*8c35d5eeSXin Li # the class head is not completed yet. 2867*8c35d5eeSXin Li classinfo = nesting_state.InnermostClass() 2868*8c35d5eeSXin Li if not classinfo or not classinfo.seen_open_brace: 2869*8c35d5eeSXin Li return 2870*8c35d5eeSXin Li 2871*8c35d5eeSXin Li # The class may have been declared with namespace or classname qualifiers. 2872*8c35d5eeSXin Li # The constructor and destructor will not have those qualifiers. 2873*8c35d5eeSXin Li base_classname = classinfo.name.split('::')[-1] 2874*8c35d5eeSXin Li 2875*8c35d5eeSXin Li # Look for single-argument constructors that aren't marked explicit. 2876*8c35d5eeSXin Li # Technically a valid construct, but against style. 2877*8c35d5eeSXin Li explicit_constructor_match = Match( 2878*8c35d5eeSXin Li r'\s+(?:(?:inline|constexpr)\s+)*(explicit\s+)?' 2879*8c35d5eeSXin Li r'(?:(?:inline|constexpr)\s+)*%s\s*' 2880*8c35d5eeSXin Li r'\(((?:[^()]|\([^()]*\))*)\)' 2881*8c35d5eeSXin Li % re.escape(base_classname), 2882*8c35d5eeSXin Li line) 2883*8c35d5eeSXin Li 2884*8c35d5eeSXin Li if explicit_constructor_match: 2885*8c35d5eeSXin Li is_marked_explicit = explicit_constructor_match.group(1) 2886*8c35d5eeSXin Li 2887*8c35d5eeSXin Li if not explicit_constructor_match.group(2): 2888*8c35d5eeSXin Li constructor_args = [] 2889*8c35d5eeSXin Li else: 2890*8c35d5eeSXin Li constructor_args = explicit_constructor_match.group(2).split(',') 2891*8c35d5eeSXin Li 2892*8c35d5eeSXin Li # collapse arguments so that commas in template parameter lists and function 2893*8c35d5eeSXin Li # argument parameter lists don't split arguments in two 2894*8c35d5eeSXin Li i = 0 2895*8c35d5eeSXin Li while i < len(constructor_args): 2896*8c35d5eeSXin Li constructor_arg = constructor_args[i] 2897*8c35d5eeSXin Li while (constructor_arg.count('<') > constructor_arg.count('>') or 2898*8c35d5eeSXin Li constructor_arg.count('(') > constructor_arg.count(')')): 2899*8c35d5eeSXin Li constructor_arg += ',' + constructor_args[i + 1] 2900*8c35d5eeSXin Li del constructor_args[i + 1] 2901*8c35d5eeSXin Li constructor_args[i] = constructor_arg 2902*8c35d5eeSXin Li i += 1 2903*8c35d5eeSXin Li 2904*8c35d5eeSXin Li defaulted_args = [arg for arg in constructor_args if '=' in arg] 2905*8c35d5eeSXin Li noarg_constructor = (not constructor_args or # empty arg list 2906*8c35d5eeSXin Li # 'void' arg specifier 2907*8c35d5eeSXin Li (len(constructor_args) == 1 and 2908*8c35d5eeSXin Li constructor_args[0].strip() == 'void')) 2909*8c35d5eeSXin Li onearg_constructor = ((len(constructor_args) == 1 and # exactly one arg 2910*8c35d5eeSXin Li not noarg_constructor) or 2911*8c35d5eeSXin Li # all but at most one arg defaulted 2912*8c35d5eeSXin Li (len(constructor_args) >= 1 and 2913*8c35d5eeSXin Li not noarg_constructor and 2914*8c35d5eeSXin Li len(defaulted_args) >= len(constructor_args) - 1)) 2915*8c35d5eeSXin Li initializer_list_constructor = bool( 2916*8c35d5eeSXin Li onearg_constructor and 2917*8c35d5eeSXin Li Search(r'\bstd\s*::\s*initializer_list\b', constructor_args[0])) 2918*8c35d5eeSXin Li copy_constructor = bool( 2919*8c35d5eeSXin Li onearg_constructor and 2920*8c35d5eeSXin Li Match(r'(const\s+)?%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&' 2921*8c35d5eeSXin Li % re.escape(base_classname), constructor_args[0].strip())) 2922*8c35d5eeSXin Li 2923*8c35d5eeSXin Li if (not is_marked_explicit and 2924*8c35d5eeSXin Li onearg_constructor and 2925*8c35d5eeSXin Li not initializer_list_constructor and 2926*8c35d5eeSXin Li not copy_constructor): 2927*8c35d5eeSXin Li if defaulted_args: 2928*8c35d5eeSXin Li error(filename, linenum, 'runtime/explicit', 5, 2929*8c35d5eeSXin Li 'Constructors callable with one argument ' 2930*8c35d5eeSXin Li 'should be marked explicit.') 2931*8c35d5eeSXin Li else: 2932*8c35d5eeSXin Li error(filename, linenum, 'runtime/explicit', 5, 2933*8c35d5eeSXin Li 'Single-parameter constructors should be marked explicit.') 2934*8c35d5eeSXin Li elif is_marked_explicit and not onearg_constructor: 2935*8c35d5eeSXin Li if noarg_constructor: 2936*8c35d5eeSXin Li error(filename, linenum, 'runtime/explicit', 5, 2937*8c35d5eeSXin Li 'Zero-parameter constructors should not be marked explicit.') 2938*8c35d5eeSXin Li 2939*8c35d5eeSXin Li 2940*8c35d5eeSXin Lidef CheckSpacingForFunctionCall(filename, clean_lines, linenum, error): 2941*8c35d5eeSXin Li """Checks for the correctness of various spacing around function calls. 2942*8c35d5eeSXin Li 2943*8c35d5eeSXin Li Args: 2944*8c35d5eeSXin Li filename: The name of the current file. 2945*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 2946*8c35d5eeSXin Li linenum: The number of the line to check. 2947*8c35d5eeSXin Li error: The function to call with any errors found. 2948*8c35d5eeSXin Li """ 2949*8c35d5eeSXin Li line = clean_lines.elided[linenum] 2950*8c35d5eeSXin Li 2951*8c35d5eeSXin Li # Since function calls often occur inside if/for/while/switch 2952*8c35d5eeSXin Li # expressions - which have their own, more liberal conventions - we 2953*8c35d5eeSXin Li # first see if we should be looking inside such an expression for a 2954*8c35d5eeSXin Li # function call, to which we can apply more strict standards. 2955*8c35d5eeSXin Li fncall = line # if there's no control flow construct, look at whole line 2956*8c35d5eeSXin Li for pattern in (r'\bif\s*\((.*)\)\s*{', 2957*8c35d5eeSXin Li r'\bfor\s*\((.*)\)\s*{', 2958*8c35d5eeSXin Li r'\bwhile\s*\((.*)\)\s*[{;]', 2959*8c35d5eeSXin Li r'\bswitch\s*\((.*)\)\s*{'): 2960*8c35d5eeSXin Li match = Search(pattern, line) 2961*8c35d5eeSXin Li if match: 2962*8c35d5eeSXin Li fncall = match.group(1) # look inside the parens for function calls 2963*8c35d5eeSXin Li break 2964*8c35d5eeSXin Li 2965*8c35d5eeSXin Li # Except in if/for/while/switch, there should never be space 2966*8c35d5eeSXin Li # immediately inside parens (eg "f( 3, 4 )"). We make an exception 2967*8c35d5eeSXin Li # for nested parens ( (a+b) + c ). Likewise, there should never be 2968*8c35d5eeSXin Li # a space before a ( when it's a function argument. I assume it's a 2969*8c35d5eeSXin Li # function argument when the char before the whitespace is legal in 2970*8c35d5eeSXin Li # a function name (alnum + _) and we're not starting a macro. Also ignore 2971*8c35d5eeSXin Li # pointers and references to arrays and functions coz they're too tricky: 2972*8c35d5eeSXin Li # we use a very simple way to recognize these: 2973*8c35d5eeSXin Li # " (something)(maybe-something)" or 2974*8c35d5eeSXin Li # " (something)(maybe-something," or 2975*8c35d5eeSXin Li # " (something)[something]" 2976*8c35d5eeSXin Li # Note that we assume the contents of [] to be short enough that 2977*8c35d5eeSXin Li # they'll never need to wrap. 2978*8c35d5eeSXin Li if ( # Ignore control structures. 2979*8c35d5eeSXin Li not Search(r'\b(if|for|while|switch|return|new|delete|catch|sizeof)\b', 2980*8c35d5eeSXin Li fncall) and 2981*8c35d5eeSXin Li # Ignore pointers/references to functions. 2982*8c35d5eeSXin Li not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and 2983*8c35d5eeSXin Li # Ignore pointers/references to arrays. 2984*8c35d5eeSXin Li not Search(r' \([^)]+\)\[[^\]]+\]', fncall)): 2985*8c35d5eeSXin Li if Search(r'\w\s*\(\s(?!\s*\\$)', fncall): # a ( used for a fn call 2986*8c35d5eeSXin Li error(filename, linenum, 'whitespace/parens', 4, 2987*8c35d5eeSXin Li 'Extra space after ( in function call') 2988*8c35d5eeSXin Li elif Search(r'\(\s+(?!(\s*\\)|\()', fncall): 2989*8c35d5eeSXin Li error(filename, linenum, 'whitespace/parens', 2, 2990*8c35d5eeSXin Li 'Extra space after (') 2991*8c35d5eeSXin Li if (Search(r'\w\s+\(', fncall) and 2992*8c35d5eeSXin Li not Search(r'_{0,2}asm_{0,2}\s+_{0,2}volatile_{0,2}\s+\(', fncall) and 2993*8c35d5eeSXin Li not Search(r'#\s*define|typedef|using\s+\w+\s*=', fncall) and 2994*8c35d5eeSXin Li not Search(r'\w\s+\((\w+::)*\*\w+\)\(', fncall) and 2995*8c35d5eeSXin Li not Search(r'\bcase\s+\(', fncall)): 2996*8c35d5eeSXin Li # TODO(unknown): Space after an operator function seem to be a common 2997*8c35d5eeSXin Li # error, silence those for now by restricting them to highest verbosity. 2998*8c35d5eeSXin Li if Search(r'\boperator_*\b', line): 2999*8c35d5eeSXin Li error(filename, linenum, 'whitespace/parens', 0, 3000*8c35d5eeSXin Li 'Extra space before ( in function call') 3001*8c35d5eeSXin Li else: 3002*8c35d5eeSXin Li error(filename, linenum, 'whitespace/parens', 4, 3003*8c35d5eeSXin Li 'Extra space before ( in function call') 3004*8c35d5eeSXin Li # If the ) is followed only by a newline or a { + newline, assume it's 3005*8c35d5eeSXin Li # part of a control statement (if/while/etc), and don't complain 3006*8c35d5eeSXin Li if Search(r'[^)]\s+\)\s*[^{\s]', fncall): 3007*8c35d5eeSXin Li # If the closing parenthesis is preceded by only whitespaces, 3008*8c35d5eeSXin Li # try to give a more descriptive error message. 3009*8c35d5eeSXin Li if Search(r'^\s+\)', fncall): 3010*8c35d5eeSXin Li error(filename, linenum, 'whitespace/parens', 2, 3011*8c35d5eeSXin Li 'Closing ) should be moved to the previous line') 3012*8c35d5eeSXin Li else: 3013*8c35d5eeSXin Li error(filename, linenum, 'whitespace/parens', 2, 3014*8c35d5eeSXin Li 'Extra space before )') 3015*8c35d5eeSXin Li 3016*8c35d5eeSXin Li 3017*8c35d5eeSXin Lidef IsBlankLine(line): 3018*8c35d5eeSXin Li """Returns true if the given line is blank. 3019*8c35d5eeSXin Li 3020*8c35d5eeSXin Li We consider a line to be blank if the line is empty or consists of 3021*8c35d5eeSXin Li only white spaces. 3022*8c35d5eeSXin Li 3023*8c35d5eeSXin Li Args: 3024*8c35d5eeSXin Li line: A line of a string. 3025*8c35d5eeSXin Li 3026*8c35d5eeSXin Li Returns: 3027*8c35d5eeSXin Li True, if the given line is blank. 3028*8c35d5eeSXin Li """ 3029*8c35d5eeSXin Li return not line or line.isspace() 3030*8c35d5eeSXin Li 3031*8c35d5eeSXin Li 3032*8c35d5eeSXin Lidef CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line, 3033*8c35d5eeSXin Li error): 3034*8c35d5eeSXin Li is_namespace_indent_item = ( 3035*8c35d5eeSXin Li len(nesting_state.stack) > 1 and 3036*8c35d5eeSXin Li nesting_state.stack[-1].check_namespace_indentation and 3037*8c35d5eeSXin Li isinstance(nesting_state.previous_stack_top, _NamespaceInfo) and 3038*8c35d5eeSXin Li nesting_state.previous_stack_top == nesting_state.stack[-2]) 3039*8c35d5eeSXin Li 3040*8c35d5eeSXin Li if ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item, 3041*8c35d5eeSXin Li clean_lines.elided, line): 3042*8c35d5eeSXin Li CheckItemIndentationInNamespace(filename, clean_lines.elided, 3043*8c35d5eeSXin Li line, error) 3044*8c35d5eeSXin Li 3045*8c35d5eeSXin Li 3046*8c35d5eeSXin Lidef CheckForFunctionLengths(filename, clean_lines, linenum, 3047*8c35d5eeSXin Li function_state, error): 3048*8c35d5eeSXin Li """Reports for long function bodies. 3049*8c35d5eeSXin Li 3050*8c35d5eeSXin Li For an overview why this is done, see: 3051*8c35d5eeSXin Li https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions 3052*8c35d5eeSXin Li 3053*8c35d5eeSXin Li Uses a simplistic algorithm assuming other style guidelines 3054*8c35d5eeSXin Li (especially spacing) are followed. 3055*8c35d5eeSXin Li Only checks unindented functions, so class members are unchecked. 3056*8c35d5eeSXin Li Trivial bodies are unchecked, so constructors with huge initializer lists 3057*8c35d5eeSXin Li may be missed. 3058*8c35d5eeSXin Li Blank/comment lines are not counted so as to avoid encouraging the removal 3059*8c35d5eeSXin Li of vertical space and comments just to get through a lint check. 3060*8c35d5eeSXin Li NOLINT *on the last line of a function* disables this check. 3061*8c35d5eeSXin Li 3062*8c35d5eeSXin Li Args: 3063*8c35d5eeSXin Li filename: The name of the current file. 3064*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 3065*8c35d5eeSXin Li linenum: The number of the line to check. 3066*8c35d5eeSXin Li function_state: Current function name and lines in body so far. 3067*8c35d5eeSXin Li error: The function to call with any errors found. 3068*8c35d5eeSXin Li """ 3069*8c35d5eeSXin Li lines = clean_lines.lines 3070*8c35d5eeSXin Li line = lines[linenum] 3071*8c35d5eeSXin Li joined_line = '' 3072*8c35d5eeSXin Li 3073*8c35d5eeSXin Li starting_func = False 3074*8c35d5eeSXin Li regexp = r'(\w(\w|::|\*|\&|\s)*)\(' # decls * & space::name( ... 3075*8c35d5eeSXin Li match_result = Match(regexp, line) 3076*8c35d5eeSXin Li if match_result: 3077*8c35d5eeSXin Li # If the name is all caps and underscores, figure it's a macro and 3078*8c35d5eeSXin Li # ignore it, unless it's TEST or TEST_F. 3079*8c35d5eeSXin Li function_name = match_result.group(1).split()[-1] 3080*8c35d5eeSXin Li if function_name == 'TEST' or function_name == 'TEST_F' or ( 3081*8c35d5eeSXin Li not Match(r'[A-Z_]+$', function_name)): 3082*8c35d5eeSXin Li starting_func = True 3083*8c35d5eeSXin Li 3084*8c35d5eeSXin Li if starting_func: 3085*8c35d5eeSXin Li body_found = False 3086*8c35d5eeSXin Li for start_linenum in xrange(linenum, clean_lines.NumLines()): 3087*8c35d5eeSXin Li start_line = lines[start_linenum] 3088*8c35d5eeSXin Li joined_line += ' ' + start_line.lstrip() 3089*8c35d5eeSXin Li if Search(r'(;|})', start_line): # Declarations and trivial functions 3090*8c35d5eeSXin Li body_found = True 3091*8c35d5eeSXin Li break # ... ignore 3092*8c35d5eeSXin Li elif Search(r'{', start_line): 3093*8c35d5eeSXin Li body_found = True 3094*8c35d5eeSXin Li function = Search(r'((\w|:)*)\(', line).group(1) 3095*8c35d5eeSXin Li if Match(r'TEST', function): # Handle TEST... macros 3096*8c35d5eeSXin Li parameter_regexp = Search(r'(\(.*\))', joined_line) 3097*8c35d5eeSXin Li if parameter_regexp: # Ignore bad syntax 3098*8c35d5eeSXin Li function += parameter_regexp.group(1) 3099*8c35d5eeSXin Li else: 3100*8c35d5eeSXin Li function += '()' 3101*8c35d5eeSXin Li function_state.Begin(function) 3102*8c35d5eeSXin Li break 3103*8c35d5eeSXin Li if not body_found: 3104*8c35d5eeSXin Li # No body for the function (or evidence of a non-function) was found. 3105*8c35d5eeSXin Li error(filename, linenum, 'readability/fn_size', 5, 3106*8c35d5eeSXin Li 'Lint failed to find start of function body.') 3107*8c35d5eeSXin Li elif Match(r'^\}\s*$', line): # function end 3108*8c35d5eeSXin Li function_state.Check(error, filename, linenum) 3109*8c35d5eeSXin Li function_state.End() 3110*8c35d5eeSXin Li elif not Match(r'^\s*$', line): 3111*8c35d5eeSXin Li function_state.Count() # Count non-blank/non-comment lines. 3112*8c35d5eeSXin Li 3113*8c35d5eeSXin Li 3114*8c35d5eeSXin Li_RE_PATTERN_TODO = re.compile(r'^//(\s*)TODO(\(.+?\))?:?(\s|$)?') 3115*8c35d5eeSXin Li 3116*8c35d5eeSXin Li 3117*8c35d5eeSXin Lidef CheckComment(line, filename, linenum, next_line_start, error): 3118*8c35d5eeSXin Li """Checks for common mistakes in comments. 3119*8c35d5eeSXin Li 3120*8c35d5eeSXin Li Args: 3121*8c35d5eeSXin Li line: The line in question. 3122*8c35d5eeSXin Li filename: The name of the current file. 3123*8c35d5eeSXin Li linenum: The number of the line to check. 3124*8c35d5eeSXin Li next_line_start: The first non-whitespace column of the next line. 3125*8c35d5eeSXin Li error: The function to call with any errors found. 3126*8c35d5eeSXin Li """ 3127*8c35d5eeSXin Li commentpos = line.find('//') 3128*8c35d5eeSXin Li if commentpos != -1: 3129*8c35d5eeSXin Li # Check if the // may be in quotes. If so, ignore it 3130*8c35d5eeSXin Li if re.sub(r'\\.', '', line[0:commentpos]).count('"') % 2 == 0: 3131*8c35d5eeSXin Li # Allow one space for new scopes, two spaces otherwise: 3132*8c35d5eeSXin Li if (not (Match(r'^.*{ *//', line) and next_line_start == commentpos) and 3133*8c35d5eeSXin Li ((commentpos >= 1 and 3134*8c35d5eeSXin Li line[commentpos-1] not in string.whitespace) or 3135*8c35d5eeSXin Li (commentpos >= 2 and 3136*8c35d5eeSXin Li line[commentpos-2] not in string.whitespace))): 3137*8c35d5eeSXin Li error(filename, linenum, 'whitespace/comments', 2, 3138*8c35d5eeSXin Li 'At least two spaces is best between code and comments') 3139*8c35d5eeSXin Li 3140*8c35d5eeSXin Li # Checks for common mistakes in TODO comments. 3141*8c35d5eeSXin Li comment = line[commentpos:] 3142*8c35d5eeSXin Li match = _RE_PATTERN_TODO.match(comment) 3143*8c35d5eeSXin Li if match: 3144*8c35d5eeSXin Li # One whitespace is correct; zero whitespace is handled elsewhere. 3145*8c35d5eeSXin Li leading_whitespace = match.group(1) 3146*8c35d5eeSXin Li if len(leading_whitespace) > 1: 3147*8c35d5eeSXin Li error(filename, linenum, 'whitespace/todo', 2, 3148*8c35d5eeSXin Li 'Too many spaces before TODO') 3149*8c35d5eeSXin Li 3150*8c35d5eeSXin Li username = match.group(2) 3151*8c35d5eeSXin Li if not username: 3152*8c35d5eeSXin Li error(filename, linenum, 'readability/todo', 2, 3153*8c35d5eeSXin Li 'Missing username in TODO; it should look like ' 3154*8c35d5eeSXin Li '"// TODO(my_username): Stuff."') 3155*8c35d5eeSXin Li 3156*8c35d5eeSXin Li middle_whitespace = match.group(3) 3157*8c35d5eeSXin Li # Comparisons made explicit for correctness -- pylint: disable=g-explicit-bool-comparison 3158*8c35d5eeSXin Li if middle_whitespace != ' ' and middle_whitespace != '': 3159*8c35d5eeSXin Li error(filename, linenum, 'whitespace/todo', 2, 3160*8c35d5eeSXin Li 'TODO(my_username) should be followed by a space') 3161*8c35d5eeSXin Li 3162*8c35d5eeSXin Li # If the comment contains an alphanumeric character, there 3163*8c35d5eeSXin Li # should be a space somewhere between it and the // unless 3164*8c35d5eeSXin Li # it's a /// or //! Doxygen comment. 3165*8c35d5eeSXin Li if (Match(r'//[^ ]*\w', comment) and 3166*8c35d5eeSXin Li not Match(r'(///|//\!)(\s+|$)', comment)): 3167*8c35d5eeSXin Li error(filename, linenum, 'whitespace/comments', 4, 3168*8c35d5eeSXin Li 'Should have a space between // and comment') 3169*8c35d5eeSXin Li 3170*8c35d5eeSXin Li 3171*8c35d5eeSXin Lidef CheckSpacing(filename, clean_lines, linenum, nesting_state, error): 3172*8c35d5eeSXin Li """Checks for the correctness of various spacing issues in the code. 3173*8c35d5eeSXin Li 3174*8c35d5eeSXin Li Things we check for: spaces around operators, spaces after 3175*8c35d5eeSXin Li if/for/while/switch, no spaces around parens in function calls, two 3176*8c35d5eeSXin Li spaces between code and comment, don't start a block with a blank 3177*8c35d5eeSXin Li line, don't end a function with a blank line, don't add a blank line 3178*8c35d5eeSXin Li after public/protected/private, don't have too many blank lines in a row. 3179*8c35d5eeSXin Li 3180*8c35d5eeSXin Li Args: 3181*8c35d5eeSXin Li filename: The name of the current file. 3182*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 3183*8c35d5eeSXin Li linenum: The number of the line to check. 3184*8c35d5eeSXin Li nesting_state: A NestingState instance which maintains information about 3185*8c35d5eeSXin Li the current stack of nested blocks being parsed. 3186*8c35d5eeSXin Li error: The function to call with any errors found. 3187*8c35d5eeSXin Li """ 3188*8c35d5eeSXin Li 3189*8c35d5eeSXin Li # Don't use "elided" lines here, otherwise we can't check commented lines. 3190*8c35d5eeSXin Li # Don't want to use "raw" either, because we don't want to check inside C++11 3191*8c35d5eeSXin Li # raw strings, 3192*8c35d5eeSXin Li raw = clean_lines.lines_without_raw_strings 3193*8c35d5eeSXin Li line = raw[linenum] 3194*8c35d5eeSXin Li 3195*8c35d5eeSXin Li # Before nixing comments, check if the line is blank for no good 3196*8c35d5eeSXin Li # reason. This includes the first line after a block is opened, and 3197*8c35d5eeSXin Li # blank lines at the end of a function (ie, right before a line like '}' 3198*8c35d5eeSXin Li # 3199*8c35d5eeSXin Li # Skip all the blank line checks if we are immediately inside a 3200*8c35d5eeSXin Li # namespace body. In other words, don't issue blank line warnings 3201*8c35d5eeSXin Li # for this block: 3202*8c35d5eeSXin Li # namespace { 3203*8c35d5eeSXin Li # 3204*8c35d5eeSXin Li # } 3205*8c35d5eeSXin Li # 3206*8c35d5eeSXin Li # A warning about missing end of namespace comments will be issued instead. 3207*8c35d5eeSXin Li # 3208*8c35d5eeSXin Li # Also skip blank line checks for 'extern "C"' blocks, which are formatted 3209*8c35d5eeSXin Li # like namespaces. 3210*8c35d5eeSXin Li if (IsBlankLine(line) and 3211*8c35d5eeSXin Li not nesting_state.InNamespaceBody() and 3212*8c35d5eeSXin Li not nesting_state.InExternC()): 3213*8c35d5eeSXin Li elided = clean_lines.elided 3214*8c35d5eeSXin Li prev_line = elided[linenum - 1] 3215*8c35d5eeSXin Li prevbrace = prev_line.rfind('{') 3216*8c35d5eeSXin Li # TODO(unknown): Don't complain if line before blank line, and line after, 3217*8c35d5eeSXin Li # both start with alnums and are indented the same amount. 3218*8c35d5eeSXin Li # This ignores whitespace at the start of a namespace block 3219*8c35d5eeSXin Li # because those are not usually indented. 3220*8c35d5eeSXin Li if prevbrace != -1 and prev_line[prevbrace:].find('}') == -1: 3221*8c35d5eeSXin Li # OK, we have a blank line at the start of a code block. Before we 3222*8c35d5eeSXin Li # complain, we check if it is an exception to the rule: The previous 3223*8c35d5eeSXin Li # non-empty line has the parameters of a function header that are indented 3224*8c35d5eeSXin Li # 4 spaces (because they did not fit in a 80 column line when placed on 3225*8c35d5eeSXin Li # the same line as the function name). We also check for the case where 3226*8c35d5eeSXin Li # the previous line is indented 6 spaces, which may happen when the 3227*8c35d5eeSXin Li # initializers of a constructor do not fit into a 80 column line. 3228*8c35d5eeSXin Li exception = False 3229*8c35d5eeSXin Li if Match(r' {6}\w', prev_line): # Initializer list? 3230*8c35d5eeSXin Li # We are looking for the opening column of initializer list, which 3231*8c35d5eeSXin Li # should be indented 4 spaces to cause 6 space indentation afterwards. 3232*8c35d5eeSXin Li search_position = linenum-2 3233*8c35d5eeSXin Li while (search_position >= 0 3234*8c35d5eeSXin Li and Match(r' {6}\w', elided[search_position])): 3235*8c35d5eeSXin Li search_position -= 1 3236*8c35d5eeSXin Li exception = (search_position >= 0 3237*8c35d5eeSXin Li and elided[search_position][:5] == ' :') 3238*8c35d5eeSXin Li else: 3239*8c35d5eeSXin Li # Search for the function arguments or an initializer list. We use a 3240*8c35d5eeSXin Li # simple heuristic here: If the line is indented 4 spaces; and we have a 3241*8c35d5eeSXin Li # closing paren, without the opening paren, followed by an opening brace 3242*8c35d5eeSXin Li # or colon (for initializer lists) we assume that it is the last line of 3243*8c35d5eeSXin Li # a function header. If we have a colon indented 4 spaces, it is an 3244*8c35d5eeSXin Li # initializer list. 3245*8c35d5eeSXin Li exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)', 3246*8c35d5eeSXin Li prev_line) 3247*8c35d5eeSXin Li or Match(r' {4}:', prev_line)) 3248*8c35d5eeSXin Li 3249*8c35d5eeSXin Li if not exception: 3250*8c35d5eeSXin Li error(filename, linenum, 'whitespace/blank_line', 2, 3251*8c35d5eeSXin Li 'Redundant blank line at the start of a code block ' 3252*8c35d5eeSXin Li 'should be deleted.') 3253*8c35d5eeSXin Li # Ignore blank lines at the end of a block in a long if-else 3254*8c35d5eeSXin Li # chain, like this: 3255*8c35d5eeSXin Li # if (condition1) { 3256*8c35d5eeSXin Li # // Something followed by a blank line 3257*8c35d5eeSXin Li # 3258*8c35d5eeSXin Li # } else if (condition2) { 3259*8c35d5eeSXin Li # // Something else 3260*8c35d5eeSXin Li # } 3261*8c35d5eeSXin Li if linenum + 1 < clean_lines.NumLines(): 3262*8c35d5eeSXin Li next_line = raw[linenum + 1] 3263*8c35d5eeSXin Li if (next_line 3264*8c35d5eeSXin Li and Match(r'\s*}', next_line) 3265*8c35d5eeSXin Li and next_line.find('} else ') == -1): 3266*8c35d5eeSXin Li error(filename, linenum, 'whitespace/blank_line', 3, 3267*8c35d5eeSXin Li 'Redundant blank line at the end of a code block ' 3268*8c35d5eeSXin Li 'should be deleted.') 3269*8c35d5eeSXin Li 3270*8c35d5eeSXin Li matched = Match(r'\s*(public|protected|private):', prev_line) 3271*8c35d5eeSXin Li if matched: 3272*8c35d5eeSXin Li error(filename, linenum, 'whitespace/blank_line', 3, 3273*8c35d5eeSXin Li 'Do not leave a blank line after "%s:"' % matched.group(1)) 3274*8c35d5eeSXin Li 3275*8c35d5eeSXin Li # Next, check comments 3276*8c35d5eeSXin Li next_line_start = 0 3277*8c35d5eeSXin Li if linenum + 1 < clean_lines.NumLines(): 3278*8c35d5eeSXin Li next_line = raw[linenum + 1] 3279*8c35d5eeSXin Li next_line_start = len(next_line) - len(next_line.lstrip()) 3280*8c35d5eeSXin Li CheckComment(line, filename, linenum, next_line_start, error) 3281*8c35d5eeSXin Li 3282*8c35d5eeSXin Li # get rid of comments and strings 3283*8c35d5eeSXin Li line = clean_lines.elided[linenum] 3284*8c35d5eeSXin Li 3285*8c35d5eeSXin Li # You shouldn't have spaces before your brackets, except maybe after 3286*8c35d5eeSXin Li # 'delete []', 'return []() {};', or 'auto [abc, ...] = ...;'. 3287*8c35d5eeSXin Li if Search(r'\w\s+\[', line) and not Search(r'(?:auto&?|delete|return)\s+\[', line): 3288*8c35d5eeSXin Li error(filename, linenum, 'whitespace/braces', 5, 3289*8c35d5eeSXin Li 'Extra space before [') 3290*8c35d5eeSXin Li 3291*8c35d5eeSXin Li # In range-based for, we wanted spaces before and after the colon, but 3292*8c35d5eeSXin Li # not around "::" tokens that might appear. 3293*8c35d5eeSXin Li if (Search(r'for *\(.*[^:]:[^: ]', line) or 3294*8c35d5eeSXin Li Search(r'for *\(.*[^: ]:[^:]', line)): 3295*8c35d5eeSXin Li error(filename, linenum, 'whitespace/forcolon', 2, 3296*8c35d5eeSXin Li 'Missing space around colon in range-based for loop') 3297*8c35d5eeSXin Li 3298*8c35d5eeSXin Li 3299*8c35d5eeSXin Lidef CheckOperatorSpacing(filename, clean_lines, linenum, error): 3300*8c35d5eeSXin Li """Checks for horizontal spacing around operators. 3301*8c35d5eeSXin Li 3302*8c35d5eeSXin Li Args: 3303*8c35d5eeSXin Li filename: The name of the current file. 3304*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 3305*8c35d5eeSXin Li linenum: The number of the line to check. 3306*8c35d5eeSXin Li error: The function to call with any errors found. 3307*8c35d5eeSXin Li """ 3308*8c35d5eeSXin Li line = clean_lines.elided[linenum] 3309*8c35d5eeSXin Li 3310*8c35d5eeSXin Li # Don't try to do spacing checks for operator methods. Do this by 3311*8c35d5eeSXin Li # replacing the troublesome characters with something else, 3312*8c35d5eeSXin Li # preserving column position for all other characters. 3313*8c35d5eeSXin Li # 3314*8c35d5eeSXin Li # The replacement is done repeatedly to avoid false positives from 3315*8c35d5eeSXin Li # operators that call operators. 3316*8c35d5eeSXin Li while True: 3317*8c35d5eeSXin Li match = Match(r'^(.*\boperator\b)(\S+)(\s*\(.*)$', line) 3318*8c35d5eeSXin Li if match: 3319*8c35d5eeSXin Li line = match.group(1) + ('_' * len(match.group(2))) + match.group(3) 3320*8c35d5eeSXin Li else: 3321*8c35d5eeSXin Li break 3322*8c35d5eeSXin Li 3323*8c35d5eeSXin Li # We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )". 3324*8c35d5eeSXin Li # Otherwise not. Note we only check for non-spaces on *both* sides; 3325*8c35d5eeSXin Li # sometimes people put non-spaces on one side when aligning ='s among 3326*8c35d5eeSXin Li # many lines (not that this is behavior that I approve of...) 3327*8c35d5eeSXin Li if ((Search(r'[\w.]=', line) or 3328*8c35d5eeSXin Li Search(r'=[\w.]', line)) 3329*8c35d5eeSXin Li and not Search(r'\b(if|while|for) ', line) 3330*8c35d5eeSXin Li # Operators taken from [lex.operators] in C++11 standard. 3331*8c35d5eeSXin Li and not Search(r'(>=|<=|==|!=|&=|\^=|\|=|\+=|\*=|\/=|\%=)', line) 3332*8c35d5eeSXin Li and not Search(r'operator=', line)): 3333*8c35d5eeSXin Li error(filename, linenum, 'whitespace/operators', 4, 3334*8c35d5eeSXin Li 'Missing spaces around =') 3335*8c35d5eeSXin Li 3336*8c35d5eeSXin Li # It's ok not to have spaces around binary operators like + - * /, but if 3337*8c35d5eeSXin Li # there's too little whitespace, we get concerned. It's hard to tell, 3338*8c35d5eeSXin Li # though, so we punt on this one for now. TODO. 3339*8c35d5eeSXin Li 3340*8c35d5eeSXin Li # You should always have whitespace around binary operators. 3341*8c35d5eeSXin Li # 3342*8c35d5eeSXin Li # Check <= and >= first to avoid false positives with < and >, then 3343*8c35d5eeSXin Li # check non-include lines for spacing around < and >. 3344*8c35d5eeSXin Li # 3345*8c35d5eeSXin Li # If the operator is followed by a comma, assume it's be used in a 3346*8c35d5eeSXin Li # macro context and don't do any checks. This avoids false 3347*8c35d5eeSXin Li # positives. 3348*8c35d5eeSXin Li # 3349*8c35d5eeSXin Li # Note that && is not included here. This is because there are too 3350*8c35d5eeSXin Li # many false positives due to RValue references. 3351*8c35d5eeSXin Li match = Search(r'[^<>=!\s](==|!=|<=|>=|\|\|)[^<>=!\s,;\)]', line) 3352*8c35d5eeSXin Li if match: 3353*8c35d5eeSXin Li error(filename, linenum, 'whitespace/operators', 3, 3354*8c35d5eeSXin Li 'Missing spaces around %s' % match.group(1)) 3355*8c35d5eeSXin Li elif not Match(r'#.*include', line): 3356*8c35d5eeSXin Li # Look for < that is not surrounded by spaces. This is only 3357*8c35d5eeSXin Li # triggered if both sides are missing spaces, even though 3358*8c35d5eeSXin Li # technically should should flag if at least one side is missing a 3359*8c35d5eeSXin Li # space. This is done to avoid some false positives with shifts. 3360*8c35d5eeSXin Li match = Match(r'^(.*[^\s<])<[^\s=<,]', line) 3361*8c35d5eeSXin Li if match: 3362*8c35d5eeSXin Li (_, _, end_pos) = CloseExpression( 3363*8c35d5eeSXin Li clean_lines, linenum, len(match.group(1))) 3364*8c35d5eeSXin Li if end_pos <= -1: 3365*8c35d5eeSXin Li error(filename, linenum, 'whitespace/operators', 3, 3366*8c35d5eeSXin Li 'Missing spaces around <') 3367*8c35d5eeSXin Li 3368*8c35d5eeSXin Li # Look for > that is not surrounded by spaces. Similar to the 3369*8c35d5eeSXin Li # above, we only trigger if both sides are missing spaces to avoid 3370*8c35d5eeSXin Li # false positives with shifts. 3371*8c35d5eeSXin Li match = Match(r'^(.*[^-\s>])>[^\s=>,]', line) 3372*8c35d5eeSXin Li if match: 3373*8c35d5eeSXin Li (_, _, start_pos) = ReverseCloseExpression( 3374*8c35d5eeSXin Li clean_lines, linenum, len(match.group(1))) 3375*8c35d5eeSXin Li if start_pos <= -1: 3376*8c35d5eeSXin Li error(filename, linenum, 'whitespace/operators', 3, 3377*8c35d5eeSXin Li 'Missing spaces around >') 3378*8c35d5eeSXin Li 3379*8c35d5eeSXin Li # We allow no-spaces around << when used like this: 10<<20, but 3380*8c35d5eeSXin Li # not otherwise (particularly, not when used as streams) 3381*8c35d5eeSXin Li # 3382*8c35d5eeSXin Li # We also allow operators following an opening parenthesis, since 3383*8c35d5eeSXin Li # those tend to be macros that deal with operators. 3384*8c35d5eeSXin Li match = Search(r'(operator|[^\s(<])(?:L|UL|LL|ULL|l|ul|ll|ull)?<<([^\s,=<])', line) 3385*8c35d5eeSXin Li if (match and not (match.group(1).isdigit() and match.group(2).isdigit()) and 3386*8c35d5eeSXin Li not (match.group(1) == 'operator' and match.group(2) == ';')): 3387*8c35d5eeSXin Li error(filename, linenum, 'whitespace/operators', 3, 3388*8c35d5eeSXin Li 'Missing spaces around <<') 3389*8c35d5eeSXin Li 3390*8c35d5eeSXin Li # We allow no-spaces around >> for almost anything. This is because 3391*8c35d5eeSXin Li # C++11 allows ">>" to close nested templates, which accounts for 3392*8c35d5eeSXin Li # most cases when ">>" is not followed by a space. 3393*8c35d5eeSXin Li # 3394*8c35d5eeSXin Li # We still warn on ">>" followed by alpha character, because that is 3395*8c35d5eeSXin Li # likely due to ">>" being used for right shifts, e.g.: 3396*8c35d5eeSXin Li # value >> alpha 3397*8c35d5eeSXin Li # 3398*8c35d5eeSXin Li # When ">>" is used to close templates, the alphanumeric letter that 3399*8c35d5eeSXin Li # follows would be part of an identifier, and there should still be 3400*8c35d5eeSXin Li # a space separating the template type and the identifier. 3401*8c35d5eeSXin Li # type<type<type>> alpha 3402*8c35d5eeSXin Li match = Search(r'>>[a-zA-Z_]', line) 3403*8c35d5eeSXin Li if match: 3404*8c35d5eeSXin Li error(filename, linenum, 'whitespace/operators', 3, 3405*8c35d5eeSXin Li 'Missing spaces around >>') 3406*8c35d5eeSXin Li 3407*8c35d5eeSXin Li # There shouldn't be space around unary operators 3408*8c35d5eeSXin Li match = Search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line) 3409*8c35d5eeSXin Li if match: 3410*8c35d5eeSXin Li error(filename, linenum, 'whitespace/operators', 4, 3411*8c35d5eeSXin Li 'Extra space for operator %s' % match.group(1)) 3412*8c35d5eeSXin Li 3413*8c35d5eeSXin Li 3414*8c35d5eeSXin Lidef CheckParenthesisSpacing(filename, clean_lines, linenum, error): 3415*8c35d5eeSXin Li """Checks for horizontal spacing around parentheses. 3416*8c35d5eeSXin Li 3417*8c35d5eeSXin Li Args: 3418*8c35d5eeSXin Li filename: The name of the current file. 3419*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 3420*8c35d5eeSXin Li linenum: The number of the line to check. 3421*8c35d5eeSXin Li error: The function to call with any errors found. 3422*8c35d5eeSXin Li """ 3423*8c35d5eeSXin Li line = clean_lines.elided[linenum] 3424*8c35d5eeSXin Li 3425*8c35d5eeSXin Li # No spaces after an if, while, switch, or for 3426*8c35d5eeSXin Li match = Search(r' (if\(|for\(|while\(|switch\()', line) 3427*8c35d5eeSXin Li if match: 3428*8c35d5eeSXin Li error(filename, linenum, 'whitespace/parens', 5, 3429*8c35d5eeSXin Li 'Missing space before ( in %s' % match.group(1)) 3430*8c35d5eeSXin Li 3431*8c35d5eeSXin Li # For if/for/while/switch, the left and right parens should be 3432*8c35d5eeSXin Li # consistent about how many spaces are inside the parens, and 3433*8c35d5eeSXin Li # there should either be zero or one spaces inside the parens. 3434*8c35d5eeSXin Li # We don't want: "if ( foo)" or "if ( foo )". 3435*8c35d5eeSXin Li # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed. 3436*8c35d5eeSXin Li match = Search(r'\b(if|for|while|switch)\s*' 3437*8c35d5eeSXin Li r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$', 3438*8c35d5eeSXin Li line) 3439*8c35d5eeSXin Li if match: 3440*8c35d5eeSXin Li if len(match.group(2)) != len(match.group(4)): 3441*8c35d5eeSXin Li if not (match.group(3) == ';' and 3442*8c35d5eeSXin Li len(match.group(2)) == 1 + len(match.group(4)) or 3443*8c35d5eeSXin Li not match.group(2) and Search(r'\bfor\s*\(.*; \)', line)): 3444*8c35d5eeSXin Li error(filename, linenum, 'whitespace/parens', 5, 3445*8c35d5eeSXin Li 'Mismatching spaces inside () in %s' % match.group(1)) 3446*8c35d5eeSXin Li if len(match.group(2)) not in [0, 1]: 3447*8c35d5eeSXin Li error(filename, linenum, 'whitespace/parens', 5, 3448*8c35d5eeSXin Li 'Should have zero or one spaces inside ( and ) in %s' % 3449*8c35d5eeSXin Li match.group(1)) 3450*8c35d5eeSXin Li 3451*8c35d5eeSXin Li 3452*8c35d5eeSXin Lidef CheckCommaSpacing(filename, clean_lines, linenum, error): 3453*8c35d5eeSXin Li """Checks for horizontal spacing near commas and semicolons. 3454*8c35d5eeSXin Li 3455*8c35d5eeSXin Li Args: 3456*8c35d5eeSXin Li filename: The name of the current file. 3457*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 3458*8c35d5eeSXin Li linenum: The number of the line to check. 3459*8c35d5eeSXin Li error: The function to call with any errors found. 3460*8c35d5eeSXin Li """ 3461*8c35d5eeSXin Li raw = clean_lines.lines_without_raw_strings 3462*8c35d5eeSXin Li line = clean_lines.elided[linenum] 3463*8c35d5eeSXin Li 3464*8c35d5eeSXin Li # You should always have a space after a comma (either as fn arg or operator) 3465*8c35d5eeSXin Li # 3466*8c35d5eeSXin Li # This does not apply when the non-space character following the 3467*8c35d5eeSXin Li # comma is another comma, since the only time when that happens is 3468*8c35d5eeSXin Li # for empty macro arguments. 3469*8c35d5eeSXin Li # 3470*8c35d5eeSXin Li # We run this check in two passes: first pass on elided lines to 3471*8c35d5eeSXin Li # verify that lines contain missing whitespaces, second pass on raw 3472*8c35d5eeSXin Li # lines to confirm that those missing whitespaces are not due to 3473*8c35d5eeSXin Li # elided comments. 3474*8c35d5eeSXin Li if (Search(r',[^,\s]', ReplaceAll(r'\boperator\s*,\s*\(', 'F(', line)) and 3475*8c35d5eeSXin Li Search(r',[^,\s]', raw[linenum])): 3476*8c35d5eeSXin Li error(filename, linenum, 'whitespace/comma', 3, 3477*8c35d5eeSXin Li 'Missing space after ,') 3478*8c35d5eeSXin Li 3479*8c35d5eeSXin Li # You should always have a space after a semicolon 3480*8c35d5eeSXin Li # except for few corner cases 3481*8c35d5eeSXin Li # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more 3482*8c35d5eeSXin Li # space after ; 3483*8c35d5eeSXin Li if Search(r';[^\s};\\)/]', line): 3484*8c35d5eeSXin Li error(filename, linenum, 'whitespace/semicolon', 3, 3485*8c35d5eeSXin Li 'Missing space after ;') 3486*8c35d5eeSXin Li 3487*8c35d5eeSXin Li 3488*8c35d5eeSXin Lidef _IsType(clean_lines, nesting_state, expr): 3489*8c35d5eeSXin Li """Check if expression looks like a type name, returns true if so. 3490*8c35d5eeSXin Li 3491*8c35d5eeSXin Li Args: 3492*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 3493*8c35d5eeSXin Li nesting_state: A NestingState instance which maintains information about 3494*8c35d5eeSXin Li the current stack of nested blocks being parsed. 3495*8c35d5eeSXin Li expr: The expression to check. 3496*8c35d5eeSXin Li Returns: 3497*8c35d5eeSXin Li True, if token looks like a type. 3498*8c35d5eeSXin Li """ 3499*8c35d5eeSXin Li # Keep only the last token in the expression 3500*8c35d5eeSXin Li last_word = Match(r'^.*(\b\S+)$', expr) 3501*8c35d5eeSXin Li if last_word: 3502*8c35d5eeSXin Li token = last_word.group(1) 3503*8c35d5eeSXin Li else: 3504*8c35d5eeSXin Li token = expr 3505*8c35d5eeSXin Li 3506*8c35d5eeSXin Li # Match native types and stdint types 3507*8c35d5eeSXin Li if _TYPES.match(token): 3508*8c35d5eeSXin Li return True 3509*8c35d5eeSXin Li 3510*8c35d5eeSXin Li # Try a bit harder to match templated types. Walk up the nesting 3511*8c35d5eeSXin Li # stack until we find something that resembles a typename 3512*8c35d5eeSXin Li # declaration for what we are looking for. 3513*8c35d5eeSXin Li typename_pattern = (r'\b(?:typename|class|struct)\s+' + re.escape(token) + 3514*8c35d5eeSXin Li r'\b') 3515*8c35d5eeSXin Li block_index = len(nesting_state.stack) - 1 3516*8c35d5eeSXin Li while block_index >= 0: 3517*8c35d5eeSXin Li if isinstance(nesting_state.stack[block_index], _NamespaceInfo): 3518*8c35d5eeSXin Li return False 3519*8c35d5eeSXin Li 3520*8c35d5eeSXin Li # Found where the opening brace is. We want to scan from this 3521*8c35d5eeSXin Li # line up to the beginning of the function, minus a few lines. 3522*8c35d5eeSXin Li # template <typename Type1, // stop scanning here 3523*8c35d5eeSXin Li # ...> 3524*8c35d5eeSXin Li # class C 3525*8c35d5eeSXin Li # : public ... { // start scanning here 3526*8c35d5eeSXin Li last_line = nesting_state.stack[block_index].starting_linenum 3527*8c35d5eeSXin Li 3528*8c35d5eeSXin Li next_block_start = 0 3529*8c35d5eeSXin Li if block_index > 0: 3530*8c35d5eeSXin Li next_block_start = nesting_state.stack[block_index - 1].starting_linenum 3531*8c35d5eeSXin Li first_line = last_line 3532*8c35d5eeSXin Li while first_line >= next_block_start: 3533*8c35d5eeSXin Li if clean_lines.elided[first_line].find('template') >= 0: 3534*8c35d5eeSXin Li break 3535*8c35d5eeSXin Li first_line -= 1 3536*8c35d5eeSXin Li if first_line < next_block_start: 3537*8c35d5eeSXin Li # Didn't find any "template" keyword before reaching the next block, 3538*8c35d5eeSXin Li # there are probably no template things to check for this block 3539*8c35d5eeSXin Li block_index -= 1 3540*8c35d5eeSXin Li continue 3541*8c35d5eeSXin Li 3542*8c35d5eeSXin Li # Look for typename in the specified range 3543*8c35d5eeSXin Li for i in xrange(first_line, last_line + 1, 1): 3544*8c35d5eeSXin Li if Search(typename_pattern, clean_lines.elided[i]): 3545*8c35d5eeSXin Li return True 3546*8c35d5eeSXin Li block_index -= 1 3547*8c35d5eeSXin Li 3548*8c35d5eeSXin Li return False 3549*8c35d5eeSXin Li 3550*8c35d5eeSXin Li 3551*8c35d5eeSXin Lidef CheckBracesSpacing(filename, clean_lines, linenum, nesting_state, error): 3552*8c35d5eeSXin Li """Checks for horizontal spacing near commas. 3553*8c35d5eeSXin Li 3554*8c35d5eeSXin Li Args: 3555*8c35d5eeSXin Li filename: The name of the current file. 3556*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 3557*8c35d5eeSXin Li linenum: The number of the line to check. 3558*8c35d5eeSXin Li nesting_state: A NestingState instance which maintains information about 3559*8c35d5eeSXin Li the current stack of nested blocks being parsed. 3560*8c35d5eeSXin Li error: The function to call with any errors found. 3561*8c35d5eeSXin Li """ 3562*8c35d5eeSXin Li line = clean_lines.elided[linenum] 3563*8c35d5eeSXin Li 3564*8c35d5eeSXin Li # Except after an opening paren, or after another opening brace (in case of 3565*8c35d5eeSXin Li # an initializer list, for instance), you should have spaces before your 3566*8c35d5eeSXin Li # braces when they are delimiting blocks, classes, namespaces etc. 3567*8c35d5eeSXin Li # And since you should never have braces at the beginning of a line, 3568*8c35d5eeSXin Li # this is an easy test. Except that braces used for initialization don't 3569*8c35d5eeSXin Li # follow the same rule; we often don't want spaces before those. 3570*8c35d5eeSXin Li match = Match(r'^(.*[^ ({>]){', line) 3571*8c35d5eeSXin Li 3572*8c35d5eeSXin Li if match: 3573*8c35d5eeSXin Li # Try a bit harder to check for brace initialization. This 3574*8c35d5eeSXin Li # happens in one of the following forms: 3575*8c35d5eeSXin Li # Constructor() : initializer_list_{} { ... } 3576*8c35d5eeSXin Li # Constructor{}.MemberFunction() 3577*8c35d5eeSXin Li # Type variable{}; 3578*8c35d5eeSXin Li # FunctionCall(type{}, ...); 3579*8c35d5eeSXin Li # LastArgument(..., type{}); 3580*8c35d5eeSXin Li # LOG(INFO) << type{} << " ..."; 3581*8c35d5eeSXin Li # map_of_type[{...}] = ...; 3582*8c35d5eeSXin Li # ternary = expr ? new type{} : nullptr; 3583*8c35d5eeSXin Li # OuterTemplate<InnerTemplateConstructor<Type>{}> 3584*8c35d5eeSXin Li # 3585*8c35d5eeSXin Li # We check for the character following the closing brace, and 3586*8c35d5eeSXin Li # silence the warning if it's one of those listed above, i.e. 3587*8c35d5eeSXin Li # "{.;,)<>]:". 3588*8c35d5eeSXin Li # 3589*8c35d5eeSXin Li # To account for nested initializer list, we allow any number of 3590*8c35d5eeSXin Li # closing braces up to "{;,)<". We can't simply silence the 3591*8c35d5eeSXin Li # warning on first sight of closing brace, because that would 3592*8c35d5eeSXin Li # cause false negatives for things that are not initializer lists. 3593*8c35d5eeSXin Li # Silence this: But not this: 3594*8c35d5eeSXin Li # Outer{ if (...) { 3595*8c35d5eeSXin Li # Inner{...} if (...){ // Missing space before { 3596*8c35d5eeSXin Li # }; } 3597*8c35d5eeSXin Li # 3598*8c35d5eeSXin Li # There is a false negative with this approach if people inserted 3599*8c35d5eeSXin Li # spurious semicolons, e.g. "if (cond){};", but we will catch the 3600*8c35d5eeSXin Li # spurious semicolon with a separate check. 3601*8c35d5eeSXin Li leading_text = match.group(1) 3602*8c35d5eeSXin Li (endline, endlinenum, endpos) = CloseExpression( 3603*8c35d5eeSXin Li clean_lines, linenum, len(match.group(1))) 3604*8c35d5eeSXin Li trailing_text = '' 3605*8c35d5eeSXin Li if endpos > -1: 3606*8c35d5eeSXin Li trailing_text = endline[endpos:] 3607*8c35d5eeSXin Li for offset in xrange(endlinenum + 1, 3608*8c35d5eeSXin Li min(endlinenum + 3, clean_lines.NumLines() - 1)): 3609*8c35d5eeSXin Li trailing_text += clean_lines.elided[offset] 3610*8c35d5eeSXin Li # We also suppress warnings for `uint64_t{expression}` etc., as the style 3611*8c35d5eeSXin Li # guide recommends brace initialization for integral types to avoid 3612*8c35d5eeSXin Li # overflow/truncation. 3613*8c35d5eeSXin Li if (not Match(r'^[\s}]*[{.;,)<>\]:]', trailing_text) 3614*8c35d5eeSXin Li and not _IsType(clean_lines, nesting_state, leading_text)): 3615*8c35d5eeSXin Li error(filename, linenum, 'whitespace/braces', 5, 3616*8c35d5eeSXin Li 'Missing space before {') 3617*8c35d5eeSXin Li 3618*8c35d5eeSXin Li # Make sure '} else {' has spaces. 3619*8c35d5eeSXin Li if Search(r'}else', line): 3620*8c35d5eeSXin Li error(filename, linenum, 'whitespace/braces', 5, 3621*8c35d5eeSXin Li 'Missing space before else') 3622*8c35d5eeSXin Li 3623*8c35d5eeSXin Li # You shouldn't have a space before a semicolon at the end of the line. 3624*8c35d5eeSXin Li # There's a special case for "for" since the style guide allows space before 3625*8c35d5eeSXin Li # the semicolon there. 3626*8c35d5eeSXin Li if Search(r':\s*;\s*$', line): 3627*8c35d5eeSXin Li error(filename, linenum, 'whitespace/semicolon', 5, 3628*8c35d5eeSXin Li 'Semicolon defining empty statement. Use {} instead.') 3629*8c35d5eeSXin Li elif Search(r'^\s*;\s*$', line): 3630*8c35d5eeSXin Li error(filename, linenum, 'whitespace/semicolon', 5, 3631*8c35d5eeSXin Li 'Line contains only semicolon. If this should be an empty statement, ' 3632*8c35d5eeSXin Li 'use {} instead.') 3633*8c35d5eeSXin Li elif (Search(r'\s+;\s*$', line) and 3634*8c35d5eeSXin Li not Search(r'\bfor\b', line)): 3635*8c35d5eeSXin Li error(filename, linenum, 'whitespace/semicolon', 5, 3636*8c35d5eeSXin Li 'Extra space before last semicolon. If this should be an empty ' 3637*8c35d5eeSXin Li 'statement, use {} instead.') 3638*8c35d5eeSXin Li 3639*8c35d5eeSXin Li 3640*8c35d5eeSXin Lidef IsDecltype(clean_lines, linenum, column): 3641*8c35d5eeSXin Li """Check if the token ending on (linenum, column) is decltype(). 3642*8c35d5eeSXin Li 3643*8c35d5eeSXin Li Args: 3644*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 3645*8c35d5eeSXin Li linenum: the number of the line to check. 3646*8c35d5eeSXin Li column: end column of the token to check. 3647*8c35d5eeSXin Li Returns: 3648*8c35d5eeSXin Li True if this token is decltype() expression, False otherwise. 3649*8c35d5eeSXin Li """ 3650*8c35d5eeSXin Li (text, _, start_col) = ReverseCloseExpression(clean_lines, linenum, column) 3651*8c35d5eeSXin Li if start_col < 0: 3652*8c35d5eeSXin Li return False 3653*8c35d5eeSXin Li if Search(r'\bdecltype\s*$', text[0:start_col]): 3654*8c35d5eeSXin Li return True 3655*8c35d5eeSXin Li return False 3656*8c35d5eeSXin Li 3657*8c35d5eeSXin Li 3658*8c35d5eeSXin Lidef CheckSectionSpacing(filename, clean_lines, class_info, linenum, error): 3659*8c35d5eeSXin Li """Checks for additional blank line issues related to sections. 3660*8c35d5eeSXin Li 3661*8c35d5eeSXin Li Currently the only thing checked here is blank line before protected/private. 3662*8c35d5eeSXin Li 3663*8c35d5eeSXin Li Args: 3664*8c35d5eeSXin Li filename: The name of the current file. 3665*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 3666*8c35d5eeSXin Li class_info: A _ClassInfo objects. 3667*8c35d5eeSXin Li linenum: The number of the line to check. 3668*8c35d5eeSXin Li error: The function to call with any errors found. 3669*8c35d5eeSXin Li """ 3670*8c35d5eeSXin Li # Skip checks if the class is small, where small means 25 lines or less. 3671*8c35d5eeSXin Li # 25 lines seems like a good cutoff since that's the usual height of 3672*8c35d5eeSXin Li # terminals, and any class that can't fit in one screen can't really 3673*8c35d5eeSXin Li # be considered "small". 3674*8c35d5eeSXin Li # 3675*8c35d5eeSXin Li # Also skip checks if we are on the first line. This accounts for 3676*8c35d5eeSXin Li # classes that look like 3677*8c35d5eeSXin Li # class Foo { public: ... }; 3678*8c35d5eeSXin Li # 3679*8c35d5eeSXin Li # If we didn't find the end of the class, last_line would be zero, 3680*8c35d5eeSXin Li # and the check will be skipped by the first condition. 3681*8c35d5eeSXin Li if (class_info.last_line - class_info.starting_linenum <= 24 or 3682*8c35d5eeSXin Li linenum <= class_info.starting_linenum): 3683*8c35d5eeSXin Li return 3684*8c35d5eeSXin Li 3685*8c35d5eeSXin Li matched = Match(r'\s*(public|protected|private):', clean_lines.lines[linenum]) 3686*8c35d5eeSXin Li if matched: 3687*8c35d5eeSXin Li # Issue warning if the line before public/protected/private was 3688*8c35d5eeSXin Li # not a blank line, but don't do this if the previous line contains 3689*8c35d5eeSXin Li # "class" or "struct". This can happen two ways: 3690*8c35d5eeSXin Li # - We are at the beginning of the class. 3691*8c35d5eeSXin Li # - We are forward-declaring an inner class that is semantically 3692*8c35d5eeSXin Li # private, but needed to be public for implementation reasons. 3693*8c35d5eeSXin Li # Also ignores cases where the previous line ends with a backslash as can be 3694*8c35d5eeSXin Li # common when defining classes in C macros. 3695*8c35d5eeSXin Li prev_line = clean_lines.lines[linenum - 1] 3696*8c35d5eeSXin Li if (not IsBlankLine(prev_line) and 3697*8c35d5eeSXin Li not Search(r'\b(class|struct)\b', prev_line) and 3698*8c35d5eeSXin Li not Search(r'\\$', prev_line)): 3699*8c35d5eeSXin Li # Try a bit harder to find the beginning of the class. This is to 3700*8c35d5eeSXin Li # account for multi-line base-specifier lists, e.g.: 3701*8c35d5eeSXin Li # class Derived 3702*8c35d5eeSXin Li # : public Base { 3703*8c35d5eeSXin Li end_class_head = class_info.starting_linenum 3704*8c35d5eeSXin Li for i in range(class_info.starting_linenum, linenum): 3705*8c35d5eeSXin Li if Search(r'\{\s*$', clean_lines.lines[i]): 3706*8c35d5eeSXin Li end_class_head = i 3707*8c35d5eeSXin Li break 3708*8c35d5eeSXin Li if end_class_head < linenum - 1: 3709*8c35d5eeSXin Li error(filename, linenum, 'whitespace/blank_line', 3, 3710*8c35d5eeSXin Li '"%s:" should be preceded by a blank line' % matched.group(1)) 3711*8c35d5eeSXin Li 3712*8c35d5eeSXin Li 3713*8c35d5eeSXin Lidef GetPreviousNonBlankLine(clean_lines, linenum): 3714*8c35d5eeSXin Li """Return the most recent non-blank line and its line number. 3715*8c35d5eeSXin Li 3716*8c35d5eeSXin Li Args: 3717*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file contents. 3718*8c35d5eeSXin Li linenum: The number of the line to check. 3719*8c35d5eeSXin Li 3720*8c35d5eeSXin Li Returns: 3721*8c35d5eeSXin Li A tuple with two elements. The first element is the contents of the last 3722*8c35d5eeSXin Li non-blank line before the current line, or the empty string if this is the 3723*8c35d5eeSXin Li first non-blank line. The second is the line number of that line, or -1 3724*8c35d5eeSXin Li if this is the first non-blank line. 3725*8c35d5eeSXin Li """ 3726*8c35d5eeSXin Li 3727*8c35d5eeSXin Li prevlinenum = linenum - 1 3728*8c35d5eeSXin Li while prevlinenum >= 0: 3729*8c35d5eeSXin Li prevline = clean_lines.elided[prevlinenum] 3730*8c35d5eeSXin Li if not IsBlankLine(prevline): # if not a blank line... 3731*8c35d5eeSXin Li return (prevline, prevlinenum) 3732*8c35d5eeSXin Li prevlinenum -= 1 3733*8c35d5eeSXin Li return ('', -1) 3734*8c35d5eeSXin Li 3735*8c35d5eeSXin Li 3736*8c35d5eeSXin Lidef CheckBraces(filename, clean_lines, linenum, error): 3737*8c35d5eeSXin Li """Looks for misplaced braces (e.g. at the end of line). 3738*8c35d5eeSXin Li 3739*8c35d5eeSXin Li Args: 3740*8c35d5eeSXin Li filename: The name of the current file. 3741*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 3742*8c35d5eeSXin Li linenum: The number of the line to check. 3743*8c35d5eeSXin Li error: The function to call with any errors found. 3744*8c35d5eeSXin Li """ 3745*8c35d5eeSXin Li 3746*8c35d5eeSXin Li line = clean_lines.elided[linenum] # get rid of comments and strings 3747*8c35d5eeSXin Li 3748*8c35d5eeSXin Li if Match(r'\s*{\s*$', line): 3749*8c35d5eeSXin Li # We allow an open brace to start a line in the case where someone is using 3750*8c35d5eeSXin Li # braces in a block to explicitly create a new scope, which is commonly used 3751*8c35d5eeSXin Li # to control the lifetime of stack-allocated variables. Braces are also 3752*8c35d5eeSXin Li # used for brace initializers inside function calls. We don't detect this 3753*8c35d5eeSXin Li # perfectly: we just don't complain if the last non-whitespace character on 3754*8c35d5eeSXin Li # the previous non-blank line is ',', ';', ':', '(', '{', or '}', or if the 3755*8c35d5eeSXin Li # previous line starts a preprocessor block. We also allow a brace on the 3756*8c35d5eeSXin Li # following line if it is part of an array initialization and would not fit 3757*8c35d5eeSXin Li # within the 80 character limit of the preceding line. 3758*8c35d5eeSXin Li prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] 3759*8c35d5eeSXin Li if (not Search(r'[,;:}{(]\s*$', prevline) and 3760*8c35d5eeSXin Li not Match(r'\s*#', prevline) and 3761*8c35d5eeSXin Li not (GetLineWidth(prevline) > _line_length - 2 and '[]' in prevline)): 3762*8c35d5eeSXin Li error(filename, linenum, 'whitespace/braces', 4, 3763*8c35d5eeSXin Li '{ should almost always be at the end of the previous line') 3764*8c35d5eeSXin Li 3765*8c35d5eeSXin Li # An else clause should be on the same line as the preceding closing brace. 3766*8c35d5eeSXin Li if Match(r'\s*else\b\s*(?:if\b|\{|$)', line): 3767*8c35d5eeSXin Li prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] 3768*8c35d5eeSXin Li if Match(r'\s*}\s*$', prevline): 3769*8c35d5eeSXin Li error(filename, linenum, 'whitespace/newline', 4, 3770*8c35d5eeSXin Li 'An else should appear on the same line as the preceding }') 3771*8c35d5eeSXin Li 3772*8c35d5eeSXin Li # If braces come on one side of an else, they should be on both. 3773*8c35d5eeSXin Li # However, we have to worry about "else if" that spans multiple lines! 3774*8c35d5eeSXin Li if Search(r'else if\s*\(', line): # could be multi-line if 3775*8c35d5eeSXin Li brace_on_left = bool(Search(r'}\s*else if\s*\(', line)) 3776*8c35d5eeSXin Li # find the ( after the if 3777*8c35d5eeSXin Li pos = line.find('else if') 3778*8c35d5eeSXin Li pos = line.find('(', pos) 3779*8c35d5eeSXin Li if pos > 0: 3780*8c35d5eeSXin Li (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos) 3781*8c35d5eeSXin Li brace_on_right = endline[endpos:].find('{') != -1 3782*8c35d5eeSXin Li if brace_on_left != brace_on_right: # must be brace after if 3783*8c35d5eeSXin Li error(filename, linenum, 'readability/braces', 5, 3784*8c35d5eeSXin Li 'If an else has a brace on one side, it should have it on both') 3785*8c35d5eeSXin Li elif Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line): 3786*8c35d5eeSXin Li error(filename, linenum, 'readability/braces', 5, 3787*8c35d5eeSXin Li 'If an else has a brace on one side, it should have it on both') 3788*8c35d5eeSXin Li 3789*8c35d5eeSXin Li # Likewise, an else should never have the else clause on the same line 3790*8c35d5eeSXin Li if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line): 3791*8c35d5eeSXin Li error(filename, linenum, 'whitespace/newline', 4, 3792*8c35d5eeSXin Li 'Else clause should never be on same line as else (use 2 lines)') 3793*8c35d5eeSXin Li 3794*8c35d5eeSXin Li # In the same way, a do/while should never be on one line 3795*8c35d5eeSXin Li if Match(r'\s*do [^\s{]', line): 3796*8c35d5eeSXin Li error(filename, linenum, 'whitespace/newline', 4, 3797*8c35d5eeSXin Li 'do/while clauses should not be on a single line') 3798*8c35d5eeSXin Li 3799*8c35d5eeSXin Li # Check single-line if/else bodies. The style guide says 'curly braces are not 3800*8c35d5eeSXin Li # required for single-line statements'. We additionally allow multi-line, 3801*8c35d5eeSXin Li # single statements, but we reject anything with more than one semicolon in 3802*8c35d5eeSXin Li # it. This means that the first semicolon after the if should be at the end of 3803*8c35d5eeSXin Li # its line, and the line after that should have an indent level equal to or 3804*8c35d5eeSXin Li # lower than the if. We also check for ambiguous if/else nesting without 3805*8c35d5eeSXin Li # braces. 3806*8c35d5eeSXin Li if_else_match = Search(r'\b(if\s*\(|else\b)', line) 3807*8c35d5eeSXin Li if if_else_match and not Match(r'\s*#', line): 3808*8c35d5eeSXin Li if_indent = GetIndentLevel(line) 3809*8c35d5eeSXin Li endline, endlinenum, endpos = line, linenum, if_else_match.end() 3810*8c35d5eeSXin Li if_match = Search(r'\bif\s*\(', line) 3811*8c35d5eeSXin Li if if_match: 3812*8c35d5eeSXin Li # This could be a multiline if condition, so find the end first. 3813*8c35d5eeSXin Li pos = if_match.end() - 1 3814*8c35d5eeSXin Li (endline, endlinenum, endpos) = CloseExpression(clean_lines, linenum, pos) 3815*8c35d5eeSXin Li # Check for an opening brace, either directly after the if or on the next 3816*8c35d5eeSXin Li # line. If found, this isn't a single-statement conditional. 3817*8c35d5eeSXin Li if (not Match(r'\s*{', endline[endpos:]) 3818*8c35d5eeSXin Li and not (Match(r'\s*$', endline[endpos:]) 3819*8c35d5eeSXin Li and endlinenum < (len(clean_lines.elided) - 1) 3820*8c35d5eeSXin Li and Match(r'\s*{', clean_lines.elided[endlinenum + 1]))): 3821*8c35d5eeSXin Li while (endlinenum < len(clean_lines.elided) 3822*8c35d5eeSXin Li and ';' not in clean_lines.elided[endlinenum][endpos:]): 3823*8c35d5eeSXin Li endlinenum += 1 3824*8c35d5eeSXin Li endpos = 0 3825*8c35d5eeSXin Li if endlinenum < len(clean_lines.elided): 3826*8c35d5eeSXin Li endline = clean_lines.elided[endlinenum] 3827*8c35d5eeSXin Li # We allow a mix of whitespace and closing braces (e.g. for one-liner 3828*8c35d5eeSXin Li # methods) and a single \ after the semicolon (for macros) 3829*8c35d5eeSXin Li endpos = endline.find(';') 3830*8c35d5eeSXin Li if not Match(r';[\s}]*(\\?)$', endline[endpos:]): 3831*8c35d5eeSXin Li # Semicolon isn't the last character, there's something trailing. 3832*8c35d5eeSXin Li # Output a warning if the semicolon is not contained inside 3833*8c35d5eeSXin Li # a lambda expression. 3834*8c35d5eeSXin Li if not Match(r'^[^{};]*\[[^\[\]]*\][^{}]*\{[^{}]*\}\s*\)*[;,]\s*$', 3835*8c35d5eeSXin Li endline): 3836*8c35d5eeSXin Li error(filename, linenum, 'readability/braces', 4, 3837*8c35d5eeSXin Li 'If/else bodies with multiple statements require braces') 3838*8c35d5eeSXin Li elif endlinenum < len(clean_lines.elided) - 1: 3839*8c35d5eeSXin Li # Make sure the next line is dedented 3840*8c35d5eeSXin Li next_line = clean_lines.elided[endlinenum + 1] 3841*8c35d5eeSXin Li next_indent = GetIndentLevel(next_line) 3842*8c35d5eeSXin Li # With ambiguous nested if statements, this will error out on the 3843*8c35d5eeSXin Li # if that *doesn't* match the else, regardless of whether it's the 3844*8c35d5eeSXin Li # inner one or outer one. 3845*8c35d5eeSXin Li if (if_match and Match(r'\s*else\b', next_line) 3846*8c35d5eeSXin Li and next_indent != if_indent): 3847*8c35d5eeSXin Li error(filename, linenum, 'readability/braces', 4, 3848*8c35d5eeSXin Li 'Else clause should be indented at the same level as if. ' 3849*8c35d5eeSXin Li 'Ambiguous nested if/else chains require braces.') 3850*8c35d5eeSXin Li elif next_indent > if_indent: 3851*8c35d5eeSXin Li error(filename, linenum, 'readability/braces', 4, 3852*8c35d5eeSXin Li 'If/else bodies with multiple statements require braces') 3853*8c35d5eeSXin Li 3854*8c35d5eeSXin Li 3855*8c35d5eeSXin Lidef CheckTrailingSemicolon(filename, clean_lines, linenum, error): 3856*8c35d5eeSXin Li """Looks for redundant trailing semicolon. 3857*8c35d5eeSXin Li 3858*8c35d5eeSXin Li Args: 3859*8c35d5eeSXin Li filename: The name of the current file. 3860*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 3861*8c35d5eeSXin Li linenum: The number of the line to check. 3862*8c35d5eeSXin Li error: The function to call with any errors found. 3863*8c35d5eeSXin Li """ 3864*8c35d5eeSXin Li 3865*8c35d5eeSXin Li line = clean_lines.elided[linenum] 3866*8c35d5eeSXin Li 3867*8c35d5eeSXin Li # Block bodies should not be followed by a semicolon. Due to C++11 3868*8c35d5eeSXin Li # brace initialization, there are more places where semicolons are 3869*8c35d5eeSXin Li # required than not, so we use a whitelist approach to check these 3870*8c35d5eeSXin Li # rather than a blacklist. These are the places where "};" should 3871*8c35d5eeSXin Li # be replaced by just "}": 3872*8c35d5eeSXin Li # 1. Some flavor of block following closing parenthesis: 3873*8c35d5eeSXin Li # for (;;) {}; 3874*8c35d5eeSXin Li # while (...) {}; 3875*8c35d5eeSXin Li # switch (...) {}; 3876*8c35d5eeSXin Li # Function(...) {}; 3877*8c35d5eeSXin Li # if (...) {}; 3878*8c35d5eeSXin Li # if (...) else if (...) {}; 3879*8c35d5eeSXin Li # 3880*8c35d5eeSXin Li # 2. else block: 3881*8c35d5eeSXin Li # if (...) else {}; 3882*8c35d5eeSXin Li # 3883*8c35d5eeSXin Li # 3. const member function: 3884*8c35d5eeSXin Li # Function(...) const {}; 3885*8c35d5eeSXin Li # 3886*8c35d5eeSXin Li # 4. Block following some statement: 3887*8c35d5eeSXin Li # x = 42; 3888*8c35d5eeSXin Li # {}; 3889*8c35d5eeSXin Li # 3890*8c35d5eeSXin Li # 5. Block at the beginning of a function: 3891*8c35d5eeSXin Li # Function(...) { 3892*8c35d5eeSXin Li # {}; 3893*8c35d5eeSXin Li # } 3894*8c35d5eeSXin Li # 3895*8c35d5eeSXin Li # Note that naively checking for the preceding "{" will also match 3896*8c35d5eeSXin Li # braces inside multi-dimensional arrays, but this is fine since 3897*8c35d5eeSXin Li # that expression will not contain semicolons. 3898*8c35d5eeSXin Li # 3899*8c35d5eeSXin Li # 6. Block following another block: 3900*8c35d5eeSXin Li # while (true) {} 3901*8c35d5eeSXin Li # {}; 3902*8c35d5eeSXin Li # 3903*8c35d5eeSXin Li # 7. End of namespaces: 3904*8c35d5eeSXin Li # namespace {}; 3905*8c35d5eeSXin Li # 3906*8c35d5eeSXin Li # These semicolons seems far more common than other kinds of 3907*8c35d5eeSXin Li # redundant semicolons, possibly due to people converting classes 3908*8c35d5eeSXin Li # to namespaces. For now we do not warn for this case. 3909*8c35d5eeSXin Li # 3910*8c35d5eeSXin Li # Try matching case 1 first. 3911*8c35d5eeSXin Li match = Match(r'^(.*\)\s*)\{', line) 3912*8c35d5eeSXin Li if match: 3913*8c35d5eeSXin Li # Matched closing parenthesis (case 1). Check the token before the 3914*8c35d5eeSXin Li # matching opening parenthesis, and don't warn if it looks like a 3915*8c35d5eeSXin Li # macro. This avoids these false positives: 3916*8c35d5eeSXin Li # - macro that defines a base class 3917*8c35d5eeSXin Li # - multi-line macro that defines a base class 3918*8c35d5eeSXin Li # - macro that defines the whole class-head 3919*8c35d5eeSXin Li # 3920*8c35d5eeSXin Li # But we still issue warnings for macros that we know are safe to 3921*8c35d5eeSXin Li # warn, specifically: 3922*8c35d5eeSXin Li # - TEST, TEST_F, TEST_P, MATCHER, MATCHER_P 3923*8c35d5eeSXin Li # - TYPED_TEST 3924*8c35d5eeSXin Li # - INTERFACE_DEF 3925*8c35d5eeSXin Li # - EXCLUSIVE_LOCKS_REQUIRED, SHARED_LOCKS_REQUIRED, LOCKS_EXCLUDED: 3926*8c35d5eeSXin Li # 3927*8c35d5eeSXin Li # We implement a whitelist of safe macros instead of a blacklist of 3928*8c35d5eeSXin Li # unsafe macros, even though the latter appears less frequently in 3929*8c35d5eeSXin Li # google code and would have been easier to implement. This is because 3930*8c35d5eeSXin Li # the downside for getting the whitelist wrong means some extra 3931*8c35d5eeSXin Li # semicolons, while the downside for getting the blacklist wrong 3932*8c35d5eeSXin Li # would result in compile errors. 3933*8c35d5eeSXin Li # 3934*8c35d5eeSXin Li # In addition to macros, we also don't want to warn on 3935*8c35d5eeSXin Li # - Compound literals 3936*8c35d5eeSXin Li # - Lambdas 3937*8c35d5eeSXin Li # - alignas specifier with anonymous structs 3938*8c35d5eeSXin Li # - decltype 3939*8c35d5eeSXin Li closing_brace_pos = match.group(1).rfind(')') 3940*8c35d5eeSXin Li opening_parenthesis = ReverseCloseExpression( 3941*8c35d5eeSXin Li clean_lines, linenum, closing_brace_pos) 3942*8c35d5eeSXin Li if opening_parenthesis[2] > -1: 3943*8c35d5eeSXin Li line_prefix = opening_parenthesis[0][0:opening_parenthesis[2]] 3944*8c35d5eeSXin Li macro = Search(r'\b([A-Z_][A-Z0-9_]*)\s*$', line_prefix) 3945*8c35d5eeSXin Li func = Match(r'^(.*\])\s*$', line_prefix) 3946*8c35d5eeSXin Li if ((macro and 3947*8c35d5eeSXin Li macro.group(1) not in ( 3948*8c35d5eeSXin Li 'TEST', 'TEST_F', 'MATCHER', 'MATCHER_P', 'TYPED_TEST', 3949*8c35d5eeSXin Li 'EXCLUSIVE_LOCKS_REQUIRED', 'SHARED_LOCKS_REQUIRED', 3950*8c35d5eeSXin Li 'LOCKS_EXCLUDED', 'INTERFACE_DEF')) or 3951*8c35d5eeSXin Li (func and not Search(r'\boperator\s*\[\s*\]', func.group(1))) or 3952*8c35d5eeSXin Li Search(r'\b(?:struct|union)\s+alignas\s*$', line_prefix) or 3953*8c35d5eeSXin Li Search(r'\bdecltype$', line_prefix) or 3954*8c35d5eeSXin Li Search(r'\s+=\s*$', line_prefix)): 3955*8c35d5eeSXin Li match = None 3956*8c35d5eeSXin Li if (match and 3957*8c35d5eeSXin Li opening_parenthesis[1] > 1 and 3958*8c35d5eeSXin Li Search(r'\]\s*$', clean_lines.elided[opening_parenthesis[1] - 1])): 3959*8c35d5eeSXin Li # Multi-line lambda-expression 3960*8c35d5eeSXin Li match = None 3961*8c35d5eeSXin Li 3962*8c35d5eeSXin Li else: 3963*8c35d5eeSXin Li # Try matching cases 2-3. 3964*8c35d5eeSXin Li match = Match(r'^(.*(?:else|\)\s*const)\s*)\{', line) 3965*8c35d5eeSXin Li if not match: 3966*8c35d5eeSXin Li # Try matching cases 4-6. These are always matched on separate lines. 3967*8c35d5eeSXin Li # 3968*8c35d5eeSXin Li # Note that we can't simply concatenate the previous line to the 3969*8c35d5eeSXin Li # current line and do a single match, otherwise we may output 3970*8c35d5eeSXin Li # duplicate warnings for the blank line case: 3971*8c35d5eeSXin Li # if (cond) { 3972*8c35d5eeSXin Li # // blank line 3973*8c35d5eeSXin Li # } 3974*8c35d5eeSXin Li prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] 3975*8c35d5eeSXin Li if prevline and Search(r'[;{}]\s*$', prevline): 3976*8c35d5eeSXin Li match = Match(r'^(\s*)\{', line) 3977*8c35d5eeSXin Li 3978*8c35d5eeSXin Li # Check matching closing brace 3979*8c35d5eeSXin Li if match: 3980*8c35d5eeSXin Li (endline, endlinenum, endpos) = CloseExpression( 3981*8c35d5eeSXin Li clean_lines, linenum, len(match.group(1))) 3982*8c35d5eeSXin Li if endpos > -1 and Match(r'^\s*;', endline[endpos:]): 3983*8c35d5eeSXin Li # Current {} pair is eligible for semicolon check, and we have found 3984*8c35d5eeSXin Li # the redundant semicolon, output warning here. 3985*8c35d5eeSXin Li # 3986*8c35d5eeSXin Li # Note: because we are scanning forward for opening braces, and 3987*8c35d5eeSXin Li # outputting warnings for the matching closing brace, if there are 3988*8c35d5eeSXin Li # nested blocks with trailing semicolons, we will get the error 3989*8c35d5eeSXin Li # messages in reversed order. 3990*8c35d5eeSXin Li 3991*8c35d5eeSXin Li # We need to check the line forward for NOLINT 3992*8c35d5eeSXin Li raw_lines = clean_lines.raw_lines 3993*8c35d5eeSXin Li ParseNolintSuppressions(filename, raw_lines[endlinenum-1], endlinenum-1, 3994*8c35d5eeSXin Li error) 3995*8c35d5eeSXin Li ParseNolintSuppressions(filename, raw_lines[endlinenum], endlinenum, 3996*8c35d5eeSXin Li error) 3997*8c35d5eeSXin Li 3998*8c35d5eeSXin Li error(filename, endlinenum, 'readability/braces', 4, 3999*8c35d5eeSXin Li "You don't need a ; after a }") 4000*8c35d5eeSXin Li 4001*8c35d5eeSXin Li 4002*8c35d5eeSXin Lidef CheckEmptyBlockBody(filename, clean_lines, linenum, error): 4003*8c35d5eeSXin Li """Look for empty loop/conditional body with only a single semicolon. 4004*8c35d5eeSXin Li 4005*8c35d5eeSXin Li Args: 4006*8c35d5eeSXin Li filename: The name of the current file. 4007*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 4008*8c35d5eeSXin Li linenum: The number of the line to check. 4009*8c35d5eeSXin Li error: The function to call with any errors found. 4010*8c35d5eeSXin Li """ 4011*8c35d5eeSXin Li 4012*8c35d5eeSXin Li # Search for loop keywords at the beginning of the line. Because only 4013*8c35d5eeSXin Li # whitespaces are allowed before the keywords, this will also ignore most 4014*8c35d5eeSXin Li # do-while-loops, since those lines should start with closing brace. 4015*8c35d5eeSXin Li # 4016*8c35d5eeSXin Li # We also check "if" blocks here, since an empty conditional block 4017*8c35d5eeSXin Li # is likely an error. 4018*8c35d5eeSXin Li line = clean_lines.elided[linenum] 4019*8c35d5eeSXin Li matched = Match(r'\s*(for|while|if)\s*\(', line) 4020*8c35d5eeSXin Li if matched: 4021*8c35d5eeSXin Li # Find the end of the conditional expression. 4022*8c35d5eeSXin Li (end_line, end_linenum, end_pos) = CloseExpression( 4023*8c35d5eeSXin Li clean_lines, linenum, line.find('(')) 4024*8c35d5eeSXin Li 4025*8c35d5eeSXin Li # Output warning if what follows the condition expression is a semicolon. 4026*8c35d5eeSXin Li # No warning for all other cases, including whitespace or newline, since we 4027*8c35d5eeSXin Li # have a separate check for semicolons preceded by whitespace. 4028*8c35d5eeSXin Li if end_pos >= 0 and Match(r';', end_line[end_pos:]): 4029*8c35d5eeSXin Li if matched.group(1) == 'if': 4030*8c35d5eeSXin Li error(filename, end_linenum, 'whitespace/empty_conditional_body', 5, 4031*8c35d5eeSXin Li 'Empty conditional bodies should use {}') 4032*8c35d5eeSXin Li else: 4033*8c35d5eeSXin Li error(filename, end_linenum, 'whitespace/empty_loop_body', 5, 4034*8c35d5eeSXin Li 'Empty loop bodies should use {} or continue') 4035*8c35d5eeSXin Li 4036*8c35d5eeSXin Li # Check for if statements that have completely empty bodies (no comments) 4037*8c35d5eeSXin Li # and no else clauses. 4038*8c35d5eeSXin Li if end_pos >= 0 and matched.group(1) == 'if': 4039*8c35d5eeSXin Li # Find the position of the opening { for the if statement. 4040*8c35d5eeSXin Li # Return without logging an error if it has no brackets. 4041*8c35d5eeSXin Li opening_linenum = end_linenum 4042*8c35d5eeSXin Li opening_line_fragment = end_line[end_pos:] 4043*8c35d5eeSXin Li # Loop until EOF or find anything that's not whitespace or opening {. 4044*8c35d5eeSXin Li while not Search(r'^\s*\{', opening_line_fragment): 4045*8c35d5eeSXin Li if Search(r'^(?!\s*$)', opening_line_fragment): 4046*8c35d5eeSXin Li # Conditional has no brackets. 4047*8c35d5eeSXin Li return 4048*8c35d5eeSXin Li opening_linenum += 1 4049*8c35d5eeSXin Li if opening_linenum == len(clean_lines.elided): 4050*8c35d5eeSXin Li # Couldn't find conditional's opening { or any code before EOF. 4051*8c35d5eeSXin Li return 4052*8c35d5eeSXin Li opening_line_fragment = clean_lines.elided[opening_linenum] 4053*8c35d5eeSXin Li # Set opening_line (opening_line_fragment may not be entire opening line). 4054*8c35d5eeSXin Li opening_line = clean_lines.elided[opening_linenum] 4055*8c35d5eeSXin Li 4056*8c35d5eeSXin Li # Find the position of the closing }. 4057*8c35d5eeSXin Li opening_pos = opening_line_fragment.find('{') 4058*8c35d5eeSXin Li if opening_linenum == end_linenum: 4059*8c35d5eeSXin Li # We need to make opening_pos relative to the start of the entire line. 4060*8c35d5eeSXin Li opening_pos += end_pos 4061*8c35d5eeSXin Li (closing_line, closing_linenum, closing_pos) = CloseExpression( 4062*8c35d5eeSXin Li clean_lines, opening_linenum, opening_pos) 4063*8c35d5eeSXin Li if closing_pos < 0: 4064*8c35d5eeSXin Li return 4065*8c35d5eeSXin Li 4066*8c35d5eeSXin Li # Now construct the body of the conditional. This consists of the portion 4067*8c35d5eeSXin Li # of the opening line after the {, all lines until the closing line, 4068*8c35d5eeSXin Li # and the portion of the closing line before the }. 4069*8c35d5eeSXin Li if (clean_lines.raw_lines[opening_linenum] != 4070*8c35d5eeSXin Li CleanseComments(clean_lines.raw_lines[opening_linenum])): 4071*8c35d5eeSXin Li # Opening line ends with a comment, so conditional isn't empty. 4072*8c35d5eeSXin Li return 4073*8c35d5eeSXin Li if closing_linenum > opening_linenum: 4074*8c35d5eeSXin Li # Opening line after the {. Ignore comments here since we checked above. 4075*8c35d5eeSXin Li body = list(opening_line[opening_pos+1:]) 4076*8c35d5eeSXin Li # All lines until closing line, excluding closing line, with comments. 4077*8c35d5eeSXin Li body.extend(clean_lines.raw_lines[opening_linenum+1:closing_linenum]) 4078*8c35d5eeSXin Li # Closing line before the }. Won't (and can't) have comments. 4079*8c35d5eeSXin Li body.append(clean_lines.elided[closing_linenum][:closing_pos-1]) 4080*8c35d5eeSXin Li body = '\n'.join(body) 4081*8c35d5eeSXin Li else: 4082*8c35d5eeSXin Li # If statement has brackets and fits on a single line. 4083*8c35d5eeSXin Li body = opening_line[opening_pos+1:closing_pos-1] 4084*8c35d5eeSXin Li 4085*8c35d5eeSXin Li # Check if the body is empty 4086*8c35d5eeSXin Li if not _EMPTY_CONDITIONAL_BODY_PATTERN.search(body): 4087*8c35d5eeSXin Li return 4088*8c35d5eeSXin Li # The body is empty. Now make sure there's not an else clause. 4089*8c35d5eeSXin Li current_linenum = closing_linenum 4090*8c35d5eeSXin Li current_line_fragment = closing_line[closing_pos:] 4091*8c35d5eeSXin Li # Loop until EOF or find anything that's not whitespace or else clause. 4092*8c35d5eeSXin Li while Search(r'^\s*$|^(?=\s*else)', current_line_fragment): 4093*8c35d5eeSXin Li if Search(r'^(?=\s*else)', current_line_fragment): 4094*8c35d5eeSXin Li # Found an else clause, so don't log an error. 4095*8c35d5eeSXin Li return 4096*8c35d5eeSXin Li current_linenum += 1 4097*8c35d5eeSXin Li if current_linenum == len(clean_lines.elided): 4098*8c35d5eeSXin Li break 4099*8c35d5eeSXin Li current_line_fragment = clean_lines.elided[current_linenum] 4100*8c35d5eeSXin Li 4101*8c35d5eeSXin Li # The body is empty and there's no else clause until EOF or other code. 4102*8c35d5eeSXin Li error(filename, end_linenum, 'whitespace/empty_if_body', 4, 4103*8c35d5eeSXin Li ('If statement had no body and no else clause')) 4104*8c35d5eeSXin Li 4105*8c35d5eeSXin Li 4106*8c35d5eeSXin Lidef FindCheckMacro(line): 4107*8c35d5eeSXin Li """Find a replaceable CHECK-like macro. 4108*8c35d5eeSXin Li 4109*8c35d5eeSXin Li Args: 4110*8c35d5eeSXin Li line: line to search on. 4111*8c35d5eeSXin Li Returns: 4112*8c35d5eeSXin Li (macro name, start position), or (None, -1) if no replaceable 4113*8c35d5eeSXin Li macro is found. 4114*8c35d5eeSXin Li """ 4115*8c35d5eeSXin Li for macro in _CHECK_MACROS: 4116*8c35d5eeSXin Li i = line.find(macro) 4117*8c35d5eeSXin Li if i >= 0: 4118*8c35d5eeSXin Li # Find opening parenthesis. Do a regular expression match here 4119*8c35d5eeSXin Li # to make sure that we are matching the expected CHECK macro, as 4120*8c35d5eeSXin Li # opposed to some other macro that happens to contain the CHECK 4121*8c35d5eeSXin Li # substring. 4122*8c35d5eeSXin Li matched = Match(r'^(.*\b' + macro + r'\s*)\(', line) 4123*8c35d5eeSXin Li if not matched: 4124*8c35d5eeSXin Li continue 4125*8c35d5eeSXin Li return (macro, len(matched.group(1))) 4126*8c35d5eeSXin Li return (None, -1) 4127*8c35d5eeSXin Li 4128*8c35d5eeSXin Li 4129*8c35d5eeSXin Lidef CheckCheck(filename, clean_lines, linenum, error): 4130*8c35d5eeSXin Li """Checks the use of CHECK and EXPECT macros. 4131*8c35d5eeSXin Li 4132*8c35d5eeSXin Li Args: 4133*8c35d5eeSXin Li filename: The name of the current file. 4134*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 4135*8c35d5eeSXin Li linenum: The number of the line to check. 4136*8c35d5eeSXin Li error: The function to call with any errors found. 4137*8c35d5eeSXin Li """ 4138*8c35d5eeSXin Li 4139*8c35d5eeSXin Li # Decide the set of replacement macros that should be suggested 4140*8c35d5eeSXin Li lines = clean_lines.elided 4141*8c35d5eeSXin Li (check_macro, start_pos) = FindCheckMacro(lines[linenum]) 4142*8c35d5eeSXin Li if not check_macro: 4143*8c35d5eeSXin Li return 4144*8c35d5eeSXin Li 4145*8c35d5eeSXin Li # Find end of the boolean expression by matching parentheses 4146*8c35d5eeSXin Li (last_line, end_line, end_pos) = CloseExpression( 4147*8c35d5eeSXin Li clean_lines, linenum, start_pos) 4148*8c35d5eeSXin Li if end_pos < 0: 4149*8c35d5eeSXin Li return 4150*8c35d5eeSXin Li 4151*8c35d5eeSXin Li # If the check macro is followed by something other than a 4152*8c35d5eeSXin Li # semicolon, assume users will log their own custom error messages 4153*8c35d5eeSXin Li # and don't suggest any replacements. 4154*8c35d5eeSXin Li if not Match(r'\s*;', last_line[end_pos:]): 4155*8c35d5eeSXin Li return 4156*8c35d5eeSXin Li 4157*8c35d5eeSXin Li if linenum == end_line: 4158*8c35d5eeSXin Li expression = lines[linenum][start_pos + 1:end_pos - 1] 4159*8c35d5eeSXin Li else: 4160*8c35d5eeSXin Li expression = lines[linenum][start_pos + 1:] 4161*8c35d5eeSXin Li for i in xrange(linenum + 1, end_line): 4162*8c35d5eeSXin Li expression += lines[i] 4163*8c35d5eeSXin Li expression += last_line[0:end_pos - 1] 4164*8c35d5eeSXin Li 4165*8c35d5eeSXin Li # Parse expression so that we can take parentheses into account. 4166*8c35d5eeSXin Li # This avoids false positives for inputs like "CHECK((a < 4) == b)", 4167*8c35d5eeSXin Li # which is not replaceable by CHECK_LE. 4168*8c35d5eeSXin Li lhs = '' 4169*8c35d5eeSXin Li rhs = '' 4170*8c35d5eeSXin Li operator = None 4171*8c35d5eeSXin Li while expression: 4172*8c35d5eeSXin Li matched = Match(r'^\s*(<<|<<=|>>|>>=|->\*|->|&&|\|\||' 4173*8c35d5eeSXin Li r'==|!=|>=|>|<=|<|\()(.*)$', expression) 4174*8c35d5eeSXin Li if matched: 4175*8c35d5eeSXin Li token = matched.group(1) 4176*8c35d5eeSXin Li if token == '(': 4177*8c35d5eeSXin Li # Parenthesized operand 4178*8c35d5eeSXin Li expression = matched.group(2) 4179*8c35d5eeSXin Li (end, _) = FindEndOfExpressionInLine(expression, 0, ['(']) 4180*8c35d5eeSXin Li if end < 0: 4181*8c35d5eeSXin Li return # Unmatched parenthesis 4182*8c35d5eeSXin Li lhs += '(' + expression[0:end] 4183*8c35d5eeSXin Li expression = expression[end:] 4184*8c35d5eeSXin Li elif token in ('&&', '||'): 4185*8c35d5eeSXin Li # Logical and/or operators. This means the expression 4186*8c35d5eeSXin Li # contains more than one term, for example: 4187*8c35d5eeSXin Li # CHECK(42 < a && a < b); 4188*8c35d5eeSXin Li # 4189*8c35d5eeSXin Li # These are not replaceable with CHECK_LE, so bail out early. 4190*8c35d5eeSXin Li return 4191*8c35d5eeSXin Li elif token in ('<<', '<<=', '>>', '>>=', '->*', '->'): 4192*8c35d5eeSXin Li # Non-relational operator 4193*8c35d5eeSXin Li lhs += token 4194*8c35d5eeSXin Li expression = matched.group(2) 4195*8c35d5eeSXin Li else: 4196*8c35d5eeSXin Li # Relational operator 4197*8c35d5eeSXin Li operator = token 4198*8c35d5eeSXin Li rhs = matched.group(2) 4199*8c35d5eeSXin Li break 4200*8c35d5eeSXin Li else: 4201*8c35d5eeSXin Li # Unparenthesized operand. Instead of appending to lhs one character 4202*8c35d5eeSXin Li # at a time, we do another regular expression match to consume several 4203*8c35d5eeSXin Li # characters at once if possible. Trivial benchmark shows that this 4204*8c35d5eeSXin Li # is more efficient when the operands are longer than a single 4205*8c35d5eeSXin Li # character, which is generally the case. 4206*8c35d5eeSXin Li matched = Match(r'^([^-=!<>()&|]+)(.*)$', expression) 4207*8c35d5eeSXin Li if not matched: 4208*8c35d5eeSXin Li matched = Match(r'^(\s*\S)(.*)$', expression) 4209*8c35d5eeSXin Li if not matched: 4210*8c35d5eeSXin Li break 4211*8c35d5eeSXin Li lhs += matched.group(1) 4212*8c35d5eeSXin Li expression = matched.group(2) 4213*8c35d5eeSXin Li 4214*8c35d5eeSXin Li # Only apply checks if we got all parts of the boolean expression 4215*8c35d5eeSXin Li if not (lhs and operator and rhs): 4216*8c35d5eeSXin Li return 4217*8c35d5eeSXin Li 4218*8c35d5eeSXin Li # Check that rhs do not contain logical operators. We already know 4219*8c35d5eeSXin Li # that lhs is fine since the loop above parses out && and ||. 4220*8c35d5eeSXin Li if rhs.find('&&') > -1 or rhs.find('||') > -1: 4221*8c35d5eeSXin Li return 4222*8c35d5eeSXin Li 4223*8c35d5eeSXin Li # At least one of the operands must be a constant literal. This is 4224*8c35d5eeSXin Li # to avoid suggesting replacements for unprintable things like 4225*8c35d5eeSXin Li # CHECK(variable != iterator) 4226*8c35d5eeSXin Li # 4227*8c35d5eeSXin Li # The following pattern matches decimal, hex integers, strings, and 4228*8c35d5eeSXin Li # characters (in that order). 4229*8c35d5eeSXin Li lhs = lhs.strip() 4230*8c35d5eeSXin Li rhs = rhs.strip() 4231*8c35d5eeSXin Li match_constant = r'^([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')$' 4232*8c35d5eeSXin Li if Match(match_constant, lhs) or Match(match_constant, rhs): 4233*8c35d5eeSXin Li # Note: since we know both lhs and rhs, we can provide a more 4234*8c35d5eeSXin Li # descriptive error message like: 4235*8c35d5eeSXin Li # Consider using CHECK_EQ(x, 42) instead of CHECK(x == 42) 4236*8c35d5eeSXin Li # Instead of: 4237*8c35d5eeSXin Li # Consider using CHECK_EQ instead of CHECK(a == b) 4238*8c35d5eeSXin Li # 4239*8c35d5eeSXin Li # We are still keeping the less descriptive message because if lhs 4240*8c35d5eeSXin Li # or rhs gets long, the error message might become unreadable. 4241*8c35d5eeSXin Li error(filename, linenum, 'readability/check', 2, 4242*8c35d5eeSXin Li 'Consider using %s instead of %s(a %s b)' % ( 4243*8c35d5eeSXin Li _CHECK_REPLACEMENT[check_macro][operator], 4244*8c35d5eeSXin Li check_macro, operator)) 4245*8c35d5eeSXin Li 4246*8c35d5eeSXin Li 4247*8c35d5eeSXin Lidef CheckAltTokens(filename, clean_lines, linenum, error): 4248*8c35d5eeSXin Li """Check alternative keywords being used in boolean expressions. 4249*8c35d5eeSXin Li 4250*8c35d5eeSXin Li Args: 4251*8c35d5eeSXin Li filename: The name of the current file. 4252*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 4253*8c35d5eeSXin Li linenum: The number of the line to check. 4254*8c35d5eeSXin Li error: The function to call with any errors found. 4255*8c35d5eeSXin Li """ 4256*8c35d5eeSXin Li line = clean_lines.elided[linenum] 4257*8c35d5eeSXin Li 4258*8c35d5eeSXin Li # Avoid preprocessor lines 4259*8c35d5eeSXin Li if Match(r'^\s*#', line): 4260*8c35d5eeSXin Li return 4261*8c35d5eeSXin Li 4262*8c35d5eeSXin Li # Last ditch effort to avoid multi-line comments. This will not help 4263*8c35d5eeSXin Li # if the comment started before the current line or ended after the 4264*8c35d5eeSXin Li # current line, but it catches most of the false positives. At least, 4265*8c35d5eeSXin Li # it provides a way to workaround this warning for people who use 4266*8c35d5eeSXin Li # multi-line comments in preprocessor macros. 4267*8c35d5eeSXin Li # 4268*8c35d5eeSXin Li # TODO(unknown): remove this once cpplint has better support for 4269*8c35d5eeSXin Li # multi-line comments. 4270*8c35d5eeSXin Li if line.find('/*') >= 0 or line.find('*/') >= 0: 4271*8c35d5eeSXin Li return 4272*8c35d5eeSXin Li 4273*8c35d5eeSXin Li for match in _ALT_TOKEN_REPLACEMENT_PATTERN.finditer(line): 4274*8c35d5eeSXin Li error(filename, linenum, 'readability/alt_tokens', 2, 4275*8c35d5eeSXin Li 'Use operator %s instead of %s' % ( 4276*8c35d5eeSXin Li _ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1))) 4277*8c35d5eeSXin Li 4278*8c35d5eeSXin Li 4279*8c35d5eeSXin Lidef GetLineWidth(line): 4280*8c35d5eeSXin Li """Determines the width of the line in column positions. 4281*8c35d5eeSXin Li 4282*8c35d5eeSXin Li Args: 4283*8c35d5eeSXin Li line: A string, which may be a Unicode string. 4284*8c35d5eeSXin Li 4285*8c35d5eeSXin Li Returns: 4286*8c35d5eeSXin Li The width of the line in column positions, accounting for Unicode 4287*8c35d5eeSXin Li combining characters and wide characters. 4288*8c35d5eeSXin Li """ 4289*8c35d5eeSXin Li if isinstance(line, unicode): 4290*8c35d5eeSXin Li width = 0 4291*8c35d5eeSXin Li for uc in unicodedata.normalize('NFC', line): 4292*8c35d5eeSXin Li if unicodedata.east_asian_width(uc) in ('W', 'F'): 4293*8c35d5eeSXin Li width += 2 4294*8c35d5eeSXin Li elif not unicodedata.combining(uc): 4295*8c35d5eeSXin Li # Issue 337 4296*8c35d5eeSXin Li # https://mail.python.org/pipermail/python-list/2012-August/628809.html 4297*8c35d5eeSXin Li if (sys.version_info.major, sys.version_info.minor) <= (3, 2): 4298*8c35d5eeSXin Li try: 4299*8c35d5eeSXin Li # https://github.com/python/cpython/blob/2.7/Include/unicodeobject.h#L81 4300*8c35d5eeSXin Li is_wide_build = sysconfig.get_config_var("Py_UNICODE_SIZE") >= 4 4301*8c35d5eeSXin Li # https://github.com/python/cpython/blob/2.7/Objects/unicodeobject.c#L564 4302*8c35d5eeSXin Li is_low_surrogate = 0xDC00 <= ord(uc) <= 0xDFFF 4303*8c35d5eeSXin Li if not is_wide_build and is_low_surrogate: 4304*8c35d5eeSXin Li width -= 1 4305*8c35d5eeSXin Li except ImportError: 4306*8c35d5eeSXin Li # Android prebuilt python ends up CHECK-failing here due to how it's compiled. 4307*8c35d5eeSXin Li pass 4308*8c35d5eeSXin Li width += 1 4309*8c35d5eeSXin Li return width 4310*8c35d5eeSXin Li else: 4311*8c35d5eeSXin Li return len(line) 4312*8c35d5eeSXin Li 4313*8c35d5eeSXin Li 4314*8c35d5eeSXin Lidef CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state, 4315*8c35d5eeSXin Li error): 4316*8c35d5eeSXin Li """Checks rules from the 'C++ style rules' section of cppguide.html. 4317*8c35d5eeSXin Li 4318*8c35d5eeSXin Li Most of these rules are hard to test (naming, comment style), but we 4319*8c35d5eeSXin Li do what we can. In particular we check for 2-space indents, line lengths, 4320*8c35d5eeSXin Li tab usage, spaces inside code, etc. 4321*8c35d5eeSXin Li 4322*8c35d5eeSXin Li Args: 4323*8c35d5eeSXin Li filename: The name of the current file. 4324*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 4325*8c35d5eeSXin Li linenum: The number of the line to check. 4326*8c35d5eeSXin Li file_extension: The extension (without the dot) of the filename. 4327*8c35d5eeSXin Li nesting_state: A NestingState instance which maintains information about 4328*8c35d5eeSXin Li the current stack of nested blocks being parsed. 4329*8c35d5eeSXin Li error: The function to call with any errors found. 4330*8c35d5eeSXin Li """ 4331*8c35d5eeSXin Li 4332*8c35d5eeSXin Li # Don't use "elided" lines here, otherwise we can't check commented lines. 4333*8c35d5eeSXin Li # Don't want to use "raw" either, because we don't want to check inside C++11 4334*8c35d5eeSXin Li # raw strings, 4335*8c35d5eeSXin Li raw_lines = clean_lines.lines_without_raw_strings 4336*8c35d5eeSXin Li line = raw_lines[linenum] 4337*8c35d5eeSXin Li prev = raw_lines[linenum - 1] if linenum > 0 else '' 4338*8c35d5eeSXin Li 4339*8c35d5eeSXin Li if line.find('\t') != -1: 4340*8c35d5eeSXin Li error(filename, linenum, 'whitespace/tab', 1, 4341*8c35d5eeSXin Li 'Tab found; better to use spaces') 4342*8c35d5eeSXin Li 4343*8c35d5eeSXin Li # One or three blank spaces at the beginning of the line is weird; it's 4344*8c35d5eeSXin Li # hard to reconcile that with 2-space indents. 4345*8c35d5eeSXin Li # NOTE: here are the conditions rob pike used for his tests. Mine aren't 4346*8c35d5eeSXin Li # as sophisticated, but it may be worth becoming so: RLENGTH==initial_spaces 4347*8c35d5eeSXin Li # if(RLENGTH > 20) complain = 0; 4348*8c35d5eeSXin Li # if(match($0, " +(error|private|public|protected):")) complain = 0; 4349*8c35d5eeSXin Li # if(match(prev, "&& *$")) complain = 0; 4350*8c35d5eeSXin Li # if(match(prev, "\\|\\| *$")) complain = 0; 4351*8c35d5eeSXin Li # if(match(prev, "[\",=><] *$")) complain = 0; 4352*8c35d5eeSXin Li # if(match($0, " <<")) complain = 0; 4353*8c35d5eeSXin Li # if(match(prev, " +for \\(")) complain = 0; 4354*8c35d5eeSXin Li # if(prevodd && match(prevprev, " +for \\(")) complain = 0; 4355*8c35d5eeSXin Li scope_or_label_pattern = r'\s*\w+\s*:\s*\\?$' 4356*8c35d5eeSXin Li classinfo = nesting_state.InnermostClass() 4357*8c35d5eeSXin Li initial_spaces = 0 4358*8c35d5eeSXin Li cleansed_line = clean_lines.elided[linenum] 4359*8c35d5eeSXin Li while initial_spaces < len(line) and line[initial_spaces] == ' ': 4360*8c35d5eeSXin Li initial_spaces += 1 4361*8c35d5eeSXin Li # There are certain situations we allow one space, notably for 4362*8c35d5eeSXin Li # section labels, and also lines containing multi-line raw strings. 4363*8c35d5eeSXin Li # We also don't check for lines that look like continuation lines 4364*8c35d5eeSXin Li # (of lines ending in double quotes, commas, equals, or angle brackets) 4365*8c35d5eeSXin Li # because the rules for how to indent those are non-trivial. 4366*8c35d5eeSXin Li if (not Search(r'[",=><] *$', prev) and 4367*8c35d5eeSXin Li (initial_spaces == 1 or initial_spaces == 3) and 4368*8c35d5eeSXin Li not Match(scope_or_label_pattern, cleansed_line) and 4369*8c35d5eeSXin Li not (clean_lines.raw_lines[linenum] != line and 4370*8c35d5eeSXin Li Match(r'^\s*""', line))): 4371*8c35d5eeSXin Li error(filename, linenum, 'whitespace/indent', 3, 4372*8c35d5eeSXin Li 'Weird number of spaces at line-start. ' 4373*8c35d5eeSXin Li 'Are you using a 2-space indent?') 4374*8c35d5eeSXin Li 4375*8c35d5eeSXin Li if line and line[-1].isspace(): 4376*8c35d5eeSXin Li error(filename, linenum, 'whitespace/end_of_line', 4, 4377*8c35d5eeSXin Li 'Line ends in whitespace. Consider deleting these extra spaces.') 4378*8c35d5eeSXin Li 4379*8c35d5eeSXin Li # Check if the line is a header guard. 4380*8c35d5eeSXin Li is_header_guard = False 4381*8c35d5eeSXin Li if IsHeaderExtension(file_extension): 4382*8c35d5eeSXin Li cppvar = GetHeaderGuardCPPVariable(filename) 4383*8c35d5eeSXin Li if (line.startswith('#ifndef %s' % cppvar) or 4384*8c35d5eeSXin Li line.startswith('#define %s' % cppvar) or 4385*8c35d5eeSXin Li line.startswith('#endif // %s' % cppvar)): 4386*8c35d5eeSXin Li is_header_guard = True 4387*8c35d5eeSXin Li # #include lines and header guards can be long, since there's no clean way to 4388*8c35d5eeSXin Li # split them. 4389*8c35d5eeSXin Li # 4390*8c35d5eeSXin Li # URLs can be long too. It's possible to split these, but it makes them 4391*8c35d5eeSXin Li # harder to cut&paste. 4392*8c35d5eeSXin Li # 4393*8c35d5eeSXin Li # The "$Id:...$" comment may also get very long without it being the 4394*8c35d5eeSXin Li # developers fault. 4395*8c35d5eeSXin Li if (not line.startswith('#include') and not is_header_guard and 4396*8c35d5eeSXin Li not Match(r'^\s*//.*http(s?)://\S*$', line) and 4397*8c35d5eeSXin Li not Match(r'^\s*//\s*[^\s]*$', line) and 4398*8c35d5eeSXin Li not Match(r'^// \$Id:.*#[0-9]+ \$$', line)): 4399*8c35d5eeSXin Li line_width = GetLineWidth(line) 4400*8c35d5eeSXin Li if line_width > _line_length: 4401*8c35d5eeSXin Li error(filename, linenum, 'whitespace/line_length', 2, 4402*8c35d5eeSXin Li 'Lines should be <= %i characters long' % _line_length) 4403*8c35d5eeSXin Li 4404*8c35d5eeSXin Li if (cleansed_line.count(';') > 1 and 4405*8c35d5eeSXin Li # for loops are allowed two ;'s (and may run over two lines). 4406*8c35d5eeSXin Li cleansed_line.find('for') == -1 and 4407*8c35d5eeSXin Li (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1 or 4408*8c35d5eeSXin Li GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1) and 4409*8c35d5eeSXin Li # It's ok to have many commands in a switch case that fits in 1 line 4410*8c35d5eeSXin Li not ((cleansed_line.find('case ') != -1 or 4411*8c35d5eeSXin Li cleansed_line.find('default:') != -1) and 4412*8c35d5eeSXin Li cleansed_line.find('break;') != -1)): 4413*8c35d5eeSXin Li error(filename, linenum, 'whitespace/newline', 0, 4414*8c35d5eeSXin Li 'More than one command on the same line') 4415*8c35d5eeSXin Li 4416*8c35d5eeSXin Li # Some more style checks 4417*8c35d5eeSXin Li CheckBraces(filename, clean_lines, linenum, error) 4418*8c35d5eeSXin Li CheckTrailingSemicolon(filename, clean_lines, linenum, error) 4419*8c35d5eeSXin Li CheckEmptyBlockBody(filename, clean_lines, linenum, error) 4420*8c35d5eeSXin Li CheckSpacing(filename, clean_lines, linenum, nesting_state, error) 4421*8c35d5eeSXin Li CheckOperatorSpacing(filename, clean_lines, linenum, error) 4422*8c35d5eeSXin Li CheckParenthesisSpacing(filename, clean_lines, linenum, error) 4423*8c35d5eeSXin Li CheckCommaSpacing(filename, clean_lines, linenum, error) 4424*8c35d5eeSXin Li CheckBracesSpacing(filename, clean_lines, linenum, nesting_state, error) 4425*8c35d5eeSXin Li CheckSpacingForFunctionCall(filename, clean_lines, linenum, error) 4426*8c35d5eeSXin Li CheckCheck(filename, clean_lines, linenum, error) 4427*8c35d5eeSXin Li CheckAltTokens(filename, clean_lines, linenum, error) 4428*8c35d5eeSXin Li classinfo = nesting_state.InnermostClass() 4429*8c35d5eeSXin Li if classinfo: 4430*8c35d5eeSXin Li CheckSectionSpacing(filename, clean_lines, classinfo, linenum, error) 4431*8c35d5eeSXin Li 4432*8c35d5eeSXin Li 4433*8c35d5eeSXin Li_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$') 4434*8c35d5eeSXin Li# Matches the first component of a filename delimited by -s and _s. That is: 4435*8c35d5eeSXin Li# _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo' 4436*8c35d5eeSXin Li# _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo' 4437*8c35d5eeSXin Li# _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo' 4438*8c35d5eeSXin Li# _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo' 4439*8c35d5eeSXin Li_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+') 4440*8c35d5eeSXin Li 4441*8c35d5eeSXin Li 4442*8c35d5eeSXin Lidef _DropCommonSuffixes(filename): 4443*8c35d5eeSXin Li """Drops common suffixes like _test.cc or -inl.h from filename. 4444*8c35d5eeSXin Li 4445*8c35d5eeSXin Li For example: 4446*8c35d5eeSXin Li >>> _DropCommonSuffixes('foo/foo-inl.h') 4447*8c35d5eeSXin Li 'foo/foo' 4448*8c35d5eeSXin Li >>> _DropCommonSuffixes('foo/bar/foo.cc') 4449*8c35d5eeSXin Li 'foo/bar/foo' 4450*8c35d5eeSXin Li >>> _DropCommonSuffixes('foo/foo_internal.h') 4451*8c35d5eeSXin Li 'foo/foo' 4452*8c35d5eeSXin Li >>> _DropCommonSuffixes('foo/foo_unusualinternal.h') 4453*8c35d5eeSXin Li 'foo/foo_unusualinternal' 4454*8c35d5eeSXin Li 4455*8c35d5eeSXin Li Args: 4456*8c35d5eeSXin Li filename: The input filename. 4457*8c35d5eeSXin Li 4458*8c35d5eeSXin Li Returns: 4459*8c35d5eeSXin Li The filename with the common suffix removed. 4460*8c35d5eeSXin Li """ 4461*8c35d5eeSXin Li for suffix in ('test.cc', 'regtest.cc', 'unittest.cc', 4462*8c35d5eeSXin Li 'inl.h', 'impl.h', 'internal.h'): 4463*8c35d5eeSXin Li if (filename.endswith(suffix) and len(filename) > len(suffix) and 4464*8c35d5eeSXin Li filename[-len(suffix) - 1] in ('-', '_')): 4465*8c35d5eeSXin Li return filename[:-len(suffix) - 1] 4466*8c35d5eeSXin Li return os.path.splitext(filename)[0] 4467*8c35d5eeSXin Li 4468*8c35d5eeSXin Li 4469*8c35d5eeSXin Lidef _ClassifyInclude(fileinfo, include, is_system): 4470*8c35d5eeSXin Li """Figures out what kind of header 'include' is. 4471*8c35d5eeSXin Li 4472*8c35d5eeSXin Li Args: 4473*8c35d5eeSXin Li fileinfo: The current file cpplint is running over. A FileInfo instance. 4474*8c35d5eeSXin Li include: The path to a #included file. 4475*8c35d5eeSXin Li is_system: True if the #include used <> rather than "". 4476*8c35d5eeSXin Li 4477*8c35d5eeSXin Li Returns: 4478*8c35d5eeSXin Li One of the _XXX_HEADER constants. 4479*8c35d5eeSXin Li 4480*8c35d5eeSXin Li For example: 4481*8c35d5eeSXin Li >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'stdio.h', True) 4482*8c35d5eeSXin Li _C_SYS_HEADER 4483*8c35d5eeSXin Li >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'string', True) 4484*8c35d5eeSXin Li _CPP_SYS_HEADER 4485*8c35d5eeSXin Li >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', False) 4486*8c35d5eeSXin Li _LIKELY_MY_HEADER 4487*8c35d5eeSXin Li >>> _ClassifyInclude(FileInfo('foo/foo_unknown_extension.cc'), 4488*8c35d5eeSXin Li ... 'bar/foo_other_ext.h', False) 4489*8c35d5eeSXin Li _POSSIBLE_MY_HEADER 4490*8c35d5eeSXin Li >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/bar.h', False) 4491*8c35d5eeSXin Li _OTHER_HEADER 4492*8c35d5eeSXin Li """ 4493*8c35d5eeSXin Li # This is a list of all standard c++ header files, except 4494*8c35d5eeSXin Li # those already checked for above. 4495*8c35d5eeSXin Li is_cpp_h = include in _CPP_HEADERS 4496*8c35d5eeSXin Li 4497*8c35d5eeSXin Li if is_system: 4498*8c35d5eeSXin Li if is_cpp_h: 4499*8c35d5eeSXin Li return _CPP_SYS_HEADER 4500*8c35d5eeSXin Li else: 4501*8c35d5eeSXin Li return _C_SYS_HEADER 4502*8c35d5eeSXin Li 4503*8c35d5eeSXin Li # If the target file and the include we're checking share a 4504*8c35d5eeSXin Li # basename when we drop common extensions, and the include 4505*8c35d5eeSXin Li # lives in . , then it's likely to be owned by the target file. 4506*8c35d5eeSXin Li target_dir, target_base = ( 4507*8c35d5eeSXin Li os.path.split(_DropCommonSuffixes(fileinfo.RepositoryName()))) 4508*8c35d5eeSXin Li include_dir, include_base = os.path.split(_DropCommonSuffixes(include)) 4509*8c35d5eeSXin Li if target_base == include_base and ( 4510*8c35d5eeSXin Li include_dir == target_dir or 4511*8c35d5eeSXin Li include_dir == os.path.normpath(target_dir + '/../public')): 4512*8c35d5eeSXin Li return _LIKELY_MY_HEADER 4513*8c35d5eeSXin Li 4514*8c35d5eeSXin Li # If the target and include share some initial basename 4515*8c35d5eeSXin Li # component, it's possible the target is implementing the 4516*8c35d5eeSXin Li # include, so it's allowed to be first, but we'll never 4517*8c35d5eeSXin Li # complain if it's not there. 4518*8c35d5eeSXin Li target_first_component = _RE_FIRST_COMPONENT.match(target_base) 4519*8c35d5eeSXin Li include_first_component = _RE_FIRST_COMPONENT.match(include_base) 4520*8c35d5eeSXin Li if (target_first_component and include_first_component and 4521*8c35d5eeSXin Li target_first_component.group(0) == 4522*8c35d5eeSXin Li include_first_component.group(0)): 4523*8c35d5eeSXin Li return _POSSIBLE_MY_HEADER 4524*8c35d5eeSXin Li 4525*8c35d5eeSXin Li return _OTHER_HEADER 4526*8c35d5eeSXin Li 4527*8c35d5eeSXin Li 4528*8c35d5eeSXin Li 4529*8c35d5eeSXin Lidef CheckIncludeLine(filename, clean_lines, linenum, include_state, error): 4530*8c35d5eeSXin Li """Check rules that are applicable to #include lines. 4531*8c35d5eeSXin Li 4532*8c35d5eeSXin Li Strings on #include lines are NOT removed from elided line, to make 4533*8c35d5eeSXin Li certain tasks easier. However, to prevent false positives, checks 4534*8c35d5eeSXin Li applicable to #include lines in CheckLanguage must be put here. 4535*8c35d5eeSXin Li 4536*8c35d5eeSXin Li Args: 4537*8c35d5eeSXin Li filename: The name of the current file. 4538*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 4539*8c35d5eeSXin Li linenum: The number of the line to check. 4540*8c35d5eeSXin Li include_state: An _IncludeState instance in which the headers are inserted. 4541*8c35d5eeSXin Li error: The function to call with any errors found. 4542*8c35d5eeSXin Li """ 4543*8c35d5eeSXin Li fileinfo = FileInfo(filename) 4544*8c35d5eeSXin Li line = clean_lines.lines[linenum] 4545*8c35d5eeSXin Li 4546*8c35d5eeSXin Li # "include" should use the new style "foo/bar.h" instead of just "bar.h" 4547*8c35d5eeSXin Li # Only do this check if the included header follows google naming 4548*8c35d5eeSXin Li # conventions. If not, assume that it's a 3rd party API that 4549*8c35d5eeSXin Li # requires special include conventions. 4550*8c35d5eeSXin Li # 4551*8c35d5eeSXin Li # We also make an exception for Lua headers, which follow google 4552*8c35d5eeSXin Li # naming convention but not the include convention. 4553*8c35d5eeSXin Li match = Match(r'#include\s*"([^/]+\.h)"', line) 4554*8c35d5eeSXin Li if match and not _THIRD_PARTY_HEADERS_PATTERN.match(match.group(1)): 4555*8c35d5eeSXin Li error(filename, linenum, 'build/include', 4, 4556*8c35d5eeSXin Li 'Include the directory when naming .h files') 4557*8c35d5eeSXin Li 4558*8c35d5eeSXin Li # we shouldn't include a file more than once. actually, there are a 4559*8c35d5eeSXin Li # handful of instances where doing so is okay, but in general it's 4560*8c35d5eeSXin Li # not. 4561*8c35d5eeSXin Li match = _RE_PATTERN_INCLUDE.search(line) 4562*8c35d5eeSXin Li if match: 4563*8c35d5eeSXin Li include = match.group(2) 4564*8c35d5eeSXin Li is_system = (match.group(1) == '<') 4565*8c35d5eeSXin Li duplicate_line = include_state.FindHeader(include) 4566*8c35d5eeSXin Li if duplicate_line >= 0: 4567*8c35d5eeSXin Li error(filename, linenum, 'build/include', 4, 4568*8c35d5eeSXin Li '"%s" already included at %s:%s' % 4569*8c35d5eeSXin Li (include, filename, duplicate_line)) 4570*8c35d5eeSXin Li elif (include.endswith('.cc') and 4571*8c35d5eeSXin Li os.path.dirname(fileinfo.RepositoryName()) != os.path.dirname(include)): 4572*8c35d5eeSXin Li error(filename, linenum, 'build/include', 4, 4573*8c35d5eeSXin Li 'Do not include .cc files from other packages') 4574*8c35d5eeSXin Li elif not _THIRD_PARTY_HEADERS_PATTERN.match(include): 4575*8c35d5eeSXin Li include_state.include_list[-1].append((include, linenum)) 4576*8c35d5eeSXin Li 4577*8c35d5eeSXin Li # We want to ensure that headers appear in the right order: 4578*8c35d5eeSXin Li # 1) for foo.cc, foo.h (preferred location) 4579*8c35d5eeSXin Li # 2) c system files 4580*8c35d5eeSXin Li # 3) cpp system files 4581*8c35d5eeSXin Li # 4) for foo.cc, foo.h (deprecated location) 4582*8c35d5eeSXin Li # 5) other google headers 4583*8c35d5eeSXin Li # 4584*8c35d5eeSXin Li # We classify each include statement as one of those 5 types 4585*8c35d5eeSXin Li # using a number of techniques. The include_state object keeps 4586*8c35d5eeSXin Li # track of the highest type seen, and complains if we see a 4587*8c35d5eeSXin Li # lower type after that. 4588*8c35d5eeSXin Li error_message = include_state.CheckNextIncludeOrder( 4589*8c35d5eeSXin Li _ClassifyInclude(fileinfo, include, is_system)) 4590*8c35d5eeSXin Li if error_message: 4591*8c35d5eeSXin Li error(filename, linenum, 'build/include_order', 4, 4592*8c35d5eeSXin Li '%s. Should be: %s.h, c system, c++ system, other.' % 4593*8c35d5eeSXin Li (error_message, fileinfo.BaseName())) 4594*8c35d5eeSXin Li canonical_include = include_state.CanonicalizeAlphabeticalOrder(include) 4595*8c35d5eeSXin Li if not include_state.IsInAlphabeticalOrder( 4596*8c35d5eeSXin Li clean_lines, linenum, canonical_include): 4597*8c35d5eeSXin Li error(filename, linenum, 'build/include_alpha', 4, 4598*8c35d5eeSXin Li 'Include "%s" not in alphabetical order' % include) 4599*8c35d5eeSXin Li include_state.SetLastHeader(canonical_include) 4600*8c35d5eeSXin Li 4601*8c35d5eeSXin Li 4602*8c35d5eeSXin Li 4603*8c35d5eeSXin Lidef _GetTextInside(text, start_pattern): 4604*8c35d5eeSXin Li r"""Retrieves all the text between matching open and close parentheses. 4605*8c35d5eeSXin Li 4606*8c35d5eeSXin Li Given a string of lines and a regular expression string, retrieve all the text 4607*8c35d5eeSXin Li following the expression and between opening punctuation symbols like 4608*8c35d5eeSXin Li (, [, or {, and the matching close-punctuation symbol. This properly nested 4609*8c35d5eeSXin Li occurrences of the punctuations, so for the text like 4610*8c35d5eeSXin Li printf(a(), b(c())); 4611*8c35d5eeSXin Li a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'. 4612*8c35d5eeSXin Li start_pattern must match string having an open punctuation symbol at the end. 4613*8c35d5eeSXin Li 4614*8c35d5eeSXin Li Args: 4615*8c35d5eeSXin Li text: The lines to extract text. Its comments and strings must be elided. 4616*8c35d5eeSXin Li It can be single line and can span multiple lines. 4617*8c35d5eeSXin Li start_pattern: The regexp string indicating where to start extracting 4618*8c35d5eeSXin Li the text. 4619*8c35d5eeSXin Li Returns: 4620*8c35d5eeSXin Li The extracted text. 4621*8c35d5eeSXin Li None if either the opening string or ending punctuation could not be found. 4622*8c35d5eeSXin Li """ 4623*8c35d5eeSXin Li # TODO(unknown): Audit cpplint.py to see what places could be profitably 4624*8c35d5eeSXin Li # rewritten to use _GetTextInside (and use inferior regexp matching today). 4625*8c35d5eeSXin Li 4626*8c35d5eeSXin Li # Give opening punctuations to get the matching close-punctuations. 4627*8c35d5eeSXin Li matching_punctuation = {'(': ')', '{': '}', '[': ']'} 4628*8c35d5eeSXin Li closing_punctuation = set(matching_punctuation.itervalues()) 4629*8c35d5eeSXin Li 4630*8c35d5eeSXin Li # Find the position to start extracting text. 4631*8c35d5eeSXin Li match = re.search(start_pattern, text, re.M) 4632*8c35d5eeSXin Li if not match: # start_pattern not found in text. 4633*8c35d5eeSXin Li return None 4634*8c35d5eeSXin Li start_position = match.end(0) 4635*8c35d5eeSXin Li 4636*8c35d5eeSXin Li assert start_position > 0, ( 4637*8c35d5eeSXin Li 'start_pattern must ends with an opening punctuation.') 4638*8c35d5eeSXin Li assert text[start_position - 1] in matching_punctuation, ( 4639*8c35d5eeSXin Li 'start_pattern must ends with an opening punctuation.') 4640*8c35d5eeSXin Li # Stack of closing punctuations we expect to have in text after position. 4641*8c35d5eeSXin Li punctuation_stack = [matching_punctuation[text[start_position - 1]]] 4642*8c35d5eeSXin Li position = start_position 4643*8c35d5eeSXin Li while punctuation_stack and position < len(text): 4644*8c35d5eeSXin Li if text[position] == punctuation_stack[-1]: 4645*8c35d5eeSXin Li punctuation_stack.pop() 4646*8c35d5eeSXin Li elif text[position] in closing_punctuation: 4647*8c35d5eeSXin Li # A closing punctuation without matching opening punctuations. 4648*8c35d5eeSXin Li return None 4649*8c35d5eeSXin Li elif text[position] in matching_punctuation: 4650*8c35d5eeSXin Li punctuation_stack.append(matching_punctuation[text[position]]) 4651*8c35d5eeSXin Li position += 1 4652*8c35d5eeSXin Li if punctuation_stack: 4653*8c35d5eeSXin Li # Opening punctuations left without matching close-punctuations. 4654*8c35d5eeSXin Li return None 4655*8c35d5eeSXin Li # punctuations match. 4656*8c35d5eeSXin Li return text[start_position:position - 1] 4657*8c35d5eeSXin Li 4658*8c35d5eeSXin Li 4659*8c35d5eeSXin Li# Patterns for matching call-by-reference parameters. 4660*8c35d5eeSXin Li# 4661*8c35d5eeSXin Li# Supports nested templates up to 2 levels deep using this messy pattern: 4662*8c35d5eeSXin Li# < (?: < (?: < [^<>]* 4663*8c35d5eeSXin Li# > 4664*8c35d5eeSXin Li# | [^<>] )* 4665*8c35d5eeSXin Li# > 4666*8c35d5eeSXin Li# | [^<>] )* 4667*8c35d5eeSXin Li# > 4668*8c35d5eeSXin Li_RE_PATTERN_IDENT = r'[_a-zA-Z]\w*' # =~ [[:alpha:]][[:alnum:]]* 4669*8c35d5eeSXin Li_RE_PATTERN_TYPE = ( 4670*8c35d5eeSXin Li r'(?:const\s+)?(?:typename\s+|class\s+|struct\s+|union\s+|enum\s+)?' 4671*8c35d5eeSXin Li r'(?:\w|' 4672*8c35d5eeSXin Li r'\s*<(?:<(?:<[^<>]*>|[^<>])*>|[^<>])*>|' 4673*8c35d5eeSXin Li r'::)+') 4674*8c35d5eeSXin Li# A call-by-reference parameter ends with '& identifier'. 4675*8c35d5eeSXin Li_RE_PATTERN_REF_PARAM = re.compile( 4676*8c35d5eeSXin Li r'(' + _RE_PATTERN_TYPE + r'(?:\s*(?:\bconst\b|[*]))*\s*' 4677*8c35d5eeSXin Li r'&\s*' + _RE_PATTERN_IDENT + r')\s*(?:=[^,()]+)?[,)]') 4678*8c35d5eeSXin Li# A call-by-const-reference parameter either ends with 'const& identifier' 4679*8c35d5eeSXin Li# or looks like 'const type& identifier' when 'type' is atomic. 4680*8c35d5eeSXin Li_RE_PATTERN_CONST_REF_PARAM = ( 4681*8c35d5eeSXin Li r'(?:.*\s*\bconst\s*&\s*' + _RE_PATTERN_IDENT + 4682*8c35d5eeSXin Li r'|const\s+' + _RE_PATTERN_TYPE + r'\s*&\s*' + _RE_PATTERN_IDENT + r')') 4683*8c35d5eeSXin Li# Stream types. 4684*8c35d5eeSXin Li_RE_PATTERN_REF_STREAM_PARAM = ( 4685*8c35d5eeSXin Li r'(?:.*stream\s*&\s*' + _RE_PATTERN_IDENT + r')') 4686*8c35d5eeSXin Li 4687*8c35d5eeSXin Li 4688*8c35d5eeSXin Lidef CheckLanguage(filename, clean_lines, linenum, file_extension, 4689*8c35d5eeSXin Li include_state, nesting_state, error): 4690*8c35d5eeSXin Li """Checks rules from the 'C++ language rules' section of cppguide.html. 4691*8c35d5eeSXin Li 4692*8c35d5eeSXin Li Some of these rules are hard to test (function overloading, using 4693*8c35d5eeSXin Li uint32 inappropriately), but we do the best we can. 4694*8c35d5eeSXin Li 4695*8c35d5eeSXin Li Args: 4696*8c35d5eeSXin Li filename: The name of the current file. 4697*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 4698*8c35d5eeSXin Li linenum: The number of the line to check. 4699*8c35d5eeSXin Li file_extension: The extension (without the dot) of the filename. 4700*8c35d5eeSXin Li include_state: An _IncludeState instance in which the headers are inserted. 4701*8c35d5eeSXin Li nesting_state: A NestingState instance which maintains information about 4702*8c35d5eeSXin Li the current stack of nested blocks being parsed. 4703*8c35d5eeSXin Li error: The function to call with any errors found. 4704*8c35d5eeSXin Li """ 4705*8c35d5eeSXin Li # If the line is empty or consists of entirely a comment, no need to 4706*8c35d5eeSXin Li # check it. 4707*8c35d5eeSXin Li line = clean_lines.elided[linenum] 4708*8c35d5eeSXin Li if not line: 4709*8c35d5eeSXin Li return 4710*8c35d5eeSXin Li 4711*8c35d5eeSXin Li match = _RE_PATTERN_INCLUDE.search(line) 4712*8c35d5eeSXin Li if match: 4713*8c35d5eeSXin Li CheckIncludeLine(filename, clean_lines, linenum, include_state, error) 4714*8c35d5eeSXin Li return 4715*8c35d5eeSXin Li 4716*8c35d5eeSXin Li # Reset include state across preprocessor directives. This is meant 4717*8c35d5eeSXin Li # to silence warnings for conditional includes. 4718*8c35d5eeSXin Li match = Match(r'^\s*#\s*(if|ifdef|ifndef|elif|else|endif)\b', line) 4719*8c35d5eeSXin Li if match: 4720*8c35d5eeSXin Li include_state.ResetSection(match.group(1)) 4721*8c35d5eeSXin Li 4722*8c35d5eeSXin Li # Make Windows paths like Unix. 4723*8c35d5eeSXin Li fullname = os.path.abspath(filename).replace('\\', '/') 4724*8c35d5eeSXin Li 4725*8c35d5eeSXin Li # Perform other checks now that we are sure that this is not an include line 4726*8c35d5eeSXin Li CheckCasts(filename, clean_lines, linenum, error) 4727*8c35d5eeSXin Li CheckGlobalStatic(filename, clean_lines, linenum, error) 4728*8c35d5eeSXin Li CheckPrintf(filename, clean_lines, linenum, error) 4729*8c35d5eeSXin Li 4730*8c35d5eeSXin Li if IsHeaderExtension(file_extension): 4731*8c35d5eeSXin Li # TODO(unknown): check that 1-arg constructors are explicit. 4732*8c35d5eeSXin Li # How to tell it's a constructor? 4733*8c35d5eeSXin Li # (handled in CheckForNonStandardConstructs for now) 4734*8c35d5eeSXin Li # TODO(unknown): check that classes declare or disable copy/assign 4735*8c35d5eeSXin Li # (level 1 error) 4736*8c35d5eeSXin Li pass 4737*8c35d5eeSXin Li 4738*8c35d5eeSXin Li # Check if people are using the verboten C basic types. The only exception 4739*8c35d5eeSXin Li # we regularly allow is "unsigned short port" for port. 4740*8c35d5eeSXin Li if Search(r'\bshort port\b', line): 4741*8c35d5eeSXin Li if not Search(r'\bunsigned short port\b', line): 4742*8c35d5eeSXin Li error(filename, linenum, 'runtime/int', 4, 4743*8c35d5eeSXin Li 'Use "unsigned short" for ports, not "short"') 4744*8c35d5eeSXin Li else: 4745*8c35d5eeSXin Li match = Search(r'\b(short|long(?! +double)|long long)\b', line) 4746*8c35d5eeSXin Li if match: 4747*8c35d5eeSXin Li error(filename, linenum, 'runtime/int', 4, 4748*8c35d5eeSXin Li 'Use int16/int64/etc, rather than the C type %s' % match.group(1)) 4749*8c35d5eeSXin Li 4750*8c35d5eeSXin Li # Check if some verboten operator overloading is going on 4751*8c35d5eeSXin Li # TODO(unknown): catch out-of-line unary operator&: 4752*8c35d5eeSXin Li # class X {}; 4753*8c35d5eeSXin Li # int operator&(const X& x) { return 42; } // unary operator& 4754*8c35d5eeSXin Li # The trick is it's hard to tell apart from binary operator&: 4755*8c35d5eeSXin Li # class Y { int operator&(const Y& x) { return 23; } }; // binary operator& 4756*8c35d5eeSXin Li if Search(r'\boperator\s*&\s*\(\s*\)', line): 4757*8c35d5eeSXin Li error(filename, linenum, 'runtime/operator', 4, 4758*8c35d5eeSXin Li 'Unary operator& is dangerous. Do not use it.') 4759*8c35d5eeSXin Li 4760*8c35d5eeSXin Li # Check for suspicious usage of "if" like 4761*8c35d5eeSXin Li # } if (a == b) { 4762*8c35d5eeSXin Li if Search(r'\}\s*if\s*\(', line): 4763*8c35d5eeSXin Li error(filename, linenum, 'readability/braces', 4, 4764*8c35d5eeSXin Li 'Did you mean "else if"? If not, start a new line for "if".') 4765*8c35d5eeSXin Li 4766*8c35d5eeSXin Li # Check for potential format string bugs like printf(foo). 4767*8c35d5eeSXin Li # We constrain the pattern not to pick things like DocidForPrintf(foo). 4768*8c35d5eeSXin Li # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str()) 4769*8c35d5eeSXin Li # TODO(unknown): Catch the following case. Need to change the calling 4770*8c35d5eeSXin Li # convention of the whole function to process multiple line to handle it. 4771*8c35d5eeSXin Li # printf( 4772*8c35d5eeSXin Li # boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line); 4773*8c35d5eeSXin Li printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(') 4774*8c35d5eeSXin Li if printf_args: 4775*8c35d5eeSXin Li match = Match(r'([\w.\->()]+)$', printf_args) 4776*8c35d5eeSXin Li if match and match.group(1) != '__VA_ARGS__': 4777*8c35d5eeSXin Li function_name = re.search(r'\b((?:string)?printf)\s*\(', 4778*8c35d5eeSXin Li line, re.I).group(1) 4779*8c35d5eeSXin Li error(filename, linenum, 'runtime/printf', 4, 4780*8c35d5eeSXin Li 'Potential format string bug. Do %s("%%s", %s) instead.' 4781*8c35d5eeSXin Li % (function_name, match.group(1))) 4782*8c35d5eeSXin Li 4783*8c35d5eeSXin Li # Check for potential memset bugs like memset(buf, sizeof(buf), 0). 4784*8c35d5eeSXin Li match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line) 4785*8c35d5eeSXin Li if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)): 4786*8c35d5eeSXin Li error(filename, linenum, 'runtime/memset', 4, 4787*8c35d5eeSXin Li 'Did you mean "memset(%s, 0, %s)"?' 4788*8c35d5eeSXin Li % (match.group(1), match.group(2))) 4789*8c35d5eeSXin Li 4790*8c35d5eeSXin Li if Search(r'\busing namespace\b', line): 4791*8c35d5eeSXin Li error(filename, linenum, 'build/namespaces', 5, 4792*8c35d5eeSXin Li 'Do not use namespace using-directives. ' 4793*8c35d5eeSXin Li 'Use using-declarations instead.') 4794*8c35d5eeSXin Li 4795*8c35d5eeSXin Li # Detect variable-length arrays. 4796*8c35d5eeSXin Li match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line) 4797*8c35d5eeSXin Li if (match and match.group(2) != 'return' and match.group(2) != 'delete' and 4798*8c35d5eeSXin Li match.group(3).find(']') == -1): 4799*8c35d5eeSXin Li # Split the size using space and arithmetic operators as delimiters. 4800*8c35d5eeSXin Li # If any of the resulting tokens are not compile time constants then 4801*8c35d5eeSXin Li # report the error. 4802*8c35d5eeSXin Li tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3)) 4803*8c35d5eeSXin Li is_const = True 4804*8c35d5eeSXin Li skip_next = False 4805*8c35d5eeSXin Li for tok in tokens: 4806*8c35d5eeSXin Li if skip_next: 4807*8c35d5eeSXin Li skip_next = False 4808*8c35d5eeSXin Li continue 4809*8c35d5eeSXin Li 4810*8c35d5eeSXin Li if Search(r'sizeof\(.+\)', tok): continue 4811*8c35d5eeSXin Li if Search(r'arraysize\(\w+\)', tok): continue 4812*8c35d5eeSXin Li 4813*8c35d5eeSXin Li tok = tok.lstrip('(') 4814*8c35d5eeSXin Li tok = tok.rstrip(')') 4815*8c35d5eeSXin Li if not tok: continue 4816*8c35d5eeSXin Li if Match(r'\d+', tok): continue 4817*8c35d5eeSXin Li if Match(r'0[xX][0-9a-fA-F]+', tok): continue 4818*8c35d5eeSXin Li if Match(r'k[A-Z0-9]\w*', tok): continue 4819*8c35d5eeSXin Li if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue 4820*8c35d5eeSXin Li if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue 4821*8c35d5eeSXin Li # A catch all for tricky sizeof cases, including 'sizeof expression', 4822*8c35d5eeSXin Li # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)' 4823*8c35d5eeSXin Li # requires skipping the next token because we split on ' ' and '*'. 4824*8c35d5eeSXin Li if tok.startswith('sizeof'): 4825*8c35d5eeSXin Li skip_next = True 4826*8c35d5eeSXin Li continue 4827*8c35d5eeSXin Li is_const = False 4828*8c35d5eeSXin Li break 4829*8c35d5eeSXin Li if not is_const: 4830*8c35d5eeSXin Li error(filename, linenum, 'runtime/arrays', 1, 4831*8c35d5eeSXin Li 'Do not use variable-length arrays. Use an appropriately named ' 4832*8c35d5eeSXin Li "('k' followed by CamelCase) compile-time constant for the size.") 4833*8c35d5eeSXin Li 4834*8c35d5eeSXin Li # Check for use of unnamed namespaces in header files. Registration 4835*8c35d5eeSXin Li # macros are typically OK, so we allow use of "namespace {" on lines 4836*8c35d5eeSXin Li # that end with backslashes. 4837*8c35d5eeSXin Li if (IsHeaderExtension(file_extension) 4838*8c35d5eeSXin Li and Search(r'\bnamespace\s*{', line) 4839*8c35d5eeSXin Li and line[-1] != '\\'): 4840*8c35d5eeSXin Li error(filename, linenum, 'build/namespaces', 4, 4841*8c35d5eeSXin Li 'Do not use unnamed namespaces in header files. See ' 4842*8c35d5eeSXin Li 'https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces' 4843*8c35d5eeSXin Li ' for more information.') 4844*8c35d5eeSXin Li 4845*8c35d5eeSXin Li 4846*8c35d5eeSXin Lidef CheckGlobalStatic(filename, clean_lines, linenum, error): 4847*8c35d5eeSXin Li """Check for unsafe global or static objects. 4848*8c35d5eeSXin Li 4849*8c35d5eeSXin Li Args: 4850*8c35d5eeSXin Li filename: The name of the current file. 4851*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 4852*8c35d5eeSXin Li linenum: The number of the line to check. 4853*8c35d5eeSXin Li error: The function to call with any errors found. 4854*8c35d5eeSXin Li """ 4855*8c35d5eeSXin Li line = clean_lines.elided[linenum] 4856*8c35d5eeSXin Li 4857*8c35d5eeSXin Li # Match two lines at a time to support multiline declarations 4858*8c35d5eeSXin Li if linenum + 1 < clean_lines.NumLines() and not Search(r'[;({]', line): 4859*8c35d5eeSXin Li line += clean_lines.elided[linenum + 1].strip() 4860*8c35d5eeSXin Li 4861*8c35d5eeSXin Li # Check for people declaring static/global STL strings at the top level. 4862*8c35d5eeSXin Li # This is dangerous because the C++ language does not guarantee that 4863*8c35d5eeSXin Li # globals with constructors are initialized before the first access, and 4864*8c35d5eeSXin Li # also because globals can be destroyed when some threads are still running. 4865*8c35d5eeSXin Li # TODO(unknown): Generalize this to also find static unique_ptr instances. 4866*8c35d5eeSXin Li # TODO(unknown): File bugs for clang-tidy to find these. 4867*8c35d5eeSXin Li match = Match( 4868*8c35d5eeSXin Li r'((?:|static +)(?:|const +))(?::*std::)?string( +const)? +' 4869*8c35d5eeSXin Li r'([a-zA-Z0-9_:]+)\b(.*)', 4870*8c35d5eeSXin Li line) 4871*8c35d5eeSXin Li 4872*8c35d5eeSXin Li # Remove false positives: 4873*8c35d5eeSXin Li # - String pointers (as opposed to values). 4874*8c35d5eeSXin Li # string *pointer 4875*8c35d5eeSXin Li # const string *pointer 4876*8c35d5eeSXin Li # string const *pointer 4877*8c35d5eeSXin Li # string *const pointer 4878*8c35d5eeSXin Li # 4879*8c35d5eeSXin Li # - Functions and template specializations. 4880*8c35d5eeSXin Li # string Function<Type>(... 4881*8c35d5eeSXin Li # string Class<Type>::Method(... 4882*8c35d5eeSXin Li # 4883*8c35d5eeSXin Li # - Operators. These are matched separately because operator names 4884*8c35d5eeSXin Li # cross non-word boundaries, and trying to match both operators 4885*8c35d5eeSXin Li # and functions at the same time would decrease accuracy of 4886*8c35d5eeSXin Li # matching identifiers. 4887*8c35d5eeSXin Li # string Class::operator*() 4888*8c35d5eeSXin Li if (match and 4889*8c35d5eeSXin Li not Search(r'\bstring\b(\s+const)?\s*[\*\&]\s*(const\s+)?\w', line) and 4890*8c35d5eeSXin Li not Search(r'\boperator\W', line) and 4891*8c35d5eeSXin Li not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)*\s*\(([^"]|$)', match.group(4))): 4892*8c35d5eeSXin Li if Search(r'\bconst\b', line): 4893*8c35d5eeSXin Li error(filename, linenum, 'runtime/string', 4, 4894*8c35d5eeSXin Li 'For a static/global string constant, use a C style string ' 4895*8c35d5eeSXin Li 'instead: "%schar%s %s[]".' % 4896*8c35d5eeSXin Li (match.group(1), match.group(2) or '', match.group(3))) 4897*8c35d5eeSXin Li else: 4898*8c35d5eeSXin Li error(filename, linenum, 'runtime/string', 4, 4899*8c35d5eeSXin Li 'Static/global string variables are not permitted.') 4900*8c35d5eeSXin Li 4901*8c35d5eeSXin Li if (Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line) or 4902*8c35d5eeSXin Li Search(r'\b([A-Za-z0-9_]*_)\(CHECK_NOTNULL\(\1\)\)', line)): 4903*8c35d5eeSXin Li error(filename, linenum, 'runtime/init', 4, 4904*8c35d5eeSXin Li 'You seem to be initializing a member variable with itself.') 4905*8c35d5eeSXin Li 4906*8c35d5eeSXin Li 4907*8c35d5eeSXin Lidef CheckPrintf(filename, clean_lines, linenum, error): 4908*8c35d5eeSXin Li """Check for printf related issues. 4909*8c35d5eeSXin Li 4910*8c35d5eeSXin Li Args: 4911*8c35d5eeSXin Li filename: The name of the current file. 4912*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 4913*8c35d5eeSXin Li linenum: The number of the line to check. 4914*8c35d5eeSXin Li error: The function to call with any errors found. 4915*8c35d5eeSXin Li """ 4916*8c35d5eeSXin Li line = clean_lines.elided[linenum] 4917*8c35d5eeSXin Li 4918*8c35d5eeSXin Li # When snprintf is used, the second argument shouldn't be a literal. 4919*8c35d5eeSXin Li match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line) 4920*8c35d5eeSXin Li if match and match.group(2) != '0': 4921*8c35d5eeSXin Li # If 2nd arg is zero, snprintf is used to calculate size. 4922*8c35d5eeSXin Li error(filename, linenum, 'runtime/printf', 3, 4923*8c35d5eeSXin Li 'If you can, use sizeof(%s) instead of %s as the 2nd arg ' 4924*8c35d5eeSXin Li 'to snprintf.' % (match.group(1), match.group(2))) 4925*8c35d5eeSXin Li 4926*8c35d5eeSXin Li # Check if some verboten C functions are being used. 4927*8c35d5eeSXin Li if Search(r'\bsprintf\s*\(', line): 4928*8c35d5eeSXin Li error(filename, linenum, 'runtime/printf', 5, 4929*8c35d5eeSXin Li 'Never use sprintf. Use snprintf instead.') 4930*8c35d5eeSXin Li match = Search(r'\b(strcpy|strcat)\s*\(', line) 4931*8c35d5eeSXin Li if match: 4932*8c35d5eeSXin Li error(filename, linenum, 'runtime/printf', 4, 4933*8c35d5eeSXin Li 'Almost always, snprintf is better than %s' % match.group(1)) 4934*8c35d5eeSXin Li 4935*8c35d5eeSXin Li 4936*8c35d5eeSXin Lidef IsDerivedFunction(clean_lines, linenum): 4937*8c35d5eeSXin Li """Check if current line contains an inherited function. 4938*8c35d5eeSXin Li 4939*8c35d5eeSXin Li Args: 4940*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 4941*8c35d5eeSXin Li linenum: The number of the line to check. 4942*8c35d5eeSXin Li Returns: 4943*8c35d5eeSXin Li True if current line contains a function with "override" 4944*8c35d5eeSXin Li virt-specifier. 4945*8c35d5eeSXin Li """ 4946*8c35d5eeSXin Li # Scan back a few lines for start of current function 4947*8c35d5eeSXin Li for i in xrange(linenum, max(-1, linenum - 10), -1): 4948*8c35d5eeSXin Li match = Match(r'^([^()]*\w+)\(', clean_lines.elided[i]) 4949*8c35d5eeSXin Li if match: 4950*8c35d5eeSXin Li # Look for "override" after the matching closing parenthesis 4951*8c35d5eeSXin Li line, _, closing_paren = CloseExpression( 4952*8c35d5eeSXin Li clean_lines, i, len(match.group(1))) 4953*8c35d5eeSXin Li return (closing_paren >= 0 and 4954*8c35d5eeSXin Li Search(r'\boverride\b', line[closing_paren:])) 4955*8c35d5eeSXin Li return False 4956*8c35d5eeSXin Li 4957*8c35d5eeSXin Li 4958*8c35d5eeSXin Lidef IsOutOfLineMethodDefinition(clean_lines, linenum): 4959*8c35d5eeSXin Li """Check if current line contains an out-of-line method definition. 4960*8c35d5eeSXin Li 4961*8c35d5eeSXin Li Args: 4962*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 4963*8c35d5eeSXin Li linenum: The number of the line to check. 4964*8c35d5eeSXin Li Returns: 4965*8c35d5eeSXin Li True if current line contains an out-of-line method definition. 4966*8c35d5eeSXin Li """ 4967*8c35d5eeSXin Li # Scan back a few lines for start of current function 4968*8c35d5eeSXin Li for i in xrange(linenum, max(-1, linenum - 10), -1): 4969*8c35d5eeSXin Li if Match(r'^([^()]*\w+)\(', clean_lines.elided[i]): 4970*8c35d5eeSXin Li return Match(r'^[^()]*\w+::\w+\(', clean_lines.elided[i]) is not None 4971*8c35d5eeSXin Li return False 4972*8c35d5eeSXin Li 4973*8c35d5eeSXin Li 4974*8c35d5eeSXin Lidef IsInitializerList(clean_lines, linenum): 4975*8c35d5eeSXin Li """Check if current line is inside constructor initializer list. 4976*8c35d5eeSXin Li 4977*8c35d5eeSXin Li Args: 4978*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 4979*8c35d5eeSXin Li linenum: The number of the line to check. 4980*8c35d5eeSXin Li Returns: 4981*8c35d5eeSXin Li True if current line appears to be inside constructor initializer 4982*8c35d5eeSXin Li list, False otherwise. 4983*8c35d5eeSXin Li """ 4984*8c35d5eeSXin Li for i in xrange(linenum, 1, -1): 4985*8c35d5eeSXin Li line = clean_lines.elided[i] 4986*8c35d5eeSXin Li if i == linenum: 4987*8c35d5eeSXin Li remove_function_body = Match(r'^(.*)\{\s*$', line) 4988*8c35d5eeSXin Li if remove_function_body: 4989*8c35d5eeSXin Li line = remove_function_body.group(1) 4990*8c35d5eeSXin Li 4991*8c35d5eeSXin Li if Search(r'\s:\s*\w+[({]', line): 4992*8c35d5eeSXin Li # A lone colon tend to indicate the start of a constructor 4993*8c35d5eeSXin Li # initializer list. It could also be a ternary operator, which 4994*8c35d5eeSXin Li # also tend to appear in constructor initializer lists as 4995*8c35d5eeSXin Li # opposed to parameter lists. 4996*8c35d5eeSXin Li return True 4997*8c35d5eeSXin Li if Search(r'\}\s*,\s*$', line): 4998*8c35d5eeSXin Li # A closing brace followed by a comma is probably the end of a 4999*8c35d5eeSXin Li # brace-initialized member in constructor initializer list. 5000*8c35d5eeSXin Li return True 5001*8c35d5eeSXin Li if Search(r'[{};]\s*$', line): 5002*8c35d5eeSXin Li # Found one of the following: 5003*8c35d5eeSXin Li # - A closing brace or semicolon, probably the end of the previous 5004*8c35d5eeSXin Li # function. 5005*8c35d5eeSXin Li # - An opening brace, probably the start of current class or namespace. 5006*8c35d5eeSXin Li # 5007*8c35d5eeSXin Li # Current line is probably not inside an initializer list since 5008*8c35d5eeSXin Li # we saw one of those things without seeing the starting colon. 5009*8c35d5eeSXin Li return False 5010*8c35d5eeSXin Li 5011*8c35d5eeSXin Li # Got to the beginning of the file without seeing the start of 5012*8c35d5eeSXin Li # constructor initializer list. 5013*8c35d5eeSXin Li return False 5014*8c35d5eeSXin Li 5015*8c35d5eeSXin Li 5016*8c35d5eeSXin Lidef CheckForNonConstReference(filename, clean_lines, linenum, 5017*8c35d5eeSXin Li nesting_state, error): 5018*8c35d5eeSXin Li """Check for non-const references. 5019*8c35d5eeSXin Li 5020*8c35d5eeSXin Li Separate from CheckLanguage since it scans backwards from current 5021*8c35d5eeSXin Li line, instead of scanning forward. 5022*8c35d5eeSXin Li 5023*8c35d5eeSXin Li Args: 5024*8c35d5eeSXin Li filename: The name of the current file. 5025*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 5026*8c35d5eeSXin Li linenum: The number of the line to check. 5027*8c35d5eeSXin Li nesting_state: A NestingState instance which maintains information about 5028*8c35d5eeSXin Li the current stack of nested blocks being parsed. 5029*8c35d5eeSXin Li error: The function to call with any errors found. 5030*8c35d5eeSXin Li """ 5031*8c35d5eeSXin Li # Do nothing if there is no '&' on current line. 5032*8c35d5eeSXin Li line = clean_lines.elided[linenum] 5033*8c35d5eeSXin Li if '&' not in line: 5034*8c35d5eeSXin Li return 5035*8c35d5eeSXin Li 5036*8c35d5eeSXin Li # If a function is inherited, current function doesn't have much of 5037*8c35d5eeSXin Li # a choice, so any non-const references should not be blamed on 5038*8c35d5eeSXin Li # derived function. 5039*8c35d5eeSXin Li if IsDerivedFunction(clean_lines, linenum): 5040*8c35d5eeSXin Li return 5041*8c35d5eeSXin Li 5042*8c35d5eeSXin Li # Don't warn on out-of-line method definitions, as we would warn on the 5043*8c35d5eeSXin Li # in-line declaration, if it isn't marked with 'override'. 5044*8c35d5eeSXin Li if IsOutOfLineMethodDefinition(clean_lines, linenum): 5045*8c35d5eeSXin Li return 5046*8c35d5eeSXin Li 5047*8c35d5eeSXin Li # Long type names may be broken across multiple lines, usually in one 5048*8c35d5eeSXin Li # of these forms: 5049*8c35d5eeSXin Li # LongType 5050*8c35d5eeSXin Li # ::LongTypeContinued &identifier 5051*8c35d5eeSXin Li # LongType:: 5052*8c35d5eeSXin Li # LongTypeContinued &identifier 5053*8c35d5eeSXin Li # LongType< 5054*8c35d5eeSXin Li # ...>::LongTypeContinued &identifier 5055*8c35d5eeSXin Li # 5056*8c35d5eeSXin Li # If we detected a type split across two lines, join the previous 5057*8c35d5eeSXin Li # line to current line so that we can match const references 5058*8c35d5eeSXin Li # accordingly. 5059*8c35d5eeSXin Li # 5060*8c35d5eeSXin Li # Note that this only scans back one line, since scanning back 5061*8c35d5eeSXin Li # arbitrary number of lines would be expensive. If you have a type 5062*8c35d5eeSXin Li # that spans more than 2 lines, please use a typedef. 5063*8c35d5eeSXin Li if linenum > 1: 5064*8c35d5eeSXin Li previous = None 5065*8c35d5eeSXin Li if Match(r'\s*::(?:[\w<>]|::)+\s*&\s*\S', line): 5066*8c35d5eeSXin Li # previous_line\n + ::current_line 5067*8c35d5eeSXin Li previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+[\w<>])\s*$', 5068*8c35d5eeSXin Li clean_lines.elided[linenum - 1]) 5069*8c35d5eeSXin Li elif Match(r'\s*[a-zA-Z_]([\w<>]|::)+\s*&\s*\S', line): 5070*8c35d5eeSXin Li # previous_line::\n + current_line 5071*8c35d5eeSXin Li previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+::)\s*$', 5072*8c35d5eeSXin Li clean_lines.elided[linenum - 1]) 5073*8c35d5eeSXin Li if previous: 5074*8c35d5eeSXin Li line = previous.group(1) + line.lstrip() 5075*8c35d5eeSXin Li else: 5076*8c35d5eeSXin Li # Check for templated parameter that is split across multiple lines 5077*8c35d5eeSXin Li endpos = line.rfind('>') 5078*8c35d5eeSXin Li if endpos > -1: 5079*8c35d5eeSXin Li (_, startline, startpos) = ReverseCloseExpression( 5080*8c35d5eeSXin Li clean_lines, linenum, endpos) 5081*8c35d5eeSXin Li if startpos > -1 and startline < linenum: 5082*8c35d5eeSXin Li # Found the matching < on an earlier line, collect all 5083*8c35d5eeSXin Li # pieces up to current line. 5084*8c35d5eeSXin Li line = '' 5085*8c35d5eeSXin Li for i in xrange(startline, linenum + 1): 5086*8c35d5eeSXin Li line += clean_lines.elided[i].strip() 5087*8c35d5eeSXin Li 5088*8c35d5eeSXin Li # Check for non-const references in function parameters. A single '&' may 5089*8c35d5eeSXin Li # found in the following places: 5090*8c35d5eeSXin Li # inside expression: binary & for bitwise AND 5091*8c35d5eeSXin Li # inside expression: unary & for taking the address of something 5092*8c35d5eeSXin Li # inside declarators: reference parameter 5093*8c35d5eeSXin Li # We will exclude the first two cases by checking that we are not inside a 5094*8c35d5eeSXin Li # function body, including one that was just introduced by a trailing '{'. 5095*8c35d5eeSXin Li # TODO(unknown): Doesn't account for 'catch(Exception& e)' [rare]. 5096*8c35d5eeSXin Li if (nesting_state.previous_stack_top and 5097*8c35d5eeSXin Li not (isinstance(nesting_state.previous_stack_top, _ClassInfo) or 5098*8c35d5eeSXin Li isinstance(nesting_state.previous_stack_top, _NamespaceInfo))): 5099*8c35d5eeSXin Li # Not at toplevel, not within a class, and not within a namespace 5100*8c35d5eeSXin Li return 5101*8c35d5eeSXin Li 5102*8c35d5eeSXin Li # Avoid initializer lists. We only need to scan back from the 5103*8c35d5eeSXin Li # current line for something that starts with ':'. 5104*8c35d5eeSXin Li # 5105*8c35d5eeSXin Li # We don't need to check the current line, since the '&' would 5106*8c35d5eeSXin Li # appear inside the second set of parentheses on the current line as 5107*8c35d5eeSXin Li # opposed to the first set. 5108*8c35d5eeSXin Li if linenum > 0: 5109*8c35d5eeSXin Li for i in xrange(linenum - 1, max(0, linenum - 10), -1): 5110*8c35d5eeSXin Li previous_line = clean_lines.elided[i] 5111*8c35d5eeSXin Li if not Search(r'[),]\s*$', previous_line): 5112*8c35d5eeSXin Li break 5113*8c35d5eeSXin Li if Match(r'^\s*:\s+\S', previous_line): 5114*8c35d5eeSXin Li return 5115*8c35d5eeSXin Li 5116*8c35d5eeSXin Li # Avoid preprocessors 5117*8c35d5eeSXin Li if Search(r'\\\s*$', line): 5118*8c35d5eeSXin Li return 5119*8c35d5eeSXin Li 5120*8c35d5eeSXin Li # Avoid constructor initializer lists 5121*8c35d5eeSXin Li if IsInitializerList(clean_lines, linenum): 5122*8c35d5eeSXin Li return 5123*8c35d5eeSXin Li 5124*8c35d5eeSXin Li # We allow non-const references in a few standard places, like functions 5125*8c35d5eeSXin Li # called "swap()" or iostream operators like "<<" or ">>". Do not check 5126*8c35d5eeSXin Li # those function parameters. 5127*8c35d5eeSXin Li # 5128*8c35d5eeSXin Li # We also accept & in static_assert, which looks like a function but 5129*8c35d5eeSXin Li # it's actually a declaration expression. 5130*8c35d5eeSXin Li whitelisted_functions = (r'(?:[sS]wap(?:<\w:+>)?|' 5131*8c35d5eeSXin Li r'operator\s*[<>][<>]|' 5132*8c35d5eeSXin Li r'static_assert|COMPILE_ASSERT' 5133*8c35d5eeSXin Li r')\s*\(') 5134*8c35d5eeSXin Li if Search(whitelisted_functions, line): 5135*8c35d5eeSXin Li return 5136*8c35d5eeSXin Li elif not Search(r'\S+\([^)]*$', line): 5137*8c35d5eeSXin Li # Don't see a whitelisted function on this line. Actually we 5138*8c35d5eeSXin Li # didn't see any function name on this line, so this is likely a 5139*8c35d5eeSXin Li # multi-line parameter list. Try a bit harder to catch this case. 5140*8c35d5eeSXin Li for i in xrange(2): 5141*8c35d5eeSXin Li if (linenum > i and 5142*8c35d5eeSXin Li Search(whitelisted_functions, clean_lines.elided[linenum - i - 1])): 5143*8c35d5eeSXin Li return 5144*8c35d5eeSXin Li 5145*8c35d5eeSXin Li decls = ReplaceAll(r'{[^}]*}', ' ', line) # exclude function body 5146*8c35d5eeSXin Li for parameter in re.findall(_RE_PATTERN_REF_PARAM, decls): 5147*8c35d5eeSXin Li if (not Match(_RE_PATTERN_CONST_REF_PARAM, parameter) and 5148*8c35d5eeSXin Li not Match(_RE_PATTERN_REF_STREAM_PARAM, parameter)): 5149*8c35d5eeSXin Li error(filename, linenum, 'runtime/references', 2, 5150*8c35d5eeSXin Li 'Is this a non-const reference? ' 5151*8c35d5eeSXin Li 'If so, make const or use a pointer: ' + 5152*8c35d5eeSXin Li ReplaceAll(' *<', '<', parameter)) 5153*8c35d5eeSXin Li 5154*8c35d5eeSXin Li 5155*8c35d5eeSXin Lidef CheckCasts(filename, clean_lines, linenum, error): 5156*8c35d5eeSXin Li """Various cast related checks. 5157*8c35d5eeSXin Li 5158*8c35d5eeSXin Li Args: 5159*8c35d5eeSXin Li filename: The name of the current file. 5160*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 5161*8c35d5eeSXin Li linenum: The number of the line to check. 5162*8c35d5eeSXin Li error: The function to call with any errors found. 5163*8c35d5eeSXin Li """ 5164*8c35d5eeSXin Li line = clean_lines.elided[linenum] 5165*8c35d5eeSXin Li 5166*8c35d5eeSXin Li # Check to see if they're using an conversion function cast. 5167*8c35d5eeSXin Li # I just try to capture the most common basic types, though there are more. 5168*8c35d5eeSXin Li # Parameterless conversion functions, such as bool(), are allowed as they are 5169*8c35d5eeSXin Li # probably a member operator declaration or default constructor. 5170*8c35d5eeSXin Li match = Search( 5171*8c35d5eeSXin Li r'(\bnew\s+(?:const\s+)?|\S<\s*(?:const\s+)?)?\b' 5172*8c35d5eeSXin Li r'(int|float|double|bool|char|int32|uint32|int64|uint64)' 5173*8c35d5eeSXin Li r'(\([^)].*)', line) 5174*8c35d5eeSXin Li expecting_function = ExpectingFunctionArgs(clean_lines, linenum) 5175*8c35d5eeSXin Li if match and not expecting_function: 5176*8c35d5eeSXin Li matched_type = match.group(2) 5177*8c35d5eeSXin Li 5178*8c35d5eeSXin Li # matched_new_or_template is used to silence two false positives: 5179*8c35d5eeSXin Li # - New operators 5180*8c35d5eeSXin Li # - Template arguments with function types 5181*8c35d5eeSXin Li # 5182*8c35d5eeSXin Li # For template arguments, we match on types immediately following 5183*8c35d5eeSXin Li # an opening bracket without any spaces. This is a fast way to 5184*8c35d5eeSXin Li # silence the common case where the function type is the first 5185*8c35d5eeSXin Li # template argument. False negative with less-than comparison is 5186*8c35d5eeSXin Li # avoided because those operators are usually followed by a space. 5187*8c35d5eeSXin Li # 5188*8c35d5eeSXin Li # function<double(double)> // bracket + no space = false positive 5189*8c35d5eeSXin Li # value < double(42) // bracket + space = true positive 5190*8c35d5eeSXin Li matched_new_or_template = match.group(1) 5191*8c35d5eeSXin Li 5192*8c35d5eeSXin Li # Avoid arrays by looking for brackets that come after the closing 5193*8c35d5eeSXin Li # parenthesis. 5194*8c35d5eeSXin Li if Match(r'\([^()]+\)\s*\[', match.group(3)): 5195*8c35d5eeSXin Li return 5196*8c35d5eeSXin Li 5197*8c35d5eeSXin Li # Other things to ignore: 5198*8c35d5eeSXin Li # - Function pointers 5199*8c35d5eeSXin Li # - Casts to pointer types 5200*8c35d5eeSXin Li # - Placement new 5201*8c35d5eeSXin Li # - Alias declarations 5202*8c35d5eeSXin Li matched_funcptr = match.group(3) 5203*8c35d5eeSXin Li if (matched_new_or_template is None and 5204*8c35d5eeSXin Li not (matched_funcptr and 5205*8c35d5eeSXin Li (Match(r'\((?:[^() ]+::\s*\*\s*)?[^() ]+\)\s*\(', 5206*8c35d5eeSXin Li matched_funcptr) or 5207*8c35d5eeSXin Li matched_funcptr.startswith('(*)'))) and 5208*8c35d5eeSXin Li not Match(r'\s*using\s+\S+\s*=\s*' + matched_type, line) and 5209*8c35d5eeSXin Li not Search(r'new\(\S+\)\s*' + matched_type, line)): 5210*8c35d5eeSXin Li error(filename, linenum, 'readability/casting', 4, 5211*8c35d5eeSXin Li 'Using deprecated casting style. ' 5212*8c35d5eeSXin Li 'Use static_cast<%s>(...) instead' % 5213*8c35d5eeSXin Li matched_type) 5214*8c35d5eeSXin Li 5215*8c35d5eeSXin Li if not expecting_function: 5216*8c35d5eeSXin Li CheckCStyleCast(filename, clean_lines, linenum, 'static_cast', 5217*8c35d5eeSXin Li r'\((int|float|double|bool|char|u?int(16|32|64))\)', error) 5218*8c35d5eeSXin Li 5219*8c35d5eeSXin Li # This doesn't catch all cases. Consider (const char * const)"hello". 5220*8c35d5eeSXin Li # 5221*8c35d5eeSXin Li # (char *) "foo" should always be a const_cast (reinterpret_cast won't 5222*8c35d5eeSXin Li # compile). 5223*8c35d5eeSXin Li if CheckCStyleCast(filename, clean_lines, linenum, 'const_cast', 5224*8c35d5eeSXin Li r'\((char\s?\*+\s?)\)\s*"', error): 5225*8c35d5eeSXin Li pass 5226*8c35d5eeSXin Li else: 5227*8c35d5eeSXin Li # Check pointer casts for other than string constants 5228*8c35d5eeSXin Li CheckCStyleCast(filename, clean_lines, linenum, 'reinterpret_cast', 5229*8c35d5eeSXin Li r'\((\w+\s?\*+\s?)\)', error) 5230*8c35d5eeSXin Li 5231*8c35d5eeSXin Li # In addition, we look for people taking the address of a cast. This 5232*8c35d5eeSXin Li # is dangerous -- casts can assign to temporaries, so the pointer doesn't 5233*8c35d5eeSXin Li # point where you think. 5234*8c35d5eeSXin Li # 5235*8c35d5eeSXin Li # Some non-identifier character is required before the '&' for the 5236*8c35d5eeSXin Li # expression to be recognized as a cast. These are casts: 5237*8c35d5eeSXin Li # expression = &static_cast<int*>(temporary()); 5238*8c35d5eeSXin Li # function(&(int*)(temporary())); 5239*8c35d5eeSXin Li # 5240*8c35d5eeSXin Li # This is not a cast: 5241*8c35d5eeSXin Li # reference_type&(int* function_param); 5242*8c35d5eeSXin Li match = Search( 5243*8c35d5eeSXin Li r'(?:[^\w]&\(([^)*][^)]*)\)[\w(])|' 5244*8c35d5eeSXin Li r'(?:[^\w]&(static|dynamic|down|reinterpret)_cast\b)', line) 5245*8c35d5eeSXin Li if match: 5246*8c35d5eeSXin Li # Try a better error message when the & is bound to something 5247*8c35d5eeSXin Li # dereferenced by the casted pointer, as opposed to the casted 5248*8c35d5eeSXin Li # pointer itself. 5249*8c35d5eeSXin Li parenthesis_error = False 5250*8c35d5eeSXin Li match = Match(r'^(.*&(?:static|dynamic|down|reinterpret)_cast\b)<', line) 5251*8c35d5eeSXin Li if match: 5252*8c35d5eeSXin Li _, y1, x1 = CloseExpression(clean_lines, linenum, len(match.group(1))) 5253*8c35d5eeSXin Li if x1 >= 0 and clean_lines.elided[y1][x1] == '(': 5254*8c35d5eeSXin Li _, y2, x2 = CloseExpression(clean_lines, y1, x1) 5255*8c35d5eeSXin Li if x2 >= 0: 5256*8c35d5eeSXin Li extended_line = clean_lines.elided[y2][x2:] 5257*8c35d5eeSXin Li if y2 < clean_lines.NumLines() - 1: 5258*8c35d5eeSXin Li extended_line += clean_lines.elided[y2 + 1] 5259*8c35d5eeSXin Li if Match(r'\s*(?:->|\[)', extended_line): 5260*8c35d5eeSXin Li parenthesis_error = True 5261*8c35d5eeSXin Li 5262*8c35d5eeSXin Li if parenthesis_error: 5263*8c35d5eeSXin Li error(filename, linenum, 'readability/casting', 4, 5264*8c35d5eeSXin Li ('Are you taking an address of something dereferenced ' 5265*8c35d5eeSXin Li 'from a cast? Wrapping the dereferenced expression in ' 5266*8c35d5eeSXin Li 'parentheses will make the binding more obvious')) 5267*8c35d5eeSXin Li else: 5268*8c35d5eeSXin Li error(filename, linenum, 'runtime/casting', 4, 5269*8c35d5eeSXin Li ('Are you taking an address of a cast? ' 5270*8c35d5eeSXin Li 'This is dangerous: could be a temp var. ' 5271*8c35d5eeSXin Li 'Take the address before doing the cast, rather than after')) 5272*8c35d5eeSXin Li 5273*8c35d5eeSXin Li 5274*8c35d5eeSXin Lidef CheckCStyleCast(filename, clean_lines, linenum, cast_type, pattern, error): 5275*8c35d5eeSXin Li """Checks for a C-style cast by looking for the pattern. 5276*8c35d5eeSXin Li 5277*8c35d5eeSXin Li Args: 5278*8c35d5eeSXin Li filename: The name of the current file. 5279*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 5280*8c35d5eeSXin Li linenum: The number of the line to check. 5281*8c35d5eeSXin Li cast_type: The string for the C++ cast to recommend. This is either 5282*8c35d5eeSXin Li reinterpret_cast, static_cast, or const_cast, depending. 5283*8c35d5eeSXin Li pattern: The regular expression used to find C-style casts. 5284*8c35d5eeSXin Li error: The function to call with any errors found. 5285*8c35d5eeSXin Li 5286*8c35d5eeSXin Li Returns: 5287*8c35d5eeSXin Li True if an error was emitted. 5288*8c35d5eeSXin Li False otherwise. 5289*8c35d5eeSXin Li """ 5290*8c35d5eeSXin Li line = clean_lines.elided[linenum] 5291*8c35d5eeSXin Li match = Search(pattern, line) 5292*8c35d5eeSXin Li if not match: 5293*8c35d5eeSXin Li return False 5294*8c35d5eeSXin Li 5295*8c35d5eeSXin Li # Exclude lines with keywords that tend to look like casts 5296*8c35d5eeSXin Li context = line[0:match.start(1) - 1] 5297*8c35d5eeSXin Li if Match(r'.*\b(?:sizeof|alignof|alignas|[_A-Z][_A-Z0-9]*)\s*$', context): 5298*8c35d5eeSXin Li return False 5299*8c35d5eeSXin Li 5300*8c35d5eeSXin Li # Try expanding current context to see if we one level of 5301*8c35d5eeSXin Li # parentheses inside a macro. 5302*8c35d5eeSXin Li if linenum > 0: 5303*8c35d5eeSXin Li for i in xrange(linenum - 1, max(0, linenum - 5), -1): 5304*8c35d5eeSXin Li context = clean_lines.elided[i] + context 5305*8c35d5eeSXin Li if Match(r'.*\b[_A-Z][_A-Z0-9]*\s*\((?:\([^()]*\)|[^()])*$', context): 5306*8c35d5eeSXin Li return False 5307*8c35d5eeSXin Li 5308*8c35d5eeSXin Li # operator++(int) and operator--(int) 5309*8c35d5eeSXin Li if context.endswith(' operator++') or context.endswith(' operator--'): 5310*8c35d5eeSXin Li return False 5311*8c35d5eeSXin Li 5312*8c35d5eeSXin Li # A single unnamed argument for a function tends to look like old style cast. 5313*8c35d5eeSXin Li # If we see those, don't issue warnings for deprecated casts. 5314*8c35d5eeSXin Li remainder = line[match.end(0):] 5315*8c35d5eeSXin Li if Match(r'^\s*(?:;|const\b|throw\b|final\b|override\b|[=>{),]|->)', 5316*8c35d5eeSXin Li remainder): 5317*8c35d5eeSXin Li return False 5318*8c35d5eeSXin Li 5319*8c35d5eeSXin Li # At this point, all that should be left is actual casts. 5320*8c35d5eeSXin Li error(filename, linenum, 'readability/casting', 4, 5321*8c35d5eeSXin Li 'Using C-style cast. Use %s<%s>(...) instead' % 5322*8c35d5eeSXin Li (cast_type, match.group(1))) 5323*8c35d5eeSXin Li 5324*8c35d5eeSXin Li return True 5325*8c35d5eeSXin Li 5326*8c35d5eeSXin Li 5327*8c35d5eeSXin Lidef ExpectingFunctionArgs(clean_lines, linenum): 5328*8c35d5eeSXin Li """Checks whether where function type arguments are expected. 5329*8c35d5eeSXin Li 5330*8c35d5eeSXin Li Args: 5331*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 5332*8c35d5eeSXin Li linenum: The number of the line to check. 5333*8c35d5eeSXin Li 5334*8c35d5eeSXin Li Returns: 5335*8c35d5eeSXin Li True if the line at 'linenum' is inside something that expects arguments 5336*8c35d5eeSXin Li of function types. 5337*8c35d5eeSXin Li """ 5338*8c35d5eeSXin Li line = clean_lines.elided[linenum] 5339*8c35d5eeSXin Li return (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) or 5340*8c35d5eeSXin Li (linenum >= 2 and 5341*8c35d5eeSXin Li (Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\((?:\S+,)?\s*$', 5342*8c35d5eeSXin Li clean_lines.elided[linenum - 1]) or 5343*8c35d5eeSXin Li Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\(\s*$', 5344*8c35d5eeSXin Li clean_lines.elided[linenum - 2]) or 5345*8c35d5eeSXin Li Search(r'\bstd::m?function\s*\<\s*$', 5346*8c35d5eeSXin Li clean_lines.elided[linenum - 1])))) 5347*8c35d5eeSXin Li 5348*8c35d5eeSXin Li 5349*8c35d5eeSXin Li_HEADERS_CONTAINING_TEMPLATES = ( 5350*8c35d5eeSXin Li ('<deque>', ('deque',)), 5351*8c35d5eeSXin Li ('<functional>', ('unary_function', 'binary_function', 5352*8c35d5eeSXin Li 'plus', 'minus', 'multiplies', 'divides', 'modulus', 5353*8c35d5eeSXin Li 'negate', 5354*8c35d5eeSXin Li 'equal_to', 'not_equal_to', 'greater', 'less', 5355*8c35d5eeSXin Li 'greater_equal', 'less_equal', 5356*8c35d5eeSXin Li 'logical_and', 'logical_or', 'logical_not', 5357*8c35d5eeSXin Li 'unary_negate', 'not1', 'binary_negate', 'not2', 5358*8c35d5eeSXin Li 'bind1st', 'bind2nd', 5359*8c35d5eeSXin Li 'pointer_to_unary_function', 5360*8c35d5eeSXin Li 'pointer_to_binary_function', 5361*8c35d5eeSXin Li 'ptr_fun', 5362*8c35d5eeSXin Li 'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t', 5363*8c35d5eeSXin Li 'mem_fun_ref_t', 5364*8c35d5eeSXin Li 'const_mem_fun_t', 'const_mem_fun1_t', 5365*8c35d5eeSXin Li 'const_mem_fun_ref_t', 'const_mem_fun1_ref_t', 5366*8c35d5eeSXin Li 'mem_fun_ref', 5367*8c35d5eeSXin Li )), 5368*8c35d5eeSXin Li ('<limits>', ('numeric_limits',)), 5369*8c35d5eeSXin Li ('<list>', ('list',)), 5370*8c35d5eeSXin Li ('<map>', ('map', 'multimap',)), 5371*8c35d5eeSXin Li ('<memory>', ('allocator', 'make_shared', 'make_unique', 'shared_ptr', 5372*8c35d5eeSXin Li 'unique_ptr', 'weak_ptr')), 5373*8c35d5eeSXin Li ('<queue>', ('queue', 'priority_queue',)), 5374*8c35d5eeSXin Li ('<set>', ('set', 'multiset',)), 5375*8c35d5eeSXin Li ('<stack>', ('stack',)), 5376*8c35d5eeSXin Li ('<string>', ('char_traits', 'basic_string',)), 5377*8c35d5eeSXin Li ('<tuple>', ('tuple',)), 5378*8c35d5eeSXin Li ('<unordered_map>', ('unordered_map', 'unordered_multimap')), 5379*8c35d5eeSXin Li ('<unordered_set>', ('unordered_set', 'unordered_multiset')), 5380*8c35d5eeSXin Li ('<utility>', ('pair',)), 5381*8c35d5eeSXin Li ('<vector>', ('vector',)), 5382*8c35d5eeSXin Li 5383*8c35d5eeSXin Li # gcc extensions. 5384*8c35d5eeSXin Li # Note: std::hash is their hash, ::hash is our hash 5385*8c35d5eeSXin Li ('<hash_map>', ('hash_map', 'hash_multimap',)), 5386*8c35d5eeSXin Li ('<hash_set>', ('hash_set', 'hash_multiset',)), 5387*8c35d5eeSXin Li ('<slist>', ('slist',)), 5388*8c35d5eeSXin Li ) 5389*8c35d5eeSXin Li 5390*8c35d5eeSXin Li_HEADERS_MAYBE_TEMPLATES = ( 5391*8c35d5eeSXin Li ('<algorithm>', ('copy', 'max', 'min', 'min_element', 'sort', 5392*8c35d5eeSXin Li 'transform', 5393*8c35d5eeSXin Li )), 5394*8c35d5eeSXin Li ('<utility>', ('forward', 'make_pair', 'move', 'swap')), 5395*8c35d5eeSXin Li ) 5396*8c35d5eeSXin Li 5397*8c35d5eeSXin Li_RE_PATTERN_STRING = re.compile(r'\bstring\b') 5398*8c35d5eeSXin Li 5399*8c35d5eeSXin Li_re_pattern_headers_maybe_templates = [] 5400*8c35d5eeSXin Lifor _header, _templates in _HEADERS_MAYBE_TEMPLATES: 5401*8c35d5eeSXin Li for _template in _templates: 5402*8c35d5eeSXin Li # Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or 5403*8c35d5eeSXin Li # type::max(). 5404*8c35d5eeSXin Li _re_pattern_headers_maybe_templates.append( 5405*8c35d5eeSXin Li (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'), 5406*8c35d5eeSXin Li _template, 5407*8c35d5eeSXin Li _header)) 5408*8c35d5eeSXin Li 5409*8c35d5eeSXin Li# Other scripts may reach in and modify this pattern. 5410*8c35d5eeSXin Li_re_pattern_templates = [] 5411*8c35d5eeSXin Lifor _header, _templates in _HEADERS_CONTAINING_TEMPLATES: 5412*8c35d5eeSXin Li for _template in _templates: 5413*8c35d5eeSXin Li _re_pattern_templates.append( 5414*8c35d5eeSXin Li (re.compile(r'(\<|\b)' + _template + r'\s*\<'), 5415*8c35d5eeSXin Li _template + '<>', 5416*8c35d5eeSXin Li _header)) 5417*8c35d5eeSXin Li 5418*8c35d5eeSXin Li 5419*8c35d5eeSXin Lidef FilesBelongToSameModule(filename_cc, filename_h): 5420*8c35d5eeSXin Li """Check if these two filenames belong to the same module. 5421*8c35d5eeSXin Li 5422*8c35d5eeSXin Li The concept of a 'module' here is a as follows: 5423*8c35d5eeSXin Li foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the 5424*8c35d5eeSXin Li same 'module' if they are in the same directory. 5425*8c35d5eeSXin Li some/path/public/xyzzy and some/path/internal/xyzzy are also considered 5426*8c35d5eeSXin Li to belong to the same module here. 5427*8c35d5eeSXin Li 5428*8c35d5eeSXin Li If the filename_cc contains a longer path than the filename_h, for example, 5429*8c35d5eeSXin Li '/absolute/path/to/base/sysinfo.cc', and this file would include 5430*8c35d5eeSXin Li 'base/sysinfo.h', this function also produces the prefix needed to open the 5431*8c35d5eeSXin Li header. This is used by the caller of this function to more robustly open the 5432*8c35d5eeSXin Li header file. We don't have access to the real include paths in this context, 5433*8c35d5eeSXin Li so we need this guesswork here. 5434*8c35d5eeSXin Li 5435*8c35d5eeSXin Li Known bugs: tools/base/bar.cc and base/bar.h belong to the same module 5436*8c35d5eeSXin Li according to this implementation. Because of this, this function gives 5437*8c35d5eeSXin Li some false positives. This should be sufficiently rare in practice. 5438*8c35d5eeSXin Li 5439*8c35d5eeSXin Li Args: 5440*8c35d5eeSXin Li filename_cc: is the path for the .cc file 5441*8c35d5eeSXin Li filename_h: is the path for the header path 5442*8c35d5eeSXin Li 5443*8c35d5eeSXin Li Returns: 5444*8c35d5eeSXin Li Tuple with a bool and a string: 5445*8c35d5eeSXin Li bool: True if filename_cc and filename_h belong to the same module. 5446*8c35d5eeSXin Li string: the additional prefix needed to open the header file. 5447*8c35d5eeSXin Li """ 5448*8c35d5eeSXin Li 5449*8c35d5eeSXin Li fileinfo = FileInfo(filename_cc) 5450*8c35d5eeSXin Li if not fileinfo.IsSource(): 5451*8c35d5eeSXin Li return (False, '') 5452*8c35d5eeSXin Li filename_cc = filename_cc[:-len(fileinfo.Extension())] 5453*8c35d5eeSXin Li matched_test_suffix = Search(_TEST_FILE_SUFFIX, fileinfo.BaseName()) 5454*8c35d5eeSXin Li if matched_test_suffix: 5455*8c35d5eeSXin Li filename_cc = filename_cc[:-len(matched_test_suffix.group(1))] 5456*8c35d5eeSXin Li filename_cc = filename_cc.replace('/public/', '/') 5457*8c35d5eeSXin Li filename_cc = filename_cc.replace('/internal/', '/') 5458*8c35d5eeSXin Li 5459*8c35d5eeSXin Li if not filename_h.endswith('.h'): 5460*8c35d5eeSXin Li return (False, '') 5461*8c35d5eeSXin Li filename_h = filename_h[:-len('.h')] 5462*8c35d5eeSXin Li if filename_h.endswith('-inl'): 5463*8c35d5eeSXin Li filename_h = filename_h[:-len('-inl')] 5464*8c35d5eeSXin Li filename_h = filename_h.replace('/public/', '/') 5465*8c35d5eeSXin Li filename_h = filename_h.replace('/internal/', '/') 5466*8c35d5eeSXin Li 5467*8c35d5eeSXin Li files_belong_to_same_module = filename_cc.endswith(filename_h) 5468*8c35d5eeSXin Li common_path = '' 5469*8c35d5eeSXin Li if files_belong_to_same_module: 5470*8c35d5eeSXin Li common_path = filename_cc[:-len(filename_h)] 5471*8c35d5eeSXin Li return files_belong_to_same_module, common_path 5472*8c35d5eeSXin Li 5473*8c35d5eeSXin Li 5474*8c35d5eeSXin Lidef UpdateIncludeState(filename, include_dict, io=codecs): 5475*8c35d5eeSXin Li """Fill up the include_dict with new includes found from the file. 5476*8c35d5eeSXin Li 5477*8c35d5eeSXin Li Args: 5478*8c35d5eeSXin Li filename: the name of the header to read. 5479*8c35d5eeSXin Li include_dict: a dictionary in which the headers are inserted. 5480*8c35d5eeSXin Li io: The io factory to use to read the file. Provided for testability. 5481*8c35d5eeSXin Li 5482*8c35d5eeSXin Li Returns: 5483*8c35d5eeSXin Li True if a header was successfully added. False otherwise. 5484*8c35d5eeSXin Li """ 5485*8c35d5eeSXin Li headerfile = None 5486*8c35d5eeSXin Li try: 5487*8c35d5eeSXin Li headerfile = io.open(filename, 'r', 'utf8', 'replace') 5488*8c35d5eeSXin Li except IOError: 5489*8c35d5eeSXin Li return False 5490*8c35d5eeSXin Li linenum = 0 5491*8c35d5eeSXin Li for line in headerfile: 5492*8c35d5eeSXin Li linenum += 1 5493*8c35d5eeSXin Li clean_line = CleanseComments(line) 5494*8c35d5eeSXin Li match = _RE_PATTERN_INCLUDE.search(clean_line) 5495*8c35d5eeSXin Li if match: 5496*8c35d5eeSXin Li include = match.group(2) 5497*8c35d5eeSXin Li include_dict.setdefault(include, linenum) 5498*8c35d5eeSXin Li return True 5499*8c35d5eeSXin Li 5500*8c35d5eeSXin Li 5501*8c35d5eeSXin Lidef CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, 5502*8c35d5eeSXin Li io=codecs): 5503*8c35d5eeSXin Li """Reports for missing stl includes. 5504*8c35d5eeSXin Li 5505*8c35d5eeSXin Li This function will output warnings to make sure you are including the headers 5506*8c35d5eeSXin Li necessary for the stl containers and functions that you use. We only give one 5507*8c35d5eeSXin Li reason to include a header. For example, if you use both equal_to<> and 5508*8c35d5eeSXin Li less<> in a .h file, only one (the latter in the file) of these will be 5509*8c35d5eeSXin Li reported as a reason to include the <functional>. 5510*8c35d5eeSXin Li 5511*8c35d5eeSXin Li Args: 5512*8c35d5eeSXin Li filename: The name of the current file. 5513*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 5514*8c35d5eeSXin Li include_state: An _IncludeState instance. 5515*8c35d5eeSXin Li error: The function to call with any errors found. 5516*8c35d5eeSXin Li io: The IO factory to use to read the header file. Provided for unittest 5517*8c35d5eeSXin Li injection. 5518*8c35d5eeSXin Li """ 5519*8c35d5eeSXin Li required = {} # A map of header name to linenumber and the template entity. 5520*8c35d5eeSXin Li # Example of required: { '<functional>': (1219, 'less<>') } 5521*8c35d5eeSXin Li 5522*8c35d5eeSXin Li for linenum in xrange(clean_lines.NumLines()): 5523*8c35d5eeSXin Li line = clean_lines.elided[linenum] 5524*8c35d5eeSXin Li if not line or line[0] == '#': 5525*8c35d5eeSXin Li continue 5526*8c35d5eeSXin Li 5527*8c35d5eeSXin Li # String is special -- it is a non-templatized type in STL. 5528*8c35d5eeSXin Li matched = _RE_PATTERN_STRING.search(line) 5529*8c35d5eeSXin Li if matched: 5530*8c35d5eeSXin Li # Don't warn about strings in non-STL namespaces: 5531*8c35d5eeSXin Li # (We check only the first match per line; good enough.) 5532*8c35d5eeSXin Li prefix = line[:matched.start()] 5533*8c35d5eeSXin Li if prefix.endswith('std::') or not prefix.endswith('::'): 5534*8c35d5eeSXin Li required['<string>'] = (linenum, 'string') 5535*8c35d5eeSXin Li 5536*8c35d5eeSXin Li for pattern, template, header in _re_pattern_headers_maybe_templates: 5537*8c35d5eeSXin Li if pattern.search(line): 5538*8c35d5eeSXin Li required[header] = (linenum, template) 5539*8c35d5eeSXin Li 5540*8c35d5eeSXin Li # The following function is just a speed up, no semantics are changed. 5541*8c35d5eeSXin Li if not '<' in line: # Reduces the cpu time usage by skipping lines. 5542*8c35d5eeSXin Li continue 5543*8c35d5eeSXin Li 5544*8c35d5eeSXin Li for pattern, template, header in _re_pattern_templates: 5545*8c35d5eeSXin Li matched = pattern.search(line) 5546*8c35d5eeSXin Li if matched: 5547*8c35d5eeSXin Li # Don't warn about IWYU in non-STL namespaces: 5548*8c35d5eeSXin Li # (We check only the first match per line; good enough.) 5549*8c35d5eeSXin Li prefix = line[:matched.start()] 5550*8c35d5eeSXin Li if prefix.endswith('std::') or not prefix.endswith('::'): 5551*8c35d5eeSXin Li required[header] = (linenum, template) 5552*8c35d5eeSXin Li 5553*8c35d5eeSXin Li # The policy is that if you #include something in foo.h you don't need to 5554*8c35d5eeSXin Li # include it again in foo.cc. Here, we will look at possible includes. 5555*8c35d5eeSXin Li # Let's flatten the include_state include_list and copy it into a dictionary. 5556*8c35d5eeSXin Li include_dict = dict([item for sublist in include_state.include_list 5557*8c35d5eeSXin Li for item in sublist]) 5558*8c35d5eeSXin Li 5559*8c35d5eeSXin Li # Did we find the header for this file (if any) and successfully load it? 5560*8c35d5eeSXin Li header_found = False 5561*8c35d5eeSXin Li 5562*8c35d5eeSXin Li # Use the absolute path so that matching works properly. 5563*8c35d5eeSXin Li abs_filename = FileInfo(filename).FullName() 5564*8c35d5eeSXin Li 5565*8c35d5eeSXin Li # For Emacs's flymake. 5566*8c35d5eeSXin Li # If cpplint is invoked from Emacs's flymake, a temporary file is generated 5567*8c35d5eeSXin Li # by flymake and that file name might end with '_flymake.cc'. In that case, 5568*8c35d5eeSXin Li # restore original file name here so that the corresponding header file can be 5569*8c35d5eeSXin Li # found. 5570*8c35d5eeSXin Li # e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h' 5571*8c35d5eeSXin Li # instead of 'foo_flymake.h' 5572*8c35d5eeSXin Li abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename) 5573*8c35d5eeSXin Li 5574*8c35d5eeSXin Li # include_dict is modified during iteration, so we iterate over a copy of 5575*8c35d5eeSXin Li # the keys. 5576*8c35d5eeSXin Li header_keys = include_dict.keys() 5577*8c35d5eeSXin Li for header in header_keys: 5578*8c35d5eeSXin Li (same_module, common_path) = FilesBelongToSameModule(abs_filename, header) 5579*8c35d5eeSXin Li fullpath = common_path + header 5580*8c35d5eeSXin Li if same_module and UpdateIncludeState(fullpath, include_dict, io): 5581*8c35d5eeSXin Li header_found = True 5582*8c35d5eeSXin Li 5583*8c35d5eeSXin Li # If we can't find the header file for a .cc, assume it's because we don't 5584*8c35d5eeSXin Li # know where to look. In that case we'll give up as we're not sure they 5585*8c35d5eeSXin Li # didn't include it in the .h file. 5586*8c35d5eeSXin Li # TODO(unknown): Do a better job of finding .h files so we are confident that 5587*8c35d5eeSXin Li # not having the .h file means there isn't one. 5588*8c35d5eeSXin Li if filename.endswith('.cc') and not header_found: 5589*8c35d5eeSXin Li return 5590*8c35d5eeSXin Li 5591*8c35d5eeSXin Li # All the lines have been processed, report the errors found. 5592*8c35d5eeSXin Li for required_header_unstripped in required: 5593*8c35d5eeSXin Li template = required[required_header_unstripped][1] 5594*8c35d5eeSXin Li if required_header_unstripped.strip('<>"') not in include_dict: 5595*8c35d5eeSXin Li error(filename, required[required_header_unstripped][0], 5596*8c35d5eeSXin Li 'build/include_what_you_use', 4, 5597*8c35d5eeSXin Li 'Add #include ' + required_header_unstripped + ' for ' + template) 5598*8c35d5eeSXin Li 5599*8c35d5eeSXin Li 5600*8c35d5eeSXin Li_RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<') 5601*8c35d5eeSXin Li 5602*8c35d5eeSXin Li 5603*8c35d5eeSXin Lidef CheckMakePairUsesDeduction(filename, clean_lines, linenum, error): 5604*8c35d5eeSXin Li """Check that make_pair's template arguments are deduced. 5605*8c35d5eeSXin Li 5606*8c35d5eeSXin Li G++ 4.6 in C++11 mode fails badly if make_pair's template arguments are 5607*8c35d5eeSXin Li specified explicitly, and such use isn't intended in any case. 5608*8c35d5eeSXin Li 5609*8c35d5eeSXin Li Args: 5610*8c35d5eeSXin Li filename: The name of the current file. 5611*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 5612*8c35d5eeSXin Li linenum: The number of the line to check. 5613*8c35d5eeSXin Li error: The function to call with any errors found. 5614*8c35d5eeSXin Li """ 5615*8c35d5eeSXin Li line = clean_lines.elided[linenum] 5616*8c35d5eeSXin Li match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line) 5617*8c35d5eeSXin Li if match: 5618*8c35d5eeSXin Li error(filename, linenum, 'build/explicit_make_pair', 5619*8c35d5eeSXin Li 4, # 4 = high confidence 5620*8c35d5eeSXin Li 'For C++11-compatibility, omit template arguments from make_pair' 5621*8c35d5eeSXin Li ' OR use pair directly OR if appropriate, construct a pair directly') 5622*8c35d5eeSXin Li 5623*8c35d5eeSXin Li 5624*8c35d5eeSXin Lidef CheckRedundantVirtual(filename, clean_lines, linenum, error): 5625*8c35d5eeSXin Li """Check if line contains a redundant "virtual" function-specifier. 5626*8c35d5eeSXin Li 5627*8c35d5eeSXin Li Args: 5628*8c35d5eeSXin Li filename: The name of the current file. 5629*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 5630*8c35d5eeSXin Li linenum: The number of the line to check. 5631*8c35d5eeSXin Li error: The function to call with any errors found. 5632*8c35d5eeSXin Li """ 5633*8c35d5eeSXin Li # Look for "virtual" on current line. 5634*8c35d5eeSXin Li line = clean_lines.elided[linenum] 5635*8c35d5eeSXin Li virtual = Match(r'^(.*)(\bvirtual\b)(.*)$', line) 5636*8c35d5eeSXin Li if not virtual: return 5637*8c35d5eeSXin Li 5638*8c35d5eeSXin Li # Ignore "virtual" keywords that are near access-specifiers. These 5639*8c35d5eeSXin Li # are only used in class base-specifier and do not apply to member 5640*8c35d5eeSXin Li # functions. 5641*8c35d5eeSXin Li if (Search(r'\b(public|protected|private)\s+$', virtual.group(1)) or 5642*8c35d5eeSXin Li Match(r'^\s+(public|protected|private)\b', virtual.group(3))): 5643*8c35d5eeSXin Li return 5644*8c35d5eeSXin Li 5645*8c35d5eeSXin Li # Ignore the "virtual" keyword from virtual base classes. Usually 5646*8c35d5eeSXin Li # there is a column on the same line in these cases (virtual base 5647*8c35d5eeSXin Li # classes are rare in google3 because multiple inheritance is rare). 5648*8c35d5eeSXin Li if Match(r'^.*[^:]:[^:].*$', line): return 5649*8c35d5eeSXin Li 5650*8c35d5eeSXin Li # Look for the next opening parenthesis. This is the start of the 5651*8c35d5eeSXin Li # parameter list (possibly on the next line shortly after virtual). 5652*8c35d5eeSXin Li # TODO(unknown): doesn't work if there are virtual functions with 5653*8c35d5eeSXin Li # decltype() or other things that use parentheses, but csearch suggests 5654*8c35d5eeSXin Li # that this is rare. 5655*8c35d5eeSXin Li end_col = -1 5656*8c35d5eeSXin Li end_line = -1 5657*8c35d5eeSXin Li start_col = len(virtual.group(2)) 5658*8c35d5eeSXin Li for start_line in xrange(linenum, min(linenum + 3, clean_lines.NumLines())): 5659*8c35d5eeSXin Li line = clean_lines.elided[start_line][start_col:] 5660*8c35d5eeSXin Li parameter_list = Match(r'^([^(]*)\(', line) 5661*8c35d5eeSXin Li if parameter_list: 5662*8c35d5eeSXin Li # Match parentheses to find the end of the parameter list 5663*8c35d5eeSXin Li (_, end_line, end_col) = CloseExpression( 5664*8c35d5eeSXin Li clean_lines, start_line, start_col + len(parameter_list.group(1))) 5665*8c35d5eeSXin Li break 5666*8c35d5eeSXin Li start_col = 0 5667*8c35d5eeSXin Li 5668*8c35d5eeSXin Li if end_col < 0: 5669*8c35d5eeSXin Li return # Couldn't find end of parameter list, give up 5670*8c35d5eeSXin Li 5671*8c35d5eeSXin Li # Look for "override" or "final" after the parameter list 5672*8c35d5eeSXin Li # (possibly on the next few lines). 5673*8c35d5eeSXin Li for i in xrange(end_line, min(end_line + 3, clean_lines.NumLines())): 5674*8c35d5eeSXin Li line = clean_lines.elided[i][end_col:] 5675*8c35d5eeSXin Li match = Search(r'\b(override|final)\b', line) 5676*8c35d5eeSXin Li if match: 5677*8c35d5eeSXin Li error(filename, linenum, 'readability/inheritance', 4, 5678*8c35d5eeSXin Li ('"virtual" is redundant since function is ' 5679*8c35d5eeSXin Li 'already declared as "%s"' % match.group(1))) 5680*8c35d5eeSXin Li 5681*8c35d5eeSXin Li # Set end_col to check whole lines after we are done with the 5682*8c35d5eeSXin Li # first line. 5683*8c35d5eeSXin Li end_col = 0 5684*8c35d5eeSXin Li if Search(r'[^\w]\s*$', line): 5685*8c35d5eeSXin Li break 5686*8c35d5eeSXin Li 5687*8c35d5eeSXin Li 5688*8c35d5eeSXin Lidef CheckRedundantOverrideOrFinal(filename, clean_lines, linenum, error): 5689*8c35d5eeSXin Li """Check if line contains a redundant "override" or "final" virt-specifier. 5690*8c35d5eeSXin Li 5691*8c35d5eeSXin Li Args: 5692*8c35d5eeSXin Li filename: The name of the current file. 5693*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 5694*8c35d5eeSXin Li linenum: The number of the line to check. 5695*8c35d5eeSXin Li error: The function to call with any errors found. 5696*8c35d5eeSXin Li """ 5697*8c35d5eeSXin Li # Look for closing parenthesis nearby. We need one to confirm where 5698*8c35d5eeSXin Li # the declarator ends and where the virt-specifier starts to avoid 5699*8c35d5eeSXin Li # false positives. 5700*8c35d5eeSXin Li line = clean_lines.elided[linenum] 5701*8c35d5eeSXin Li declarator_end = line.rfind(')') 5702*8c35d5eeSXin Li if declarator_end >= 0: 5703*8c35d5eeSXin Li fragment = line[declarator_end:] 5704*8c35d5eeSXin Li else: 5705*8c35d5eeSXin Li if linenum > 1 and clean_lines.elided[linenum - 1].rfind(')') >= 0: 5706*8c35d5eeSXin Li fragment = line 5707*8c35d5eeSXin Li else: 5708*8c35d5eeSXin Li return 5709*8c35d5eeSXin Li 5710*8c35d5eeSXin Li # Check that at most one of "override" or "final" is present, not both 5711*8c35d5eeSXin Li if Search(r'\boverride\b', fragment) and Search(r'\bfinal\b', fragment): 5712*8c35d5eeSXin Li error(filename, linenum, 'readability/inheritance', 4, 5713*8c35d5eeSXin Li ('"override" is redundant since function is ' 5714*8c35d5eeSXin Li 'already declared as "final"')) 5715*8c35d5eeSXin Li 5716*8c35d5eeSXin Li 5717*8c35d5eeSXin Li 5718*8c35d5eeSXin Li 5719*8c35d5eeSXin Li# Returns true if we are at a new block, and it is directly 5720*8c35d5eeSXin Li# inside of a namespace. 5721*8c35d5eeSXin Lidef IsBlockInNameSpace(nesting_state, is_forward_declaration): 5722*8c35d5eeSXin Li """Checks that the new block is directly in a namespace. 5723*8c35d5eeSXin Li 5724*8c35d5eeSXin Li Args: 5725*8c35d5eeSXin Li nesting_state: The _NestingState object that contains info about our state. 5726*8c35d5eeSXin Li is_forward_declaration: If the class is a forward declared class. 5727*8c35d5eeSXin Li Returns: 5728*8c35d5eeSXin Li Whether or not the new block is directly in a namespace. 5729*8c35d5eeSXin Li """ 5730*8c35d5eeSXin Li if is_forward_declaration: 5731*8c35d5eeSXin Li if len(nesting_state.stack) >= 1 and ( 5732*8c35d5eeSXin Li isinstance(nesting_state.stack[-1], _NamespaceInfo)): 5733*8c35d5eeSXin Li return True 5734*8c35d5eeSXin Li else: 5735*8c35d5eeSXin Li return False 5736*8c35d5eeSXin Li 5737*8c35d5eeSXin Li return (len(nesting_state.stack) > 1 and 5738*8c35d5eeSXin Li nesting_state.stack[-1].check_namespace_indentation and 5739*8c35d5eeSXin Li isinstance(nesting_state.stack[-2], _NamespaceInfo)) 5740*8c35d5eeSXin Li 5741*8c35d5eeSXin Li 5742*8c35d5eeSXin Lidef ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item, 5743*8c35d5eeSXin Li raw_lines_no_comments, linenum): 5744*8c35d5eeSXin Li """This method determines if we should apply our namespace indentation check. 5745*8c35d5eeSXin Li 5746*8c35d5eeSXin Li Args: 5747*8c35d5eeSXin Li nesting_state: The current nesting state. 5748*8c35d5eeSXin Li is_namespace_indent_item: If we just put a new class on the stack, True. 5749*8c35d5eeSXin Li If the top of the stack is not a class, or we did not recently 5750*8c35d5eeSXin Li add the class, False. 5751*8c35d5eeSXin Li raw_lines_no_comments: The lines without the comments. 5752*8c35d5eeSXin Li linenum: The current line number we are processing. 5753*8c35d5eeSXin Li 5754*8c35d5eeSXin Li Returns: 5755*8c35d5eeSXin Li True if we should apply our namespace indentation check. Currently, it 5756*8c35d5eeSXin Li only works for classes and namespaces inside of a namespace. 5757*8c35d5eeSXin Li """ 5758*8c35d5eeSXin Li 5759*8c35d5eeSXin Li is_forward_declaration = IsForwardClassDeclaration(raw_lines_no_comments, 5760*8c35d5eeSXin Li linenum) 5761*8c35d5eeSXin Li 5762*8c35d5eeSXin Li if not (is_namespace_indent_item or is_forward_declaration): 5763*8c35d5eeSXin Li return False 5764*8c35d5eeSXin Li 5765*8c35d5eeSXin Li # If we are in a macro, we do not want to check the namespace indentation. 5766*8c35d5eeSXin Li if IsMacroDefinition(raw_lines_no_comments, linenum): 5767*8c35d5eeSXin Li return False 5768*8c35d5eeSXin Li 5769*8c35d5eeSXin Li return IsBlockInNameSpace(nesting_state, is_forward_declaration) 5770*8c35d5eeSXin Li 5771*8c35d5eeSXin Li 5772*8c35d5eeSXin Li# Call this method if the line is directly inside of a namespace. 5773*8c35d5eeSXin Li# If the line above is blank (excluding comments) or the start of 5774*8c35d5eeSXin Li# an inner namespace, it cannot be indented. 5775*8c35d5eeSXin Lidef CheckItemIndentationInNamespace(filename, raw_lines_no_comments, linenum, 5776*8c35d5eeSXin Li error): 5777*8c35d5eeSXin Li line = raw_lines_no_comments[linenum] 5778*8c35d5eeSXin Li if Match(r'^\s+', line): 5779*8c35d5eeSXin Li error(filename, linenum, 'runtime/indentation_namespace', 4, 5780*8c35d5eeSXin Li 'Do not indent within a namespace') 5781*8c35d5eeSXin Li 5782*8c35d5eeSXin Li 5783*8c35d5eeSXin Lidef ProcessLine(filename, file_extension, clean_lines, line, 5784*8c35d5eeSXin Li include_state, function_state, nesting_state, error, 5785*8c35d5eeSXin Li extra_check_functions=[]): 5786*8c35d5eeSXin Li """Processes a single line in the file. 5787*8c35d5eeSXin Li 5788*8c35d5eeSXin Li Args: 5789*8c35d5eeSXin Li filename: Filename of the file that is being processed. 5790*8c35d5eeSXin Li file_extension: The extension (dot not included) of the file. 5791*8c35d5eeSXin Li clean_lines: An array of strings, each representing a line of the file, 5792*8c35d5eeSXin Li with comments stripped. 5793*8c35d5eeSXin Li line: Number of line being processed. 5794*8c35d5eeSXin Li include_state: An _IncludeState instance in which the headers are inserted. 5795*8c35d5eeSXin Li function_state: A _FunctionState instance which counts function lines, etc. 5796*8c35d5eeSXin Li nesting_state: A NestingState instance which maintains information about 5797*8c35d5eeSXin Li the current stack of nested blocks being parsed. 5798*8c35d5eeSXin Li error: A callable to which errors are reported, which takes 4 arguments: 5799*8c35d5eeSXin Li filename, line number, error level, and message 5800*8c35d5eeSXin Li extra_check_functions: An array of additional check functions that will be 5801*8c35d5eeSXin Li run on each source line. Each function takes 4 5802*8c35d5eeSXin Li arguments: filename, clean_lines, line, error 5803*8c35d5eeSXin Li """ 5804*8c35d5eeSXin Li raw_lines = clean_lines.raw_lines 5805*8c35d5eeSXin Li ParseNolintSuppressions(filename, raw_lines[line], line, error) 5806*8c35d5eeSXin Li nesting_state.Update(filename, clean_lines, line, error) 5807*8c35d5eeSXin Li CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line, 5808*8c35d5eeSXin Li error) 5809*8c35d5eeSXin Li if nesting_state.InAsmBlock(): return 5810*8c35d5eeSXin Li CheckForFunctionLengths(filename, clean_lines, line, function_state, error) 5811*8c35d5eeSXin Li CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error) 5812*8c35d5eeSXin Li CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error) 5813*8c35d5eeSXin Li CheckLanguage(filename, clean_lines, line, file_extension, include_state, 5814*8c35d5eeSXin Li nesting_state, error) 5815*8c35d5eeSXin Li CheckForNonConstReference(filename, clean_lines, line, nesting_state, error) 5816*8c35d5eeSXin Li CheckForNonStandardConstructs(filename, clean_lines, line, 5817*8c35d5eeSXin Li nesting_state, error) 5818*8c35d5eeSXin Li CheckVlogArguments(filename, clean_lines, line, error) 5819*8c35d5eeSXin Li CheckPosixThreading(filename, clean_lines, line, error) 5820*8c35d5eeSXin Li CheckInvalidIncrement(filename, clean_lines, line, error) 5821*8c35d5eeSXin Li CheckMakePairUsesDeduction(filename, clean_lines, line, error) 5822*8c35d5eeSXin Li CheckRedundantVirtual(filename, clean_lines, line, error) 5823*8c35d5eeSXin Li CheckRedundantOverrideOrFinal(filename, clean_lines, line, error) 5824*8c35d5eeSXin Li for check_fn in extra_check_functions: 5825*8c35d5eeSXin Li check_fn(filename, clean_lines, line, error) 5826*8c35d5eeSXin Li 5827*8c35d5eeSXin Lidef FlagCxx11Features(filename, clean_lines, linenum, error): 5828*8c35d5eeSXin Li """Flag those c++11 features that we only allow in certain places. 5829*8c35d5eeSXin Li 5830*8c35d5eeSXin Li Args: 5831*8c35d5eeSXin Li filename: The name of the current file. 5832*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 5833*8c35d5eeSXin Li linenum: The number of the line to check. 5834*8c35d5eeSXin Li error: The function to call with any errors found. 5835*8c35d5eeSXin Li """ 5836*8c35d5eeSXin Li line = clean_lines.elided[linenum] 5837*8c35d5eeSXin Li 5838*8c35d5eeSXin Li include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line) 5839*8c35d5eeSXin Li 5840*8c35d5eeSXin Li # Flag unapproved C++ TR1 headers. 5841*8c35d5eeSXin Li if include and include.group(1).startswith('tr1/'): 5842*8c35d5eeSXin Li error(filename, linenum, 'build/c++tr1', 5, 5843*8c35d5eeSXin Li ('C++ TR1 headers such as <%s> are unapproved.') % include.group(1)) 5844*8c35d5eeSXin Li 5845*8c35d5eeSXin Li # Flag unapproved C++11 headers. 5846*8c35d5eeSXin Li if include and include.group(1) in ('cfenv', 5847*8c35d5eeSXin Li 'condition_variable', 5848*8c35d5eeSXin Li 'fenv.h', 5849*8c35d5eeSXin Li 'future', 5850*8c35d5eeSXin Li 'mutex', 5851*8c35d5eeSXin Li 'thread', 5852*8c35d5eeSXin Li 'chrono', 5853*8c35d5eeSXin Li 'ratio', 5854*8c35d5eeSXin Li 'regex', 5855*8c35d5eeSXin Li 'system_error', 5856*8c35d5eeSXin Li ): 5857*8c35d5eeSXin Li error(filename, linenum, 'build/c++11', 5, 5858*8c35d5eeSXin Li ('<%s> is an unapproved C++11 header.') % include.group(1)) 5859*8c35d5eeSXin Li 5860*8c35d5eeSXin Li # The only place where we need to worry about C++11 keywords and library 5861*8c35d5eeSXin Li # features in preprocessor directives is in macro definitions. 5862*8c35d5eeSXin Li if Match(r'\s*#', line) and not Match(r'\s*#\s*define\b', line): return 5863*8c35d5eeSXin Li 5864*8c35d5eeSXin Li # These are classes and free functions. The classes are always 5865*8c35d5eeSXin Li # mentioned as std::*, but we only catch the free functions if 5866*8c35d5eeSXin Li # they're not found by ADL. They're alphabetical by header. 5867*8c35d5eeSXin Li for top_name in ( 5868*8c35d5eeSXin Li # type_traits 5869*8c35d5eeSXin Li 'alignment_of', 5870*8c35d5eeSXin Li 'aligned_union', 5871*8c35d5eeSXin Li ): 5872*8c35d5eeSXin Li if Search(r'\bstd::%s\b' % top_name, line): 5873*8c35d5eeSXin Li error(filename, linenum, 'build/c++11', 5, 5874*8c35d5eeSXin Li ('std::%s is an unapproved C++11 class or function. Send c-style ' 5875*8c35d5eeSXin Li 'an example of where it would make your code more readable, and ' 5876*8c35d5eeSXin Li 'they may let you use it.') % top_name) 5877*8c35d5eeSXin Li 5878*8c35d5eeSXin Li 5879*8c35d5eeSXin Lidef FlagCxx14Features(filename, clean_lines, linenum, error): 5880*8c35d5eeSXin Li """Flag those C++14 features that we restrict. 5881*8c35d5eeSXin Li 5882*8c35d5eeSXin Li Args: 5883*8c35d5eeSXin Li filename: The name of the current file. 5884*8c35d5eeSXin Li clean_lines: A CleansedLines instance containing the file. 5885*8c35d5eeSXin Li linenum: The number of the line to check. 5886*8c35d5eeSXin Li error: The function to call with any errors found. 5887*8c35d5eeSXin Li """ 5888*8c35d5eeSXin Li line = clean_lines.elided[linenum] 5889*8c35d5eeSXin Li 5890*8c35d5eeSXin Li include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line) 5891*8c35d5eeSXin Li 5892*8c35d5eeSXin Li # Flag unapproved C++14 headers. 5893*8c35d5eeSXin Li if include and include.group(1) in ('scoped_allocator', 'shared_mutex'): 5894*8c35d5eeSXin Li error(filename, linenum, 'build/c++14', 5, 5895*8c35d5eeSXin Li ('<%s> is an unapproved C++14 header.') % include.group(1)) 5896*8c35d5eeSXin Li 5897*8c35d5eeSXin Li 5898*8c35d5eeSXin Lidef ProcessFileData(filename, file_extension, lines, error, 5899*8c35d5eeSXin Li extra_check_functions=[]): 5900*8c35d5eeSXin Li """Performs lint checks and reports any errors to the given error function. 5901*8c35d5eeSXin Li 5902*8c35d5eeSXin Li Args: 5903*8c35d5eeSXin Li filename: Filename of the file that is being processed. 5904*8c35d5eeSXin Li file_extension: The extension (dot not included) of the file. 5905*8c35d5eeSXin Li lines: An array of strings, each representing a line of the file, with the 5906*8c35d5eeSXin Li last element being empty if the file is terminated with a newline. 5907*8c35d5eeSXin Li error: A callable to which errors are reported, which takes 4 arguments: 5908*8c35d5eeSXin Li filename, line number, error level, and message 5909*8c35d5eeSXin Li extra_check_functions: An array of additional check functions that will be 5910*8c35d5eeSXin Li run on each source line. Each function takes 4 5911*8c35d5eeSXin Li arguments: filename, clean_lines, line, error 5912*8c35d5eeSXin Li """ 5913*8c35d5eeSXin Li lines = (['// marker so line numbers and indices both start at 1'] + lines + 5914*8c35d5eeSXin Li ['// marker so line numbers end in a known way']) 5915*8c35d5eeSXin Li 5916*8c35d5eeSXin Li include_state = _IncludeState() 5917*8c35d5eeSXin Li function_state = _FunctionState() 5918*8c35d5eeSXin Li nesting_state = NestingState() 5919*8c35d5eeSXin Li 5920*8c35d5eeSXin Li ResetNolintSuppressions() 5921*8c35d5eeSXin Li 5922*8c35d5eeSXin Li CheckForCopyright(filename, lines, error) 5923*8c35d5eeSXin Li ProcessGlobalSuppresions(lines) 5924*8c35d5eeSXin Li RemoveMultiLineComments(filename, lines, error) 5925*8c35d5eeSXin Li clean_lines = CleansedLines(lines) 5926*8c35d5eeSXin Li 5927*8c35d5eeSXin Li if IsHeaderExtension(file_extension): 5928*8c35d5eeSXin Li CheckForHeaderGuard(filename, clean_lines, error) 5929*8c35d5eeSXin Li 5930*8c35d5eeSXin Li for line in xrange(clean_lines.NumLines()): 5931*8c35d5eeSXin Li ProcessLine(filename, file_extension, clean_lines, line, 5932*8c35d5eeSXin Li include_state, function_state, nesting_state, error, 5933*8c35d5eeSXin Li extra_check_functions) 5934*8c35d5eeSXin Li FlagCxx11Features(filename, clean_lines, line, error) 5935*8c35d5eeSXin Li nesting_state.CheckCompletedBlocks(filename, error) 5936*8c35d5eeSXin Li 5937*8c35d5eeSXin Li CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error) 5938*8c35d5eeSXin Li 5939*8c35d5eeSXin Li # Check that the .cc file has included its header if it exists. 5940*8c35d5eeSXin Li if _IsSourceExtension(file_extension): 5941*8c35d5eeSXin Li CheckHeaderFileIncluded(filename, include_state, error) 5942*8c35d5eeSXin Li 5943*8c35d5eeSXin Li # We check here rather than inside ProcessLine so that we see raw 5944*8c35d5eeSXin Li # lines rather than "cleaned" lines. 5945*8c35d5eeSXin Li CheckForBadCharacters(filename, lines, error) 5946*8c35d5eeSXin Li 5947*8c35d5eeSXin Li CheckForNewlineAtEOF(filename, lines, error) 5948*8c35d5eeSXin Li 5949*8c35d5eeSXin Lidef ProcessConfigOverrides(filename): 5950*8c35d5eeSXin Li """ Loads the configuration files and processes the config overrides. 5951*8c35d5eeSXin Li 5952*8c35d5eeSXin Li Args: 5953*8c35d5eeSXin Li filename: The name of the file being processed by the linter. 5954*8c35d5eeSXin Li 5955*8c35d5eeSXin Li Returns: 5956*8c35d5eeSXin Li False if the current |filename| should not be processed further. 5957*8c35d5eeSXin Li """ 5958*8c35d5eeSXin Li 5959*8c35d5eeSXin Li abs_filename = os.path.abspath(filename) 5960*8c35d5eeSXin Li cfg_filters = [] 5961*8c35d5eeSXin Li keep_looking = True 5962*8c35d5eeSXin Li while keep_looking: 5963*8c35d5eeSXin Li abs_path, base_name = os.path.split(abs_filename) 5964*8c35d5eeSXin Li if not base_name: 5965*8c35d5eeSXin Li break # Reached the root directory. 5966*8c35d5eeSXin Li 5967*8c35d5eeSXin Li cfg_file = os.path.join(abs_path, "CPPLINT.cfg") 5968*8c35d5eeSXin Li abs_filename = abs_path 5969*8c35d5eeSXin Li if not os.path.isfile(cfg_file): 5970*8c35d5eeSXin Li continue 5971*8c35d5eeSXin Li 5972*8c35d5eeSXin Li try: 5973*8c35d5eeSXin Li with open(cfg_file) as file_handle: 5974*8c35d5eeSXin Li for line in file_handle: 5975*8c35d5eeSXin Li line, _, _ = line.partition('#') # Remove comments. 5976*8c35d5eeSXin Li if not line.strip(): 5977*8c35d5eeSXin Li continue 5978*8c35d5eeSXin Li 5979*8c35d5eeSXin Li name, _, val = line.partition('=') 5980*8c35d5eeSXin Li name = name.strip() 5981*8c35d5eeSXin Li val = val.strip() 5982*8c35d5eeSXin Li if name == 'set noparent': 5983*8c35d5eeSXin Li keep_looking = False 5984*8c35d5eeSXin Li elif name == 'filter': 5985*8c35d5eeSXin Li cfg_filters.append(val) 5986*8c35d5eeSXin Li elif name == 'exclude_files': 5987*8c35d5eeSXin Li # When matching exclude_files pattern, use the base_name of 5988*8c35d5eeSXin Li # the current file name or the directory name we are processing. 5989*8c35d5eeSXin Li # For example, if we are checking for lint errors in /foo/bar/baz.cc 5990*8c35d5eeSXin Li # and we found the .cfg file at /foo/CPPLINT.cfg, then the config 5991*8c35d5eeSXin Li # file's "exclude_files" filter is meant to be checked against "bar" 5992*8c35d5eeSXin Li # and not "baz" nor "bar/baz.cc". 5993*8c35d5eeSXin Li if base_name: 5994*8c35d5eeSXin Li pattern = re.compile(val) 5995*8c35d5eeSXin Li if pattern.match(base_name): 5996*8c35d5eeSXin Li if _cpplint_state.quiet: 5997*8c35d5eeSXin Li # Suppress "Ignoring file" warning when using --quiet. 5998*8c35d5eeSXin Li return False 5999*8c35d5eeSXin Li sys.stderr.write('Ignoring "%s": file excluded by "%s". ' 6000*8c35d5eeSXin Li 'File path component "%s" matches ' 6001*8c35d5eeSXin Li 'pattern "%s"\n' % 6002*8c35d5eeSXin Li (filename, cfg_file, base_name, val)) 6003*8c35d5eeSXin Li return False 6004*8c35d5eeSXin Li elif name == 'linelength': 6005*8c35d5eeSXin Li global _line_length 6006*8c35d5eeSXin Li try: 6007*8c35d5eeSXin Li _line_length = int(val) 6008*8c35d5eeSXin Li except ValueError: 6009*8c35d5eeSXin Li sys.stderr.write('Line length must be numeric.') 6010*8c35d5eeSXin Li elif name == 'root': 6011*8c35d5eeSXin Li global _root 6012*8c35d5eeSXin Li # root directories are specified relative to CPPLINT.cfg dir. 6013*8c35d5eeSXin Li _root = os.path.join(os.path.dirname(cfg_file), val) 6014*8c35d5eeSXin Li elif name == 'headers': 6015*8c35d5eeSXin Li ProcessHppHeadersOption(val) 6016*8c35d5eeSXin Li else: 6017*8c35d5eeSXin Li sys.stderr.write( 6018*8c35d5eeSXin Li 'Invalid configuration option (%s) in file %s\n' % 6019*8c35d5eeSXin Li (name, cfg_file)) 6020*8c35d5eeSXin Li 6021*8c35d5eeSXin Li except IOError: 6022*8c35d5eeSXin Li sys.stderr.write( 6023*8c35d5eeSXin Li "Skipping config file '%s': Can't open for reading\n" % cfg_file) 6024*8c35d5eeSXin Li keep_looking = False 6025*8c35d5eeSXin Li 6026*8c35d5eeSXin Li # Apply all the accumulated filters in reverse order (top-level directory 6027*8c35d5eeSXin Li # config options having the least priority). 6028*8c35d5eeSXin Li for filter in reversed(cfg_filters): 6029*8c35d5eeSXin Li _AddFilters(filter) 6030*8c35d5eeSXin Li 6031*8c35d5eeSXin Li return True 6032*8c35d5eeSXin Li 6033*8c35d5eeSXin Li 6034*8c35d5eeSXin Lidef ProcessFile(filename, vlevel, extra_check_functions=[]): 6035*8c35d5eeSXin Li """Does google-lint on a single file. 6036*8c35d5eeSXin Li 6037*8c35d5eeSXin Li Args: 6038*8c35d5eeSXin Li filename: The name of the file to parse. 6039*8c35d5eeSXin Li 6040*8c35d5eeSXin Li vlevel: The level of errors to report. Every error of confidence 6041*8c35d5eeSXin Li >= verbose_level will be reported. 0 is a good default. 6042*8c35d5eeSXin Li 6043*8c35d5eeSXin Li extra_check_functions: An array of additional check functions that will be 6044*8c35d5eeSXin Li run on each source line. Each function takes 4 6045*8c35d5eeSXin Li arguments: filename, clean_lines, line, error 6046*8c35d5eeSXin Li """ 6047*8c35d5eeSXin Li 6048*8c35d5eeSXin Li _SetVerboseLevel(vlevel) 6049*8c35d5eeSXin Li _BackupFilters() 6050*8c35d5eeSXin Li old_errors = _cpplint_state.error_count 6051*8c35d5eeSXin Li 6052*8c35d5eeSXin Li if not ProcessConfigOverrides(filename): 6053*8c35d5eeSXin Li _RestoreFilters() 6054*8c35d5eeSXin Li return 6055*8c35d5eeSXin Li 6056*8c35d5eeSXin Li lf_lines = [] 6057*8c35d5eeSXin Li crlf_lines = [] 6058*8c35d5eeSXin Li try: 6059*8c35d5eeSXin Li # Support the UNIX convention of using "-" for stdin. Note that 6060*8c35d5eeSXin Li # we are not opening the file with universal newline support 6061*8c35d5eeSXin Li # (which codecs doesn't support anyway), so the resulting lines do 6062*8c35d5eeSXin Li # contain trailing '\r' characters if we are reading a file that 6063*8c35d5eeSXin Li # has CRLF endings. 6064*8c35d5eeSXin Li # If after the split a trailing '\r' is present, it is removed 6065*8c35d5eeSXin Li # below. 6066*8c35d5eeSXin Li if filename == '-': 6067*8c35d5eeSXin Li lines = codecs.StreamReaderWriter(sys.stdin, 6068*8c35d5eeSXin Li codecs.getreader('utf8'), 6069*8c35d5eeSXin Li codecs.getwriter('utf8'), 6070*8c35d5eeSXin Li 'replace').read().split('\n') 6071*8c35d5eeSXin Li else: 6072*8c35d5eeSXin Li lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n') 6073*8c35d5eeSXin Li 6074*8c35d5eeSXin Li # Remove trailing '\r'. 6075*8c35d5eeSXin Li # The -1 accounts for the extra trailing blank line we get from split() 6076*8c35d5eeSXin Li for linenum in range(len(lines) - 1): 6077*8c35d5eeSXin Li if lines[linenum].endswith('\r'): 6078*8c35d5eeSXin Li lines[linenum] = lines[linenum].rstrip('\r') 6079*8c35d5eeSXin Li crlf_lines.append(linenum + 1) 6080*8c35d5eeSXin Li else: 6081*8c35d5eeSXin Li lf_lines.append(linenum + 1) 6082*8c35d5eeSXin Li 6083*8c35d5eeSXin Li except IOError: 6084*8c35d5eeSXin Li sys.stderr.write( 6085*8c35d5eeSXin Li "Skipping input '%s': Can't open for reading\n" % filename) 6086*8c35d5eeSXin Li _RestoreFilters() 6087*8c35d5eeSXin Li return 6088*8c35d5eeSXin Li 6089*8c35d5eeSXin Li # Note, if no dot is found, this will give the entire filename as the ext. 6090*8c35d5eeSXin Li file_extension = filename[filename.rfind('.') + 1:] 6091*8c35d5eeSXin Li 6092*8c35d5eeSXin Li # When reading from stdin, the extension is unknown, so no cpplint tests 6093*8c35d5eeSXin Li # should rely on the extension. 6094*8c35d5eeSXin Li if filename != '-' and file_extension not in _valid_extensions: 6095*8c35d5eeSXin Li sys.stderr.write('Ignoring %s; not a valid file name ' 6096*8c35d5eeSXin Li '(%s)\n' % (filename, ', '.join(_valid_extensions))) 6097*8c35d5eeSXin Li else: 6098*8c35d5eeSXin Li ProcessFileData(filename, file_extension, lines, Error, 6099*8c35d5eeSXin Li extra_check_functions) 6100*8c35d5eeSXin Li 6101*8c35d5eeSXin Li # If end-of-line sequences are a mix of LF and CR-LF, issue 6102*8c35d5eeSXin Li # warnings on the lines with CR. 6103*8c35d5eeSXin Li # 6104*8c35d5eeSXin Li # Don't issue any warnings if all lines are uniformly LF or CR-LF, 6105*8c35d5eeSXin Li # since critique can handle these just fine, and the style guide 6106*8c35d5eeSXin Li # doesn't dictate a particular end of line sequence. 6107*8c35d5eeSXin Li # 6108*8c35d5eeSXin Li # We can't depend on os.linesep to determine what the desired 6109*8c35d5eeSXin Li # end-of-line sequence should be, since that will return the 6110*8c35d5eeSXin Li # server-side end-of-line sequence. 6111*8c35d5eeSXin Li if lf_lines and crlf_lines: 6112*8c35d5eeSXin Li # Warn on every line with CR. An alternative approach might be to 6113*8c35d5eeSXin Li # check whether the file is mostly CRLF or just LF, and warn on the 6114*8c35d5eeSXin Li # minority, we bias toward LF here since most tools prefer LF. 6115*8c35d5eeSXin Li for linenum in crlf_lines: 6116*8c35d5eeSXin Li Error(filename, linenum, 'whitespace/newline', 1, 6117*8c35d5eeSXin Li 'Unexpected \\r (^M) found; better to use only \\n') 6118*8c35d5eeSXin Li 6119*8c35d5eeSXin Li # Suppress printing anything if --quiet was passed unless the error 6120*8c35d5eeSXin Li # count has increased after processing this file. 6121*8c35d5eeSXin Li if not _cpplint_state.quiet or old_errors != _cpplint_state.error_count: 6122*8c35d5eeSXin Li sys.stdout.write('Done processing %s\n' % filename) 6123*8c35d5eeSXin Li _RestoreFilters() 6124*8c35d5eeSXin Li 6125*8c35d5eeSXin Li 6126*8c35d5eeSXin Lidef PrintUsage(message): 6127*8c35d5eeSXin Li """Prints a brief usage string and exits, optionally with an error message. 6128*8c35d5eeSXin Li 6129*8c35d5eeSXin Li Args: 6130*8c35d5eeSXin Li message: The optional error message. 6131*8c35d5eeSXin Li """ 6132*8c35d5eeSXin Li sys.stderr.write(_USAGE) 6133*8c35d5eeSXin Li if message: 6134*8c35d5eeSXin Li sys.exit('\nFATAL ERROR: ' + message) 6135*8c35d5eeSXin Li else: 6136*8c35d5eeSXin Li sys.exit(1) 6137*8c35d5eeSXin Li 6138*8c35d5eeSXin Li 6139*8c35d5eeSXin Lidef PrintCategories(): 6140*8c35d5eeSXin Li """Prints a list of all the error-categories used by error messages. 6141*8c35d5eeSXin Li 6142*8c35d5eeSXin Li These are the categories used to filter messages via --filter. 6143*8c35d5eeSXin Li """ 6144*8c35d5eeSXin Li sys.stderr.write(''.join(' %s\n' % cat for cat in _ERROR_CATEGORIES)) 6145*8c35d5eeSXin Li sys.exit(0) 6146*8c35d5eeSXin Li 6147*8c35d5eeSXin Li 6148*8c35d5eeSXin Lidef ParseArguments(args): 6149*8c35d5eeSXin Li """Parses the command line arguments. 6150*8c35d5eeSXin Li 6151*8c35d5eeSXin Li This may set the output format and verbosity level as side-effects. 6152*8c35d5eeSXin Li 6153*8c35d5eeSXin Li Args: 6154*8c35d5eeSXin Li args: The command line arguments: 6155*8c35d5eeSXin Li 6156*8c35d5eeSXin Li Returns: 6157*8c35d5eeSXin Li The list of filenames to lint. 6158*8c35d5eeSXin Li """ 6159*8c35d5eeSXin Li try: 6160*8c35d5eeSXin Li (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=', 6161*8c35d5eeSXin Li 'counting=', 6162*8c35d5eeSXin Li 'filter=', 6163*8c35d5eeSXin Li 'root=', 6164*8c35d5eeSXin Li 'linelength=', 6165*8c35d5eeSXin Li 'extensions=', 6166*8c35d5eeSXin Li 'headers=', 6167*8c35d5eeSXin Li 'quiet']) 6168*8c35d5eeSXin Li except getopt.GetoptError: 6169*8c35d5eeSXin Li PrintUsage('Invalid arguments.') 6170*8c35d5eeSXin Li 6171*8c35d5eeSXin Li verbosity = _VerboseLevel() 6172*8c35d5eeSXin Li output_format = _OutputFormat() 6173*8c35d5eeSXin Li filters = '' 6174*8c35d5eeSXin Li quiet = _Quiet() 6175*8c35d5eeSXin Li counting_style = '' 6176*8c35d5eeSXin Li 6177*8c35d5eeSXin Li for (opt, val) in opts: 6178*8c35d5eeSXin Li if opt == '--help': 6179*8c35d5eeSXin Li PrintUsage(None) 6180*8c35d5eeSXin Li elif opt == '--output': 6181*8c35d5eeSXin Li if val not in ('emacs', 'vs7', 'eclipse'): 6182*8c35d5eeSXin Li PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.') 6183*8c35d5eeSXin Li output_format = val 6184*8c35d5eeSXin Li elif opt == '--quiet': 6185*8c35d5eeSXin Li quiet = True 6186*8c35d5eeSXin Li elif opt == '--verbose': 6187*8c35d5eeSXin Li verbosity = int(val) 6188*8c35d5eeSXin Li elif opt == '--filter': 6189*8c35d5eeSXin Li filters = val 6190*8c35d5eeSXin Li if not filters: 6191*8c35d5eeSXin Li PrintCategories() 6192*8c35d5eeSXin Li elif opt == '--counting': 6193*8c35d5eeSXin Li if val not in ('total', 'toplevel', 'detailed'): 6194*8c35d5eeSXin Li PrintUsage('Valid counting options are total, toplevel, and detailed') 6195*8c35d5eeSXin Li counting_style = val 6196*8c35d5eeSXin Li elif opt == '--root': 6197*8c35d5eeSXin Li global _root 6198*8c35d5eeSXin Li _root = val 6199*8c35d5eeSXin Li elif opt == '--linelength': 6200*8c35d5eeSXin Li global _line_length 6201*8c35d5eeSXin Li try: 6202*8c35d5eeSXin Li _line_length = int(val) 6203*8c35d5eeSXin Li except ValueError: 6204*8c35d5eeSXin Li PrintUsage('Line length must be digits.') 6205*8c35d5eeSXin Li elif opt == '--extensions': 6206*8c35d5eeSXin Li global _valid_extensions 6207*8c35d5eeSXin Li try: 6208*8c35d5eeSXin Li _valid_extensions = set(val.split(',')) 6209*8c35d5eeSXin Li except ValueError: 6210*8c35d5eeSXin Li PrintUsage('Extensions must be comma separated list.') 6211*8c35d5eeSXin Li elif opt == '--headers': 6212*8c35d5eeSXin Li ProcessHppHeadersOption(val) 6213*8c35d5eeSXin Li 6214*8c35d5eeSXin Li if not filenames: 6215*8c35d5eeSXin Li PrintUsage('No files were specified.') 6216*8c35d5eeSXin Li 6217*8c35d5eeSXin Li _SetOutputFormat(output_format) 6218*8c35d5eeSXin Li _SetQuiet(quiet) 6219*8c35d5eeSXin Li _SetVerboseLevel(verbosity) 6220*8c35d5eeSXin Li _SetFilters(filters) 6221*8c35d5eeSXin Li _SetCountingStyle(counting_style) 6222*8c35d5eeSXin Li 6223*8c35d5eeSXin Li return filenames 6224*8c35d5eeSXin Li 6225*8c35d5eeSXin Li 6226*8c35d5eeSXin Lidef main(): 6227*8c35d5eeSXin Li filenames = ParseArguments(sys.argv[1:]) 6228*8c35d5eeSXin Li 6229*8c35d5eeSXin Li # Change stderr to write with replacement characters so we don't die 6230*8c35d5eeSXin Li # if we try to print something containing non-ASCII characters. 6231*8c35d5eeSXin Li sys.stderr = codecs.StreamReaderWriter(sys.stderr, 6232*8c35d5eeSXin Li codecs.getreader('utf8'), 6233*8c35d5eeSXin Li codecs.getwriter('utf8'), 6234*8c35d5eeSXin Li 'replace') 6235*8c35d5eeSXin Li 6236*8c35d5eeSXin Li _cpplint_state.ResetErrorCounts() 6237*8c35d5eeSXin Li for filename in filenames: 6238*8c35d5eeSXin Li ProcessFile(filename, _cpplint_state.verbose_level) 6239*8c35d5eeSXin Li # If --quiet is passed, suppress printing error count unless there are errors. 6240*8c35d5eeSXin Li if not _cpplint_state.quiet or _cpplint_state.error_count > 0: 6241*8c35d5eeSXin Li _cpplint_state.PrintErrorCounts() 6242*8c35d5eeSXin Li 6243*8c35d5eeSXin Li sys.exit(_cpplint_state.error_count > 0) 6244*8c35d5eeSXin Li 6245*8c35d5eeSXin Li 6246*8c35d5eeSXin Liif __name__ == '__main__': 6247*8c35d5eeSXin Li main() 6248